]> granicus.if.org Git - clang/commitdiff
[analyzer] Introduce ObjCMessage which represents both explicit ObjC message expressi...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 25 Jan 2011 00:03:53 +0000 (00:03 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 25 Jan 2011 00:03:53 +0000 (00:03 +0000)
messages that are sent for handling properties in dot syntax.

Replace all direct uses of ObjCMessageExpr in the checkers and checker interface with ObjCMessage.

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

13 files changed:
include/clang/StaticAnalyzer/PathSensitive/Checker.h
include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def
include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h
include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h
lib/StaticAnalyzer/CFRefCount.cpp
lib/StaticAnalyzer/CMakeLists.txt
lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
lib/StaticAnalyzer/Checkers/ExprEngine.cpp
lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
lib/StaticAnalyzer/ObjCMessage.cpp [new file with mode: 0644]

index f363fcc852573c369367ced9fbfa1198c4923f4e..a009932ca3696c602a4d297616539b0871759844 100644 (file)
@@ -203,12 +203,26 @@ private:
       _PostVisit(C, S);
   }
 
+  void GR_visitObjCMessage(ExplodedNodeSet &Dst,
+                           StmtNodeBuilder &Builder,
+                           ExprEngine &Eng,
+                           const ObjCMessage &msg,
+                           ExplodedNode *Pred, void *tag, bool isPrevisit) {
+    CheckerContext C(Dst, Builder, Eng, Pred, tag,
+                     isPrevisit ? ProgramPoint::PreStmtKind :
+                     ProgramPoint::PostStmtKind, 0, msg.getOriginExpr());
+    if (isPrevisit)
+      preVisitObjCMessage(C, msg);
+    else
+      postVisitObjCMessage(C, msg);
+  }
+
   bool GR_evalNilReceiver(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
-                          ExprEngine &Eng, const ObjCMessageExpr *ME,
+                          ExprEngine &Eng, const ObjCMessage &msg,
                           ExplodedNode *Pred, const GRState *state, void *tag) {
     CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
-                     0, ME, state);
-    return evalNilReceiver(C, ME);
+                     0, msg.getOriginExpr(), state);
+    return evalNilReceiver(C, msg);
   }
 
   bool GR_evalCallExpr(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
@@ -258,6 +272,8 @@ public:
   virtual ~Checker();
   virtual void _PreVisit(CheckerContext &C, const Stmt *S) {}
   virtual void _PostVisit(CheckerContext &C, const Stmt *S) {}
+  virtual void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg) {}
+  virtual void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg) {}
   virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location,
                              bool isLoad) {}
   virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
@@ -272,7 +288,7 @@ public:
                                     ExprEngine &Eng,
                                     const Stmt *Condition, void *tag) {}
 
-  virtual bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) {
+  virtual bool evalNilReceiver(CheckerContext &C, ObjCMessage msg) {
     return false;
   }
 
index 840aaa76fd7e9c43eb5f172466089ce0eedd2633..9b3c263e7d53b398f3a11251a3fb72ef31360358 100644 (file)
@@ -34,7 +34,6 @@ PREVISIT(CXXStaticCastExpr, CastExpr)
 PREVISIT(DeclStmt, Stmt)
 PREVISIT(ImplicitCastExpr, CastExpr)
 PREVISIT(ObjCAtSynchronizedStmt, Stmt)
-PREVISIT(ObjCMessageExpr, Stmt)
 PREVISIT(ReturnStmt, Stmt)
 
 POSTVISIT(BlockExpr, Stmt)
@@ -43,7 +42,6 @@ POSTVISIT(CallExpr, GenericCall)
 POSTVISIT(CompoundAssignOperator, BinaryOperator)
 POSTVISIT(CXXOperatorCallExpr, GenericCall)
 POSTVISIT(CXXMemberCallExpr, GenericCall)
-POSTVISIT(ObjCMessageExpr, Stmt)
 POSTVISIT(ObjCIvarRefExpr, Stmt)
 
 #undef PREVISIT
index 747c8ebb2a3b9e3ea10086dd9bbbc3e68b3616ba..5617bf1c3b4e4870971e808552dc0ef500ad8d99 100644 (file)
@@ -282,11 +282,14 @@ public:
   void CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, 
                     CallbackKind Kind);
 
+  void CheckerVisitObjCMessage(const ObjCMessage &msg, ExplodedNodeSet &Dst,
+                               ExplodedNodeSet &Src, bool isPrevisit);
+
   bool CheckerEvalCall(const CallExpr *CE, 
                        ExplodedNodeSet &Dst, 
                        ExplodedNode *Pred);
 
-  void CheckerEvalNilReceiver(const ObjCMessageExpr *ME, 
+  void CheckerEvalNilReceiver(const ObjCMessage &msg,
                               ExplodedNodeSet &Dst,
                               const GRState *state,
                               ExplodedNode *Pred);
@@ -490,10 +493,10 @@ public:
   }
   
 protected:
-  void evalObjCMessageExpr(ExplodedNodeSet& Dst, const ObjCMessageExpr* ME
-                           ExplodedNode* Pred, const GRState *state) {
+  void evalObjCMessage(ExplodedNodeSet& Dst, const ObjCMessage &msg
+                       ExplodedNode* Pred, const GRState *state) {
     assert (Builder && "StmtNodeBuilder must be defined.");
-    getTF().evalObjCMessageExpr(Dst, *this, *Builder, ME, Pred, state);
+    getTF().evalObjCMessage(Dst, *this, *Builder, msg, Pred, state);
   }
 
   const GRState* MarkBranch(const GRState* St, const Stmt* Terminator,
diff --git a/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/PathSensitive/ObjCMessage.h
new file mode 100644 (file)
index 0000000..4e5ce09
--- /dev/null
@@ -0,0 +1,207 @@
+//===- ObjCMessage.h - Wrapper for ObjC messages and dot syntax ---*- C++ -*--//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ObjCMessage which serves as a common wrapper for ObjC
+// message expressions or implicit messages for loading/storing ObjC properties.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
+#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
+
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/AST/ExprObjC.h"
+
+namespace clang {
+namespace ento {
+
+/// \brief Represents both explicit ObjC message expressions and implicit
+/// messages that are sent for handling properties in dot syntax.
+class ObjCMessage {
+  const Expr *MsgOrPropE;
+  const Expr *OriginE;
+  bool IsPropSetter;
+  SVal SetterArgV;
+
+protected:
+  ObjCMessage(const Expr *E, const Expr *origE, bool isSetter, SVal setArgV)
+    : MsgOrPropE(E), OriginE(origE),
+      IsPropSetter(isSetter), SetterArgV(setArgV) { }
+
+public:
+  ObjCMessage() : MsgOrPropE(0), OriginE(0) { }
+
+  ObjCMessage(const ObjCMessageExpr *E)
+    : MsgOrPropE(E), OriginE(E) {
+    assert(E && "should not be initialized with null expression");
+  }
+
+  bool isValid() const { return MsgOrPropE != 0; }
+  bool isInvalid() const { return !isValid(); }
+
+  bool isMessageExpr() const {
+    return isValid() && isa<ObjCMessageExpr>(MsgOrPropE);
+  }
+
+  bool isPropertyGetter() const {
+    return isValid() &&
+           isa<ObjCPropertyRefExpr>(MsgOrPropE) && !IsPropSetter;
+  }
+
+  bool isPropertySetter() const {
+    return isValid() &&
+           isa<ObjCPropertyRefExpr>(MsgOrPropE) && IsPropSetter;
+  }
+  
+  const Expr *getOriginExpr() const { return OriginE; }
+
+  QualType getType(ASTContext &ctx) const;
+
+  QualType getResultType(ASTContext &ctx) const {
+    assert(isValid() && "This ObjCMessage is uninitialized!");
+    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+      if (const ObjCMethodDecl *MD = msgE->getMethodDecl())
+        return MD->getResultType();
+    return getType(ctx);
+  }
+
+  Selector getSelector() const;
+
+  const Expr *getInstanceReceiver() const {
+    assert(isValid() && "This ObjCMessage is uninitialized!");
+    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+      return msgE->getInstanceReceiver();
+    return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getBase();
+  }
+
+  bool isInstanceMessage() const {
+    assert(isValid() && "This ObjCMessage is uninitialized!");
+    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+      return msgE->isInstanceMessage();
+    const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
+    // FIXME: 'super' may be super class.
+    return propE->isObjectReceiver() || propE->isSuperReceiver();
+  }
+
+  const ObjCMethodDecl *getMethodDecl() const;
+  
+  const ObjCInterfaceDecl *getReceiverInterface() const;
+
+  SourceLocation getSuperLoc() const {
+    assert(isValid() && "This ObjCMessage is uninitialized!");
+    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+      return msgE->getSuperLoc();
+    return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getReceiverLocation();
+  }
+
+   SourceRange getSourceRange() const {
+     assert(isValid() && "This ObjCMessage is uninitialized!");
+    return MsgOrPropE->getSourceRange();
+  }
+
+   unsigned getNumArgs() const {
+     assert(isValid() && "This ObjCMessage is uninitialized!");
+     if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+       return msgE->getNumArgs();
+     return isPropertySetter() ? 1 : 0;
+   }
+
+   SVal getArgSVal(unsigned i, const GRState *state) const {
+     assert(isValid() && "This ObjCMessage is uninitialized!");
+     assert(i < getNumArgs() && "Invalid index for argument");
+     if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+       return state->getSVal(msgE->getArg(i));
+     assert(isPropertySetter());
+     return SetterArgV;
+   }
+
+   QualType getArgType(unsigned i) const {
+     assert(isValid() && "This ObjCMessage is uninitialized!");
+     assert(i < getNumArgs() && "Invalid index for argument");
+     if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+       return msgE->getArg(i)->getType();
+     assert(isPropertySetter());
+     return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getType();
+   }
+   
+   const Expr *getArgExpr(unsigned i) const;
+
+   SourceRange getArgSourceRange(unsigned i) const {
+     assert(isValid() && "This ObjCMessage is uninitialized!");
+     assert(i < getNumArgs() && "Invalid index for argument");
+     if (const Expr *argE = getArgExpr(i))
+       return argE->getSourceRange();
+     return OriginE->getSourceRange();
+   }
+};
+
+class ObjCPropertyGetter : public ObjCMessage {
+public:
+  ObjCPropertyGetter(const ObjCPropertyRefExpr *propE, const Expr *originE)
+    : ObjCMessage(propE, originE, false, SVal()) {
+    assert(propE && originE &&
+           "should not be initialized with null expressions");
+  }
+};
+
+class ObjCPropertySetter : public ObjCMessage {
+public:
+  ObjCPropertySetter(const ObjCPropertyRefExpr *propE, const Expr *storeE,
+                     SVal argV)
+    : ObjCMessage(propE, storeE, true, argV) {
+    assert(propE && storeE &&"should not be initialized with null expressions");
+  }
+};
+
+/// \brief Common wrapper for a call expression or an ObjC message, mainly to
+/// provide a common interface for handling their arguments.
+class CallOrObjCMessage {
+  const CallExpr *CallE;
+  ObjCMessage Msg;
+  const GRState *State;
+  
+public:
+  CallOrObjCMessage(const CallExpr *callE, const GRState *state)
+    : CallE(callE), State(state) { }
+  CallOrObjCMessage(const ObjCMessage &msg, const GRState *state)
+    : CallE(0), Msg(msg), State(state) { }
+
+  QualType getResultType(ASTContext &ctx) const;
+
+  unsigned getNumArgs() const {
+    if (CallE) return CallE->getNumArgs();
+    return Msg.getNumArgs();
+  }
+
+  SVal getArgSVal(unsigned i) const {
+    assert(i < getNumArgs());
+    if (CallE) return State->getSVal(CallE->getArg(i));
+    return Msg.getArgSVal(i, State);
+  }
+
+  SVal getArgSValAsScalarOrLoc(unsigned i) const;
+
+  const Expr *getArg(unsigned i) const {
+    assert(i < getNumArgs());
+    if (CallE) return CallE->getArg(i);
+    return Msg.getArgExpr(i);
+  }
+
+  SourceRange getArgSourceRange(unsigned i) const {
+    assert(i < getNumArgs());
+    if (CallE) return CallE->getArg(i)->getSourceRange();
+    return Msg.getArgSourceRange(i);
+  }
+};
+
+}
+}
+
+#endif
index 950143d91da0ad04ccecbd1b1d153c19d7f6e44c..92598fcdd6c4f7810ce781d4954ab515fe902a15 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 #include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/ObjCMessage.h"
 #include <vector>
 
 namespace clang {
@@ -47,12 +48,12 @@ public:
                         const CallExpr* CE, SVal L,
                         ExplodedNode* Pred) {}
 
-  virtual void evalObjCMessageExpr(ExplodedNodeSet& Dst,
-                                   ExprEngine& Engine,
-                                   StmtNodeBuilder& Builder,
-                                   const ObjCMessageExpr* ME,
-                                   ExplodedNode* Pred,
-                                   const GRState *state) {}
+  virtual void evalObjCMessage(ExplodedNodeSet& Dst,
+                               ExprEngine& Engine,
+                               StmtNodeBuilder& Builder,
+                               ObjCMessage msg,
+                               ExplodedNode* Pred,
+                               const GRState *state) {}
 
   // Stores.
 
index d4bed35317ecbc3cb56b834d0aecafd0fcc4d892..5cc4a3c3ee3406ce6aa9ee3200e5d5c0afdf02ca 100644 (file)
@@ -40,14 +40,15 @@ using llvm::StrInStrNoCase;
 
 namespace {
 class InstanceReceiver {
-  const ObjCMessageExpr *ME;
+  ObjCMessage Msg;
   const LocationContext *LC;
 public:
-  InstanceReceiver(const ObjCMessageExpr *me = 0,
-                   const LocationContext *lc = 0) : ME(me), LC(lc) {}
+  InstanceReceiver() : LC(0) { }
+  InstanceReceiver(const ObjCMessage &msg,
+                   const LocationContext *lc = 0) : Msg(msg), LC(lc) {}
 
   bool isValid() const {
-    return ME && ME->isInstanceMessage();
+    return Msg.isValid() && Msg.isInstanceMessage();
   }
   operator bool() const {
     return isValid();
@@ -57,7 +58,7 @@ public:
     assert(isValid());
     // We have an expression for the receiver?  Fetch the value
     // of that expression.
-    if (const Expr *Ex = ME->getInstanceReceiver())
+    if (const Expr *Ex = Msg.getInstanceReceiver())
       return state->getSValAsScalarOrLoc(Ex);
 
     // Otherwise we are sending a message to super.  In this case the
@@ -70,11 +71,11 @@ public:
 
   SourceRange getSourceRange() const {
     assert(isValid());
-    if (const Expr *Ex = ME->getInstanceReceiver())
+    if (const Expr *Ex = Msg.getInstanceReceiver())
       return Ex->getSourceRange();
 
     // Otherwise we are sending a message to super.
-    SourceLocation L = ME->getSuperLoc();
+    SourceLocation L = Msg.getSuperLoc();
     assert(L.isValid());
     return SourceRange(L, L);
   }
@@ -798,14 +799,14 @@ public:
 
   RetainSummary* getSummary(const FunctionDecl* FD);
 
-  RetainSummary *getInstanceMethodSummary(const ObjCMessageExpr *ME,
+  RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg,
                                           const GRState *state,
                                           const LocationContext *LC);
 
-  RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
+  RetainSummary* getInstanceMethodSummary(const ObjCMessage &msg,
                                           const ObjCInterfaceDecl* ID) {
-    return getInstanceMethodSummary(ME->getSelector(), 0,
-                            ID, ME->getMethodDecl(), ME->getType());
+    return getInstanceMethodSummary(msg.getSelector(), 0,
+                            ID, msg.getMethodDecl(), msg.getType(Ctx));
   }
 
   RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName,
@@ -818,23 +819,15 @@ public:
                                        const ObjCMethodDecl *MD,
                                        QualType RetTy);
 
-  RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
-    ObjCInterfaceDecl *Class = 0;
-    switch (ME->getReceiverKind()) {
-    case ObjCMessageExpr::Class:
-    case ObjCMessageExpr::SuperClass:
-      Class = ME->getReceiverInterface();
-      break;
-
-    case ObjCMessageExpr::Instance:
-    case ObjCMessageExpr::SuperInstance:
-      break;
-    }
+  RetainSummary *getClassMethodSummary(const ObjCMessage &msg) {
+    const ObjCInterfaceDecl *Class = 0;
+    if (!msg.isInstanceMessage())
+      Class = msg.getReceiverInterface();
 
-    return getClassMethodSummary(ME->getSelector(),
+    return getClassMethodSummary(msg.getSelector(),
                                  Class? Class->getIdentifier() : 0,
                                  Class,
-                                 ME->getMethodDecl(), ME->getType());
+                                 msg.getMethodDecl(), msg.getType(Ctx));
   }
 
   /// getMethodSummary - This version of getMethodSummary is used to query
@@ -1310,13 +1303,13 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
 }
 
 RetainSummary*
-RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
+RetainSummaryManager::getInstanceMethodSummary(const ObjCMessage &msg,
                                                const GRState *state,
                                                const LocationContext *LC) {
 
   // We need the type-information of the tracked receiver object
   // Retrieve it from the state.
-  const Expr *Receiver = ME->getInstanceReceiver();
+  const Expr *Receiver = msg.getInstanceReceiver();
   const ObjCInterfaceDecl* ID = 0;
 
   // FIXME: Is this really working as expected?  There are cases where
@@ -1344,12 +1337,12 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
     }
   } else {
     // FIXME: Hack for 'super'.
-    ID = ME->getReceiverInterface();
+    ID = msg.getReceiverInterface();
   }
 
   // FIXME: The receiver could be a reference to a class, meaning that
   //  we should use the class method.
-  RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
+  RetainSummary *Summ = getInstanceMethodSummary(msg, ID);
 
   // Special-case: are we sending a mesage to "self"?
   //  This is a hack.  When we have full-IP this should be removed.
@@ -1693,10 +1686,10 @@ public:
                    ExprEngine& Eng,
                    StmtNodeBuilder& Builder,
                    const Expr* Ex,
+                   const CallOrObjCMessage &callOrMsg,
                    InstanceReceiver Receiver,
                    const RetainSummary& Summ,
                    const MemRegion *Callee,
-                   ConstExprIterator arg_beg, ConstExprIterator arg_end,
                    ExplodedNode* Pred, const GRState *state);
 
   virtual void evalCall(ExplodedNodeSet& Dst,
@@ -1706,12 +1699,12 @@ public:
                         ExplodedNode* Pred);
 
 
-  virtual void evalObjCMessageExpr(ExplodedNodeSet& Dst,
-                                   ExprEngine& Engine,
-                                   StmtNodeBuilder& Builder,
-                                   const ObjCMessageExpr* ME,
-                                   ExplodedNode* Pred,
-                                   const GRState *state);
+  virtual void evalObjCMessage(ExplodedNodeSet& Dst,
+                               ExprEngine& Engine,
+                               StmtNodeBuilder& Builder,
+                               ObjCMessage msg,
+                               ExplodedNode* Pred,
+                               const GRState *state);
   // Stores.
   virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val);
 
@@ -2477,16 +2470,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
                              ExprEngine& Eng,
                              StmtNodeBuilder& Builder,
                              const Expr* Ex,
+                             const CallOrObjCMessage &callOrMsg,
                              InstanceReceiver Receiver,
                              const RetainSummary& Summ,
                              const MemRegion *Callee,
-                             ConstExprIterator arg_beg, 
-                             ConstExprIterator arg_end,
                              ExplodedNode* Pred, const GRState *state) {
 
   // Evaluate the effect of the arguments.
   RefVal::Kind hasErr = (RefVal::Kind) 0;
-  unsigned idx = 0;
   SourceRange ErrorRange;
   SymbolRef ErrorSym = 0;
 
@@ -2498,8 +2489,8 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
   //  done an invalidation pass.
   llvm::DenseSet<SymbolRef> WhitelistedSymbols;
 
-  for (ConstExprIterator I = arg_beg; I != arg_end; ++I, ++idx) {
-    SVal V = state->getSValAsScalarOrLoc(*I);
+  for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) {
+    SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx);
     SymbolRef Sym = V.getAsLocSymbol();
 
     if (Sym)
@@ -2507,7 +2498,7 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
         WhitelistedSymbols.insert(Sym);
         state = Update(state, Sym, *T, Summ.getArg(idx), hasErr);
         if (hasErr) {
-          ErrorRange = (*I)->getSourceRange();
+          ErrorRange = callOrMsg.getArgSourceRange(idx);
           ErrorSym = Sym;
           break;
         }
@@ -2650,19 +2641,7 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
       // FIXME: We eventually should handle structs and other compound types
       // that are returned by value.
 
-      QualType T = Ex->getType();
-
-      // For CallExpr, use the result type to know if it returns a reference.
-      if (const CallExpr *CE = dyn_cast<CallExpr>(Ex)) {
-        const Expr *Callee = CE->getCallee();
-        if (const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl())
-          T = FD->getResultType();
-      }
-      else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Ex)) {
-        if (const ObjCMethodDecl *MD = ME->getMethodDecl())
-          T = MD->getResultType();
-      }
-
+      QualType T = callOrMsg.getResultType(Eng.getContext());
       if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
         unsigned Count = Builder.getCurrentBlockCount();
         SValBuilder &svalBuilder = Eng.getSValBuilder();
@@ -2675,9 +2654,8 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
 
     case RetEffect::Alias: {
       unsigned idx = RE.getIndex();
-      assert (arg_end >= arg_beg);
-      assert (idx < (unsigned) (arg_end - arg_beg));
-      SVal V = state->getSValAsScalarOrLoc(*(arg_beg+idx));
+      assert (idx < callOrMsg.getNumArgs());
+      SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx);
       state = state->BindExpr(Ex, V, false);
       break;
     }
@@ -2756,25 +2734,28 @@ void CFRefCount::evalCall(ExplodedNodeSet& Dst,
   }
 
   assert(Summ);
-  evalSummary(Dst, Eng, Builder, CE, 0, *Summ, L.getAsRegion(),
-              CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred));
+  evalSummary(Dst, Eng, Builder, CE,
+              CallOrObjCMessage(CE, Builder.GetState(Pred)),
+              InstanceReceiver(), *Summ,L.getAsRegion(),
+              Pred, Builder.GetState(Pred));
 }
 
-void CFRefCount::evalObjCMessageExpr(ExplodedNodeSet& Dst,
-                                     ExprEngine& Eng,
-                                     StmtNodeBuilder& Builder,
-                                     const ObjCMessageExpr* ME,
-                                     ExplodedNode* Pred,
-                                     const GRState *state) {
+void CFRefCount::evalObjCMessage(ExplodedNodeSet& Dst,
+                                 ExprEngine& Eng,
+                                 StmtNodeBuilder& Builder,
+                                 ObjCMessage msg,
+                                 ExplodedNode* Pred,
+                                 const GRState *state) {
   RetainSummary *Summ =
-    ME->isInstanceMessage()
-      ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
-      : Summaries.getClassMethodSummary(ME);
+    msg.isInstanceMessage()
+      ? Summaries.getInstanceMethodSummary(msg, state,Pred->getLocationContext())
+      : Summaries.getClassMethodSummary(msg);
 
   assert(Summ && "RetainSummary is null");
-  evalSummary(Dst, Eng, Builder, ME,
-              InstanceReceiver(ME, Pred->getLocationContext()), *Summ, NULL,
-              ME->arg_begin(), ME->arg_end(), Pred, state);
+  evalSummary(Dst, Eng, Builder, msg.getOriginExpr(),
+              CallOrObjCMessage(msg, Builder.GetState(Pred)),
+              InstanceReceiver(msg, Pred->getLocationContext()), *Summ, NULL,
+              Pred, state);
 }
 
 namespace {
index cf81e1d5ad89f783309b53b4d968a5e7778b53c5..352138599ecc3c26db7f171d4924a89492e9a1b2 100644 (file)
@@ -24,6 +24,7 @@ add_clang_library(clangStaticAnalyzerCore
   HTMLDiagnostics.cpp
   ManagerRegistry.cpp
   MemRegion.cpp
+  ObjCMessage.cpp
   PathDiagnostic.cpp
   PlistDiagnostics.cpp
   RangeConstraintManager.cpp
index 3910196265ba47690cdb5ebcfc422a70f062f746..8fa7e24cab006c477d4a034b28cd26276e70c7ea 100644 (file)
@@ -42,14 +42,14 @@ public:
 // Utility functions.
 //===----------------------------------------------------------------------===//
 
-static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
-  if (ObjCInterfaceDecl *ID = ME->getReceiverInterface())
+static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) {
+  if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
     return ID->getTypeForDecl()->getAs<ObjCInterfaceType>();
   return NULL;
 }
 
-static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
-  if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
+static const char* GetReceiverNameType(const ObjCMessage &msg) {
+  if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg))
     return ReceiverType->getDecl()->getIdentifier()->getNameStart();
   return NULL;
 }
@@ -69,16 +69,16 @@ static inline bool isNil(SVal X) {
 namespace {
   class NilArgChecker : public CheckerVisitor<NilArgChecker> {
     APIMisuse *BT;
-    void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg);
+    void WarnNilArg(CheckerContext &C, const ObjCMessage &msg, unsigned Arg);
   public:
     NilArgChecker() : BT(0) {}
     static void *getTag() { static int x = 0; return &x; }
-    void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+    void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
   };
 }
 
 void NilArgChecker::WarnNilArg(CheckerContext &C,
-                               const clang::ObjCMessageExpr *ME,
+                               const ObjCMessage &msg,
                                unsigned int Arg)
 {
   if (!BT)
@@ -87,24 +87,24 @@ void NilArgChecker::WarnNilArg(CheckerContext &C,
   if (ExplodedNode *N = C.generateSink()) {
     llvm::SmallString<128> sbuf;
     llvm::raw_svector_ostream os(sbuf);
-    os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
-       << ME->getSelector().getAsString() << "' cannot be nil";
+    os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
+       << msg.getSelector().getAsString() << "' cannot be nil";
 
     RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
-    R->addRange(ME->getArg(Arg)->getSourceRange());
+    R->addRange(msg.getArgSourceRange(Arg));
     C.EmitReport(R);
   }
 }
 
-void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
-                                            const ObjCMessageExpr *ME)
+void NilArgChecker::preVisitObjCMessage(CheckerContext &C,
+                                        ObjCMessage msg)
 {
-  const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
+  const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
   if (!ReceiverType)
     return;
   
   if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
-    Selector S = ME->getSelector();
+    Selector S = msg.getSelector();
     
     if (S.isUnarySelector())
       return;
@@ -127,8 +127,8 @@ void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
         Name == "compare:options:range:locale:" ||
         Name == "componentsSeparatedByCharactersInSet:" ||
         Name == "initWithFormat:") {
-      if (isNil(C.getState()->getSVal(ME->getArg(0))))
-        WarnNilArg(C, ME, 0);
+      if (isNil(msg.getArgSVal(0, C.getState())))
+        WarnNilArg(C, msg, 0);
     }
   }
 }
@@ -441,12 +441,12 @@ public:
 
   static void *getTag() { static int x = 0; return &x; }
       
-  void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);    
+  void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
 };
 }
 
-void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
-                                                  const ObjCMessageExpr *ME) {
+void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C,
+                                              ObjCMessage msg) {
   
   if (!BT) {
     BT = new APIMisuse("message incorrectly sent to class instead of class "
@@ -459,21 +459,12 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
     drainS = GetNullarySelector("drain", Ctx);
   }
   
-  ObjCInterfaceDecl *Class = 0;
-
-  switch (ME->getReceiverKind()) {
-  case ObjCMessageExpr::Class:
-    Class = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
-    break;
-  case ObjCMessageExpr::SuperClass:
-    Class = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface();
-    break;
-  case ObjCMessageExpr::Instance:
-  case ObjCMessageExpr::SuperInstance:
+  if (msg.isInstanceMessage())
     return;
-  }
+  const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
+  assert(Class);
 
-  Selector S = ME->getSelector();
+  Selector S = msg.getSelector();
   if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
     return;
   
@@ -486,7 +477,7 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
        << "' and not the class directly";
   
     RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
-    report->addRange(ME->getSourceRange());
+    report->addRange(msg.getSourceRange());
     C.EmitReport(report);
   }
 }
index 2998406da05910685997024a033a584179aba128..e6a40bb59757bcab589c0fc65c970cb90c3bb4bd 100644 (file)
@@ -41,19 +41,21 @@ public:
   }
 
   void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-  void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
-  bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
+  void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
+  bool evalNilReceiver(CheckerContext &C, ObjCMessage msg);
 
 private:
-  bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex,
-                          const char *BT_desc, BugType *&BT);
+  void PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg,
+                           const char *BT_desc, BugType *&BT);
+  bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange,
+                          const Expr *argEx, const char *BT_desc, BugType *&BT);
 
   void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
-  void emitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
+  void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
                           ExplodedNode *N);
 
   void HandleNilReceiver(CheckerContext &C, const GRState *state,
-                         const ObjCMessageExpr *ME);
+                         ObjCMessage msg);
 
   void LazyInit_BT(const char *desc, BugType *&BT) {
     if (!BT)
@@ -78,21 +80,32 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
   C.EmitReport(R);
 }
 
+void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C,
+                                                CallOrObjCMessage callOrMsg,
+                                                const char *BT_desc,
+                                                BugType *&BT) {
+  for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i)
+    if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i),
+                           callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i),
+                           BT_desc, BT))
+      return;
+}
+
 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
-                                               const Expr *Ex,
+                                               SVal V, SourceRange argRange,
+                                               const Expr *argEx,
                                                const char *BT_desc,
                                                BugType *&BT) {
 
-  const SVal &V = C.getState()->getSVal(Ex);
-
   if (V.isUndef()) {
     if (ExplodedNode *N = C.generateSink()) {
       LazyInit_BT(BT_desc, BT);
 
       // Generate a report for this bug.
       EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
-      R->addRange(Ex->getSourceRange());
-      R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+      R->addRange(argRange);
+      if (argEx)
+        R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, argEx);
       C.EmitReport(R);
     }
     return true;
@@ -172,7 +185,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
 
         // Generate a report for this bug.
         EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
-        R->addRange(Ex->getSourceRange());
+        R->addRange(argRange);
 
         // FIXME: enhance track back for uninitialized value for arbitrary
         // memregions
@@ -206,21 +219,18 @@ void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
     EmitBadCall(BT_call_null, C, CE);
   }
 
-  for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
-       I != E; ++I)
-    if (PreVisitProcessArg(C, *I,
-                           "Function call argument is an uninitialized value",
-                           BT_call_arg))
-      return;
+  PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState()),
+                      "Function call argument is an uninitialized value",
+                      BT_call_arg);
 }
 
-void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
-                                                    const ObjCMessageExpr *ME) {
+void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C,
+                                                ObjCMessage msg) {
 
   const GRState *state = C.getState();
 
   // FIXME: Handle 'super'?
-  if (const Expr *receiver = ME->getInstanceReceiver())
+  if (const Expr *receiver = msg.getInstanceReceiver())
     if (state->getSVal(receiver).isUndef()) {
       if (ExplodedNode *N = C.generateSink()) {
         if (!BT_msg_undef)
@@ -237,22 +247,19 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
     }
 
   // Check for any arguments that are uninitialized/undefined.
-  for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
-         E = ME->arg_end(); I != E; ++I)
-    if (PreVisitProcessArg(C, *I,
-                           "Argument in message expression "
-                           "is an uninitialized value", BT_msg_arg))
-        return;
+  PreVisitProcessArgs(C, CallOrObjCMessage(msg, state),
+                      "Argument in message expression "
+                      "is an uninitialized value", BT_msg_arg);
 }
 
 bool CallAndMessageChecker::evalNilReceiver(CheckerContext &C,
-                                            const ObjCMessageExpr *ME) {
-  HandleNilReceiver(C, C.getState(), ME);
+                                            ObjCMessage msg) {
+  HandleNilReceiver(C, C.getState(), msg);
   return true; // Nil receiver is not handled elsewhere.
 }
 
 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
-                                               const ObjCMessageExpr *ME,
+                                               const ObjCMessage &msg,
                                                ExplodedNode *N) {
 
   if (!BT_msg_ret)
@@ -262,12 +269,12 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
 
   llvm::SmallString<200> buf;
   llvm::raw_svector_ostream os(buf);
-  os << "The receiver of message '" << ME->getSelector().getAsString()
+  os << "The receiver of message '" << msg.getSelector().getAsString()
      << "' is nil and returns a value of type '"
-     << ME->getType().getAsString() << "' that will be garbage";
+     << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage";
 
   EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
-  if (const Expr *receiver = ME->getInstanceReceiver()) {
+  if (const Expr *receiver = msg.getInstanceReceiver()) {
     report->addRange(receiver->getSourceRange());
     report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
                               receiver);
@@ -284,22 +291,22 @@ static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
 
 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
                                               const GRState *state,
-                                              const ObjCMessageExpr *ME) {
+                                              ObjCMessage msg) {
+  ASTContext &Ctx = C.getASTContext();
 
   // Check the return type of the message expression.  A message to nil will
   // return different values depending on the return type and the architecture.
-  QualType RetTy = ME->getType();
+  QualType RetTy = msg.getType(Ctx);
 
-  ASTContext &Ctx = C.getASTContext();
   CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
 
   if (CanRetTy->isStructureOrClassType()) {
     // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
     // have the "use of undefined value" be smarter about where the
     // undefined value came from.
-    if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+    if (C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())){
       if (ExplodedNode* N = C.generateSink(state))
-        emitNilReceiverBug(C, ME, N);
+        emitNilReceiverBug(C, msg, N);
       return;
     }
 
@@ -311,7 +318,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
 
   // Other cases: check if the return type is smaller than void*.
   if (CanRetTy != Ctx.VoidTy &&
-      C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+      C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())) {
     // Compute: sizeof(void *) and sizeof(return type)
     const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
     const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
@@ -324,7 +331,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
            Ctx.LongLongTy == CanRetTy ||
            Ctx.UnsignedLongLongTy == CanRetTy))) {
       if (ExplodedNode* N = C.generateSink(state))
-        emitNilReceiverBug(C, ME, N);
+        emitNilReceiverBug(C, msg, N);
       return;
     }
 
@@ -341,8 +348,8 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
     // it most likely isn't nil.  We should assume the semantics
     // of this case unless we have *a lot* more knowledge.
     //
-    SVal V = C.getSValBuilder().makeZeroVal(ME->getType());
-    C.generateNode(state->BindExpr(ME, V));
+    SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
+    C.generateNode(state->BindExpr(msg.getOriginExpr(), V));
     return;
   }
 
index a022562a1292b3dc7b6fc698cad0367a205af2f1..6932f4a71727f8544b82785e1eb160f6f80e4db7 100644 (file)
@@ -145,10 +145,49 @@ void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst,
   // automatically.
 }
 
-void ExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
-                                          ExplodedNodeSet &Dst,
-                                          const GRState *state,
-                                          ExplodedNode *Pred) {
+void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
+                                         ExplodedNodeSet &Dst,
+                                         ExplodedNodeSet &Src,
+                                         bool isPrevisit) {
+
+  if (Checkers.empty()) {
+    Dst.insert(Src);
+    return;
+  }
+
+  ExplodedNodeSet Tmp;
+  ExplodedNodeSet *PrevSet = &Src;
+
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
+  {
+    ExplodedNodeSet *CurrSet = 0;
+    if (I+1 == E)
+      CurrSet = &Dst;
+    else {
+      CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+      CurrSet->clear();
+    }
+
+    void *tag = I->first;
+    Checker *checker = I->second;
+
+    for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+         NI != NE; ++NI)
+      checker->GR_visitObjCMessage(*CurrSet, *Builder, *this, msg,
+                                   *NI, tag, isPrevisit);
+
+    // Update which NodeSet is the current one.
+    PrevSet = CurrSet;
+  }
+
+  // Don't autotransition.  The CheckerContext objects should do this
+  // automatically.
+}
+
+void ExprEngine::CheckerEvalNilReceiver(const ObjCMessage &msg,
+                                        ExplodedNodeSet &Dst,
+                                        const GRState *state,
+                                        ExplodedNode *Pred) {
   bool evaluated = false;
   ExplodedNodeSet DstTmp;
 
@@ -156,7 +195,7 @@ void ExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
     void *tag = I->first;
     Checker *checker = I->second;
 
-    if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state,
+    if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, msg, Pred, state,
                                     tag)) {
       evaluated = true;
       break;
@@ -2263,7 +2302,7 @@ void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME,
 
   // Now that the arguments are processed, handle the previsits checks.
   ExplodedNodeSet DstPrevisit;
-  CheckerVisit(ME, DstPrevisit, ArgsEvaluated, PreVisitStmtCallback);
+  CheckerVisitObjCMessage(ME, DstPrevisit, ArgsEvaluated, /*isPreVisit=*/true);
 
   // Proceed with evaluate the message expression.
   ExplodedNodeSet dstEval;
@@ -2305,7 +2344,7 @@ void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME,
         Builder->BuildSinks = true;
 
       // Dispatch to plug-in transfer function.
-      evalObjCMessageExpr(dstEval, ME, Pred, notNilState);
+      evalObjCMessage(dstEval, ME, Pred, notNilState);
     }
     else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) {
       IdentifierInfo* ClsName = Iface->getIdentifier();
@@ -2353,7 +2392,7 @@ void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME,
         Builder->BuildSinks = true;
 
       // Dispatch to plug-in transfer function.
-      evalObjCMessageExpr(dstEval, ME, Pred, Builder->GetState(Pred));
+      evalObjCMessage(dstEval, ME, Pred, Builder->GetState(Pred));
     }
 
     // Handle the case where no nodes where generated.  Auto-generate that
@@ -2365,7 +2404,7 @@ void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME,
 
   // Finally, perform the post-condition check of the ObjCMessageExpr and store
   // the created nodes in 'Dst'.
-  CheckerVisit(ME, Dst, dstEval, PostVisitStmtCallback);
+  CheckerVisitObjCMessage(ME, Dst, dstEval, /*isPreVisit=*/false);
 }
 
 //===----------------------------------------------------------------------===//
index 6ef242ba427a6b9c86762c4275f8185490e28a20..b1b4773aee5ce52bf3a527c6bf260039fae01d32 100644 (file)
@@ -39,7 +39,7 @@ public:
     return &x;
   }
 
-  void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);    
+  void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);    
 };
 
 } // end anonymous namespace
@@ -54,10 +54,10 @@ void ento::RegisterNSAutoreleasePoolChecks(ExprEngine &Eng) {
 }
 
 void
-NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
-                                                  const ObjCMessageExpr *ME) {
+NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C,
+                                              ObjCMessage msg) {
   
-  const Expr *receiver = ME->getInstanceReceiver();
+  const Expr *receiver = msg.getInstanceReceiver();
   if (!receiver)
     return;
   
@@ -75,13 +75,13 @@ NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
     return;
   
   // Sending 'release' message?
-  if (ME->getSelector() != releaseS)
+  if (msg.getSelector() != releaseS)
     return;
                      
-  SourceRange R = ME->getSourceRange();
+  SourceRange R = msg.getSourceRange();
 
   C.getBugReporter().EmitBasicReport("Use -drain instead of -release",
     "API Upgrade (Apple)",
     "Use -drain instead of -release when using NSAutoreleasePool "
-    "and garbage collection", ME->getLocStart(), &R, 1);
+    "and garbage collection", R.getBegin(), &R, 1);
 }
index 9eb6b19ec7106899fd3667be356e90c3fb0a5b6c..c887ac86ef50043452bf127e60b8ded1f72595de 100644 (file)
@@ -58,7 +58,7 @@ using namespace ento;
 
 static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND);
 static bool isInitializationMethod(const ObjCMethodDecl *MD);
-static bool isInitMessage(const ObjCMessageExpr *E);
+static bool isInitMessage(const ObjCMessage &msg);
 static bool isSelfVar(SVal location, CheckerContext &C);
 
 namespace {
@@ -82,7 +82,7 @@ class ObjCSelfInitChecker : public CheckerVisitor<ObjCSelfInitChecker> {
 
 public:
   static void *getTag() { static int tag = 0; return &tag; }
-  void PostVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *E);
+  void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
   void PostVisitObjCIvarRefExpr(CheckerContext &C, const ObjCIvarRefExpr *E);
   void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
   void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE);
@@ -176,8 +176,8 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C,
   C.EmitReport(report);
 }
 
-void ObjCSelfInitChecker::PostVisitObjCMessageExpr(CheckerContext &C,
-                                                   const ObjCMessageExpr *E) {
+void ObjCSelfInitChecker::postVisitObjCMessage(CheckerContext &C,
+                                               ObjCMessage msg) {
   // When encountering a message that does initialization (init rule),
   // tag the return value so that we know later on that if self has this value
   // then it is properly initialized.
@@ -187,10 +187,10 @@ void ObjCSelfInitChecker::PostVisitObjCMessageExpr(CheckerContext &C,
                                      C.getCurrentAnalysisContext()->getDecl())))
     return;
 
-  if (isInitMessage(E)) {
+  if (isInitMessage(msg)) {
     // Tag the return value as the result of an initializer.
     const GRState *state = C.getState();
-    SVal V = state->getSVal(E);
+    SVal V = state->getSVal(msg.getOriginExpr());
     addSelfFlag(V, SelfFlag_InitRes, C);
     return;
   }
@@ -301,6 +301,6 @@ static bool isInitializationMethod(const ObjCMethodDecl *MD) {
                                     /*ignorePrefix=*/false) == cocoa::InitRule;
 }
 
-static bool isInitMessage(const ObjCMessageExpr *E) {
-  return cocoa::deriveNamingConvention(E->getSelector()) == cocoa::InitRule;
+static bool isInitMessage(const ObjCMessage &msg) {
+  return cocoa::deriveNamingConvention(msg.getSelector()) == cocoa::InitRule;
 }
diff --git a/lib/StaticAnalyzer/ObjCMessage.cpp b/lib/StaticAnalyzer/ObjCMessage.cpp
new file mode 100644 (file)
index 0000000..53c7175
--- /dev/null
@@ -0,0 +1,99 @@
+//===- ObjCMessage.cpp - Wrapper for ObjC messages and dot syntax -*- C++ -*--//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ObjCMessage which serves as a common wrapper for ObjC
+// message expressions or implicit messages for loading/storing ObjC properties.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/ObjCMessage.h"
+
+using namespace clang;
+using namespace ento;
+
+QualType ObjCMessage::getType(ASTContext &ctx) const {
+  assert(isValid() && "This ObjCMessage is uninitialized!");
+  if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+    return msgE->getType();
+  const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
+  if (isPropertySetter())
+    return ctx.VoidTy;
+  return propE->getType();
+}
+
+Selector ObjCMessage::getSelector() const {
+  assert(isValid() && "This ObjCMessage is uninitialized!");
+  if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+    return msgE->getSelector();
+  const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
+  if (isPropertySetter())
+    return propE->getSetterSelector();
+  return propE->getGetterSelector();
+}
+
+const ObjCMethodDecl *ObjCMessage::getMethodDecl() const {
+  assert(isValid() && "This ObjCMessage is uninitialized!");
+  if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+    return msgE->getMethodDecl();
+  const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
+  if (propE->isImplicitProperty())
+    return isPropertySetter() ? propE->getImplicitPropertySetter()
+                              : propE->getImplicitPropertyGetter();
+  return 0;
+}
+
+const ObjCInterfaceDecl *ObjCMessage::getReceiverInterface() const {
+  assert(isValid() && "This ObjCMessage is uninitialized!");
+  if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+    return msgE->getReceiverInterface();
+  const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
+  if (propE->isClassReceiver())
+    return propE->getClassReceiver();
+  QualType recT;
+  if (const Expr *recE = getInstanceReceiver())
+    recT = recE->getType();
+  else {
+    assert(propE->isSuperReceiver());
+    recT = propE->getSuperReceiverType();
+  }
+  if (const ObjCObjectPointerType *Ptr = recT->getAs<ObjCObjectPointerType>())
+    return Ptr->getInterfaceDecl();
+  return 0;
+}
+
+const Expr *ObjCMessage::getArgExpr(unsigned i) const {
+  assert(isValid() && "This ObjCMessage is uninitialized!");
+  assert(i < getNumArgs() && "Invalid index for argument");
+  if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+    return msgE->getArg(i);
+  assert(isPropertySetter());
+  if (const BinaryOperator *bop = dyn_cast<BinaryOperator>(OriginE))
+    if (bop->isAssignmentOp())
+      return bop->getRHS();
+  return 0;
+}
+
+QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const {
+  if (CallE) {
+    const Expr *Callee = CallE->getCallee();
+    if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl())
+      return FD->getResultType();
+    return CallE->getType();
+  }
+  return Msg.getResultType(ctx);
+}
+
+SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const {
+  assert(i < getNumArgs());
+  if (CallE) return State->getSValAsScalarOrLoc(CallE->getArg(i));
+  QualType argT = Msg.getArgType(i);
+  if (Loc::IsLocType(argT) || argT->isIntegerType())
+    return Msg.getArgSVal(i, State);
+  return UnknownVal();
+}