[cfe-commits] r160459 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h lib/StaticAnalyzer/Core/Calls.cpp

Jordan Rose jordan_rose at apple.com
Wed Jul 18 14:59:42 PDT 2012


Author: jrose
Date: Wed Jul 18 16:59:41 2012
New Revision: 160459

URL: http://llvm.org/viewvc/llvm-project?rev=160459&view=rev
Log:
[analyzer] Make CallEvent a value object.

We will need to be able to easily reconstruct a CallEvent from an ExplodedNode
for diagnostic purposes, and that's exactly what factory functions are for.
CallEvent objects are small enough (four pointers and a SourceLocation) that
returning them through the stack is fairly cheap. Clients who just need to use
existing CallEvents can continue to do so using const references.

This uses the same sort of "kind-field-dispatch" as SVal, though most of the
nastiness is contained in the DISPATCH and DISPATCH_ARG macros at the end of
the file. (We can't use a template for this because member-pointers to base
class methods don't call derived-class methods even when casting to the
derived class. We can't use variadic macros because they're a C99 feature.)

Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
    cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp

Modified: 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=160459&r1=160458&r2=160459&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h Wed Jul 18 16:59:41 2012
@@ -22,6 +22,7 @@
 #include "clang/AST/ExprObjC.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/PointerIntPair.h"
 
 namespace clang {
 class ProgramPoint;
@@ -49,38 +50,78 @@
   CE_END_OBJC_CALLS = CE_ObjCPropertyAccess
 };
 
+
 /// \brief Represents an abstract call to a function or method along a
 /// particular path.
 class CallEvent {
 public:
   typedef CallEventKind Kind;
 
+private:
+  // PointerIntPair doesn't respect IntrusiveRefCntPtr, so we have to manually
+  // retain and release the state.
+  llvm::PointerIntPair<const ProgramState *, 2> State;
+  llvm::PointerIntPair<const LocationContext *, 2> LCtx;
+  llvm::PointerUnion<const Expr *, const Decl *> Origin;
+
 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() {}
+  // This is user data for subclasses.
+  const void *Data;
+  SourceLocation Location;
+
+  CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx,
+            Kind k)
+    : State(state.getPtr(), (k & 0x3)),
+      LCtx(lctx, ((k >> 2) & 0x3)),
+      Origin(E) {
+    IntrusiveRefCntPtrInfo<const ProgramState>::retain(getState());
+    assert(k == getKind() && "More kinds than bits in the PointerIntPairs.");
+  }
+
+  CallEvent(const Decl *D, ProgramStateRef state, const LocationContext *lctx,
+            Kind k)
+    : State(state.getPtr(), (k & 0x3)),
+      LCtx(lctx, ((k >> 2) & 0x3)),
+      Origin(D) {
+    IntrusiveRefCntPtrInfo<const ProgramState>::retain(getState());
+    assert(k == getKind() && "More kinds than bits in the PointerIntPairs.");
+  }
+
+  const ProgramState *getState() const {
+    return State.getPointer();
+  }
+
+  const LocationContext *getLocationContext() const {
+    return LCtx.getPointer();
+  }
+
+  ~CallEvent() {
+    IntrusiveRefCntPtrInfo<const ProgramState>::release(getState());
+  }
+
 
   /// \brief Get the value of arbitrary expressions at this point in the path.
   SVal getSVal(const Stmt *S) const {
-    return State->getSVal(S, LCtx);
+    return getState()->getSVal(S, getLocationContext());
   }
 
   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 {}
+  void addExtraInvalidatedRegions(RegionList &Regions) const;
 
-  virtual QualType getDeclaredResultType() const { return QualType(); }
+  QualType getDeclaredResultType() const;
 
 public:
+  /// \brief Returns the kind of call this is.
+  Kind getKind() const {
+    return static_cast<Kind>((State.getInt()) | (LCtx.getInt() << 2));
+  }
+
   /// \brief Returns the declaration of the function or method that will be
   /// called. May be null.
-  virtual const Decl *getDecl() const = 0;
+  const Decl *getDecl() const;
 
   /// \brief Returns the definition of the function or method that will be
   /// called. May be null.
@@ -91,21 +132,20 @@
   ///   definition that is actually invoked at runtime. Note that if we have
   ///   sufficient type information to devirtualize a dynamic method call,
   ///   we will (and \p IsDynamicDispatch will be set to \c false).
-  virtual const Decl *getDefinition(bool &IsDynamicDispatch) const {
-    IsDynamicDispatch = false;
-    return getDecl();
-  }
+  const Decl *getDefinition(bool &IsDynamicDispatch) const;
 
   /// \brief Returns the expression whose value will be the result of this call.
   /// May be null.
-  virtual const Expr *getOriginExpr() const = 0;
+  const Expr *getOriginExpr() const {
+    return Origin.dyn_cast<const Expr *>();
+  }
 
   /// \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;
+  unsigned getNumArgs() const;
 
   /// \brief Returns true if the callee is known to be from a system header.
   bool isInSystemHeader() const {
@@ -116,7 +156,7 @@
     SourceLocation Loc = D->getLocation();
     if (Loc.isValid()) {
       const SourceManager &SM =
-        State->getStateManager().getContext().getSourceManager();
+        getState()->getStateManager().getContext().getSourceManager();
       return SM.isInSystemHeader(D->getLocation());
     }
 
@@ -128,34 +168,29 @@
     return false;
   }
 
-  /// \brief Returns the kind of call this is.
-  Kind getKind() const { return K; }
-
   /// \brief Returns a source range for the entire call, suitable for
   /// outputting in diagnostics.
-  virtual SourceRange getSourceRange() const = 0;
+  SourceRange getSourceRange() const;
 
   /// \brief Returns the value of a given argument at the time of the call.
-  virtual SVal getArgSVal(unsigned Index) const;
+  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;
-  }
+  const Expr *getArgExpr(unsigned Index) const;
 
   /// \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;
+  SourceRange getArgSourceRange(unsigned Index) const;
 
   /// \brief Returns the result type, adjusted for references.
   QualType getResultType() const;
 
   /// \brief Returns the value of the implicit 'this' object, or UndefinedVal if
   /// this is not a C++ member function call.
-  virtual SVal getCXXThisVal() const { return UndefinedVal(); }
+  SVal getCXXThisVal() const;
 
   /// \brief Returns true if any of the arguments appear to represent callbacks.
   bool hasNonZeroCallbackArg() const;
@@ -165,9 +200,7 @@
   // NOTE: The exact semantics of this are still being defined!
   // We don't really want a list of hardcoded exceptions in the long run,
   // but we don't want duplicated lists of known APIs in the short term either.
-  virtual bool argumentsMayEscape() const {
-    return hasNonZeroCallbackArg();
-  }
+  bool argumentsMayEscape() const;
 
   /// \brief Returns an appropriate ProgramPoint for this call.
   ProgramPoint getProgramPoint(bool IsPreVisit = false,
@@ -205,9 +238,9 @@
   /// If the call has no accessible declaration (or definition, if
   /// \p UseDefinitionParams is set), \c param_begin() will be equal to
   /// \c param_end().
-  virtual param_iterator param_begin(bool UseDefinitionParams = false) const = 0;
+  param_iterator param_begin(bool UseDefinitionParams = false) const;
   /// \sa param_begin()
-  virtual param_iterator param_end(bool UseDefinitionParams = false) const = 0;
+  param_iterator param_end(bool UseDefinitionParams = false) const;
 
   typedef llvm::mapped_iterator<param_iterator, get_type_fun>
     param_type_iterator;
@@ -227,26 +260,37 @@
   }
 
   // For debugging purposes only
-  virtual void dump(raw_ostream &Out) const;
+  void dump(raw_ostream &Out) const;
   LLVM_ATTRIBUTE_USED void dump() const { dump(llvm::errs()); }
 
   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 {
+  friend class CallEvent;
+
 protected:
-  AnyFunctionCall(ProgramStateRef St, const LocationContext *LCtx, Kind K)
-    : CallEvent(St, LCtx, K) {}
+  AnyFunctionCall(const Expr *E, ProgramStateRef St,
+                  const LocationContext *LCtx, Kind K)
+    : CallEvent(E, St, LCtx, K) {}
+  AnyFunctionCall(const Decl *D, ProgramStateRef St,
+                  const LocationContext *LCtx, Kind K)
+    : CallEvent(D, St, LCtx, K) {}
 
-  param_iterator param_begin(bool UseDefinitionParams = false) const;
-  param_iterator param_end(bool UseDefinitionParams = false) const;
+  // Most function calls have no extra invalidated regions.
+  void addExtraInvalidatedRegions(RegionList &Regions) const {}
 
   QualType getDeclaredResultType() const;
 
 public:
-  virtual const FunctionDecl *getDecl() const = 0;
+  // This function is overridden by subclasses, but they must return
+  // a FunctionDecl.
+  const FunctionDecl *getDecl() const {
+    return cast_or_null<FunctionDecl>(CallEvent::getDecl());
+  }
 
   const Decl *getDefinition(bool &IsDynamicDispatch) const {
     IsDynamicDispatch = false;
@@ -259,6 +303,12 @@
 
   bool argumentsMayEscape() const;
 
+  SVal getArgSVal(unsigned Index) const;
+  SourceRange getArgSourceRange(unsigned Index) const;
+
+  param_iterator param_begin(bool UseDefinitionParams = false) const;
+  param_iterator param_end(bool UseDefinitionParams = false) const;
+
   static bool classof(const CallEvent *CA) {
     return CA->getKind() >= CE_BEG_FUNCTION_CALLS &&
            CA->getKind() <= CE_END_FUNCTION_CALLS;
@@ -267,24 +317,26 @@
 
 /// \brief Represents a call to a written as a CallExpr.
 class SimpleCall : public AnyFunctionCall {
-  const CallExpr *CE;
-
 protected:
-  SimpleCall(const CallExpr *ce, ProgramStateRef St,
+  SimpleCall(const CallExpr *CE, ProgramStateRef St,
              const LocationContext *LCtx, Kind K)
-    : AnyFunctionCall(St, LCtx, K), CE(ce) {
+    : AnyFunctionCall(CE, St, LCtx, K) {
   }
 
 public:
-  const CallExpr *getOriginExpr() const { return CE; }
+  const CallExpr *getOriginExpr() const {
+    return cast<CallExpr>(AnyFunctionCall::getOriginExpr());
+  }
 
   const FunctionDecl *getDecl() const;
 
-  unsigned getNumArgs() const { return CE->getNumArgs(); }
-  SourceRange getSourceRange() const { return CE->getSourceRange(); }
+  unsigned getNumArgs() const { return getOriginExpr()->getNumArgs(); }
+  SourceRange getSourceRange() const {
+    return getOriginExpr()->getSourceRange();
+  }
   
   const Expr *getArgExpr(unsigned Index) const {
-    return CE->getArg(Index);
+    return getOriginExpr()->getArg(Index);
   }
 
   static bool classof(const CallEvent *CA) {
@@ -302,6 +354,8 @@
                const LocationContext *LCtx)
     : SimpleCall(CE, St, LCtx, CE_Function) {}
 
+  SVal getCXXThisVal() const { return UndefinedVal(); }
+
   static bool classof(const CallEvent *CA) {
     return CA->getKind() == CE_Function;
   }
@@ -310,6 +364,8 @@
 /// \brief Represents a non-static C++ member function call, no matter how
 /// it is written.
 class CXXInstanceCall : public SimpleCall {
+  friend class CallEvent;
+
 protected:
   void addExtraInvalidatedRegions(RegionList &Regions) const;
 
@@ -318,8 +374,6 @@
     : SimpleCall(CE, St, LCtx, K) {}
 
 public:
-  SVal getCXXThisVal() const = 0;
-
   const Decl *getDefinition(bool &IsDynamicDispatch) const;
 
   static bool classof(const CallEvent *CA) {
@@ -378,12 +432,11 @@
 ///
 /// Example: <tt>^{ /* ... */ }()</tt>
 class BlockCall : public SimpleCall {
+  friend class CallEvent;
+
 protected:
   void addExtraInvalidatedRegions(RegionList &Regions) const;
 
-  param_iterator param_begin(bool UseDefinitionParams = false) const;
-  param_iterator param_end(bool UseDefinitionParams = false) const;
-
   QualType getDeclaredResultType() const;
 
 public:
@@ -412,6 +465,11 @@
     return getBlockDecl();
   }
 
+  param_iterator param_begin(bool UseDefinitionParams = false) const;
+  param_iterator param_end(bool UseDefinitionParams = false) const;
+
+  SVal getCXXThisVal() const { return UndefinedVal(); }
+
   static bool classof(const CallEvent *CA) {
     return CA->getKind() == CE_Block;
   }
@@ -421,31 +479,42 @@
 ///
 /// Example: \c T(1)
 class CXXConstructorCall : public AnyFunctionCall {
-  const CXXConstructExpr *CE;
-  const MemRegion *Target;
+  friend class CallEvent;
 
 protected:
   void addExtraInvalidatedRegions(RegionList &Regions) const;
 
 public:
-  CXXConstructorCall(const CXXConstructExpr *ce, ProgramStateRef St,
+  /// Represents a constructor call to a new or unknown region.
+  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,
+    : AnyFunctionCall(CE, St, LCtx, CE_CXXConstructor) {
+    Data = 0;
+  }
+
+  /// Represents a constructor call on an existing object region.
+  CXXConstructorCall(const CXXConstructExpr *CE, const MemRegion *target,
                      ProgramStateRef St, const LocationContext *LCtx)
-    : AnyFunctionCall(St, LCtx, CE_CXXConstructor), CE(ce), Target(target) {}
+    : AnyFunctionCall(CE, St, LCtx, CE_CXXConstructor) {
+    Data = target;
+  }
 
-  const CXXConstructExpr *getOriginExpr() const { return CE; }
-  SourceRange getSourceRange() const { return CE->getSourceRange(); }
+  const CXXConstructExpr *getOriginExpr() const {
+    return cast<CXXConstructExpr>(AnyFunctionCall::getOriginExpr());
+  }
+
+  SourceRange getSourceRange() const {
+    return getOriginExpr()->getSourceRange();
+  }
 
   const CXXConstructorDecl *getDecl() const {
-    return CE->getConstructor();
+    return getOriginExpr()->getConstructor();
   }
 
-  unsigned getNumArgs() const { return CE->getNumArgs(); }
+  unsigned getNumArgs() const { return getOriginExpr()->getNumArgs(); }
 
   const Expr *getArgExpr(unsigned Index) const {
-    return CE->getArg(Index);
+    return getOriginExpr()->getArg(Index);
   }
 
   SVal getCXXThisVal() const;
@@ -460,24 +529,28 @@
 /// This can occur at the end of a scope (for automatic objects), at the end
 /// of a full-expression (for temporaries), or as part of a delete.
 class CXXDestructorCall : public AnyFunctionCall {
-  const CXXDestructorDecl *DD;
-  const MemRegion *Target;
-  SourceLocation Loc;
+  friend class CallEvent;
 
 protected:
   void addExtraInvalidatedRegions(RegionList &Regions) const;
 
 public:
-  CXXDestructorCall(const CXXDestructorDecl *dd, const Stmt *Trigger,
-                    const MemRegion *target, ProgramStateRef St,
+  /// Creates an implicit destructor.
+  ///
+  /// \param DD The destructor that will be called.
+  /// \param Trigger The statement whose completion causes this destructor call.
+  /// \param Target The object region to be destructed.
+  /// \param St The path-sensitive state at this point in the program.
+  /// \param LCtx The location context at this point in the program.
+  CXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
+                    const MemRegion *Target, ProgramStateRef St,
                     const LocationContext *LCtx)
-    : AnyFunctionCall(St, LCtx, CE_CXXDestructor), DD(dd), Target(target),
-      Loc(Trigger->getLocEnd()) {}
-
-  const Expr *getOriginExpr() const { return 0; }
-  SourceRange getSourceRange() const { return Loc; }
+    : AnyFunctionCall(DD, St, LCtx, CE_CXXDestructor) {
+    Data = Target;
+    Location = Trigger->getLocEnd();
+  }
 
-  const CXXDestructorDecl *getDecl() const { return DD; }
+  SourceRange getSourceRange() const { return Location; }
   unsigned getNumArgs() const { return 0; }
 
   SVal getCXXThisVal() const;
@@ -492,29 +565,37 @@
 ///
 /// This is a call to "operator new".
 class CXXAllocatorCall : public AnyFunctionCall {
-  const CXXNewExpr *E;
-
 public:
-  CXXAllocatorCall(const CXXNewExpr *e, ProgramStateRef St,
+  CXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef St,
                    const LocationContext *LCtx)
-    : AnyFunctionCall(St, LCtx, CE_CXXAllocator), E(e) {}
+    : AnyFunctionCall(E, St, LCtx, CE_CXXAllocator) {}
 
-  const CXXNewExpr *getOriginExpr() const { return E; }
-  SourceRange getSourceRange() const { return E->getSourceRange(); }
+  const CXXNewExpr *getOriginExpr() const {
+    return cast<CXXNewExpr>(AnyFunctionCall::getOriginExpr());
+  }
+
+  // FIXME: This isn't exactly the range of the allocator...
+  SourceRange getSourceRange() const {
+    return getOriginExpr()->getSourceRange();
+  }
 
   const FunctionDecl *getDecl() const {
-    return E->getOperatorNew();
+    return getOriginExpr()->getOperatorNew();
   }
 
-  unsigned getNumArgs() const { return E->getNumPlacementArgs() + 1; }
+  unsigned getNumArgs() const {
+    return getOriginExpr()->getNumPlacementArgs() + 1;
+  }
 
   const Expr *getArgExpr(unsigned Index) const {
     // The first argument of an allocator call is the size of the allocation.
     if (Index == 0)
       return 0;
-    return E->getPlacementArg(Index - 1);
+    return getOriginExpr()->getPlacementArg(Index - 1);
   }
 
+  SVal getCXXThisVal() const { return UndefinedVal(); }
+
   static bool classof(const CallEvent *CE) {
     return CE->getKind() == CE_CXXAllocator;
   }
@@ -522,33 +603,45 @@
 
 /// \brief Represents any expression that calls an Objective-C method.
 class ObjCMethodCall : public CallEvent {
-  const ObjCMessageExpr *Msg;
+  friend class CallEvent;
 
 protected:
-  ObjCMethodCall(const ObjCMessageExpr *msg, ProgramStateRef St,
+  ObjCMethodCall(const ObjCMessageExpr *Msg, ProgramStateRef St,
                  const LocationContext *LCtx, Kind K)
-    : CallEvent(St, LCtx, K), Msg(msg) {}
+    : CallEvent(Msg, St, LCtx, K) {}
 
   void addExtraInvalidatedRegions(RegionList &Regions) const;
 
-  param_iterator param_begin(bool UseDefinitionParams = false) const;
-  param_iterator param_end(bool UseDefinitionParams = false) const;
-
   QualType getDeclaredResultType() const;
 
 public:
-  Selector getSelector() const { return Msg->getSelector(); }
-  bool isInstanceMessage() const { return Msg->isInstanceMessage(); }
-  ObjCMethodFamily getMethodFamily() const { return Msg->getMethodFamily(); }
-
-  const ObjCMethodDecl *getDecl() const { return Msg->getMethodDecl(); }
-  SourceRange getSourceRange() const { return Msg->getSourceRange(); }
-  unsigned getNumArgs() const { return Msg->getNumArgs(); }
-  const Expr *getArgExpr(unsigned Index) const {
-    return Msg->getArg(Index);
+  const ObjCMessageExpr *getOriginExpr() const {
+    return cast<ObjCMessageExpr>(CallEvent::getOriginExpr());
+  }
+
+  Selector getSelector() const {
+    return getOriginExpr()->getSelector();
+  }
+  bool isInstanceMessage() const {
+    return getOriginExpr()->isInstanceMessage();
+  }
+  ObjCMethodFamily getMethodFamily() const {
+    return getOriginExpr()->getMethodFamily();
   }
 
-  const ObjCMessageExpr *getOriginExpr() const { return Msg; }
+  const ObjCMethodDecl *getDecl() const {
+    return getOriginExpr()->getMethodDecl();
+  }
+
+  SourceRange getSourceRange() const {
+    return getOriginExpr()->getSourceRange();
+  }
+  unsigned getNumArgs() const {
+    return getOriginExpr()->getNumArgs();
+  }
+  const Expr *getArgExpr(unsigned Index) const {
+    return getOriginExpr()->getArg(Index);
+  }
 
   /// \brief Returns the value of the receiver at the time of this call.
   SVal getReceiverSVal() const;
@@ -559,7 +652,7 @@
   /// Returns NULL otherwise.
   /// \sa ObjCMessageExpr::getInstanceReceiver()
   const Expr *getInstanceReceiverExpr() const {
-    return Msg->getInstanceReceiver();
+    return getOriginExpr()->getInstanceReceiver();
   }
 
   /// \brief Get the interface for the receiver.
@@ -567,11 +660,11 @@
   /// This works whether this is an instance message or a class message.
   /// However, it currently just uses the static type of the receiver.
   const ObjCInterfaceDecl *getReceiverInterface() const {
-    return Msg->getReceiverInterface();
+    return getOriginExpr()->getReceiverInterface();
   }
 
   SourceRange getReceiverSourceRange() const {
-    return Msg->getReceiverRange();
+    return getOriginExpr()->getReceiverRange();
   }
 
   const Decl *getDefinition(bool &IsDynamicDispatch) const {
@@ -586,6 +679,21 @@
     return 0;
   }
 
+  SVal getCXXThisVal() const { return UndefinedVal(); }
+
+  bool argumentsMayEscape() const {
+    return hasNonZeroCallbackArg();
+  }
+  
+  SVal getArgSVal(unsigned Index) const { return getSVal(getArgExpr(Index)); }
+  SourceRange getArgSourceRange(unsigned Index) const {
+    return getArgExpr(Index)->getSourceRange();
+  }
+
+
+  param_iterator param_begin(bool UseDefinitionParams = false) const;
+  param_iterator param_end(bool UseDefinitionParams = false) const;
+
   static bool classof(const CallEvent *CA) {
     return CA->getKind() >= CE_BEG_OBJC_CALLS &&
            CA->getKind() <= CE_END_OBJC_CALLS;
@@ -610,32 +718,27 @@
 ///
 /// Example: obj.prop += 1;
 class ObjCPropertyAccess : public ObjCMethodCall {
-  const ObjCPropertyRefExpr *PropE;
-  SourceRange EntireRange;
-
 public:
-  ObjCPropertyAccess(const ObjCPropertyRefExpr *pe, SourceRange range,
+  ObjCPropertyAccess(const ObjCPropertyRefExpr *PE, SourceRange range,
                      const ObjCMessageExpr *Msg, const ProgramStateRef St,
                      const LocationContext *LCtx)
-    : ObjCMethodCall(Msg, St, LCtx, CE_ObjCPropertyAccess), PropE(pe),
-      EntireRange(range)
-    {}
+    : ObjCMethodCall(Msg, St, LCtx, CE_ObjCPropertyAccess) {
+    Data = PE;
+  }
 
   /// \brief Returns true if this property access is calling the setter method.
   bool isSetter() const {
     return getNumArgs() > 0;
   }
 
-  SourceRange getSourceRange() const {
-    return EntireRange;
-  }
+  SourceRange getSourceRange() const;
 
   /// \brief Return the property reference part of this access.
   ///
   /// In the expression "obj.prop += 1", the property reference expression is
   /// "obj.prop".
   const ObjCPropertyRefExpr *getPropertyExpr() const {
-    return PropE;
+    return static_cast<const ObjCPropertyRefExpr *>(Data);
   }
 
   static bool classof(const CallEvent *CA) {
@@ -643,6 +746,112 @@
   }
 };
 
+
+// FIXME: Use a .def or .td file for this.
+#define DISPATCH(fn) \
+  switch (getKind()) { \
+  case CE_Function: \
+    return cast<FunctionCall>(this)->fn(); \
+  case CE_CXXMember: \
+    return cast<CXXMemberCall>(this)->fn(); \
+  case CE_CXXMemberOperator: \
+    return cast<CXXMemberOperatorCall>(this)->fn(); \
+  case CE_Block: \
+    return cast<BlockCall>(this)->fn(); \
+  case CE_CXXConstructor: \
+    return cast<CXXConstructorCall>(this)->fn(); \
+  case CE_CXXDestructor: \
+    return cast<CXXDestructorCall>(this)->fn(); \
+  case CE_CXXAllocator: \
+    return cast<CXXAllocatorCall>(this)->fn(); \
+  case CE_ObjCMessage: \
+    return cast<ObjCMessageSend>(this)->fn(); \
+  case CE_ObjCPropertyAccess: \
+    return cast<ObjCPropertyAccess>(this)->fn(); \
+  }
+
+#define DISPATCH_ARG(fn, arg) \
+  switch (getKind()) { \
+  case CE_Function: \
+    return cast<FunctionCall>(this)->fn(arg); \
+  case CE_CXXMember: \
+    return cast<CXXMemberCall>(this)->fn(arg); \
+  case CE_CXXMemberOperator: \
+    return cast<CXXMemberOperatorCall>(this)->fn(arg); \
+  case CE_Block: \
+    return cast<BlockCall>(this)->fn(arg); \
+  case CE_CXXConstructor: \
+    return cast<CXXConstructorCall>(this)->fn(arg); \
+  case CE_CXXDestructor: \
+    return cast<CXXDestructorCall>(this)->fn(arg); \
+  case CE_CXXAllocator: \
+    return cast<CXXAllocatorCall>(this)->fn(arg); \
+  case CE_ObjCMessage: \
+    return cast<ObjCMessageSend>(this)->fn(arg); \
+  case CE_ObjCPropertyAccess: \
+    return cast<ObjCPropertyAccess>(this)->fn(arg); \
+  }
+
+inline void CallEvent::addExtraInvalidatedRegions(RegionList &Regions) const {
+  DISPATCH_ARG(addExtraInvalidatedRegions, Regions);
+}
+
+inline QualType CallEvent::getDeclaredResultType() const {
+  DISPATCH(getDeclaredResultType);
+}
+
+inline const Decl *CallEvent::getDecl() const {
+  if (const Decl *D = Origin.dyn_cast<const Decl *>())
+    return D;
+  DISPATCH(getDecl);
+}
+
+inline const Decl *CallEvent::getDefinition(bool &IsDynamicDispatch) const {
+  DISPATCH_ARG(getDefinition, IsDynamicDispatch);
+}
+
+inline unsigned CallEvent::getNumArgs() const {
+  DISPATCH(getNumArgs);
+}
+
+inline SourceRange CallEvent::getSourceRange() const {
+  DISPATCH(getSourceRange);
+}
+
+inline SVal CallEvent::getArgSVal(unsigned Index) const {
+  DISPATCH_ARG(getArgSVal, Index);
+}
+
+inline const Expr *CallEvent::getArgExpr(unsigned Index) const {
+  DISPATCH_ARG(getArgExpr, Index);
+}
+
+inline SourceRange CallEvent::getArgSourceRange(unsigned Index) const {
+  DISPATCH_ARG(getArgSourceRange, Index);
+}
+
+inline SVal CallEvent::getCXXThisVal() const {
+  DISPATCH(getCXXThisVal);
+}
+
+
+inline bool CallEvent::argumentsMayEscape() const {
+  DISPATCH(argumentsMayEscape);
+}
+
+inline CallEvent::param_iterator
+CallEvent::param_begin(bool UseDefinitionParams) const {
+  DISPATCH_ARG(param_begin, UseDefinitionParams);
+}
+
+inline CallEvent::param_iterator
+CallEvent::param_end(bool UseDefinitionParams) const {
+  DISPATCH_ARG(param_end, UseDefinitionParams);
+}
+
+#undef DISPATCH
+#undef DISPATCH_ARG
+
 } // end namespace ento
 } // end namespace clang
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp?rev=160459&r1=160458&r2=160459&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp Wed Jul 18 16:59:41 2012
@@ -15,26 +15,13 @@
 
 #include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
 #include "clang/Analysis/ProgramPoint.h"
+#include "clang/AST/ParentMap.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/StringExtras.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();
 
@@ -125,7 +112,7 @@
 
 ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
                                               ProgramStateRef Orig) const {
-  ProgramStateRef Result = (Orig ? Orig : State);
+  ProgramStateRef Result = (Orig ? Orig : getState());
 
   SmallVector<const MemRegion *, 8> RegionsToInvalidate;
   addExtraInvalidatedRegions(RegionsToInvalidate);
@@ -185,15 +172,16 @@
   // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
   //  global variables.
   return Result->invalidateRegions(RegionsToInvalidate, getOriginExpr(),
-                                   BlockCount, LCtx, /*Symbols=*/0, this);
+                                   BlockCount, getLocationContext(),
+                                   /*Symbols=*/0, this);
 }
 
 ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
                                         const ProgramPointTag *Tag) const {
   if (const Expr *E = getOriginExpr()) {
     if (IsPreVisit)
-      return PreStmt(E, LCtx, Tag);
-    return PostStmt(E, LCtx, Tag);
+      return PreStmt(E, getLocationContext(), Tag);
+    return PostStmt(E, getLocationContext(), Tag);
   }
 
   const Decl *D = getDecl();
@@ -201,8 +189,8 @@
 
   SourceLocation Loc = getSourceRange().getBegin();
   if (IsPreVisit)
-    return PreImplicitCall(D, Loc, LCtx, Tag);
-  return PostImplicitCall(D, Loc, LCtx, Tag);
+    return PreImplicitCall(D, Loc, getLocationContext(), Tag);
+  return PostImplicitCall(D, Loc, getLocationContext(), Tag);
 }
 
 
@@ -242,7 +230,7 @@
 }
 
 bool AnyFunctionCall::argumentsMayEscape() const {
-  if (CallEvent::argumentsMayEscape())
+  if (hasNonZeroCallbackArg())
     return true;
 
   const FunctionDecl *D = getDecl();
@@ -297,17 +285,31 @@
   return false;
 }
 
+SVal AnyFunctionCall::getArgSVal(unsigned Index) const {
+  const Expr *ArgE = getArgExpr(Index);
+  if (!ArgE)
+    return UnknownVal();
+  return getSVal(ArgE);
+}
+
+SourceRange AnyFunctionCall::getArgSourceRange(unsigned Index) const {
+  const Expr *ArgE = getArgExpr(Index);
+  if (!ArgE)
+    return SourceRange();
+  return ArgE->getSourceRange();
+}
+
 
 const FunctionDecl *SimpleCall::getDecl() const {
-  const FunctionDecl *D = CE->getDirectCallee();
+  const FunctionDecl *D = getOriginExpr()->getDirectCallee();
   if (D)
     return D;
 
-  return getSVal(CE->getCallee()).getAsFunctionDecl();
+  return getSVal(getOriginExpr()->getCallee()).getAsFunctionDecl();
 }
 
 void CallEvent::dump(raw_ostream &Out) const {
-  ASTContext &Ctx = State->getStateManager().getContext();
+  ASTContext &Ctx = getState()->getStateManager().getContext();
   if (const Expr *E = getOriginExpr()) {
     E->printPretty(Out, Ctx, 0, Ctx.getLangOpts());
     Out << "\n";
@@ -343,10 +345,6 @@
   if (!RD)
     return 0;
 
-  RD = RD->getDefinition();
-  if (!RD)
-    return 0;
-
   const CXXMethodDecl *Result = MD->getCorrespondingMethodInClass(RD);
   const FunctionDecl *Definition;
   if (!Result->hasBody(Definition))
@@ -438,26 +436,26 @@
 
 
 SVal CXXConstructorCall::getCXXThisVal() const {
-  if (Target)
-    return loc::MemRegionVal(Target);
+  if (Data)
+    return loc::MemRegionVal(static_cast<const MemRegion *>(Data));
   return UnknownVal();
 }
 
 void CXXConstructorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
-  if (Target)
-    Regions.push_back(Target);
+  if (Data)
+    Regions.push_back(static_cast<const MemRegion *>(Data));
 }
 
 
 SVal CXXDestructorCall::getCXXThisVal() const {
-  if (Target)
-    return loc::MemRegionVal(Target);
+  if (Data)
+    return loc::MemRegionVal(static_cast<const MemRegion *>(Data));
   return UnknownVal();
 }
 
 void CXXDestructorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
-  if (Target)
-    Regions.push_back(Target);
+  if (Data)
+    Regions.push_back(static_cast<const MemRegion *>(Data));
 }
 
 const Decl *CXXDestructorCall::getDefinition(bool &IsDynamicDispatch) const {
@@ -520,14 +518,21 @@
   if (!isInstanceMessage())
     return UnknownVal();
     
-  const Expr *Base = Msg->getInstanceReceiver();
-  if (Base)
+  if (const Expr *Base = getInstanceReceiverExpr())
     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 LocationContext *LCtx = getLocationContext();
   const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
   assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
-  return State->getSVal(State->getRegion(SelfDecl, LCtx));
+  return getState()->getSVal(getState()->getRegion(SelfDecl, LCtx));
+}
+
+SourceRange ObjCPropertyAccess::getSourceRange() const {
+  const ParentMap &PM = getLocationContext()->getParentMap();
+  const ObjCMessageExpr *ME = getOriginExpr();
+  const PseudoObjectExpr *PO = cast<PseudoObjectExpr>(PM.getParent(ME));
+  return PO->getSourceRange();
 }
 





More information about the cfe-commits mailing list