Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / unittests / StaticAnalyzer / RegisterCustomCheckersTest.cpp
blobd5c7a5c9bb8233a6a48409fa04b0f56b59b433d6
1 //===- unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp ------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "CheckerRegistration.h"
10 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
12 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
13 #include "clang/StaticAnalyzer/Core/Checker.h"
14 #include "clang/StaticAnalyzer/Core/CheckerRegistryData.h"
15 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
16 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
17 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
18 #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
19 #include "clang/Tooling/Tooling.h"
20 #include "llvm/Support/raw_ostream.h"
21 #include "gtest/gtest.h"
22 #include <memory>
24 namespace clang {
25 namespace ento {
26 namespace {
28 //===----------------------------------------------------------------------===//
29 // Just a minimal test for how checker registration works with statically
30 // linked, non TableGen generated checkers.
31 //===----------------------------------------------------------------------===//
33 class CustomChecker : public Checker<check::ASTCodeBody> {
34 public:
35 void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
36 BugReporter &BR) const {
37 BR.EmitBasicReport(D, this, "Custom diagnostic", categories::LogicError,
38 "Custom diagnostic description",
39 PathDiagnosticLocation(D, Mgr.getSourceManager()), {});
43 void addCustomChecker(AnalysisASTConsumer &AnalysisConsumer,
44 AnalyzerOptions &AnOpts) {
45 AnOpts.CheckersAndPackages = {{"test.CustomChecker", true}};
46 AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
47 Registry.addChecker<CustomChecker>("test.CustomChecker", "Description", "");
48 });
51 TEST(RegisterCustomCheckers, RegisterChecker) {
52 std::string Diags;
53 EXPECT_TRUE(runCheckerOnCode<addCustomChecker>("void f() {;}", Diags));
54 EXPECT_EQ(Diags, "test.CustomChecker: Custom diagnostic description\n");
57 //===----------------------------------------------------------------------===//
58 // Pretty much the same.
59 //===----------------------------------------------------------------------===//
61 class LocIncDecChecker : public Checker<check::Location> {
62 public:
63 void checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
64 CheckerContext &C) const {
65 const auto *UnaryOp = dyn_cast<UnaryOperator>(S);
66 if (UnaryOp && !IsLoad) {
67 EXPECT_FALSE(UnaryOp->isIncrementOp());
72 void addLocIncDecChecker(AnalysisASTConsumer &AnalysisConsumer,
73 AnalyzerOptions &AnOpts) {
74 AnOpts.CheckersAndPackages = {{"test.LocIncDecChecker", true}};
75 AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
76 Registry.addChecker<CustomChecker>("test.LocIncDecChecker", "Description",
77 "");
78 });
81 TEST(RegisterCustomCheckers, CheckLocationIncDec) {
82 EXPECT_TRUE(
83 runCheckerOnCode<addLocIncDecChecker>("void f() { int *p; (*p)++; }"));
86 //===----------------------------------------------------------------------===//
87 // Unsatisfied checker dependency
88 //===----------------------------------------------------------------------===//
90 class CheckerRegistrationOrderPrinter
91 : public Checker<check::PreStmt<DeclStmt>> {
92 std::unique_ptr<BugType> BT =
93 std::make_unique<BugType>(this, "Registration order");
95 public:
96 void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
97 ExplodedNode *N = nullptr;
98 N = C.generateErrorNode();
99 llvm::SmallString<200> Buf;
100 llvm::raw_svector_ostream OS(Buf);
101 C.getAnalysisManager()
102 .getCheckerManager()
103 ->getCheckerRegistryData()
104 .printEnabledCheckerList(OS);
105 // Strip a newline off.
106 auto R =
107 std::make_unique<PathSensitiveBugReport>(*BT, OS.str().drop_back(1), N);
108 C.emitReport(std::move(R));
112 void registerCheckerRegistrationOrderPrinter(CheckerManager &mgr) {
113 mgr.registerChecker<CheckerRegistrationOrderPrinter>();
116 bool shouldRegisterCheckerRegistrationOrderPrinter(const CheckerManager &mgr) {
117 return true;
120 void addCheckerRegistrationOrderPrinter(CheckerRegistry &Registry) {
121 Registry.addChecker(registerCheckerRegistrationOrderPrinter,
122 shouldRegisterCheckerRegistrationOrderPrinter,
123 "test.RegistrationOrder", "Description", "", false);
126 #define UNITTEST_CHECKER(CHECKER_NAME, DIAG_MSG) \
127 class CHECKER_NAME : public Checker<check::PreStmt<DeclStmt>> { \
128 std::unique_ptr<BugType> BT = std::make_unique<BugType>(this, DIAG_MSG); \
130 public: \
131 void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {} \
132 }; \
134 void register##CHECKER_NAME(CheckerManager &mgr) { \
135 mgr.registerChecker<CHECKER_NAME>(); \
138 bool shouldRegister##CHECKER_NAME(const CheckerManager &mgr) { \
139 return true; \
141 void add##CHECKER_NAME(CheckerRegistry &Registry) { \
142 Registry.addChecker(register##CHECKER_NAME, shouldRegister##CHECKER_NAME, \
143 "test." #CHECKER_NAME, "Description", "", false); \
146 UNITTEST_CHECKER(StrongDep, "Strong")
147 UNITTEST_CHECKER(Dep, "Dep")
149 bool shouldRegisterStrongFALSE(const CheckerManager &mgr) {
150 return false;
154 void addDep(AnalysisASTConsumer &AnalysisConsumer,
155 AnalyzerOptions &AnOpts) {
156 AnOpts.CheckersAndPackages = {{"test.Dep", true},
157 {"test.RegistrationOrder", true}};
158 AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
159 Registry.addChecker(registerStrongDep, shouldRegisterStrongFALSE,
160 "test.Strong", "Description", "", false);
161 addStrongDep(Registry);
162 addDep(Registry);
163 addCheckerRegistrationOrderPrinter(Registry);
164 Registry.addDependency("test.Dep", "test.Strong");
168 TEST(RegisterDeps, UnsatisfiedDependency) {
169 std::string Diags;
170 EXPECT_TRUE(runCheckerOnCode<addDep>("void f() {int i;}", Diags));
171 EXPECT_EQ(Diags, "test.RegistrationOrder: test.RegistrationOrder\n");
174 //===----------------------------------------------------------------------===//
175 // Weak checker dependencies.
176 //===----------------------------------------------------------------------===//
178 UNITTEST_CHECKER(WeakDep, "Weak")
180 void addWeakDepCheckerBothEnabled(AnalysisASTConsumer &AnalysisConsumer,
181 AnalyzerOptions &AnOpts) {
182 AnOpts.CheckersAndPackages = {{"test.Dep", true},
183 {"test.WeakDep", true},
184 {"test.RegistrationOrder", true}};
185 AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
186 addWeakDep(Registry);
187 addDep(Registry);
188 addCheckerRegistrationOrderPrinter(Registry);
189 Registry.addWeakDependency("test.Dep", "test.WeakDep");
193 void addWeakDepCheckerBothEnabledSwitched(AnalysisASTConsumer &AnalysisConsumer,
194 AnalyzerOptions &AnOpts) {
195 AnOpts.CheckersAndPackages = {{"test.Dep", true},
196 {"test.WeakDep", true},
197 {"test.RegistrationOrder", true}};
198 AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
199 addWeakDep(Registry);
200 addDep(Registry);
201 addCheckerRegistrationOrderPrinter(Registry);
202 Registry.addWeakDependency("test.WeakDep", "test.Dep");
206 void addWeakDepCheckerDepDisabled(AnalysisASTConsumer &AnalysisConsumer,
207 AnalyzerOptions &AnOpts) {
208 AnOpts.CheckersAndPackages = {{"test.Dep", true},
209 {"test.WeakDep", false},
210 {"test.RegistrationOrder", true}};
211 AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
212 addWeakDep(Registry);
213 addDep(Registry);
214 addCheckerRegistrationOrderPrinter(Registry);
215 Registry.addWeakDependency("test.Dep", "test.WeakDep");
219 void addWeakDepCheckerDepUnspecified(AnalysisASTConsumer &AnalysisConsumer,
220 AnalyzerOptions &AnOpts) {
221 AnOpts.CheckersAndPackages = {{"test.Dep", true},
222 {"test.RegistrationOrder", true}};
223 AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
224 addWeakDep(Registry);
225 addDep(Registry);
226 addCheckerRegistrationOrderPrinter(Registry);
227 Registry.addWeakDependency("test.Dep", "test.WeakDep");
231 UNITTEST_CHECKER(WeakDep2, "Weak2")
232 UNITTEST_CHECKER(Dep2, "Dep2")
234 void addWeakDepHasWeakDep(AnalysisASTConsumer &AnalysisConsumer,
235 AnalyzerOptions &AnOpts) {
236 AnOpts.CheckersAndPackages = {{"test.Dep", true},
237 {"test.WeakDep", true},
238 {"test.WeakDep2", true},
239 {"test.RegistrationOrder", true}};
240 AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
241 addStrongDep(Registry);
242 addWeakDep(Registry);
243 addWeakDep2(Registry);
244 addDep(Registry);
245 addDep2(Registry);
246 addCheckerRegistrationOrderPrinter(Registry);
247 Registry.addWeakDependency("test.Dep", "test.WeakDep");
248 Registry.addWeakDependency("test.WeakDep", "test.WeakDep2");
252 void addWeakDepTransitivity(AnalysisASTConsumer &AnalysisConsumer,
253 AnalyzerOptions &AnOpts) {
254 AnOpts.CheckersAndPackages = {{"test.Dep", true},
255 {"test.WeakDep", false},
256 {"test.WeakDep2", true},
257 {"test.RegistrationOrder", true}};
258 AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
259 addStrongDep(Registry);
260 addWeakDep(Registry);
261 addWeakDep2(Registry);
262 addDep(Registry);
263 addDep2(Registry);
264 addCheckerRegistrationOrderPrinter(Registry);
265 Registry.addWeakDependency("test.Dep", "test.WeakDep");
266 Registry.addWeakDependency("test.WeakDep", "test.WeakDep2");
270 TEST(RegisterDeps, SimpleWeakDependency) {
271 std::string Diags;
272 EXPECT_TRUE(runCheckerOnCode<addWeakDepCheckerBothEnabled>(
273 "void f() {int i;}", Diags));
274 EXPECT_EQ(Diags, "test.RegistrationOrder: test.WeakDep\ntest."
275 "Dep\ntest.RegistrationOrder\n");
276 Diags.clear();
278 // Mind that AnalyzerOption listed the enabled checker list in the same order,
279 // but the dependencies are switched.
280 EXPECT_TRUE(runCheckerOnCode<addWeakDepCheckerBothEnabledSwitched>(
281 "void f() {int i;}", Diags));
282 EXPECT_EQ(Diags, "test.RegistrationOrder: test.Dep\ntest."
283 "RegistrationOrder\ntest.WeakDep\n");
284 Diags.clear();
286 // Weak dependencies dont prevent dependent checkers from being enabled.
287 EXPECT_TRUE(runCheckerOnCode<addWeakDepCheckerDepDisabled>(
288 "void f() {int i;}", Diags));
289 EXPECT_EQ(Diags,
290 "test.RegistrationOrder: test.Dep\ntest.RegistrationOrder\n");
291 Diags.clear();
293 // Nor will they be enabled just because a dependent checker is.
294 EXPECT_TRUE(runCheckerOnCode<addWeakDepCheckerDepUnspecified>(
295 "void f() {int i;}", Diags));
296 EXPECT_EQ(Diags,
297 "test.RegistrationOrder: test.Dep\ntest.RegistrationOrder\n");
298 Diags.clear();
300 EXPECT_TRUE(
301 runCheckerOnCode<addWeakDepTransitivity>("void f() {int i;}", Diags));
302 EXPECT_EQ(Diags, "test.RegistrationOrder: test.WeakDep2\ntest."
303 "Dep\ntest.RegistrationOrder\n");
304 Diags.clear();
306 EXPECT_TRUE(
307 runCheckerOnCode<addWeakDepHasWeakDep>("void f() {int i;}", Diags));
308 EXPECT_EQ(Diags, "test.RegistrationOrder: test.WeakDep2\ntest."
309 "WeakDep\ntest.Dep\ntest.RegistrationOrder\n");
310 Diags.clear();
313 //===----------------------------------------------------------------------===//
314 // Interaction of weak and regular checker dependencies.
315 //===----------------------------------------------------------------------===//
317 void addWeakDepHasStrongDep(AnalysisASTConsumer &AnalysisConsumer,
318 AnalyzerOptions &AnOpts) {
319 AnOpts.CheckersAndPackages = {{"test.Dep", true},
320 {"test.StrongDep", true},
321 {"test.WeakDep", true},
322 {"test.RegistrationOrder", true}};
323 AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
324 addStrongDep(Registry);
325 addWeakDep(Registry);
326 addDep(Registry);
327 addCheckerRegistrationOrderPrinter(Registry);
328 Registry.addDependency("test.WeakDep", "test.StrongDep");
329 Registry.addWeakDependency("test.Dep", "test.WeakDep");
333 void addWeakDepAndStrongDep(AnalysisASTConsumer &AnalysisConsumer,
334 AnalyzerOptions &AnOpts) {
335 AnOpts.CheckersAndPackages = {{"test.Dep", true},
336 {"test.StrongDep", true},
337 {"test.WeakDep", true},
338 {"test.RegistrationOrder", true}};
339 AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
340 addStrongDep(Registry);
341 addWeakDep(Registry);
342 addDep(Registry);
343 addCheckerRegistrationOrderPrinter(Registry);
344 Registry.addDependency("test.Dep", "test.StrongDep");
345 Registry.addWeakDependency("test.Dep", "test.WeakDep");
349 void addDisabledWeakDepHasStrongDep(AnalysisASTConsumer &AnalysisConsumer,
350 AnalyzerOptions &AnOpts) {
351 AnOpts.CheckersAndPackages = {{"test.Dep", true},
352 {"test.StrongDep", true},
353 {"test.WeakDep", false},
354 {"test.RegistrationOrder", true}};
355 AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
356 addStrongDep(Registry);
357 addWeakDep(Registry);
358 addDep(Registry);
359 addCheckerRegistrationOrderPrinter(Registry);
360 Registry.addDependency("test.WeakDep", "test.StrongDep");
361 Registry.addWeakDependency("test.Dep", "test.WeakDep");
365 void addDisabledWeakDepHasUnspecifiedStrongDep(
366 AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) {
367 AnOpts.CheckersAndPackages = {{"test.Dep", true},
368 {"test.WeakDep", false},
369 {"test.RegistrationOrder", true}};
370 AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
371 addStrongDep(Registry);
372 addWeakDep(Registry);
373 addDep(Registry);
374 addCheckerRegistrationOrderPrinter(Registry);
375 Registry.addDependency("test.WeakDep", "test.StrongDep");
376 Registry.addWeakDependency("test.Dep", "test.WeakDep");
380 void addWeakDepHasDisabledStrongDep(AnalysisASTConsumer &AnalysisConsumer,
381 AnalyzerOptions &AnOpts) {
382 AnOpts.CheckersAndPackages = {{"test.Dep", true},
383 {"test.StrongDep", false},
384 {"test.WeakDep", true},
385 {"test.RegistrationOrder", true}};
386 AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
387 addStrongDep(Registry);
388 addWeakDep(Registry);
389 addDep(Registry);
390 addCheckerRegistrationOrderPrinter(Registry);
391 Registry.addDependency("test.WeakDep", "test.StrongDep");
392 Registry.addWeakDependency("test.Dep", "test.WeakDep");
396 void addWeakDepHasUnspecifiedButLaterEnabledStrongDep(
397 AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) {
398 AnOpts.CheckersAndPackages = {{"test.Dep", true},
399 {"test.Dep2", true},
400 {"test.WeakDep", true},
401 {"test.RegistrationOrder", true}};
402 AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
403 addStrongDep(Registry);
404 addWeakDep(Registry);
405 addDep(Registry);
406 addDep2(Registry);
407 addCheckerRegistrationOrderPrinter(Registry);
408 Registry.addDependency("test.WeakDep", "test.StrongDep");
409 Registry.addDependency("test.Dep2", "test.StrongDep");
410 Registry.addWeakDependency("test.Dep", "test.WeakDep");
414 TEST(RegisterDeps, DependencyInteraction) {
415 std::string Diags;
416 EXPECT_TRUE(
417 runCheckerOnCode<addWeakDepHasStrongDep>("void f() {int i;}", Diags));
418 EXPECT_EQ(Diags, "test.RegistrationOrder: test.StrongDep\ntest."
419 "WeakDep\ntest.Dep\ntest.RegistrationOrder\n");
420 Diags.clear();
422 // Weak dependencies are registered before strong dependencies. This is most
423 // important for purely diagnostic checkers that are implemented as a part of
424 // purely modeling checkers, becuse the checker callback order will have to be
425 // established in between the modeling portion and the weak dependency.
426 EXPECT_TRUE(
427 runCheckerOnCode<addWeakDepAndStrongDep>("void f() {int i;}", Diags));
428 EXPECT_EQ(Diags, "test.RegistrationOrder: test.WeakDep\ntest."
429 "StrongDep\ntest.Dep\ntest.RegistrationOrder\n");
430 Diags.clear();
432 // If a weak dependency is disabled, the checker itself can still be enabled.
433 EXPECT_TRUE(runCheckerOnCode<addDisabledWeakDepHasStrongDep>(
434 "void f() {int i;}", Diags));
435 EXPECT_EQ(Diags, "test.RegistrationOrder: test.Dep\ntest."
436 "RegistrationOrder\ntest.StrongDep\n");
437 Diags.clear();
439 // If a weak dependency is disabled, the checker itself can still be enabled,
440 // but it shouldn't enable a strong unspecified dependency.
441 EXPECT_TRUE(runCheckerOnCode<addDisabledWeakDepHasUnspecifiedStrongDep>(
442 "void f() {int i;}", Diags));
443 EXPECT_EQ(Diags,
444 "test.RegistrationOrder: test.Dep\ntest.RegistrationOrder\n");
445 Diags.clear();
447 // A strong dependency of a weak dependency is disabled, so neither of them
448 // should be enabled.
449 EXPECT_TRUE(runCheckerOnCode<addWeakDepHasDisabledStrongDep>(
450 "void f() {int i;}", Diags));
451 EXPECT_EQ(Diags,
452 "test.RegistrationOrder: test.Dep\ntest.RegistrationOrder\n");
453 Diags.clear();
455 EXPECT_TRUE(
456 runCheckerOnCode<addWeakDepHasUnspecifiedButLaterEnabledStrongDep>(
457 "void f() {int i;}", Diags));
458 EXPECT_EQ(Diags, "test.RegistrationOrder: test.StrongDep\ntest.WeakDep\ntest."
459 "Dep\ntest.Dep2\ntest.RegistrationOrder\n");
460 Diags.clear();
462 } // namespace
463 } // namespace ento
464 } // namespace clang