• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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