xref: /llvm-project/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp (revision 18f219c5ac8369ec3e46c4accbb19ca51dc8bc67)
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:
checkASTCodeBody(const Decl * D,AnalysisManager & Mgr,BugReporter & BR) const35   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 
addCustomChecker(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)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 
TEST(RegisterCustomCheckers,RegisterChecker)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:
checkLocation(SVal Loc,bool IsLoad,const Stmt * S,CheckerContext & C) const63   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 
addLocIncDecChecker(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)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 
TEST(RegisterCustomCheckers,CheckLocationIncDec)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   const BugType BT{this, "Registration order"};
93 
94 public:
checkPreStmt(const DeclStmt * DS,CheckerContext & C) const95   void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
96     ExplodedNode *N = nullptr;
97     N = C.generateErrorNode();
98     llvm::SmallString<200> Buf;
99     llvm::raw_svector_ostream OS(Buf);
100     C.getAnalysisManager()
101         .getCheckerManager()
102         ->getCheckerRegistryData()
103         .printEnabledCheckerList(OS);
104     // Strip a newline off.
105     auto R =
106         std::make_unique<PathSensitiveBugReport>(BT, OS.str().drop_back(1), N);
107     C.emitReport(std::move(R));
108   }
109 };
110 
registerCheckerRegistrationOrderPrinter(CheckerManager & mgr)111 void registerCheckerRegistrationOrderPrinter(CheckerManager &mgr) {
112   mgr.registerChecker<CheckerRegistrationOrderPrinter>();
113 }
114 
shouldRegisterCheckerRegistrationOrderPrinter(const CheckerManager & mgr)115 bool shouldRegisterCheckerRegistrationOrderPrinter(const CheckerManager &mgr) {
116   return true;
117 }
118 
addCheckerRegistrationOrderPrinter(CheckerRegistry & Registry)119 void addCheckerRegistrationOrderPrinter(CheckerRegistry &Registry) {
120   Registry.addChecker(registerCheckerRegistrationOrderPrinter,
121                       shouldRegisterCheckerRegistrationOrderPrinter,
122                       "test.RegistrationOrder", "Description", "", false);
123 }
124 
125 #define UNITTEST_CHECKER(CHECKER_NAME, DIAG_MSG)                               \
126   class CHECKER_NAME : public Checker<check::PreStmt<DeclStmt>> {              \
127   public:                                                                      \
128     void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {}          \
129   };                                                                           \
130                                                                                \
131   void register##CHECKER_NAME(CheckerManager &mgr) {                           \
132     mgr.registerChecker<CHECKER_NAME>();                                       \
133   }                                                                            \
134                                                                                \
135   bool shouldRegister##CHECKER_NAME(const CheckerManager &mgr) {               \
136     return true;                                                               \
137   }                                                                            \
138   void add##CHECKER_NAME(CheckerRegistry &Registry) {                          \
139     Registry.addChecker(register##CHECKER_NAME, shouldRegister##CHECKER_NAME,  \
140                         "test." #CHECKER_NAME, "Description", "", false);      \
141   }
142 
143 UNITTEST_CHECKER(StrongDep, "Strong")
144 UNITTEST_CHECKER(Dep, "Dep")
145 
shouldRegisterStrongFALSE(const CheckerManager & mgr)146 bool shouldRegisterStrongFALSE(const CheckerManager &mgr) {
147   return false;
148 }
149 
150 
addDep(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)151 void addDep(AnalysisASTConsumer &AnalysisConsumer,
152                   AnalyzerOptions &AnOpts) {
153   AnOpts.CheckersAndPackages = {{"test.Dep", true},
154                                 {"test.RegistrationOrder", true}};
155   AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
156     Registry.addChecker(registerStrongDep, shouldRegisterStrongFALSE,
157                         "test.Strong", "Description", "", false);
158     addStrongDep(Registry);
159     addDep(Registry);
160     addCheckerRegistrationOrderPrinter(Registry);
161     Registry.addDependency("test.Dep", "test.Strong");
162   });
163 }
164 
TEST(RegisterDeps,UnsatisfiedDependency)165 TEST(RegisterDeps, UnsatisfiedDependency) {
166   std::string Diags;
167   EXPECT_TRUE(runCheckerOnCode<addDep>("void f() {int i;}", Diags));
168   EXPECT_EQ(Diags, "test.RegistrationOrder: test.RegistrationOrder\n");
169 }
170 
171 //===----------------------------------------------------------------------===//
172 // Weak checker dependencies.
173 //===----------------------------------------------------------------------===//
174 
175 UNITTEST_CHECKER(WeakDep, "Weak")
176 
addWeakDepCheckerBothEnabled(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)177 void addWeakDepCheckerBothEnabled(AnalysisASTConsumer &AnalysisConsumer,
178                                   AnalyzerOptions &AnOpts) {
179   AnOpts.CheckersAndPackages = {{"test.Dep", true},
180                                 {"test.WeakDep", true},
181                                 {"test.RegistrationOrder", true}};
182   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
183     addWeakDep(Registry);
184     addDep(Registry);
185     addCheckerRegistrationOrderPrinter(Registry);
186     Registry.addWeakDependency("test.Dep", "test.WeakDep");
187   });
188 }
189 
addWeakDepCheckerBothEnabledSwitched(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)190 void addWeakDepCheckerBothEnabledSwitched(AnalysisASTConsumer &AnalysisConsumer,
191                                           AnalyzerOptions &AnOpts) {
192   AnOpts.CheckersAndPackages = {{"test.Dep", true},
193                                 {"test.WeakDep", true},
194                                 {"test.RegistrationOrder", true}};
195   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
196     addWeakDep(Registry);
197     addDep(Registry);
198     addCheckerRegistrationOrderPrinter(Registry);
199     Registry.addWeakDependency("test.WeakDep", "test.Dep");
200   });
201 }
202 
addWeakDepCheckerDepDisabled(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)203 void addWeakDepCheckerDepDisabled(AnalysisASTConsumer &AnalysisConsumer,
204                                   AnalyzerOptions &AnOpts) {
205   AnOpts.CheckersAndPackages = {{"test.Dep", true},
206                                 {"test.WeakDep", false},
207                                 {"test.RegistrationOrder", true}};
208   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
209     addWeakDep(Registry);
210     addDep(Registry);
211     addCheckerRegistrationOrderPrinter(Registry);
212     Registry.addWeakDependency("test.Dep", "test.WeakDep");
213   });
214 }
215 
addWeakDepCheckerDepUnspecified(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)216 void addWeakDepCheckerDepUnspecified(AnalysisASTConsumer &AnalysisConsumer,
217                                      AnalyzerOptions &AnOpts) {
218   AnOpts.CheckersAndPackages = {{"test.Dep", true},
219                                 {"test.RegistrationOrder", true}};
220   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
221     addWeakDep(Registry);
222     addDep(Registry);
223     addCheckerRegistrationOrderPrinter(Registry);
224     Registry.addWeakDependency("test.Dep", "test.WeakDep");
225   });
226 }
227 
228 UNITTEST_CHECKER(WeakDep2, "Weak2")
229 UNITTEST_CHECKER(Dep2, "Dep2")
230 
addWeakDepHasWeakDep(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)231 void addWeakDepHasWeakDep(AnalysisASTConsumer &AnalysisConsumer,
232                           AnalyzerOptions &AnOpts) {
233   AnOpts.CheckersAndPackages = {{"test.Dep", true},
234                                 {"test.WeakDep", true},
235                                 {"test.WeakDep2", true},
236                                 {"test.RegistrationOrder", true}};
237   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
238     addStrongDep(Registry);
239     addWeakDep(Registry);
240     addWeakDep2(Registry);
241     addDep(Registry);
242     addDep2(Registry);
243     addCheckerRegistrationOrderPrinter(Registry);
244     Registry.addWeakDependency("test.Dep", "test.WeakDep");
245     Registry.addWeakDependency("test.WeakDep", "test.WeakDep2");
246   });
247 }
248 
addWeakDepTransitivity(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)249 void addWeakDepTransitivity(AnalysisASTConsumer &AnalysisConsumer,
250                             AnalyzerOptions &AnOpts) {
251   AnOpts.CheckersAndPackages = {{"test.Dep", true},
252                                 {"test.WeakDep", false},
253                                 {"test.WeakDep2", true},
254                                 {"test.RegistrationOrder", true}};
255   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
256     addStrongDep(Registry);
257     addWeakDep(Registry);
258     addWeakDep2(Registry);
259     addDep(Registry);
260     addDep2(Registry);
261     addCheckerRegistrationOrderPrinter(Registry);
262     Registry.addWeakDependency("test.Dep", "test.WeakDep");
263     Registry.addWeakDependency("test.WeakDep", "test.WeakDep2");
264   });
265 }
266 
TEST(RegisterDeps,SimpleWeakDependency)267 TEST(RegisterDeps, SimpleWeakDependency) {
268   std::string Diags;
269   EXPECT_TRUE(runCheckerOnCode<addWeakDepCheckerBothEnabled>(
270       "void f() {int i;}", Diags));
271   EXPECT_EQ(Diags, "test.RegistrationOrder: test.WeakDep\ntest."
272                    "Dep\ntest.RegistrationOrder\n");
273   Diags.clear();
274 
275   // Mind that AnalyzerOption listed the enabled checker list in the same order,
276   // but the dependencies are switched.
277   EXPECT_TRUE(runCheckerOnCode<addWeakDepCheckerBothEnabledSwitched>(
278       "void f() {int i;}", Diags));
279   EXPECT_EQ(Diags, "test.RegistrationOrder: test.Dep\ntest."
280                    "RegistrationOrder\ntest.WeakDep\n");
281   Diags.clear();
282 
283   // Weak dependencies dont prevent dependent checkers from being enabled.
284   EXPECT_TRUE(runCheckerOnCode<addWeakDepCheckerDepDisabled>(
285       "void f() {int i;}", Diags));
286   EXPECT_EQ(Diags,
287             "test.RegistrationOrder: test.Dep\ntest.RegistrationOrder\n");
288   Diags.clear();
289 
290   // Nor will they be enabled just because a dependent checker is.
291   EXPECT_TRUE(runCheckerOnCode<addWeakDepCheckerDepUnspecified>(
292       "void f() {int i;}", Diags));
293   EXPECT_EQ(Diags,
294             "test.RegistrationOrder: test.Dep\ntest.RegistrationOrder\n");
295   Diags.clear();
296 
297   EXPECT_TRUE(
298       runCheckerOnCode<addWeakDepTransitivity>("void f() {int i;}", Diags));
299   EXPECT_EQ(Diags, "test.RegistrationOrder: test.WeakDep2\ntest."
300                    "Dep\ntest.RegistrationOrder\n");
301   Diags.clear();
302 
303   EXPECT_TRUE(
304       runCheckerOnCode<addWeakDepHasWeakDep>("void f() {int i;}", Diags));
305   EXPECT_EQ(Diags, "test.RegistrationOrder: test.WeakDep2\ntest."
306                    "WeakDep\ntest.Dep\ntest.RegistrationOrder\n");
307   Diags.clear();
308 }
309 
310 //===----------------------------------------------------------------------===//
311 // Interaction of weak and regular checker dependencies.
312 //===----------------------------------------------------------------------===//
313 
addWeakDepHasStrongDep(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)314 void addWeakDepHasStrongDep(AnalysisASTConsumer &AnalysisConsumer,
315                             AnalyzerOptions &AnOpts) {
316   AnOpts.CheckersAndPackages = {{"test.Dep", true},
317                                 {"test.StrongDep", true},
318                                 {"test.WeakDep", true},
319                                 {"test.RegistrationOrder", true}};
320   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
321     addStrongDep(Registry);
322     addWeakDep(Registry);
323     addDep(Registry);
324     addCheckerRegistrationOrderPrinter(Registry);
325     Registry.addDependency("test.WeakDep", "test.StrongDep");
326     Registry.addWeakDependency("test.Dep", "test.WeakDep");
327   });
328 }
329 
addWeakDepAndStrongDep(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)330 void addWeakDepAndStrongDep(AnalysisASTConsumer &AnalysisConsumer,
331                             AnalyzerOptions &AnOpts) {
332   AnOpts.CheckersAndPackages = {{"test.Dep", true},
333                                 {"test.StrongDep", true},
334                                 {"test.WeakDep", true},
335                                 {"test.RegistrationOrder", true}};
336   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
337     addStrongDep(Registry);
338     addWeakDep(Registry);
339     addDep(Registry);
340     addCheckerRegistrationOrderPrinter(Registry);
341     Registry.addDependency("test.Dep", "test.StrongDep");
342     Registry.addWeakDependency("test.Dep", "test.WeakDep");
343   });
344 }
345 
addDisabledWeakDepHasStrongDep(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)346 void addDisabledWeakDepHasStrongDep(AnalysisASTConsumer &AnalysisConsumer,
347                                     AnalyzerOptions &AnOpts) {
348   AnOpts.CheckersAndPackages = {{"test.Dep", true},
349                                 {"test.StrongDep", true},
350                                 {"test.WeakDep", false},
351                                 {"test.RegistrationOrder", true}};
352   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
353     addStrongDep(Registry);
354     addWeakDep(Registry);
355     addDep(Registry);
356     addCheckerRegistrationOrderPrinter(Registry);
357     Registry.addDependency("test.WeakDep", "test.StrongDep");
358     Registry.addWeakDependency("test.Dep", "test.WeakDep");
359   });
360 }
361 
addDisabledWeakDepHasUnspecifiedStrongDep(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)362 void addDisabledWeakDepHasUnspecifiedStrongDep(
363     AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) {
364   AnOpts.CheckersAndPackages = {{"test.Dep", true},
365                                 {"test.WeakDep", false},
366                                 {"test.RegistrationOrder", true}};
367   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
368     addStrongDep(Registry);
369     addWeakDep(Registry);
370     addDep(Registry);
371     addCheckerRegistrationOrderPrinter(Registry);
372     Registry.addDependency("test.WeakDep", "test.StrongDep");
373     Registry.addWeakDependency("test.Dep", "test.WeakDep");
374   });
375 }
376 
addWeakDepHasDisabledStrongDep(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)377 void addWeakDepHasDisabledStrongDep(AnalysisASTConsumer &AnalysisConsumer,
378                                     AnalyzerOptions &AnOpts) {
379   AnOpts.CheckersAndPackages = {{"test.Dep", true},
380                                 {"test.StrongDep", false},
381                                 {"test.WeakDep", true},
382                                 {"test.RegistrationOrder", true}};
383   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
384     addStrongDep(Registry);
385     addWeakDep(Registry);
386     addDep(Registry);
387     addCheckerRegistrationOrderPrinter(Registry);
388     Registry.addDependency("test.WeakDep", "test.StrongDep");
389     Registry.addWeakDependency("test.Dep", "test.WeakDep");
390   });
391 }
392 
addWeakDepHasUnspecifiedButLaterEnabledStrongDep(AnalysisASTConsumer & AnalysisConsumer,AnalyzerOptions & AnOpts)393 void addWeakDepHasUnspecifiedButLaterEnabledStrongDep(
394     AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) {
395   AnOpts.CheckersAndPackages = {{"test.Dep", true},
396                                 {"test.Dep2", true},
397                                 {"test.WeakDep", true},
398                                 {"test.RegistrationOrder", true}};
399   AnalysisConsumer.AddCheckerRegistrationFn([=](CheckerRegistry &Registry) {
400     addStrongDep(Registry);
401     addWeakDep(Registry);
402     addDep(Registry);
403     addDep2(Registry);
404     addCheckerRegistrationOrderPrinter(Registry);
405     Registry.addDependency("test.WeakDep", "test.StrongDep");
406     Registry.addDependency("test.Dep2", "test.StrongDep");
407     Registry.addWeakDependency("test.Dep", "test.WeakDep");
408   });
409 }
410 
TEST(RegisterDeps,DependencyInteraction)411 TEST(RegisterDeps, DependencyInteraction) {
412   std::string Diags;
413   EXPECT_TRUE(
414       runCheckerOnCode<addWeakDepHasStrongDep>("void f() {int i;}", Diags));
415   EXPECT_EQ(Diags, "test.RegistrationOrder: test.StrongDep\ntest."
416                    "WeakDep\ntest.Dep\ntest.RegistrationOrder\n");
417   Diags.clear();
418 
419   // Weak dependencies are registered before strong dependencies. This is most
420   // important for purely diagnostic checkers that are implemented as a part of
421   // purely modeling checkers, becuse the checker callback order will have to be
422   // established in between the modeling portion and the weak dependency.
423   EXPECT_TRUE(
424       runCheckerOnCode<addWeakDepAndStrongDep>("void f() {int i;}", Diags));
425   EXPECT_EQ(Diags, "test.RegistrationOrder: test.WeakDep\ntest."
426                    "StrongDep\ntest.Dep\ntest.RegistrationOrder\n");
427   Diags.clear();
428 
429   // If a weak dependency is disabled, the checker itself can still be enabled.
430   EXPECT_TRUE(runCheckerOnCode<addDisabledWeakDepHasStrongDep>(
431       "void f() {int i;}", Diags));
432   EXPECT_EQ(Diags, "test.RegistrationOrder: test.Dep\ntest."
433                    "RegistrationOrder\ntest.StrongDep\n");
434   Diags.clear();
435 
436   // If a weak dependency is disabled, the checker itself can still be enabled,
437   // but it shouldn't enable a strong unspecified dependency.
438   EXPECT_TRUE(runCheckerOnCode<addDisabledWeakDepHasUnspecifiedStrongDep>(
439       "void f() {int i;}", Diags));
440   EXPECT_EQ(Diags,
441             "test.RegistrationOrder: test.Dep\ntest.RegistrationOrder\n");
442   Diags.clear();
443 
444   // A strong dependency of a weak dependency is disabled, so neither of them
445   // should be enabled.
446   EXPECT_TRUE(runCheckerOnCode<addWeakDepHasDisabledStrongDep>(
447       "void f() {int i;}", Diags));
448   EXPECT_EQ(Diags,
449             "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