r216550 - Add support for the static analyzer to synthesize function implementations from external model files.

Ted Kremenek kremenek at apple.com
Wed Aug 27 08:14:16 PDT 2014


Author: kremenek
Date: Wed Aug 27 10:14:15 2014
New Revision: 216550

URL: http://llvm.org/viewvc/llvm-project?rev=216550&view=rev
Log:
Add support for the static analyzer to synthesize function implementations from external model files.

Currently the analyzer lazily models some functions using 'BodyFarm',
which constructs a fake function implementation that the analyzer
can simulate that approximates the semantics of the function when
it is called.  BodyFarm does this by constructing the AST for
such definitions on-the-fly.  One strength of BodyFarm
is that all symbols and types referenced by synthesized function
bodies are contextual adapted to the containing translation unit.
The downside is that these ASTs are hardcoded in Clang's own
source code.

A more scalable model is to allow these models to be defined as source
code in separate "model" files and have the analyzer use those
definitions lazily when a function body is needed.  Among other things,
it will allow more customization of the analyzer for specific APIs
and platforms.

This patch provides the initial infrastructure for this feature.
It extends BodyFarm to use an abstract API 'CodeInjector' that can be
used to synthesize function bodies.  That 'CodeInjector' is
implemented using a new 'ModelInjector' in libFrontend, which lazily
parses a model file and injects the ASTs into the current translation
unit.  

Models are currently found by specifying a 'model-path' as an
analyzer option; if no path is specified the CodeInjector is not
used, thus defaulting to the current behavior in the analyzer.

Models currently contain a single function definition, and can
be found by finding the file <function name>.model.  This is an
initial starting point for something more rich, but it bootstraps
this feature for future evolution.

This patch was contributed by Gábor Horváth as part of his
Google Summer of Code project.

Some notes:

- This introduces the notion of a "model file" into
  FrontendAction and the Preprocessor.  This nomenclature
  is specific to the static analyzer, but possibly could be
  generalized.  Essentially these are sources pulled in
  exogenously from the principal translation.

  Preprocessor gets a 'InitializeForModelFile' and
  'FinalizeForModelFile' which could possibly be hoisted out
  of Preprocessor if Preprocessor exposed a new API to
  change the PragmaHandlers and some other internal pieces.  This
  can be revisited.

  FrontendAction gets a 'isModelParsingAction()' predicate function
  used to allow a new FrontendAction to recycle the Preprocessor
  and ASTContext.  This name could probably be made something
  more general (i.e., not tied to 'model files') at the expense
  of losing the intent of why it exists.  This can be revisited.

- This is a moderate sized patch; it has gone through some amount of
  offline code review.  Most of the changes to the non-analyzer
  parts are fairly small, and would make little sense without
  the analyzer changes.

- Most of the analyzer changes are plumbing, with the interesting
  behavior being introduced by ModelInjector.cpp and
  ModelConsumer.cpp.

- The new functionality introduced by this change is off-by-default.
  It requires an analyzer config option to enable.

Added:
    cfe/trunk/include/clang/Analysis/CodeInjector.h
    cfe/trunk/include/clang/StaticAnalyzer/Frontend/ModelConsumer.h
    cfe/trunk/lib/Analysis/CodeInjector.cpp
    cfe/trunk/lib/StaticAnalyzer/Frontend/ModelConsumer.cpp
    cfe/trunk/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
    cfe/trunk/lib/StaticAnalyzer/Frontend/ModelInjector.h
    cfe/trunk/test/Analysis/Inputs/Models/
    cfe/trunk/test/Analysis/Inputs/Models/modeledFunction.model
    cfe/trunk/test/Analysis/Inputs/Models/notzero.model
    cfe/trunk/test/Analysis/model-file.cpp
Modified:
    cfe/trunk/include/clang/Analysis/AnalysisContext.h
    cfe/trunk/include/clang/Basic/SourceManager.h
    cfe/trunk/include/clang/Frontend/FrontendAction.h
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
    cfe/trunk/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
    cfe/trunk/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
    cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp
    cfe/trunk/lib/Analysis/BodyFarm.cpp
    cfe/trunk/lib/Analysis/BodyFarm.h
    cfe/trunk/lib/Analysis/CMakeLists.txt
    cfe/trunk/lib/Frontend/CompilerInstance.cpp
    cfe/trunk/lib/Frontend/FrontendAction.cpp
    cfe/trunk/lib/Lex/Preprocessor.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp
    cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
    cfe/trunk/lib/StaticAnalyzer/Frontend/CMakeLists.txt
    cfe/trunk/lib/StaticAnalyzer/Frontend/FrontendActions.cpp

Modified: cfe/trunk/include/clang/Analysis/AnalysisContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/AnalysisContext.h?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/AnalysisContext.h (original)
+++ cfe/trunk/include/clang/Analysis/AnalysisContext.h Wed Aug 27 10:14:15 2014
@@ -17,8 +17,10 @@
 
 #include "clang/AST/Decl.h"
 #include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CodeInjector.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/OwningPtr.h"
 #include "llvm/Support/Allocator.h"
 #include <memory>
 
@@ -143,6 +145,14 @@ public:
   /// \sa getBody
   bool isBodyAutosynthesized() const;
 
+  /// \brief Checks if the body of the Decl is generated by the BodyFarm from a
+  /// model file.
+  ///
+  /// Note, the lookup is not free. We are going to call getBody behind
+  /// the scenes.
+  /// \sa getBody
+  bool isBodyAutosynthesizedFromModelFile() const;
+
   CFG *getCFG();
 
   CFGStmtMap *getCFGStmtMap();
@@ -398,6 +408,10 @@ class AnalysisDeclContextManager {
   ContextMap Contexts;
   LocationContextManager LocContexts;
   CFG::BuildOptions cfgBuildOptions;
+
+  /// Pointer to an interface that can provide function bodies for
+  /// declarations from external source.
+  llvm::OwningPtr<CodeInjector> Injector;
   
   /// Flag to indicate whether or not bodies should be synthesized
   /// for well-known functions.
@@ -410,7 +424,8 @@ public:
                              bool addTemporaryDtors = false,
                              bool synthesizeBodies = false,
                              bool addStaticInitBranches = false,
-                             bool addCXXNewAllocator = true);
+                             bool addCXXNewAllocator = true,
+                             CodeInjector* injector = nullptr);
 
   ~AnalysisDeclContextManager();
 

Added: cfe/trunk/include/clang/Analysis/CodeInjector.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CodeInjector.h?rev=216550&view=auto
==============================================================================
--- cfe/trunk/include/clang/Analysis/CodeInjector.h (added)
+++ cfe/trunk/include/clang/Analysis/CodeInjector.h Wed Aug 27 10:14:15 2014
@@ -0,0 +1,46 @@
+//===-- CodeInjector.h ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the clang::CodeInjector interface which is responsible for
+/// injecting AST of function definitions that may not be available in the
+/// original source.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CODEINJECTOR_H
+#define LLVM_CLANG_ANALYSIS_CODEINJECTOR_H
+
+namespace clang {
+
+class Stmt;
+class FunctionDecl;
+class ObjCMethodDecl;
+
+/// \brief CodeInjector is an interface which is responsible for injecting AST
+/// of function definitions that may not be available in the original source.
+///
+/// The getBody function will be called each time the static analyzer examines a
+/// function call that has no definition available in the current translation
+/// unit. If the returned statement is not a null pointer, it is assumed to be
+/// the body of a function which will be used for the analysis. The source of
+/// the body can be arbitrary, but it is advised to use memoization to avoid
+/// unnecessary reparsing of the external source that provides the body of the
+/// functions.
+class CodeInjector {
+public:
+  CodeInjector();
+  virtual ~CodeInjector();
+
+  virtual Stmt *getBody(const FunctionDecl *D) = 0;
+  virtual Stmt *getBody(const ObjCMethodDecl *D) = 0;
+};
+}
+
+#endif
\ No newline at end of file

Modified: cfe/trunk/include/clang/Basic/SourceManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/SourceManager.h?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/SourceManager.h (original)
+++ cfe/trunk/include/clang/Basic/SourceManager.h Wed Aug 27 10:14:15 2014
@@ -754,7 +754,6 @@ public:
 
   /// \brief Set the file ID for the main source file.
   void setMainFileID(FileID FID) {
-    assert(MainFileID.isInvalid() && "MainFileID already set!");
     MainFileID = FID;
   }
 

Modified: cfe/trunk/include/clang/Frontend/FrontendAction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendAction.h?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendAction.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendAction.h Wed Aug 27 10:14:15 2014
@@ -157,6 +157,13 @@ public:
   /// @name Supported Modes
   /// @{
 
+  /// \brief Is this action invoked on a model file? 
+  ///
+  /// Model files are incomplete translation units that relies on type
+  /// information from another translation unit. Check ParseModelFileAction for
+  /// details.
+  virtual bool isModelParsingAction() const { return false; }
+
   /// \brief Does this action only use the preprocessor?
   ///
   /// If so no AST context will be created and this action will be invalid
@@ -224,6 +231,7 @@ protected:
   void ExecuteAction() override;
 
 public:
+  ASTFrontendAction() {}
   bool usesPreprocessorOnly() const override { return false; }
 };
 

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Wed Aug 27 10:14:15 2014
@@ -194,6 +194,10 @@ class Preprocessor : public RefCountedBa
   /// with this preprocessor.
   PragmaNamespace *PragmaHandlers;
 
+  /// \brief Pragma handlers of the original source is stored here during the
+  /// parsing of a model file.
+  PragmaNamespace *PragmaHandlersBackup;
+
   /// \brief Tracks all of the comment handlers that the client registered
   /// with this preprocessor.
   std::vector<CommentHandler *> CommentHandlers;
@@ -464,6 +468,17 @@ public:
   /// lifetime of the preprocessor.
   void Initialize(const TargetInfo &Target);
 
+  /// \brief Initialize the preprocessor to parse a model file
+  ///
+  /// To parse model files the preprocessor of the original source is reused to
+  /// preserver the identifier table. However to avoid some duplicate
+  /// information in the preprocessor some cleanup is needed before it is used
+  /// to parse model files. This method does that cleanup.
+  void InitializeForModelFile();
+
+  /// \brief Cleanup after model file parsing
+  void FinalizeForModelFile();
+
   /// \brief Retrieve the preprocessor options used to initialize this
   /// preprocessor.
   PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; }

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=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h Wed Aug 27 10:14:15 2014
@@ -23,6 +23,8 @@
 
 namespace clang {
 
+class CodeInjector;
+
 namespace ento {
   class CheckerManager;
 
@@ -50,7 +52,8 @@ public:
                   StoreManagerCreator storemgr,
                   ConstraintManagerCreator constraintmgr, 
                   CheckerManager *checkerMgr,
-                  AnalyzerOptions &Options);
+                  AnalyzerOptions &Options,
+                  CodeInjector* injector = nullptr);
 
   ~AnalysisManager();
   

Modified: cfe/trunk/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h Wed Aug 27 10:14:15 2014
@@ -25,6 +25,8 @@ namespace clang {
 
 class Preprocessor;
 class DiagnosticsEngine;
+class CodeInjector;
+class CompilerInstance;
 
 namespace ento {
 class CheckerManager;
@@ -38,8 +40,7 @@ public:
 /// analysis passes.  (The set of analyses run is controlled by command-line
 /// options.)
 std::unique_ptr<AnalysisASTConsumer>
-CreateAnalysisConsumer(const Preprocessor &pp, const std::string &output,
-                       AnalyzerOptionsRef opts, ArrayRef<std::string> plugins);
+CreateAnalysisConsumer(CompilerInstance &CI);
 
 } // end GR namespace
 

Modified: cfe/trunk/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Frontend/FrontendActions.h?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Frontend/FrontendActions.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Frontend/FrontendActions.h Wed Aug 27 10:14:15 2014
@@ -11,9 +11,13 @@
 #define LLVM_CLANG_STATICANALYZER_FRONTEND_FRONTENDACTIONS_H
 
 #include "clang/Frontend/FrontendAction.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringMap.h"
 
 namespace clang {
 
+class Stmt;
+
 namespace ento {
 
 //===----------------------------------------------------------------------===//
@@ -26,6 +30,27 @@ protected:
                                                  StringRef InFile) override;
 };
 
+/// \brief Frontend action to parse model files.
+///
+/// This frontend action is responsible for parsing model files. Model files can
+/// not be parsed on their own, they rely on type information that is available
+/// in another translation unit. The parsing of model files is done by a
+/// separate compiler instance that reuses the ASTContext and othen information
+/// from the main translation unit that is being compiled. After a model file is
+/// parsed, the function definitions will be collected into a StringMap.
+class ParseModelFileAction : public ASTFrontendAction {
+public:
+  ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies);
+  bool isModelParsingAction() const override { return true; }
+
+protected:
+  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+                                                 StringRef InFile) override;
+
+private:
+  llvm::StringMap<Stmt *> &Bodies;
+};
+
 void printCheckerHelp(raw_ostream &OS, ArrayRef<std::string> plugins);
 
 } // end GR namespace

Added: cfe/trunk/include/clang/StaticAnalyzer/Frontend/ModelConsumer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Frontend/ModelConsumer.h?rev=216550&view=auto
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Frontend/ModelConsumer.h (added)
+++ cfe/trunk/include/clang/StaticAnalyzer/Frontend/ModelConsumer.h Wed Aug 27 10:14:15 2014
@@ -0,0 +1,44 @@
+//===-- ModelConsumer.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements clang::ento::ModelConsumer which is an
+/// ASTConsumer for model files.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_MODELCONSUMER_H
+#define LLVM_CLANG_GR_MODELCONSUMER_H
+
+#include "clang/AST/ASTConsumer.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace clang {
+
+class Stmt;
+
+namespace ento {
+
+/// \brief ASTConsumer to consume model files' AST.
+///
+/// This consumer collects the bodies of function definitions into a StringMap
+/// from a model file.
+class ModelConsumer : public ASTConsumer {
+public:
+  ModelConsumer(llvm::StringMap<Stmt *> &Bodies);
+
+  bool HandleTopLevelDecl(DeclGroupRef D) override;
+
+private:
+  llvm::StringMap<Stmt *> &Bodies;
+};
+}
+}
+
+#endif

Modified: cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp (original)
+++ cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp Wed Aug 27 10:14:15 2014
@@ -69,8 +69,9 @@ AnalysisDeclContextManager::AnalysisDecl
                                                        bool addTemporaryDtors,
                                                        bool synthesizeBodies,
                                                        bool addStaticInitBranch,
-                                                       bool addCXXNewAllocator)
-  : SynthesizeBodies(synthesizeBodies)
+                                                       bool addCXXNewAllocator,
+                                                       CodeInjector *injector)
+  : Injector(injector), SynthesizeBodies(synthesizeBodies)
 {
   cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
   cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
@@ -84,8 +85,8 @@ void AnalysisDeclContextManager::clear()
   llvm::DeleteContainerSeconds(Contexts);
 }
 
-static BodyFarm &getBodyFarm(ASTContext &C) {
-  static BodyFarm *BF = new BodyFarm(C);
+static BodyFarm &getBodyFarm(ASTContext &C, CodeInjector *injector = nullptr) {
+  static BodyFarm *BF = new BodyFarm(C, injector);
   return *BF;
 }
 
@@ -94,7 +95,7 @@ Stmt *AnalysisDeclContext::getBody(bool
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     Stmt *Body = FD->getBody();
     if (!Body && Manager && Manager->synthesizeBodies()) {
-      Body = getBodyFarm(getASTContext()).getBody(FD);
+      Body = getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(FD);
       if (Body)
         IsAutosynthesized = true;
     }
@@ -103,7 +104,7 @@ Stmt *AnalysisDeclContext::getBody(bool
   else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
     Stmt *Body = MD->getBody();
     if (!Body && Manager && Manager->synthesizeBodies()) {
-      Body = getBodyFarm(getASTContext()).getBody(MD);
+      Body = getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(MD);
       if (Body)
         IsAutosynthesized = true;
     }
@@ -128,6 +129,13 @@ bool AnalysisDeclContext::isBodyAutosynt
   return Tmp;
 }
 
+bool AnalysisDeclContext::isBodyAutosynthesizedFromModelFile() const {
+  bool Tmp;
+  Stmt *Body = getBody(Tmp);
+  return Tmp && Body->getLocStart().isValid();
+}
+
+
 const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
   if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
     return MD->getSelfDecl();

Modified: cfe/trunk/lib/Analysis/BodyFarm.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BodyFarm.cpp?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/BodyFarm.cpp (original)
+++ cfe/trunk/lib/Analysis/BodyFarm.cpp Wed Aug 27 10:14:15 2014
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "BodyFarm.h"
+#include "clang/Analysis/CodeInjector.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
@@ -381,6 +382,7 @@ Stmt *BodyFarm::getBody(const FunctionDe
   }
   
   if (FF) { Val = FF(C, D); }
+  else if (Injector) { Val = Injector->getBody(D); }
   return Val.getValue();
 }
 

Modified: cfe/trunk/lib/Analysis/BodyFarm.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BodyFarm.h?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/BodyFarm.h (original)
+++ cfe/trunk/lib/Analysis/BodyFarm.h Wed Aug 27 10:14:15 2014
@@ -27,10 +27,11 @@ class FunctionDecl;
 class ObjCMethodDecl;
 class ObjCPropertyDecl;
 class Stmt;
+class CodeInjector;
   
 class BodyFarm {
 public:
-  BodyFarm(ASTContext &C) : C(C) {}
+  BodyFarm(ASTContext &C, CodeInjector *injector) : C(C), Injector(injector) {}
   
   /// Factory method for creating bodies for ordinary functions.
   Stmt *getBody(const FunctionDecl *D);
@@ -43,6 +44,7 @@ private:
 
   ASTContext &C;
   BodyMap Bodies;
+  CodeInjector *Injector;
 };
 }
 

Modified: cfe/trunk/lib/Analysis/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CMakeLists.txt (original)
+++ cfe/trunk/lib/Analysis/CMakeLists.txt Wed Aug 27 10:14:15 2014
@@ -11,6 +11,7 @@ add_clang_library(clangAnalysis
   CallGraph.cpp
   CocoaConventions.cpp
   Consumed.cpp
+  CodeInjector.cpp
   Dominators.cpp
   DataflowWorklist.cpp
   FormatString.cpp

Added: cfe/trunk/lib/Analysis/CodeInjector.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CodeInjector.cpp?rev=216550&view=auto
==============================================================================
--- cfe/trunk/lib/Analysis/CodeInjector.cpp (added)
+++ cfe/trunk/lib/Analysis/CodeInjector.cpp Wed Aug 27 10:14:15 2014
@@ -0,0 +1,15 @@
+//===-- CodeInjector.cpp ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/CodeInjector.h"
+
+using namespace clang;
+
+CodeInjector::CodeInjector() {}
+CodeInjector::~CodeInjector() {}
\ No newline at end of file

Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Wed Aug 27 10:14:15 2014
@@ -797,8 +797,9 @@ bool CompilerInstance::ExecuteAction(Fro
     llvm::EnableStatistics();
 
   for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) {
-    // Reset the ID tables if we are reusing the SourceManager.
-    if (hasSourceManager())
+    // Reset the ID tables if we are reusing the SourceManager and parsing
+    // regular files.
+    if (hasSourceManager() && !Act.isModelParsingAction())
       getSourceManager().clearIDTables();
 
     if (Act.BeginSourceFile(*this, getFrontendOpts().Inputs[i])) {

Modified: cfe/trunk/lib/Frontend/FrontendAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendAction.cpp?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendAction.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendAction.cpp Wed Aug 27 10:14:15 2014
@@ -287,8 +287,10 @@ bool FrontendAction::BeginSourceFile(Com
     }
   }
 
-  // Set up the preprocessor.
-  CI.createPreprocessor(getTranslationUnitKind());
+  // Set up the preprocessor if needed. When parsing model files the
+  // preprocessor of the original source is reused.
+  if (!isModelParsingAction())
+    CI.createPreprocessor(getTranslationUnitKind());
 
   // Inform the diagnostic client we are processing a source file.
   CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
@@ -307,14 +309,18 @@ bool FrontendAction::BeginSourceFile(Com
   // Create the AST context and consumer unless this is a preprocessor only
   // action.
   if (!usesPreprocessorOnly()) {
-    CI.createASTContext();
+    // Parsing a model file should reuse the existing ASTContext.
+    if (!isModelParsingAction())
+      CI.createASTContext();
 
     std::unique_ptr<ASTConsumer> Consumer =
         CreateWrappedASTConsumer(CI, InputFile);
     if (!Consumer)
       goto failure;
 
-    CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
+    // FIXME: should not overwrite ASTMutationListener when parsing model files?
+    if (!isModelParsingAction())
+      CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
     
     if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
       // Convert headers to PCH and chain them.

Modified: cfe/trunk/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/lib/Lex/Preprocessor.cpp Wed Aug 27 10:14:15 2014
@@ -187,6 +187,25 @@ void Preprocessor::Initialize(const Targ
   HeaderInfo.setTarget(Target);
 }
 
+void Preprocessor::InitializeForModelFile() {
+  NumEnteredSourceFiles = 0;
+
+  // Reset pragmas
+  PragmaHandlersBackup = PragmaHandlers;
+  PragmaHandlers = new PragmaNamespace(StringRef());
+  RegisterBuiltinPragmas();
+
+  // Reset PredefinesFileID
+  PredefinesFileID = FileID();
+}
+
+void Preprocessor::FinalizeForModelFile() {
+  NumEnteredSourceFiles = 1;
+
+  delete PragmaHandlers;
+  PragmaHandlers = PragmaHandlersBackup;
+}
+
 void Preprocessor::setPTHManager(PTHManager* pm) {
   PTH.reset(pm);
   FileMgr.addStatCache(PTH->createStatCache());

Modified: cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp Wed Aug 27 10:14:15 2014
@@ -20,13 +20,16 @@ AnalysisManager::AnalysisManager(ASTCont
                                  StoreManagerCreator storemgr,
                                  ConstraintManagerCreator constraintmgr, 
                                  CheckerManager *checkerMgr,
-                                 AnalyzerOptions &Options)
+                                 AnalyzerOptions &Options,
+                                 CodeInjector *injector)
   : AnaCtxMgr(Options.UnoptimizedCFG,
               /*AddImplicitDtors=*/true,
               /*AddInitializers=*/true,
               Options.includeTemporaryDtorsInCFG(),
               Options.shouldSynthesizeBodies(),
-              Options.shouldConditionalizeStaticInitializers()),
+              Options.shouldConditionalizeStaticInitializers(),
+              /*addCXXNewAllocator=*/true,
+              injector),
     Ctx(ctx),
     Diags(diags),
     LangOpts(lang),

Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp Wed Aug 27 10:14:15 2014
@@ -3247,15 +3247,15 @@ void BugReporter::emitReport(BugReport*
   // To guarantee memory release.
   std::unique_ptr<BugReport> UniqueR(R);
 
-  // Defensive checking: throw the bug away if it comes from a BodyFarm-
-  // generated body. We do this very early because report processing relies
-  // on the report's location being valid.
-  // FIXME: Valid bugs can occur in BodyFarm-generated bodies, so really we
-  // need to just find a reasonable location like we do later on with the path
-  // pieces.
   if (const ExplodedNode *E = R->getErrorNode()) {
-    const LocationContext *LCtx = E->getLocationContext();
-    if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized())
+    const AnalysisDeclContext *DeclCtx =
+        E->getLocationContext()->getAnalysisDeclContext();
+    // The source of autosynthesized body can be handcrafted AST or a model
+    // file. The locations from handcrafted ASTs have no valid source locations
+    // and have to be discarded. Locations from model files should be preserved
+    // for processing and reporting.
+    if (DeclCtx->isBodyAutosynthesized() &&
+        !DeclCtx->isBodyAutosynthesizedFromModelFile())
       return;
   }
   

Modified: cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp Wed Aug 27 10:14:15 2014
@@ -18,6 +18,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ParentMap.h"
+#include "clang/Analysis/CodeInjector.h"
 #include "clang/Analysis/Analyses/LiveVariables.h"
 #include "clang/Analysis/CFG.h"
 #include "clang/Analysis/CallGraph.h"
@@ -33,6 +34,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
+#include "clang/Frontend/CompilerInstance.h"
 #include "llvm/ADT/DepthFirstIterator.h"
 #include "llvm/ADT/PostOrderIterator.h"
 #include "llvm/ADT/SmallPtrSet.h"
@@ -42,6 +44,7 @@
 #include "llvm/Support/Program.h"
 #include "llvm/Support/Timer.h"
 #include "llvm/Support/raw_ostream.h"
+#include "ModelInjector.h"
 #include <memory>
 #include <queue>
 
@@ -157,6 +160,7 @@ public:
   const std::string OutDir;
   AnalyzerOptionsRef Opts;
   ArrayRef<std::string> Plugins;
+  CodeInjector *Injector;
 
   /// \brief Stores the declarations from the local translation unit.
   /// Note, we pre-compute the local declarations at parse time as an
@@ -184,9 +188,10 @@ public:
   AnalysisConsumer(const Preprocessor& pp,
                    const std::string& outdir,
                    AnalyzerOptionsRef opts,
-                   ArrayRef<std::string> plugins)
-    : RecVisitorMode(0), RecVisitorBR(nullptr),
-      Ctx(nullptr), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) {
+                   ArrayRef<std::string> plugins,
+                   CodeInjector *injector)
+    : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr), PP(pp),
+      OutDir(outdir), Opts(opts), Plugins(plugins), Injector(injector) {
     DigestAnalyzerOptions();
     if (Opts->PrintStats) {
       llvm::EnableStatistics();
@@ -286,6 +291,7 @@ public:
     Ctx = &Context;
     checkerMgr.reset(createCheckerManager(*Opts, PP.getLangOpts(), Plugins,
                                           PP.getDiagnostics()));
+
     Mgr.reset(new AnalysisManager(*Ctx,
                                   PP.getDiagnostics(),
                                   PP.getLangOpts(),
@@ -293,7 +299,8 @@ public:
                                   CreateStoreMgr,
                                   CreateConstraintMgr,
                                   checkerMgr.get(),
-                                  *Opts));
+                                  *Opts,
+                                  Injector));
   }
 
   /// \brief Store the top level decls in the set to be processed later on.
@@ -688,13 +695,17 @@ void AnalysisConsumer::RunPathSensitiveC
 //===----------------------------------------------------------------------===//
 
 std::unique_ptr<AnalysisASTConsumer>
-ento::CreateAnalysisConsumer(const Preprocessor &pp, const std::string &outDir,
-                             AnalyzerOptionsRef opts,
-                             ArrayRef<std::string> plugins) {
+ento::CreateAnalysisConsumer(CompilerInstance &CI) {
   // Disable the effects of '-Werror' when using the AnalysisConsumer.
-  pp.getDiagnostics().setWarningsAsErrors(false);
+  CI.getPreprocessor().getDiagnostics().setWarningsAsErrors(false);
+
+  AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
+  bool hasModelPath = analyzerOpts->Config.count("model-path") > 0;
 
-  return llvm::make_unique<AnalysisConsumer>(pp, outDir, opts, plugins);
+  return llvm::make_unique<AnalysisConsumer>(
+      CI.getPreprocessor(), CI.getFrontendOpts().OutputFile, analyzerOpts,
+      CI.getFrontendOpts().Plugins,
+      hasModelPath ? new ModelInjector(CI) : nullptr);
 }
 
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/StaticAnalyzer/Frontend/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/CMakeLists.txt?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Frontend/CMakeLists.txt (original)
+++ cfe/trunk/lib/StaticAnalyzer/Frontend/CMakeLists.txt Wed Aug 27 10:14:15 2014
@@ -7,7 +7,9 @@ set(LLVM_LINK_COMPONENTS
 add_clang_library(clangStaticAnalyzerFrontend
   AnalysisConsumer.cpp
   CheckerRegistration.cpp
+  ModelConsumer.cpp
   FrontendActions.cpp
+  ModelInjector.cpp
 
   LINK_LIBS
   clangAST

Modified: cfe/trunk/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/FrontendActions.cpp?rev=216550&r1=216549&r2=216550&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Frontend/FrontendActions.cpp Wed Aug 27 10:14:15 2014
@@ -8,16 +8,21 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
-#include "clang/Frontend/CompilerInstance.h"
 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
+#include "clang/StaticAnalyzer/Frontend/ModelConsumer.h"
 using namespace clang;
 using namespace ento;
 
 std::unique_ptr<ASTConsumer>
 AnalysisAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
-  return CreateAnalysisConsumer(CI.getPreprocessor(),
-                                CI.getFrontendOpts().OutputFile,
-                                CI.getAnalyzerOpts(),
-                                CI.getFrontendOpts().Plugins);
+  return CreateAnalysisConsumer(CI);
 }
 
+ParseModelFileAction::ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies)
+    : Bodies(Bodies) {}
+
+std::unique_ptr<ASTConsumer>
+ParseModelFileAction::CreateASTConsumer(CompilerInstance &CI,
+                                        StringRef InFile) {
+  return llvm::make_unique<ModelConsumer>(Bodies);
+}

Added: cfe/trunk/lib/StaticAnalyzer/Frontend/ModelConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/ModelConsumer.cpp?rev=216550&view=auto
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Frontend/ModelConsumer.cpp (added)
+++ cfe/trunk/lib/StaticAnalyzer/Frontend/ModelConsumer.cpp Wed Aug 27 10:14:15 2014
@@ -0,0 +1,42 @@
+//===--- ModelConsumer.cpp - ASTConsumer for consuming model files --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements an ASTConsumer for consuming model files.
+///
+/// This ASTConsumer handles the AST of a parsed model file. All top level
+/// function definitions will be collected from that model file for later
+/// retrieval during the static analysis. The body of these functions will not
+/// be injected into the ASTUnit of the analyzed translation unit. It will be
+/// available through the BodyFarm which is utilized by the AnalysisDeclContext
+/// class.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Frontend/ModelConsumer.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclGroup.h"
+
+using namespace clang;
+using namespace ento;
+
+ModelConsumer::ModelConsumer(llvm::StringMap<Stmt *> &Bodies)
+    : Bodies(Bodies) {}
+
+bool ModelConsumer::HandleTopLevelDecl(DeclGroupRef D) {
+  for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
+
+    // Only interested in definitions.
+    const FunctionDecl *func = llvm::dyn_cast<FunctionDecl>(*I);
+    if (func && func->hasBody()) {
+      Bodies.insert(std::make_pair(func->getName(), func->getBody()));
+    }
+  }
+  return true;
+}
\ No newline at end of file

Added: cfe/trunk/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/ModelInjector.cpp?rev=216550&view=auto
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Frontend/ModelInjector.cpp (added)
+++ cfe/trunk/lib/StaticAnalyzer/Frontend/ModelInjector.cpp Wed Aug 27 10:14:15 2014
@@ -0,0 +1,119 @@
+//===-- ModelInjector.cpp ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ModelInjector.h"
+
+#include <string>
+#include <utility>
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
+#include "clang/Serialization/ASTReader.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/AST/Decl.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace clang;
+using namespace ento;
+
+ModelInjector::ModelInjector(CompilerInstance &CI) : CI(CI) {}
+
+Stmt *ModelInjector::getBody(const FunctionDecl *D) {
+  onBodySynthesis(D);
+  return Bodies[D->getName()];
+}
+
+Stmt *ModelInjector::getBody(const ObjCMethodDecl *D) {
+  onBodySynthesis(D);
+  return Bodies[D->getName()];
+}
+
+void ModelInjector::onBodySynthesis(const NamedDecl *D) {
+
+  // FIXME: what about overloads? Declarations can be used as keys but what
+  // about file name index? Mangled names may not be suitable for that either.
+  if (Bodies.count(D->getName()) != 0)
+    return;
+
+  SourceManager &SM = CI.getSourceManager();
+  FileID mainFileID = SM.getMainFileID();
+
+  AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
+  llvm::StringRef modelPath = analyzerOpts->Config["model-path"];
+
+  llvm::SmallString<128> fileName;
+
+  if (!modelPath.empty())
+    fileName =
+        llvm::StringRef(modelPath.str() + "/" + D->getName().str() + ".model");
+  else
+    fileName = llvm::StringRef(D->getName().str() + ".model");
+
+  if (!llvm::sys::fs::exists(fileName.str())) {
+    Bodies[D->getName()] = nullptr;
+    return;
+  }
+
+  IntrusiveRefCntPtr<CompilerInvocation> Invocation(
+      new CompilerInvocation(CI.getInvocation()));
+
+  FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
+  InputKind IK = IK_CXX; // FIXME
+  FrontendOpts.Inputs.clear();
+  FrontendOpts.Inputs.push_back(FrontendInputFile(fileName, IK));
+  FrontendOpts.DisableFree = true;
+
+  Invocation->getDiagnosticOpts().VerifyDiagnostics = 0;
+
+  // Modules are parsed by a separate CompilerInstance, so this code mimics that
+  // behavior for models
+  CompilerInstance Instance;
+  Instance.setInvocation(&*Invocation);
+  Instance.createDiagnostics(
+      new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
+      /*ShouldOwnClient=*/true);
+
+  Instance.getDiagnostics().setSourceManager(&SM);
+
+  Instance.setVirtualFileSystem(&CI.getVirtualFileSystem());
+
+  // The instance wants to take ownership, however DisableFree frontend option
+  // is set to true to avoid double free issues
+  Instance.setFileManager(&CI.getFileManager());
+  Instance.setSourceManager(&SM);
+  Instance.setPreprocessor(&CI.getPreprocessor());
+  Instance.setASTContext(&CI.getASTContext());
+
+  Instance.getPreprocessor().InitializeForModelFile();
+
+  ParseModelFileAction parseModelFile(Bodies);
+
+  const unsigned ThreadStackSize = 8 << 20;
+  llvm::CrashRecoveryContext CRC;
+
+  CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(parseModelFile); },
+                        ThreadStackSize);
+
+  Instance.getPreprocessor().FinalizeForModelFile();
+
+  Instance.resetAndLeakSourceManager();
+  Instance.resetAndLeakFileManager();
+  Instance.resetAndLeakPreprocessor();
+
+  // The preprocessor enters to the main file id when parsing is started, so
+  // the main file id is changed to the model file during parsing and it needs
+  // to be reseted to the former main file id after parsing of the model file
+  // is done.
+  SM.setMainFileID(mainFileID);
+}

Added: cfe/trunk/lib/StaticAnalyzer/Frontend/ModelInjector.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/ModelInjector.h?rev=216550&view=auto
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Frontend/ModelInjector.h (added)
+++ cfe/trunk/lib/StaticAnalyzer/Frontend/ModelInjector.h Wed Aug 27 10:14:15 2014
@@ -0,0 +1,75 @@
+//===-- ModelInjector.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file defines the clang::ento::ModelInjector class which implements the
+/// clang::CodeInjector interface. This class is responsible for injecting
+/// function definitions that were synthesized from model files.
+///
+/// Model files allow definitions of functions to be lazily constituted for functions
+/// which lack bodies in the original source code.  This allows the analyzer
+/// to more precisely analyze code that calls such functions, analyzing the
+/// artificial definitions (which typically approximate the semantics of the
+/// called function) when called by client code.  These definitions are
+/// reconstituted lazily, on-demand, by the static analyzer engine.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SA_FRONTEND_MODELINJECTOR_H
+#define LLVM_CLANG_SA_FRONTEND_MODELINJECTOR_H
+
+#include <map>
+#include <vector>
+#include <memory>
+
+#include "clang/Analysis/CodeInjector.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace clang {
+
+class CompilerInstance;
+class ASTUnit;
+class ASTReader;
+class NamedDecl;
+class Module;
+
+namespace ento {
+class ModelInjector : public CodeInjector {
+public:
+  ModelInjector(CompilerInstance &CI);
+  Stmt *getBody(const FunctionDecl *D);
+  Stmt *getBody(const ObjCMethodDecl *D);
+
+private:
+  /// \brief Synthesize a body for a declaration
+  ///
+  /// This method first looks up the appropriate model file based on the
+  /// model-path configuration option and the name of the declaration that is
+  /// looked up. If no model were synthesized yet for a function with that name
+  /// it will create a new compiler instance to parse the model file using the
+  /// ASTContext, Preprocessor, SourceManager of the original compiler instance.
+  /// The former resources are shared between the two compiler instance, so the
+  /// newly created instance have to "leak" these objects, since they are owned
+  /// by the original instance.
+  ///
+  /// The model-path should be either an absolute path or relative to the
+  /// working directory of the compiler.
+  void onBodySynthesis(const NamedDecl *D);
+
+  CompilerInstance &CI;
+
+  // FIXME: double memoization is redundant, with memoization both here and in
+  // BodyFarm.
+  llvm::StringMap<Stmt *> Bodies;
+};
+}
+}
+
+#endif
\ No newline at end of file

Added: cfe/trunk/test/Analysis/Inputs/Models/modeledFunction.model
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Inputs/Models/modeledFunction.model?rev=216550&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/Inputs/Models/modeledFunction.model (added)
+++ cfe/trunk/test/Analysis/Inputs/Models/modeledFunction.model Wed Aug 27 10:14:15 2014
@@ -0,0 +1,3 @@
+void modelled(intptr p) {
+ ++*p;
+}
\ No newline at end of file

Added: cfe/trunk/test/Analysis/Inputs/Models/notzero.model
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Inputs/Models/notzero.model?rev=216550&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/Inputs/Models/notzero.model (added)
+++ cfe/trunk/test/Analysis/Inputs/Models/notzero.model Wed Aug 27 10:14:15 2014
@@ -0,0 +1,3 @@
+bool notzero(int i) {
+ return i != 0;
+}
\ No newline at end of file

Added: cfe/trunk/test/Analysis/model-file.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/model-file.cpp?rev=216550&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/model-file.cpp (added)
+++ cfe/trunk/test/Analysis/model-file.cpp Wed Aug 27 10:14:15 2014
@@ -0,0 +1,288 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config faux-bodies=true,model-path=%S/Inputs/Models -analyzer-output=plist-multi-file -verify %s -o %t
+// RUN: FileCheck --input-file=%t %s
+
+typedef int* intptr;
+
+// This function is modeled and the p pointer is dereferenced in the model
+// function and there is no function definition available. The modeled
+// function can use any types that are available in the original translation
+// unit, for example intptr in this case.
+void modeledFunction(intptr p);
+
+// This function is modeled and returns true if the parameter is not zero
+// and there is no function definition available.
+bool notzero(int i);
+
+// This functions is not modeled and there is no function definition.
+// available
+bool notzero_notmodeled(int i);
+
+int main() {
+  // There is a nullpointer dereference inside this function.
+  modeledFunction(0);
+
+  int p = 0;
+  if (notzero(p)) {
+   // It is known that p != 0 because of the information provided by the
+   // model of the notzero function.
+    int j = 5 / p;
+  }
+
+  if (notzero_notmodeled(p)) {
+   // There is no information about the value of p, because
+   // notzero_notmodeled is not modeled and the function definition
+   // is not available.
+    int j = 5 / p; // expected-warning {{Division by zero}}
+  }
+
+  return 0;
+}
+
+// CHECK:  <key>diagnostics</key>
+// CHECK-NEXT:  <array>
+// CHECK-NEXT:  <dict>
+// CHECK-NEXT:   <key>path</key>
+// CHECK-NEXT:   <array>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>control</string>
+// CHECK-NEXT:     <key>edges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:       <dict>
+// CHECK-NEXT:        <key>start</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>22</integer>
+// CHECK-NEXT:           <key>col</key><integer>3</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>22</integer>
+// CHECK-NEXT:           <key>col</key><integer>17</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:        <key>end</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>24</integer>
+// CHECK-NEXT:           <key>col</key><integer>3</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>24</integer>
+// CHECK-NEXT:           <key>col</key><integer>5</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:       </dict>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>event</string>
+// CHECK-NEXT:     <key>location</key>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>line</key><integer>24</integer>
+// CHECK-NEXT:      <key>col</key><integer>3</integer>
+// CHECK-NEXT:      <key>file</key><integer>0</integer>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <key>ranges</key>
+// CHECK-NEXT:     <array>
+// CHECK-NEXT:       <array>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>line</key><integer>24</integer>
+// CHECK-NEXT:         <key>col</key><integer>3</integer>
+// CHECK-NEXT:         <key>file</key><integer>0</integer>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>line</key><integer>24</integer>
+// CHECK-NEXT:         <key>col</key><integer>7</integer>
+// CHECK-NEXT:         <key>file</key><integer>0</integer>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:       </array>
+// CHECK-NEXT:     </array>
+// CHECK-NEXT:     <key>depth</key><integer>0</integer>
+// CHECK-NEXT:     <key>extended_message</key>
+// CHECK-NEXT:     <string>'p' initialized to 0</string>
+// CHECK-NEXT:     <key>message</key>
+// CHECK-NEXT:     <string>'p' initialized to 0</string>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>control</string>
+// CHECK-NEXT:     <key>edges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:       <dict>
+// CHECK-NEXT:        <key>start</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>24</integer>
+// CHECK-NEXT:           <key>col</key><integer>3</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>24</integer>
+// CHECK-NEXT:           <key>col</key><integer>5</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:        <key>end</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>25</integer>
+// CHECK-NEXT:           <key>col</key><integer>3</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>25</integer>
+// CHECK-NEXT:           <key>col</key><integer>4</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:       </dict>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>control</string>
+// CHECK-NEXT:     <key>edges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:       <dict>
+// CHECK-NEXT:        <key>start</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>25</integer>
+// CHECK-NEXT:           <key>col</key><integer>3</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>25</integer>
+// CHECK-NEXT:           <key>col</key><integer>4</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:        <key>end</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>31</integer>
+// CHECK-NEXT:           <key>col</key><integer>3</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>31</integer>
+// CHECK-NEXT:           <key>col</key><integer>4</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:       </dict>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>control</string>
+// CHECK-NEXT:     <key>edges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:       <dict>
+// CHECK-NEXT:        <key>start</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>31</integer>
+// CHECK-NEXT:           <key>col</key><integer>3</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>31</integer>
+// CHECK-NEXT:           <key>col</key><integer>4</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:        <key>end</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>31</integer>
+// CHECK-NEXT:           <key>col</key><integer>7</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>31</integer>
+// CHECK-NEXT:           <key>col</key><integer>24</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:       </dict>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>control</string>
+// CHECK-NEXT:     <key>edges</key>
+// CHECK-NEXT:      <array>
+// CHECK-NEXT:       <dict>
+// CHECK-NEXT:        <key>start</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>31</integer>
+// CHECK-NEXT:           <key>col</key><integer>7</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>31</integer>
+// CHECK-NEXT:           <key>col</key><integer>24</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:        <key>end</key>
+// CHECK-NEXT:         <array>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>35</integer>
+// CHECK-NEXT:           <key>col</key><integer>15</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:          <dict>
+// CHECK-NEXT:           <key>line</key><integer>35</integer>
+// CHECK-NEXT:           <key>col</key><integer>15</integer>
+// CHECK-NEXT:           <key>file</key><integer>0</integer>
+// CHECK-NEXT:          </dict>
+// CHECK-NEXT:         </array>
+// CHECK-NEXT:       </dict>
+// CHECK-NEXT:      </array>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:    <dict>
+// CHECK-NEXT:     <key>kind</key><string>event</string>
+// CHECK-NEXT:     <key>location</key>
+// CHECK-NEXT:     <dict>
+// CHECK-NEXT:      <key>line</key><integer>35</integer>
+// CHECK-NEXT:      <key>col</key><integer>15</integer>
+// CHECK-NEXT:      <key>file</key><integer>0</integer>
+// CHECK-NEXT:     </dict>
+// CHECK-NEXT:     <key>ranges</key>
+// CHECK-NEXT:     <array>
+// CHECK-NEXT:       <array>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>line</key><integer>35</integer>
+// CHECK-NEXT:         <key>col</key><integer>13</integer>
+// CHECK-NEXT:         <key>file</key><integer>0</integer>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:        <dict>
+// CHECK-NEXT:         <key>line</key><integer>35</integer>
+// CHECK-NEXT:         <key>col</key><integer>17</integer>
+// CHECK-NEXT:         <key>file</key><integer>0</integer>
+// CHECK-NEXT:        </dict>
+// CHECK-NEXT:       </array>
+// CHECK-NEXT:     </array>
+// CHECK-NEXT:     <key>depth</key><integer>0</integer>
+// CHECK-NEXT:     <key>extended_message</key>
+// CHECK-NEXT:     <string>Division by zero</string>
+// CHECK-NEXT:     <key>message</key>
+// CHECK-NEXT:     <string>Division by zero</string>
+// CHECK-NEXT:    </dict>
+// CHECK-NEXT:   </array>
+// CHECK-NEXT:   <key>description</key><string>Division by zero</string>
+// CHECK-NEXT:   <key>category</key><string>Logic error</string>
+// CHECK-NEXT:   <key>type</key><string>Division by zero</string>
+// CHECK-NEXT:  <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT:  <key>issue_context</key><string>main</string>
+// CHECK-NEXT:  <key>issue_hash</key><string>15</string>
+// CHECK-NEXT:  <key>location</key>
+// CHECK-NEXT:  <dict>
+// CHECK-NEXT:   <key>line</key><integer>35</integer>
+// CHECK-NEXT:   <key>col</key><integer>15</integer>
+// CHECK-NEXT:   <key>file</key><integer>0</integer>
+// CHECK-NEXT:  </dict>
+// CHECK-NEXT:  </dict>
+// CHECK-NEXT: </array>
\ No newline at end of file





More information about the cfe-commits mailing list