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

Anna Zaks ganna at apple.com
Mon Jul 16 13:20:12 PDT 2012


Jordan,

Here are the much delayed comments for the new CallEvent hierarchy. Based on TOT as of today (r160287).

1. CXXDestructorCall needs comments for the constructor arguments.

2. ObjCMethodCall contains a bunch of getters which are just wrappers around the ObjCMethodExpr. Why not just provide the getter to the Expr? That would result in less code and less maintenance. (I guess, some of them were written assuming that we might track the actual message receiver in the future..)

3. Most of the current users don't differentiate between ObjCPropertyAccess and ObjCMessageSend. However, each time we construct an object, we make effort to determine if it's a property access. It looks like all the info to determine if it's a property access is accessible from CallEvent, so can we lazily differentiate between them? (The only user that does care CallAndMessageChecker uses the info to determine error message when error occurs; it would make sense to only do the check after we actually find the bug, not on each call.)

4. Calls.h -> CallEvent.h
I find it convenient when the file name matches the class/class hierarchy name.

5. Rename the following to reflect that it returns regions (no a setter):
  virtual void addExtraInvalidatedRegions(RegionList &Regions) const {}

6. Why getDefinition() implementation defaults to getDecl() instead of being pure abstract?
  virtual const Decl *getDefinition(bool &IsDynamicDispatch) const {
    IsDynamicDispatch = false;
    return getDecl();
  }

7. Why do we need C++- specific getCXXThisVal() in CallEvent?

8. What is the difference between getResultType() and getDeclaredResultType()? Would be good to find out why thi sis needed:// FIXME: This is copied from CallOrObjCMessage, but it seems suspicious.
    if (E->isGLValue()) {
      ASTContext &Ctx = State->getStateManager().getContext();
      ResultTy = Ctx.getPointerType(ResultTy);

9. It might be cleaner to keep the program point construction API inside ProgramPoint instead of CallEvent::getProgramPoint.

10. Should some of the code in ExprEngine::shouldInlineDecl migrate to CallEvent::mayBeInlined()?

Looks good overall!
Anna.
On Jul 2, 2012, at 12:27 PM, Jordan Rose wrote:

> 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}}
> +}
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20120716/5b80c495/attachment.html>


More information about the cfe-commits mailing list