Skip to content

Commit a807e8e

Browse files
authored
[analyzer] Prettify checker registration and unittest code (#147797)
This commit tweaks the interface of `CheckerRegistry::addChecker` to make it more practical for plugins and tests: - The parameter `IsHidden` now defaults to `false` even in the non-templated overload (because setting it to true is unusual, especially in plugins). - The parameter `DocsUri` defaults to the dummy placeholder string `"NoDocsUri"` because (as of now) nothing queries its value 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 demand specifying this value. In addition to propagating these changes, this commit clarifies, corrects and extends lots of comments and performs various minor code quality improvements in the code of unit tests 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 #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 analyzer will be compatible with plugins that rely on the default argument values and don't specify `IsHidden` or `DocsUri`. (But existing plugin code will remain valid as well.)
1 parent f78c4ce commit a807e8e

18 files changed

+90
-96
lines changed

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

Lines changed: 29 additions & 34 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 overload 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;
@@ -108,30 +108,25 @@ class CheckerRegistry {
108108
mgr.template registerChecker<T>();
109109
}
110110

111-
template <typename T> static bool returnTrue(const CheckerManager &mgr) {
112-
return true;
113-
}
111+
static bool returnTrue(const CheckerManager &) { return true; }
114112

115113
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,
119-
StringRef FullName, StringRef Desc, StringRef DocsUri,
120-
bool IsHidden);
121-
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.
114+
/// Adds a checker to the registry.
115+
/// Use this for a checker defined in a plugin if it requires custom
116+
/// registration functions (e.g. for handling checker options).
117+
/// NOTE: As of now `DocsUri` is never queried from the checker registry.
118+
void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction Sfn,
119+
StringRef FullName, StringRef Desc,
120+
StringRef DocsUri = "NoDocsUri", bool IsHidden = false);
121+
122+
/// Adds a checker to the registry.
123+
/// Use this for a checker defined in a plugin if it doesn't require custom
124+
/// registration functions.
127125
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
126+
void addChecker(StringRef FullName, StringRef Desc,
127+
StringRef DocsUri = "NoDocsUri", bool IsHidden = false) {
132128
addChecker(&CheckerRegistry::initializeManager<CheckerManager, T>,
133-
&CheckerRegistry::returnTrue<T>, FullName, Desc, DocsUri,
134-
IsHidden);
129+
&CheckerRegistry::returnTrue, FullName, Desc, DocsUri, IsHidden);
135130
}
136131

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

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

Lines changed: 8 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,12 @@ 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.addChecker<Dependency>("example.Dependency", "MockDescription");
23+
Registry.addChecker<DependendentChecker>("example.DependendentChecker",
24+
"MockDescription");
2225

23-
registry.addDependency("example.DependendentChecker", "example.Dependency");
26+
Registry.addDependency("example.DependendentChecker", "example.Dependency");
2427
}
2528

2629
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+
const 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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class TestAction : public ASTFrontendAction {
120120
std::move(ExpectedDiags), Compiler.getSourceManager()));
121121
AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
122122
Registry.addChecker<InterestingnessTestChecker>("test.Interestingness",
123-
"Description", "");
123+
"MockDescription");
124124
});
125125
Compiler.getAnalyzerOpts().CheckersAndPackages = {
126126
{"test.Interestingness", true}};

clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,8 +616,8 @@ 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.addChecker<CallDescChecker>("test.CallDescChecker",
620+
"MockDescription");
621621
});
622622
}
623623

clang/unittests/StaticAnalyzer/CallEventTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ void addCXXDeallocatorChecker(AnalysisASTConsumer &AnalysisConsumer,
5656
AnOpts.CheckersAndPackages = {{"test.CXXDeallocator", true}};
5757
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
5858
Registry.addChecker<CXXDeallocatorChecker>("test.CXXDeallocator",
59-
"Description", "");
59+
"MockDescription");
6060
});
6161
}
6262

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.addChecker<EvalCallFoo1>("test.EvalFoo1", "MockDescription");
37+
Registry.addChecker<EvalCallFoo2>("test.EvalFoo2", "MockDescription");
4038
});
4139
}
4240
} // namespace

clang/unittests/StaticAnalyzer/ExprEngineVisitTest.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ void addExprEngineVisitPreChecker(AnalysisASTConsumer &AnalysisConsumer,
7878
AnOpts.CheckersAndPackages = {{"ExprEngineVisitPreChecker", true}};
7979
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
8080
Registry.addChecker<ExprEngineVisitPreChecker>("ExprEngineVisitPreChecker",
81-
"Desc", "DocsURI");
81+
"MockDescription");
8282
});
8383
}
8484

@@ -87,16 +87,16 @@ void addExprEngineVisitPostChecker(AnalysisASTConsumer &AnalysisConsumer,
8787
AnOpts.CheckersAndPackages = {{"ExprEngineVisitPostChecker", true}};
8888
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
8989
Registry.addChecker<ExprEngineVisitPostChecker>(
90-
"ExprEngineVisitPostChecker", "Desc", "DocsURI");
90+
"ExprEngineVisitPostChecker", "MockDescription");
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.addChecker<MemAccessChecker>("MemAccessChecker",
99+
"MockDescription");
100100
});
101101
}
102102

0 commit comments

Comments
 (0)