Skip to content

Commit fc638a1

Browse files
committed
[analyzer] Prettify checker registration and unittest code
This commit tweaks the interface of `CheckerRegistry::addChecker` to make it more practical for plugins and tests: - The most general overload (where `DocsUri` appears in the parameter list) is turned into a private method which is only used for loading the checkers described in `Checkers.td`. Note that currently _nothing_ queries the documentation URI from the checker registry (it's only used by the logic that generates the clang-tidy documentation, but that loads it directly from `Checkers.td` without involving the `CheckerRegistry`), so there is no reason to require anyone to provide this value. (In fact, it may be a good idea to remove it completely from the `CheckerRegistry`.) - A new public overload is introduced which differs from the most general one by omitting the `DocsUri` argument and making the `IsHidden` parameter optional (by setting it to `false` by default). This will cover the needs of plugins that want maximal customization. - The templated overload (which takes the checker type as a template paarameter + the checker name and description as parameters) also loses the `DocsUri` parameter. - A new method `addMockChecker<T>` is added for use in unit tests. In addition to propagating these changes (e.g. using `addMockChecker` in unittests), this commit clarifies, corrects and extends lots of comments and performs various minor code quality improvements in the code of unittests and example plugins. I originally wrote the bulk of this commit when I was planning to add an extra parameter to `addChecker` in order to implement some technical details of the CheckerFamily framework. At the end I decided against adding that extra parameter, so this cleanup was left out of the PR llvm#139256 and I'm merging it now as a separate commit (after minor tweaks). This commit is mostly NFC: the only functional change is that the public checker registration functions no longer require (or accept) `DocsUri` as an argument, and the `IsHidden` argument is optional for both public overloads of `addChecker` (and not just the "basic" templated one).
1 parent 39bc052 commit fc638a1

18 files changed

+102
-100
lines changed

clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -38,29 +38,29 @@
3838
// function clang_registerCheckers. For example:
3939
//
4040
// extern "C"
41-
// void clang_registerCheckers (CheckerRegistry &registry) {
42-
// registry.addChecker<MainCallChecker>("example.MainCallChecker",
43-
// "Disallows calls to functions called main");
41+
// void clang_registerCheckers(CheckerRegistry &Registry) {
42+
// Registry.addChecker<MainCallChecker>(
43+
// "example.MainCallChecker",
44+
// "Disallows calls to functions called main");
4445
// }
4546
//
46-
// The first method argument is the full name of the checker, including its
47-
// enclosing package. By convention, the registered name of a checker is the
48-
// name of the associated class (the template argument).
49-
// The second method argument is a short human-readable description of the
50-
// checker.
47+
// The first argument of this templated method is the full name of the checker
48+
// (including its package), while the second argument is a short description
49+
// that is printed by `-analyzer-checker-help`.
5150
//
52-
// The clang_registerCheckers function may add any number of checkers to the
53-
// registry. If any checkers require additional initialization, use the three-
54-
// argument form of CheckerRegistry::addChecker.
51+
// A plugin may register several separate checkers by calling `addChecker()`
52+
// multiple times. If a checker requires custom registration functions (e.g.
53+
// checker option handling) use the non-templated variant of `addChecker` that
54+
// takes two callback functions as the first two parameters.
5555
//
5656
// To load a checker plugin, specify the full path to the dynamic library as
5757
// the argument to the -load option in the cc1 frontend. You can then enable
5858
// your custom checker using the -analyzer-checker:
5959
//
60-
// clang -cc1 -load </path/to/plugin.dylib> -analyze
61-
// -analyzer-checker=<example.MainCallChecker>
60+
// clang -cc1 -load /path/to/plugin.dylib -analyze
61+
// -analyzer-checker=example.MainCallChecker
6262
//
63-
// For a complete working example, see examples/analyzer-plugin.
63+
// For complete examples, see clang/lib/Analysis/plugins/SampleAnalyzer
6464

6565
#ifndef CLANG_ANALYZER_API_VERSION_STRING
6666
// FIXME: The Clang version string is not particularly granular;
@@ -112,26 +112,35 @@ class CheckerRegistry {
112112
return true;
113113
}
114114

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

122-
/// Adds a checker to the registry. Use this templated overload when your
123-
/// checker does not require any custom initialization.
124-
/// This function isn't really needed and probably causes more headaches than
125-
/// the tiny convenience that it provides, but external plugins might use it,
126-
/// and there isn't a strong incentive to remove it.
123+
public:
124+
/// Adds a checker to the registry. Use this for a checker defined in a
125+
/// plugin if it requires custom registration functions.
126+
void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction Sfn,
127+
StringRef FullName, StringRef Desc, bool IsHidden = false) {
128+
addChecker(Fn, Sfn, FullName, Desc, "NoDocsUri", IsHidden);
129+
}
130+
131+
/// Adds a checker to the registry. Use this for a checker defined in a
132+
/// plugin if it doesn't require custom registration functions.
127133
template <class T>
128-
void addChecker(StringRef FullName, StringRef Desc, StringRef DocsUri,
129-
bool IsHidden = false) {
130-
// Avoid MSVC's Compiler Error C2276:
131-
// http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx
134+
void addChecker(StringRef FullName, StringRef Desc, bool IsHidden = false) {
132135
addChecker(&CheckerRegistry::initializeManager<CheckerManager, T>,
133-
&CheckerRegistry::returnTrue<T>, FullName, Desc, DocsUri,
134-
IsHidden);
136+
&CheckerRegistry::returnTrue<T>, FullName, Desc,
137+
/*IsHidden=*/IsHidden);
138+
}
139+
140+
/// Add a mock checker to the registry for testing purposes, without
141+
/// specifying metadata that is not relevant in simple tests.
142+
template <class T> void addMockChecker(StringRef FullName) {
143+
addChecker<T>(FullName, "MockCheckerDescription");
135144
}
136145

137146
/// Makes the checker with the full name \p fullName depend on the checker

clang/lib/Analysis/plugins/CheckerDependencyHandling/CheckerDependencyHandling.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
33
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
44

5+
// This barebones plugin is used by clang/test/Analysis/checker-plugins.c
6+
// to test dependency handling among checkers loaded from plugins.
7+
58
using namespace clang;
69
using namespace ento;
710

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

1720
// Register plugin!
18-
extern "C" void clang_registerCheckers(CheckerRegistry &registry) {
19-
registry.addChecker<Dependency>("example.Dependency", "", "");
20-
registry.addChecker<DependendentChecker>("example.DependendentChecker", "",
21-
"");
21+
extern "C" void clang_registerCheckers(CheckerRegistry &Registry) {
22+
Registry.addMockChecker<Dependency>("example.Dependency");
23+
Registry.addMockChecker<DependendentChecker>("example.DependendentChecker");
2224

23-
registry.addDependency("example.DependendentChecker", "example.Dependency");
25+
Registry.addDependency("example.DependendentChecker", "example.Dependency");
2426
}
2527

2628
extern "C" const char clang_analyzerAPIVersionString[] =

clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
using namespace clang;
66
using namespace ento;
77

8+
// This barebones plugin is used by clang/test/Analysis/checker-plugins.c
9+
// to test option handling on checkers loaded from plugins.
10+
811
namespace {
912
struct MyChecker : public Checker<check::BeginFunction> {
1013
void checkBeginFunction(CheckerContext &Ctx) const {}
@@ -25,13 +28,11 @@ bool shouldRegisterMyChecker(const CheckerManager &mgr) { return true; }
2528
} // end anonymous namespace
2629

2730
// Register plugin!
28-
extern "C" void clang_registerCheckers(CheckerRegistry &registry) {
29-
registry.addChecker(registerMyChecker, shouldRegisterMyChecker,
30-
"example.MyChecker", "Example Description",
31-
"example.mychecker.documentation.nonexistent.html",
32-
/*isHidden*/false);
31+
extern "C" void clang_registerCheckers(CheckerRegistry &Registry) {
32+
Registry.addChecker(registerMyChecker, shouldRegisterMyChecker,
33+
"example.MyChecker", "Example Description");
3334

34-
registry.addCheckerOption(/*OptionType*/ "bool",
35+
Registry.addCheckerOption(/*OptionType*/ "bool",
3536
/*CheckerFullName*/ "example.MyChecker",
3637
/*OptionName*/ "ExampleOption",
3738
/*DefaultValStr*/ "false",

clang/lib/Analysis/plugins/SampleAnalyzer/MainCallChecker.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@
33
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
44
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
55

6+
// This simple plugin is used by clang/test/Analysis/checker-plugins.c
7+
// to test the use of a checker that is defined in a plugin.
8+
69
using namespace clang;
710
using namespace ento;
811

912
namespace {
1013
class MainCallChecker : public Checker<check::PreStmt<CallExpr>> {
11-
mutable std::unique_ptr<BugType> BT;
14+
15+
BugType BT{this, "call to main", "example analyzer plugin"};
1216

1317
public:
1418
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -33,21 +37,17 @@ void MainCallChecker::checkPreStmt(const CallExpr *CE,
3337
if (!N)
3438
return;
3539

36-
if (!BT)
37-
BT.reset(new BugType(this, "call to main", "example analyzer plugin"));
38-
3940
auto report =
40-
std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
41+
std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N);
4142
report->addRange(Callee->getSourceRange());
4243
C.emitReport(std::move(report));
4344
}
4445
}
4546

4647
// Register plugin!
47-
extern "C" void clang_registerCheckers(CheckerRegistry &registry) {
48-
registry.addChecker<MainCallChecker>(
49-
"example.MainCallChecker", "Disallows calls to functions called main",
50-
"");
48+
extern "C" void clang_registerCheckers(CheckerRegistry &Registry) {
49+
Registry.addChecker<MainCallChecker>("example.MainCallChecker",
50+
"Example Description");
5151
}
5252

5353
extern "C" const char clang_analyzerAPIVersionString[] =

clang/unittests/StaticAnalyzer/BlockEntranceCallbackTest.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,7 @@ void addBlockEntranceTester(AnalysisASTConsumer &AnalysisConsumer,
9191
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
9292
Registry.addChecker(&registerChecker<BlockEntranceCallbackTester>,
9393
&shouldAlwaysRegister, "test.BlockEntranceTester",
94-
"EmptyDescription", "EmptyDocsUri",
95-
/*IsHidden=*/false);
94+
"EmptyDescription");
9695
});
9796
}
9897

@@ -102,8 +101,7 @@ void addBranchConditionTester(AnalysisASTConsumer &AnalysisConsumer,
102101
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
103102
Registry.addChecker(&registerChecker<BranchConditionCallbackTester>,
104103
&shouldAlwaysRegister, "test.BranchConditionTester",
105-
"EmptyDescription", "EmptyDocsUri",
106-
/*IsHidden=*/false);
104+
"EmptyDescription");
107105
});
108106
}
109107

clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ class TestAction : public ASTFrontendAction {
119119
std::make_unique<VerifyPathDiagnosticConsumer>(
120120
std::move(ExpectedDiags), Compiler.getSourceManager()));
121121
AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
122-
Registry.addChecker<InterestingnessTestChecker>("test.Interestingness",
123-
"Description", "");
122+
Registry.addMockChecker<InterestingnessTestChecker>(
123+
"test.Interestingness");
124124
});
125125
Compiler.getAnalyzerOpts().CheckersAndPackages = {
126126
{"test.Interestingness", true}};

clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,8 +616,7 @@ void addCallDescChecker(AnalysisASTConsumer &AnalysisConsumer,
616616
AnalyzerOptions &AnOpts) {
617617
AnOpts.CheckersAndPackages = {{"test.CallDescChecker", true}};
618618
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
619-
Registry.addChecker<CallDescChecker>("test.CallDescChecker", "Description",
620-
"");
619+
Registry.addMockChecker<CallDescChecker>("test.CallDescChecker");
621620
});
622621
}
623622

clang/unittests/StaticAnalyzer/CallEventTest.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ void addCXXDeallocatorChecker(AnalysisASTConsumer &AnalysisConsumer,
5555
AnalyzerOptions &AnOpts) {
5656
AnOpts.CheckersAndPackages = {{"test.CXXDeallocator", true}};
5757
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
58-
Registry.addChecker<CXXDeallocatorChecker>("test.CXXDeallocator",
59-
"Description", "");
58+
Registry.addMockChecker<CXXDeallocatorChecker>("test.CXXDeallocator");
6059
});
6160
}
6261

clang/unittests/StaticAnalyzer/ConflictingEvalCallsTest.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,8 @@ void addEvalFooCheckers(AnalysisASTConsumer &AnalysisConsumer,
3333
AnOpts.CheckersAndPackages = {{"test.EvalFoo1", true},
3434
{"test.EvalFoo2", true}};
3535
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
36-
Registry.addChecker<EvalCallFoo1>("test.EvalFoo1", "EmptyDescription",
37-
"EmptyDocsUri");
38-
Registry.addChecker<EvalCallFoo2>("test.EvalFoo2", "EmptyDescription",
39-
"EmptyDocsUri");
36+
Registry.addMockChecker<EvalCallFoo1>("test.EvalFoo1");
37+
Registry.addMockChecker<EvalCallFoo2>("test.EvalFoo2");
4038
});
4139
}
4240
} // namespace

clang/unittests/StaticAnalyzer/ExprEngineVisitTest.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,26 +77,25 @@ void addExprEngineVisitPreChecker(AnalysisASTConsumer &AnalysisConsumer,
7777
AnalyzerOptions &AnOpts) {
7878
AnOpts.CheckersAndPackages = {{"ExprEngineVisitPreChecker", true}};
7979
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
80-
Registry.addChecker<ExprEngineVisitPreChecker>("ExprEngineVisitPreChecker",
81-
"Desc", "DocsURI");
80+
Registry.addMockChecker<ExprEngineVisitPreChecker>(
81+
"ExprEngineVisitPreChecker");
8282
});
8383
}
8484

8585
void addExprEngineVisitPostChecker(AnalysisASTConsumer &AnalysisConsumer,
8686
AnalyzerOptions &AnOpts) {
8787
AnOpts.CheckersAndPackages = {{"ExprEngineVisitPostChecker", true}};
8888
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
89-
Registry.addChecker<ExprEngineVisitPostChecker>(
90-
"ExprEngineVisitPostChecker", "Desc", "DocsURI");
89+
Registry.addMockChecker<ExprEngineVisitPostChecker>(
90+
"ExprEngineVisitPostChecker");
9191
});
9292
}
9393

9494
void addMemAccessChecker(AnalysisASTConsumer &AnalysisConsumer,
9595
AnalyzerOptions &AnOpts) {
9696
AnOpts.CheckersAndPackages = {{"MemAccessChecker", true}};
9797
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
98-
Registry.addChecker<MemAccessChecker>("MemAccessChecker", "Desc",
99-
"DocsURI");
98+
Registry.addMockChecker<MemAccessChecker>("MemAccessChecker");
10099
});
101100
}
102101

0 commit comments

Comments
 (0)