1 //==-- DebugContainerModeling.cpp ---------------------------------*- C++ -*--//
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
7 //===----------------------------------------------------------------------===//
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/CallEvent.h"
17 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21 using namespace clang;
23 using namespace iterator;
27 class DebugContainerModeling
28 : public Checker<eval::Call> {
30 std::unique_ptr<BugType> DebugMsgBugType;
32 template <typename Getter>
33 void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
35 void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;
36 void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;
37 ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
39 typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *,
40 CheckerContext &) const;
42 CallDescriptionMap<FnCheck> Callbacks = {
43 {{0, "clang_analyzer_container_begin", 1},
44 &DebugContainerModeling::analyzerContainerBegin},
45 {{0, "clang_analyzer_container_end", 1},
46 &DebugContainerModeling::analyzerContainerEnd},
50 DebugContainerModeling();
52 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
57 DebugContainerModeling::DebugContainerModeling() {
58 DebugMsgBugType.reset(
59 new BugType(this, "Checking analyzer assumptions", "debug",
60 /*SuppressOnSink=*/true));
63 bool DebugContainerModeling::evalCall(const CallEvent &Call,
64 CheckerContext &C) const {
65 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
69 const FnCheck *Handler = Callbacks.lookup(Call);
73 (this->**Handler)(CE, C);
77 template <typename Getter>
78 void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,
81 if (CE->getNumArgs() == 0) {
82 reportDebugMsg("Missing container argument", C);
86 auto State = C.getState();
87 const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
89 const auto *Data = getContainerData(State, Cont);
91 SymbolRef Field = get(Data);
93 State = State->BindExpr(CE, C.getLocationContext(),
94 nonloc::SymbolVal(Field));
96 // Progpagate interestingness from the container's data (marked
97 // interesting by an `ExprInspection` debug call to the container
99 const NoteTag *InterestingTag =
101 [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
102 if (BR.isInteresting(Field)) {
103 BR.markInteresting(Cont);
107 C.addTransition(State, InterestingTag);
113 auto &BVF = C.getSValBuilder().getBasicValueFactory();
114 State = State->BindExpr(CE, C.getLocationContext(),
115 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
118 void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,
119 CheckerContext &C) const {
120 analyzerContainerDataField(CE, C, [](const ContainerData *D) {
121 return D->getBegin();
125 void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE,
126 CheckerContext &C) const {
127 analyzerContainerDataField(CE, C, [](const ContainerData *D) {
132 ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,
133 CheckerContext &C) const {
134 ExplodedNode *N = C.generateNonFatalErrorNode();
138 auto &BR = C.getBugReporter();
139 BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
144 void ento::registerDebugContainerModeling(CheckerManager &mgr) {
145 mgr.registerChecker<DebugContainerModeling>();
148 bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) {