Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -210,6 +210,22 @@ return None; } +static bool isVarAnInterestingCondition(const Expr *CondVarExpr, + const ExplodedNode *N, + const BugReport *B) { + // Even if this condition is marked as interesting, it isn't *that* + // interesting if it didn't happen in a nested stackframe, the user could just + // follow the arrows. + if (!B->getErrorNode()->getStackFrame()->isParentOf(N->getStackFrame())) + return false; + + if (Optional V = getSValForVar(CondVarExpr, N)) + if (Optional K = B->getInterestingnessKind(*V)) + return *K == bugreporter::TrackingKind::Condition; + + return false; +} + static bool isInterestingExpr(const Expr *E, const ExplodedNode *N, const BugReport *B) { if (Optional V = getSValForVar(E, N)) @@ -2485,6 +2501,10 @@ const LocationContext *LCtx = N->getLocationContext(); PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); + if (isVarAnInterestingCondition(BExpr->getLHS(), N, &R) || + isVarAnInterestingCondition(BExpr->getRHS(), N, &R)) + Out << WillBeUsedForACondition; + // Convert 'field ...' to 'Field ...' if it is a MemberExpr. std::string Message = Out.str(); Message[0] = toupper(Message[0]); @@ -2515,6 +2535,9 @@ const LocationContext *LCtx = N->getLocationContext(); PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx); + if (isVarAnInterestingCondition(CondVarExpr, N, &report)) + Out << WillBeUsedForACondition; + auto event = std::make_shared(Loc, Out.str()); if (isInterestingExpr(CondVarExpr, N, &report)) @@ -2541,6 +2564,9 @@ const LocationContext *LCtx = N->getLocationContext(); PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); + if (isVarAnInterestingCondition(DRE, N, &report)) + Out << WillBeUsedForACondition; + // If we know the value create a pop-up note. if (!IsAssuming) return std::make_shared(Loc, Out.str()); @@ -2570,6 +2596,9 @@ if (!Loc.isValid() || !Loc.asLocation().isValid()) return nullptr; + if (isVarAnInterestingCondition(ME, N, &report)) + Out << WillBeUsedForACondition; + // If we know the value create a pop-up note. if (!IsAssuming) return std::make_shared(Loc, Out.str()); Index: clang/test/Analysis/track-control-dependency-conditions.cpp =================================================================== --- clang/test/Analysis/track-control-dependency-conditions.cpp +++ clang/test/Analysis/track-control-dependency-conditions.cpp @@ -407,12 +407,37 @@ } } // end of namespace condition_written_in_nested_stackframe_before_assignment +namespace collapse_point_not_in_condition_bool { + +[[noreturn]] void halt(); + +void check(bool b) { + if (!b) // tracking-note{{Assuming 'b' is true, which will be (a part of a) condition}} + // tracking-note@-1{{Taking false branch}} + halt(); +} + +void f(bool flag) { + int *x = 0; // expected-note{{'x' initialized to a null pointer value}} + + check(flag); // tracking-note{{Calling 'check'}} + // tracking-note@-1{{Returning from 'check'}} + + if (flag) // expected-note{{'flag' is true}} + // expected-note@-1{{Taking true branch}} + // debug-note@-2{{Tracking condition 'flag'}} + *x = 5; // expected-warning{{Dereference of null pointer}} + // expected-note@-1{{Dereference of null pointer}} +} + +} // end of namespace collapse_point_not_in_condition_bool + namespace collapse_point_not_in_condition { [[noreturn]] void halt(); void assert(int b) { - if (!b) // tracking-note{{Assuming 'b' is not equal to 0}} + if (!b) // tracking-note{{Assuming 'b' is not equal to 0, which will be (a part of a) condition}} // tracking-note@-1{{Taking false branch}} halt(); } @@ -437,7 +462,7 @@ [[noreturn]] void halt(); void assert(int b) { - if (!b) // tracking-note{{Assuming 'b' is not equal to 0}} + if (!b) // tracking-note{{Assuming 'b' is not equal to 0, which will be (a part of a) condition}} // tracking-note@-1{{Taking false branch}} halt(); } @@ -459,6 +484,31 @@ } // end of namespace unimportant_write_before_collapse_point +namespace collapse_point_not_in_condition_binary_op { + +[[noreturn]] void halt(); + +void check(int b) { + if (b == 1) // tracking-note{{Assuming 'b' is not equal to 1, which will be (a part of a) condition}} + // tracking-note@-1{{Taking false branch}} + halt(); +} + +void f(int flag) { + int *x = 0; // expected-note{{'x' initialized to a null pointer value}} + + check(flag); // tracking-note{{Calling 'check'}} + // tracking-note@-1{{Returning from 'check'}} + + if (flag) // expected-note{{'flag' is not equal to 0}} + // expected-note@-1{{Taking true branch}} + // debug-note@-2{{Tracking condition 'flag'}} + *x = 5; // expected-warning{{Dereference of null pointer}} + // expected-note@-1{{Dereference of null pointer}} +} + +} // end of namespace collapse_point_not_in_condition_binary_op + namespace collapse_point_not_in_condition_as_field { [[noreturn]] void halt(); @@ -467,7 +517,7 @@ IntWrapper(); void check() { - if (!b) // tracking-note{{Assuming field 'b' is not equal to 0}} + if (!b) // tracking-note{{Assuming field 'b' is not equal to 0, which will be (a part of a) condition}} // tracking-note@-1{{Taking false branch}} halt(); return; @@ -488,6 +538,65 @@ } // end of namespace collapse_point_not_in_condition_as_field +namespace assignemnt_in_condition_in_nested_stackframe { +int flag; + +bool coin(); + +[[noreturn]] void halt(); + +void foo() { + if ((flag = coin())) + // tracking-note@-1{{Value assigned to 'flag', which will be (a part of a) condition}} + // tracking-note@-2{{Assuming 'flag' is not equal to 0, which will be (a part of a) condition}} + // tracking-note@-3{{Taking true branch}} + return; + halt(); + return; +} + +void f() { + int *x = 0; // expected-note{{'x' initialized to a null pointer value}} + + foo(); // tracking-note{{Calling 'foo'}} + // tracking-note@-1{{Returning from 'foo'}} + if (flag) // expected-note{{'flag' is not equal to 0}} + // expected-note@-1{{Taking true branch}} + // debug-note@-2{{Tracking condition 'flag'}} + *x = 5; // expected-warning{{Dereference of null pointer}} + // expected-note@-1{{Dereference of null pointer}} +} +} // end of namespace assignemnt_in_condition_in_nested_stackframe + +namespace condition_variable_less { +int flag; + +bool coin(); + +[[noreturn]] void halt(); + +void foo() { + if (flag > 0) + // tracking-note@-1{{Assuming 'flag' is > 0, which will be (a part of a) condition}} + // tracking-note@-2{{Taking true branch}} + return; + halt(); + return; +} + +void f() { + int *x = 0; // expected-note{{'x' initialized to a null pointer value}} + + foo(); // tracking-note{{Calling 'foo'}} + // tracking-note@-1{{Returning from 'foo'}} + if (flag) // expected-note{{'flag' is not equal to 0}} + // expected-note@-1{{Taking true branch}} + // debug-note@-2{{Tracking condition 'flag'}} + *x = 5; // expected-warning{{Dereference of null pointer}} + // expected-note@-1{{Dereference of null pointer}} +} +} // end of namespace condition_variable_less + namespace dont_track_assertlike_conditions { extern void __assert_fail (__const char *__assertion, __const char *__file,