pgousseau updated this revision to Diff 38438.
pgousseau added a comment.

Following Anna's review:

Remove unnecessary AST walk over declarations by reusing already captured 
declarations.
Add handling of merge conflicts using Sema merge methods.
Add condition at the end of ModelInjector::onBodySynthesis to prevent 
unnecessary model file parsing.
Fix 80 col in regression tests.
Add regression tests to exercise merge conflicts.

The const qualifier on model's declarations has to be removed as Sema merge 
methods take non const parameters.


http://reviews.llvm.org/D13731

Files:
  include/clang/Analysis/AnalysisContext.h
  include/clang/Analysis/CodeInjector.h
  include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
  include/clang/StaticAnalyzer/Frontend/FrontendActions.h
  include/clang/StaticAnalyzer/Frontend/ModelConsumer.h
  lib/Analysis/AnalysisDeclContext.cpp
  lib/Analysis/BodyFarm.cpp
  lib/Analysis/BodyFarm.h
  lib/StaticAnalyzer/Core/AnalysisManager.cpp
  lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
  lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
  lib/StaticAnalyzer/Frontend/FrontendActions.cpp
  lib/StaticAnalyzer/Frontend/ModelConsumer.cpp
  lib/StaticAnalyzer/Frontend/ModelInjector.cpp
  lib/StaticAnalyzer/Frontend/ModelInjector.h
  test/Analysis/Inputs/Models/modelFileHasAttributes.model
  test/Analysis/Inputs/Models/modelFileHasConflicts.model
  test/Analysis/analyzer-config.c
  test/Analysis/analyzer-config.cpp
  test/Analysis/model-attributes.cpp

Index: test/Analysis/model-attributes.cpp
===================================================================
--- /dev/null
+++ test/Analysis/model-attributes.cpp
@@ -0,0 +1,49 @@
+// This is testing the 'faux-attributes' analyzer option.
+// The declaration of 'modelFileHasAttributes' found in
+// modelFileHasAttributes.model has 'nonnull' attributes on the 2nd and 3rd
+// parameter, and a '_Nonnull' attribute on the 4th parameter.
+// The declaration of 'modelFileHasConflicts' has a visibility 'protected'
+// attribute and a '_Nullable' parameter attribute.
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-unknown -analyze -analyzer-checker=core,nullability -analyzer-config faux-attributes=true,model-path=%S/Inputs/Models %s -verify
+
+int modelFileHasAttributes(int *p0, int *p1, int *p2, int *p3);
+void modelFileHasConflicts(int *_Nonnull p) __attribute__((visibility("hidden")));
+// expected-warning@-1 {{nullability specifier '_Nonnull' conflicts with existing specifier '_Nullable'}}
+// expected-note@-2 {{previous attribute is here}}
+// expected-note@-3 {{previous declaration is here}}
+
+int f0(int *x, int *y, int *z) {
+  int *p = 0;
+  modelFileHasAttributes(p, x, y, z); // no-warning
+  return 0;
+}
+
+int f1(int *x, int *y, int *z) {
+  int *p = 0;
+  modelFileHasAttributes(x, p, y, z);
+  // expected-warning@-1{{Null pointer passed as an argument to a 'nonnull' parameter}}
+  return 0;
+}
+
+int f2(int *x, int *y, int *z) {
+  int *p = 0;
+  modelFileHasAttributes(x, y, p, z);
+  // expected-warning@-1{{Null pointer passed as an argument to a 'nonnull' parameter}}
+  return 0;
+}
+
+int f2a(int *x, int *y, int *z) {
+  int *p = 0;
+  modelFileHasAttributes(x, y, z, p);
+  // expected-warning@-1{{Null passed to a callee that requires a non-null argument}}
+  return 0;
+}
+
+int f3() {
+  modelFileHasConflicts(0);
+  // expected-warning@-1 {{null passed to a callee that requires a non-null argument}}
+  // expected-error@./Inputs/Models/modelFileHasConflicts.model:2 {{visibility does not match previous declaration}}
+  // expected-warning@./Inputs/Models/modelFileHasConflicts.model:1 {{nullability specifier '_Nullable' conflicts with existing specifier '_Nonnull'}}
+  // expected-note@./Inputs/Models/modelFileHasConflicts.model:1 {{previous declaration is here}}
+  return 0;
+}
Index: test/Analysis/analyzer-config.cpp
===================================================================
--- test/Analysis/analyzer-config.cpp
+++ test/Analysis/analyzer-config.cpp
@@ -24,6 +24,7 @@
 // CHECK-NEXT: c++-template-inlining = true
 // CHECK-NEXT: cfg-conditional-static-initializers = true
 // CHECK-NEXT: cfg-temporary-dtors = false
+// CHECK-NEXT: faux-attributes = false
 // CHECK-NEXT: faux-bodies = true
 // CHECK-NEXT: graph-trim-interval = 1000
 // CHECK-NEXT: inline-lambdas = true
@@ -37,4 +38,4 @@
 // CHECK-NEXT: mode = deep
 // CHECK-NEXT: region-store-small-struct-limit = 2
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 19
+// CHECK-NEXT: num-entries = 20
Index: test/Analysis/analyzer-config.c
===================================================================
--- test/Analysis/analyzer-config.c
+++ test/Analysis/analyzer-config.c
@@ -13,6 +13,7 @@
 // CHECK: [config]
 // CHECK-NEXT: cfg-conditional-static-initializers = true
 // CHECK-NEXT: cfg-temporary-dtors = false
+// CHECK-NEXT: faux-attributes = false
 // CHECK-NEXT: faux-bodies = true
 // CHECK-NEXT: graph-trim-interval = 1000
 // CHECK-NEXT: inline-lambdas = true
@@ -26,5 +27,5 @@
 // CHECK-NEXT: mode = deep
 // CHECK-NEXT: region-store-small-struct-limit = 2
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 14
+// CHECK-NEXT: num-entries = 15
 
Index: test/Analysis/Inputs/Models/modelFileHasConflicts.model
===================================================================
--- /dev/null
+++ test/Analysis/Inputs/Models/modelFileHasConflicts.model
@@ -0,0 +1,2 @@
+void modelFileHasConflicts(int *_Nullable p)
+    __attribute__((visibility("protected")));
\ No newline at end of file
Index: test/Analysis/Inputs/Models/modelFileHasAttributes.model
===================================================================
--- /dev/null
+++ test/Analysis/Inputs/Models/modelFileHasAttributes.model
@@ -0,0 +1,2 @@
+int modelFileHasAttributes(int *p0, int *p1, int *p2 __attribute__((nonnull)),
+                           int *_Nonnull p3) __attribute__((nonnull(2)));
\ No newline at end of file
Index: lib/StaticAnalyzer/Frontend/ModelInjector.h
===================================================================
--- lib/StaticAnalyzer/Frontend/ModelInjector.h
+++ lib/StaticAnalyzer/Frontend/ModelInjector.h
@@ -45,6 +45,7 @@
   ModelInjector(CompilerInstance &CI);
   Stmt *getBody(const FunctionDecl *D) override;
   Stmt *getBody(const ObjCMethodDecl *D) override;
+  FunctionDecl *getModelDecl(const FunctionDecl *D) override;
 
 private:
   /// \brief Synthesize a body for a declaration
@@ -67,6 +68,9 @@
   // FIXME: double memoization is redundant, with memoization both here and in
   // BodyFarm.
   llvm::StringMap<Stmt *> Bodies;
+
+  // Store the model's function declaration if provided.
+  llvm::StringMap<FunctionDecl *> Decls;
 };
 }
 }
Index: lib/StaticAnalyzer/Frontend/ModelInjector.cpp
===================================================================
--- lib/StaticAnalyzer/Frontend/ModelInjector.cpp
+++ lib/StaticAnalyzer/Frontend/ModelInjector.cpp
@@ -37,11 +37,16 @@
   return Bodies[D->getName()];
 }
 
+FunctionDecl *ModelInjector::getModelDecl(const FunctionDecl *D) {
+  onBodySynthesis(D);
+  return Decls[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)
+  if (Bodies.count(D->getName()) != 0 || Decls.count(D->getName()) != 0)
     return;
 
   SourceManager &SM = CI.getSourceManager();
@@ -60,6 +65,7 @@
 
   if (!llvm::sys::fs::exists(fileName.str())) {
     Bodies[D->getName()] = nullptr;
+    Decls[D->getName()] = nullptr;
     return;
   }
 
@@ -95,14 +101,20 @@
 
   Instance.getPreprocessor().InitializeForModelFile();
 
-  ParseModelFileAction parseModelFile(Bodies);
+  ParseModelFileAction parseModelFile(Bodies, Decls);
 
   const unsigned ThreadStackSize = 8 << 20;
   llvm::CrashRecoveryContext CRC;
 
   CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(parseModelFile); },
                         ThreadStackSize);
 
+  // Prevent the model file from being parsed again.
+  if (Bodies.count(D->getName()) == 0)
+    Bodies[D->getName()] = nullptr;
+  if (Decls.count(D->getName()) == 0)
+    Decls[D->getName()] = nullptr;
+
   Instance.getPreprocessor().FinalizeForModelFile();
 
   Instance.resetAndLeakSourceManager();
Index: lib/StaticAnalyzer/Frontend/ModelConsumer.cpp
===================================================================
--- lib/StaticAnalyzer/Frontend/ModelConsumer.cpp
+++ lib/StaticAnalyzer/Frontend/ModelConsumer.cpp
@@ -26,16 +26,22 @@
 using namespace clang;
 using namespace ento;
 
-ModelConsumer::ModelConsumer(llvm::StringMap<Stmt *> &Bodies)
-    : Bodies(Bodies) {}
+ModelConsumer::ModelConsumer(llvm::StringMap<Stmt *> &Bodies,
+                             llvm::StringMap<FunctionDecl *> &Decls)
+    : Bodies(Bodies), Decls(Decls) {}
 
 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()));
+    // We are interested in definitions and declarations.
+    // We cant have constness due to Sema's merging methods taking non-const
+    // params.
+    FunctionDecl *func = llvm::dyn_cast<FunctionDecl>(*I);
+    if (func) {
+      Decls.insert(std::make_pair(func->getName(), func));
+      if (func->hasBody()) {
+        Bodies.insert(std::make_pair(func->getName(), func->getBody()));
+      }
     }
   }
   return true;
Index: lib/StaticAnalyzer/Frontend/FrontendActions.cpp
===================================================================
--- lib/StaticAnalyzer/Frontend/FrontendActions.cpp
+++ lib/StaticAnalyzer/Frontend/FrontendActions.cpp
@@ -18,11 +18,13 @@
   return CreateAnalysisConsumer(CI);
 }
 
-ParseModelFileAction::ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies)
-    : Bodies(Bodies) {}
+ParseModelFileAction::ParseModelFileAction(
+    llvm::StringMap<Stmt *> &Bodies,
+    llvm::StringMap<FunctionDecl *> &Decls)
+    : Bodies(Bodies), Decls(Decls) {}
 
 std::unique_ptr<ASTConsumer>
 ParseModelFileAction::CreateASTConsumer(CompilerInstance &CI,
                                         StringRef InFile) {
-  return llvm::make_unique<ModelConsumer>(Bodies);
+  return llvm::make_unique<ModelConsumer>(Bodies, Decls);
 }
Index: lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
===================================================================
--- lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -27,6 +27,7 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Sema.h"
 #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
@@ -161,6 +162,7 @@
   AnalyzerOptionsRef Opts;
   ArrayRef<std::string> Plugins;
   CodeInjector *Injector;
+  CompilerInstance &CI;
 
   /// \brief Stores the declarations from the local translation unit.
   /// Note, we pre-compute the local declarations at parse time as an
@@ -189,9 +191,10 @@
                    const std::string& outdir,
                    AnalyzerOptionsRef opts,
                    ArrayRef<std::string> plugins,
-                   CodeInjector *injector)
+                   CodeInjector *injector,
+                   CompilerInstance &CI)
     : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr), PP(pp),
-      OutDir(outdir), Opts(opts), Plugins(plugins), Injector(injector) {
+      OutDir(outdir), Opts(opts), Plugins(plugins), Injector(injector), CI(CI) {
     DigestAnalyzerOptions();
     if (Opts->PrintStats) {
       llvm::EnableStatistics();
@@ -383,6 +386,10 @@
   /// \brief Check if we should skip (not analyze) the given function.
   AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode);
 
+  /// \brief Merge attributes from model files' declarations.
+  /// Iterates over all local TU declarations.
+  void MergeModelAttributes(AnalysisDeclContextManager &ADCMgr);
+
 };
 } // end anonymous namespace
 
@@ -500,6 +507,42 @@
   }
 }
 
+void AnalysisConsumer::MergeModelAttributes(
+    AnalysisDeclContextManager &ADCMgr) {
+  // For all local TU function declarations, check if there is a corresponding
+  // model's declaration. If yes, merge its attributes, using Sema to handle
+  // conflicts.
+  assert(CI.hasSema() && "Compiler instance should have Sema at this point.");
+  Sema &S = CI.getSema();
+  const unsigned LocalTUDeclsSize = LocalTUDecls.size();
+  for (unsigned i = 0; i < LocalTUDeclsSize; ++i) {
+    Decl *D = LocalTUDecls[i];
+    FunctionDecl *NewFD = dyn_cast<FunctionDecl>(D);
+    if (!NewFD)
+      continue;
+    AnalysisDeclContext *ADC = ADCMgr.getContext(NewFD);
+    FunctionDecl *OldFD = ADC->getModelDecl();
+    if (!OldFD) // No matching model declarations found.
+      continue;
+    NamedDecl *OldND = cast<NamedDecl>(OldFD);
+    // Merge the declarations.
+    S.MergeFunctionDecl(NewFD, OldND,
+                        S.getScopeForContext(NewFD->getDeclContext()),
+                        true /*MergeTypeWithOld*/);
+    // Sema wont merge parameters' attributes if the old declaration does not
+    // already have attributes. So we do it manually here.
+    unsigned NewNumParams = NewFD->getNumParams();
+    unsigned OldNewNumParams = OldFD->getNumParams();
+    if (NewNumParams != OldNewNumParams)
+      return;
+    for (unsigned i = 0; i < NewNumParams; i++) {
+      ParmVarDecl *NewP = NewFD->getParamDecl(i);
+      ParmVarDecl *OldP = OldFD->getParamDecl(i);
+      S.mergeDeclAttributes(NewP, OldP);
+    }
+  }
+}
+
 void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
   // Don't run the actions if an error has occurred with parsing the file.
   DiagnosticsEngine &Diags = PP.getDiagnostics();
@@ -514,9 +557,16 @@
   {
     if (TUTotalTimer) TUTotalTimer->startTimer();
 
+    // If "faux-attributes=true" is given, merge model's attributes.
+    AnalysisDeclContextManager &ADCMgr = Mgr->getAnalysisDeclContextManager();
+    if (ADCMgr.mergeModelAttributes()) {
+      MergeModelAttributes(ADCMgr);
+    }
+
     // Introduce a scope to destroy BR before Mgr.
     BugReporter BR(*Mgr);
     TranslationUnitDecl *TU = C.getTranslationUnitDecl();
+
     checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
 
     // Run the AST-only checks using the order in which functions are defined.
@@ -706,7 +756,7 @@
   return llvm::make_unique<AnalysisConsumer>(
       CI.getPreprocessor(), CI.getFrontendOpts().OutputFile, analyzerOpts,
       CI.getFrontendOpts().Plugins,
-      hasModelPath ? new ModelInjector(CI) : nullptr);
+      hasModelPath ? new ModelInjector(CI) : nullptr, CI);
 }
 
 //===----------------------------------------------------------------------===//
Index: lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
===================================================================
--- lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -325,6 +325,10 @@
   return getBooleanOption("faux-bodies", true);
 }
 
+bool AnalyzerOptions::shouldMergeModelAttributes() {
+  return getBooleanOption("faux-attributes", false);
+}
+
 bool AnalyzerOptions::shouldPrunePaths() {
   return getBooleanOption("prune-paths", true);
 }
Index: lib/StaticAnalyzer/Core/AnalysisManager.cpp
===================================================================
--- lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -27,6 +27,7 @@
               /*AddInitializers=*/true,
               Options.includeTemporaryDtorsInCFG(),
               Options.shouldSynthesizeBodies(),
+              Options.shouldMergeModelAttributes(),
               Options.shouldConditionalizeStaticInitializers(),
               /*addCXXNewAllocator=*/true,
               injector),
Index: lib/Analysis/BodyFarm.h
===================================================================
--- lib/Analysis/BodyFarm.h
+++ lib/Analysis/BodyFarm.h
@@ -39,11 +39,16 @@
   /// Factory method for creating bodies for Objective-C properties.
   Stmt *getBody(const ObjCMethodDecl *D);
 
+  /// \brief Retrieve the declaration from the model file.
+  FunctionDecl *getModelDecl(const FunctionDecl *FD);
+
 private:
   typedef llvm::DenseMap<const Decl *, Optional<Stmt *> > BodyMap;
+  typedef llvm::DenseMap<const Decl *, Optional<FunctionDecl *>> DeclsMap;
 
   ASTContext &C;
   BodyMap Bodies;
+  DeclsMap Decls;
   CodeInjector *Injector;
 };
 }
Index: lib/Analysis/BodyFarm.cpp
===================================================================
--- lib/Analysis/BodyFarm.cpp
+++ lib/Analysis/BodyFarm.cpp
@@ -386,6 +386,26 @@
   return Val.getValue();
 }
 
+FunctionDecl *BodyFarm::getModelDecl(const FunctionDecl *D) {
+  D = D->getCanonicalDecl();
+
+  Optional<FunctionDecl *> &Val = Decls[D];
+  if (Val.hasValue())
+    return Val.getValue();
+
+  Val = nullptr;
+
+  if (D->getIdentifier() == nullptr)
+    return nullptr;
+
+  StringRef Name = D->getName();
+  if (Name.empty())
+    return nullptr;
+
+  if (Injector) {Val = Injector->getModelDecl(D); }
+  return Val.getValue();
+}
+
 static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
                                       const ObjCPropertyDecl *Prop) {
   // First, find the backing ivar.
Index: lib/Analysis/AnalysisDeclContext.cpp
===================================================================
--- lib/Analysis/AnalysisDeclContext.cpp
+++ lib/Analysis/AnalysisDeclContext.cpp
@@ -68,10 +68,13 @@
                                                        bool addInitializers,
                                                        bool addTemporaryDtors,
                                                        bool synthesizeBodies,
+                                                       bool mergeModelAttrs,
                                                        bool addStaticInitBranch,
                                                        bool addCXXNewAllocator,
                                                        CodeInjector *injector)
-  : Injector(injector), SynthesizeBodies(synthesizeBodies)
+  : Injector(injector),
+    SynthesizeBodies(synthesizeBodies),
+    MergeModelAttrs(mergeModelAttrs)
 {
   cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
   cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
@@ -135,6 +138,15 @@
   return Tmp && Body->getLocStart().isValid();
 }
 
+FunctionDecl *AnalysisDeclContext::getModelDecl() const {
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+    if (Manager) {
+      return getBodyFarm(getASTContext(), Manager->Injector.get())
+          .getModelDecl(FD);
+    }
+  }
+  return nullptr;
+}
 
 const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
   if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
Index: include/clang/StaticAnalyzer/Frontend/ModelConsumer.h
===================================================================
--- include/clang/StaticAnalyzer/Frontend/ModelConsumer.h
+++ include/clang/StaticAnalyzer/Frontend/ModelConsumer.h
@@ -31,12 +31,15 @@
 /// from a model file.
 class ModelConsumer : public ASTConsumer {
 public:
-  ModelConsumer(llvm::StringMap<Stmt *> &Bodies);
+  ModelConsumer(llvm::StringMap<Stmt *> &Bodies,
+                llvm::StringMap<FunctionDecl *> &Decls);
 
   bool HandleTopLevelDecl(DeclGroupRef D) override;
 
 private:
   llvm::StringMap<Stmt *> &Bodies;
+  /// Store the models' declarations.
+  llvm::StringMap<FunctionDecl *> &Decls;
 };
 }
 }
Index: include/clang/StaticAnalyzer/Frontend/FrontendActions.h
===================================================================
--- include/clang/StaticAnalyzer/Frontend/FrontendActions.h
+++ include/clang/StaticAnalyzer/Frontend/FrontendActions.h
@@ -40,15 +40,18 @@
 /// parsed, the function definitions will be collected into a StringMap.
 class ParseModelFileAction : public ASTFrontendAction {
 public:
-  ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies);
+  ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies,
+                       llvm::StringMap<FunctionDecl *> &Decls);
   bool isModelParsingAction() const override { return true; }
 
 protected:
   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
                                                  StringRef InFile) override;
 
 private:
   llvm::StringMap<Stmt *> &Bodies;
+  /// Stores the models' declarations.
+  llvm::StringMap<FunctionDecl *> &Decls;
 };
 
 void printCheckerHelp(raw_ostream &OS, ArrayRef<std::string> plugins);
Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
===================================================================
--- include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -496,6 +496,10 @@
   /// for well-known functions.
   bool shouldSynthesizeBodies();
 
+  /// Return true if attributes of functions' declarations taken from model
+  /// files should be merged with existing ones.
+  bool shouldMergeModelAttributes();
+
   /// Returns how often nodes in the ExplodedGraph should be recycled to save
   /// memory.
   ///
Index: include/clang/Analysis/CodeInjector.h
===================================================================
--- include/clang/Analysis/CodeInjector.h
+++ include/clang/Analysis/CodeInjector.h
@@ -40,6 +40,8 @@
 
   virtual Stmt *getBody(const FunctionDecl *D) = 0;
   virtual Stmt *getBody(const ObjCMethodDecl *D) = 0;
+  /// \brief Returns the model's declaration.
+  virtual FunctionDecl *getModelDecl(const FunctionDecl *D) = 0;
 };
 }
 
Index: include/clang/Analysis/AnalysisContext.h
===================================================================
--- include/clang/Analysis/AnalysisContext.h
+++ include/clang/Analysis/AnalysisContext.h
@@ -152,6 +152,10 @@
   /// \sa getBody
   bool isBodyAutosynthesizedFromModelFile() const;
 
+  /// \brief Retrieve the declaration from the model file.
+  /// \sa getModelDecl
+  FunctionDecl *getModelDecl() const;
+
   CFG *getCFG();
 
   CFGStmtMap *getCFGStmtMap();
@@ -416,12 +420,16 @@
   /// for well-known functions.
   bool SynthesizeBodies;
 
+  /// Flag to indicate whether or not model attributes should be merged.
+  bool MergeModelAttrs;
+
 public:
   AnalysisDeclContextManager(bool useUnoptimizedCFG = false,
                              bool addImplicitDtors = false,
                              bool addInitializers = false,
                              bool addTemporaryDtors = false,
                              bool synthesizeBodies = false,
+                             bool mergeModelAttrs = false,
                              bool addStaticInitBranches = false,
                              bool addCXXNewAllocator = true,
                              CodeInjector* injector = nullptr);
@@ -442,6 +450,10 @@
   /// functions.
   bool synthesizeBodies() const { return SynthesizeBodies; }
 
+  /// Return true if attributes of functions' declarations taken from model
+  /// files should be merged with existing ones.
+  bool mergeModelAttributes() const { return MergeModelAttrs; }
+
   const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx,
                                          LocationContext const *Parent,
                                          const Stmt *S,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to