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