Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -213,6 +213,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)) @@ -2490,6 +2506,10 @@ const LocationContext *LCtx = N->getLocationContext(); const SourceManager &SM = BRC.getSourceManager(); + 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]); @@ -2535,6 +2555,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)) @@ -2560,6 +2583,9 @@ const LocationContext *LCtx = N->getLocationContext(); + if (isVarAnInterestingCondition(DRE, N, &report)) + Out << WillBeUsedForACondition; + // If we know the value create a pop-up note to the 'DRE'. if (!IsAssuming) { PathDiagnosticLocation Loc(DRE, BRC.getSourceManager(), LCtx); @@ -2599,6 +2625,10 @@ 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 @@ -443,7 +443,7 @@ int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}} auto lambda = [flag]() { - if (!flag) // tracking-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}} + if (!flag) // tracking-note-re{{{{^}}Assuming 'flag' is not equal to 0, which participates in a condition later{{$}}}} // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}} halt(); }; @@ -474,7 +474,7 @@ int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}} auto lambda = [&flag]() { - if (!flag) // tracking-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}} + if (!flag) // tracking-note-re{{{{^}}Assuming 'flag' is not equal to 0, which participates in a condition later{{$}}}} // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}} halt(); }; @@ -486,18 +486,42 @@ if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}} // expected-note-re@-1{{{{^}}Taking true branch{{$}}}} - // debug-note-re@-2{{{{^}}Tracking condition 'flag'}} + // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}} *x = 5; // expected-warning{{Dereference of null pointer}} // expected-note@-1{{Dereference of null pointer}} } } // end of namespace condition_lambda_capture_by_reference_assumption +namespace collapse_point_not_in_condition_bool { + +[[noreturn]] void halt(); + +void check(bool b) { + if (!b) // tracking-note-re{{{{^}}Assuming 'b' is true, which participates in a condition later{{$}}}} + // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}} + halt(); +} + +void f(bool flag) { + int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}} + + check(flag); // tracking-note-re{{{{^}}Calling 'check'{{$}}}} + // tracking-note-re@-1{{{{^}}Returning from 'check'{{$}}}} + + if (flag) // expected-note-re{{{{^}}'flag' is true{{$}}}} + // expected-note-re@-1{{{{^}}Taking true branch{{$}}}} + // debug-note-re@-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-re{{{{^}}Assuming 'b' is not equal to 0{{$}}}} + if (!b) // tracking-note-re{{{{^}}Assuming 'b' is not equal to 0, which participates in a condition later{{$}}}} // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}} halt(); } @@ -522,7 +546,7 @@ [[noreturn]] void halt(); void assert(int b) { - if (!b) // tracking-note-re{{{{^}}Assuming 'b' is not equal to 0{{$}}}} + if (!b) // tracking-note-re{{{{^}}Assuming 'b' is not equal to 0, which participates in a condition later{{$}}}} // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}} halt(); } @@ -544,6 +568,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-re{{{{^}}Assuming 'b' is not equal to 1, which participates in a condition later{{$}}}} + // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}} + halt(); +} + +void f(int flag) { + int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}} + + check(flag); // tracking-note-re{{{{^}}Calling 'check'{{$}}}} + // tracking-note-re@-1{{{{^}}Returning from 'check'{{$}}}} + + if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}} + // expected-note-re@-1{{{{^}}Taking true branch{{$}}}} + // debug-note-re@-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(); @@ -552,7 +601,7 @@ IntWrapper(); void check() { - if (!b) // tracking-note-re{{{{^}}Assuming field 'b' is not equal to 0{{$}}}} + if (!b) // tracking-note-re{{{{^}}Assuming field 'b' is not equal to 0, which participates in a condition later{{$}}}} // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}} halt(); return; @@ -573,6 +622,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-re@-1{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}} + // tracking-note-re@-2{{{{^}}Assuming 'flag' is not equal to 0, which participates in a condition later{{$}}}} + // tracking-note-re@-3{{{{^}}Taking true branch{{$}}}} + return; + halt(); + return; +} + +void f() { + int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}} + + foo(); // tracking-note-re{{{{^}}Calling 'foo'{{$}}}} + // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}} + if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}} + // expected-note-re@-1{{{{^}}Taking true branch{{$}}}} + // debug-note-re@-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-re@-1{{{{^}}Assuming 'flag' is > 0, which participates in a condition later{{$}}}} + // tracking-note-re@-2{{{{^}}Taking true branch{{$}}}} + return; + halt(); + return; +} + +void f() { + int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}} + + foo(); // tracking-note-re{{{{^}}Calling 'foo'{{$}}}} + // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}} + if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}} + // expected-note-re@-1{{{{^}}Taking true branch{{$}}}} + // debug-note-re@-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,