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

source code of clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp