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 {{{"setInteresting"}, 1}, &InterestingnessTestChecker::handleInteresting
},
37 {{{"setNotInteresting"}, 1},
38 &InterestingnessTestChecker::handleNotInteresting
},
39 {{{"check"}, 1}, &InterestingnessTestChecker::handleCheck
},
40 {{{"bug"}, 1}, &InterestingnessTestChecker::handleBug
},
43 void handleInteresting(const CallEvent
&Call
, CheckerContext
&C
) const;
44 void handleNotInteresting(const CallEvent
&Call
, CheckerContext
&C
) const;
45 void handleCheck(const CallEvent
&Call
, CheckerContext
&C
) const;
46 void handleBug(const CallEvent
&Call
, CheckerContext
&C
) const;
49 InterestingnessTestChecker()
50 : BT_TestBug(this, "InterestingnessTestBug", "Test") {}
52 void checkPreCall(const CallEvent
&Call
, CheckerContext
&C
) const {
53 const HandlerFn
*Handler
= Handlers
.lookup(Call
);
57 (*Handler
)(this, Call
, C
);
63 void InterestingnessTestChecker::handleInteresting(const CallEvent
&Call
,
64 CheckerContext
&C
) const {
65 SymbolRef Sym
= Call
.getArgSVal(0).getAsSymbol();
67 C
.addTransition(nullptr, C
.getNoteTag([Sym
](PathSensitiveBugReport
&BR
) {
68 BR
.markInteresting(Sym
);
73 void InterestingnessTestChecker::handleNotInteresting(const CallEvent
&Call
,
74 CheckerContext
&C
) const {
75 SymbolRef Sym
= Call
.getArgSVal(0).getAsSymbol();
77 C
.addTransition(nullptr, C
.getNoteTag([Sym
](PathSensitiveBugReport
&BR
) {
78 BR
.markNotInteresting(Sym
);
83 void InterestingnessTestChecker::handleCheck(const CallEvent
&Call
,
84 CheckerContext
&C
) const {
85 SymbolRef Sym
= Call
.getArgSVal(0).getAsSymbol();
87 C
.addTransition(nullptr, C
.getNoteTag([Sym
](PathSensitiveBugReport
&BR
) {
88 if (BR
.isInteresting(Sym
))
91 return "NotInteresting";
95 void InterestingnessTestChecker::handleBug(const CallEvent
&Call
,
96 CheckerContext
&C
) const {
97 ExplodedNode
*N
= C
.generateErrorNode();
99 std::make_unique
<PathSensitiveBugReport
>(BT_TestBug
, "test bug", N
));
104 class TestAction
: public ASTFrontendAction
{
105 ExpectedDiagsTy ExpectedDiags
;
108 TestAction(ExpectedDiagsTy
&&ExpectedDiags
)
109 : ExpectedDiags(std::move(ExpectedDiags
)) {}
111 std::unique_ptr
<ASTConsumer
> CreateASTConsumer(CompilerInstance
&Compiler
,
112 StringRef File
) override
{
113 std::unique_ptr
<AnalysisASTConsumer
> AnalysisConsumer
=
114 CreateAnalysisConsumer(Compiler
);
115 AnalysisConsumer
->AddDiagnosticConsumer(new VerifyPathDiagnosticConsumer(
116 std::move(ExpectedDiags
), Compiler
.getSourceManager()));
117 AnalysisConsumer
->AddCheckerRegistrationFn([](CheckerRegistry
&Registry
) {
118 Registry
.addChecker
<InterestingnessTestChecker
>("test.Interestingness",
121 Compiler
.getAnalyzerOpts().CheckersAndPackages
= {
122 {"test.Interestingness", true}};
123 return std::move(AnalysisConsumer
);
129 TEST(BugReportInterestingness
, Symbols
) {
130 EXPECT_TRUE(tooling::runToolOnCode(
131 std::make_unique
<TestAction
>(ExpectedDiagsTy
{
135 "test.Interestingness",
136 "InterestingnessTestBug",
139 {{8, 7}, "Interesting", {{{8, 7}, {8, 14}}}},
140 {{10, 7}, "NotInteresting", {{{10, 7}, {10, 14}}}},
141 {{12, 7}, "Interesting", {{{12, 7}, {12, 14}}}},
142 {{14, 7}, "NotInteresting", {{{14, 7}, {14, 14}}}},
143 {{15, 7}, "test bug", {{{15, 7}, {15, 12}}}},
146 void setInteresting(int);
147 void setNotInteresting(int);
155 setNotInteresting(A);