[cfe-commits] r148997 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp lib/StaticAnalyzer/Core/PathDiagnostic.cpp lib/StaticAnalyzer/Core/PlistDiagnostics.cpp lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp test/Analysis/inline-unique-reports.c

Ted Kremenek kremenek at apple.com
Wed Jan 25 15:47:15 PST 2012


Author: kremenek
Date: Wed Jan 25 17:47:14 2012
New Revision: 148997

URL: http://llvm.org/viewvc/llvm-project?rev=148997&view=rev
Log:
Rework flushing of diagnostics to PathDiagnosticConsumer.  Now all the reports are batched up before being flushed
to the underlying consumer implementation.  This allows us to unique reports across analyses to multiple functions (which
shows up with inlining).

Added:
    cfe/trunk/test/Analysis/inline-unique-reports.c
Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
    cfe/trunk/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h?rev=148997&r1=148996&r2=148997&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h Wed Jan 25 17:47:14 2012
@@ -48,20 +48,18 @@
 class PathDiagnosticConsumer {
   virtual void anchor();
 public:
-  PathDiagnosticConsumer() {}
+  PathDiagnosticConsumer() : flushed(false) {}
+  virtual ~PathDiagnosticConsumer();
+
+  void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade);
+
+  virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
+                                    SmallVectorImpl<std::string> *FilesMade)
+                                    = 0;
 
-  virtual ~PathDiagnosticConsumer() {}
-  
-  virtual void
-  FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade = 0) = 0;
-  
-  void FlushDiagnostics(SmallVectorImpl<std::string> &FilesMade) {
-    FlushDiagnostics(&FilesMade);
-  }
-  
   virtual StringRef getName() const = 0;
   
-  void HandlePathDiagnostic(const PathDiagnostic* D);
+  void HandlePathDiagnostic(PathDiagnostic *D);
 
   enum PathGenerationScheme { Minimal, Extensive };
   virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
@@ -70,10 +68,8 @@
   virtual bool useVerboseDescription() const { return true; }
 
 protected:
-  /// The actual logic for handling path diagnostics, as implemented
-  /// by subclasses of PathDiagnosticConsumer.
-  virtual void HandlePathDiagnosticImpl(const PathDiagnostic* D) = 0;
-
+  bool flushed;
+  llvm::FoldingSet<PathDiagnostic> Diags;
 };
 
 //===----------------------------------------------------------------------===//
@@ -597,6 +593,8 @@
   }
   
   void Profile(llvm::FoldingSetNodeID &ID) const;
+  
+  void FullProfile(llvm::FoldingSetNodeID &ID) const;
 };  
 
 } // end GR namespace

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h?rev=148997&r1=148996&r2=148997&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h Wed Jan 25 17:47:14 2012
@@ -138,7 +138,7 @@
   
   void FlushDiagnostics() {
     if (PD.get())
-      PD->FlushDiagnostics();
+      PD->FlushDiagnostics(0);
   }
 
   unsigned getMaxNodes() const { return MaxNodes; }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp?rev=148997&r1=148996&r2=148997&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp Wed Jan 25 17:47:14 2012
@@ -39,15 +39,13 @@
   llvm::sys::Path Directory, FilePrefix;
   bool createdDir, noDir;
   const Preprocessor &PP;
-  std::vector<const PathDiagnostic*> BatchedDiags;
 public:
   HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp);
 
   virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); }
 
-  virtual void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade);
-
-  virtual void HandlePathDiagnosticImpl(const PathDiagnostic* D);
+  virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
+                                    SmallVectorImpl<std::string> *FilesMade);
 
   virtual StringRef getName() const {
     return "HTMLDiagnostics";
@@ -88,30 +86,13 @@
 // Report processing.
 //===----------------------------------------------------------------------===//
 
-void HTMLDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) {
-  if (!D)
-    return;
-
-  if (D->empty()) {
-    delete D;
-    return;
+void HTMLDiagnostics::FlushDiagnosticsImpl(
+  std::vector<const PathDiagnostic *> &Diags,
+  SmallVectorImpl<std::string> *FilesMade) {
+  for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(),
+       et = Diags.end(); it != et; ++it) {
+    ReportDiag(**it, FilesMade);
   }
-
-  const_cast<PathDiagnostic*>(D)->flattenLocations();
-  BatchedDiags.push_back(D);
-}
-
-void
-HTMLDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade)
-{
-  while (!BatchedDiags.empty()) {
-    const PathDiagnostic* D = BatchedDiags.back();
-    BatchedDiags.pop_back();
-    ReportDiag(*D, FilesMade);
-    delete D;
-  }
-
-  BatchedDiags.clear();
 }
 
 void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,

Modified: cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp?rev=148997&r1=148996&r2=148997&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp Wed Jan 25 17:47:14 2012
@@ -84,11 +84,122 @@
 
 void PathDiagnosticConsumer::anchor() { }
 
-void PathDiagnosticConsumer::HandlePathDiagnostic(const PathDiagnostic *D) {
-  // For now this simply forwards to HandlePathDiagnosticImpl.  In the future
-  // we can use this indirection to control for multi-threaded access to
-  // the PathDiagnosticConsumer from multiple bug reporters.
-  HandlePathDiagnosticImpl(D);
+PathDiagnosticConsumer::~PathDiagnosticConsumer() {
+  // Delete the contents of the FoldingSet if it isn't empty already.
+  for (llvm::FoldingSet<PathDiagnostic>::iterator it =
+       Diags.begin(), et = Diags.end() ; it != et ; ++it) {
+    delete &*it;
+  }
+}
+
+void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
+  if (!D)
+    return;
+  
+  if (D->empty()) {
+    delete D;
+    return;
+  }
+  
+  // We need to flatten the locations (convert Stmt* to locations) because
+  // the referenced statements may be freed by the time the diagnostics
+  // are emitted.
+  D->flattenLocations();
+
+  // Profile the node to see if we already have something matching it
+  llvm::FoldingSetNodeID profile;
+  D->Profile(profile);
+  void *InsertPos = 0;
+
+  if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
+    // Keep the PathDiagnostic with the shorter path.
+    if (orig->size() <= D->size()) {
+      bool shouldKeepOriginal = true;
+      if (orig->size() == D->size()) {
+        // Here we break ties in a fairly arbitrary, but deterministic, way.
+        llvm::FoldingSetNodeID fullProfile, fullProfileOrig;
+        D->FullProfile(fullProfile);
+        orig->FullProfile(fullProfileOrig);
+        if (fullProfile.ComputeHash() < fullProfileOrig.ComputeHash())
+          shouldKeepOriginal = false;
+      }
+
+      if (shouldKeepOriginal) {
+        delete D;
+        return;
+      }
+    }
+    Diags.RemoveNode(orig);
+    delete orig;
+  }
+  
+  Diags.InsertNode(D);
+}
+
+
+namespace {
+struct CompareDiagnostics {
+  // Compare if 'X' is "<" than 'Y'.
+  bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
+    // First compare by location
+    const FullSourceLoc &XLoc = X->getLocation().asLocation();
+    const FullSourceLoc &YLoc = Y->getLocation().asLocation();
+    if (XLoc < YLoc)
+      return true;
+    if (XLoc != YLoc)
+      return false;
+    
+    // Next, compare by bug type.
+    StringRef XBugType = X->getBugType();
+    StringRef YBugType = Y->getBugType();
+    if (XBugType < YBugType)
+      return true;
+    if (XBugType != YBugType)
+      return false;
+    
+    // Next, compare by bug description.
+    StringRef XDesc = X->getDescription();
+    StringRef YDesc = Y->getDescription();
+    if (XDesc < YDesc)
+      return true;
+    if (XDesc != YDesc)
+      return false;
+    
+    // FIXME: Further refine by comparing PathDiagnosticPieces?
+    return false;    
+  }  
+};  
+}
+
+void
+PathDiagnosticConsumer::FlushDiagnostics(SmallVectorImpl<std::string> *Files) {
+  if (flushed)
+    return;
+  
+  flushed = true;
+  
+  std::vector<const PathDiagnostic *> BatchDiags;
+  for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
+       et = Diags.end(); it != et; ++it) {
+    BatchDiags.push_back(&*it);
+  }
+  
+  // Clear out the FoldingSet.
+  Diags.clear();
+
+  // Sort the diagnostics so that they are always emitted in a deterministic
+  // order.
+  if (!BatchDiags.empty())
+    std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
+  
+  FlushDiagnosticsImpl(BatchDiags, Files);
+
+  // Delete the flushed diagnostics.
+  for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
+       et = BatchDiags.end(); it != et; ++it) {
+    const PathDiagnostic *D = *it;
+    delete D;
+  }
 }
 
 //===----------------------------------------------------------------------===//
@@ -366,13 +477,17 @@
 }
 
 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
-  ID.AddInteger(Size);
+  if (Size)
+    getLocation().Profile(ID);
   ID.AddString(BugType);
   ID.AddString(Desc);
   ID.AddString(Category);
+}
+
+void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
+  Profile(ID);
   for (const_iterator I = begin(), E = end(); I != E; ++I)
     ID.Add(*I);
-  
   for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
     ID.AddString(*I);
 }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp?rev=148997&r1=148996&r2=148997&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp Wed Jan 25 17:47:14 2012
@@ -25,43 +25,9 @@
 
 typedef llvm::DenseMap<FileID, unsigned> FIDMap;
 
-namespace {
-struct CompareDiagnostics {
-  // Compare if 'X' is "<" than 'Y'.
-  bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
-    // First compare by location
-    const FullSourceLoc &XLoc = X->getLocation().asLocation();
-    const FullSourceLoc &YLoc = Y->getLocation().asLocation();
-    if (XLoc < YLoc)
-      return true;
-    if (XLoc != YLoc)
-      return false;
-    
-    // Next, compare by bug type.
-    StringRef XBugType = X->getBugType();
-    StringRef YBugType = Y->getBugType();
-    if (XBugType < YBugType)
-      return true;
-    if (XBugType != YBugType)
-      return false;
-    
-    // Next, compare by bug description.
-    StringRef XDesc = X->getDescription();
-    StringRef YDesc = Y->getDescription();
-    if (XDesc < YDesc)
-      return true;
-    if (XDesc != YDesc)
-      return false;
-    
-    // FIXME: Further refine by comparing PathDiagnosticPieces?
-    return false;    
-  }  
-};  
-}
 
 namespace {
   class PlistDiagnostics : public PathDiagnosticConsumer {
-    std::vector<const PathDiagnostic*> BatchedDiags;
     const std::string OutputFile;
     const LangOptions &LangOpts;
     llvm::OwningPtr<PathDiagnosticConsumer> SubPD;
@@ -70,11 +36,10 @@
     PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts,
                      PathDiagnosticConsumer *subPD);
 
-    ~PlistDiagnostics() { FlushDiagnostics(NULL); }
+    virtual ~PlistDiagnostics() {}
 
-    void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade);
-    
-    void HandlePathDiagnosticImpl(const PathDiagnostic* D);
+    void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
+                              SmallVectorImpl<std::string> *FilesMade);
     
     virtual StringRef getName() const {
       return "PlistDiagnostics";
@@ -321,46 +286,20 @@
   }
 }
 
-void PlistDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) {
-  if (!D)
-    return;
-
-  if (D->empty()) {
-    delete D;
-    return;
-  }
-
-  // We need to flatten the locations (convert Stmt* to locations) because
-  // the referenced statements may be freed by the time the diagnostics
-  // are emitted.
-  const_cast<PathDiagnostic*>(D)->flattenLocations();
-  BatchedDiags.push_back(D);
-}
-
-void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string>
-                                        *FilesMade) {
-  
-  if (flushed)
-    return;
-  
-  flushed = true;
-  
-  // Sort the diagnostics so that they are always emitted in a deterministic
-  // order.
-  if (!BatchedDiags.empty())
-    std::sort(BatchedDiags.begin(), BatchedDiags.end(), CompareDiagnostics()); 
-
+void PlistDiagnostics::FlushDiagnosticsImpl(
+                                    std::vector<const PathDiagnostic *> &Diags,
+                                    SmallVectorImpl<std::string> *FilesMade) {
   // Build up a set of FIDs that we use by scanning the locations and
   // ranges of the diagnostics.
   FIDMap FM;
   SmallVector<FileID, 10> Fids;
   const SourceManager* SM = 0;
 
-  if (!BatchedDiags.empty())
-    SM = &(*BatchedDiags.begin())->begin()->getLocation().getManager();
+  if (!Diags.empty())
+    SM = &(*Diags.begin())->begin()->getLocation().getManager();
 
-  for (std::vector<const PathDiagnostic*>::iterator DI = BatchedDiags.begin(),
-       DE = BatchedDiags.end(); DI != DE; ++DI) {
+  for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(),
+       DE = Diags.end(); DI != DE; ++DI) {
 
     const PathDiagnostic *D = *DI;
 
@@ -406,16 +345,13 @@
        " <key>diagnostics</key>\n"
        " <array>\n";
 
-  for (std::vector<const PathDiagnostic*>::iterator DI=BatchedDiags.begin(),
-       DE = BatchedDiags.end(); DI!=DE; ++DI) {
+  for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(),
+       DE = Diags.end(); DI!=DE; ++DI) {
 
     o << "  <dict>\n"
          "   <key>path</key>\n";
 
     const PathDiagnostic *D = *DI;
-    // Create an owning smart pointer for 'D' just so that we auto-free it
-    // when we exit this method.
-    llvm::OwningPtr<PathDiagnostic> OwnedD(const_cast<PathDiagnostic*>(D));
 
     o << "   <array>\n";
 
@@ -438,9 +374,10 @@
 
     // Output the diagnostic to the sub-diagnostic client, if any.
     if (SubPD) {
-      SubPD->HandlePathDiagnostic(OwnedD.take());
+      std::vector<const PathDiagnostic *> SubDiags;
+      SubDiags.push_back(D);
       SmallVector<std::string, 1> SubFilesMade;
-      SubPD->FlushDiagnostics(SubFilesMade);
+      SubPD->FlushDiagnosticsImpl(SubDiags, &SubFilesMade);
 
       if (!SubFilesMade.empty()) {
         o << "  <key>" << SubPD->getName() << "_files</key>\n";
@@ -462,6 +399,4 @@
   
   if (FilesMade)
     FilesMade->push_back(OutputFile);
-  
-  BatchedDiags.clear();
 }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp?rev=148997&r1=148996&r2=148997&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp Wed Jan 25 17:47:14 2012
@@ -31,9 +31,8 @@
   TextPathDiagnostics(const std::string& output, DiagnosticsEngine &diag)
     : OutputFile(output), Diag(diag) {}
 
-  void HandlePathDiagnosticImpl(const PathDiagnostic* D);
-
-  void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade) { }
+  void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
+                            SmallVectorImpl<std::string> *FilesMade);
   
   virtual StringRef getName() const {
     return "TextPathDiagnostics";
@@ -53,18 +52,17 @@
   return new TextPathDiagnostics(out, PP.getDiagnostics());
 }
 
-void TextPathDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) {
-  if (!D)
-    return;
-
-  if (D->empty()) {
-    delete D;
-    return;
-  }
-
-  for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I) {
-    unsigned diagID = Diag.getDiagnosticIDs()->getCustomDiagID(
-                                           DiagnosticIDs::Note, I->getString());
-    Diag.Report(I->getLocation().asLocation(), diagID);
+void TextPathDiagnostics::FlushDiagnosticsImpl(
+                              std::vector<const PathDiagnostic *> &Diags,
+                              SmallVectorImpl<std::string> *FilesMade) {
+  for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(),
+       et = Diags.end(); it != et; ++it) {
+    const PathDiagnostic *D = *it;
+    for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I) {
+      unsigned diagID =
+        Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note,
+                                                 I->getString());
+      Diag.Report(I->getLocation().asLocation(), diagID);
+    }
   }
 }

Added: cfe/trunk/test/Analysis/inline-unique-reports.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inline-unique-reports.c?rev=148997&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/inline-unique-reports.c (added)
+++ cfe/trunk/test/Analysis/inline-unique-reports.c Wed Jan 25 17:47:14 2012
@@ -0,0 +1,139 @@
+// RUN: %clang --analyze %s -Xclang -analyzer-inline-call -o %t > /dev/null 2>&1
+// RUN: FileCheck -input-file %t %s
+
+static inline bug(int *p) {
+  *p = 0xDEADBEEF;
+}
+
+void test_bug_1() {
+  int *p = 0;
+  bug(p);
+}
+
+void test_bug_2() {
+  int *p = 0;
+  bug(p);
+}
+
+// CHECK: <?xml version="1.0" encoding="UTF-8"?>
+// CHECK: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+// CHECK: <plist version="1.0">
+// CHECK: <dict>
+// CHECK:  <key>files</key>
+// CHECK:  <array>
+// CHECK:  </array>
+// CHECK:  <key>diagnostics</key>
+// CHECK:  <array>
+// CHECK:   <dict>
+// CHECK:    <key>path</key>
+// CHECK:    <array>
+// CHECK:     <dict>
+// CHECK:      <key>kind</key><string>control</string>
+// CHECK:      <key>edges</key>
+// CHECK:       <array>
+// CHECK:        <dict>
+// CHECK:         <key>start</key>
+// CHECK:          <array>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>5</integer>
+// CHECK:            <key>col</key><integer>3</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>5</integer>
+// CHECK:            <key>col</key><integer>3</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:          </array>
+// CHECK:         <key>end</key>
+// CHECK:          <array>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>9</integer>
+// CHECK:            <key>col</key><integer>12</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>9</integer>
+// CHECK:            <key>col</key><integer>12</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:          </array>
+// CHECK:        </dict>
+// CHECK:       </array>
+// CHECK:     </dict>
+// CHECK:     <dict>
+// CHECK:      <key>kind</key><string>control</string>
+// CHECK:      <key>edges</key>
+// CHECK:       <array>
+// CHECK:        <dict>
+// CHECK:         <key>start</key>
+// CHECK:          <array>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>9</integer>
+// CHECK:            <key>col</key><integer>12</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>9</integer>
+// CHECK:            <key>col</key><integer>12</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:          </array>
+// CHECK:         <key>end</key>
+// CHECK:          <array>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>5</integer>
+// CHECK:            <key>col</key><integer>3</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:           <dict>
+// CHECK:            <key>line</key><integer>5</integer>
+// CHECK:            <key>col</key><integer>4</integer>
+// CHECK:            <key>file</key><integer>0</integer>
+// CHECK:           </dict>
+// CHECK:          </array>
+// CHECK:        </dict>
+// CHECK:       </array>
+// CHECK:     </dict>
+// CHECK:     <dict>
+// CHECK:      <key>kind</key><string>event</string>
+// CHECK:      <key>location</key>
+// CHECK:      <dict>
+// CHECK:       <key>line</key><integer>5</integer>
+// CHECK:       <key>col</key><integer>3</integer>
+// CHECK:       <key>file</key><integer>0</integer>
+// CHECK:      </dict>
+// CHECK:      <key>ranges</key>
+// CHECK:      <array>
+// CHECK:        <array>
+// CHECK:         <dict>
+// CHECK:          <key>line</key><integer>5</integer>
+// CHECK:          <key>col</key><integer>4</integer>
+// CHECK:          <key>file</key><integer>0</integer>
+// CHECK:         </dict>
+// CHECK:         <dict>
+// CHECK:          <key>line</key><integer>5</integer>
+// CHECK:          <key>col</key><integer>4</integer>
+// CHECK:          <key>file</key><integer>0</integer>
+// CHECK:         </dict>
+// CHECK:        </array>
+// CHECK:      </array>
+// CHECK:      <key>extended_message</key>
+// CHECK:      <string>Dereference of null pointer (loaded from variable 'p')</string>
+// CHECK:      <key>message</key>
+// CHECK: <string>Dereference of null pointer (loaded from variable 'p')</string>
+// CHECK:     </dict>
+// CHECK:    </array>
+// CHECK:    <key>description</key><string>Dereference of null pointer (loaded from variable 'p')</string>
+// CHECK:    <key>category</key><string>Logic error</string>
+// CHECK:    <key>type</key><string>Dereference of null pointer</string>
+// CHECK:   <key>location</key>
+// CHECK:   <dict>
+// CHECK:    <key>line</key><integer>5</integer>
+// CHECK:    <key>col</key><integer>3</integer>
+// CHECK:    <key>file</key><integer>0</integer>
+// CHECK:   </dict>
+// CHECK:   </dict>
+// CHECK:  </array>
+// CHECK: </dict>
+// CHECK: </plist>





More information about the cfe-commits mailing list