Index: clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp +++ clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp @@ -716,6 +716,9 @@ return C.getNoteTag( [Text, Name, ContReg](PathSensitiveBugReport &BR) -> std::string { + if (!BR.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](PathSensitiveBugReport &BR) -> std::string { + if (BR.isInteresting(Field)) { + BR.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 @@ -52,9 +52,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; @@ -144,22 +147,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; } @@ -406,7 +415,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; @@ -419,7 +429,7 @@ return; } - reportBug(*Str, C); + reportBug(*Str, C, Optional(ArgVal)); } void ExprInspectionChecker::analyzerIsTainted(const CallExpr *CE, Index: clang/test/Analysis/container-modeling.cpp =================================================================== --- clang/test/Analysis/container-modeling.cpp +++ clang/test/Analysis/container-modeling.cpp @@ -76,8 +76,7 @@ clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); - V.push_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}} + V.push_back(n); // expected-note 2{{Container 'V' extended to the right by 1 position}} clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} // expected-note@-1{{$V.begin()}} @@ -203,10 +202,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 +217,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