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 //===----------------------------------------------------------------------===//
8 
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>
23 
24 namespace clang {
25 namespace ento {
26 namespace {
27 
28 //===----------------------------------------------------------------------===//
29 // Just a minimal test for how checker registration works with statically
30 // linked, non TableGen generated checkers.
31 //===----------------------------------------------------------------------===//
32 
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()), {});
40   }
41 };
42 
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   });
49 }
50 
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");
55 }
56 
57 //===----------------------------------------------------------------------===//
58 // Pretty much the same.
59 //===----------------------------------------------------------------------===//
60 
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());
68     }
69   }
70 };
71 
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   });
79 }
80 
81 TEST(RegisterCustomCheckers, CheckLocationIncDec) {
82   EXPECT_TRUE(
83       runCheckerOnCode<addLocIncDecChecker>("void f() { int *p; (*p)++; }"));
84 }
85 
86 //===----------------------------------------------------------------------===//
87 // Unsatisfied checker dependency
88 //===----------------------------------------------------------------------===//
89 
90 class CheckerRegistrationOrderPrinter
91     : public Checker<check::PreStmt<DeclStmt>> {
92   std::unique_ptr<BuiltinBug> BT =
93       std::make_unique<BuiltinBug>(this, "Registration order");
94 
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));
109   }
110 };
111 
112 void registerCheckerRegistrationOrderPrinter(CheckerManager &mgr) {
113   mgr.registerChecker<CheckerRegistrationOrderPrinter>();
114 }
115 
116 bool shouldRegisterCheckerRegistrationOrderPrinter(const CheckerManager &mgr) {
117   return true;
118 }
119 
120 void addCheckerRegistrationOrderPrinter(CheckerRegistry &Registry) {
121   Registry.addChecker(registerCheckerRegistrationOrderPrinter,
122                       shouldRegisterCheckerRegistrationOrderPrinter,
123                       "test.RegistrationOrder", "Description", "", false);
124 }
125 
126 #define UNITTEST_CHECKER(CHECKER_NAME, DIAG_MSG)                               \
127   class CHECKER_NAME : public Checker<check::PreStmt<DeclStmt>> {              \
128     std::unique_ptr<BuiltinBug> BT =                                           \
129         std::make_unique<BuiltinBug>(this, DIAG_MSG);                          \
130                                                                                \
131   public:                                                                      \
132     void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {}          \
133   };                                                                           \
134                                                                                \
135   void register##CHECKER_NAME(CheckerManager &mgr) {                           \
136     mgr.registerChecker<CHECKER_NAME>();                                       \
137   }                                                                            \
138                                                                                \
139   bool shouldRegister##CHECKER_NAME(const CheckerManager &mgr) {               \
140     return true;                                                               \
141   }                                                                            \
142   void add##CHECKER_NAME(CheckerRegistry &Registry) {                          \
143     Registry.addChecker(register##CHECKER_NAME, shouldRegister##CHECKER_NAME,  \
144                         "test." #CHECKER_NAME, "Description", "", false);      \
145   }
146 
147 UNITTEST_CHECKER(StrongDep, "Strong")
148 UNITTEST_CHECKER(Dep, "Dep")
149 
150 bool shouldRegisterStrongFALSE(const CheckerManager &mgr) {
151   return false;
152 }
153 
154 
155 void addDep(AnalysisASTConsumer &AnalysisConsumer,
156                   AnalyzerOptions &AnOpts) {
157   AnOpts.CheckersAndPackages = {{"test.Dep", true},
158                                 {"test.RegistrationOrder", true}};
159   AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
160     Registry.addChecker(registerStrongDep, shouldRegisterStrongFALSE,
161                         "test.Strong", "Description", "", false);
162     addStrongDep(Registry);
163     addDep(Registry);
164     addCheckerRegistrationOrderPrinter(Registry);
165     Registry.addDependency("test.Dep", "test.Strong");
166   });
167 }
168 
169 TEST(RegisterDeps, UnsatisfiedDependency) {
170   std::string Diags;
171   EXPECT_TRUE(runCheckerOnCode<addDep>("void f() {int i;}", Diags));
172   EXPECT_EQ(Diags, "test.RegistrationOrder:test.RegistrationOrder\n");
173 }
174 
175 //===----------------------------------------------------------------------===//
176 // Weak checker dependencies.
177 //===----------------------------------------------------------------------===//
178 
179 UNITTEST_CHECKER(WeakDep, "Weak")
180 
181 void addWeakDepCheckerBothEnabled(AnalysisASTConsumer &AnalysisConsumer,
182                                   AnalyzerOptions &AnOpts) {
183   AnOpts.CheckersAndPackages = {{"test.Dep", true},
184                                 {"test.WeakDep", true},
185                                 {"test.RegistrationOrder", true}};
186   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
187     addWeakDep(Registry);
188     addDep(Registry);
189     addCheckerRegistrationOrderPrinter(Registry);
190     Registry.addWeakDependency("test.Dep", "test.WeakDep");
191   });
192 }
193 
194 void addWeakDepCheckerBothEnabledSwitched(AnalysisASTConsumer &AnalysisConsumer,
195                                           AnalyzerOptions &AnOpts) {
196   AnOpts.CheckersAndPackages = {{"test.Dep", true},
197                                 {"test.WeakDep", true},
198                                 {"test.RegistrationOrder", true}};
199   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
200     addWeakDep(Registry);
201     addDep(Registry);
202     addCheckerRegistrationOrderPrinter(Registry);
203     Registry.addWeakDependency("test.WeakDep", "test.Dep");
204   });
205 }
206 
207 void addWeakDepCheckerDepDisabled(AnalysisASTConsumer &AnalysisConsumer,
208                                   AnalyzerOptions &AnOpts) {
209   AnOpts.CheckersAndPackages = {{"test.Dep", true},
210                                 {"test.WeakDep", false},
211                                 {"test.RegistrationOrder", true}};
212   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
213     addWeakDep(Registry);
214     addDep(Registry);
215     addCheckerRegistrationOrderPrinter(Registry);
216     Registry.addWeakDependency("test.Dep", "test.WeakDep");
217   });
218 }
219 
220 void addWeakDepCheckerDepUnspecified(AnalysisASTConsumer &AnalysisConsumer,
221                                      AnalyzerOptions &AnOpts) {
222   AnOpts.CheckersAndPackages = {{"test.Dep", true},
223                                 {"test.RegistrationOrder", true}};
224   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
225     addWeakDep(Registry);
226     addDep(Registry);
227     addCheckerRegistrationOrderPrinter(Registry);
228     Registry.addWeakDependency("test.Dep", "test.WeakDep");
229   });
230 }
231 
232 UNITTEST_CHECKER(WeakDep2, "Weak2")
233 UNITTEST_CHECKER(Dep2, "Dep2")
234 
235 void addWeakDepHasWeakDep(AnalysisASTConsumer &AnalysisConsumer,
236                           AnalyzerOptions &AnOpts) {
237   AnOpts.CheckersAndPackages = {{"test.Dep", true},
238                                 {"test.WeakDep", true},
239                                 {"test.WeakDep2", true},
240                                 {"test.RegistrationOrder", true}};
241   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
242     addStrongDep(Registry);
243     addWeakDep(Registry);
244     addWeakDep2(Registry);
245     addDep(Registry);
246     addDep2(Registry);
247     addCheckerRegistrationOrderPrinter(Registry);
248     Registry.addWeakDependency("test.Dep", "test.WeakDep");
249     Registry.addWeakDependency("test.WeakDep", "test.WeakDep2");
250   });
251 }
252 
253 void addWeakDepTransitivity(AnalysisASTConsumer &AnalysisConsumer,
254                             AnalyzerOptions &AnOpts) {
255   AnOpts.CheckersAndPackages = {{"test.Dep", true},
256                                 {"test.WeakDep", false},
257                                 {"test.WeakDep2", true},
258                                 {"test.RegistrationOrder", true}};
259   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
260     addStrongDep(Registry);
261     addWeakDep(Registry);
262     addWeakDep2(Registry);
263     addDep(Registry);
264     addDep2(Registry);
265     addCheckerRegistrationOrderPrinter(Registry);
266     Registry.addWeakDependency("test.Dep", "test.WeakDep");
267     Registry.addWeakDependency("test.WeakDep", "test.WeakDep2");
268   });
269 }
270 
271 TEST(RegisterDeps, SimpleWeakDependency) {
272   std::string Diags;
273   EXPECT_TRUE(runCheckerOnCode<addWeakDepCheckerBothEnabled>(
274       "void f() {int i;}", Diags));
275   EXPECT_EQ(Diags, "test.RegistrationOrder:test.WeakDep\ntest."
276                    "Dep\ntest.RegistrationOrder\n");
277   Diags.clear();
278 
279   // Mind that AnalyzerOption listed the enabled checker list in the same order,
280   // but the dependencies are switched.
281   EXPECT_TRUE(runCheckerOnCode<addWeakDepCheckerBothEnabledSwitched>(
282       "void f() {int i;}", Diags));
283   EXPECT_EQ(Diags, "test.RegistrationOrder:test.Dep\ntest."
284                    "RegistrationOrder\ntest.WeakDep\n");
285   Diags.clear();
286 
287   // Weak dependencies dont prevent dependent checkers from being enabled.
288   EXPECT_TRUE(runCheckerOnCode<addWeakDepCheckerDepDisabled>(
289       "void f() {int i;}", Diags));
290   EXPECT_EQ(Diags, "test.RegistrationOrder:test.Dep\ntest.RegistrationOrder\n");
291   Diags.clear();
292 
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, "test.RegistrationOrder:test.Dep\ntest.RegistrationOrder\n");
297   Diags.clear();
298 
299   EXPECT_TRUE(
300       runCheckerOnCode<addWeakDepTransitivity>("void f() {int i;}", Diags));
301   EXPECT_EQ(Diags, "test.RegistrationOrder:test.WeakDep2\ntest."
302                    "Dep\ntest.RegistrationOrder\n");
303   Diags.clear();
304 
305   EXPECT_TRUE(
306       runCheckerOnCode<addWeakDepHasWeakDep>("void f() {int i;}", Diags));
307   EXPECT_EQ(Diags, "test.RegistrationOrder:test.WeakDep2\ntest."
308                    "WeakDep\ntest.Dep\ntest.RegistrationOrder\n");
309   Diags.clear();
310 }
311 
312 //===----------------------------------------------------------------------===//
313 // Interaction of weak and regular checker dependencies.
314 //===----------------------------------------------------------------------===//
315 
316 void addWeakDepHasStrongDep(AnalysisASTConsumer &AnalysisConsumer,
317                             AnalyzerOptions &AnOpts) {
318   AnOpts.CheckersAndPackages = {{"test.Dep", true},
319                                 {"test.StrongDep", true},
320                                 {"test.WeakDep", true},
321                                 {"test.RegistrationOrder", true}};
322   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
323     addStrongDep(Registry);
324     addWeakDep(Registry);
325     addDep(Registry);
326     addCheckerRegistrationOrderPrinter(Registry);
327     Registry.addDependency("test.WeakDep", "test.StrongDep");
328     Registry.addWeakDependency("test.Dep", "test.WeakDep");
329   });
330 }
331 
332 void addWeakDepAndStrongDep(AnalysisASTConsumer &AnalysisConsumer,
333                             AnalyzerOptions &AnOpts) {
334   AnOpts.CheckersAndPackages = {{"test.Dep", true},
335                                 {"test.StrongDep", true},
336                                 {"test.WeakDep", true},
337                                 {"test.RegistrationOrder", true}};
338   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
339     addStrongDep(Registry);
340     addWeakDep(Registry);
341     addDep(Registry);
342     addCheckerRegistrationOrderPrinter(Registry);
343     Registry.addDependency("test.Dep", "test.StrongDep");
344     Registry.addWeakDependency("test.Dep", "test.WeakDep");
345   });
346 }
347 
348 void addDisabledWeakDepHasStrongDep(AnalysisASTConsumer &AnalysisConsumer,
349                                     AnalyzerOptions &AnOpts) {
350   AnOpts.CheckersAndPackages = {{"test.Dep", true},
351                                 {"test.StrongDep", true},
352                                 {"test.WeakDep", false},
353                                 {"test.RegistrationOrder", true}};
354   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
355     addStrongDep(Registry);
356     addWeakDep(Registry);
357     addDep(Registry);
358     addCheckerRegistrationOrderPrinter(Registry);
359     Registry.addDependency("test.WeakDep", "test.StrongDep");
360     Registry.addWeakDependency("test.Dep", "test.WeakDep");
361   });
362 }
363 
364 void addDisabledWeakDepHasUnspecifiedStrongDep(
365     AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) {
366   AnOpts.CheckersAndPackages = {{"test.Dep", true},
367                                 {"test.WeakDep", false},
368                                 {"test.RegistrationOrder", true}};
369   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
370     addStrongDep(Registry);
371     addWeakDep(Registry);
372     addDep(Registry);
373     addCheckerRegistrationOrderPrinter(Registry);
374     Registry.addDependency("test.WeakDep", "test.StrongDep");
375     Registry.addWeakDependency("test.Dep", "test.WeakDep");
376   });
377 }
378 
379 void addWeakDepHasDisabledStrongDep(AnalysisASTConsumer &AnalysisConsumer,
380                                     AnalyzerOptions &AnOpts) {
381   AnOpts.CheckersAndPackages = {{"test.Dep", true},
382                                 {"test.StrongDep", false},
383                                 {"test.WeakDep", true},
384                                 {"test.RegistrationOrder", true}};
385   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
386     addStrongDep(Registry);
387     addWeakDep(Registry);
388     addDep(Registry);
389     addCheckerRegistrationOrderPrinter(Registry);
390     Registry.addDependency("test.WeakDep", "test.StrongDep");
391     Registry.addWeakDependency("test.Dep", "test.WeakDep");
392   });
393 }
394 
395 void addWeakDepHasUnspecifiedButLaterEnabledStrongDep(
396     AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) {
397   AnOpts.CheckersAndPackages = {{"test.Dep", true},
398                                 {"test.Dep2", true},
399                                 {"test.WeakDep", true},
400                                 {"test.RegistrationOrder", true}};
401   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
402     addStrongDep(Registry);
403     addWeakDep(Registry);
404     addDep(Registry);
405     addDep2(Registry);
406     addCheckerRegistrationOrderPrinter(Registry);
407     Registry.addDependency("test.WeakDep", "test.StrongDep");
408     Registry.addDependency("test.Dep2", "test.StrongDep");
409     Registry.addWeakDependency("test.Dep", "test.WeakDep");
410   });
411 }
412 
413 TEST(RegisterDeps, DependencyInteraction) {
414   std::string Diags;
415   EXPECT_TRUE(
416       runCheckerOnCode<addWeakDepHasStrongDep>("void f() {int i;}", Diags));
417   EXPECT_EQ(Diags, "test.RegistrationOrder:test.StrongDep\ntest."
418                    "WeakDep\ntest.Dep\ntest.RegistrationOrder\n");
419   Diags.clear();
420 
421   // Weak dependencies are registered before strong dependencies. This is most
422   // important for purely diagnostic checkers that are implemented as a part of
423   // purely modeling checkers, becuse the checker callback order will have to be
424   // established in between the modeling portion and the weak dependency.
425   EXPECT_TRUE(
426       runCheckerOnCode<addWeakDepAndStrongDep>("void f() {int i;}", Diags));
427   EXPECT_EQ(Diags, "test.RegistrationOrder:test.WeakDep\ntest."
428                    "StrongDep\ntest.Dep\ntest.RegistrationOrder\n");
429   Diags.clear();
430 
431   // If a weak dependency is disabled, the checker itself can still be enabled.
432   EXPECT_TRUE(runCheckerOnCode<addDisabledWeakDepHasStrongDep>(
433       "void f() {int i;}", Diags));
434   EXPECT_EQ(Diags, "test.RegistrationOrder:test.Dep\ntest."
435                    "RegistrationOrder\ntest.StrongDep\n");
436   Diags.clear();
437 
438   // If a weak dependency is disabled, the checker itself can still be enabled,
439   // but it shouldn't enable a strong unspecified dependency.
440   EXPECT_TRUE(runCheckerOnCode<addDisabledWeakDepHasUnspecifiedStrongDep>(
441       "void f() {int i;}", Diags));
442   EXPECT_EQ(Diags, "test.RegistrationOrder:test.Dep\ntest.RegistrationOrder\n");
443   Diags.clear();
444 
445   // A strong dependency of a weak dependency is disabled, so neither of them
446   // should be enabled.
447   EXPECT_TRUE(runCheckerOnCode<addWeakDepHasDisabledStrongDep>(
448       "void f() {int i;}", Diags));
449   EXPECT_EQ(Diags, "test.RegistrationOrder:test.Dep\ntest.RegistrationOrder\n");
450   Diags.clear();
451 
452   EXPECT_TRUE(
453       runCheckerOnCode<addWeakDepHasUnspecifiedButLaterEnabledStrongDep>(
454           "void f() {int i;}", Diags));
455   EXPECT_EQ(Diags, "test.RegistrationOrder:test.StrongDep\ntest.WeakDep\ntest."
456                    "Dep\ntest.Dep2\ntest.RegistrationOrder\n");
457   Diags.clear();
458 }
459 } // namespace
460 } // namespace ento
461 } // namespace clang
462