[analyzer] Perform post-call checks for all inlined calls.

Previously, we were only checking the origin expressions of inlined calls.
Checkers using the generic postCall and older postObjCMessage callbacks were
ignored. Now that we have CallEventManager, it is much easier to create
a CallEvent generically when exiting an inlined function, which we can then
use for post-call checks.

No test case because we don't (yet) have any checkers that depend on this
behavior (which is why it hadn't been fixed before now).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161005 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 7e1b07a..aef9e71 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -211,15 +211,18 @@
   void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst,
                                      const ExplodedNodeSet &Src,
                                      const ObjCMethodCall &msg,
-                                     ExprEngine &Eng) {
-    runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng);
+                                     ExprEngine &Eng,
+                                     bool wasInlined = false) {
+    runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng,
+                              wasInlined);
   }
 
   /// \brief Run checkers for visiting obj-c messages.
   void runCheckersForObjCMessage(bool isPreVisit,
                                  ExplodedNodeSet &Dst,
                                  const ExplodedNodeSet &Src,
-                                 const ObjCMethodCall &msg, ExprEngine &Eng);
+                                 const ObjCMethodCall &msg, ExprEngine &Eng,
+                                 bool wasInlined = false);
 
   /// \brief Run checkers for pre-visiting obj-c messages.
   void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
@@ -229,14 +232,17 @@
 
   /// \brief Run checkers for post-visiting obj-c messages.
   void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
-                              const CallEvent &Call, ExprEngine &Eng) {
-    runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng);
+                              const CallEvent &Call, ExprEngine &Eng,
+                              bool wasInlined = false) {
+    runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng,
+                            wasInlined);
   }
 
   /// \brief Run checkers for visiting obj-c messages.
   void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst,
                                const ExplodedNodeSet &Src,
-                               const CallEvent &Call, ExprEngine &Eng);
+                               const CallEvent &Call, ExprEngine &Eng,
+                               bool wasInlined = false);
 
   /// \brief Run checkers for load/store of a location.
   void runCheckersForLocation(ExplodedNodeSet &Dst,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 74ac253..bc9320f 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -59,6 +59,13 @@
   CallEventRef<T> cloneWithState(ProgramStateRef State) const {
     return this->getPtr()->template cloneWithState<T>(State);
   }
+
+  // Allow implicit conversions to a superclass type, since CallEventRef
+  // behaves like a pointer-to-const.
+  template <typename SuperT>
+  operator CallEventRef<SuperT> () const {
+    return this->getPtr();
+  }
 };
 
 /// \brief Represents an abstract call to a function or method along a
@@ -807,6 +814,11 @@
 public:
   CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {}
 
+
+  CallEventRef<>
+  getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State);
+
+
   CallEventRef<SimpleCall>
   getSimpleCall(const CallExpr *E, ProgramStateRef State,
                 const LocationContext *LCtx);
@@ -871,4 +883,16 @@
 } // end namespace ento
 } // end namespace clang
 
+namespace llvm {
+  // Support isa<>, cast<>, and dyn_cast<> for CallEventRef.
+  template<class T> struct simplify_type< clang::ento::CallEventRef<T> > {
+    typedef const T *SimpleType;
+
+    static SimpleType
+    getSimplifiedValue(const clang::ento::CallEventRef<T>& Val) {
+      return Val.getPtr();
+    }
+  };
+}
+
 #endif
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index 6a5d0f0..ad5a104 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -641,3 +641,60 @@
   // something we can't reason about.
   return create<FunctionCall>(CE, State, LCtx);
 }
+
+
+CallEventRef<>
+CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
+                            ProgramStateRef State) {
+  const LocationContext *ParentCtx = CalleeCtx->getParent();
+  const LocationContext *CallerCtx = ParentCtx->getCurrentStackFrame();
+  assert(CallerCtx && "This should not be used for top-level stack frames");
+
+  const Stmt *CallSite = CalleeCtx->getCallSite();
+
+  if (CallSite) {
+    if (const CallExpr *CE = dyn_cast<CallExpr>(CallSite))
+      return getSimpleCall(CE, State, CallerCtx);
+
+    switch (CallSite->getStmtClass()) {
+    case Stmt::CXXConstructExprClass: {
+      SValBuilder &SVB = State->getStateManager().getSValBuilder();
+      const CXXMethodDecl *Ctor = cast<CXXMethodDecl>(CalleeCtx->getDecl());
+      Loc ThisPtr = SVB.getCXXThis(Ctor, CalleeCtx);
+      SVal ThisVal = State->getSVal(ThisPtr);
+
+      return getCXXConstructorCall(cast<CXXConstructExpr>(CallSite),
+                                   ThisVal.getAsRegion(), State, CallerCtx);
+    }
+    case Stmt::CXXNewExprClass:
+      return getCXXAllocatorCall(cast<CXXNewExpr>(CallSite), State, CallerCtx);
+    case Stmt::ObjCMessageExprClass:
+      return getObjCMethodCall(cast<ObjCMessageExpr>(CallSite),
+                               State, CallerCtx);
+    default:
+      llvm_unreachable("This is not an inlineable statement.");
+    }
+  }
+
+  // Fall back to the CFG. The only thing we haven't handled yet is
+  // destructors, though this could change in the future.
+  const CFGBlock *B = CalleeCtx->getCallSiteBlock();
+  CFGElement E = (*B)[CalleeCtx->getIndex()];
+  assert(isa<CFGImplicitDtor>(E) && "All other CFG elements should have exprs");
+  assert(!isa<CFGTemporaryDtor>(E) && "We don't handle temporaries yet");
+
+  SValBuilder &SVB = State->getStateManager().getSValBuilder();
+  const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CalleeCtx->getDecl());
+  Loc ThisPtr = SVB.getCXXThis(Dtor, CalleeCtx);
+  SVal ThisVal = State->getSVal(ThisPtr);
+
+  const Stmt *Trigger;
+  if (const CFGAutomaticObjDtor *AutoDtor = dyn_cast<CFGAutomaticObjDtor>(&E))
+    Trigger = AutoDtor->getTriggerStmt();
+  else
+    Trigger = Dtor->getBody();
+
+  return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(),
+                              State, CallerCtx);
+}
+
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index e1d6a26..564404e 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -140,7 +140,7 @@
     const CheckersTy &Checkers;
     const Stmt *S;
     ExprEngine &Eng;
-    bool wasInlined;
+    bool WasInlined;
 
     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
@@ -148,7 +148,7 @@
     CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
                      const Stmt *s, ExprEngine &eng, bool wasInlined = false)
       : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng),
-        wasInlined(wasInlined) {}
+        WasInlined(wasInlined) {}
 
     void runChecker(CheckerManager::CheckStmtFunc checkFn,
                     NodeBuilder &Bldr, ExplodedNode *Pred) {
@@ -157,7 +157,7 @@
                                            ProgramPoint::PostStmtKind;
       const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
                                 Pred->getLocationContext(), checkFn.Checker);
-      CheckerContext C(Bldr, Eng, Pred, L, wasInlined);
+      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
       checkFn(S, C);
     }
   };
@@ -169,16 +169,16 @@
                                         const ExplodedNodeSet &Src,
                                         const Stmt *S,
                                         ExprEngine &Eng,
-                                        bool wasInlined) {
+                                        bool WasInlined) {
   CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit),
-                     S, Eng, wasInlined);
+                     S, Eng, WasInlined);
   expandGraphWithCheckers(C, Dst, Src);
 }
 
 namespace {
   struct CheckObjCMessageContext {
     typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy;
-    bool IsPreVisit;
+    bool IsPreVisit, WasInlined;
     const CheckersTy &Checkers;
     const ObjCMethodCall &Msg;
     ExprEngine &Eng;
@@ -187,13 +187,15 @@
     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
 
     CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers,
-                            const ObjCMethodCall &msg, ExprEngine &eng)
-      : IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { }
+                            const ObjCMethodCall &msg, ExprEngine &eng,
+                            bool wasInlined)
+      : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers),
+        Msg(msg), Eng(eng) { }
 
     void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
                     NodeBuilder &Bldr, ExplodedNode *Pred) {
       const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker);
-      CheckerContext C(Bldr, Eng, Pred, L);
+      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
 
       checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C);
     }
@@ -205,11 +207,12 @@
                                                ExplodedNodeSet &Dst,
                                                const ExplodedNodeSet &Src,
                                                const ObjCMethodCall &msg,
-                                               ExprEngine &Eng) {
+                                               ExprEngine &Eng,
+                                               bool WasInlined) {
   CheckObjCMessageContext C(isPreVisit,
                             isPreVisit ? PreObjCMessageCheckers
                                        : PostObjCMessageCheckers,
-                            msg, Eng);
+                            msg, Eng, WasInlined);
   expandGraphWithCheckers(C, Dst, Src);
 }
 
@@ -218,7 +221,7 @@
   // Is there a way we can merge the two?
   struct CheckCallContext {
     typedef std::vector<CheckerManager::CheckCallFunc> CheckersTy;
-    bool IsPreVisit;
+    bool IsPreVisit, WasInlined;
     const CheckersTy &Checkers;
     const CallEvent &Call;
     ExprEngine &Eng;
@@ -227,13 +230,15 @@
     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
 
     CheckCallContext(bool isPreVisit, const CheckersTy &checkers,
-                     const CallEvent &call, ExprEngine &eng)
-    : IsPreVisit(isPreVisit), Checkers(checkers), Call(call), Eng(eng) { }
+                     const CallEvent &call, ExprEngine &eng,
+                     bool wasInlined)
+    : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers),
+      Call(call), Eng(eng) { }
 
     void runChecker(CheckerManager::CheckCallFunc checkFn,
                     NodeBuilder &Bldr, ExplodedNode *Pred) {
       const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker);
-      CheckerContext C(Bldr, Eng, Pred, L);
+      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
 
       checkFn(*Call.cloneWithState(Pred->getState()), C);
     }
@@ -245,11 +250,12 @@
                                              ExplodedNodeSet &Dst,
                                              const ExplodedNodeSet &Src,
                                              const CallEvent &Call,
-                                             ExprEngine &Eng) {
+                                             ExprEngine &Eng,
+                                             bool WasInlined) {
   CheckCallContext C(isPreVisit,
                      isPreVisit ? PreCallCheckers
                                 : PostCallCheckers,
-                     Call, Eng);
+                     Call, Eng, WasInlined);
   expandGraphWithCheckers(C, Dst, Src);
 }
 
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 5e9f3f3..47d732e 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -132,7 +132,7 @@
     if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) {
       const LocationContext *LCtx = CEBNode->getLocationContext();
       SVal V = state->getSVal(RS, LCtx);
-      state = state->BindExpr(CE, calleeCtx->getParent(), V);
+      state = state->BindExpr(CE, callerCtx, V);
     }
 
     // Bind the constructed object value to CXXConstructExpr.
@@ -142,7 +142,7 @@
       SVal ThisV = state->getSVal(This);
 
       // Always bind the region to the CXXConstructExpr.
-      state = state->BindExpr(CCE, calleeCtx->getParent(), ThisV);
+      state = state->BindExpr(CCE, callerCtx, ThisV);
     }
   }
 
@@ -190,19 +190,29 @@
     // Step 5: Perform the post-condition check of the CallExpr and enqueue the
     // result onto the work list.
     // CEENode -> Dst -> WorkList
-    ExplodedNodeSet Dst;
     NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode);
     SaveAndRestore<const NodeBuilderContext*> NBCSave(currentBuilderContext,
         &Ctx);
     SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex());
 
-    // FIXME: This needs to call PostCall.
-    // FIXME: If/when we inline Objective-C messages, this also needs to call
-    // PostObjCMessage.
-    if (CE)
-      getCheckerManager().runCheckersForPostStmt(Dst, CEENode, CE, *this, true);
-    else
-      Dst.Add(CEENode);
+    CallEventManager &CEMgr = getStateManager().getCallEventManager();
+    CallEventRef<> Call = CEMgr.getCaller(calleeCtx, CEEState);
+
+    ExplodedNodeSet DstPostCall;
+    getCheckerManager().runCheckersForPostCall(DstPostCall, CEENode, *Call,
+                                               *this, true);
+
+    ExplodedNodeSet Dst;
+    if (isa<ObjCMethodCall>(Call)) {
+      getCheckerManager().runCheckersForPostObjCMessage(Dst, DstPostCall,
+                                                    cast<ObjCMethodCall>(*Call),
+                                                        *this, true);
+    } else if (CE) {
+      getCheckerManager().runCheckersForPostStmt(Dst, DstPostCall, CE,
+                                                 *this, true);
+    } else {
+      Dst.insert(DstPostCall);
+    }
 
     // Enqueue the next element in the block.
     for (ExplodedNodeSet::iterator PSI = Dst.begin(), PSE = Dst.end();