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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

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