Major refactoring/cleanup of GRExprEngine, ExplodedGraph, and BugReporter.

Bugs are now reported using a combination of "BugType" (previously
BugDescription) and Bug "BugReport" objects, which are fed to BugReporter (which
generates PathDiagnostics). This provides a far more modular way of registering
bug types and plugging in diagnostics.

GRExprEngine now owns its copy of GRCoreEngine, and is not owned by the
ExplodedGraph.

ExplodedGraph is no longer templated on the "checker", but instead on the state
contained in the nodes.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49453 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/GRSimpleVals.cpp b/lib/Analysis/GRSimpleVals.cpp
index d7ee560..e7b456f 100644
--- a/lib/Analysis/GRSimpleVals.cpp
+++ b/lib/Analysis/GRSimpleVals.cpp
@@ -25,142 +25,9 @@
 using namespace clang;
 
 //===----------------------------------------------------------------------===//
-// Bug Descriptions.
-//===----------------------------------------------------------------------===//
-
-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.";
-  }
-};
-
-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.";
-  }
-};
-  
-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.";
-  }
-};
-  
-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.";
-  }
-};
-  
-class VISIBILITY_HIDDEN BadArg : public BugDescription {
-  SourceRange R;
-public:
-  BadArg(Expr *E) {
-    R = E->getSourceRange();
-  }
-  
-  virtual const char* getName() const {
-    return "bad argument";
-  }
-  virtual const char* getDescription() const {
-    return "Pass-by-value argument in function is undefined.";
-  }
-  
-  virtual void getRanges(const SourceRange*& B, const SourceRange*& E) const {
-    B = &R;
-    E = B+1;
-  }
-};
-
-class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg {
-public:
-  BadMsgExprArg(Expr *E) : BadArg(E) {}
-  
-  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 {
-  SourceRange R;
-public:
-  BadReceiver(ExplodedNode<ValueState>* N) {
-    Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
-    Expr* E = cast<ObjCMessageExpr>(S)->getReceiver();
-    assert (E && "Receiver cannot be NULL");
-    R = E->getSourceRange();
-  }
-  
-  virtual const char* getName() const {
-    return "bad receiver";
-  }
-  virtual const char* getDescription() const {
-    return "Receiver in message expression is an uninitialized value.";
-  }
-  
-  virtual void getRanges(const SourceRange*& B, const SourceRange*& E) const {
-    B = &R;
-    E = B+1;
-  }
-};
-  
-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 anonymous namespace
-  
-//===----------------------------------------------------------------------===//
 // Utility functions.
 //===----------------------------------------------------------------------===//
-  
+
 template <typename ITERATOR> inline
 ExplodedNode<ValueState>* GetNode(ITERATOR I) {
   return *I;
@@ -171,93 +38,302 @@
   return I->first;
 }
 
+template <typename ITER>
+void GenericEmitWarnings(BugReporter& BR, const BugType& D,
+                         ITER I, ITER E) {
+  
+  for (; I != E; ++I) {
+    BugReport R(D);    
+    BR.EmitPathWarning(R, GetNode(I));
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// Bug Descriptions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+  
+class VISIBILITY_HIDDEN NullDeref : public BugType {
+public:
+  virtual const char* getName() const {
+    return "null dereference";
+  }
+  
+  virtual const char* getDescription() const {
+    return "Dereference of null pointer.";
+  }
+  
+  virtual void EmitWarnings(BugReporter& BR) {
+    GRExprEngine& Eng = BR.getEngine();
+    GenericEmitWarnings(BR, *this, Eng.null_derefs_begin(),
+                        Eng.null_derefs_end());
+  }
+};
+
+class VISIBILITY_HIDDEN UndefDeref : public BugType {
+public:
+  virtual const char* getName() const {
+    return "bad dereference";
+  }
+  
+  virtual const char* getDescription() const {
+    return "Dereference of undefined value.";
+  }
+  
+  virtual void EmitWarnings(BugReporter& BR) {
+    GRExprEngine& Eng = BR.getEngine();
+    GenericEmitWarnings(BR, *this, Eng.undef_derefs_begin(),
+                        Eng.undef_derefs_end());
+  }
+};
+  
+class VISIBILITY_HIDDEN UndefBranch : public BugType {
+public:
+  virtual const char* getName() const {
+    return "uninitialized value";
+  }
+  
+  virtual const char* getDescription() const {
+    return "Branch condition evaluates to an uninitialized value.";
+  }
+  
+  virtual void EmitWarnings(BugReporter& BR) {
+    GRExprEngine& Eng = BR.getEngine();
+    GenericEmitWarnings(BR, *this, Eng.undef_branches_begin(),
+                        Eng.undef_branches_end());
+  }
+};
+  
+class VISIBILITY_HIDDEN DivZero : public BugType {
+public:
+  virtual const char* getName() const {
+    return "divide-by-zero";
+  }
+  
+  virtual const char* getDescription() const {
+    return "Division by zero/undefined value.";
+  }
+  
+  virtual void EmitWarnings(BugReporter& BR) {
+    GRExprEngine& Eng = BR.getEngine();
+    GenericEmitWarnings(BR, *this, Eng.explicit_bad_divides_begin(),
+                        Eng.explicit_bad_divides_end());
+  }
+};
+
+class VISIBILITY_HIDDEN UndefResult : public BugType {
+public:
+  virtual const char* getName() const {
+    return "undefined result";
+  }
+  
+  virtual const char* getDescription() const {
+    return "Result of operation is undefined.";
+  }
+  
+  virtual void EmitWarnings(BugReporter& BR) {
+    GRExprEngine& Eng = BR.getEngine();
+    GenericEmitWarnings(BR, *this, Eng.undef_results_begin(),
+                        Eng.undef_results_begin());
+  }
+};
+  
+class VISIBILITY_HIDDEN BadCall : public BugType {
+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.";
+  }
+  
+  virtual void EmitWarnings(BugReporter& BR) {
+    GRExprEngine& Eng = BR.getEngine();
+    GenericEmitWarnings(BR, *this, Eng.bad_calls_begin(),
+                        Eng.bad_calls_begin());
+  }
+};
+  
+  
+class VISIBILITY_HIDDEN BadArg : public BugType {
+protected:
+  
+  class Report : public BugReport {
+    const SourceRange R;
+  public:
+    Report(BugType& D, Expr* E) : BugReport(D), R(E->getSourceRange()) {}
+    virtual ~Report() {}
+
+    virtual void getRanges(const SourceRange*& B, const SourceRange*& E) const {
+      B = &R;
+      E = B+1;
+    }
+  };
+    
+public:
+  
+  virtual ~BadArg() {}
+  
+  virtual const char* getName() const {
+    return "bad argument";
+  }
+  
+  virtual const char* getDescription() const {
+    return "Pass-by-value argument in function is undefined.";
+  }  
+
+  virtual void EmitWarnings(BugReporter& BR) {
+    GRExprEngine& Eng = BR.getEngine();
+
+    for (GRExprEngine::UndefArgsTy::iterator I = Eng.undef_arg_begin(),
+         E = Eng.undef_arg_end(); I!=E; ++I) {
+      
+      // Generate a report for this bug.
+      Report report(*this, I->second);
+
+      // Emit the warning.
+      BR.EmitPathWarning(report, I->first);
+    }
+
+  }
+};
+  
+class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg {
+public:
+  virtual const char* getName() const {
+    return "bad argument";
+  }
+  
+  virtual const char* getDescription() const {
+    return "Pass-by-value argument in message expression is undefined.";
+  }
+  
+  virtual void EmitWarnings(BugReporter& BR) {
+    GRExprEngine& Eng = BR.getEngine();
+    
+    for (GRExprEngine::UndefArgsTy::iterator I=Eng.msg_expr_undef_arg_begin(),
+         E = Eng.msg_expr_undef_arg_begin(); I!=E; ++I) {
+      
+      // Generate a report for this bug.
+      Report report(*this, I->second);
+      
+      // Emit the warning.
+      BR.EmitPathWarning(report, I->first);
+    }
+    
+  }
+};
+
+class VISIBILITY_HIDDEN BadReceiver : public BugType {
+  
+  class Report : public BugReport {
+    SourceRange R;
+  public:
+    Report(BugType& D, ExplodedNode<ValueState> *N) : BugReport(D) {      
+      Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
+      Expr* E = cast<ObjCMessageExpr>(S)->getReceiver();
+      assert (E && "Receiver cannot be NULL");
+      R = E->getSourceRange();
+    }
+    
+    virtual ~Report() {}
+    
+    virtual void getRanges(const SourceRange*& B, const SourceRange*& E) const {
+      B = &R;
+      E = B+1;
+    }
+  };
+
+public:  
+  virtual const char* getName() const {
+    return "bad receiver";
+  }
+  
+  virtual const char* getDescription() const {
+    return "Receiver in message expression is an uninitialized value.";
+  }
+  
+  virtual void EmitWarnings(BugReporter& BR) {
+    GRExprEngine& Eng = BR.getEngine();
+    
+    for (GRExprEngine::UndefReceiversTy::iterator I=Eng.undef_receivers_begin(),
+         E = Eng.undef_receivers_end(); I!=E; ++I) {
+          
+      // Generate a report for this bug.
+      Report report(*this, *I);
+      
+      // Emit the warning.
+      BR.EmitPathWarning(report, *I);
+    }    
+  }
+};
+  
+class VISIBILITY_HIDDEN RetStack : public BugType {
+public:
+  virtual const char* getName() const {
+    return "return of stack address";
+  }
+  
+  virtual const char* getDescription() const {
+    return "Address of stack-allocated variable returned.";
+  }
+  
+  virtual void EmitWarnings(BugReporter& BR) {
+    GRExprEngine& Eng = BR.getEngine();
+    GenericEmitWarnings(BR, *this, Eng.ret_stackaddr_begin(),
+                        Eng.ret_stackaddr_begin());
+  }
+};
+  
+} // end anonymous namespace
+
+void GRSimpleVals::RegisterChecks(GRExprEngine& Eng) {
+  Eng.Register(new NullDeref());
+  Eng.Register(new UndefDeref());
+  Eng.Register(new UndefBranch());
+  Eng.Register(new DivZero());
+  Eng.Register(new UndefResult());
+  Eng.Register(new BadCall());
+  Eng.Register(new RetStack());
+  Eng.Register(new BadArg());
+  Eng.Register(new BadMsgExprArg());
+  Eng.Register(new BadReceiver());
+  
+  // Add extra checkers.
+
+  GRSimpleAPICheck* FoundationCheck =
+    CreateBasicObjCFoundationChecks(Eng.getContext(), &Eng.getStateManager());
+  
+  Eng.AddObjCMessageExprCheck(FoundationCheck);
+}
+
 //===----------------------------------------------------------------------===//
 // Analysis Driver.
 //===----------------------------------------------------------------------===//
 
-template <typename ITERATOR>
-void EmitWarning(Diagnostic& Diag, PathDiagnosticClient* PD,
-                 ASTContext& Ctx, BugReporter& BR,
-                 const BugDescription& Desc,
-                 ExplodedGraph<GRExprEngine>& G,
-                 ITERATOR I, ITERATOR E) {
-  
-  for (; I != E; ++I)
-    BR.EmitPathWarning(Diag, PD, Ctx, Desc, G, GetNode(I));
-}
-
 namespace clang {
   
 unsigned RunGRSimpleVals(CFG& cfg, Decl& CD, ASTContext& Ctx,
                          Diagnostic& Diag, PathDiagnosticClient* PD,
                          bool Visualize, bool TrimGraph) {
-  
-  GRCoreEngine<GRExprEngine> Eng(cfg, CD, Ctx);
-  GRExprEngine* CS = &Eng.getCheckerState();
+
+  // Construct the analysis engine.
+  GRExprEngine Eng(cfg, CD, Ctx);
   
   // Set base transfer functions.
   GRSimpleVals GRSV;
-  CS->setTransferFunctions(GRSV);
-  
-  // Add extra checkers.
-  llvm::OwningPtr<GRSimpleAPICheck> FoundationCheck(
-    CreateBasicObjCFoundationChecks(Ctx, &CS->getStateManager()));
-  
-  CS->AddObjCMessageExprCheck(FoundationCheck.get());
+  Eng.setTransferFunctions(GRSV);
   
   // Execute the worklist algorithm.
-  Eng.ExecuteWorkList(120000);
+  Eng.ExecuteWorkList();
   
-  BugReporter BR;
-  ExplodedGraph<GRExprEngine>& G = Eng.getGraph();
+  // Display warnings.
+  Eng.EmitWarnings(Diag, PD);
   
-  EmitWarning(Diag, PD, Ctx, BR, NullDeref(), G,
-              CS->null_derefs_begin(), CS->null_derefs_end());
-
-
-  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());
-  
-  for (GRExprEngine::UndefArgsTy::iterator I = CS->undef_arg_begin(),
-       E = CS->undef_arg_end(); I!=E; ++I) {
-    
-    BadArg Desc(I->second);
-    BR.EmitPathWarning(Diag, PD, Ctx, Desc, G, I->first);
-  }
-  
-  for (GRExprEngine::UndefArgsTy::iterator I = CS->msg_expr_undef_arg_begin(),
-        E = CS->msg_expr_undef_arg_end(); I!=E; ++I) {
-    
-    BadMsgExprArg Desc(I->second);
-    BR.EmitPathWarning(Diag, PD, Ctx, Desc, G, I->first);
-  }
-  
-  for (GRExprEngine::UndefReceiversTy::iterator I = CS->undef_receivers_begin(),
-                                  E = CS->undef_receivers_end(); I!=E; ++I) {
-       
-    BadReceiver Desc(*I);
-    BR.EmitPathWarning(Diag, PD, Ctx, Desc, G, *I);
-  }
-  
-  EmitWarning(Diag, PD, Ctx, BR, RetStack(), G,
-              CS->ret_stackaddr_begin(), CS->ret_stackaddr_end());
-
-  
-  FoundationCheck.get()->ReportResults(Diag, PD, Ctx, BR, G);
 #ifndef NDEBUG
-  if (Visualize) CS->ViewGraph(TrimGraph);
+  if (Visualize) Eng.ViewGraph(TrimGraph);
 #endif
   
   return Eng.getGraph().size();