[cfe-commits] r159554 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/ include/clang/StaticAnalyzer/Core/PathSensitive/ lib/StaticAnalyzer/Checkers/ lib/StaticAnalyzer/Core/ test/Analysis/

Jordan Rose jordan_rose at apple.com
Mon Jul 2 12:27:36 PDT 2012


Author: jrose
Date: Mon Jul  2 14:27:35 2012
New Revision: 159554

URL: http://llvm.org/viewvc/llvm-project?rev=159554&view=rev
Log:
[analyzer] Add a new abstraction over all types of calls: CallEvent

This is intended to replace CallOrObjCMessage, and is eventually intended to be
used for anything that cares more about /what/ is being called than /how/ it's
being called. For example, inlining destructors should be the same as inlining
blocks, and checking __attribute__((nonnull)) should apply to the allocator
calls generated by operator new.

Added:
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
    cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp
    cfe/trunk/test/Analysis/blocks-no-inline.c
Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt
    cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h Mon Jul  2 14:27:35 2012
@@ -266,7 +266,7 @@
                       const StoreManager::InvalidatedSymbols *invalidated,
                       ArrayRef<const MemRegion *> Explicits,
                       ArrayRef<const MemRegion *> Regions,
-                      const CallOrObjCMessage *Call) {
+                      const CallEvent *Call) {
     return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated,
                                                       Explicits, Regions, Call);
   }

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h Mon Jul  2 14:27:35 2012
@@ -294,7 +294,7 @@
                             const StoreManager::InvalidatedSymbols *invalidated,
                               ArrayRef<const MemRegion *> ExplicitRegions,
                               ArrayRef<const MemRegion *> Regions,
-                              const CallOrObjCMessage *Call);
+                              const CallEvent *Call);
 
   /// \brief Run checkers for handling assumptions on symbolic values.
   ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state,
@@ -373,7 +373,7 @@
                                 const StoreManager::InvalidatedSymbols *symbols,
                                 ArrayRef<const MemRegion *> ExplicitRegions,
                                 ArrayRef<const MemRegion *> Regions,
-                                const CallOrObjCMessage *Call)>
+                                const CallEvent *Call)>
       CheckRegionChangesFunc;
   
   typedef CheckerFn<bool (ProgramStateRef)> WantsRegionChangeUpdateFunc;

Added: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h?rev=159554&view=auto
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h (added)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h Mon Jul  2 14:27:35 2012
@@ -0,0 +1,356 @@
+//===- Calls.h - Wrapper for all function and method calls --------*- C++ -*--//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file This file defines CallEvent and its subclasses, which represent path-
+/// sensitive instances of different kinds of function and method calls
+/// (C, C++, and Objective-C).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL
+#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+
+namespace clang {
+namespace ento {
+
+enum CallEventKind {
+  CE_Function,
+  CE_CXXMember,
+  CE_Block,
+  CE_BEG_SIMPLE_CALLS = CE_Function,
+  CE_END_SIMPLE_CALLS = CE_Block,
+  CE_CXXConstructor,
+  CE_BEG_FUNCTION_CALLS = CE_Function,
+  CE_END_FUNCTION_CALLS = CE_CXXConstructor,
+  CE_ObjCMessage
+};
+
+/// \brief Represents an abstract call to a function or method along a
+/// particular path.
+class CallEvent {
+public:
+  typedef CallEventKind Kind;
+
+protected:
+  ProgramStateRef State;
+  const LocationContext *LCtx;
+  const Kind K;
+
+  CallEvent(ProgramStateRef state, const LocationContext *lctx, Kind k)
+    : State(state), LCtx(lctx), K(k) {}
+  virtual ~CallEvent() {}
+
+  /// \brief Get the value of arbitrary expressions at this point in the path.
+  SVal getSVal(const Stmt *S) const {
+    return State->getSVal(S, LCtx);
+  }
+
+  typedef SmallVectorImpl<const MemRegion *> RegionList;
+
+  /// \brief Used to specify non-argument regions that will be invalidated as a
+  /// result of this call.
+  virtual void addExtraInvalidatedRegions(RegionList &Regions) const {}
+
+  typedef const ParmVarDecl * const *param_iterator;
+  virtual param_iterator param_begin() const = 0;
+  virtual param_iterator param_end() const = 0;
+
+  virtual QualType getDeclaredResultType() const { return QualType(); }
+
+public:
+  /// \brief Returns the declaration of the function or method that will be
+  /// called. May be null.
+  virtual const Decl *getDecl() const = 0;
+
+  /// \brief Returns the expression whose value will be the result of this call.
+  /// May be null.
+  virtual const Expr *getOriginExpr() const = 0;
+
+  /// \brief Returns the number of arguments (explicit and implicit).
+  ///
+  /// Note that this may be greater than the number of parameters in the
+  /// callee's declaration, and that it may include arguments not written in
+  /// the source.
+  virtual unsigned getNumArgs() const = 0;
+
+  /// \brief Returns true if the callee is known to be from a system header.
+  bool isInSystemHeader() const {
+    const Decl *D = getDecl();
+    if (!D)
+      return false;
+
+    SourceLocation Loc = D->getLocation();
+    if (Loc.isValid()) {
+      const SourceManager &SM =
+        State->getStateManager().getContext().getSourceManager();
+      return SM.isInSystemHeader(D->getLocation());
+    }
+
+    // Special case for implicitly-declared global operator new/delete.
+    // These should be considered system functions.
+    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+      return FD->isOverloadedOperator() && FD->isImplicit() && FD->isGlobal();
+
+    return false;
+  }
+
+  /// \brief Returns the kind of call this is.
+  Kind getKind() const { return K; }
+
+  /// \brief Returns the value of a given argument at the time of the call.
+  virtual SVal getArgSVal(unsigned Index) const;
+
+  /// \brief Returns the expression associated with a given argument.
+  /// May be null if this expression does not appear in the source.
+  virtual const Expr *getArgExpr(unsigned Index) const {
+    return 0;
+  }
+
+  /// \brief Returns the source range for errors associated with this argument.
+  /// May be invalid if the argument is not written in the source.
+  // FIXME: Is it better to return an invalid range or the range of the origin
+  // expression?
+  virtual SourceRange getArgSourceRange(unsigned Index) const;
+
+  /// \brief Returns the result type, adjusted for references.
+  QualType getResultType() const;
+
+  /// \brief Returns true if any of the arguments appear to represent callbacks.
+  bool hasNonZeroCallbackArg() const;
+
+  /// \brief Returns a new state with all argument regions invalidated.
+  ///
+  /// This accepts an alternate state in case some processing has already
+  /// occurred.
+  ProgramStateRef invalidateRegions(unsigned BlockCount,
+                                    ProgramStateRef Orig = 0) const;
+
+  // Iterator access to parameter types.
+private:
+  typedef std::const_mem_fun_t<QualType, ParmVarDecl> get_type_fun;
+  
+public:
+  typedef llvm::mapped_iterator<param_iterator, get_type_fun>
+    param_type_iterator;
+
+  param_type_iterator param_type_begin() const {
+    return llvm::map_iterator(param_begin(),
+                              get_type_fun(&ParmVarDecl::getType));
+  }
+  param_type_iterator param_type_end() const {
+    return llvm::map_iterator(param_end(), get_type_fun(&ParmVarDecl::getType));
+  }
+
+  static bool classof(const CallEvent *) { return true; }
+};
+
+/// \brief Represents a call to any sort of function that might have a
+/// FunctionDecl.
+class AnyFunctionCall : public CallEvent {
+protected:
+  AnyFunctionCall(ProgramStateRef St, const LocationContext *LCtx, Kind K)
+    : CallEvent(St, LCtx, K) {}
+
+  param_iterator param_begin() const;
+  param_iterator param_end() const;
+
+  QualType getDeclaredResultType() const;
+
+public:
+  virtual const FunctionDecl *getDecl() const = 0;
+
+  static bool classof(const CallEvent *CA) {
+    return CA->getKind() >= CE_BEG_FUNCTION_CALLS &&
+           CA->getKind() <= CE_END_FUNCTION_CALLS;
+  }
+};
+
+/// \brief Represents a call to a written as a CallExpr.
+class SimpleCall : public AnyFunctionCall {
+  const CallExpr *CE;
+
+protected:
+  SimpleCall(const CallExpr *ce, ProgramStateRef St,
+             const LocationContext *LCtx, Kind K)
+    : AnyFunctionCall(St, LCtx, K), CE(ce) {
+  }
+
+public:
+  const CallExpr *getOriginExpr() const { return CE; }
+
+  const FunctionDecl *getDecl() const;
+
+  unsigned getNumArgs() const { return CE->getNumArgs(); }
+  
+  const Expr *getArgExpr(unsigned Index) const {
+    return CE->getArg(Index);
+  }
+
+  static bool classof(const CallEvent *CA) {
+    return CA->getKind() >= CE_BEG_SIMPLE_CALLS &&
+           CA->getKind() <= CE_END_SIMPLE_CALLS;
+  }
+};
+
+/// \brief Represents a C function or static C++ member function call.
+///
+/// Example: \c fun()
+class FunctionCall : public SimpleCall {
+public:
+  FunctionCall(const CallExpr *CE, ProgramStateRef St,
+               const LocationContext *LCtx)
+    : SimpleCall(CE, St, LCtx, CE_Function) {}
+
+  static bool classof(const CallEvent *CA) {
+    return CA->getKind() == CE_Function;
+  }
+};
+
+/// \brief Represents a non-static C++ member function call.
+///
+/// Example: \c obj.fun()
+class CXXMemberCall : public SimpleCall {
+protected:
+  void addExtraInvalidatedRegions(RegionList &Regions) const;
+
+public:
+  CXXMemberCall(const CXXMemberCallExpr *CE, ProgramStateRef St,
+               const LocationContext *LCtx)
+    : SimpleCall(CE, St, LCtx, CE_CXXMember) {}
+
+  const CXXMemberCallExpr *getOriginExpr() const {
+    return cast<CXXMemberCallExpr>(SimpleCall::getOriginExpr());
+  }
+
+  static bool classof(const CallEvent *CA) {
+    return CA->getKind() == CE_CXXMember;
+  }
+};
+
+/// \brief Represents a call to a block.
+///
+/// Example: \c ^{ /* ... */ }()
+class BlockCall : public SimpleCall {
+protected:
+  void addExtraInvalidatedRegions(RegionList &Regions) const;
+
+  param_iterator param_begin() const;
+  param_iterator param_end() const;
+
+  QualType getDeclaredResultType() const;
+
+public:
+  BlockCall(const CallExpr *CE, ProgramStateRef St,
+            const LocationContext *LCtx)
+    : SimpleCall(CE, St, LCtx, CE_Block) {
+    assert(isa<BlockDataRegion>(getSVal(CE->getCallee()).getAsRegion()));
+  }
+
+  static bool classof(const CallEvent *CA) {
+    return CA->getKind() == CE_Block;
+  }
+
+private:
+  const BlockDataRegion *getBlockRegion() const;
+};
+
+/// \brief Represents a call to a C++ constructor.
+///
+/// Example: \c T(1)
+class CXXConstructorCall : public AnyFunctionCall {
+  const CXXConstructExpr *CE;
+  const MemRegion *Target;
+
+protected:
+  void addExtraInvalidatedRegions(RegionList &Regions) const;
+
+public:
+  CXXConstructorCall(const CXXConstructExpr *ce, ProgramStateRef St,
+                     const LocationContext *LCtx)
+    : AnyFunctionCall(St, LCtx, CE_CXXConstructor), CE(ce), Target(0) {}
+  CXXConstructorCall(const CXXConstructExpr *ce, const MemRegion *target,
+                     ProgramStateRef St, const LocationContext *LCtx)
+    : AnyFunctionCall(St, LCtx, CE_CXXConstructor), CE(ce), Target(target) {}
+
+  const CXXConstructExpr *getOriginExpr() const { return CE; }
+
+  const CXXConstructorDecl *getDecl() const {
+    return CE->getConstructor();
+  }
+
+  unsigned getNumArgs() const { return CE->getNumArgs(); }
+
+  const Expr *getArgExpr(unsigned Index) const {
+    return CE->getArg(Index);
+  }
+
+  static bool classof(const CallEvent *CA) {
+    return CA->getKind() == CE_CXXConstructor;
+  }
+};
+
+/// \brief Represents any expression that causes an Objective-C message send.
+//
+// This class is mostly passthrough to ObjCMessage, because /that/ class is the
+// adapter for the different kinds of Objective-C messages in the system. The
+// difference here is that like other CallActions this refers to a specific
+// (path-sensitive) message send, while ObjCMessage is simply a wrapper for the
+// various (path-insensitive) expressions that are implemented using messages.
+class ObjCMessageInvocation : public CallEvent {
+  ObjCMessage Msg;
+
+protected:
+  void addExtraInvalidatedRegions(RegionList &Regions) const;
+
+  param_iterator param_begin() const;
+  param_iterator param_end() const;
+
+  QualType getDeclaredResultType() const;
+
+public:
+  ObjCMessageInvocation(const ObjCMessage &msg, ProgramStateRef St,
+                        const LocationContext *LCtx)
+    : CallEvent(St, LCtx, CE_ObjCMessage), Msg(msg) {}
+
+  Selector getSelector() const { return Msg.getSelector(); }
+  bool isInstanceMessage() const { return Msg.isInstanceMessage(); }
+  const ObjCMethodDecl *getDecl() const { return Msg.getMethodDecl(); }
+  unsigned getNumArgs() const { return Msg.getNumArgs(); }
+  const Expr *getArgExpr(unsigned Index) const { return Msg.getArgExpr(Index); }
+
+  // FIXME: for emitting warnings and such this may not be the best idea.
+  const Expr *getOriginExpr() const { return Msg.getMessageExpr(); }
+
+  SVal getReceiverSVal() const;
+
+  SourceRange getReceiverSourceRange() const {
+    return Msg.getReceiverSourceRange();
+  }
+
+  const ObjCInterfaceDecl *getReceiverInterface() const {
+    return Msg.getReceiverInterface();
+  }
+
+  static bool classof(const CallEvent *CA) {
+    return CA->getKind() == CE_ObjCMessage;
+  }
+};
+
+} // end namespace ento
+} // end namespace clang
+
+#endif

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Mon Jul  2 14:27:35 2012
@@ -41,7 +41,7 @@
 namespace ento {
 
 class AnalysisManager;
-class CallOrObjCMessage;
+class CallEvent;
 class ObjCMessage;
 
 class ExprEngine : public SubEngine {
@@ -240,7 +240,7 @@
                        const StoreManager::InvalidatedSymbols *invalidated,
                        ArrayRef<const MemRegion *> ExplicitRegions,
                        ArrayRef<const MemRegion *> Regions,
-                       const CallOrObjCMessage *Call);
+                       const CallEvent *Call);
 
   /// printState - Called by ProgramStateManager to print checker-specific data.
   void printState(raw_ostream &Out, ProgramStateRef State,
@@ -437,10 +437,6 @@
                        ExplodedNode *Pred, ProgramStateRef state,
                        bool GenSink);
 
-  ProgramStateRef invalidateArguments(ProgramStateRef State,
-                                          const CallOrObjCMessage &Call,
-                                          const LocationContext *LC);
-
   ProgramStateRef MarkBranch(ProgramStateRef state,
                                  const Stmt *Terminator,
                                  const LocationContext *LCtx,

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h Mon Jul  2 14:27:35 2012
@@ -35,7 +35,7 @@
 
 namespace ento {
 
-class CallOrObjCMessage;
+class CallEvent;
 
 typedef ConstraintManager* (*ConstraintManagerCreator)(ProgramStateManager&,
                                                        SubEngine&);
@@ -219,7 +219,7 @@
                                const Expr *E, unsigned BlockCount,
                                const LocationContext *LCtx,
                                StoreManager::InvalidatedSymbols *IS = 0,
-                               const CallOrObjCMessage *Call = 0) const;
+                               const CallEvent *Call = 0) const;
 
   /// enterStackFrame - Returns the state for entry to the given stack frame,
   ///  preserving the current state.
@@ -381,7 +381,7 @@
                         const Expr *E, unsigned BlockCount,
                         const LocationContext *LCtx,
                         StoreManager::InvalidatedSymbols &IS,
-                        const CallOrObjCMessage *Call) const;
+                        const CallEvent *Call) const;
 };
 
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h Mon Jul  2 14:27:35 2012
@@ -29,7 +29,7 @@
 
 namespace ento {
 
-class CallOrObjCMessage;
+class CallEvent;
 class ProgramState;
 class ProgramStateManager;
 class SubRegionMap;
@@ -194,7 +194,7 @@
                                      const Expr *E, unsigned Count,
                                      const LocationContext *LCtx,
                                      InvalidatedSymbols &IS,
-                                     const CallOrObjCMessage *Call,
+                                     const CallEvent *Call,
                                      InvalidatedRegions *Invalidated) = 0;
 
   /// enterStackFrame - Let the StoreManager to do something when execution

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h Mon Jul  2 14:27:35 2012
@@ -105,7 +105,7 @@
                        const StoreManager::InvalidatedSymbols *invalidated,
                        ArrayRef<const MemRegion *> ExplicitRegions,
                        ArrayRef<const MemRegion *> Regions,
-                       const CallOrObjCMessage *Call) = 0;
+                       const CallEvent *Call) = 0;
 
 
   inline ProgramStateRef 

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Mon Jul  2 14:27:35 2012
@@ -66,7 +66,7 @@
                        const StoreManager::InvalidatedSymbols *,
                        ArrayRef<const MemRegion *> ExplicitRegions,
                        ArrayRef<const MemRegion *> Regions,
-                       const CallOrObjCMessage *Call) const;
+                       const CallEvent *Call) const;
 
   typedef void (CStringChecker::*FnCheck)(CheckerContext &,
                                           const CallExpr *) const;
@@ -1895,7 +1895,7 @@
                                    const StoreManager::InvalidatedSymbols *,
                                    ArrayRef<const MemRegion *> ExplicitRegions,
                                    ArrayRef<const MemRegion *> Regions,
-                                   const CallOrObjCMessage *Call) const {
+                                   const CallEvent *Call) const {
   CStringLength::EntryMap Entries = state->get<CStringLength>();
   if (Entries.isEmpty())
     return state;

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp Mon Jul  2 14:27:35 2012
@@ -206,7 +206,7 @@
                        const StoreManager::InvalidatedSymbols *Invalidated,
                        ArrayRef<const MemRegion *> ExplicitRegions,
                        ArrayRef<const MemRegion *> Regions,
-                       const CallOrObjCMessage *Call) const {
+                       const CallEvent *Call) const {
     return State;
   }
 

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Mon Jul  2 14:27:35 2012
@@ -18,7 +18,7 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -140,7 +140,7 @@
                      const StoreManager::InvalidatedSymbols *invalidated,
                      ArrayRef<const MemRegion *> ExplicitRegions,
                      ArrayRef<const MemRegion *> Regions,
-                     const CallOrObjCMessage *Call) const;
+                     const CallEvent *Call) const;
   bool wantsRegionChangeUpdate(ProgramStateRef state) const {
     return true;
   }
@@ -200,7 +200,7 @@
 
   /// Check if the function is not known to us. So, for example, we could
   /// conservatively assume it can free/reallocate it's pointer arguments.
-  bool doesNotFreeMemory(const CallOrObjCMessage *Call,
+  bool doesNotFreeMemory(const CallEvent *Call,
                          ProgramStateRef State) const;
 
   static bool SummarizeValue(raw_ostream &os, SVal V);
@@ -481,7 +481,8 @@
   C.addTransition(State);
 }
 
-static bool isFreeWhenDoneSetToZero(CallOrObjCMessage Call, Selector &S) {
+static bool isFreeWhenDoneSetToZero(const ObjCMessageInvocation &Call,
+                                    Selector &S) {
   for (unsigned i = 1; i < S.getNumArgs(); ++i)
     if (S.getNameForSlot(i).equals("freeWhenDone"))
       if (Call.getArgSVal(i).isConstant(0))
@@ -491,12 +492,12 @@
 }
 
 void MallocChecker::checkPreObjCMessage(const ObjCMessage &Msg,
-                                         CheckerContext &C) const {
+                                        CheckerContext &C) const {
   const ObjCMethodDecl *MD = Msg.getMethodDecl();
   if (!MD)
     return;
 
-  CallOrObjCMessage Call(Msg, C.getState(), C.getLocationContext());
+  ObjCMessageInvocation Call(Msg, C.getState(), C.getLocationContext());
   Selector S = Msg.getSelector();
 
   // If the first selector is dataWithBytesNoCopy, assume that the memory will
@@ -509,7 +510,7 @@
        S.getNameForSlot(0) == "initWithCharactersNoCopy") &&
       !isFreeWhenDoneSetToZero(Call, S)){
     unsigned int argIdx  = 0;
-    C.addTransition(FreeMemAux(C, Call.getArg(argIdx),
+    C.addTransition(FreeMemAux(C, Call.getArgExpr(argIdx),
                     Msg.getMessageExpr(), C.getState(), true));
   }
 }
@@ -1310,10 +1311,10 @@
 }
 
 // Check if the function is known to us. So, for example, we could
-// conservatively assume it can free/reallocate it's pointer arguments.
+// conservatively assume it can free/reallocate its pointer arguments.
 // (We assume that the pointers cannot escape through calls to system
 // functions not handled by this checker.)
-bool MallocChecker::doesNotFreeMemory(const CallOrObjCMessage *Call,
+bool MallocChecker::doesNotFreeMemory(const CallEvent *Call,
                                       ProgramStateRef State) const {
   if (!Call)
     return false;
@@ -1322,118 +1323,23 @@
   // TODO: If we want to be more optimistic here, we'll need to make sure that
   // regions escape to C++ containers. They seem to do that even now, but for
   // mysterious reasons.
-  if (Call->isCXXCall())
+  if (!(isa<FunctionCall>(Call) || isa<ObjCMessageInvocation>(Call)))
     return false;
 
-  const Decl *D = Call->getDecl();
-  if (!D)
+  // If the call has a callback as an argument, assume the memory
+  // can be freed.
+  if (Call->hasNonZeroCallbackArg())
     return false;
 
-  ASTContext &ASTC = State->getStateManager().getContext();
-
-  // If it's one of the allocation functions we can reason about, we model
-  // its behavior explicitly.
-  if (isa<FunctionDecl>(D) && isMemFunction(cast<FunctionDecl>(D), ASTC)) {
-    return true;
-  }
-
-  // If it's not a system call, assume it frees memory.
-  if (!Call->isInSystemHeader())
-    return false;
-
-  // Process C/ObjC functions.
-  if (const FunctionDecl *FD  = dyn_cast<FunctionDecl>(D)) {
-    // White list the system functions whose arguments escape.
-    const IdentifierInfo *II = FD->getIdentifier();
-    if (!II)
-      return true;
-    StringRef FName = II->getName();
-
-    // White list thread local storage.
-    if (FName.equals("pthread_setspecific"))
+  // Check Objective-C messages by selector name.
+  if (const ObjCMessageInvocation *Msg = dyn_cast<ObjCMessageInvocation>(Call)){
+    // If it's not a framework call, assume it frees memory.
+    if (!Call->isInSystemHeader())
       return false;
 
-    // White list xpc connection context.
-    // TODO: Ensure that the deallocation actually happens, need to reason
-    // about "xpc_connection_set_finalizer_f".
-    if (FName.equals("xpc_connection_set_context"))
-      return false;
+    Selector S = Msg->getSelector();
 
-    // White list the 'XXXNoCopy' ObjC functions.
-    if (FName.endswith("NoCopy")) {
-      // Look for the deallocator argument. We know that the memory ownership
-      // is not transferred only if the deallocator argument is
-      // 'kCFAllocatorNull'.
-      for (unsigned i = 1; i < Call->getNumArgs(); ++i) {
-        const Expr *ArgE = Call->getArg(i)->IgnoreParenCasts();
-        if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
-          StringRef DeallocatorName = DE->getFoundDecl()->getName();
-          if (DeallocatorName == "kCFAllocatorNull")
-            return true;
-        }
-      }
-      return false;
-    }
-
-    // PR12101
-    // Many CoreFoundation and CoreGraphics might allow a tracked object 
-    // to escape.
-    if (Call->isCFCGAllowingEscape(FName))
-      return false;
-
-    // Associating streams with malloced buffers. The pointer can escape if
-    // 'closefn' is specified (and if that function does free memory).
-    // Currently, we do not inspect the 'closefn' function (PR12101).
-    if (FName == "funopen")
-      if (Call->getNumArgs() >= 4 && !Call->getArgSVal(4).isConstant(0))
-        return false;
-
-    // Do not warn on pointers passed to 'setbuf' when used with std streams,
-    // these leaks might be intentional when setting the buffer for stdio.
-    // http://stackoverflow.com/questions/2671151/who-frees-setvbuf-buffer
-    if (FName == "setbuf" || FName =="setbuffer" ||
-        FName == "setlinebuf" || FName == "setvbuf") {
-      if (Call->getNumArgs() >= 1)
-        if (const DeclRefExpr *Arg =
-              dyn_cast<DeclRefExpr>(Call->getArg(0)->IgnoreParenCasts()))
-          if (const VarDecl *D = dyn_cast<VarDecl>(Arg->getDecl()))
-              if (D->getCanonicalDecl()->getName().find("std")
-                                                   != StringRef::npos)
-                return false;
-    }
-
-    // A bunch of other functions which either take ownership of a pointer or
-    // wrap the result up in a struct or object, meaning it can be freed later.
-    // (See RetainCountChecker.) Not all the parameters here are invalidated,
-    // but the Malloc checker cannot differentiate between them. The right way
-    // of doing this would be to implement a pointer escapes callback.
-    if (FName == "CGBitmapContextCreate" ||
-        FName == "CGBitmapContextCreateWithData" ||
-        FName == "CVPixelBufferCreateWithBytes" ||
-        FName == "CVPixelBufferCreateWithPlanarBytes" ||
-        FName == "OSAtomicEnqueue") {
-      return false;
-    }
-
-    // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
-    // be deallocated by NSMapRemove.
-    if (FName.startswith("NS") && (FName.find("Insert") != StringRef::npos))
-      return false;
-
-    // If the call has a callback as an argument, assume the memory
-    // can be freed.
-    if (Call->hasNonZeroCallbackArg())
-      return false;
-
-    // Otherwise, assume that the function does not free memory.
-    // Most system calls, do not free the memory.
-    return true;
-
-  // Process ObjC functions.
-  } else if (const ObjCMethodDecl * ObjCD = dyn_cast<ObjCMethodDecl>(D)) {
-    Selector S = ObjCD->getSelector();
-
-    // White list the ObjC functions which do free memory.
+    // Whitelist the ObjC methods which do free memory.
     // - Anything containing 'freeWhenDone' param set to 1.
     //   Ex: dataWithBytesNoCopy:length:freeWhenDone.
     for (unsigned i = 1; i < S.getNumArgs(); ++i) {
@@ -1448,33 +1354,117 @@
     // If the first selector ends with NoCopy, assume that the ownership is
     // transferred as well.
     // Ex:  [NSData dataWithBytesNoCopy:bytes length:10];
-    if (S.getNameForSlot(0).endswith("NoCopy")) {
+    StringRef FirstSlot = S.getNameForSlot(0);
+    if (FirstSlot.endswith("NoCopy"))
       return false;
-    }
 
     // If the first selector starts with addPointer, insertPointer,
     // or replacePointer, assume we are dealing with NSPointerArray or similar.
     // This is similar to C++ containers (vector); we still might want to check
-    // that the pointers get freed, by following the container itself.
-    if (S.getNameForSlot(0).startswith("addPointer") ||
-        S.getNameForSlot(0).startswith("insertPointer") ||
-        S.getNameForSlot(0).startswith("replacePointer")) {
+    // that the pointers get freed by following the container itself.
+    if (FirstSlot.startswith("addPointer") ||
+        FirstSlot.startswith("insertPointer") ||
+        FirstSlot.startswith("replacePointer")) {
       return false;
     }
 
-    // If the call has a callback as an argument, assume the memory
-    // can be freed.
-    if (Call->hasNonZeroCallbackArg())
-      return false;
+    // Otherwise, assume that the method does not free memory.
+    // Most framework methods do not free memory.
+    return true;
+  }
 
-    // Otherwise, assume that the function does not free memory.
-    // Most system calls, do not free the memory.
+  // At this point the only thing left to handle is straight function calls.
+  const FunctionDecl *FD = cast<FunctionCall>(Call)->getDecl();
+  if (!FD)
+    return false;
+
+  ASTContext &ASTC = State->getStateManager().getContext();
+
+  // If it's one of the allocation functions we can reason about, we model
+  // its behavior explicitly.
+  if (isMemFunction(FD, ASTC))
     return true;
+
+  // If it's not a system call, assume it frees memory.
+  if (!Call->isInSystemHeader())
+    return false;
+
+  // White list the system functions whose arguments escape.
+  const IdentifierInfo *II = FD->getIdentifier();
+  if (!II)
+    return false;
+  StringRef FName = II->getName();
+
+  // White list thread local storage.
+  if (FName.equals("pthread_setspecific"))
+    return false;
+  if (FName.equals("xpc_connection_set_context"))
+    return false;
+
+  // White list the 'XXXNoCopy' CoreFoundation functions.
+  if (FName.endswith("NoCopy")) {
+    // Look for the deallocator argument. We know that the memory ownership
+    // is not transferred only if the deallocator argument is
+    // 'kCFAllocatorNull'.
+    for (unsigned i = 1; i < Call->getNumArgs(); ++i) {
+      const Expr *ArgE = Call->getArgExpr(i)->IgnoreParenCasts();
+      if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
+        StringRef DeallocatorName = DE->getFoundDecl()->getName();
+        if (DeallocatorName == "kCFAllocatorNull")
+          return true;
+      }
+    }
+    return false;
   }
 
-  // Otherwise, assume that the function can free memory.
-  return false;
+  // PR12101
+  // Many CoreFoundation and CoreGraphics might allow a tracked object
+  // to escape.
+  if (CallOrObjCMessage::isCFCGAllowingEscape(FName))
+    return false;
+
+  // Associating streams with malloced buffers. The pointer can escape if
+  // 'closefn' is specified (and if that function does free memory).
+  // Currently, we do not inspect the 'closefn' function (PR12101).
+  if (FName == "funopen")
+    if (Call->getNumArgs() >= 4 && !Call->getArgSVal(4).isConstant(0))
+      return false;
 
+  // Do not warn on pointers passed to 'setbuf' when used with std streams,
+  // these leaks might be intentional when setting the buffer for stdio.
+  // http://stackoverflow.com/questions/2671151/who-frees-setvbuf-buffer
+  if (FName == "setbuf" || FName =="setbuffer" ||
+      FName == "setlinebuf" || FName == "setvbuf") {
+    if (Call->getNumArgs() >= 1) {
+      const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts();
+      if (const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
+        if (const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
+          if (D->getCanonicalDecl()->getName().find("std") != StringRef::npos)
+            return false;
+    }
+  }
+
+  // A bunch of other functions which either take ownership of a pointer or
+  // wrap the result up in a struct or object, meaning it can be freed later.
+  // (See RetainCountChecker.) Not all the parameters here are invalidated,
+  // but the Malloc checker cannot differentiate between them. The right way
+  // of doing this would be to implement a pointer escapes callback.
+  if (FName == "CGBitmapContextCreate" ||
+      FName == "CGBitmapContextCreateWithData" ||
+      FName == "CVPixelBufferCreateWithBytes" ||
+      FName == "CVPixelBufferCreateWithPlanarBytes" ||
+      FName == "OSAtomicEnqueue") {
+    return false;
+  }
+
+  // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
+  // be deallocated by NSMapRemove.
+  if (FName.startswith("NS") && (FName.find("Insert") != StringRef::npos))
+    return false;
+
+  // Otherwise, assume that the function does not free memory.
+  // Most system calls do not free the memory.
+  return true;
 }
 
 // If the symbol we are tracking is invalidated, but not explicitly (ex: the &p
@@ -1485,7 +1475,7 @@
                             const StoreManager::InvalidatedSymbols *invalidated,
                                     ArrayRef<const MemRegion *> ExplicitRegions,
                                     ArrayRef<const MemRegion *> Regions,
-                                    const CallOrObjCMessage *Call) const {
+                                    const CallEvent *Call) const {
   if (!invalidated || invalidated->empty())
     return State;
   llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Mon Jul  2 14:27:35 2012
@@ -2500,7 +2500,7 @@
                      const StoreManager::InvalidatedSymbols *invalidated,
                      ArrayRef<const MemRegion *> ExplicitRegions,
                      ArrayRef<const MemRegion *> Regions,
-                     const CallOrObjCMessage *Call) const;
+                     const CallEvent *Call) const;
                                         
   bool wantsRegionChangeUpdate(ProgramStateRef state) const {
     return true;
@@ -3454,7 +3454,7 @@
                             const StoreManager::InvalidatedSymbols *invalidated,
                                     ArrayRef<const MemRegion *> ExplicitRegions,
                                     ArrayRef<const MemRegion *> Regions,
-                                    const CallOrObjCMessage *Call) const {
+                                    const CallEvent *Call) const {
   if (!invalidated)
     return state;
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt Mon Jul  2 14:27:35 2012
@@ -8,6 +8,7 @@
   BlockCounter.cpp
   BugReporter.cpp
   BugReporterVisitors.cpp
+  Calls.cpp
   Checker.cpp
   CheckerContext.cpp
   CheckerHelpers.cpp

Added: cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp?rev=159554&view=auto
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp (added)
+++ cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp Mon Jul  2 14:27:35 2012
@@ -0,0 +1,353 @@
+//===- Calls.cpp - Wrapper for all function and method calls ------*- C++ -*--//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file This file defines CallEvent and its subclasses, which represent path-
+/// sensitive instances of different kinds of function and method calls
+/// (C, C++, and Objective-C).
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "llvm/ADT/SmallSet.h"
+
+using namespace clang;
+using namespace ento;
+
+SVal CallEvent::getArgSVal(unsigned Index) const {
+  const Expr *ArgE = getArgExpr(Index);
+  if (!ArgE)
+    return UnknownVal();
+  return getSVal(ArgE);
+}
+
+SourceRange CallEvent::getArgSourceRange(unsigned Index) const {
+  const Expr *ArgE = getArgExpr(Index);
+  if (!ArgE)
+    return SourceRange();
+  return ArgE->getSourceRange();
+}
+
+QualType CallEvent::getResultType() const {
+  QualType ResultTy = getDeclaredResultType();
+
+  if (const Expr *E = getOriginExpr()) {
+    if (ResultTy.isNull())
+      ResultTy = E->getType();
+
+    // FIXME: This is copied from CallOrObjCMessage, but it seems suspicious.
+    if (E->isGLValue()) {
+      ASTContext &Ctx = State->getStateManager().getContext();
+      ResultTy = Ctx.getPointerType(ResultTy);
+    }
+  }
+
+  return ResultTy;
+}
+
+static bool isCallbackArg(SVal V, QualType T) {
+  // If the parameter is 0, it's harmless.
+  if (V.isZeroConstant())
+    return false;
+
+  // If a parameter is a block or a callback, assume it can modify pointer.
+  if (T->isBlockPointerType() ||
+      T->isFunctionPointerType() ||
+      T->isObjCSelType())
+    return true;
+
+  // Check if a callback is passed inside a struct (for both, struct passed by
+  // reference and by value). Dig just one level into the struct for now.
+
+  if (isa<PointerType>(T) || isa<ReferenceType>(T))
+    T = T->getPointeeType();
+
+  if (const RecordType *RT = T->getAsStructureType()) {
+    const RecordDecl *RD = RT->getDecl();
+    for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+         I != E; ++I) {
+      QualType FieldT = I->getType();
+      if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType())
+        return true;
+    }
+  }
+
+  return false;
+}
+
+bool CallEvent::hasNonZeroCallbackArg() const {
+  unsigned NumOfArgs = getNumArgs();
+
+  // If calling using a function pointer, assume the function does not
+  // have a callback. TODO: We could check the types of the arguments here.
+  if (!getDecl())
+    return false;
+
+  unsigned Idx = 0;
+  for (CallEvent::param_type_iterator I = param_type_begin(),
+                                       E = param_type_end();
+       I != E && Idx < NumOfArgs; ++I, ++Idx) {
+    if (NumOfArgs <= Idx)
+      break;
+
+    if (isCallbackArg(getArgSVal(Idx), *I))
+      return true;
+  }
+  
+  return false;
+}
+
+/// \brief Returns true if a type is a pointer-to-const or reference-to-const
+/// with no further indirection.
+static bool isPointerToConst(QualType Ty) {
+  QualType PointeeTy = Ty->getPointeeType();
+  if (PointeeTy == QualType())
+    return false;
+  if (!PointeeTy.isConstQualified())
+    return false;
+  if (PointeeTy->isAnyPointerType())
+    return false;
+  return true;
+}
+
+// Try to retrieve the function declaration and find the function parameter
+// types which are pointers/references to a non-pointer const.
+// We do not invalidate the corresponding argument regions.
+static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs,
+                                 const CallEvent &Call) {
+  const Decl *CallDecl = Call.getDecl();
+  if (!CallDecl)
+    return;
+
+  if (Call.hasNonZeroCallbackArg())
+    return;
+
+  if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) {
+    const IdentifierInfo *II = FDecl->getIdentifier();
+
+    // List the cases, where the region should be invalidated even if the
+    // argument is const.
+    // FIXME: This is conflating invalidating /contents/ and invalidating
+    // /metadata/. Now that we pass the CallEvent to the checkers, they
+    // should probably be doing this work themselves.
+    if (II) {
+      StringRef FName = II->getName();
+      //  - 'int pthread_setspecific(ptheread_key k, const void *)' stores a
+      // value into thread local storage. The value can later be retrieved with
+      // 'void *ptheread_getspecific(pthread_key)'. So even thought the
+      // parameter is 'const void *', the region escapes through the call.
+      //  - funopen - sets a buffer for future IO calls.
+      //  - ObjC functions that end with "NoCopy" can free memory, of the passed
+      // in buffer.
+      // - Many CF containers allow objects to escape through custom
+      // allocators/deallocators upon container construction.
+      // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
+      // be deallocated by NSMapRemove.
+      // - Any call that has a callback as one of the arguments.
+      if (FName == "pthread_setspecific" ||
+          FName == "funopen" ||
+          FName.endswith("NoCopy") ||
+          (FName.startswith("NS") &&
+           (FName.find("Insert") != StringRef::npos)) ||
+          CallOrObjCMessage::isCFCGAllowingEscape(FName))
+        return;
+    }
+  }
+
+  unsigned Idx = 0;
+  for (CallEvent::param_type_iterator I = Call.param_type_begin(),
+                                       E = Call.param_type_end();
+       I != E; ++I, ++Idx) {
+    if (isPointerToConst(*I))
+      PreserveArgs.insert(Idx);
+  }
+}
+
+ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
+                                              ProgramStateRef Orig) const {
+  ProgramStateRef Result = (Orig ? Orig : State);
+
+  SmallVector<const MemRegion *, 8> RegionsToInvalidate;
+  addExtraInvalidatedRegions(RegionsToInvalidate);
+
+  // Indexes of arguments whose values will be preserved by the call.
+  llvm::SmallSet<unsigned, 1> PreserveArgs;
+  findPtrToConstParams(PreserveArgs, *this);
+
+  for (unsigned Idx = 0, Count = getNumArgs(); Idx != Count; ++Idx) {
+    if (PreserveArgs.count(Idx))
+      continue;
+
+    SVal V = getArgSVal(Idx);
+
+    // If we are passing a location wrapped as an integer, unwrap it and
+    // invalidate the values referred by the location.
+    if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V))
+      V = Wrapped->getLoc();
+    else if (!isa<Loc>(V))
+      continue;
+
+    if (const MemRegion *R = V.getAsRegion()) {
+      // Invalidate the value of the variable passed by reference.
+
+      // Are we dealing with an ElementRegion?  If the element type is
+      // a basic integer type (e.g., char, int) and the underlying region
+      // is a variable region then strip off the ElementRegion.
+      // FIXME: We really need to think about this for the general case
+      //   as sometimes we are reasoning about arrays and other times
+      //   about (char*), etc., is just a form of passing raw bytes.
+      //   e.g., void *p = alloca(); foo((char*)p);
+      if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+        // Checking for 'integral type' is probably too promiscuous, but
+        // we'll leave it in for now until we have a systematic way of
+        // handling all of these cases.  Eventually we need to come up
+        // with an interface to StoreManager so that this logic can be
+        // appropriately delegated to the respective StoreManagers while
+        // still allowing us to do checker-specific logic (e.g.,
+        // invalidating reference counts), probably via callbacks.
+        if (ER->getElementType()->isIntegralOrEnumerationType()) {
+          const MemRegion *superReg = ER->getSuperRegion();
+          if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
+              isa<ObjCIvarRegion>(superReg))
+            R = cast<TypedRegion>(superReg);
+        }
+        // FIXME: What about layers of ElementRegions?
+      }
+
+      // Mark this region for invalidation.  We batch invalidate regions
+      // below for efficiency.
+      RegionsToInvalidate.push_back(R);
+    }
+  }
+
+  // Invalidate designated regions using the batch invalidation API.
+  // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
+  //  global variables.
+  return Result->invalidateRegions(RegionsToInvalidate, getOriginExpr(),
+                                   BlockCount, LCtx, /*Symbols=*/0, this);
+}
+
+CallEvent::param_iterator AnyFunctionCall::param_begin() const {
+  const FunctionDecl *D = getDecl();
+  if (!D)
+    return 0;
+
+  return D->param_begin();
+}
+
+CallEvent::param_iterator AnyFunctionCall::param_end() const {
+  const FunctionDecl *D = getDecl();
+  if (!D)
+    return 0;
+
+  return D->param_end();
+}
+
+QualType AnyFunctionCall::getDeclaredResultType() const {
+  const FunctionDecl *D = getDecl();
+  if (!D)
+    return QualType();
+
+  return D->getResultType();
+}
+
+const FunctionDecl *SimpleCall::getDecl() const {
+  const FunctionDecl *D = CE->getDirectCallee();
+  if (D)
+    return D;
+
+  return getSVal(CE->getCallee()).getAsFunctionDecl();
+}
+
+void CXXMemberCall::addExtraInvalidatedRegions(RegionList &Regions) const {
+  const Expr *Base = getOriginExpr()->getImplicitObjectArgument();
+
+  // FIXME: Will eventually need to cope with member pointers.  This is
+  // a limitation in getImplicitObjectArgument().
+  if (!Base)
+    return;
+    
+  if (const MemRegion *R = getSVal(Base).getAsRegion())
+    Regions.push_back(R);
+}
+
+const BlockDataRegion *BlockCall::getBlockRegion() const {
+  const Expr *Callee = getOriginExpr()->getCallee();
+  const MemRegion *DataReg = getSVal(Callee).getAsRegion();
+
+  return cast<BlockDataRegion>(DataReg);
+}
+
+CallEvent::param_iterator BlockCall::param_begin() const {
+  return getBlockRegion()->getDecl()->param_begin();
+}
+
+CallEvent::param_iterator BlockCall::param_end() const {
+  return getBlockRegion()->getDecl()->param_end();
+}
+
+void BlockCall::addExtraInvalidatedRegions(RegionList &Regions) const {
+  Regions.push_back(getBlockRegion());
+}
+
+QualType BlockCall::getDeclaredResultType() const {
+  QualType BlockTy = getBlockRegion()->getCodeRegion()->getLocationType();
+  return cast<FunctionType>(BlockTy->getPointeeType())->getResultType();
+}
+
+void CXXConstructorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
+  if (Target)
+    Regions.push_back(Target);
+}
+
+CallEvent::param_iterator ObjCMessageInvocation::param_begin() const {
+  const ObjCMethodDecl *D = getDecl();
+  if (!D)
+    return 0;
+
+  return D->param_begin();
+}
+
+CallEvent::param_iterator ObjCMessageInvocation::param_end() const {
+  const ObjCMethodDecl *D = getDecl();
+  if (!D)
+    return 0;
+
+  return D->param_end();
+}
+
+void
+ObjCMessageInvocation::addExtraInvalidatedRegions(RegionList &Regions) const {
+  if (const MemRegion *R = getReceiverSVal().getAsRegion())
+    Regions.push_back(R);
+}
+
+QualType ObjCMessageInvocation::getDeclaredResultType() const {
+  const ObjCMethodDecl *D = getDecl();
+  if (!D)
+    return QualType();
+
+  return D->getResultType();
+}
+
+SVal ObjCMessageInvocation::getReceiverSVal() const {
+  // FIXME: Is this the best way to handle class receivers?
+  if (!isInstanceMessage())
+    return UnknownVal();
+    
+  const Expr *Base = Msg.getInstanceReceiver();
+  if (Base)
+    return getSVal(Base);
+
+  // An instance message with no expression means we are sending to super.
+  // In this case the object reference is the same as 'self'.
+  const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
+  assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
+  return loc::MemRegionVal(State->getRegion(SelfDecl, LCtx));
+}

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Mon Jul  2 14:27:35 2012
@@ -431,7 +431,7 @@
                             const StoreManager::InvalidatedSymbols *invalidated,
                                     ArrayRef<const MemRegion *> ExplicitRegions,
                                           ArrayRef<const MemRegion *> Regions,
-                                          const CallOrObjCMessage *Call) {
+                                          const CallEvent *Call) {
   for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
     // If any checker declares the state infeasible (or if it starts that way),
     // bail out.

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Mon Jul  2 14:27:35 2012
@@ -185,7 +185,7 @@
                             const StoreManager::InvalidatedSymbols *invalidated,
                                  ArrayRef<const MemRegion *> Explicits,
                                  ArrayRef<const MemRegion *> Regions,
-                                 const CallOrObjCMessage *Call) {
+                                 const CallEvent *Call) {
   return getCheckerManager().runCheckersForRegionChanges(state, invalidated,
                                                       Explicits, Regions, Call);
 }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Mon Jul  2 14:27:35 2012
@@ -14,7 +14,7 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/StmtCXX.h"
 
@@ -125,7 +125,9 @@
       const LocationContext *LC = Pred->getLocationContext();
       ProgramStateRef state = Pred->getState();
 
-      state = invalidateArguments(state, CallOrObjCMessage(E, state, LC), LC);
+      CXXConstructorCall Call(E, state, LC);
+      unsigned BlockCount = currentBuilderContext->getCurrentBlockCount();
+      state = Call.invalidateRegions(BlockCount);
       Bldr.generateNode(E, Pred, state);
     }
   }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Mon Jul  2 14:27:35 2012
@@ -13,7 +13,7 @@
 
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
 #include "clang/AST/DeclCXX.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/Support/SaveAndRestore.h"
@@ -307,179 +307,6 @@
   return true;
 }
 
-static bool isPointerToConst(const ParmVarDecl *ParamDecl) {
-  QualType PointeeTy = ParamDecl->getOriginalType()->getPointeeType();
-  if (PointeeTy != QualType() && PointeeTy.isConstQualified() &&
-      !PointeeTy->isAnyPointerType() && !PointeeTy->isReferenceType()) {
-    return true;
-  }
-  return false;
-}
-
-// Try to retrieve the function declaration and find the function parameter
-// types which are pointers/references to a non-pointer const.
-// We do not invalidate the corresponding argument regions.
-static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs,
-                       const CallOrObjCMessage &Call) {
-  const Decl *CallDecl = Call.getDecl();
-  if (!CallDecl)
-    return;
-
-  if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) {
-    const IdentifierInfo *II = FDecl->getIdentifier();
-
-    // List the cases, where the region should be invalidated even if the
-    // argument is const.
-    if (II) {
-      StringRef FName = II->getName();
-      //  - 'int pthread_setspecific(ptheread_key k, const void *)' stores a
-      // value into thread local storage. The value can later be retrieved with
-      // 'void *ptheread_getspecific(pthread_key)'. So even thought the
-      // parameter is 'const void *', the region escapes through the call.
-      //  - funopen - sets a buffer for future IO calls.
-      //  - ObjC functions that end with "NoCopy" can free memory, of the passed
-      // in buffer.
-      // - Many CF containers allow objects to escape through custom
-      // allocators/deallocators upon container construction.
-      // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
-      // be deallocated by NSMapRemove.
-      // - Any call that has a callback as one of the arguments.
-      if (FName == "pthread_setspecific" ||
-          FName == "funopen" ||
-          FName.endswith("NoCopy") ||
-          (FName.startswith("NS") &&
-            (FName.find("Insert") != StringRef::npos)) ||
-          Call.isCFCGAllowingEscape(FName) ||
-          Call.hasNonZeroCallbackArg())
-        return;
-    }
-
-    for (unsigned Idx = 0, E = Call.getNumArgs(); Idx != E; ++Idx) {
-      if (FDecl && Idx < FDecl->getNumParams()) {
-        if (isPointerToConst(FDecl->getParamDecl(Idx)))
-          PreserveArgs.insert(Idx);
-      }
-    }
-    return;
-  }
-
-  if (const ObjCMethodDecl *MDecl = dyn_cast<ObjCMethodDecl>(CallDecl)) {
-    assert(MDecl->param_size() <= Call.getNumArgs());
-    unsigned Idx = 0;
-
-    if (Call.hasNonZeroCallbackArg())
-      return;
-
-    for (clang::ObjCMethodDecl::param_const_iterator
-         I = MDecl->param_begin(), E = MDecl->param_end(); I != E; ++I, ++Idx) {
-      if (isPointerToConst(*I))
-        PreserveArgs.insert(Idx);
-    }
-    return;
-  }
-}
-
-ProgramStateRef 
-ExprEngine::invalidateArguments(ProgramStateRef State,
-                                const CallOrObjCMessage &Call,
-                                const LocationContext *LC) {
-  SmallVector<const MemRegion *, 8> RegionsToInvalidate;
-
-  if (Call.isObjCMessage()) {
-    // Invalidate all instance variables of the receiver of an ObjC message.
-    // FIXME: We should be able to do better with inter-procedural analysis.
-    if (const MemRegion *MR = Call.getInstanceMessageReceiver(LC).getAsRegion())
-      RegionsToInvalidate.push_back(MR);
-
-  } else if (Call.isCXXCall()) {
-    // Invalidate all instance variables for the callee of a C++ method call.
-    // FIXME: We should be able to do better with inter-procedural analysis.
-    // FIXME: We can probably do better for const versus non-const methods.
-    if (const MemRegion *Callee = Call.getCXXCallee().getAsRegion())
-      RegionsToInvalidate.push_back(Callee);
-
-  } else if (Call.isFunctionCall()) {
-    // Block calls invalidate all captured-by-reference values.
-    SVal CalleeVal = Call.getFunctionCallee();
-    if (const MemRegion *Callee = CalleeVal.getAsRegion()) {
-      if (isa<BlockDataRegion>(Callee))
-        RegionsToInvalidate.push_back(Callee);
-    }
-  }
-
-  // Indexes of arguments whose values will be preserved by the call.
-  llvm::SmallSet<unsigned, 1> PreserveArgs;
-  findPtrToConstParams(PreserveArgs, Call);
-
-  for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) {
-    if (PreserveArgs.count(idx))
-      continue;
-
-    SVal V = Call.getArgSVal(idx);
-
-    // If we are passing a location wrapped as an integer, unwrap it and
-    // invalidate the values referred by the location.
-    if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V))
-      V = Wrapped->getLoc();
-    else if (!isa<Loc>(V))
-      continue;
-
-    if (const MemRegion *R = V.getAsRegion()) {
-      // Invalidate the value of the variable passed by reference.
-
-      // Are we dealing with an ElementRegion?  If the element type is
-      // a basic integer type (e.g., char, int) and the underlying region
-      // is a variable region then strip off the ElementRegion.
-      // FIXME: We really need to think about this for the general case
-      //   as sometimes we are reasoning about arrays and other times
-      //   about (char*), etc., is just a form of passing raw bytes.
-      //   e.g., void *p = alloca(); foo((char*)p);
-      if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
-        // Checking for 'integral type' is probably too promiscuous, but
-        // we'll leave it in for now until we have a systematic way of
-        // handling all of these cases.  Eventually we need to come up
-        // with an interface to StoreManager so that this logic can be
-        // appropriately delegated to the respective StoreManagers while
-        // still allowing us to do checker-specific logic (e.g.,
-        // invalidating reference counts), probably via callbacks.
-        if (ER->getElementType()->isIntegralOrEnumerationType()) {
-          const MemRegion *superReg = ER->getSuperRegion();
-          if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
-              isa<ObjCIvarRegion>(superReg))
-            R = cast<TypedRegion>(superReg);
-        }
-        // FIXME: What about layers of ElementRegions?
-      }
-
-      // Mark this region for invalidation.  We batch invalidate regions
-      // below for efficiency.
-      RegionsToInvalidate.push_back(R);
-    } else {
-      // Nuke all other arguments passed by reference.
-      // FIXME: is this necessary or correct? This handles the non-Region
-      //  cases.  Is it ever valid to store to these?
-      State = State->unbindLoc(cast<Loc>(V));
-    }
-  }
-
-  // Invalidate designated regions using the batch invalidation API.
-
-  // FIXME: We can have collisions on the conjured symbol if the
-  //  expression *I also creates conjured symbols.  We probably want
-  //  to identify conjured symbols by an expression pair: the enclosing
-  //  expression (the context) and the expression itself.  This should
-  //  disambiguate conjured symbols.
-  unsigned Count = currentBuilderContext->getCurrentBlockCount();
-  StoreManager::InvalidatedSymbols IS;
-
-  // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
-  //  global variables.
-  return State->invalidateRegions(RegionsToInvalidate,
-                                  Call.getOriginExpr(), Count, LC,
-                                  &IS, &Call);
-
-}
-
 static ProgramStateRef getReplayWithoutInliningState(ExplodedNode *&N,
                                                      const CallExpr *CE) {
   void *ReplayState = N->getState()->get<ReplayWithoutInlining>();
@@ -524,6 +351,7 @@
       SVal L = state->getSVal(Callee, Pred->getLocationContext());
 
       // Figure out the result type. We do this dance to handle references.
+      // FIXME: This doesn't handle C++ methods, blocks, etc.
       QualType ResultTy;
       if (const FunctionDecl *FD = L.getAsFunctionDecl())
         ResultTy = FD->getResultType();
@@ -543,8 +371,16 @@
       state = state->BindExpr(CE, LCtx, RetVal);
 
       // Invalidate the arguments.
-      state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state, LCtx),
-                                      LCtx);
+      if (const CXXMemberCallExpr *MemberCE = dyn_cast<CXXMemberCallExpr>(CE)) {
+        CXXMemberCall Call(MemberCE, state, LCtx);
+        state = Call.invalidateRegions(Count);
+      } else if (isa<BlockDataRegion>(L.getAsRegion())) {
+        BlockCall Call(CE, state, LCtx);
+        state = Call.invalidateRegions(Count);
+      } else {
+        FunctionCall Call(CE, state, LCtx);
+        state = Call.invalidateRegions(Count);
+      }
 
       // And make the result node.
       Bldr.generateNode(CE, Pred, state);

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp Mon Jul  2 14:27:35 2012
@@ -13,6 +13,7 @@
 
 #include "clang/AST/StmtObjC.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
 
@@ -246,6 +247,9 @@
                                  ExplodedNode *Pred,
                                  ProgramStateRef state,
                                  bool GenSink) {
+  const LocationContext *LCtx = Pred->getLocationContext();
+  unsigned BlockCount = currentBuilderContext->getCurrentBlockCount();
+
   // First handle the return value.
   SVal ReturnValue = UnknownVal();
 
@@ -259,7 +263,7 @@
     // These methods return their receivers.
     const Expr *ReceiverE = msg.getInstanceReceiver();
     if (ReceiverE)
-      ReturnValue = state->getSVal(ReceiverE, Pred->getLocationContext());
+      ReturnValue = state->getSVal(ReceiverE, LCtx);
     break;
   }
   }
@@ -268,18 +272,17 @@
   if (ReturnValue.isUnknown()) {
     SValBuilder &SVB = getSValBuilder();
     QualType ResultTy = msg.getResultType(getContext());
-    unsigned Count = currentBuilderContext->getCurrentBlockCount();
     const Expr *CurrentE = cast<Expr>(currentStmt);
-    const LocationContext *LCtx = Pred->getLocationContext();
-    ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, LCtx, ResultTy, Count);
+    ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, LCtx, ResultTy,
+                                           BlockCount);
   }
 
   // Bind the return value.
-  const LocationContext *LCtx = Pred->getLocationContext();
   state = state->BindExpr(currentStmt, LCtx, ReturnValue);
 
   // Invalidate the arguments (and the receiver)
-  state = invalidateArguments(state, CallOrObjCMessage(msg, state, LCtx), LCtx);
+  ObjCMessageInvocation Invocation(msg, state, LCtx);
+  state = Invocation.invalidateRegions(BlockCount);
 
   // And create the new node.
   Bldr.generateNode(msg.getMessageExpr(), Pred, state, GenSink);

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ProgramState.cpp Mon Jul  2 14:27:35 2012
@@ -157,7 +157,7 @@
                                 const Expr *E, unsigned Count,
                                 const LocationContext *LCtx,
                                 StoreManager::InvalidatedSymbols *IS,
-                                const CallOrObjCMessage *Call) const {
+                                const CallEvent *Call) const {
   if (!IS) {
     StoreManager::InvalidatedSymbols invalidated;
     return invalidateRegionsImpl(Regions, E, Count, LCtx,
@@ -171,7 +171,7 @@
                                     const Expr *E, unsigned Count,
                                     const LocationContext *LCtx,
                                     StoreManager::InvalidatedSymbols &IS,
-                                    const CallOrObjCMessage *Call) const {
+                                    const CallEvent *Call) const {
   ProgramStateManager &Mgr = getStateManager();
   SubEngine* Eng = Mgr.getOwningEngine();
  

Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp?rev=159554&r1=159553&r2=159554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp Mon Jul  2 14:27:35 2012
@@ -20,7 +20,7 @@
 #include "clang/Analysis/Analyses/LiveVariables.h"
 #include "clang/Analysis/AnalysisContext.h"
 #include "clang/Basic/TargetInfo.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
@@ -252,7 +252,7 @@
                              const Expr *E, unsigned Count,
                              const LocationContext *LCtx,
                              InvalidatedSymbols &IS,
-                             const CallOrObjCMessage *Call,
+                             const CallEvent *Call,
                              InvalidatedRegions *Invalidated);
 
 public:   // Made public for helper classes.
@@ -790,7 +790,7 @@
                                                const Expr *Ex, unsigned Count,
                                                const LocationContext *LCtx,
                                                InvalidatedSymbols &IS,
-                                               const CallOrObjCMessage *Call,
+                                               const CallEvent *Call,
                                               InvalidatedRegions *Invalidated) {
   invalidateRegionsWorker W(*this, StateMgr,
                             RegionStoreManager::GetRegionBindings(store),

Added: cfe/trunk/test/Analysis/blocks-no-inline.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/blocks-no-inline.c?rev=159554&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/blocks-no-inline.c (added)
+++ cfe/trunk/test/Analysis/blocks-no-inline.c Mon Jul  2 14:27:35 2012
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=none -fblocks -verify %s
+
+void clang_analyzer_eval(int);
+
+void testInvalidation() {
+  __block int i = 0;
+  ^{
+    ++i;
+  }();
+
+  // Under inlining, we will know that i == 1.
+  clang_analyzer_eval(i == 0); // expected-warning{{UNKNOWN}}
+}





More information about the cfe-commits mailing list