[cfe-commits] r66524 - in /cfe/trunk/lib: Analysis/BugReporter.cpp Analysis/PathDiagnostic.cpp Frontend/HTMLDiagnostics.cpp

Ted Kremenek kremenek at apple.com
Mon Mar 9 22:16:17 PDT 2009


Author: kremenek
Date: Tue Mar 10 00:16:17 2009
New Revision: 66524

URL: http://llvm.org/viewvc/llvm-project?rev=66524&view=rev
Log:
BugReporter:
- Group control flow and event PathDiagnosticPieces into PathDiagnosticMacroPieces.
- Afterwards, eliminate any PathDiagnosticMacroPieces from a PathDiagnostic that
  contain no informative events.

HTMLDiagnostics:
- Use new information about PathDiagnosticMacroPieces to specially format
  message bubbles for macro expansions containing interesting events.

Modified:
    cfe/trunk/lib/Analysis/BugReporter.cpp
    cfe/trunk/lib/Analysis/PathDiagnostic.cpp
    cfe/trunk/lib/Frontend/HTMLDiagnostics.cpp

Modified: cfe/trunk/lib/Analysis/BugReporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BugReporter.cpp?rev=66524&r1=66523&r2=66524&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/BugReporter.cpp (original)
+++ cfe/trunk/lib/Analysis/BugReporter.cpp Tue Mar 10 00:16:17 2009
@@ -563,6 +563,98 @@
 };
 }
 
+/// CompactPathDiagnostic - This function postprocesses a PathDiagnostic object
+///  and collapses PathDiagosticPieces that are expanded by macros.
+static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
+  typedef std::vector<std::pair<PathDiagnosticMacroPiece*, SourceLocation> >
+          MacroStackTy;
+  
+  typedef std::vector<PathDiagnosticPiece*>
+          PiecesTy;
+  
+  MacroStackTy MacroStack;
+  PiecesTy Pieces;
+  
+  for (PathDiagnostic::iterator I = PD.begin(), E = PD.end(); I!=E; ++I) {
+    // Get the location of the PathDiagnosticPiece.
+    const FullSourceLoc Loc = I->getLocation();    
+    
+    // Determine the instantiation location, which is the location we group
+    // related PathDiagnosticPieces.
+    SourceLocation InstantiationLoc = Loc.isMacroID() ? 
+                                      SM.getInstantiationLoc(Loc) :
+                                      SourceLocation();
+    
+    if (Loc.isFileID()) {
+      MacroStack.clear();
+      Pieces.push_back(&*I);
+      continue;
+    }
+
+    assert(Loc.isMacroID());
+    
+    // Is the PathDiagnosticPiece within the same macro group?
+    if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
+      MacroStack.back().first->push_back(&*I);
+      continue;
+    }
+
+    // We aren't in the same group.  Are we descending into a new macro
+    // or are part of an old one?
+    PathDiagnosticMacroPiece *MacroGroup = 0;
+
+    SourceLocation ParentInstantiationLoc = InstantiationLoc.isMacroID() ?
+                                          SM.getInstantiationLoc(Loc) :
+                                          SourceLocation();
+    
+    // Walk the entire macro stack.
+    while (!MacroStack.empty()) {
+      if (InstantiationLoc == MacroStack.back().second) {
+        MacroGroup = MacroStack.back().first;
+        break;
+      }
+      
+      if (ParentInstantiationLoc == MacroStack.back().second) {
+        MacroGroup = MacroStack.back().first;
+        break;
+      }
+      
+      MacroStack.pop_back();
+    }
+    
+    if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
+      // Create a new macro group and add it to the stack.
+      PathDiagnosticMacroPiece *NewGroup = new PathDiagnosticMacroPiece(Loc);
+
+      if (MacroGroup)
+        MacroGroup->push_back(NewGroup);
+      else {
+        assert(InstantiationLoc.isFileID());
+        Pieces.push_back(NewGroup);
+      }
+      
+      MacroGroup = NewGroup;
+      MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
+    }
+
+    // Finally, add the PathDiagnosticPiece to the group.
+    MacroGroup->push_back(&*I);
+  }
+  
+  // Now take the pieces and construct a new PathDiagnostic.
+  PD.resetPath(false);
+    
+  for (PiecesTy::iterator I=Pieces.begin(), E=Pieces.end(); I!=E; ++I) {
+    if (PathDiagnosticMacroPiece *MP=dyn_cast<PathDiagnosticMacroPiece>(*I))
+      if (!MP->containsEvent()) {
+        delete MP;
+        continue;
+      }
+    
+    PD.push_back(*I);
+  }
+}
+
 void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
                                            BugReportEquivClass& EQ) {
   
@@ -799,6 +891,10 @@
       getStateManager().iterBindings(N->getState(), SNS);
     }
   }
+  
+  // After constructing the full PathDiagnostic, do a pass over it to compact
+  // PathDiagnosticPieces that occur within a macro.
+  CompactPathDiagnostic(PD, getSourceManager());
 }
 
 

Modified: cfe/trunk/lib/Analysis/PathDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PathDiagnostic.cpp?rev=66524&r1=66523&r2=66524&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/PathDiagnostic.cpp (original)
+++ cfe/trunk/lib/Analysis/PathDiagnostic.cpp Tue Mar 10 00:16:17 2009
@@ -13,8 +13,24 @@
 
 #include "clang/Analysis/PathDiagnostic.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Casting.h"
 #include <sstream>
 using namespace clang;
+using llvm::dyn_cast;
+using llvm::isa;
+
+bool PathDiagnosticMacroPiece::containsEvent() const {
+  for (const_iterator I = begin(), E = end(); I!=E; ++I) {
+    if (isa<PathDiagnosticEventPiece>(*I))
+      return true;
+    
+    if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
+      if (MP->containsEvent())
+        return true;
+  }
+
+  return false;
+}
 
 static size_t GetNumCharsToLastNonPeriod(const char *s) {
   const char *start = s;
@@ -63,6 +79,16 @@
   for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
 }
 
+void PathDiagnostic::resetPath(bool deletePieces) {
+  Size = 0;
+
+  if (deletePieces)
+    for (iterator I=begin(), E=end(); I!=E; ++I)
+      delete &*I;
+  
+  path.clear();
+}
+
 
 PathDiagnostic::PathDiagnostic(const char* bugtype, const char* desc,
                                const char* category)

Modified: cfe/trunk/lib/Frontend/HTMLDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/HTMLDiagnostics.cpp?rev=66524&r1=66523&r2=66524&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/HTMLDiagnostics.cpp (original)
+++ cfe/trunk/lib/Frontend/HTMLDiagnostics.cpp Tue Mar 10 00:16:17 2009
@@ -20,6 +20,7 @@
 #include "clang/Rewrite/Rewriter.h"
 #include "clang/Rewrite/HTMLRewrite.h"
 #include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Streams.h"
@@ -48,6 +49,10 @@
   
   virtual void HandlePathDiagnostic(const PathDiagnostic* D);
   
+  unsigned ProcessMacroPiece(llvm::raw_ostream& os,
+                             const PathDiagnosticMacroPiece& P,
+                             unsigned num);
+    
   void HandlePiece(Rewriter& R, FileID BugFileID,
                    const PathDiagnosticPiece& P, unsigned num, unsigned max);
   
@@ -364,7 +369,32 @@
     PosNo += *c == '\t' ? 8 : 1;
   
   // Create the html for the message.
-  {
+
+  const char *Kind = 0;
+  switch (P.getKind()) {
+    case PathDiagnosticPiece::Event:  Kind = "Event"; break;
+    case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break;
+      // Setting Kind to "Control" is intentional.
+    case PathDiagnosticPiece::Macro: Kind = "Control"; break;
+  }
+    
+  std::string sbuf;
+  llvm::raw_string_ostream os(sbuf);
+    
+  os << "\n<tr><td class=\"num\"></td><td class=\"line\"><div id=\"";
+    
+  if (num == max)
+    os << "EndPath";
+  else
+    os << "Path" << num;
+    
+  os << "\" class=\"msg";
+  if (Kind)
+    os << " msg" << Kind;  
+  os << "\" style=\"margin-left:" << PosNo << "ex";
+    
+  // Output a maximum size.
+  if (!isa<PathDiagnosticMacroPiece>(P)) {
     // Get the string and determining its maximum substring.
     const std::string& Msg = P.getString();
     unsigned max_token = 0;
@@ -383,9 +413,10 @@
           cnt = 0;
       }
     
-    if (cnt > max_token) max_token = cnt;
+    if (cnt > max_token)
+      max_token = cnt;
     
-    // Next, determine the approximate size of the message bubble in em.
+    // Determine the approximate size of the message bubble in em.
     unsigned em;
     const unsigned max_line = 120;
     
@@ -394,7 +425,7 @@
     else {
       unsigned characters = max_line;
       unsigned lines = len / max_line;
-      
+    
       if (lines > 0) {
         for (; characters > max_token; --characters)
           if (len / characters > lines) {
@@ -402,60 +433,71 @@
             break;
           }
       }
-      
-      em = characters / 2;
-    }
     
-    // Now generate the message bubble. 
-    const char *Kind = 0;
-    switch (P.getKind()) {
-      case PathDiagnosticPiece::Event:  Kind = "Event"; break;
-      case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break;
-      case PathDiagnosticPiece::Macro: Kind = "Macro"; break;
+      em = characters / 2;
     }
-    
-    std::string sbuf;
-    llvm::raw_string_ostream os(sbuf);
-    
-    os << "\n<tr><td class=\"num\"></td><td class=\"line\"><div id=\"";
-    
-    if (num == max)
-      os << "EndPath";
-    else
-      os << "Path" << num;
-    
-    os << "\" class=\"msg";
-    if (Kind) os << " msg" << Kind;
-    os << "\" style=\"margin-left:" << PosNo << "ex";
-    if (em < max_line/2) os << "; max-width:" << em << "em";
-    os << "\">";
-    
-    if (max > 1) {
-      os << "<table class=\"msgT\"><tr><td valign=\"top\">";
-      os << "<div class=\"PathIndex";
-      if (Kind) os << " PathIndex" << Kind;
-      os << "\">" << num << "</div>";
-      os << "</td><td>";
+  
+    if (em < max_line/2)
+      os << "; max-width:" << em << "em";      
+  }
+  else
+    os << "; max-width:100em";
+  
+  os << "\">";
+  
+  if (max > 1) {
+    os << "<table class=\"msgT\"><tr><td valign=\"top\">";
+    os << "<div class=\"PathIndex";
+    if (Kind) os << " PathIndex" << Kind;
+    os << "\">" << num << "</div>";
+    os << "</td><td>";
+  }
+
+  if (const PathDiagnosticMacroPiece *MP =
+        dyn_cast<PathDiagnosticMacroPiece>(&P)) {        
+
+    os << "Within the expansion of the macro '";
+    
+    // Get the name of the macro by relexing it.
+    {
+      FullSourceLoc L = MP->getLocation().getInstantiationLoc();
+      assert(L.isFileID());
+      std::pair<const char*, const char*> BufferInfo = L.getBufferData();
+      const char* MacroName = L.getDecomposedLoc().second + BufferInfo.first;
+      Lexer rawLexer(L, PP->getLangOptions(), BufferInfo.first,
+                     MacroName, BufferInfo.second);
+      
+      Token TheTok;
+      rawLexer.LexFromRawLexer(TheTok);
+      for (unsigned i = 0, n = TheTok.getLength(); i < n; ++i)
+        os << MacroName[i];
     }
+      
+    os << "':\n";
     
-    os << html::EscapeText(Msg);
-    
-    if (max > 1) {
+    if (max > 1)
       os << "</td></tr></table>";
-    }
-    
-    os << "</div></td></tr>";
-
-    // Insert the new html.
-    unsigned DisplayPos = LineEnd - FileStart;    
-    SourceLocation Loc = 
-      SM.getLocForStartOfFile(LPosInfo.first).getFileLocWithOffset(DisplayPos);
 
-    R.InsertStrBefore(Loc, os.str());
+    // Within a macro piece.  Write out each event.
+    ProcessMacroPiece(os, *MP, 0);
+  }
+  else {
+    os << html::EscapeText(P.getString());
+    
+    if (max > 1)
+      os << "</td></tr></table>";
   }
   
-  // Now highlight the ranges.
-  
+  os << "</div></td></tr>";
+
+  // Insert the new html.
+  unsigned DisplayPos = LineEnd - FileStart;    
+  SourceLocation Loc = 
+    SM.getLocForStartOfFile(LPosInfo.first).getFileLocWithOffset(DisplayPos);
+
+  R.InsertStrBefore(Loc, os.str());
+
+  // Now highlight the ranges.  
   for (const SourceRange *I = P.ranges_begin(), *E = P.ranges_end();
         I != E; ++I)
     HighlightRange(R, LPosInfo.first, *I);
@@ -482,6 +524,50 @@
 #endif
 }
 
+static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) {
+  llvm::SmallVector<char, 10> buf;
+
+  do {
+    unsigned x = n % ('z' - 'a');
+    buf.push_back('a' + x);
+    n = n / ('z' - 'a');
+  } while (n);
+  
+  assert(!buf.empty());
+  
+  for (llvm::SmallVectorImpl<char>::reverse_iterator I=buf.rbegin(),
+       E=buf.rend(); I!=E; ++I)
+    os << *I;
+}
+
+unsigned HTMLDiagnostics::ProcessMacroPiece(llvm::raw_ostream& os,
+                                            const PathDiagnosticMacroPiece& P,
+                                            unsigned num) {
+  
+  for (PathDiagnosticMacroPiece::const_iterator I=P.begin(), E=P.end();
+        I!=E; ++I) {
+    
+    if (const PathDiagnosticMacroPiece *MP =
+          dyn_cast<PathDiagnosticMacroPiece>(*I)) {
+      num = ProcessMacroPiece(os, *MP, num);
+      continue;
+    }
+
+    if (PathDiagnosticEventPiece *EP = dyn_cast<PathDiagnosticEventPiece>(*I)) {
+      os << "<div class=\"msg msgEvent\" style=\"width:94%; "
+            "margin-left:5px\">"
+            "<table class=\"msgT\"><tr>"
+            "<td valign=\"top\"><div class=\"PathIndex PathIndexEvent\">";
+      EmitAlphaCounter(os, num++);
+      os << "</div></td><td valign=\"top\">"
+         << html::EscapeText(EP->getString())
+         << "</td></tr></table></div>\n";
+    }
+  }
+  
+  return num;
+}
+
 void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID,
                                      SourceRange Range,
                                      const char *HighlightStart,





More information about the cfe-commits mailing list