Skip to content
Merged
74 changes: 42 additions & 32 deletions clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,29 @@
// function clang_registerCheckers. For example:
//
// extern "C"
// void clang_registerCheckers (CheckerRegistry &registry) {
// registry.addChecker<MainCallChecker>("example.MainCallChecker",
// "Disallows calls to functions called main");
// void clang_registerCheckers(CheckerRegistry &Registry) {
// Registry.addChecker<MainCallChecker>(
// "example.MainCallChecker",
// "Disallows calls to functions called main");
// }
//
// The first method argument is the full name of the checker, including its
// enclosing package. By convention, the registered name of a checker is the
// name of the associated class (the template argument).
// The second method argument is a short human-readable description of the
// checker.
// The first argument of this templated method is the full name of the checker
// (including its package), while the second argument is a short description
// that is printed by `-analyzer-checker-help`.
//
// The clang_registerCheckers function may add any number of checkers to the
// registry. If any checkers require additional initialization, use the three-
// argument form of CheckerRegistry::addChecker.
// A plugin may register several separate checkers by calling `addChecker()`
// multiple times. If a checker requires custom registration functions (e.g.
// checker option handling) use the non-templated variant of `addChecker` that
// takes two callback functions as the first two parameters.
//
// To load a checker plugin, specify the full path to the dynamic library as
// the argument to the -load option in the cc1 frontend. You can then enable
// your custom checker using the -analyzer-checker:
//
// clang -cc1 -load </path/to/plugin.dylib> -analyze
// -analyzer-checker=<example.MainCallChecker>
// clang -cc1 -load /path/to/plugin.dylib -analyze
// -analyzer-checker=example.MainCallChecker
//
// For a complete working example, see examples/analyzer-plugin.
// For complete examples, see clang/lib/Analysis/plugins/SampleAnalyzer

#ifndef CLANG_ANALYZER_API_VERSION_STRING
// FIXME: The Clang version string is not particularly granular;
Expand Down Expand Up @@ -108,30 +108,40 @@ class CheckerRegistry {
mgr.template registerChecker<T>();
}

template <typename T> static bool returnTrue(const CheckerManager &mgr) {
return true;
}
static bool returnTrue(const CheckerManager &) { return true; }

public:
/// Adds a checker to the registry. Use this non-templated overload when your
/// checker requires custom initialization.
void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction sfn,
/// Adds a checker to the registry.
/// This private, most general variant is intended for loading the checker
/// definitions from `Checkers.td`.
/// FIXME: The checker registry should not bother with loading `DocsUri`
/// because it is (as of now) never queried from the checker registry.
void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction Sfn,
StringRef FullName, StringRef Desc, StringRef DocsUri,
bool IsHidden);

/// Adds a checker to the registry. Use this templated overload when your
/// checker does not require any custom initialization.
/// This function isn't really needed and probably causes more headaches than
/// the tiny convenience that it provides, but external plugins might use it,
/// and there isn't a strong incentive to remove it.
public:
/// Adds a checker to the registry.
/// Use this for a checker defined in a plugin if it requires custom
/// registration functions (e.g. for handling checker options).
void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction Sfn,
StringRef FullName, StringRef Desc, bool IsHidden = false) {
addChecker(Fn, Sfn, FullName, Desc, "NoDocsUri", IsHidden);
}

/// Adds a checker to the registry.
/// Use this for a checker defined in a plugin if it doesn't require custom
/// registration functions.
template <class T>
void addChecker(StringRef FullName, StringRef Desc, StringRef DocsUri,
bool IsHidden = false) {
// Avoid MSVC's Compiler Error C2276:
// http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx
void addChecker(StringRef FullName, StringRef Desc, bool IsHidden = false) {
addChecker(&CheckerRegistry::initializeManager<CheckerManager, T>,
&CheckerRegistry::returnTrue<T>, FullName, Desc, DocsUri,
IsHidden);
&CheckerRegistry::returnTrue, FullName, Desc,
/*IsHidden=*/IsHidden);
}

/// Add a mock checker to the registry for testing purposes, without
/// specifying metadata that is not relevant in simple tests.
template <class T> void addMockChecker(StringRef FullName) {
addChecker<T>(FullName, "MockCheckerDescription");
}

/// Makes the checker with the full name \p fullName depend on the checker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"

// This barebones plugin is used by clang/test/Analysis/checker-plugins.c
// to test dependency handling among checkers loaded from plugins.

using namespace clang;
using namespace ento;

Expand All @@ -15,12 +18,11 @@ struct DependendentChecker : public Checker<check::BeginFunction> {
} // end anonymous namespace

// Register plugin!
extern "C" void clang_registerCheckers(CheckerRegistry &registry) {
registry.addChecker<Dependency>("example.Dependency", "", "");
registry.addChecker<DependendentChecker>("example.DependendentChecker", "",
"");
extern "C" void clang_registerCheckers(CheckerRegistry &Registry) {
Registry.addMockChecker<Dependency>("example.Dependency");
Registry.addMockChecker<DependendentChecker>("example.DependendentChecker");

registry.addDependency("example.DependendentChecker", "example.Dependency");
Registry.addDependency("example.DependendentChecker", "example.Dependency");
}

extern "C" const char clang_analyzerAPIVersionString[] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
using namespace clang;
using namespace ento;

// This barebones plugin is used by clang/test/Analysis/checker-plugins.c
// to test option handling on checkers loaded from plugins.

namespace {
struct MyChecker : public Checker<check::BeginFunction> {
void checkBeginFunction(CheckerContext &Ctx) const {}
Expand All @@ -25,13 +28,11 @@ bool shouldRegisterMyChecker(const CheckerManager &mgr) { return true; }
} // end anonymous namespace

// Register plugin!
extern "C" void clang_registerCheckers(CheckerRegistry &registry) {
registry.addChecker(registerMyChecker, shouldRegisterMyChecker,
"example.MyChecker", "Example Description",
"example.mychecker.documentation.nonexistent.html",
/*isHidden*/false);
extern "C" void clang_registerCheckers(CheckerRegistry &Registry) {
Registry.addChecker(registerMyChecker, shouldRegisterMyChecker,
"example.MyChecker", "Example Description");

registry.addCheckerOption(/*OptionType*/ "bool",
Registry.addCheckerOption(/*OptionType*/ "bool",
/*CheckerFullName*/ "example.MyChecker",
/*OptionName*/ "ExampleOption",
/*DefaultValStr*/ "false",
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/Analysis/plugins/SampleAnalyzer/MainCallChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"

// This simple plugin is used by clang/test/Analysis/checker-plugins.c
// to test the use of a checker that is defined in a plugin.

using namespace clang;
using namespace ento;

namespace {
class MainCallChecker : public Checker<check::PreStmt<CallExpr>> {
mutable std::unique_ptr<BugType> BT;

const BugType BT{this, "call to main", "example analyzer plugin"};

public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
Expand All @@ -33,21 +37,17 @@ void MainCallChecker::checkPreStmt(const CallExpr *CE,
if (!N)
return;

if (!BT)
BT.reset(new BugType(this, "call to main", "example analyzer plugin"));

auto report =
std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N);
report->addRange(Callee->getSourceRange());
C.emitReport(std::move(report));
}
}

// Register plugin!
extern "C" void clang_registerCheckers(CheckerRegistry &registry) {
registry.addChecker<MainCallChecker>(
"example.MainCallChecker", "Disallows calls to functions called main",
"");
extern "C" void clang_registerCheckers(CheckerRegistry &Registry) {
Registry.addChecker<MainCallChecker>("example.MainCallChecker",
"Example Description");
}

extern "C" const char clang_analyzerAPIVersionString[] =
Expand Down
6 changes: 2 additions & 4 deletions clang/unittests/StaticAnalyzer/BlockEntranceCallbackTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ void addBlockEntranceTester(AnalysisASTConsumer &AnalysisConsumer,
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker(&registerChecker<BlockEntranceCallbackTester>,
&shouldAlwaysRegister, "test.BlockEntranceTester",
"EmptyDescription", "EmptyDocsUri",
/*IsHidden=*/false);
"EmptyDescription");
});
}

Expand All @@ -102,8 +101,7 @@ void addBranchConditionTester(AnalysisASTConsumer &AnalysisConsumer,
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker(&registerChecker<BranchConditionCallbackTester>,
&shouldAlwaysRegister, "test.BranchConditionTester",
"EmptyDescription", "EmptyDocsUri",
/*IsHidden=*/false);
"EmptyDescription");
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ class TestAction : public ASTFrontendAction {
std::make_unique<VerifyPathDiagnosticConsumer>(
std::move(ExpectedDiags), Compiler.getSourceManager()));
AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<InterestingnessTestChecker>("test.Interestingness",
"Description", "");
Registry.addMockChecker<InterestingnessTestChecker>(
"test.Interestingness");
});
Compiler.getAnalyzerOpts().CheckersAndPackages = {
{"test.Interestingness", true}};
Expand Down
3 changes: 1 addition & 2 deletions clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -616,8 +616,7 @@ void addCallDescChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"test.CallDescChecker", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<CallDescChecker>("test.CallDescChecker", "Description",
"");
Registry.addMockChecker<CallDescChecker>("test.CallDescChecker");
});
}

Expand Down
3 changes: 1 addition & 2 deletions clang/unittests/StaticAnalyzer/CallEventTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ void addCXXDeallocatorChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"test.CXXDeallocator", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<CXXDeallocatorChecker>("test.CXXDeallocator",
"Description", "");
Registry.addMockChecker<CXXDeallocatorChecker>("test.CXXDeallocator");
});
}

Expand Down
6 changes: 2 additions & 4 deletions clang/unittests/StaticAnalyzer/ConflictingEvalCallsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,8 @@ void addEvalFooCheckers(AnalysisASTConsumer &AnalysisConsumer,
AnOpts.CheckersAndPackages = {{"test.EvalFoo1", true},
{"test.EvalFoo2", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<EvalCallFoo1>("test.EvalFoo1", "EmptyDescription",
"EmptyDocsUri");
Registry.addChecker<EvalCallFoo2>("test.EvalFoo2", "EmptyDescription",
"EmptyDocsUri");
Registry.addMockChecker<EvalCallFoo1>("test.EvalFoo1");
Registry.addMockChecker<EvalCallFoo2>("test.EvalFoo2");
});
}
} // namespace
Expand Down
11 changes: 5 additions & 6 deletions clang/unittests/StaticAnalyzer/ExprEngineVisitTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,26 +77,25 @@ void addExprEngineVisitPreChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"ExprEngineVisitPreChecker", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<ExprEngineVisitPreChecker>("ExprEngineVisitPreChecker",
"Desc", "DocsURI");
Registry.addMockChecker<ExprEngineVisitPreChecker>(
"ExprEngineVisitPreChecker");
});
}

void addExprEngineVisitPostChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"ExprEngineVisitPostChecker", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<ExprEngineVisitPostChecker>(
"ExprEngineVisitPostChecker", "Desc", "DocsURI");
Registry.addMockChecker<ExprEngineVisitPostChecker>(
"ExprEngineVisitPostChecker");
});
}

void addMemAccessChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"MemAccessChecker", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<MemAccessChecker>("MemAccessChecker", "Desc",
"DocsURI");
Registry.addMockChecker<MemAccessChecker>("MemAccessChecker");
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ void addFalsePositiveGenerator(AnalysisASTConsumer &AnalysisConsumer,
AnOpts.CheckersAndPackages = {{"test.FalsePositiveGenerator", true},
{"debug.ViewExplodedGraph", false}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<FalsePositiveGenerator>(
"test.FalsePositiveGenerator", "EmptyDescription", "EmptyDocsUri");
Registry.addMockChecker<FalsePositiveGenerator>(
"test.FalsePositiveGenerator");
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ void addDescriptiveNameChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"DescriptiveNameChecker", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<DescriptiveNameChecker>("DescriptiveNameChecker",
"Desc", "DocsURI");
Registry.addMockChecker<DescriptiveNameChecker>("DescriptiveNameChecker");
});
}

Expand Down
11 changes: 6 additions & 5 deletions clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ void addNonThoroughStatefulChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"test.StatefulChecker", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry
.addChecker<StatefulChecker<NonThoroughErrorNotPreventedFuncVisitor>>(
"test.StatefulChecker", "Description", "");
Registry.addMockChecker<
StatefulChecker<NonThoroughErrorNotPreventedFuncVisitor>>(
"test.StatefulChecker");
});
}

Expand Down Expand Up @@ -232,8 +232,9 @@ void addThoroughStatefulChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"test.StatefulChecker", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<StatefulChecker<ThoroughErrorNotPreventedFuncVisitor>>(
"test.StatefulChecker", "Description", "");
Registry
.addMockChecker<StatefulChecker<ThoroughErrorNotPreventedFuncVisitor>>(
"test.StatefulChecker");
});
}

Expand Down
4 changes: 2 additions & 2 deletions clang/unittests/StaticAnalyzer/ObjcBug-124477.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ void addFlagFlipperChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"test.FlipFlagOnCheckLocation", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<FlipFlagOnCheckLocation>("test.FlipFlagOnCheckLocation",
"Description", "");
Registry.addMockChecker<FlipFlagOnCheckLocation>(
"test.FlipFlagOnCheckLocation");
});
}

Expand Down
Loading
Loading