[CFG] [analyzer] Add stubs for constructor and message argument constructors.

CFG now correctly identifies construction context for temporaries constructed
for the purpose of passing into a function as an argument.

Such context is still not fully implemented because the information it provides
is not rich enough: it doens't contain information about argument index.
It will be addresssed later.

This patch is an extension of r330377 to C++ construct-expressions and
Objective-C message expressions which aren't call-expressions but require
similar handling. C++ new-expressions with placement arguments still remain to
be handled.

Differential Revision: https://reviews.llvm.org/D49826

llvm-svn: 338425
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 0e529bb..9e4fbd6 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -569,6 +569,7 @@
   CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
   CFGBlock *VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S);
   CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
+  CFGBlock *VisitObjCMessageExpr(ObjCMessageExpr *E, AddStmtChoice asc);
   CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E);
   CFGBlock *VisitReturnStmt(ReturnStmt *R);
   CFGBlock *VisitSEHExceptStmt(SEHExceptStmt *S);
@@ -683,6 +684,27 @@
   void findConstructionContexts(const ConstructionContextLayer *Layer,
                                 Stmt *Child);
 
+  // Scan all arguments of a call expression for a construction context.
+  // These sorts of call expressions don't have a common superclass,
+  // hence strict duck-typing.
+  template <typename CallLikeExpr,
+            typename = typename std::enable_if<
+                std::is_same<CallLikeExpr, CallExpr>::value ||
+                std::is_same<CallLikeExpr, CXXConstructExpr>::value ||
+                std::is_same<CallLikeExpr, ObjCMessageExpr>::value>>
+  void findConstructionContextsForArguments(CallLikeExpr *E) {
+    // A stub for the code that'll eventually be used for finding construction
+    // contexts for constructors of C++ object-type arguments passed into
+    // call-like expression E.
+    // FIXME: Once actually implemented, this construction context layer should
+    // include the index of the argument as well.
+    for (auto Arg : E->arguments())
+      if (Arg->getType()->getAsCXXRecordDecl() && !Arg->isGLValue())
+        findConstructionContexts(
+            ConstructionContextLayer::create(cfg->getBumpVectorContext(), E),
+            Arg);
+  }
+
   // Unset the construction context after consuming it. This is done immediately
   // after adding the CFGConstructor or CFGCXXRecordTypedCall element, so
   // there's no need to do this manually in every Visit... function.
@@ -2101,6 +2123,9 @@
     case Stmt::ObjCForCollectionStmtClass:
       return VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S));
 
+    case Stmt::ObjCMessageExprClass:
+      return VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), asc);
+
     case Stmt::OpaqueValueExprClass:
       return Block;
 
@@ -2383,12 +2408,7 @@
     if (!boundType.isNull()) calleeType = boundType;
   }
 
-  // FIXME: Once actually implemented, this construction context layer should
-  // include the number of the argument as well.
-  for (auto Arg: C->arguments()) {
-    findConstructionContexts(
-        ConstructionContextLayer::create(cfg->getBumpVectorContext(), C), Arg);
-  }
+  findConstructionContextsForArguments(C);
 
   // If this is a call to a no-return function, this stops the block here.
   bool NoReturn = getFunctionExtInfo(*calleeType).getNoReturn();
@@ -3580,6 +3600,16 @@
   return VisitStmt(S, AddStmtChoice::AlwaysAdd);
 }
 
+CFGBlock *CFGBuilder::VisitObjCMessageExpr(ObjCMessageExpr *ME,
+                                           AddStmtChoice asc) {
+  findConstructionContextsForArguments(ME);
+
+  autoCreateBlock();
+  appendStmt(Block, ME);
+
+  return VisitChildren(ME);
+}
+
 CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) {
   // If we were in the middle of a block we stop processing that block.
   if (badCFG)
@@ -4244,6 +4274,11 @@
 
 CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C,
                                             AddStmtChoice asc) {
+  // If the constructor takes objects as arguments by value, we need to properly
+  // construct these objects. Construction contexts we find here aren't for the
+  // constructor C, they're for its arguments only.
+  findConstructionContextsForArguments(C);
+
   autoCreateBlock();
   appendConstructor(Block, C);
 
diff --git a/clang/lib/Analysis/ConstructionContext.cpp b/clang/lib/Analysis/ConstructionContext.cpp
index ed1e632..3ffb0a6 100644
--- a/clang/lib/Analysis/ConstructionContext.cpp
+++ b/clang/lib/Analysis/ConstructionContext.cpp
@@ -15,6 +15,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Analysis/ConstructionContext.h"
+#include "clang/AST/ExprObjC.h"
 
 using namespace clang;
 
@@ -111,7 +112,9 @@
         assert(ParentLayer->isLast());
 
         // This is a constructor into a function argument. Not implemented yet.
-        if (isa<CallExpr>(ParentLayer->getTriggerStmt()))
+        if (isa<CallExpr>(ParentLayer->getTriggerStmt()) ||
+            isa<CXXConstructExpr>(ParentLayer->getTriggerStmt()) ||
+            isa<ObjCMessageExpr>(ParentLayer->getTriggerStmt()))
           return nullptr;
         // This is C++17 copy-elided construction into return statement.
         if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) {
@@ -173,7 +176,9 @@
       return create<SimpleReturnedValueConstructionContext>(C, RS);
     }
     // This is a constructor into a function argument. Not implemented yet.
-    if (isa<CallExpr>(TopLayer->getTriggerStmt()))
+    if (isa<CallExpr>(TopLayer->getTriggerStmt()) ||
+        isa<CXXConstructExpr>(TopLayer->getTriggerStmt()) ||
+        isa<ObjCMessageExpr>(TopLayer->getTriggerStmt()))
       return nullptr;
     llvm_unreachable("Unexpected construction context with statement!");
   } else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) {