1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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/CallDescription.h"
16 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
17 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
18 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
19 #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
20 #include "clang/Tooling/Tooling.h"
21 #include "gtest/gtest.h"
23 using namespace clang
;
29 class InterestingnessTestChecker
: public Checker
<check::PreCall
> {
32 using HandlerFn
= std::function
<void(const InterestingnessTestChecker
*,
33 const CallEvent
&, CheckerContext
&)>;
35 CallDescriptionMap
<HandlerFn
> Handlers
= {
36 {{CDM::SimpleFunc
, {"setInteresting"}, 1},
37 &InterestingnessTestChecker::handleInteresting
},
38 {{CDM::SimpleFunc
, {"setNotInteresting"}, 1},
39 &InterestingnessTestChecker::handleNotInteresting
},
40 {{CDM::SimpleFunc
, {"check"}, 1},
41 &InterestingnessTestChecker::handleCheck
},
42 {{CDM::SimpleFunc
, {"bug"}, 1}, &InterestingnessTestChecker::handleBug
},
45 void handleInteresting(const CallEvent
&Call
, CheckerContext
&C
) const;
46 void handleNotInteresting(const CallEvent
&Call
, CheckerContext
&C
) const;
47 void handleCheck(const CallEvent
&Call
, CheckerContext
&C
) const;
48 void handleBug(const CallEvent
&Call
, CheckerContext
&C
) const;
51 InterestingnessTestChecker()
52 : BT_TestBug(this, "InterestingnessTestBug", "Test") {}
54 void checkPreCall(const CallEvent
&Call
, CheckerContext
&C
) const {
55 const HandlerFn
*Handler
= Handlers
.lookup(Call
);
59 (*Handler
)(this, Call
, C
);
65 void InterestingnessTestChecker::handleInteresting(const CallEvent
&Call
,
66 CheckerContext
&C
) const {
67 SymbolRef Sym
= Call
.getArgSVal(0).getAsSymbol();
69 C
.addTransition(nullptr, C
.getNoteTag([Sym
](PathSensitiveBugReport
&BR
) {
70 BR
.markInteresting(Sym
);
75 void InterestingnessTestChecker::handleNotInteresting(const CallEvent
&Call
,
76 CheckerContext
&C
) const {
77 SymbolRef Sym
= Call
.getArgSVal(0).getAsSymbol();
79 C
.addTransition(nullptr, C
.getNoteTag([Sym
](PathSensitiveBugReport
&BR
) {
80 BR
.markNotInteresting(Sym
);
85 void InterestingnessTestChecker::handleCheck(const CallEvent
&Call
,
86 CheckerContext
&C
) const {
87 SymbolRef Sym
= Call
.getArgSVal(0).getAsSymbol();
89 C
.addTransition(nullptr, C
.getNoteTag([Sym
](PathSensitiveBugReport
&BR
) {
90 if (BR
.isInteresting(Sym
))
93 return "NotInteresting";
97 void InterestingnessTestChecker::handleBug(const CallEvent
&Call
,
98 CheckerContext
&C
) const {
99 ExplodedNode
*N
= C
.generateErrorNode();
101 std::make_unique
<PathSensitiveBugReport
>(BT_TestBug
, "test bug", N
));
106 class TestAction
: public ASTFrontendAction
{
107 ExpectedDiagsTy ExpectedDiags
;
110 TestAction(ExpectedDiagsTy
&&ExpectedDiags
)
111 : ExpectedDiags(std::move(ExpectedDiags
)) {}
113 std::unique_ptr
<ASTConsumer
> CreateASTConsumer(CompilerInstance
&Compiler
,
114 StringRef File
) override
{
115 std::unique_ptr
<AnalysisASTConsumer
> AnalysisConsumer
=
116 CreateAnalysisConsumer(Compiler
);
117 AnalysisConsumer
->AddDiagnosticConsumer(new VerifyPathDiagnosticConsumer(
118 std::move(ExpectedDiags
), Compiler
.getSourceManager()));
119 AnalysisConsumer
->AddCheckerRegistrationFn([](CheckerRegistry
&Registry
) {
120 Registry
.addChecker
<InterestingnessTestChecker
>("test.Interestingness",
123 Compiler
.getAnalyzerOpts().CheckersAndPackages
= {
124 {"test.Interestingness", true}};
125 return std::move(AnalysisConsumer
);
131 TEST(BugReportInterestingness
, Symbols
) {
132 EXPECT_TRUE(tooling::runToolOnCode(
133 std::make_unique
<TestAction
>(ExpectedDiagsTy
{
137 "test.Interestingness",
138 "InterestingnessTestBug",
141 {{8, 7}, "Interesting", {{{8, 7}, {8, 14}}}},
142 {{10, 7}, "NotInteresting", {{{10, 7}, {10, 14}}}},
143 {{12, 7}, "Interesting", {{{12, 7}, {12, 14}}}},
144 {{14, 7}, "NotInteresting", {{{14, 7}, {14, 14}}}},
145 {{15, 7}, "test bug", {{{15, 7}, {15, 12}}}},
148 void setInteresting(int);
149 void setNotInteresting(int);
157 setNotInteresting(A);