[cfe-commits] r49127 - in /cfe/trunk: include/clang/Analysis/PathSensitive/BugReporter.h lib/Analysis/BugReporter.cpp lib/Analysis/GRSimpleVals.cpp

Ted Kremenek kremenek at apple.com
Wed Apr 2 21:42:53 PDT 2008


Author: kremenek
Date: Wed Apr  2 23:42:52 2008
New Revision: 49127

URL: http://llvm.org/viewvc/llvm-project?rev=49127&view=rev
Log:
Created new path-sensitive bug-reporting scheme based on the classes
"BugReporter" and "BugDescription".  BugDescription is used to describe
a bug and provide pieces of the PathDiagnostic, and BugReporter creates
the actual PathDiagnostic by crawling through the ExplodedGraph.

Migrated checks done by GRSimpleVals to be reported using the new BugReporter
mechanism.


Added:
    cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h
    cfe/trunk/lib/Analysis/BugReporter.cpp
Modified:
    cfe/trunk/lib/Analysis/GRSimpleVals.cpp

Added: cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h?rev=49127&view=auto

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h (added)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h Wed Apr  2 23:42:52 2008
@@ -0,0 +1,74 @@
+// BugReporter.h - Generate PathDiagnostics  ----------*- C++ -*--//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines BugReporter, a utility class for generating
+//  PathDiagnostics for analyses based on ValueState.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER
+#define LLVM_CLANG_ANALYSIS_BUGREPORTER
+
+#include "clang/Analysis/PathSensitive/ValueState.h"
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+// FIXME: ExplodedGraph<> should be templated on state, not the checker engine.
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+
+namespace clang {
+  
+class PathDiagnostic;
+class PathDiagnosticPiece;
+class PathDiagnosticClient;
+class ASTContext;
+class Diagnostic;
+
+class BugDescription {
+public:
+  BugDescription() {}
+  virtual ~BugDescription() {}
+  
+  virtual const char* getName() const = 0;
+  
+  virtual const char* getDescription() const = 0;
+  
+  virtual PathDiagnosticPiece* getEndPath(ASTContext& Ctx,
+                                          ExplodedNode<ValueState> *N) const;
+};
+  
+class BugReporter {
+  llvm::SmallPtrSet<void*,10> CachedErrors;
+  
+public:
+  BugReporter() {}
+  ~BugReporter();
+  
+  void EmitPathWarning(Diagnostic& Diag, PathDiagnosticClient* PDC,
+                       ASTContext& Ctx, const BugDescription& B,
+                       ExplodedGraph<GRExprEngine>& G,
+                       ExplodedNode<ValueState>* N);
+  
+  void EmitWarning(Diagnostic& Diag, ASTContext& Ctx,
+                   const BugDescription& B,
+                   ExplodedNode<ValueState>* N);
+  
+
+private:
+  bool IsCached(ExplodedNode<ValueState>* N);
+  
+  void GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx,
+                              const BugDescription& B,
+                              ExplodedGraph<GRExprEngine>& G,
+                              ExplodedNode<ValueState>* N);
+};
+  
+} // end clang namespace
+
+#endif

Added: cfe/trunk/lib/Analysis/BugReporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BugReporter.cpp?rev=49127&view=auto

==============================================================================
--- cfe/trunk/lib/Analysis/BugReporter.cpp (added)
+++ cfe/trunk/lib/Analysis/BugReporter.cpp Wed Apr  2 23:42:52 2008
@@ -0,0 +1,262 @@
+// BugReporter.cpp - Generate PathDiagnostics for Bugs ------------*- C++ -*--//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines BugReporter, a utility class for generating
+//  PathDiagnostics for analyses based on GRSimpleVals.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CFG.h"
+#include "clang/AST/Expr.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include <sstream>
+
+using namespace clang;
+
+BugReporter::~BugReporter() {}
+
+static inline Stmt* GetStmt(const ProgramPoint& P) {
+  if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
+    return PS->getStmt();
+  }
+  else if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
+    return BE->getSrc()->getTerminator();
+  }
+  else if (const BlockEntrance* BE = dyn_cast<BlockEntrance>(&P)) {
+    return BE->getFirstStmt();
+  }
+  
+  assert (false && "Unsupported ProgramPoint.");
+  return NULL;
+}
+
+
+PathDiagnosticPiece*
+BugDescription::getEndPath(ASTContext& Ctx,
+                           ExplodedNode<ValueState> *N) const {
+  
+  Stmt* S = GetStmt(N->getLocation());
+  
+  if (!S)
+    return NULL;
+  
+  FullSourceLoc L(S->getLocStart(), Ctx.getSourceManager());  
+  PathDiagnosticPiece* P = new PathDiagnosticPiece(L, getDescription());
+  
+  if (Expr* E = dyn_cast<Expr>(S))
+    P->addRange(E->getSourceRange());
+  
+  return P;
+}
+
+void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx,
+                                         const BugDescription& B,
+                                         ExplodedGraph<GRExprEngine>& G,
+                                         ExplodedNode<ValueState>* N) {
+    
+  PD.push_back(B.getEndPath(Ctx, N));
+  
+  SourceManager& SMgr = Ctx.getSourceManager();
+  
+  
+  llvm::OwningPtr<ExplodedGraph<GRExprEngine> > GTrim(G.Trim(&N, &N+1));
+
+  while (!N->pred_empty()) {
+    
+    ExplodedNode<ValueState>* LastNode = N;
+    N = *(N->pred_begin());
+    
+    ProgramPoint P = N->getLocation();
+    
+    if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
+      
+      CFGBlock* Src = BE->getSrc();
+      CFGBlock* Dst = BE->getDst();
+      
+      Stmt* T = Src->getTerminator();
+      
+      if (!T)
+        continue;
+      
+      FullSourceLoc L(T->getLocStart(), SMgr);
+      
+      switch (T->getStmtClass()) {
+        default:
+          break;
+          
+        case Stmt::GotoStmtClass:
+        case Stmt::IndirectGotoStmtClass: {
+          
+          Stmt* S = GetStmt(LastNode->getLocation());
+          
+          if (!S)
+            continue;
+          
+          std::ostringstream os;
+          
+          os << "Control jumps to line "
+          << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";
+          
+          PD.push_front(new PathDiagnosticPiece(L, os.str()));
+          break;
+        }
+          
+        case Stmt::SwitchStmtClass: {
+          
+          // Figure out what case arm we took.
+          
+          Stmt* S = Dst->getLabel();
+          
+          if (!S)
+            continue;
+          
+          std::ostringstream os;
+          
+          switch (S->getStmtClass()) {
+            default:
+              continue;
+              
+            case Stmt::DefaultStmtClass: {
+              
+              os << "Control jumps to the 'default' case at line "
+              << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";
+              
+              break;
+            }
+              
+            case Stmt::CaseStmtClass: {
+              
+              os << "Control jumps to 'case ";
+              
+              Expr* CondE = cast<SwitchStmt>(T)->getCond();
+              unsigned bits = Ctx.getTypeSize(CondE->getType());
+              
+              llvm::APSInt V1(bits, false);
+              
+              CaseStmt* Case = cast<CaseStmt>(S);
+              
+              if (!Case->getLHS()->isIntegerConstantExpr(V1, Ctx, 0, true)) {
+                assert (false &&
+                        "Case condition must evaluate to an integer constant.");
+                continue;
+              }
+              
+              os << V1.toString();
+              
+              // Get the RHS of the case, if it exists.
+              
+              if (Expr* E = Case->getRHS()) {
+                
+                llvm::APSInt V2(bits, false);
+                
+                if (!E->isIntegerConstantExpr(V2, Ctx, 0, true)) {
+                  assert (false &&
+                  "Case condition (RHS) must evaluate to an integer constant.");
+                  continue;
+                }
+                
+                os << " .. " << V2.toString();
+              }
+              
+              os << ":'  at line " 
+              << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";
+              
+              break;
+              
+            }
+          }
+          
+          PD.push_front(new PathDiagnosticPiece(L, os.str()));
+          break;
+        }
+          
+          
+        case Stmt::DoStmtClass:
+        case Stmt::WhileStmtClass:
+        case Stmt::ForStmtClass:
+        case Stmt::IfStmtClass: {
+          
+          if (*(Src->succ_begin()+1) == Dst)
+            PD.push_front(new PathDiagnosticPiece(L, "Taking false branch."));
+          else 
+            PD.push_front(new PathDiagnosticPiece(L, "Taking true branch."));
+          
+          break;
+        }
+      }
+    }  
+  }
+}
+
+bool BugReporter::IsCached(ExplodedNode<ValueState>* N) {
+  
+  // HACK: Cache the location of the error.  Don't emit the same
+  // warning for the same error type that occurs at the same program
+  // location but along a different path.
+  
+  void* p = N->getLocation().getRawData();
+  
+  if (CachedErrors.count(p))
+    return true;
+  
+  CachedErrors.insert(p);
+  
+  return false;
+}
+
+void BugReporter::EmitPathWarning(Diagnostic& Diag,
+                                  PathDiagnosticClient* PDC,
+                                  ASTContext& Ctx,
+                                  const BugDescription& B,
+                                  ExplodedGraph<GRExprEngine>& G,
+                                  ExplodedNode<ValueState>* N) {
+  
+  if (!PDC) {
+    EmitWarning(Diag, Ctx, B, N);
+    return;
+  }
+  
+  if (IsCached(N))
+    return;
+  
+  PathDiagnostic D;  
+  GeneratePathDiagnostic(D, Ctx, B, G, N);
+  PDC->HandlePathDiagnostic(D);
+}
+
+
+void BugReporter::EmitWarning(Diagnostic& Diag, ASTContext& Ctx,
+                              const BugDescription& B,
+                              ExplodedNode<ValueState>* N) {  
+  if (IsCached(N))
+    return;
+  
+  std::ostringstream os;
+  os << "[CHECKER] " << B.getName();
+  
+  unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
+                                            os.str().c_str());
+
+  // FIXME: Add support for multiple ranges.
+  
+  Stmt* S = GetStmt(N->getLocation());
+  
+  if (!S)
+    return;
+  
+  SourceRange R = S->getSourceRange();
+  
+  Diag.Report(FullSourceLoc(S->getLocStart(), Ctx.getSourceManager()),
+              ErrorDiag, NULL, 0, &R, 1);   
+}

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

==============================================================================
--- cfe/trunk/lib/Analysis/GRSimpleVals.cpp (original)
+++ cfe/trunk/lib/Analysis/GRSimpleVals.cpp Wed Apr  2 23:42:52 2008
@@ -16,8 +16,10 @@
 #include "GRSimpleVals.h"
 #include "BasicObjCFoundationChecks.h"
 #include "clang/Basic/SourceManager.h"
-#include "clang/Analysis/PathSensitive/ValueState.h"
 #include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/PathSensitive/ValueState.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "llvm/Support/Compiler.h"
 #include <sstream>
 
 using namespace clang;
@@ -26,322 +28,139 @@
 // Bug Descriptions.
 //===----------------------------------------------------------------------===//
 
-namespace bugdesc {
-
-struct NullDeref {
-  static const char* getName() { return "Null dereference"; }
+namespace {
+  
+class VISIBILITY_HIDDEN NullDeref : public BugDescription {
+public:
+  virtual const char* getName() const {
+    return "null dereference";
+  }
+  virtual const char* getDescription() const {
+    return "Dereference of null pointer.";
+  }
+};
+  
+class VISIBILITY_HIDDEN UndefDeref : public BugDescription {
+public:
+  virtual const char* getName() const {
+    return "bad dereference";
+  }
+  virtual const char* getDescription() const {
+    return "Dereference of undefined value.";
+  }
+};
+  
+class VISIBILITY_HIDDEN UndefBranch : public BugDescription {
+public:
+  virtual const char* getName() const {
+    return "uninitialized value";
+  }
+  virtual const char* getDescription() const {
+    return "Branch condition evaluates to an uninitialized value.";
+  }
+};
 
-  static PathDiagnosticPiece* getEndPath(SourceManager& SMgr,
-                                         ExplodedNode<ValueState> *N);
+class VISIBILITY_HIDDEN DivZero : public BugDescription {
+public:
+  virtual const char* getName() const {
+    return "divide-by-zero";
+  }
+  virtual const char* getDescription() const {
+    return "Division by zero/undefined value.";
+  }
 };
   
-PathDiagnosticPiece* NullDeref::getEndPath(SourceManager& SMgr,
-                                           ExplodedNode<ValueState> *N) {
+class VISIBILITY_HIDDEN UndefResult : public BugDescription {
+public:
+  virtual const char* getName() const {
+    return "undefined result";
+  }
+  virtual const char* getDescription() const {
+    return "Result of operation is undefined.";
+  }
+};
   
-  Expr* E = cast<Expr>(cast<PostStmt>(N->getLocation()).getStmt());
+class VISIBILITY_HIDDEN BadCall : public BugDescription {
+public:
+  virtual const char* getName() const {
+    return "invalid function call";
+  }
+  virtual const char* getDescription() const {
+    return "Called function is a NULL or undefined function pointer value.";
+  }
+};
   
-  // FIXME: Do better ranges for different kinds of null dereferences.
+class VISIBILITY_HIDDEN BadArg : public BugDescription {
+public:
+  virtual const char* getName() const {
+    return "bad argument";
+  }
+  virtual const char* getDescription() const {
+    return "Pass-by-value argument in function is undefined.";
+  }
+};
 
-  FullSourceLoc L(E->getLocStart(), SMgr);
-  
-  PathDiagnosticPiece* P = new PathDiagnosticPiece(L, getName());
-  P->addRange(E->getSourceRange());
+class VISIBILITY_HIDDEN BadMsgExprArg : public BugDescription {
+public:
+  virtual const char* getName() const {
+    return "bad argument";
+  }
+  virtual const char* getDescription() const {
+    return "Pass-by-value argument in message expression is undefined.";
+  }
+};
+
+class VISIBILITY_HIDDEN BadReceiver : public BugDescription {
+public:
+  virtual const char* getName() const {
+    return "invalid message expression";
+  }
+  virtual const char* getDescription() const {
+    return "Receiver in message expression is an uninitialized value.";
+  }
+};
   
-  return P;
-}
+class VISIBILITY_HIDDEN RetStack : public BugDescription {
+public:
+  virtual const char* getName() const {
+    return "return of stack address";
+  }
+  virtual const char* getDescription() const {
+    return "Address of stack-allocated variable returned.";
+  }
+};
   
-} // end namespace: bugdesc
+} // end anonymous namespace
   
 //===----------------------------------------------------------------------===//
 // Utility functions.
 //===----------------------------------------------------------------------===//
   
-template <typename ITERATOR>
-static inline ExplodedNode<ValueState>* GetNode(ITERATOR I) {
+template <typename ITERATOR> static inline
+ExplodedNode<ValueState>* GetNode(ITERATOR I) {
   return *I;
 }
 
-template <>
-static inline ExplodedNode<ValueState>*
-GetNode(GRExprEngine::undef_arg_iterator I) {
+template <> static inline
+ExplodedNode<ValueState>* GetNode(GRExprEngine::undef_arg_iterator I) {
   return I->first;
 }
-  
-template <typename ITERATOR>
-static inline ProgramPoint GetLocation(ITERATOR I) {
-  return (*I)->getLocation();
-}
-  
-template <>
-static inline ProgramPoint GetLocation(GRExprEngine::undef_arg_iterator I) {
-  return I->first->getLocation();
-}
-  
-static inline Stmt* GetStmt(const ProgramPoint& P) {
-  if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
-    return PS->getStmt();
-  }
-  else if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
-    return BE->getSrc()->getTerminator();
-  }
-  else if (const BlockEntrance* BE = dyn_cast<BlockEntrance>(&P)) {
-    return BE->getFirstStmt();
-  }
-
-  assert (false && "Unsupported ProgramPoint.");
-  return NULL;
-}
 
 //===----------------------------------------------------------------------===//
-// Pathless Warnings
+// Analysis Driver.
 //===----------------------------------------------------------------------===//
-  
-template <typename ITERATOR>
-static void EmitDiag(Diagnostic& Diag, PathDiagnosticClient* PD,
-                     SourceManager& SrcMgr,
-unsigned ErrorDiag, ITERATOR I) {  
-  
-  Stmt* S = GetStmt(GetLocation(I));
-  SourceRange R = S->getSourceRange();
-  Diag.Report(PD, FullSourceLoc(S->getLocStart(), SrcMgr), ErrorDiag,
-              NULL, 0, &R, 1);    
-}
-
-
-template <>
-static void EmitDiag(Diagnostic& Diag, PathDiagnosticClient* PD, 
-                     SourceManager& SrcMgr, unsigned ErrorDiag,
-                     GRExprEngine::undef_arg_iterator I) {
-
-  Stmt* S1 = GetStmt(GetLocation(I));
-  Expr* E2 = cast<Expr>(I->second);
-  
-  SourceLocation Loc = S1->getLocStart();
-  SourceRange R = E2->getSourceRange();
-  Diag.Report(PD, FullSourceLoc(Loc, SrcMgr), ErrorDiag, 0, 0, &R, 1);
-}
 
 template <typename ITERATOR>
-static void EmitWarning(Diagnostic& Diag,  PathDiagnosticClient* PD,
-                        SourceManager& SrcMgr,
-                        ITERATOR I, ITERATOR E, const char* msg) {
- 
-  std::ostringstream Out;
-  std::string Str(msg);
-
-  if (!PD) {
-    Out << "[CHECKER] " << msg;
-    Str = Out.str();
-    msg = Str.c_str();
-  }
-  
-  bool isFirst = true;
-  unsigned ErrorDiag = 0;
-  llvm::SmallPtrSet<void*,10> CachedErrors;  
-  
-  for (; I != E; ++I) {
-  
-    if (isFirst) {
-      isFirst = false;    
-      ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, msg);
-    }
-    else {
-      
-      // HACK: Cache the location of the error.  Don't emit the same
-      // warning for the same error type that occurs at the same program
-      // location but along a different path.
-      void* p = GetLocation(I).getRawData();
-
-      if (CachedErrors.count(p))
-        continue;
-      
-      CachedErrors.insert(p);
-    }
-    
-    EmitDiag(Diag, PD, SrcMgr, ErrorDiag, I);  
-  }
-}
-  
-//===----------------------------------------------------------------------===//
-// Path warnings.
-//===----------------------------------------------------------------------===//
-
-static void GeneratePathDiagnostic(PathDiagnostic& PD,
-                                   ASTContext& Ctx,
-                                   ExplodedNode<ValueState>* N) {
-  
-  SourceManager& SMgr = Ctx.getSourceManager();
-  
-  while (!N->pred_empty()) {
-  
-    ExplodedNode<ValueState>* LastNode = N;
-    N = *(N->pred_begin());
-    
-    ProgramPoint P = N->getLocation();
-    
-    if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
-      
-      CFGBlock* Src = BE->getSrc();
-      CFGBlock* Dst = BE->getDst();
-      
-      Stmt* T = Src->getTerminator();
-      
-      if (!T)
-        continue;
-
-      FullSourceLoc L(T->getLocStart(), SMgr);
-      
-      switch (T->getStmtClass()) {
-        default:
-          break;
-        
-        case Stmt::GotoStmtClass:
-        case Stmt::IndirectGotoStmtClass: {
-          
-          Stmt* S = GetStmt(LastNode->getLocation());
- 
-          if (!S)
-            continue;
-          
-          std::ostringstream os;
-
-          os << "Control jumps to line "
-             << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";
-          
-          PD.push_front(new PathDiagnosticPiece(L, os.str()));
-          break;
-        }
-          
-        case Stmt::SwitchStmtClass: {
-          
-          // Figure out what case arm we took.
-          
-          Stmt* S = Dst->getLabel();
-
-          if (!S)
-            continue;
-          
-          std::ostringstream os;
-
-          switch (S->getStmtClass()) {
-            default:
-              continue;
-              
-            case Stmt::DefaultStmtClass: {
-                          
-              os << "Control jumps to the 'default' case at line "
-                  << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";
-              
-              break;
-            }
-              
-            case Stmt::CaseStmtClass: {
-              
-              os << "Control jumps to 'case ";
-                            
-              Expr* CondE = cast<SwitchStmt>(T)->getCond();
-              unsigned bits = Ctx.getTypeSize(CondE->getType());
-              
-              llvm::APSInt V1(bits, false);
-              
-              CaseStmt* Case = cast<CaseStmt>(S);
-
-              if (!Case->getLHS()->isIntegerConstantExpr(V1, Ctx, 0, true)) {
-                assert (false &&
-                        "Case condition must evaluate to an integer constant.");
-                continue;
-              }
-              
-              os << V1.toString();
-                
-              // Get the RHS of the case, if it exists.
-                
-              if (Expr* E = Case->getRHS()) {
-              
-                llvm::APSInt V2(bits, false);
-
-                if (!E->isIntegerConstantExpr(V2, Ctx, 0, true)) {
-                  assert (false &&
-                "Case condition (RHS) must evaluate to an integer constant.");
-                  continue;
-                }
-                  
-                os << " .. " << V2.toString();
-              }
-              
-              os << ":'  at line " 
-                 << SMgr.getLogicalLineNumber(S->getLocStart()) << ".\n";
-
-              break;
-              
-            }
-          }
-          
-          PD.push_front(new PathDiagnosticPiece(L, os.str()));
-          break;
-        }
-        
-        
-        case Stmt::DoStmtClass:
-        case Stmt::WhileStmtClass:
-        case Stmt::ForStmtClass:
-        case Stmt::IfStmtClass: {
-        
-          if (*(Src->succ_begin()+1) == Dst)
-            PD.push_front(new PathDiagnosticPiece(L, "Taking false branch."));
-          else 
-            PD.push_front(new PathDiagnosticPiece(L, "Taking true branch."));
-          
-          break;
-        }
-      }
-    }  
-  }
-}
-
-template <typename ITERATOR, typename DESC>
-static void Report(PathDiagnosticClient& PDC, ASTContext& Ctx, DESC,
-                   ITERATOR I, ITERATOR E) {
-  
-
-  if (I == E)
-    return;
-  
-  const char* BugName = DESC::getName();
-
-  llvm::SmallPtrSet<void*,10> CachedErrors;  
+static void EmitWarning(Diagnostic& Diag, PathDiagnosticClient* PD,
+                        ASTContext& Ctx, BugReporter& BR,
+                        const BugDescription& Desc,
+                        ExplodedGraph<GRExprEngine>& G,
+                        ITERATOR I, ITERATOR E) {
   
-  for (; I != E; ++I) {
-    
-    // HACK: Cache the location of the error.  Don't emit the same
-    // warning for the same error type that occurs at the same program
-    // location but along a different path.
-    void* p = GetLocation(I).getRawData();
-    
-    if (CachedErrors.count(p))
-      continue;
-    
-    CachedErrors.insert(p);
-    
-    // Create the PathDiagnostic.
-    
-    PathDiagnostic D(BugName);
-    
-    // Get the end-of-path diagnostic.
-    D.push_back(DESC::getEndPath(Ctx.getSourceManager(), GetNode(I)));
-    
-    // Generate the rest of the diagnostic.
-    GeneratePathDiagnostic(D, Ctx, GetNode(I));
-    
-    PDC.HandlePathDiagnostic(D);
-  }
+  for (; I != E; ++I)
+    BR.EmitPathWarning(Diag, PD, Ctx, Desc, G, GetNode(I));
 }
 
-
-//===----------------------------------------------------------------------===//
-// Analysis Driver.
-//===----------------------------------------------------------------------===//
-  
 namespace clang {
   
 unsigned RunGRSimpleVals(CFG& cfg, Decl& CD, ASTContext& Ctx,
@@ -364,61 +183,39 @@
   // Execute the worklist algorithm.
   Eng.ExecuteWorkList(120000);
   
-  SourceManager& SrcMgr = Ctx.getSourceManager();  
+  BugReporter BR;
+  ExplodedGraph<GRExprEngine>& G = Eng.getGraph();
+  
+  EmitWarning(Diag, PD, Ctx, BR, NullDeref(), G,
+              CS->null_derefs_begin(), CS->null_derefs_end());
+
 
-  if (!PD)
-    EmitWarning(Diag, PD, SrcMgr,
-                CS->null_derefs_begin(), CS->null_derefs_end(),
-                "Dereference of NULL pointer.");
-  else 
-    Report(*PD, Ctx, bugdesc::NullDeref(),
-           CS->null_derefs_begin(), CS->null_derefs_end());
-
-  
-  EmitWarning(Diag, PD, SrcMgr,
-              CS->undef_derefs_begin(),
-              CS->undef_derefs_end(),
-              "Dereference of undefined value.");
-  
-  EmitWarning(Diag, PD, SrcMgr,
-              CS->undef_branches_begin(),
-              CS->undef_branches_end(),
-              "Branch condition evaluates to an uninitialized value.");
-  
-  EmitWarning(Diag, PD, SrcMgr,
-              CS->explicit_bad_divides_begin(),
-              CS->explicit_bad_divides_end(),
-              "Division by zero/undefined value.");
-  
-  EmitWarning(Diag, PD, SrcMgr,
-              CS->undef_results_begin(),
-              CS->undef_results_end(),
-              "Result of operation is undefined.");
-  
-  EmitWarning(Diag, PD, SrcMgr,
-              CS->bad_calls_begin(),
-              CS->bad_calls_end(),
-              "Call using a NULL or undefined function pointer value.");
-  
-  EmitWarning(Diag, PD, SrcMgr,
-              CS->undef_arg_begin(),
-              CS->undef_arg_end(),
-              "Pass-by-value argument in function is undefined.");
-  
-  EmitWarning(Diag, PD, SrcMgr,
-              CS->msg_expr_undef_arg_begin(),
-              CS->msg_expr_undef_arg_end(),
-              "Pass-by-value argument in message expression is undefined.");
-  
-  EmitWarning(Diag, PD, SrcMgr,
-              CS->undef_receivers_begin(),
-              CS->undef_receivers_end(),
-              "Receiver in message expression is an uninitialized value.");
-  
-  EmitWarning(Diag, PD, SrcMgr,
-              CS->ret_stackaddr_begin(),
-              CS->ret_stackaddr_end(),
-              "Address of stack-allocated variable returned.");
+  EmitWarning(Diag, PD, Ctx, BR, UndefDeref(), G,
+              CS->undef_derefs_begin(), CS->undef_derefs_end());
+
+  EmitWarning(Diag, PD, Ctx, BR, UndefBranch(), G,
+              CS->undef_branches_begin(), CS->undef_branches_end());
+  
+  EmitWarning(Diag, PD, Ctx, BR, DivZero(), G,
+              CS->explicit_bad_divides_begin(), CS->explicit_bad_divides_end());
+  
+  EmitWarning(Diag, PD, Ctx, BR, UndefResult(), G,
+              CS->undef_results_begin(), CS->undef_results_end());
+  
+  EmitWarning(Diag, PD, Ctx, BR, BadCall(), G,
+              CS->bad_calls_begin(), CS->bad_calls_end());
+  
+  EmitWarning(Diag, PD, Ctx, BR, BadArg(), G,
+              CS->undef_arg_begin(), CS->undef_arg_end());
+  
+  EmitWarning(Diag, PD, Ctx, BR, BadMsgExprArg(), G,
+              CS->msg_expr_undef_arg_begin(), CS->msg_expr_undef_arg_end());
+  
+  EmitWarning(Diag, PD, Ctx, BR, BadReceiver(), G,
+              CS->undef_receivers_begin(), CS->undef_receivers_end());
+  
+  EmitWarning(Diag, PD, Ctx, BR, RetStack(), G,
+              CS->ret_stackaddr_begin(), CS->ret_stackaddr_end());
 
   FoundationCheck.get()->ReportResults(Diag);
 #ifndef NDEBUG





More information about the cfe-commits mailing list