Szelethus created this revision.
Szelethus added reviewers: NoQ, baloghadamsoftware, xazax.hun, Charusso, 
rnkovacs, dcoughlin.
Szelethus added a project: clang.
Herald added subscribers: cfe-commits, gamesh411, dkrupp, donat.nagy, 
mikhail.ramalho, a.sidorin, szepet, whisperity.

Exactly what it says on the tin!

I expect this to be especially valuable on production code where control 
dependencies aren't obvious.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D63642

Files:
  clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/track-control-dependency-conditions.cpp

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
@@ -2,7 +2,23 @@
 // RUN:   -analyzer-config track-conditions=true \
 // RUN:   -analyzer-output=text \
 // RUN:   -analyzer-checker=core
+
+// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config track-conditions-debug=true \
+// RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-DEBUG
+
+// CHECK-INVALID-DEBUG: (frontend): invalid input for analyzer-config option
+// CHECK-INVALID-DEBUG-SAME:        'track-conditions-debug', that expects
+// CHECK-INVALID-DEBUG-SAME:        'track-conditions' to also be enabled
 //
+// RUN: %clang_analyze_cc1 %s -verify \
+// RUN:   -DTRACKING_CONDITIONS -DTRACKING_CONDITIONS_DEBUG \
+// RUN:   -analyzer-config track-conditions=true \
+// RUN:   -analyzer-config track-conditions-debug=true \
+// RUN:   -analyzer-output=text \
+// RUN:   -analyzer-checker=core
+
 // RUN: %clang_analyze_cc1 %s -verify \
 // RUN:   -analyzer-output=text \
 // RUN:   -analyzer-checker=core
@@ -35,6 +51,9 @@
 
   if (flag) // expected-note   {{Assuming 'flag' is not equal to 0}}
             // expected-note@-1{{Taking true branch}}
+#ifdef TRACKING_CONDITIONS_DEBUG
+            // expected-note@-3{{Tracking condition 'flag'}}
+#endif // TRACKING_CONDITIONS_DEBUG
     *x = 5; // expected-warning{{Dereference of null pointer}}
             // expected-note@-1{{Dereference of null pointer}}
 }
@@ -70,6 +89,9 @@
 
   if (flag) // expected-note   {{Assuming 'flag' is not equal to 0}}
             // expected-note@-1{{Taking true branch}}
+#ifdef TRACKING_CONDITIONS_DEBUG
+            // expected-note@-3{{Tracking condition 'flag'}}
+#endif // TRACKING_CONDITIONS_DEBUG
     *x = 5; // expected-warning{{Dereference of null pointer}}
             // expected-note@-1{{Dereference of null pointer}}
 }
@@ -102,8 +124,14 @@
 
   if (bar) // expected-note   {{Assuming 'bar' is not equal to 0}}
            // expected-note@-1{{Taking true branch}}
+#ifdef TRACKING_CONDITIONS_DEBUG
+           // expected-note@-3{{Tracking condition 'bar'}}
+#endif // TRACKING_CONDITIONS_DEBUG
     if (flag) // expected-note   {{Assuming 'flag' is not equal to 0}}
               // expected-note@-1{{Taking true branch}}
+#ifdef TRACKING_CONDITIONS_DEBUG
+              // expected-note@-3{{Tracking condition 'flag'}}
+#endif // TRACKING_CONDITIONS_DEBUG
       *x = 5; // expected-warning{{Dereference of null pointer}}
               // expected-note@-1{{Dereference of null pointer}}
 }
@@ -129,9 +157,13 @@
     // expected-note@-2{{Calling 'foo'}}
     // expected-note@-3{{Returning from 'foo'}}
     // expected-note@-4{{'flag' initialized here}}
+#ifdef TRACKING_CONDITIONS_DEBUG
+    // expected-note@-6{{Tracking condition 'flag'}}
+#endif // TRACKING_CONDITIONS_DEBUG
 #endif // TRACKING_CONDITIONS
-    // expected-note@-6{{Assuming 'flag' is not equal to 0}}
-    // expected-note@-7{{Taking true branch}}
+    // expected-note@-9{{Assuming 'flag' is not equal to 0}}
+    // expected-note@-10{{Taking true branch}}
+
     *x = 5; // expected-warning{{Dereference of null pointer}}
             // expected-note@-1{{Dereference of null pointer}}
 }
@@ -154,9 +186,12 @@
 #ifdef TRACKING_CONDITIONS
     // expected-note@-2 {{Calling 'ConvertsToBool::operator bool'}}
     // expected-note@-3{{Returning from 'ConvertsToBool::operator bool'}}
+#ifdef TRACKING_CONDITIONS_DEBUG
+    // expected-note@-5{{Tracking condition 'ConvertsToBool()'}}
+#endif // TRACKING_CONDITIONS_DEBUG
 #endif // TRACKING_CONDITIONS
-    // expected-note@-5{{Assuming the condition is true}}
-    // expected-note@-6{{Taking true branch}}
+    // expected-note@-8{{Assuming the condition is true}}
+    // expected-note@-9{{Taking true branch}}
     *x = 5; // expected-warning{{Dereference of null pointer}}
             // expected-note@-1{{Dereference of null pointer}}
 }
@@ -174,6 +209,9 @@
   int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
   if (flag) // expected-note{{Assuming 'flag' is not equal to 0}}
             // expected-note@-1{{Taking true branch}}
+#ifdef TRACKING_CONDITIONS_DEBUG
+            // expected-note@-3{{Tracking condition 'flag'}}
+#endif // TRACKING_CONDITIONS_DEBUG
     *x = 5; // expected-warning{{Dereference of null pointer}}
             // expected-note@-1{{Dereference of null pointer}}
 }
@@ -193,6 +231,9 @@
   int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
   if (flag) // expected-note{{'flag' is 1}}
             // expected-note@-1{{Taking true branch}}
+#ifdef TRACKING_CONDITIONS_DEBUG
+            // expected-note@-3{{Tracking condition 'flag'}}
+#endif // TRACKING_CONDITIONS_DEBUG
     *x = 5; // expected-warning{{Dereference of null pointer}}
             // expected-note@-1{{Dereference of null pointer}}
 }
@@ -222,6 +263,9 @@
 #endif // TRACKING_CONDITIONS
   if (flag) // expected-note{{'flag' is 1}}
             // expected-note@-1{{Taking true branch}}
+#ifdef TRACKING_CONDITIONS_DEBUG
+            // expected-note@-3{{Tracking condition 'flag'}}
+#endif // TRACKING_CONDITIONS_DEBUG
     *x = 5; // expected-warning{{Dereference of null pointer}}
             // expected-note@-1{{Dereference of null pointer}}
 }
@@ -249,6 +293,9 @@
 #endif // TRACKING_CONDITIONS
   if (flag) // expected-note{{'flag' is not equal to 0}}
             // expected-note@-1{{Taking true branch}}
+#ifdef TRACKING_CONDITIONS_DEBUG
+            // expected-note@-3{{Tracking condition 'flag'}}
+#endif // TRACKING_CONDITIONS_DEBUG
     *x = 5; // expected-warning{{Dereference of null pointer}}
             // expected-note@-1{{Dereference of null pointer}}
 }
@@ -280,6 +327,9 @@
 #endif // TRACKING_CONDITIONS
   if (flag) // expected-note{{'flag' is not equal to 0}}
             // expected-note@-1{{Taking true branch}}
+#ifdef TRACKING_CONDITIONS_DEBUG
+            // expected-note@-3{{Tracking condition 'flag'}}
+#endif // TRACKING_CONDITIONS_DEBUG
     *x = 5; // expected-warning{{Dereference of null pointer}}
             // expected-note@-1{{Dereference of null pointer}}
 }
Index: clang/test/Analysis/analyzer-config.c
===================================================================
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -85,8 +85,9 @@
 // CHECK-NEXT: suppress-inlined-defensive-checks = true
 // CHECK-NEXT: suppress-null-return-paths = true
 // CHECK-NEXT: track-conditions = false
+// CHECK-NEXT: track-conditions-debug = false
 // CHECK-NEXT: unix.DynamicMemoryModeling:Optimistic = false
 // CHECK-NEXT: unroll-loops = false
 // CHECK-NEXT: widen-loops = false
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 86
+// CHECK-NEXT: num-entries = 87
Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1603,6 +1603,26 @@
   return nullptr;
 }
 
+static std::shared_ptr<PathDiagnosticEventPiece>
+constructDebugPieceForTrackedCondition(const Expr *Cond,
+                                       const ExplodedNode *N,
+                                       BugReporterContext &BRC) {
+
+  if (BRC.getAnalyzerOptions().AnalysisDiagOpt == PD_NONE ||
+      !BRC.getAnalyzerOptions().ShouldTrackConditionsDebug)
+    return nullptr;
+
+  std::string ConditionText = Lexer::getSourceText(
+      CharSourceRange::getTokenRange(Cond->getSourceRange()),
+                                     BRC.getSourceManager(),
+                                     BRC.getASTContext().getLangOpts());
+
+  return std::make_shared<PathDiagnosticEventPiece>(
+      PathDiagnosticLocation::createBegin(
+          Cond, BRC.getSourceManager(), N->getLocationContext()),
+          (Twine() + "Tracking condition '" + ConditionText + "'").str());
+}
+
 std::shared_ptr<PathDiagnosticPiece>
 TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N,
                                                BugReporterContext &BRC,
@@ -1623,11 +1643,15 @@
   if (!OriginB || !NB)
     return nullptr;
 
-  if (ControlDeps.isControlDependent(OriginB, NB))
-    if (const Expr *Condition = NB->getTerminatorConditionExpr())
-      if (BR.addTrackedCondition(N))
+  if (ControlDeps.isControlDependent(OriginB, NB)) {
+    if (const Expr *Condition = NB->getTerminatorConditionExpr()) {
+      if (BR.addTrackedCondition(N)) {
         bugreporter::trackExpressionValue(
             N, Condition, BR, /*EnableNullFPSuppression=*/false);
+        return constructDebugPieceForTrackedCondition(Condition, N, BRC);
+      }
+    }
+  }
 
   return nullptr;
 }
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -467,6 +467,10 @@
   if (!Diags)
     return;
 
+  if (AnOpts.ShouldTrackConditionsDebug && !AnOpts.ShouldTrackConditions)
+    Diags->Report(diag::err_analyzer_config_invalid_input)
+        << "track-conditions-debug" << "'track-conditions' to also be enabled";
+
   if (!AnOpts.CTUDir.empty() && !llvm::sys::fs::is_directory(AnOpts.CTUDir))
     Diags->Report(diag::err_analyzer_config_invalid_input) << "ctu-dir"
                                                            << "a filename";
Index: clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
+++ clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
@@ -296,6 +296,10 @@
                 "an already tracked variable.",
                 false)
 
+ANALYZER_OPTION(bool, ShouldTrackConditionsDebug, "track-conditions-debug",
+                "Whether to place an event at each tracked condition.",
+                false)
+
 //===----------------------------------------------------------------------===//
 // Unsinged analyzer options.
 //===----------------------------------------------------------------------===//
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to