]> granicus.if.org Git - clang/commitdiff
Begin reworking static analyzer support for C++ method calls. The current logic...
authorTed Kremenek <kremenek@apple.com>
Wed, 30 Mar 2011 17:41:19 +0000 (17:41 +0000)
committerTed Kremenek <kremenek@apple.com>
Wed, 30 Mar 2011 17:41:19 +0000 (17:41 +0000)
from how we process ordinary function calls, had a tremendous about of redundancy, and relied
strictly on inlining behavior (which was incomplete) to provide semantics instead of falling
back to the conservative analysis we use for C functions.  This is a significant step into
making C++ analyzer support more useful.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@128557 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ExprCXX.h
include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
lib/AST/ExprCXX.cpp
lib/StaticAnalyzer/Core/AggExprVisitor.cpp
lib/StaticAnalyzer/Core/CFRefCount.cpp
lib/StaticAnalyzer/Core/CXXExprEngine.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
lib/StaticAnalyzer/Core/ObjCMessage.cpp
test/Analysis/base-init.cpp
test/Analysis/inline.c
test/Analysis/misc-ps-region-store.cpp

index 30481ba779e76e5022903d23b18bf3c2e7362e77..e926267f5c9b924552ae0bc62c646f2f1f8d1122 100644 (file)
@@ -99,7 +99,10 @@ public:
   /// getImplicitObjectArgument - Retrieves the implicit object
   /// argument for the member call. For example, in "x.f(5)", this
   /// operation would return "x".
-  Expr *getImplicitObjectArgument();
+  Expr *getImplicitObjectArgument() const;
+  
+  /// Retrieves the declaration of the called method.
+  CXXMethodDecl *getMethodDecl() const;
 
   /// getRecordDecl - Retrieves the CXXRecordDecl for the underlying type of
   /// the implicit object argument. Note that this is may not be the same
index 7a562482c266dfbce698ccb8a557ed246f1a2c22..3708bb8e11e5fcdd851f9005e066b766e21b6ece 100644 (file)
@@ -264,10 +264,8 @@ public:
 
 
   /// VisitCall - Transfer function for function calls.
-  void VisitCall(const CallExpr* CE, ExplodedNode* Pred,
-                 CallExpr::const_arg_iterator AI, 
-                 CallExpr::const_arg_iterator AE,
-                 ExplodedNodeSet& Dst);
+  void VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred,
+                     ExplodedNodeSet& Dst);
 
   /// VisitCast - Transfer function logic for all casts (implicit and explicit).
   void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred,
@@ -362,12 +360,6 @@ public:
                           const MemRegion *Dest, const Stmt *S,
                           ExplodedNode *Pred, ExplodedNodeSet &Dst);
 
-  void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred,
-                              ExplodedNodeSet &Dst);
-
-  void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C,
-                                ExplodedNode *Pred, ExplodedNodeSet &Dst);
-
   void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
                        ExplodedNodeSet &Dst);
 
@@ -393,12 +385,10 @@ public:
                      const FunctionProtoType *FnType, 
                      ExplodedNode *Pred, ExplodedNodeSet &Dst,
                      bool FstArgAsLValue = false);
-
-  /// Evaluate method call itself. Used for CXXMethodCallExpr and
-  /// CXXOperatorCallExpr.
-  void evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD,
-                      const Expr *ThisExpr, ExplodedNode *Pred,
-                      ExplodedNodeSet &Src, ExplodedNodeSet &Dst);
+  
+  /// Evaluate callee expression (for a function call).
+  void evalCallee(const CallExpr *callExpr, const ExplodedNodeSet &src,
+                  ExplodedNodeSet &dest);
 
   /// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
   ///  expressions of the form 'x != 0' and generate new nodes (stored in Dst)
index 35c2d4100823f13a497896bf67853b09fbd1da58..02d60ef0a7d9ef9145867e15fad2b9c35491f3ba 100644 (file)
@@ -384,14 +384,25 @@ SourceRange CXXOperatorCallExpr::getSourceRange() const {
   }
 }
 
-Expr *CXXMemberCallExpr::getImplicitObjectArgument() {
-  if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
+Expr *CXXMemberCallExpr::getImplicitObjectArgument() const {
+  if (const MemberExpr *MemExpr = 
+        dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
     return MemExpr->getBase();
 
   // FIXME: Will eventually need to cope with member pointers.
   return 0;
 }
 
+CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const {
+  if (const MemberExpr *MemExpr = 
+      dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
+    return cast<CXXMethodDecl>(MemExpr->getMemberDecl());
+
+  // FIXME: Will eventually need to cope with member pointers.
+  return 0;
+}
+
+
 CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() {
   Expr* ThisArg = getImplicitObjectArgument();
   if (!ThisArg)
index e80cf9b4a331c0131530b724282c50ae405cdb60..901190d901dde7acb61ab4864a81b52308966b16 100644 (file)
@@ -60,7 +60,7 @@ void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) {
 }
 
 void AggExprVisitor::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
-  Eng.VisitCXXMemberCallExpr(E, Pred, DstSet);
+  Eng.Visit(E, Pred, DstSet);
 }
 
 void ExprEngine::VisitAggExpr(const Expr *E, const MemRegion *Dest, 
index 690ffb58765268a0e98fa37aae7940cff157c9e1..416e1209ae6ad2540a97053bd64c3f1b04d775e6 100644 (file)
@@ -16,6 +16,7 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceManager.h"
@@ -2680,11 +2681,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
       // FIXME: We eventually should handle structs and other compound types
       // that are returned by value.
 
-      QualType T = callOrMsg.getResultType(Eng.getContext());
-      if (Loc::isLocType(T) || (T->isIntegerType() && T->isScalarType())) {
+      // Use the result type from callOrMsg as it automatically adjusts
+      // for methods/functions that return references.
+      QualType resultTy = callOrMsg.getResultType(Eng.getContext());
+      if (Loc::isLocType(resultTy) || 
+            (resultTy->isIntegerType() && resultTy->isScalarType())) {
         unsigned Count = Builder.getCurrentBlockCount();
         SValBuilder &svalBuilder = Eng.getSValBuilder();
-        SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, T, Count);
+        SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, resultTy, Count);
         state = state->BindExpr(Ex, X, false);
       }
 
@@ -2711,9 +2715,12 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
       unsigned Count = Builder.getCurrentBlockCount();
       SValBuilder &svalBuilder = Eng.getSValBuilder();
       SymbolRef Sym = svalBuilder.getConjuredSymbol(Ex, Count);
-      QualType RetT = GetReturnType(Ex, svalBuilder.getContext());
+
+      // Use the result type from callOrMsg as it automatically adjusts
+      // for methods/functions that return references.      
+      QualType resultTy = callOrMsg.getResultType(Eng.getContext());
       state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(),
-                                                            RetT));
+                                                            resultTy));
       state = state->BindExpr(Ex, svalBuilder.makeLoc(Sym), false);
 
       // FIXME: Add a flag to the checker where allocations are assumed to
@@ -2766,11 +2773,17 @@ void CFRefCount::evalCall(ExplodedNodeSet& Dst,
   if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) {
     Summ = Summaries.getPersistentStopSummary();
   }
-  else {
-    const FunctionDecl* FD = L.getAsFunctionDecl();
-    Summ = !FD ? Summaries.getDefaultSummary() :
-                 Summaries.getSummary(FD);
+  else if (const FunctionDecl* FD = L.getAsFunctionDecl()) {
+    Summ = Summaries.getSummary(FD);
   }
+  else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) {
+    if (const CXXMethodDecl *MD = me->getMethodDecl())
+      Summ = Summaries.getSummary(MD);
+    else
+      Summ = Summaries.getDefaultSummary();    
+  }
+  else
+    Summ = Summaries.getDefaultSummary();
 
   assert(Summ);
   evalSummary(Dst, Eng, Builder, CE,
index a71761dab8bfe3b0f0f919088dfe1ae3c983360f..b015d4f264d786fad2e0d77ebf7973b0a799f8fe 100644 (file)
@@ -62,6 +62,34 @@ void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE,
   }
 }
 
+void ExprEngine::evalCallee(const CallExpr *callExpr,
+                            const ExplodedNodeSet &src,
+                            ExplodedNodeSet &dest) {
+  
+  const Expr *callee = 0;
+  
+  switch (callExpr->getStmtClass()) {
+    case Stmt::CXXMemberCallExprClass: {
+      // Evaluate the implicit object argument that is the recipient of the
+      // call.
+      callee = cast<CXXMemberCallExpr>(callExpr)->getImplicitObjectArgument();
+      
+      // FIXME: handle member pointers.
+      if (!callee)
+        return;
+
+      break;      
+    }
+    default: {
+      callee = callExpr->getCallee()->IgnoreParens();
+      break;
+    }
+  }
+
+  for (ExplodedNodeSet::iterator i = src.begin(), e = src.end(); i != e; ++i)
+    Visit(callee, *i, dest);
+}
+
 const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXRecordDecl *D,
                                                  const StackFrameContext *SFC) {
   const Type *T = D->getTypeForDecl();
@@ -169,89 +197,6 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
     Dst.Add(N);
 }
 
-void ExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, 
-                                          ExplodedNode *Pred, 
-                                          ExplodedNodeSet &Dst) {
-  // Get the method type.
-  const FunctionProtoType *FnType = 
-                       MCE->getCallee()->getType()->getAs<FunctionProtoType>();
-  assert(FnType && "Method type not available");
-
-  // Evaluate explicit arguments with a worklist.
-  ExplodedNodeSet argsEvaluated;
-  evalArguments(MCE->arg_begin(), MCE->arg_end(), FnType, Pred, argsEvaluated);
-  // Evaluate the implicit object argument.
-  ExplodedNodeSet AllargsEvaluated;
-  const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
-  if (!ME)
-    return;
-  Expr *ObjArgExpr = ME->getBase();
-  for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), 
-                                 E = argsEvaluated.end(); I != E; ++I) {
-      Visit(ObjArgExpr, *I, AllargsEvaluated);
-  }
-
-  // Now evaluate the call itself.
-  const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
-  assert(MD && "not a CXXMethodDecl?");
-  evalMethodCall(MCE, MD, ObjArgExpr, Pred, AllargsEvaluated, Dst);
-}
-
-void ExprEngine::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C,
-                                            ExplodedNode *Pred,
-                                            ExplodedNodeSet &Dst) {
-  const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(C->getCalleeDecl());
-  if (!MD) {
-    // If the operator doesn't represent a method call treat as regular call.
-    VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
-    return;
-  }
-
-  // Determine the type of function we're calling (if available).
-  const FunctionProtoType *Proto = NULL;
-  QualType FnType = C->getCallee()->IgnoreParens()->getType();
-  if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
-    Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
-
-  // Evaluate arguments treating the first one (object method is called on)
-  // as alvalue.
-  ExplodedNodeSet argsEvaluated;
-  evalArguments(C->arg_begin(), C->arg_end(), Proto, Pred, argsEvaluated, true);
-
-  // Now evaluate the call itself.
-  evalMethodCall(C, MD, C->getArg(0), Pred, argsEvaluated, Dst);
-}
-
-void ExprEngine::evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD,
-                                  const Expr *ThisExpr, ExplodedNode *Pred,
-                                  ExplodedNodeSet &Src, ExplodedNodeSet &Dst) {
-  // Allow checkers to pre-visit the member call.
-  ExplodedNodeSet PreVisitChecks;
-  getCheckerManager().runCheckersForPreStmt(PreVisitChecks, Src, MCE, *this);
-
-  if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) {
-    // FIXME: conservative method call evaluation.
-    getCheckerManager().runCheckersForPostStmt(Dst, PreVisitChecks, MCE, *this);
-    return;
-  }
-
-  const StackFrameContext *SFC = AMgr.getStackFrame(MD, 
-                                                    Pred->getLocationContext(),
-                                                    MCE,
-                                                    Builder->getBlock(), 
-                                                    Builder->getIndex());
-  const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
-  CallEnter Loc(MCE, SFC, Pred->getLocationContext());
-  for (ExplodedNodeSet::iterator I = PreVisitChecks.begin(),
-         E = PreVisitChecks.end(); I != E; ++I) {
-    // Set up 'this' region.
-    const GRState *state = GetState(*I);
-    state = state->bindLoc(loc::MemRegionVal(ThisR), state->getSVal(ThisExpr));
-    Dst.Add(Builder->generateNode(Loc, state, *I));
-  }
-}
-
 void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
                                    ExplodedNodeSet &Dst) {
   if (CNE->isArray()) {
index e90864ed369d64564c1cc37b4bf681b509e13b98..2facd567b14de6d72f7978510439e1a0b3745e80 100644 (file)
@@ -554,9 +554,10 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
       break;
     }
 
-    case Stmt::CallExprClass: {
-      const CallExpr* C = cast<CallExpr>(S);
-      VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
+    case Stmt::CallExprClass:
+    case Stmt::CXXOperatorCallExprClass:
+    case Stmt::CXXMemberCallExprClass: {
+      VisitCallExpr(cast<CallExpr>(S), Pred, Dst);
       break;
     }
 
@@ -568,18 +569,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
       break;
     }
 
-    case Stmt::CXXMemberCallExprClass: {
-      const CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S);
-      VisitCXXMemberCallExpr(MCE, Pred, Dst);
-      break;
-    }
-
-    case Stmt::CXXOperatorCallExprClass: {
-      const CXXOperatorCallExpr *C = cast<CXXOperatorCallExpr>(S);
-      VisitCXXOperatorCallExpr(C, Pred, Dst);
-      break;
-    }
-
     case Stmt::CXXNewExprClass: {
       const CXXNewExpr *NE = cast<CXXNewExpr>(S);
       VisitCXXNewExpr(NE, Pred, Dst);
@@ -1554,6 +1543,15 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
 
 bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, 
                               ExplodedNode *Pred) {
+  return false;
+  
+  // Inlining isn't correct right now because we:
+  // (a) don't generate CallExit nodes.
+  // (b) we need a way to postpone doing post-visits of CallExprs until
+  // the CallExit.  This means we need CallExits for the non-inline
+  // cases as well.
+  
+#if 0
   const GRState *state = GetState(Pred);
   const Expr *Callee = CE->getCallee();
   SVal L = state->getSVal(Callee);
@@ -1562,6 +1560,29 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
   if (!FD)
     return false;
 
+  // Specially handle CXXMethods.
+  const CXXMethodDecl *methodDecl = 0;
+  
+  switch (CE->getStmtClass()) {
+    default: break;
+    case Stmt::CXXOperatorCallExprClass: {
+      const CXXOperatorCallExpr *opCall = cast<CXXOperatorCallExpr>(CE);
+      methodDecl = 
+        llvm::dyn_cast_or_null<CXXMethodDecl>(opCall->getCalleeDecl());
+      break;
+    }
+    case Stmt::CXXMemberCallExprClass: {
+      const CXXMemberCallExpr *memberCall = cast<CXXMemberCallExpr>(CE);
+      const MemberExpr *memberExpr = 
+        cast<MemberExpr>(memberCall->getCallee()->IgnoreParens());
+      methodDecl = cast<CXXMethodDecl>(memberExpr->getMemberDecl());
+      break;
+    }
+  }
+      
+  
+  
+  
   // Check if the function definition is in the same translation unit.
   if (FD->hasBody(FD)) {
     const StackFrameContext *stackFrame = 
@@ -1589,14 +1610,15 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
     Dst.Add(N);
     return true;
   }
+  
+  // Generate the CallExit node.
 
   return false;
+#endif
 }
 
-void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred,
-                             CallExpr::const_arg_iterator AI,
-                             CallExpr::const_arg_iterator AE,
-                             ExplodedNodeSet& Dst) {
+void ExprEngine::VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred,
+                               ExplodedNodeSet& dst) {
 
   // Determine the type of function we're calling (if available).
   const FunctionProtoType *Proto = NULL;
@@ -1604,73 +1626,78 @@ void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred,
   if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
     Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
 
-  // Evaluate the arguments.
-  ExplodedNodeSet ArgsEvaluated;
-  evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, ArgsEvaluated);
-
-  // Now process the call itself.
-  ExplodedNodeSet DstTmp;
-  const Expr* Callee = CE->getCallee()->IgnoreParens();
-
-  for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(),
-                                 NE=ArgsEvaluated.end(); NI != NE; ++NI) {
-    // Evaluate the callee.
-    ExplodedNodeSet DstTmp2;
-    Visit(Callee, *NI, DstTmp2);
-    // Perform the previsit of the CallExpr, storing the results in DstTmp.
-    getCheckerManager().runCheckersForPreStmt(DstTmp, DstTmp2, CE, *this);
+  // Should the first argument be evaluated as an lvalue?
+  bool firstArgumentAsLvalue = false;
+  switch (CE->getStmtClass()) {
+    case Stmt::CXXOperatorCallExprClass:
+      firstArgumentAsLvalue = true;
+      break;
+    default:
+      break;
   }
-
+  
+  // Evaluate the arguments.
+  ExplodedNodeSet dstArgsEvaluated;
+  evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, dstArgsEvaluated,
+                firstArgumentAsLvalue);
+
+  // Evaluate the callee.
+  ExplodedNodeSet dstCalleeEvaluated;
+  evalCallee(CE, dstArgsEvaluated, dstCalleeEvaluated);
+
+  // Perform the previsit of the CallExpr.
+  ExplodedNodeSet dstPreVisit;
+  getCheckerManager().runCheckersForPreStmt(dstPreVisit, dstCalleeEvaluated,
+                                            CE, *this);
+    
+  // Now evaluate the call itself.
   class DefaultEval : public GraphExpander {
     ExprEngine &Eng;
     const CallExpr *CE;
   public:
-    bool Inlined;
     
     DefaultEval(ExprEngine &eng, const CallExpr *ce)
-      : Eng(eng), CE(ce), Inlined(false) { }
+      : Eng(eng), CE(ce) {}
     virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+      // Should we inline the call?
       if (Eng.getAnalysisManager().shouldInlineCall() &&
           Eng.InlineCall(Dst, CE, Pred)) {
-        Inlined = true;
-      } else {
-        StmtNodeBuilder &Builder = Eng.getBuilder();
-        assert(&Builder && "StmtNodeBuilder must be defined.");
-
-        // Dispatch to the plug-in transfer function.
-        unsigned oldSize = Dst.size();
-        SaveOr OldHasGen(Builder.hasGeneratedNode);
-
-        // Dispatch to transfer function logic to handle the call itself.
-        const Expr* Callee = CE->getCallee()->IgnoreParens();
-        const GRState* state = Eng.GetState(Pred);
-        SVal L = state->getSVal(Callee);
-        Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred);
-
-        // Handle the case where no nodes where generated.  Auto-generate that
-        // contains the updated state if we aren't generating sinks.
-        if (!Builder.BuildSinks && Dst.size() == oldSize &&
-            !Builder.hasGeneratedNode)
-          Eng.MakeNode(Dst, CE, Pred, state);
+        return;
       }
+
+      StmtNodeBuilder &Builder = Eng.getBuilder();
+      assert(&Builder && "StmtNodeBuilder must be defined.");
+
+      // Dispatch to the plug-in transfer function.
+      unsigned oldSize = Dst.size();
+      SaveOr OldHasGen(Builder.hasGeneratedNode);
+
+      // Dispatch to transfer function logic to handle the call itself.
+      const Expr* Callee = CE->getCallee()->IgnoreParens();
+      const GRState* state = Eng.GetState(Pred);
+      SVal L = state->getSVal(Callee);
+      Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred);
+
+      // Handle the case where no nodes where generated.  Auto-generate that
+      // contains the updated state if we aren't generating sinks.
+      if (!Builder.BuildSinks && Dst.size() == oldSize &&
+          !Builder.hasGeneratedNode)
+        Eng.MakeNode(Dst, CE, Pred, state);
     }
   };
 
   // Finally, evaluate the function call.  We try each of the checkers
   // to see if the can evaluate the function call.
-  ExplodedNodeSet DstTmp3;
+  ExplodedNodeSet dstCallEvaluated;
   DefaultEval defEval(*this, CE);
-
-  getCheckerManager().runCheckersForEvalCall(DstTmp3, DstTmp, CE,
-                                             *this, &defEval);
-
-  // Callee is inlined. We shouldn't do post call checking.
-  if (defEval.Inlined)
-    return;
+  getCheckerManager().runCheckersForEvalCall(dstCallEvaluated,
+                                             dstPreVisit,
+                                             CE, *this, &defEval);
 
   // Finally, perform the post-condition check of the CallExpr and store
   // the created nodes in 'Dst'.
-  getCheckerManager().runCheckersForPostStmt(Dst, DstTmp3, CE, *this);
+  getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE,
+                                             *this);
 }
 
 //===----------------------------------------------------------------------===//
index b2272968bb9169a25bb31daac5ef18999e0a4ff7..c44d36ae49f5a5153997e2e9b8e49daf45582109 100644 (file)
@@ -109,13 +109,27 @@ const Expr *ObjCMessage::getArgExpr(unsigned i) const {
 }
 
 QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const {
+  QualType resultTy;
+  bool isLVal = false;
+  
   if (CallE) {
+    isLVal = CallE->isLValue();
     const Expr *Callee = CallE->getCallee();
     if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl())
-      return FD->getResultType();
-    return CallE->getType();
+      resultTy = FD->getResultType();
+    else
+      resultTy = CallE->getType();
+  }
+  else {
+    isLVal = isa<ObjCMessageExpr>(Msg.getOriginExpr()) &&
+             Msg.getOriginExpr()->isLValue();
+    resultTy = Msg.getResultType(ctx);
   }
-  return Msg.getResultType(ctx);
+
+  if (isLVal)
+    resultTy = ctx.getPointerType(resultTy);
+
+  return resultTy;
 }
 
 SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const {
index 828c9e0b4e40298ffe0e5f7f08fcb835a94eecbe..8fd7abcc37780adaade0434d7e00fd5848d96ccd 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -analyzer-inline-call -cfg-add-initializers -verify %s
+// XFAIL: *
 
 class A {
   int x;
index e3c7e838934a152f935258b79201be80d66b99dc..2aac15661b14a02048c0a652a3b28f9da7bfa5e3 100644 (file)
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s
+// XFAIL: *
 
 int test1_f1() {
   int y = 1;
index 79bb03f86ae86579a5ace9bc074fc84ec771f4cd..3b8d4e378202e2ba26cab7eebf9efdf73214869e 100644 (file)
@@ -240,3 +240,19 @@ void test_namespace() {
   int x = i;
 }
 
+// Test handling methods that accept references as parameters, and that
+// variables are properly invalidated.
+class RDar9203355 {
+  bool foo(unsigned valA, long long &result) const;
+  bool foo(unsigned valA, int &result) const;
+};
+bool RDar9203355::foo(unsigned valA, int &result) const {
+  long long val;
+  if (foo(valA, val) ||
+      (int)val != val) // no-warning
+    return true;
+  result = val; // no-warning
+  return false;
+}
+
+