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/ProgramState.h"
20#include "clang/AST/ExprObjC.h"
21#include "clang/AST/ExprCXX.h"
22#include "llvm/ADT/PointerUnion.h"
23
24namespace clang {
25namespace ento {
26
27/// \brief Represents both explicit ObjC message expressions and implicit
28/// messages that are sent for handling properties in dot syntax.
29class ObjCMessage {
30  const Expr *MsgOrPropE;
31  const Expr *OriginE;
32  bool IsPropSetter;
33  SVal SetterArgV;
34
35protected:
36  ObjCMessage(const Expr *E, const Expr *origE, bool isSetter, SVal setArgV)
37    : MsgOrPropE(E), OriginE(origE),
38      IsPropSetter(isSetter), SetterArgV(setArgV) { }
39
40public:
41  ObjCMessage() : MsgOrPropE(0), OriginE(0) { }
42
43  ObjCMessage(const ObjCMessageExpr *E)
44    : MsgOrPropE(E), OriginE(E) {
45    assert(E && "should not be initialized with null expression");
46  }
47
48  bool isValid() const { return MsgOrPropE != 0; }
49  bool isInvalid() const { return !isValid(); }
50
51  bool isMessageExpr() const {
52    return isValid() && isa<ObjCMessageExpr>(MsgOrPropE);
53  }
54
55  bool isPropertyGetter() const {
56    return isValid() &&
57           isa<ObjCPropertyRefExpr>(MsgOrPropE) && !IsPropSetter;
58  }
59
60  bool isPropertySetter() const {
61    return isValid() &&
62           isa<ObjCPropertyRefExpr>(MsgOrPropE) && IsPropSetter;
63  }
64
65  const Expr *getOriginExpr() const { return OriginE; }
66
67  QualType getType(ASTContext &ctx) const;
68
69  QualType getResultType(ASTContext &ctx) const {
70    assert(isValid() && "This ObjCMessage is uninitialized!");
71    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
72      if (const ObjCMethodDecl *MD = msgE->getMethodDecl())
73        return MD->getResultType();
74    return getType(ctx);
75  }
76
77  ObjCMethodFamily getMethodFamily() const;
78
79  Selector getSelector() const;
80
81  const Expr *getInstanceReceiver() const {
82    assert(isValid() && "This ObjCMessage is uninitialized!");
83    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
84      return msgE->getInstanceReceiver();
85    const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
86    if (propE->isObjectReceiver())
87      return propE->getBase();
88    return 0;
89  }
90
91  SVal getInstanceReceiverSVal(const ProgramState *State,
92                               const LocationContext *LC) const {
93    assert(isValid() && "This ObjCMessage is uninitialized!");
94    if (!isInstanceMessage())
95      return UndefinedVal();
96    if (const Expr *Ex = getInstanceReceiver())
97      return State->getSValAsScalarOrLoc(Ex);
98
99    // An instance message with no expression means we are sending to super.
100    // In this case the object reference is the same as 'self'.
101    const ImplicitParamDecl *SelfDecl = LC->getSelfDecl();
102    assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
103    return State->getSVal(State->getRegion(SelfDecl, LC));
104  }
105
106  bool isInstanceMessage() const {
107    assert(isValid() && "This ObjCMessage is uninitialized!");
108    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
109      return msgE->isInstanceMessage();
110    const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
111    // FIXME: 'super' may be super class.
112    return propE->isObjectReceiver() || propE->isSuperReceiver();
113  }
114
115  const ObjCMethodDecl *getMethodDecl() const;
116
117  const ObjCInterfaceDecl *getReceiverInterface() const;
118
119  SourceLocation getSuperLoc() const {
120    assert(isValid() && "This ObjCMessage is uninitialized!");
121    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
122      return msgE->getSuperLoc();
123    return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getReceiverLocation();
124  }
125
126  const Expr *getMsgOrPropExpr() const {
127    assert(isValid() && "This ObjCMessage is uninitialized!");
128    return MsgOrPropE;
129  }
130
131  SourceRange getSourceRange() const {
132    assert(isValid() && "This ObjCMessage is uninitialized!");
133    return MsgOrPropE->getSourceRange();
134  }
135
136  unsigned getNumArgs() const {
137    assert(isValid() && "This ObjCMessage is uninitialized!");
138    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
139      return msgE->getNumArgs();
140    return isPropertySetter() ? 1 : 0;
141  }
142
143  SVal getArgSVal(unsigned i, const ProgramState *state) const {
144    assert(isValid() && "This ObjCMessage is uninitialized!");
145    assert(i < getNumArgs() && "Invalid index for argument");
146    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
147      return state->getSVal(msgE->getArg(i));
148    assert(isPropertySetter());
149    return SetterArgV;
150  }
151
152  QualType getArgType(unsigned i) const {
153    assert(isValid() && "This ObjCMessage is uninitialized!");
154    assert(i < getNumArgs() && "Invalid index for argument");
155    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
156      return msgE->getArg(i)->getType();
157    assert(isPropertySetter());
158    return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getType();
159  }
160
161  const Expr *getArgExpr(unsigned i) const;
162
163  SourceRange getArgSourceRange(unsigned i) const {
164    assert(isValid() && "This ObjCMessage is uninitialized!");
165    assert(i < getNumArgs() && "Invalid index for argument");
166    if (const Expr *argE = getArgExpr(i))
167      return argE->getSourceRange();
168    return OriginE->getSourceRange();
169  }
170
171  SourceRange getReceiverSourceRange() const {
172    assert(isValid() && "This ObjCMessage is uninitialized!");
173    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
174      return msgE->getReceiverRange();
175
176    const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
177    if (propE->isObjectReceiver())
178      return propE->getBase()->getSourceRange();
179
180    // FIXME: This isn't a range.
181    return propE->getReceiverLocation();
182  }
183};
184
185class ObjCPropertyGetter : public ObjCMessage {
186public:
187  ObjCPropertyGetter(const ObjCPropertyRefExpr *propE, const Expr *originE)
188    : ObjCMessage(propE, originE, false, SVal()) {
189    assert(propE && originE &&
190           "should not be initialized with null expressions");
191  }
192};
193
194class ObjCPropertySetter : public ObjCMessage {
195public:
196  ObjCPropertySetter(const ObjCPropertyRefExpr *propE, const Expr *storeE,
197                     SVal argV)
198    : ObjCMessage(propE, storeE, true, argV) {
199    assert(propE && storeE &&"should not be initialized with null expressions");
200  }
201};
202
203/// \brief Common wrapper for a call expression, ObjC message, or C++
204/// constructor, mainly to provide a common interface for their arguments.
205class CallOrObjCMessage {
206  llvm::PointerUnion<const CallExpr *, const CXXConstructExpr *> CallE;
207  ObjCMessage Msg;
208  const ProgramState *State;
209public:
210  CallOrObjCMessage(const CallExpr *callE, const ProgramState *state)
211    : CallE(callE), State(state) {}
212  CallOrObjCMessage(const CXXConstructExpr *consE, const ProgramState *state)
213    : CallE(consE), State(state) {}
214  CallOrObjCMessage(const ObjCMessage &msg, const ProgramState *state)
215    : CallE((CallExpr *)0), Msg(msg), State(state) {}
216
217  QualType getResultType(ASTContext &ctx) const;
218
219  bool isFunctionCall() const {
220    return CallE && CallE.is<const CallExpr *>();
221  }
222
223  bool isCXXConstructExpr() const {
224    return CallE && CallE.is<const CXXConstructExpr *>();
225  }
226
227  bool isObjCMessage() const {
228    return !CallE;
229  }
230
231  bool isCXXCall() const {
232    const CallExpr *ActualCallE = CallE.dyn_cast<const CallExpr *>();
233    return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE);
234  }
235
236  const Expr *getOriginExpr() const {
237    if (!CallE)
238      return Msg.getOriginExpr();
239    if (const CXXConstructExpr *Ctor =
240          CallE.dyn_cast<const CXXConstructExpr *>())
241      return Ctor;
242    return CallE.get<const CallExpr *>();
243  }
244
245  SVal getFunctionCallee() const;
246  SVal getCXXCallee() const;
247  SVal getInstanceMessageReceiver(const LocationContext *LC) const;
248
249  unsigned getNumArgs() const {
250    if (!CallE)
251      return Msg.getNumArgs();
252    if (const CXXConstructExpr *Ctor =
253          CallE.dyn_cast<const CXXConstructExpr *>())
254      return Ctor->getNumArgs();
255    return CallE.get<const CallExpr *>()->getNumArgs();
256  }
257
258  SVal getArgSVal(unsigned i) const {
259    assert(i < getNumArgs());
260    if (!CallE)
261      return Msg.getArgSVal(i, State);
262    return State->getSVal(getArg(i));
263  }
264
265  const Expr *getArg(unsigned i) const {
266    assert(i < getNumArgs());
267    if (!CallE)
268      return Msg.getArgExpr(i);
269    if (const CXXConstructExpr *Ctor =
270          CallE.dyn_cast<const CXXConstructExpr *>())
271      return Ctor->getArg(i);
272    return CallE.get<const CallExpr *>()->getArg(i);
273  }
274
275  SourceRange getArgSourceRange(unsigned i) const {
276    assert(i < getNumArgs());
277    if (CallE)
278      return getArg(i)->getSourceRange();
279    return Msg.getArgSourceRange(i);
280  }
281
282  SourceRange getReceiverSourceRange() const {
283    assert(isObjCMessage());
284    return Msg.getReceiverSourceRange();
285  }
286};
287
288}
289}
290
291#endif
292