summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Kornienko <alexfh@google.com>2018-06-27 14:56:12 +0000
committerAlexander Kornienko <alexfh@google.com>2018-06-27 14:56:12 +0000
commitd00ed8e2c20014044e42fb7b9380dc9e297cd66f (patch)
tree8e90ce7b57988384c31b9b20fdf07f3acce3c63c
parentafc62b7032848e8dfbd30eb2323c7e7d57f981e4 (diff)
downloadbcm5719-llvm-d00ed8e2c20014044e42fb7b9380dc9e297cd66f.tar.gz
bcm5719-llvm-d00ed8e2c20014044e42fb7b9380dc9e297cd66f.zip
[analyzer] Allow registering custom statically-linked analyzer checkers
Summary: Add an extension point to allow registration of statically-linked Clang Static Analyzer checkers that are not a part of the Clang tree. This extension point employs the mechanism used when checkers are registered from dynamically loaded plugins. Reviewers: george.karpenkov, NoQ, xazax.hun, dcoughlin Reviewed By: george.karpenkov Subscribers: mgorny, mikhail.ramalho, rnkovacs, xazax.hun, szepet, a.sidorin, cfe-commits Differential Revision: https://reviews.llvm.org/D45718 llvm-svn: 335740
-rw-r--r--clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h15
-rw-r--r--clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h10
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp11
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp13
-rw-r--r--clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp2
-rw-r--r--clang/unittests/StaticAnalyzer/CMakeLists.txt5
-rw-r--r--clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp80
7 files changed, 125 insertions, 11 deletions
diff --git a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
index a9dad6c5e9a..59fbbc3ca80 100644
--- a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
+++ b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
@@ -17,6 +17,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/LLVM.h"
+#include <functional>
#include <memory>
namespace clang {
@@ -29,10 +30,24 @@ class CompilerInstance;
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<MyCustomChecker>("example.MyCustomChecker",
+ /// "Description");
+ /// });
+ virtual void
+ AddCheckerRegistrationFn(std::function<void(CheckerRegistry &)> Fn) = 0;
};
/// CreateAnalysisConsumer - Creates an ASTConsumer to run various code
diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
index 2985b7c117e..216a2359efb 100644
--- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
+++ b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H
#include "clang/Basic/LLVM.h"
+#include <functional>
#include <memory>
#include <string>
@@ -21,10 +22,13 @@ namespace clang {
namespace ento {
class CheckerManager;
+ class CheckerRegistry;
- std::unique_ptr<CheckerManager>
- createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts,
- ArrayRef<std::string> plugins, DiagnosticsEngine &diags);
+ std::unique_ptr<CheckerManager> createCheckerManager(
+ AnalyzerOptions &opts, const LangOptions &langOpts,
+ ArrayRef<std::string> plugins,
+ ArrayRef<std::function<void(CheckerRegistry &)>> checkerRegistrationFns,
+ DiagnosticsEngine &diags);
} // end ento namespace
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 81f69436861..44abde5da6d 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -164,6 +164,8 @@ class AnalysisConsumer : public AnalysisASTConsumer,
/// Bug Reporter to use while recursively visiting Decls.
BugReporter *RecVisitorBR;
+ std::vector<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns;
+
public:
ASTContext *Ctx;
const Preprocessor &PP;
@@ -293,8 +295,9 @@ public:
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<AnalysisManager>(
*Ctx, PP.getDiagnostics(), PP.getLangOpts(), PathConsumers,
@@ -385,6 +388,10 @@ public:
PathConsumers.push_back(Consumer);
}
+ void AddCheckerRegistrationFn(std::function<void(CheckerRegistry&)> Fn) override {
+ CheckerRegistrationFns.push_back(std::move(Fn));
+ }
+
private:
void storeTopLevelDecls(DeclGroupRef DG);
std::string getFunctionName(const Decl *D);
diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index 6792f89876c..a260c2d85b1 100644
--- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -111,16 +111,21 @@ getCheckerOptList(const AnalyzerOptions &opts) {
return checkerOpts;
}
-std::unique_ptr<CheckerManager>
-ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts,
- ArrayRef<std::string> plugins,
- DiagnosticsEngine &diags) {
+std::unique_ptr<CheckerManager> ento::createCheckerManager(
+ AnalyzerOptions &opts, const LangOptions &langOpts,
+ ArrayRef<std::string> plugins,
+ ArrayRef<std::function<void(CheckerRegistry &)>> checkerRegistrationFns,
+ DiagnosticsEngine &diags) {
std::unique_ptr<CheckerManager> checkerMgr(
new CheckerManager(langOpts, opts));
SmallVector<CheckerOptInfo, 8> checkerOpts = getCheckerOptList(opts);
ClangCheckerRegistry allCheckers(plugins, &diags);
+
+ for (const auto &Fn : checkerRegistrationFns)
+ Fn(allCheckers);
+
allCheckers.initializeManager(*checkerMgr, checkerOpts);
allCheckers.validateCheckerOptions(opts, diags);
checkerMgr->finishedCheckerRegistration();
diff --git a/clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp b/clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp
index cd2289d4f28..3d8332554fb 100644
--- a/clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp
+++ b/clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp
@@ -1,4 +1,4 @@
-//===- unittest/Analysis/AnalyzerOptionsTest.cpp - SA Options test --------===//
+//===- unittest/StaticAnalyzer/AnalyzerOptionsTest.cpp - SA Options test --===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/clang/unittests/StaticAnalyzer/CMakeLists.txt b/clang/unittests/StaticAnalyzer/CMakeLists.txt
index 4ca0be50e5c..117a5d9ae4c 100644
--- a/clang/unittests/StaticAnalyzer/CMakeLists.txt
+++ b/clang/unittests/StaticAnalyzer/CMakeLists.txt
@@ -4,11 +4,14 @@ set(LLVM_LINK_COMPONENTS
add_clang_unittest(StaticAnalysisTests
AnalyzerOptionsTest.cpp
+ RegisterCustomCheckersTest.cpp
)
target_link_libraries(StaticAnalysisTests
PRIVATE
clangBasic
clangAnalysis
- clangStaticAnalyzerCore
+ clangStaticAnalyzerCore
+ clangStaticAnalyzerFrontend
+ clangTooling
)
diff --git a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
new file mode 100644
index 00000000000..82887a1daf3
--- /dev/null
+++ b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
@@ -0,0 +1,80 @@
+//===- unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ento {
+namespace {
+
+class CustomChecker : public Checker<check::ASTCodeBody> {
+public:
+ void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
+ BugReporter &BR) const {
+ BR.EmitBasicReport(D, this, "Custom diagnostic", categories::LogicError,
+ "Custom diagnostic description",
+ PathDiagnosticLocation(D, Mgr.getSourceManager()), {});
+ }
+};
+
+class TestAction : public ASTFrontendAction {
+ class DiagConsumer : public PathDiagnosticConsumer {
+ llvm::raw_ostream &Output;
+
+ public:
+ DiagConsumer(llvm::raw_ostream &Output) : Output(Output) {}
+ void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
+ FilesMade *filesMade) override {
+ for (const auto *PD : Diags)
+ Output << PD->getCheckName() << ":" << PD->getShortDescription();
+ }
+
+ StringRef getName() const override { return "Test"; }
+ };
+
+ llvm::raw_ostream &DiagsOutput;
+
+public:
+ TestAction(llvm::raw_ostream &DiagsOutput) : DiagsOutput(DiagsOutput) {}
+
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef File) override {
+ std::unique_ptr<AnalysisASTConsumer> AnalysisConsumer =
+ CreateAnalysisConsumer(Compiler);
+ AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput));
+ Compiler.getAnalyzerOpts()->CheckersControlList = {
+ {"custom.CustomChecker", true}};
+ AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
+ Registry.addChecker<CustomChecker>("custom.CustomChecker", "Description");
+ });
+ return AnalysisConsumer;
+ }
+};
+
+
+TEST(RegisterCustomCheckers, RegisterChecker) {
+ std::string Diags;
+ {
+ llvm::raw_string_ostream OS(Diags);
+ EXPECT_TRUE(tooling::runToolOnCode(new TestAction(OS), "void f() {;}"));
+ }
+ EXPECT_EQ(Diags, "custom.CustomChecker:Custom diagnostic description");
+}
+
+}
+}
+}
OpenPOWER on IntegriCloud