brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.7 KiB · e17d107 Raw
462 lines · cpp
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-exception6//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 24namespace clang {25namespace ento {26namespace {27 28//===----------------------------------------------------------------------===//29// Just a minimal test for how checker registration works with statically30// linked, non TableGen generated checkers.31//===----------------------------------------------------------------------===//32 33class CustomChecker : public Checker<check::ASTCodeBody> {34public: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 43void addCustomChecker(AnalysisASTConsumer &AnalysisConsumer,44                      AnalyzerOptions &AnOpts) {45  AnOpts.CheckersAndPackages = {{"test.CustomChecker", true}};46  AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {47    Registry.addChecker<CustomChecker>("test.CustomChecker", "MockDescription");48  });49}50 51TEST(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 61class LocIncDecChecker : public Checker<check::Location> {62public: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 72void addLocIncDecChecker(AnalysisASTConsumer &AnalysisConsumer,73                         AnalyzerOptions &AnOpts) {74  AnOpts.CheckersAndPackages = {{"test.LocIncDecChecker", true}};75  AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {76    Registry.addChecker<CustomChecker>("test.LocIncDecChecker",77                                       "MockDescription");78  });79}80 81TEST(RegisterCustomCheckers, CheckLocationIncDec) {82  EXPECT_TRUE(83      runCheckerOnCode<addLocIncDecChecker>("void f() { int *p; (*p)++; }"));84}85 86//===----------------------------------------------------------------------===//87// Unsatisfied checker dependency88//===----------------------------------------------------------------------===//89 90class CheckerRegistrationOrderPrinter91    : public Checker<check::PreStmt<DeclStmt>> {92  const BugType BT{this, "Registration order"};93 94public:95  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 111void registerCheckerRegistrationOrderPrinter(CheckerManager &mgr) {112  mgr.registerChecker<CheckerRegistrationOrderPrinter>();113}114 115bool shouldRegisterCheckerRegistrationOrderPrinter(const CheckerManager &mgr) {116  return true;117}118 119void addCheckerRegistrationOrderPrinter(CheckerRegistry &Registry) {120  Registry.addChecker(registerCheckerRegistrationOrderPrinter,121                      shouldRegisterCheckerRegistrationOrderPrinter,122                      "test.RegistrationOrder", "Description");123}124 125#define UNITTEST_CHECKER(CHECKER_NAME)                                         \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");                 \141  }142 143UNITTEST_CHECKER(StrongDep)144UNITTEST_CHECKER(Dep)145 146bool shouldRegisterStrongFALSE(const CheckerManager &mgr) {147  return false;148}149 150 151void 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");158    addStrongDep(Registry);159    addDep(Registry);160    addCheckerRegistrationOrderPrinter(Registry);161    Registry.addDependency("test.Dep", "test.Strong");162  });163}164 165TEST(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 175UNITTEST_CHECKER(WeakDep)176 177void 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 190void 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 203void 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 216void 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 228UNITTEST_CHECKER(WeakDep2)229UNITTEST_CHECKER(Dep2)230 231void 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 249void 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 267TEST(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 314void 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 330void 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 346void 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 362void 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 377void 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 393void 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 411TEST(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 most420  // important for purely diagnostic checkers that are implemented as a part of421  // purely modeling checkers, because the checker callback order will have to422  // be 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 them445  // 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} // namespace460} // namespace ento461} // namespace clang462