1 //===----------------------------------------------------------------------===// 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 "Reusables.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/PathSensitive/AnalysisManager.h" 15 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.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 "gtest/gtest.h" 21 22 using namespace clang; 23 using namespace ento; 24 using namespace llvm; 25 26 namespace { 27 28 class InterestingnessTestChecker : public Checker<check::PreCall> { 29 BugType BT_TestBug; 30 31 using HandlerFn = std::function<void(const InterestingnessTestChecker *, 32 const CallEvent &, CheckerContext &)>; 33 34 CallDescriptionMap<HandlerFn> Handlers = { 35 {{"setInteresting", 1}, &InterestingnessTestChecker::handleInteresting}, 36 {{"setNotInteresting", 1}, 37 &InterestingnessTestChecker::handleNotInteresting}, 38 {{"check", 1}, &InterestingnessTestChecker::handleCheck}, 39 {{"bug", 1}, &InterestingnessTestChecker::handleBug}, 40 }; 41 42 void handleInteresting(const CallEvent &Call, CheckerContext &C) const; 43 void handleNotInteresting(const CallEvent &Call, CheckerContext &C) const; 44 void handleCheck(const CallEvent &Call, CheckerContext &C) const; 45 void handleBug(const CallEvent &Call, CheckerContext &C) const; 46 47 public: 48 InterestingnessTestChecker() 49 : BT_TestBug(this, "InterestingnessTestBug", "Test") {} 50 51 void checkPreCall(const CallEvent &Call, CheckerContext &C) const { 52 const HandlerFn *Handler = Handlers.lookup(Call); 53 if (!Handler) 54 return; 55 56 (*Handler)(this, Call, C); 57 } 58 }; 59 60 } // namespace 61 62 void InterestingnessTestChecker::handleInteresting(const CallEvent &Call, 63 CheckerContext &C) const { 64 SymbolRef Sym = Call.getArgSVal(0).getAsSymbol(); 65 assert(Sym); 66 C.addTransition(nullptr, C.getNoteTag([Sym](PathSensitiveBugReport &BR) { 67 BR.markInteresting(Sym); 68 return ""; 69 })); 70 } 71 72 void InterestingnessTestChecker::handleNotInteresting(const CallEvent &Call, 73 CheckerContext &C) const { 74 SymbolRef Sym = Call.getArgSVal(0).getAsSymbol(); 75 assert(Sym); 76 C.addTransition(nullptr, C.getNoteTag([Sym](PathSensitiveBugReport &BR) { 77 BR.markNotInteresting(Sym); 78 return ""; 79 })); 80 } 81 82 void InterestingnessTestChecker::handleCheck(const CallEvent &Call, 83 CheckerContext &C) const { 84 SymbolRef Sym = Call.getArgSVal(0).getAsSymbol(); 85 assert(Sym); 86 C.addTransition(nullptr, C.getNoteTag([Sym](PathSensitiveBugReport &BR) { 87 if (BR.isInteresting(Sym)) 88 return "Interesting"; 89 else 90 return "NotInteresting"; 91 })); 92 } 93 94 void InterestingnessTestChecker::handleBug(const CallEvent &Call, 95 CheckerContext &C) const { 96 ExplodedNode *N = C.generateErrorNode(); 97 C.emitReport( 98 std::make_unique<PathSensitiveBugReport>(BT_TestBug, "test bug", N)); 99 } 100 101 namespace { 102 103 class TestAction : public ASTFrontendAction { 104 ExpectedDiagsTy ExpectedDiags; 105 106 public: 107 TestAction(ExpectedDiagsTy &&ExpectedDiags) 108 : ExpectedDiags(std::move(ExpectedDiags)) {} 109 110 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, 111 StringRef File) override { 112 std::unique_ptr<AnalysisASTConsumer> AnalysisConsumer = 113 CreateAnalysisConsumer(Compiler); 114 AnalysisConsumer->AddDiagnosticConsumer(new VerifyPathDiagnosticConsumer( 115 std::move(ExpectedDiags), Compiler.getSourceManager())); 116 AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) { 117 Registry.addChecker<InterestingnessTestChecker>("test.Interestingness", 118 "Description", ""); 119 }); 120 Compiler.getAnalyzerOpts()->CheckersAndPackages = { 121 {"test.Interestingness", true}}; 122 return std::move(AnalysisConsumer); 123 } 124 }; 125 126 } // namespace 127 128 TEST(BugReportInterestingness, Symbols) { 129 EXPECT_TRUE(tooling::runToolOnCode( 130 std::make_unique<TestAction>(ExpectedDiagsTy{ 131 {{15, 7}, 132 "test bug", 133 "test bug", 134 "test.Interestingness", 135 "InterestingnessTestBug", 136 "Test", 137 { 138 {{8, 7}, "Interesting", {{{8, 7}, {8, 14}}}}, 139 {{10, 7}, "NotInteresting", {{{10, 7}, {10, 14}}}}, 140 {{12, 7}, "Interesting", {{{12, 7}, {12, 14}}}}, 141 {{14, 7}, "NotInteresting", {{{14, 7}, {14, 14}}}}, 142 {{15, 7}, "test bug", {{{15, 7}, {15, 12}}}}, 143 }}}), 144 R"( 145 void setInteresting(int); 146 void setNotInteresting(int); 147 void check(int); 148 void bug(int); 149 150 void f(int A) { 151 check(A); 152 setInteresting(A); 153 check(A); 154 setNotInteresting(A); 155 check(A); 156 setInteresting(A); 157 check(A); 158 bug(A); 159 } 160 )", 161 "input.cpp")); 162 } 163