168 lines · cpp
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-exception6//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} // namespace65 66void InterestingnessTestChecker::handleInteresting(const CallEvent &Call,67 CheckerContext &C) const {68 SymbolRef Sym = Call.getArgSVal(0).getAsSymbol();69 assert(Sym);70 C.addTransition(nullptr, C.getNoteTag([Sym](PathSensitiveBugReport &BR) {71 BR.markInteresting(Sym);72 return "";73 }));74}75 76void InterestingnessTestChecker::handleNotInteresting(const CallEvent &Call,77 CheckerContext &C) const {78 SymbolRef Sym = Call.getArgSVal(0).getAsSymbol();79 assert(Sym);80 C.addTransition(nullptr, C.getNoteTag([Sym](PathSensitiveBugReport &BR) {81 BR.markNotInteresting(Sym);82 return "";83 }));84}85 86void InterestingnessTestChecker::handleCheck(const CallEvent &Call,87 CheckerContext &C) const {88 SymbolRef Sym = Call.getArgSVal(0).getAsSymbol();89 assert(Sym);90 C.addTransition(nullptr, C.getNoteTag([Sym](PathSensitiveBugReport &BR) {91 if (BR.isInteresting(Sym))92 return "Interesting";93 else94 return "NotInteresting";95 }));96}97 98void InterestingnessTestChecker::handleBug(const CallEvent &Call,99 CheckerContext &C) const {100 ExplodedNode *N = C.generateErrorNode();101 C.emitReport(102 std::make_unique<PathSensitiveBugReport>(BT_TestBug, "test bug", 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(Compiler);118 AnalysisConsumer->AddDiagnosticConsumer(119 std::make_unique<VerifyPathDiagnosticConsumer>(120 std::move(ExpectedDiags), Compiler.getSourceManager()));121 AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) {122 Registry.addChecker<InterestingnessTestChecker>("test.Interestingness",123 "MockDescription");124 });125 Compiler.getAnalyzerOpts().CheckersAndPackages = {126 {"test.Interestingness", true}};127 return std::move(AnalysisConsumer);128 }129};130 131} // namespace132 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