1 //===- ObjCMessage.h - Wrapper for ObjC messages and dot syntax ---*- C++ -*--// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines ObjCMessage which serves as a common wrapper for ObjC 11 // message expressions or implicit messages for loading/storing ObjC properties. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE 16 #define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE 17 18 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 19 #include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" 20 #include "clang/AST/ExprObjC.h" 21 22 namespace clang { 23 namespace ento { 24 25 /// \brief Represents both explicit ObjC message expressions and implicit 26 /// messages that are sent for handling properties in dot syntax. 27 class ObjCMessage { 28 const Expr *MsgOrPropE; 29 const Expr *OriginE; 30 bool IsPropSetter; 31 SVal SetterArgV; 32 33 protected: ObjCMessage(const Expr * E,const Expr * origE,bool isSetter,SVal setArgV)34 ObjCMessage(const Expr *E, const Expr *origE, bool isSetter, SVal setArgV) 35 : MsgOrPropE(E), OriginE(origE), 36 IsPropSetter(isSetter), SetterArgV(setArgV) { } 37 38 public: ObjCMessage()39 ObjCMessage() : MsgOrPropE(0), OriginE(0) { } 40 ObjCMessage(const ObjCMessageExpr * E)41 ObjCMessage(const ObjCMessageExpr *E) 42 : MsgOrPropE(E), OriginE(E) { 43 assert(E && "should not be initialized with null expression"); 44 } 45 isValid()46 bool isValid() const { return MsgOrPropE != 0; } isInvalid()47 bool isInvalid() const { return !isValid(); } 48 isMessageExpr()49 bool isMessageExpr() const { 50 return isValid() && isa<ObjCMessageExpr>(MsgOrPropE); 51 } 52 isPropertyGetter()53 bool isPropertyGetter() const { 54 return isValid() && 55 isa<ObjCPropertyRefExpr>(MsgOrPropE) && !IsPropSetter; 56 } 57 isPropertySetter()58 bool isPropertySetter() const { 59 return isValid() && 60 isa<ObjCPropertyRefExpr>(MsgOrPropE) && IsPropSetter; 61 } 62 getOriginExpr()63 const Expr *getOriginExpr() const { return OriginE; } 64 65 QualType getType(ASTContext &ctx) const; 66 getResultType(ASTContext & ctx)67 QualType getResultType(ASTContext &ctx) const { 68 assert(isValid() && "This ObjCMessage is uninitialized!"); 69 if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) 70 if (const ObjCMethodDecl *MD = msgE->getMethodDecl()) 71 return MD->getResultType(); 72 return getType(ctx); 73 } 74 75 ObjCMethodFamily getMethodFamily() const; 76 77 Selector getSelector() const; 78 getInstanceReceiver()79 const Expr *getInstanceReceiver() const { 80 assert(isValid() && "This ObjCMessage is uninitialized!"); 81 if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) 82 return msgE->getInstanceReceiver(); 83 const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE); 84 if (propE->isObjectReceiver()) 85 return propE->getBase(); 86 return 0; 87 } 88 isInstanceMessage()89 bool isInstanceMessage() const { 90 assert(isValid() && "This ObjCMessage is uninitialized!"); 91 if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) 92 return msgE->isInstanceMessage(); 93 const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE); 94 // FIXME: 'super' may be super class. 95 return propE->isObjectReceiver() || propE->isSuperReceiver(); 96 } 97 98 const ObjCMethodDecl *getMethodDecl() const; 99 100 const ObjCInterfaceDecl *getReceiverInterface() const; 101 getSuperLoc()102 SourceLocation getSuperLoc() const { 103 assert(isValid() && "This ObjCMessage is uninitialized!"); 104 if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) 105 return msgE->getSuperLoc(); 106 return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getReceiverLocation(); 107 } 108 getSourceRange()109 SourceRange getSourceRange() const { 110 assert(isValid() && "This ObjCMessage is uninitialized!"); 111 return MsgOrPropE->getSourceRange(); 112 } 113 getNumArgs()114 unsigned getNumArgs() const { 115 assert(isValid() && "This ObjCMessage is uninitialized!"); 116 if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) 117 return msgE->getNumArgs(); 118 return isPropertySetter() ? 1 : 0; 119 } 120 getArgSVal(unsigned i,const GRState * state)121 SVal getArgSVal(unsigned i, const GRState *state) const { 122 assert(isValid() && "This ObjCMessage is uninitialized!"); 123 assert(i < getNumArgs() && "Invalid index for argument"); 124 if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) 125 return state->getSVal(msgE->getArg(i)); 126 assert(isPropertySetter()); 127 return SetterArgV; 128 } 129 getArgType(unsigned i)130 QualType getArgType(unsigned i) const { 131 assert(isValid() && "This ObjCMessage is uninitialized!"); 132 assert(i < getNumArgs() && "Invalid index for argument"); 133 if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) 134 return msgE->getArg(i)->getType(); 135 assert(isPropertySetter()); 136 return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getType(); 137 } 138 139 const Expr *getArgExpr(unsigned i) const; 140 getArgSourceRange(unsigned i)141 SourceRange getArgSourceRange(unsigned i) const { 142 assert(isValid() && "This ObjCMessage is uninitialized!"); 143 assert(i < getNumArgs() && "Invalid index for argument"); 144 if (const Expr *argE = getArgExpr(i)) 145 return argE->getSourceRange(); 146 return OriginE->getSourceRange(); 147 } 148 }; 149 150 class ObjCPropertyGetter : public ObjCMessage { 151 public: ObjCPropertyGetter(const ObjCPropertyRefExpr * propE,const Expr * originE)152 ObjCPropertyGetter(const ObjCPropertyRefExpr *propE, const Expr *originE) 153 : ObjCMessage(propE, originE, false, SVal()) { 154 assert(propE && originE && 155 "should not be initialized with null expressions"); 156 } 157 }; 158 159 class ObjCPropertySetter : public ObjCMessage { 160 public: ObjCPropertySetter(const ObjCPropertyRefExpr * propE,const Expr * storeE,SVal argV)161 ObjCPropertySetter(const ObjCPropertyRefExpr *propE, const Expr *storeE, 162 SVal argV) 163 : ObjCMessage(propE, storeE, true, argV) { 164 assert(propE && storeE &&"should not be initialized with null expressions"); 165 } 166 }; 167 168 /// \brief Common wrapper for a call expression or an ObjC message, mainly to 169 /// provide a common interface for handling their arguments. 170 class CallOrObjCMessage { 171 const CallExpr *CallE; 172 ObjCMessage Msg; 173 const GRState *State; 174 public: CallOrObjCMessage(const CallExpr * callE,const GRState * state)175 CallOrObjCMessage(const CallExpr *callE, const GRState *state) 176 : CallE(callE), State(state) {} CallOrObjCMessage(const ObjCMessage & msg,const GRState * state)177 CallOrObjCMessage(const ObjCMessage &msg, const GRState *state) 178 : CallE(0), Msg(msg), State(state) {} 179 180 QualType getResultType(ASTContext &ctx) const; 181 isFunctionCall()182 bool isFunctionCall() const { 183 return (bool) CallE; 184 } 185 isCXXCall()186 bool isCXXCall() const { 187 return CallE && isa<CXXMemberCallExpr>(CallE); 188 } 189 190 SVal getFunctionCallee() const; 191 SVal getCXXCallee() const; 192 getNumArgs()193 unsigned getNumArgs() const { 194 if (CallE) return CallE->getNumArgs(); 195 return Msg.getNumArgs(); 196 } 197 getArgSVal(unsigned i)198 SVal getArgSVal(unsigned i) const { 199 assert(i < getNumArgs()); 200 if (CallE) 201 return State->getSVal(CallE->getArg(i)); 202 return Msg.getArgSVal(i, State); 203 } 204 205 SVal getArgSValAsScalarOrLoc(unsigned i) const; 206 getArg(unsigned i)207 const Expr *getArg(unsigned i) const { 208 assert(i < getNumArgs()); 209 if (CallE) 210 return CallE->getArg(i); 211 return Msg.getArgExpr(i); 212 } 213 getArgSourceRange(unsigned i)214 SourceRange getArgSourceRange(unsigned i) const { 215 assert(i < getNumArgs()); 216 if (CallE) 217 return CallE->getArg(i)->getSourceRange(); 218 return Msg.getArgSourceRange(i); 219 } 220 }; 221 222 } 223 } 224 225 #endif 226