From: Gabor Horvath Date: Thu, 9 Jul 2015 21:43:45 +0000 (+0000) Subject: [Static Analyzer] Basic per checker command line option validation. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=89d5a6eab8c5445a4943cc71dafb6ae35110070d;p=clang [Static Analyzer] Basic per checker command line option validation. Differential Revision: http://reviews.llvm.org/D8077 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@241863 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h index ca68a74fef..c9724c08da 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h +++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h @@ -64,6 +64,9 @@ #endif namespace clang { +class DiagnosticsEngine; +class AnalyzerOptions; + namespace ento { class CheckerOptInfo; @@ -118,6 +121,10 @@ public: void initializeManager(CheckerManager &mgr, SmallVectorImpl &opts) const; + /// Check if every option corresponds to a specific checker or package. + void validateCheckerOptions(const AnalyzerOptions &opts, + DiagnosticsEngine &diags) const; + /// Prints the name and description of all checkers in this registry. /// This output is not intended to be machine-parseable. void printHelp(raw_ostream &out, size_t maxNameChars = 30) const ; diff --git a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp index b64e30b310..6ba64f52d1 100644 --- a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp +++ b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp @@ -8,7 +8,10 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/CheckerRegistry.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/StaticAnalyzer/Core/CheckerOptInfo.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "llvm/ADT/SetVector.h" #include "llvm/Support/raw_ostream.h" @@ -111,6 +114,28 @@ void CheckerRegistry::initializeManager(CheckerManager &checkerMgr, } } +void CheckerRegistry::validateCheckerOptions(const AnalyzerOptions &opts, + DiagnosticsEngine &diags) const { + for (auto &config : opts.Config) { + size_t pos = config.getKey().find(':'); + if (pos == StringRef::npos) + continue; + + bool hasChecker = false; + StringRef checkerName = config.getKey().substr(0, pos); + for (auto &checker : Checkers) { + if (checker.FullName.startswith(checkerName) && + (checker.FullName.size() == pos || checker.FullName[pos] == '.')) { + hasChecker = true; + break; + } + } + if (!hasChecker) { + diags.Report(diag::err_unknown_analyzer_checker) << checkerName; + } + } +} + void CheckerRegistry::printHelp(raw_ostream &out, size_t maxNameChars) const { // FIXME: Alphabetical sort puts 'experimental' in the middle. diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp index b3ff79750b..7fced1e5c7 100644 --- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -114,6 +114,7 @@ ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, ClangCheckerRegistry allCheckers(plugins, &diags); allCheckers.initializeManager(*checkerMgr, checkerOpts); + allCheckers.validateCheckerOptions(opts, diags); checkerMgr->finishedCheckerRegistration(); for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) { diff --git a/test/Analysis/analyzer-checker-config.c b/test/Analysis/analyzer-checker-config.c new file mode 100644 index 0000000000..642c96c996 --- /dev/null +++ b/test/Analysis/analyzer-checker-config.c @@ -0,0 +1,12 @@ +// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config unix.mallo:Optimistic=true 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config uni:Optimistic=true 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config uni.:Optimistic=true 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config ..:Optimistic=true 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config unix.:Optimistic=true 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config unrelated:Optimistic=true 2>&1 | FileCheck %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-config unix.Malloc:Optimistic=true + +// Just to test clang is working. +# foo + +// CHECK: error: