xref: /llvm-project/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp (revision 58bad2862cf136f9483eb005bbfa6915d459b46d)
1b0d38ad0SBalázs Kéri //===----------------------------------------------------------------------===//
2b0d38ad0SBalázs Kéri //
3b0d38ad0SBalázs Kéri // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b0d38ad0SBalázs Kéri // See https://llvm.org/LICENSE.txt for license information.
5b0d38ad0SBalázs Kéri // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b0d38ad0SBalázs Kéri //
7b0d38ad0SBalázs Kéri //===----------------------------------------------------------------------===//
8b0d38ad0SBalázs Kéri 
9b0d38ad0SBalázs Kéri #include "Reusables.h"
10b0d38ad0SBalázs Kéri #include "clang/Frontend/CompilerInstance.h"
11b0d38ad0SBalázs Kéri #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
12b0d38ad0SBalázs Kéri #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
13b0d38ad0SBalázs Kéri #include "clang/StaticAnalyzer/Core/Checker.h"
14b0d38ad0SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
150b9d3a6eSBalazs Benics #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
16b0d38ad0SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
17b0d38ad0SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
18b0d38ad0SBalázs Kéri #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
19b0d38ad0SBalázs Kéri #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
20b0d38ad0SBalázs Kéri #include "clang/Tooling/Tooling.h"
21b0d38ad0SBalázs Kéri #include "gtest/gtest.h"
22b0d38ad0SBalázs Kéri 
23b0d38ad0SBalázs Kéri using namespace clang;
24b0d38ad0SBalázs Kéri using namespace ento;
25b0d38ad0SBalázs Kéri using namespace llvm;
26b0d38ad0SBalázs Kéri 
27b0d38ad0SBalázs Kéri namespace {
28b0d38ad0SBalázs Kéri 
29b0d38ad0SBalázs Kéri class InterestingnessTestChecker : public Checker<check::PreCall> {
30b0d38ad0SBalázs Kéri   BugType BT_TestBug;
31b0d38ad0SBalázs Kéri 
32b0d38ad0SBalázs Kéri   using HandlerFn = std::function<void(const InterestingnessTestChecker *,
33b0d38ad0SBalázs Kéri                                        const CallEvent &, CheckerContext &)>;
34b0d38ad0SBalázs Kéri 
35b0d38ad0SBalázs Kéri   CallDescriptionMap<HandlerFn> Handlers = {
36*58bad286SDonát Nagy       {{CDM::SimpleFunc, {"setInteresting"}, 1},
37*58bad286SDonát Nagy        &InterestingnessTestChecker::handleInteresting},
38*58bad286SDonát Nagy       {{CDM::SimpleFunc, {"setNotInteresting"}, 1},
39b0d38ad0SBalázs Kéri        &InterestingnessTestChecker::handleNotInteresting},
40*58bad286SDonát Nagy       {{CDM::SimpleFunc, {"check"}, 1},
41*58bad286SDonát Nagy        &InterestingnessTestChecker::handleCheck},
42*58bad286SDonát Nagy       {{CDM::SimpleFunc, {"bug"}, 1}, &InterestingnessTestChecker::handleBug},
43b0d38ad0SBalázs Kéri   };
44b0d38ad0SBalázs Kéri 
45b0d38ad0SBalázs Kéri   void handleInteresting(const CallEvent &Call, CheckerContext &C) const;
46b0d38ad0SBalázs Kéri   void handleNotInteresting(const CallEvent &Call, CheckerContext &C) const;
47b0d38ad0SBalázs Kéri   void handleCheck(const CallEvent &Call, CheckerContext &C) const;
48b0d38ad0SBalázs Kéri   void handleBug(const CallEvent &Call, CheckerContext &C) const;
49b0d38ad0SBalázs Kéri 
50b0d38ad0SBalázs Kéri public:
InterestingnessTestChecker()51b0d38ad0SBalázs Kéri   InterestingnessTestChecker()
52b0d38ad0SBalázs Kéri       : BT_TestBug(this, "InterestingnessTestBug", "Test") {}
53b0d38ad0SBalázs Kéri 
checkPreCall(const CallEvent & Call,CheckerContext & C) const54b0d38ad0SBalázs Kéri   void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
55b0d38ad0SBalázs Kéri     const HandlerFn *Handler = Handlers.lookup(Call);
56b0d38ad0SBalázs Kéri     if (!Handler)
57b0d38ad0SBalázs Kéri       return;
58b0d38ad0SBalázs Kéri 
59b0d38ad0SBalázs Kéri     (*Handler)(this, Call, C);
60b0d38ad0SBalázs Kéri   }
61b0d38ad0SBalázs Kéri };
62b0d38ad0SBalázs Kéri 
63b0d38ad0SBalázs Kéri } // namespace
64b0d38ad0SBalázs Kéri 
handleInteresting(const CallEvent & Call,CheckerContext & C) const65b0d38ad0SBalázs Kéri void InterestingnessTestChecker::handleInteresting(const CallEvent &Call,
66b0d38ad0SBalázs Kéri                                                    CheckerContext &C) const {
67b0d38ad0SBalázs Kéri   SymbolRef Sym = Call.getArgSVal(0).getAsSymbol();
68b0d38ad0SBalázs Kéri   assert(Sym);
69b0d38ad0SBalázs Kéri   C.addTransition(nullptr, C.getNoteTag([Sym](PathSensitiveBugReport &BR) {
70b0d38ad0SBalázs Kéri     BR.markInteresting(Sym);
71b0d38ad0SBalázs Kéri     return "";
72b0d38ad0SBalázs Kéri   }));
73b0d38ad0SBalázs Kéri }
74b0d38ad0SBalázs Kéri 
handleNotInteresting(const CallEvent & Call,CheckerContext & C) const75b0d38ad0SBalázs Kéri void InterestingnessTestChecker::handleNotInteresting(const CallEvent &Call,
76b0d38ad0SBalázs Kéri                                                       CheckerContext &C) const {
77b0d38ad0SBalázs Kéri   SymbolRef Sym = Call.getArgSVal(0).getAsSymbol();
78b0d38ad0SBalázs Kéri   assert(Sym);
79b0d38ad0SBalázs Kéri   C.addTransition(nullptr, C.getNoteTag([Sym](PathSensitiveBugReport &BR) {
80b0d38ad0SBalázs Kéri     BR.markNotInteresting(Sym);
81b0d38ad0SBalázs Kéri     return "";
82b0d38ad0SBalázs Kéri   }));
83b0d38ad0SBalázs Kéri }
84b0d38ad0SBalázs Kéri 
handleCheck(const CallEvent & Call,CheckerContext & C) const85b0d38ad0SBalázs Kéri void InterestingnessTestChecker::handleCheck(const CallEvent &Call,
86b0d38ad0SBalázs Kéri                                              CheckerContext &C) const {
87b0d38ad0SBalázs Kéri   SymbolRef Sym = Call.getArgSVal(0).getAsSymbol();
88b0d38ad0SBalázs Kéri   assert(Sym);
89b0d38ad0SBalázs Kéri   C.addTransition(nullptr, C.getNoteTag([Sym](PathSensitiveBugReport &BR) {
90b0d38ad0SBalázs Kéri     if (BR.isInteresting(Sym))
91b0d38ad0SBalázs Kéri       return "Interesting";
92b0d38ad0SBalázs Kéri     else
93b0d38ad0SBalázs Kéri       return "NotInteresting";
94b0d38ad0SBalázs Kéri   }));
95b0d38ad0SBalázs Kéri }
96b0d38ad0SBalázs Kéri 
handleBug(const CallEvent & Call,CheckerContext & C) const97b0d38ad0SBalázs Kéri void InterestingnessTestChecker::handleBug(const CallEvent &Call,
98b0d38ad0SBalázs Kéri                                            CheckerContext &C) const {
99b0d38ad0SBalázs Kéri   ExplodedNode *N = C.generateErrorNode();
100b0d38ad0SBalázs Kéri   C.emitReport(
101b0d38ad0SBalázs Kéri       std::make_unique<PathSensitiveBugReport>(BT_TestBug, "test bug", N));
102b0d38ad0SBalázs Kéri }
103b0d38ad0SBalázs Kéri 
104b0d38ad0SBalázs Kéri namespace {
105b0d38ad0SBalázs Kéri 
106b0d38ad0SBalázs Kéri class TestAction : public ASTFrontendAction {
107b0d38ad0SBalázs Kéri   ExpectedDiagsTy ExpectedDiags;
108b0d38ad0SBalázs Kéri 
109b0d38ad0SBalázs Kéri public:
TestAction(ExpectedDiagsTy && ExpectedDiags)110b0d38ad0SBalázs Kéri   TestAction(ExpectedDiagsTy &&ExpectedDiags)
111b0d38ad0SBalázs Kéri       : ExpectedDiags(std::move(ExpectedDiags)) {}
112b0d38ad0SBalázs Kéri 
CreateASTConsumer(CompilerInstance & Compiler,StringRef File)113b0d38ad0SBalázs Kéri   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
114b0d38ad0SBalázs Kéri                                                  StringRef File) override {
115b0d38ad0SBalázs Kéri     std::unique_ptr<AnalysisASTConsumer> AnalysisConsumer =
116b0d38ad0SBalázs Kéri         CreateAnalysisConsumer(Compiler);
117b0d38ad0SBalázs Kéri     AnalysisConsumer->AddDiagnosticConsumer(new VerifyPathDiagnosticConsumer(
118b0d38ad0SBalázs Kéri         std::move(ExpectedDiags), Compiler.getSourceManager()));
119b0d38ad0SBalázs Kéri     AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
120b0d38ad0SBalázs Kéri       Registry.addChecker<InterestingnessTestChecker>("test.Interestingness",
121b0d38ad0SBalázs Kéri                                                       "Description", "");
122b0d38ad0SBalázs Kéri     });
1238e0c9bb9SJan Svoboda     Compiler.getAnalyzerOpts().CheckersAndPackages = {
124b0d38ad0SBalázs Kéri         {"test.Interestingness", true}};
125b0d38ad0SBalázs Kéri     return std::move(AnalysisConsumer);
126b0d38ad0SBalázs Kéri   }
127b0d38ad0SBalázs Kéri };
128b0d38ad0SBalázs Kéri 
129b0d38ad0SBalázs Kéri } // namespace
130b0d38ad0SBalázs Kéri 
TEST(BugReportInterestingness,Symbols)131b0d38ad0SBalázs Kéri TEST(BugReportInterestingness, Symbols) {
132b0d38ad0SBalázs Kéri   EXPECT_TRUE(tooling::runToolOnCode(
133b0d38ad0SBalázs Kéri       std::make_unique<TestAction>(ExpectedDiagsTy{
134b0d38ad0SBalázs Kéri           {{15, 7},
135b0d38ad0SBalázs Kéri            "test bug",
136b0d38ad0SBalázs Kéri            "test bug",
137b0d38ad0SBalázs Kéri            "test.Interestingness",
138b0d38ad0SBalázs Kéri            "InterestingnessTestBug",
139b0d38ad0SBalázs Kéri            "Test",
140b0d38ad0SBalázs Kéri            {
141b0d38ad0SBalázs Kéri                {{8, 7}, "Interesting", {{{8, 7}, {8, 14}}}},
142b0d38ad0SBalázs Kéri                {{10, 7}, "NotInteresting", {{{10, 7}, {10, 14}}}},
143b0d38ad0SBalázs Kéri                {{12, 7}, "Interesting", {{{12, 7}, {12, 14}}}},
144b0d38ad0SBalázs Kéri                {{14, 7}, "NotInteresting", {{{14, 7}, {14, 14}}}},
145b0d38ad0SBalázs Kéri                {{15, 7}, "test bug", {{{15, 7}, {15, 12}}}},
146b0d38ad0SBalázs Kéri            }}}),
147b0d38ad0SBalázs Kéri       R"(
148b0d38ad0SBalázs Kéri     void setInteresting(int);
149b0d38ad0SBalázs Kéri     void setNotInteresting(int);
150b0d38ad0SBalázs Kéri     void check(int);
151b0d38ad0SBalázs Kéri     void bug(int);
152b0d38ad0SBalázs Kéri 
153b0d38ad0SBalázs Kéri     void f(int A) {
154b0d38ad0SBalázs Kéri       check(A);
155b0d38ad0SBalázs Kéri       setInteresting(A);
156b0d38ad0SBalázs Kéri       check(A);
157b0d38ad0SBalázs Kéri       setNotInteresting(A);
158b0d38ad0SBalázs Kéri       check(A);
159b0d38ad0SBalázs Kéri       setInteresting(A);
160b0d38ad0SBalázs Kéri       check(A);
161b0d38ad0SBalázs Kéri       bug(A);
162b0d38ad0SBalázs Kéri     }
163b0d38ad0SBalázs Kéri   )",
164b0d38ad0SBalázs Kéri       "input.cpp"));
165b0d38ad0SBalázs Kéri }
166