Index: include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h =================================================================== --- include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h +++ include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h @@ -17,6 +17,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/Basic/LLVM.h" +#include #include namespace clang { @@ -29,10 +30,24 @@ namespace ento { class PathDiagnosticConsumer; class CheckerManager; +class CheckerRegistry; class AnalysisASTConsumer : public ASTConsumer { public: virtual void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer) = 0; + + /// This method allows registering statically linked custom checkers that are + /// not a part of the Clang tree. It employs the same mechanism that is used + /// by plugins. + /// + /// Example: + /// + /// Consumer->AddCheckerRegistrationFn([] (CheckerRegistry& Registry) { + /// Registry.addChecker("example.MyCustomChecker", + /// "Description"); + /// }); + virtual void + AddCheckerRegistrationFn(std::function Fn) = 0; }; /// CreateAnalysisConsumer - Creates an ASTConsumer to run various code Index: include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h =================================================================== --- include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h +++ include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H #include "clang/Basic/LLVM.h" +#include #include #include @@ -21,10 +22,13 @@ namespace ento { class CheckerManager; + class CheckerRegistry; - std::unique_ptr - createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, - ArrayRef plugins, DiagnosticsEngine &diags); + std::unique_ptr createCheckerManager( + AnalyzerOptions &opts, const LangOptions &langOpts, + ArrayRef plugins, + ArrayRef> checkerRegistrationFns, + DiagnosticsEngine &diags); } // end ento namespace Index: lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp =================================================================== --- lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -164,6 +164,8 @@ /// Bug Reporter to use while recursively visiting Decls. BugReporter *RecVisitorBR; + std::vector> CheckerRegistrationFns; + public: ASTContext *Ctx; const Preprocessor &PP; @@ -293,8 +295,9 @@ void Initialize(ASTContext &Context) override { Ctx = &Context; - checkerMgr = createCheckerManager(*Opts, PP.getLangOpts(), Plugins, - PP.getDiagnostics()); + checkerMgr = + createCheckerManager(*Opts, PP.getLangOpts(), Plugins, + CheckerRegistrationFns, PP.getDiagnostics()); Mgr = llvm::make_unique( *Ctx, PP.getDiagnostics(), PP.getLangOpts(), PathConsumers, @@ -385,6 +388,10 @@ PathConsumers.push_back(Consumer); } + void AddCheckerRegistrationFn(std::function Fn) override { + CheckerRegistrationFns.push_back(std::move(Fn)); + } + private: void storeTopLevelDecls(DeclGroupRef DG); std::string getFunctionName(const Decl *D); Index: lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp =================================================================== --- lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -111,16 +111,21 @@ return checkerOpts; } -std::unique_ptr -ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, - ArrayRef plugins, - DiagnosticsEngine &diags) { +std::unique_ptr ento::createCheckerManager( + AnalyzerOptions &opts, const LangOptions &langOpts, + ArrayRef plugins, + ArrayRef> checkerRegistrationFns, + DiagnosticsEngine &diags) { std::unique_ptr checkerMgr( new CheckerManager(langOpts, opts)); SmallVector checkerOpts = getCheckerOptList(opts); ClangCheckerRegistry allCheckers(plugins, &diags); + + for (const auto &Fn : checkerRegistrationFns) + Fn(allCheckers); + allCheckers.initializeManager(*checkerMgr, checkerOpts); allCheckers.validateCheckerOptions(opts, diags); checkerMgr->finishedCheckerRegistration();