[AMDGPU][AsmParser][NFC] Get rid of custom default operand handlers.
[llvm-project.git] / clang / lib / StaticAnalyzer / Checkers / DebugContainerModeling.cpp
blob832bb78c48035c394dcde75932bce7a8df2c0064
1 //==-- DebugContainerModeling.cpp ---------------------------------*- C++ -*--//
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 // Defines a checker for debugging iterator modeling.
11 //===----------------------------------------------------------------------===//
13 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
15 #include "clang/StaticAnalyzer/Core/Checker.h"
16 #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
17 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20 #include "Iterator.h"
22 using namespace clang;
23 using namespace ento;
24 using namespace iterator;
26 namespace {
28 class DebugContainerModeling
29 : public Checker<eval::Call> {
31 std::unique_ptr<BugType> DebugMsgBugType;
33 template <typename Getter>
34 void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
35 Getter get) const;
36 void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;
37 void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;
38 ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
40 typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *,
41 CheckerContext &) const;
43 CallDescriptionMap<FnCheck> Callbacks = {
44 {{{"clang_analyzer_container_begin"}, 1},
45 &DebugContainerModeling::analyzerContainerBegin},
46 {{{"clang_analyzer_container_end"}, 1},
47 &DebugContainerModeling::analyzerContainerEnd},
50 public:
51 DebugContainerModeling();
53 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
56 } //namespace
58 DebugContainerModeling::DebugContainerModeling() {
59 DebugMsgBugType.reset(
60 new BugType(this, "Checking analyzer assumptions", "debug",
61 /*SuppressOnSink=*/true));
64 bool DebugContainerModeling::evalCall(const CallEvent &Call,
65 CheckerContext &C) const {
66 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
67 if (!CE)
68 return false;
70 const FnCheck *Handler = Callbacks.lookup(Call);
71 if (!Handler)
72 return false;
74 (this->**Handler)(CE, C);
75 return true;
78 template <typename Getter>
79 void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,
80 CheckerContext &C,
81 Getter get) const {
82 if (CE->getNumArgs() == 0) {
83 reportDebugMsg("Missing container argument", C);
84 return;
87 auto State = C.getState();
88 const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
89 if (Cont) {
90 const auto *Data = getContainerData(State, Cont);
91 if (Data) {
92 SymbolRef Field = get(Data);
93 if (Field) {
94 State = State->BindExpr(CE, C.getLocationContext(),
95 nonloc::SymbolVal(Field));
97 // Progpagate interestingness from the container's data (marked
98 // interesting by an `ExprInspection` debug call to the container
99 // itself.
100 const NoteTag *InterestingTag =
101 C.getNoteTag(
102 [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
103 if (BR.isInteresting(Field)) {
104 BR.markInteresting(Cont);
106 return "";
108 C.addTransition(State, InterestingTag);
109 return;
114 auto &BVF = C.getSValBuilder().getBasicValueFactory();
115 State = State->BindExpr(CE, C.getLocationContext(),
116 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
119 void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,
120 CheckerContext &C) const {
121 analyzerContainerDataField(CE, C, [](const ContainerData *D) {
122 return D->getBegin();
126 void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE,
127 CheckerContext &C) const {
128 analyzerContainerDataField(CE, C, [](const ContainerData *D) {
129 return D->getEnd();
133 ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,
134 CheckerContext &C) const {
135 ExplodedNode *N = C.generateNonFatalErrorNode();
136 if (!N)
137 return nullptr;
139 auto &BR = C.getBugReporter();
140 BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
141 Msg, N));
142 return N;
145 void ento::registerDebugContainerModeling(CheckerManager &mgr) {
146 mgr.registerChecker<DebugContainerModeling>();
149 bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) {
150 return true;