Index: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp +++ clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp @@ -715,6 +715,11 @@ } return C.getNoteTag([Text, Name, ContReg](BugReport &BR) -> std::string { + const auto *PSBR = cast(&BR); + + if (!PSBR->isInteresting(ContReg)) + return ""; + SmallString<256> Msg; llvm::raw_svector_ostream Out(Msg); Out << "Container " << (!Name.empty() ? ("'" + Name.str() + "' ") : "" ) Index: clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp +++ clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp @@ -92,7 +92,15 @@ if (Field) { State = State->BindExpr(CE, C.getLocationContext(), nonloc::SymbolVal(Field)); - C.addTransition(State); + const NoteTag *InterestingTag = + C.getNoteTag([Cont, Field](BugReport &BR) -> std::string { + auto *PSBR = cast(&BR); + if (PSBR->isInteresting(Field)) { + PSBR->markInteresting(Cont); + } + return ""; + }); + C.addTransition(State, InterestingTag); return; } } Index: clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -50,9 +50,12 @@ typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *, CheckerContext &C) const; - ExplodedNode *reportBug(llvm::StringRef Msg, CheckerContext &C) const; + // Optional parameter `ExprVal` for expression value to be marked interesting + ExplodedNode *reportBug(llvm::StringRef Msg, CheckerContext &C, + Optional ExprVal = None) const; ExplodedNode *reportBug(llvm::StringRef Msg, BugReporter &BR, - ExplodedNode *N) const; + ExplodedNode *N, + Optional ExprVal = None) const; public: bool evalCall(const CallEvent &Call, CheckerContext &C) const; @@ -134,22 +137,28 @@ } ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg, - CheckerContext &C) const { + CheckerContext &C, + Optional ExprVal) const { ExplodedNode *N = C.generateNonFatalErrorNode(); - reportBug(Msg, C.getBugReporter(), N); + reportBug(Msg, C.getBugReporter(), N, ExprVal); return N; } ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg, BugReporter &BR, - ExplodedNode *N) const { + ExplodedNode *N, + Optional ExprVal) const { if (!N) return nullptr; if (!BT) BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); - BR.emitReport(std::make_unique(*BT, Msg, N)); + auto R = std::make_unique(*BT, Msg, N); + if (ExprVal) { + R->markInteresting(*ExprVal); + } + BR.emitReport(std::move(R)); return N; } @@ -396,7 +405,8 @@ return; } - SymbolRef Sym = C.getSVal(CE->getArg(0)).getAsSymbol(); + SVal ArgVal = C.getSVal(CE->getArg(0)); + SymbolRef Sym = ArgVal.getAsSymbol(); if (!Sym) { reportBug("Not a symbol", C); return; @@ -409,7 +419,7 @@ return; } - reportBug(*Str, C); + reportBug(*Str, C, Optional(ArgVal)); } void ento::registerExprInspectionChecker(CheckerManager &Mgr) { Index: clang/test/Analysis/container-modeling.cpp =================================================================== --- clang/test/Analysis/container-modeling.cpp +++ clang/test/Analysis/container-modeling.cpp @@ -97,7 +97,8 @@ clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); - V.emplace_back(n); // expected-note 2{{Container 'V' extended to the right by 1 position}} + V.emplace_back(n); // expected-note{{Container 'V' extended to the right by 1 position}} + // expected-note@-1{{Container 'V' extended to the right by 1 position}} clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} @@ -118,7 +119,8 @@ clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); - V.pop_back(); // expected-note 2{{Container 'V' shrank from the right by 1 position}} + V.pop_back(); // expected-note{{Container 'V' shrank from the right by 1 position}} + // expected-note@-1{{Container 'V' shrank from the right by 1 position}} clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} @@ -139,7 +141,8 @@ clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); - L.push_front(n); // expected-note 2{{Container 'L' extended to the left by 1 position}} + L.push_front(n); // expected-note{{Container 'L' extended to the left by 1 position}} + // expected-note@-1{{Container 'L' extended to the left by 1 position}} clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() - 1}} // expected-note@-1{{$L.begin() - 1}} @@ -159,7 +162,8 @@ clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); - L.emplace_front(n); // expected-note 2{{Container 'L' extended to the left by 1 position}} + L.emplace_front(n); // expected-note{{Container 'L' extended to the left by 1 position}} + // expected-note@-1{{Container 'L' extended to the left by 1 position}} clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() - 1}} // expected-note@-1{{$L.begin() - 1}} @@ -179,7 +183,8 @@ clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); - L.pop_front(); // expected-note 2{{Container 'L' shrank from the left by 1 position}} + L.pop_front(); // expected-note{{Container 'L' shrank from the left by 1 position}} + // expected-note@-1{{Container 'L' shrank from the left by 1 position}} clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() + 1}} // expected-note@-1{{$L.begin() + 1}} @@ -203,10 +208,10 @@ clang_analyzer_denote(clang_analyzer_container_begin(V1), "$V1.begin()"); - V2.push_back(n); // expected-note{{Container 'V2' extended to the right by 1 position}} FIXME: This note should not appear since `V2` is not affected in the "bug" + V2.push_back(n); // no-note clang_analyzer_express(clang_analyzer_container_begin(V1)); // expected-warning{{$V1.begin()}} - // expected-note@-1{{$V1.begin()}} + // expected-note@-1{{$V1.begin()}} } void push_back2(std::vector &V1, std::vector &V2, int n) { @@ -218,15 +223,14 @@ clang_analyzer_denote(clang_analyzer_container_begin(V1), "$V1.begin()"); clang_analyzer_denote(clang_analyzer_container_begin(V2), "$V2.begin()"); - V1.push_back(n); // expected-note 2{{Container 'V1' extended to the right by 1 position}} - // FIXME: This should appear only once since there is only - // one "bug" where `V1` is affected + V1.push_back(n); // expected-note{{Container 'V1' extended to the right by 1 position}} + // Only once! clang_analyzer_express(clang_analyzer_container_begin(V1)); // expected-warning{{$V1.begin()}} - // expected-note@-1{{$V1.begin()}} + // expected-note@-1{{$V1.begin()}} clang_analyzer_express(clang_analyzer_container_begin(V2)); // expected-warning{{$V2.begin()}} - // expected-note@-1{{$V2.begin()}} + // expected-note@-1{{$V2.begin()}} } /// Print Container Data as Part of the Program State