]> granicus.if.org Git - clang/commitdiff
[analyzer] Flatten path diagnostics for text output like we do for HTML.
authorJordan Rose <jordan_rose@apple.com>
Fri, 3 Aug 2012 23:08:54 +0000 (23:08 +0000)
committerJordan Rose <jordan_rose@apple.com>
Fri, 3 Aug 2012 23:08:54 +0000 (23:08 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161279 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
lib/StaticAnalyzer/Core/PathDiagnostic.cpp
lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
test/Analysis/inlining/path-notes.c [new file with mode: 0644]

index 73958a6ef480a031fa731abda5bad48108d5de41..2e7abfa5cc3bbe94e723eb6e3a0fb86bbed5a397 100644 (file)
@@ -350,10 +350,17 @@ public:
 };
   
   
-class PathPieces :
-  public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > {
+class PathPieces : public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > {
+  void flattenTo(PathPieces &Primary, PathPieces &Current,
+                 bool ShouldFlattenMacros) const;
 public:
-  ~PathPieces();  
+  ~PathPieces();
+
+  PathPieces flatten(bool ShouldFlattenMacros) const {
+    PathPieces Result;
+    flattenTo(Result, Result, ShouldFlattenMacros);
+    return Result;
+  }
 };
 
 class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
index ded341caf9f58821a9f30aa13ee59328687c18fc..3dedcb3edf0378c5981c9036b1917fc6a8d2998c 100644 (file)
@@ -707,6 +707,9 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString,
                                            BugReporterContext &BRC,
                                            BugReport &report,
                                            const ExplodedNode *N) {
+  // FIXME: If there's already a constraint tracker for this variable,
+  // we shouldn't emit anything here (c.f. the double note in
+  // test/Analysis/inlining/path-notes.c)
   SmallString<256> buf;
   llvm::raw_svector_ostream Out(buf);
   Out << "Assuming " << LhsString << " is ";
index f6e8dccdfb7994ee94fefd29ec39fa854bae74ca..0152e328e508def7be7e8757a02f73eb07feb43c 100644 (file)
@@ -95,37 +95,6 @@ void HTMLDiagnostics::FlushDiagnosticsImpl(
   }
 }
 
-static void flattenPath(PathPieces &primaryPath, PathPieces &currentPath,
-                        const PathPieces &oldPath) {
-  for (PathPieces::const_iterator it = oldPath.begin(), et = oldPath.end();
-       it != et; ++it ) {
-    PathDiagnosticPiece *piece = it->getPtr();
-    if (const PathDiagnosticCallPiece *call =
-        dyn_cast<PathDiagnosticCallPiece>(piece)) {
-      IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnter =
-        call->getCallEnterEvent();
-      if (callEnter)
-        currentPath.push_back(callEnter);
-      flattenPath(primaryPath, primaryPath, call->path);
-      IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
-        call->getCallExitEvent();
-      if (callExit)
-        currentPath.push_back(callExit);
-      continue;
-    }
-    if (PathDiagnosticMacroPiece *macro =
-        dyn_cast<PathDiagnosticMacroPiece>(piece)) {
-      currentPath.push_back(piece);
-      PathPieces newPath;
-      flattenPath(primaryPath, newPath, macro->subPieces);
-      macro->subPieces = newPath;
-      continue;
-    }
-    
-    currentPath.push_back(piece);
-  }
-}
-
 void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
                                  SmallVectorImpl<std::string> *FilesMade) {
     
@@ -152,8 +121,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
     return;
 
   // First flatten out the entire path to make it easier to use.
-  PathPieces path;
-  flattenPath(path, path, D.path);
+  PathPieces path = D.path.flatten(/*ShouldFlattenMacros=*/false);
 
   // The path as already been prechecked that all parts of the path are
   // from the same file and that it is non-empty.
index c482d6796c01037e97abcd00f225850f2adf0da2..7d52aac71c25ed65f3d781c23a7175115c01264d 100644 (file)
@@ -59,6 +59,48 @@ PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
 
 
 PathPieces::~PathPieces() {}
+
+void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
+                           bool ShouldFlattenMacros) const {
+  for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
+    PathDiagnosticPiece *Piece = I->getPtr();
+
+    switch (Piece->getKind()) {
+    case PathDiagnosticPiece::Call: {
+      PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece);
+      IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter =
+        Call->getCallEnterEvent();
+      if (CallEnter)
+        Current.push_back(CallEnter);
+      Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros);
+      IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
+        Call->getCallExitEvent();
+      if (callExit)
+        Current.push_back(callExit);
+      break;
+    }
+    case PathDiagnosticPiece::Macro: {
+      PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece);
+      if (ShouldFlattenMacros) {
+        Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
+      } else {
+        Current.push_back(Piece);
+        PathPieces NewPath;
+        Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
+        // FIXME: This probably shouldn't mutate the original path piece.
+        Macro->subPieces = NewPath;
+      }
+      break;
+    }
+    case PathDiagnosticPiece::Event:
+    case PathDiagnosticPiece::ControlFlow:
+      Current.push_back(Piece);
+      break;
+    }
+  }
+}
+
+
 PathDiagnostic::~PathDiagnostic() {}
 
 PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
index fe912dfd21f9a29608bec6dbe0a29b9811456582..e5b8553aeda1f01e42677f539cb9baaf93a0df40 100644 (file)
@@ -42,6 +42,7 @@ public:
   bool supportsLogicalOpControlFlow() const { return true; }
   bool supportsAllBlockEdges() const { return true; }
   virtual bool useVerboseDescription() const { return true; }
+  virtual bool supportsCrossFileDiagnostics() const { return true; }
 };
 
 } // end anonymous namespace
@@ -58,7 +59,9 @@ void TextPathDiagnostics::FlushDiagnosticsImpl(
   for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(),
        et = Diags.end(); it != et; ++it) {
     const PathDiagnostic *D = *it;
-    for (PathPieces::const_iterator I = D->path.begin(), E = D->path.end(); 
+
+    PathPieces FlatPath = D->path.flatten(/*ShouldFlattenMacros=*/true);
+    for (PathPieces::const_iterator I = FlatPath.begin(), E = FlatPath.end(); 
          I != E; ++I) {
       unsigned diagID =
         Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note,
diff --git a/test/Analysis/inlining/path-notes.c b/test/Analysis/inlining/path-notes.c
new file mode 100644 (file)
index 0000000..1db3c5a
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-output=text -verify %s
+
+void zero(int **p) {
+  *p = 0;
+  // expected-note@-1 {{Null pointer value stored to 'a'}}
+}
+
+void testZero(int *a) {
+  zero(&a);
+  // expected-note@-1 {{Calling 'zero'}}
+  // expected-note@-2 {{Returning from 'zero'}}
+  *a = 1; // expected-warning{{Dereference of null pointer}}
+  // expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}}
+}
\ No newline at end of file