NoQ updated this revision to Diff 132053.
NoQ added a comment.

Remove the stack of contexts for now. We're not using it anywhere yet, and i'm 
not sure if it'd be necessary.


https://reviews.llvm.org/D42672

Files:
  include/clang/Analysis/AnalysisDeclContext.h
  include/clang/Analysis/CFG.h
  include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  lib/Analysis/AnalysisDeclContext.cpp
  lib/Analysis/CFG.cpp
  lib/Analysis/LiveVariables.cpp
  lib/StaticAnalyzer/Core/AnalysisManager.cpp
  lib/StaticAnalyzer/Core/CoreEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  lib/StaticAnalyzer/Core/PathDiagnostic.cpp
  test/Analysis/cfg.cpp

Index: test/Analysis/cfg.cpp
===================================================================
--- test/Analysis/cfg.cpp
+++ test/Analysis/cfg.cpp
@@ -116,7 +116,7 @@
 // CHECK-NEXT:   Succs (1): B1
 // CHECK: [B1]
 // CHECK-NEXT:   1:  CFGNewAllocator(A *)
-// CHECK-NEXT:   2:  (CXXConstructExpr, class A)
+// CHECK-NEXT:   2:  (CXXConstructExpr, [B1.3], class A)
 // CHECK-NEXT:   3: new A([B1.2])
 // CHECK-NEXT:   4: A *a = new A();
 // CHECK-NEXT:   5: a
@@ -138,7 +138,7 @@
 // CHECK: [B1]
 // CHECK-NEXT:   1: 5
 // CHECK-NEXT:   2: CFGNewAllocator(A *)
-// CHECK-NEXT:   3:  (CXXConstructExpr, class A [5])
+// CHECK-NEXT:   3:  (CXXConstructExpr, [B1.4], class A [5])
 // CHECK-NEXT:   4: new A {{\[\[}}B1.1]]
 // CHECK-NEXT:   5: A *a = new A [5];
 // CHECK-NEXT:   6: a
@@ -331,7 +331,7 @@
 // CHECK-NEXT:  3: [B1.2] (ImplicitCastExpr, ArrayToPointerDecay, int *)
 // CHECK-NEXT:  4: [B1.3] (ImplicitCastExpr, BitCast, void *)
 // CHECK-NEXT:  5: CFGNewAllocator(MyClass *)
-// CHECK-NEXT:  6:  (CXXConstructExpr, class MyClass)
+// CHECK-NEXT:  6:  (CXXConstructExpr, [B1.7], class MyClass)
 // CHECK-NEXT:  7: new ([B1.4]) MyClass([B1.6])
 // CHECK-NEXT:  8: MyClass *obj = new (buffer) MyClass();
 // CHECK-NEXT:  Preds (1): B2
@@ -363,7 +363,7 @@
 // CHECK-NEXT:  4: [B1.3] (ImplicitCastExpr, BitCast, void *)
 // CHECK-NEXT:  5: 5
 // CHECK-NEXT:  6: CFGNewAllocator(MyClass *)
-// CHECK-NEXT:  7:  (CXXConstructExpr, class MyClass [5])
+// CHECK-NEXT:  7:  (CXXConstructExpr, [B1.8], class MyClass [5])
 // CHECK-NEXT:  8: new ([B1.4]) MyClass {{\[\[}}B1.5]]
 // CHECK-NEXT:  9: MyClass *obj = new (buffer) MyClass [5];
 // CHECK-NEXT:  Preds (1): B2
Index: lib/StaticAnalyzer/Core/PathDiagnostic.cpp
===================================================================
--- lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -553,6 +553,9 @@
   case CFGElement::Statement:
     return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
                                   SM, CallerCtx);
+  case CFGElement::Constructor:
+    return PathDiagnosticLocation(
+        Source.castAs<CFGConstructor>().getConstructor(), SM, CallerCtx);
   case CFGElement::Initializer: {
     const CFGInitializer &Init = Source.castAs<CFGInitializer>();
     return PathDiagnosticLocation(Init.getInitializer()->getInit(),
Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -209,7 +209,10 @@
   // See if we're constructing an existing region by looking at the next
   // element in the CFG.
   const CFGBlock *B = CurrBldrCtx.getBlock();
-  assert(isa<CXXConstructExpr>(((*B)[currStmtIdx]).castAs<CFGStmt>().getStmt()));
+  // TODO: Retrieve construction target from CFGConstructor directly.
+  assert(
+      (*B)[currStmtIdx].getAs<CFGConstructor>() ||
+      isa<CXXConstructExpr>(((*B)[currStmtIdx]).castAs<CFGStmt>().getStmt()));
   unsigned int NextStmtIdx = currStmtIdx + 1;
   if (NextStmtIdx >= B->size())
     return None;
@@ -250,10 +253,14 @@
     Previous = (*B)[PreviousStmtIdx];
   }
 
-  if (Optional<CFGStmt> PrevStmtElem = Previous.getAs<CFGStmt>()) {
+  if (auto PrevStmtElem = Previous.getAs<CFGStmt>()) {
     if (auto *CtorExpr = dyn_cast<CXXConstructExpr>(PrevStmtElem->getStmt())) {
       return CtorExpr;
     }
+  } else if (auto PrevCtorElem = Previous.getAs<CFGConstructor>()) {
+    if (auto *CtorExpr = PrevCtorElem->getConstructor()) {
+      return CtorExpr;
+    }
   }
 
   return nullptr;
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -454,10 +454,13 @@
 
   switch (E.getKind()) {
     case CFGElement::Statement:
-      ProcessStmt(const_cast<Stmt*>(E.castAs<CFGStmt>().getStmt()), Pred);
+      ProcessStmt(E.castAs<CFGStmt>(), Pred);
+      return;
+    case CFGElement::Constructor:
+      ProcessConstructor(E.castAs<CFGConstructor>(), Pred);
       return;
     case CFGElement::Initializer:
-      ProcessInitializer(E.castAs<CFGInitializer>().getInitializer(), Pred);
+      ProcessInitializer(E.castAs<CFGInitializer>(), Pred);
       return;
     case CFGElement::NewAllocator:
       ProcessNewAllocator(E.castAs<CFGNewAllocator>().getAllocatorExpr(),
@@ -479,7 +482,7 @@
 }
 
 static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
-                                     const CFGStmt S,
+                                     const Stmt *S,
                                      const ExplodedNode *Pred,
                                      const LocationContext *LC) {
 
@@ -492,17 +495,17 @@
     return true;
 
   // Is this on a non-expression?
-  if (!isa<Expr>(S.getStmt()))
+  if (!isa<Expr>(S))
     return true;
 
   // Run before processing a call.
-  if (CallEvent::isCallStmt(S.getStmt()))
+  if (CallEvent::isCallStmt(S))
     return true;
 
   // Is this an expression that is consumed by another expression?  If so,
   // postpone cleaning out the state.
   ParentMap &PM = LC->getAnalysisDeclContext()->getParentMap();
-  return !PM.isConsumedExpr(cast<Expr>(S.getStmt()));
+  return !PM.isConsumedExpr(cast<Expr>(S));
 }
 
 void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
@@ -606,18 +609,48 @@
 
   // Remove dead bindings and symbols.
   ExplodedNodeSet CleanedStates;
-  if (shouldRemoveDeadBindings(AMgr, S, Pred, Pred->getLocationContext())){
-    removeDead(Pred, CleanedStates, currStmt, Pred->getLocationContext());
+  if (shouldRemoveDeadBindings(AMgr, currStmt, Pred,
+                               Pred->getLocationContext())) {
+    removeDead(Pred, CleanedStates, currStmt,
+                                    Pred->getLocationContext());
   } else
     CleanedStates.Add(Pred);
 
   // Visit the statement.
   ExplodedNodeSet Dst;
-  for (ExplodedNodeSet::iterator I = CleanedStates.begin(),
-                                 E = CleanedStates.end(); I != E; ++I) {
+  for (auto I: CleanedStates) {
     ExplodedNodeSet DstI;
     // Visit the statement.
-    Visit(currStmt, *I, DstI);
+    Visit(currStmt, I, DstI);
+    Dst.insert(DstI);
+  }
+
+  // Enqueue the new nodes onto the work list.
+  Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
+}
+
+void ExprEngine::ProcessConstructor(const CFGConstructor C,
+                                    ExplodedNode *Pred) {
+  // Reclaim any unnecessary nodes in the ExplodedGraph.
+  G.reclaimRecentlyAllocatedNodes();
+
+  const CXXConstructExpr *CE = C.getConstructor();
+  PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+                                CE->getLocStart(),
+                                "Error evaluating statement");
+
+  // Remove dead bindings and symbols.
+  ExplodedNodeSet CleanedStates;
+  if (shouldRemoveDeadBindings(AMgr, CE, Pred, Pred->getLocationContext())){
+    removeDead(Pred, CleanedStates, CE, Pred->getLocationContext());
+  } else
+    CleanedStates.Add(Pred);
+
+  // Visit the statement.
+  ExplodedNodeSet Dst;
+  for (auto I : CleanedStates) {
+    ExplodedNodeSet DstI;
+    VisitCXXConstructExpr(CE, I, DstI);
     Dst.insert(DstI);
   }
 
Index: lib/StaticAnalyzer/Core/CoreEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -585,8 +585,14 @@
   }
 
   // At this point, we know we're processing a normal statement.
-  CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>();
-  PostStmt Loc(CS.getStmt(), N->getLocationContext());
+  const Stmt *S = nullptr;
+  if (Optional<CFGStmt> CS = (*Block)[Idx].getAs<CFGStmt>())
+    S = CS->getStmt();
+  else
+    S = (*Block)[Idx].castAs<CFGConstructor>().getConstructor();
+
+  assert(S);
+  PostStmt Loc(S, N->getLocationContext());
 
   if (Loc == N->getLocation().withTag(nullptr)) {
     // Note: 'N' should be a fresh node because otherwise it shouldn't be
Index: lib/StaticAnalyzer/Core/AnalysisManager.cpp
===================================================================
--- lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -29,6 +29,7 @@
                 Options.shouldSynthesizeBodies(),
                 Options.shouldConditionalizeStaticInitializers(),
                 /*addCXXNewAllocator=*/true,
+                /*addRichCXXConstructors=*/true,
                 injector),
       Ctx(ASTCtx), Diags(diags), LangOpts(lang), PathConsumers(PDC),
       CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
Index: lib/Analysis/LiveVariables.cpp
===================================================================
--- lib/Analysis/LiveVariables.cpp
+++ lib/Analysis/LiveVariables.cpp
@@ -452,10 +452,15 @@
       continue;
     }
 
-    if (!elem.getAs<CFGStmt>())
+    const Stmt *S = nullptr;
+    if (auto CS = elem.getAs<CFGStmt>())
+      S = CS->getStmt();
+    else if (auto CC = elem.getAs<CFGConstructor>())
+      S = CC->getConstructor();
+    else
       continue;
-    
-    const Stmt *S = elem.castAs<CFGStmt>().getStmt();
+    assert(S);
+
     TF.Visit(const_cast<Stmt*>(S));
     stmtsToLiveness[S] = val;
   }
Index: lib/Analysis/CFG.cpp
===================================================================
--- lib/Analysis/CFG.cpp
+++ lib/Analysis/CFG.cpp
@@ -472,6 +472,8 @@
   using LabelSetTy = llvm::SmallSetVector<LabelDecl *, 8>;
   LabelSetTy AddressTakenLabels;
 
+  ConstructionContext CurrentConstructionContext = {nullptr, nullptr};
+
   bool badCFG = false;
   const CFG::BuildOptions &BuildOpts;
   
@@ -682,6 +684,17 @@
     B->appendStmt(const_cast<Stmt*>(S), cfg->getBumpVectorContext());
   }
 
+  void appendConstructor(CFGBlock *B, CXXConstructExpr *CE) {
+    if (CurrentConstructionContext.Constructor == CE) {
+      B->appendConstructor(CurrentConstructionContext,
+                           cfg->getBumpVectorContext());
+      return;
+    }
+
+    // No valid construction context found. Fall back to statement.
+    B->appendStmt(CE, cfg->getBumpVectorContext());
+  }
+
   void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) {
     B->appendInitializer(I, cfg->getBumpVectorContext());
   }
@@ -3872,7 +3885,7 @@
 CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C,
                                             AddStmtChoice asc) {
   autoCreateBlock();
-  appendStmt(Block, C);
+  appendConstructor(Block, C);
 
   return VisitChildren(C);
 }
@@ -3882,15 +3895,22 @@
   autoCreateBlock();
   appendStmt(Block, NE);
 
+  if (auto *CE = const_cast<CXXConstructExpr *>(NE->getConstructExpr()))
+    CurrentConstructionContext = {/*Constructor=*/CE, /*Trigger=*/NE};
+
   if (NE->getInitializer())
     Block = Visit(NE->getInitializer());
+
   if (BuildOpts.AddCXXNewAllocator)
     appendNewAllocator(Block, NE);
+
   if (NE->isArray())
     Block = Visit(NE->getArraySize());
+
   for (CXXNewExpr::arg_iterator I = NE->placement_arg_begin(),
        E = NE->placement_arg_end(); I != E; ++I)
     Block = Visit(*I);
+
   return Block;
 }
 
@@ -4210,11 +4230,12 @@
 const CXXDestructorDecl *
 CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
   switch (getKind()) {
-    case CFGElement::Statement:
     case CFGElement::Initializer:
     case CFGElement::NewAllocator:
     case CFGElement::LoopExit:
     case CFGElement::LifetimeEnds:
+    case CFGElement::Statement:
+    case CFGElement::Constructor:
       llvm_unreachable("getDestructorDecl should only be used with "
                        "ImplicitDtors");
     case CFGElement::AutomaticObjectDtor: {
@@ -4335,52 +4356,54 @@
     for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
       unsigned j = 1;
       for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
-           BI != BEnd; ++BI, ++j ) {        
-        if (Optional<CFGStmt> SE = BI->getAs<CFGStmt>()) {
-          const Stmt *stmt= SE->getStmt();
-          std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
-          StmtMap[stmt] = P;
-
-          switch (stmt->getStmtClass()) {
-            case Stmt::DeclStmtClass:
-                DeclMap[cast<DeclStmt>(stmt)->getSingleDecl()] = P;
-                break;
-            case Stmt::IfStmtClass: {
-              const VarDecl *var = cast<IfStmt>(stmt)->getConditionVariable();
-              if (var)
-                DeclMap[var] = P;
-              break;
-            }
-            case Stmt::ForStmtClass: {
-              const VarDecl *var = cast<ForStmt>(stmt)->getConditionVariable();
-              if (var)
-                DeclMap[var] = P;
-              break;
-            }
-            case Stmt::WhileStmtClass: {
-              const VarDecl *var =
-                cast<WhileStmt>(stmt)->getConditionVariable();
-              if (var)
-                DeclMap[var] = P;
-              break;
-            }
-            case Stmt::SwitchStmtClass: {
-              const VarDecl *var =
-                cast<SwitchStmt>(stmt)->getConditionVariable();
-              if (var)
-                DeclMap[var] = P;
-              break;
-            }
-            case Stmt::CXXCatchStmtClass: {
-              const VarDecl *var =
-                cast<CXXCatchStmt>(stmt)->getExceptionDecl();
-              if (var)
-                DeclMap[var] = P;
-              break;
-            }
-            default:
-              break;
-          }
+           BI != BEnd; ++BI, ++j ) {
+        const Stmt *stmt = nullptr;
+        if (auto SE = BI->getAs<CFGStmt>())
+          stmt = SE->getStmt();
+        else if (auto CE = BI->getAs<CFGConstructor>())
+          stmt = CE->getConstructor();
+        else
+          continue;
+
+        std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
+        StmtMap[stmt] = P;
+
+        switch (stmt->getStmtClass()) {
+        case Stmt::DeclStmtClass:
+          DeclMap[cast<DeclStmt>(stmt)->getSingleDecl()] = P;
+          break;
+        case Stmt::IfStmtClass: {
+          const VarDecl *var = cast<IfStmt>(stmt)->getConditionVariable();
+          if (var)
+            DeclMap[var] = P;
+          break;
+        }
+        case Stmt::ForStmtClass: {
+          const VarDecl *var = cast<ForStmt>(stmt)->getConditionVariable();
+          if (var)
+            DeclMap[var] = P;
+          break;
+        }
+        case Stmt::WhileStmtClass: {
+          const VarDecl *var = cast<WhileStmt>(stmt)->getConditionVariable();
+          if (var)
+            DeclMap[var] = P;
+          break;
+        }
+        case Stmt::SwitchStmtClass: {
+          const VarDecl *var = cast<SwitchStmt>(stmt)->getConditionVariable();
+          if (var)
+            DeclMap[var] = P;
+          break;
+        }
+        case Stmt::CXXCatchStmtClass: {
+          const VarDecl *var = cast<CXXCatchStmt>(stmt)->getExceptionDecl();
+          if (var)
+            DeclMap[var] = P;
+          break;
+        }
+        default:
+          break;
         }
       }
     }
@@ -4575,14 +4598,11 @@
 
     if (isa<CXXOperatorCallExpr>(S)) {
       OS << " (OperatorCall)";
-    }
-    else if (isa<CXXBindTemporaryExpr>(S)) {
+    } else if (isa<CXXBindTemporaryExpr>(S)) {
       OS << " (BindTemporary)";
-    }
-    else if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(S)) {
-      OS << " (CXXConstructExpr, " << CCE->getType().getAsString() << ")";
-    }
-    else if (const CastExpr *CE = dyn_cast<CastExpr>(S)) {
+    } else if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(S)) {
+      OS << " (CXXConstructExpr, " << CCE->getType().getAsString() << ')';
+    } else if (const CastExpr *CE = dyn_cast<CastExpr>(S)) {
       OS << " (" << CE->getStmtClassName() << ", "
          << CE->getCastKindName()
          << ", " << CE->getType().getAsString()
@@ -4592,6 +4612,12 @@
     // Expressions need a newline.
     if (isa<Expr>(S))
       OS << '\n';
+  } else if (Optional<CFGConstructor> CE = E.getAs<CFGConstructor>()) {
+    CE->getConstructor()->printPretty(OS, &Helper,
+                                      PrintingPolicy(Helper.getLangOpts()));
+    OS << " (CXXConstructExpr, ";
+    Helper.handledStmt((CE->getTriggerStmt()), OS);
+    OS << ", " << CE->getType().getAsString() << ")\n";
   } else if (Optional<CFGInitializer> IE = E.getAs<CFGInitializer>()) {
     const CXXCtorInitializer *I = IE->getInitializer();
     if (I->isBaseInitializer())
Index: lib/Analysis/AnalysisDeclContext.cpp
===================================================================
--- lib/Analysis/AnalysisDeclContext.cpp
+++ lib/Analysis/AnalysisDeclContext.cpp
@@ -67,7 +67,8 @@
     ASTContext &ASTCtx, bool useUnoptimizedCFG, bool addImplicitDtors,
     bool addInitializers, bool addTemporaryDtors, bool addLifetime,
     bool addLoopExit, bool synthesizeBodies, bool addStaticInitBranch,
-    bool addCXXNewAllocator, CodeInjector *injector)
+    bool addCXXNewAllocator, bool addRichCXXConstructors,
+    CodeInjector *injector)
     : Injector(injector), FunctionBodyFarm(ASTCtx, injector),
       SynthesizeBodies(synthesizeBodies) {
   cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
@@ -78,6 +79,7 @@
   cfgBuildOptions.AddLoopExit = addLoopExit;
   cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch;
   cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator;
+  cfgBuildOptions.AddRichCXXConstructors = addRichCXXConstructors;
 }
 
 void AnalysisDeclContextManager::clear() { Contexts.clear(); }
Index: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -196,6 +196,8 @@
 
   void ProcessStmt(const CFGStmt S, ExplodedNode *Pred);
 
+  void ProcessConstructor(const CFGConstructor C, ExplodedNode *Pred);
+
   void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred);
 
   void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred);
Index: include/clang/Analysis/CFG.h
===================================================================
--- include/clang/Analysis/CFG.h
+++ include/clang/Analysis/CFG.h
@@ -15,7 +15,7 @@
 #ifndef LLVM_CLANG_ANALYSIS_CFG_H
 #define LLVM_CLANG_ANALYSIS_CFG_H
 
-#include "clang/AST/Stmt.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/Analysis/Support/BumpVector.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/DenseMap.h"
@@ -56,6 +56,7 @@
   enum Kind {
     // main kind
     Statement,
+    Constructor,
     Initializer,
     NewAllocator,
     LifetimeEnds,
@@ -117,7 +118,7 @@
 
 class CFGStmt : public CFGElement {
 public:
-  CFGStmt(Stmt *S) : CFGElement(Statement, S) {}
+  explicit CFGStmt(Stmt *S) : CFGElement(Statement, S) {}
 
   const Stmt *getStmt() const {
     return static_cast<const Stmt *>(Data1.getPointer());
@@ -133,11 +134,56 @@
   }
 };
 
+// This is bulky data for CFGConstructor which would not fit into the
+// CFGElement's room (pair of pointers). Contains the information
+// necessary to express what memory is being initialized by
+// the construction.
+struct ConstructionContext {
+  CXXConstructExpr *Constructor;
+  Stmt *Trigger;
+
+  const ConstructionContext *getPersistentCopy(BumpVectorContext &C) const {
+    ConstructionContext *CC = C.getAllocator().Allocate<ConstructionContext>();
+    *CC = *this;
+    return CC;
+  }
+};
+
+/// CFGConstructor - Represents C++ constructor call. Maintains information
+/// necessary to figure out what memory is being initialized by the
+/// constructor expression.
+class CFGConstructor : public CFGElement {
+public:
+  explicit CFGConstructor(const ConstructionContext *C)
+      : CFGElement(Constructor, C) {}
+
+  const ConstructionContext *getConstructionContext() const  {
+    return static_cast<ConstructionContext *>(Data1.getPointer());
+  }
+
+  CXXConstructExpr *getConstructor() const {
+    return getConstructionContext()->Constructor;
+  }
+
+  QualType getType() const { return getConstructor()->getType(); }
+
+  Stmt *getTriggerStmt() const { return getConstructionContext()->Trigger; }
+
+private:
+  friend class CFGElement;
+
+  CFGConstructor() = default;
+
+  static bool isKind(const CFGElement &E) {
+    return E.getKind() == Constructor;
+  }
+};
+
 /// CFGInitializer - Represents C++ base or member initializer from
 /// constructor's initialization list.
 class CFGInitializer : public CFGElement {
 public:
-  CFGInitializer(CXXCtorInitializer *initializer)
+  explicit CFGInitializer(CXXCtorInitializer *initializer)
       : CFGElement(Initializer, initializer) {}
 
   CXXCtorInitializer* getInitializer() const {
@@ -747,6 +793,10 @@
     Elements.push_back(CFGStmt(statement), C);
   }
 
+  void appendConstructor(const ConstructionContext &CC, BumpVectorContext &C) {
+    Elements.push_back(CFGConstructor(CC.getPersistentCopy(C)), C);
+  }
+
   void appendInitializer(CXXCtorInitializer *initializer,
                         BumpVectorContext &C) {
     Elements.push_back(CFGInitializer(initializer), C);
@@ -855,6 +905,7 @@
     bool AddStaticInitBranches = false;
     bool AddCXXNewAllocator = false;
     bool AddCXXDefaultInitExprInCtors = false;
+    bool AddRichCXXConstructors = false;
 
     BuildOptions() = default;
 
Index: include/clang/Analysis/AnalysisDeclContext.h
===================================================================
--- include/clang/Analysis/AnalysisDeclContext.h
+++ include/clang/Analysis/AnalysisDeclContext.h
@@ -439,6 +439,7 @@
                              bool synthesizeBodies = false,
                              bool addStaticInitBranches = false,
                              bool addCXXNewAllocator = true,
+                             bool addRichCXXConstructors = true,
                              CodeInjector *injector = nullptr);
 
   AnalysisDeclContext *getContext(const Decl *D);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to