1 //===- ObjCMessage.h - Wrapper for ObjC messages and dot syntax ---*- C++ -*--//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines ObjCMessage which serves as a common wrapper for ObjC
11 // message expressions or implicit messages for loading/storing ObjC properties.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
16 #define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
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 "clang/Basic/SourceManager.h"
23 #include "llvm/ADT/PointerUnion.h"
24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/Support/Compiler.h"
29 using llvm::StrInStrNoCase;
31 /// \brief Represents both explicit ObjC message expressions and implicit
32 /// messages that are sent for handling properties in dot syntax.
34 const ObjCMessageExpr *Msg;
35 const ObjCPropertyRefExpr *PE;
36 const bool IsPropSetter;
38 ObjCMessage() : Msg(0), PE(0), IsPropSetter(false) {}
40 ObjCMessage(const ObjCMessageExpr *E, const ObjCPropertyRefExpr *pe = 0,
41 bool isSetter = false)
42 : Msg(E), PE(pe), IsPropSetter(isSetter) {
43 assert(E && "should not be initialized with null expression");
46 bool isValid() const { return Msg; }
48 bool isPureMessageExpr() const { return !PE; }
50 bool isPropertyGetter() const { return PE && !IsPropSetter; }
52 bool isPropertySetter() const {
56 const Expr *getMessageExpr() const {
60 QualType getType(ASTContext &ctx) const {
61 return Msg->getType();
64 QualType getResultType(ASTContext &ctx) const {
65 if (const ObjCMethodDecl *MD = Msg->getMethodDecl())
66 return MD->getResultType();
70 ObjCMethodFamily getMethodFamily() const {
71 return Msg->getMethodFamily();
74 Selector getSelector() const {
75 return Msg->getSelector();
78 const Expr *getInstanceReceiver() const {
79 return Msg->getInstanceReceiver();
82 SVal getInstanceReceiverSVal(ProgramStateRef State,
83 const LocationContext *LC) const {
84 if (!isInstanceMessage())
85 return UndefinedVal();
86 if (const Expr *Ex = getInstanceReceiver())
87 return State->getSValAsScalarOrLoc(Ex, LC);
89 // An instance message with no expression means we are sending to super.
90 // In this case the object reference is the same as 'self'.
91 const ImplicitParamDecl *SelfDecl = LC->getSelfDecl();
92 assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
93 return State->getSVal(State->getRegion(SelfDecl, LC));
96 bool isInstanceMessage() const {
97 return Msg->isInstanceMessage();
100 const ObjCMethodDecl *getMethodDecl() const {
101 return Msg->getMethodDecl();
104 const ObjCInterfaceDecl *getReceiverInterface() const {
105 return Msg->getReceiverInterface();
108 SourceLocation getSuperLoc() const {
110 return PE->getReceiverLocation();
111 return Msg->getSuperLoc();
114 SourceRange getSourceRange() const LLVM_READONLY {
116 return PE->getSourceRange();
117 return Msg->getSourceRange();
120 unsigned getNumArgs() const {
121 return Msg->getNumArgs();
124 SVal getArgSVal(unsigned i,
125 const LocationContext *LCtx,
126 ProgramStateRef state) const {
127 assert(i < getNumArgs() && "Invalid index for argument");
128 return state->getSVal(Msg->getArg(i), LCtx);
131 QualType getArgType(unsigned i) const {
132 assert(i < getNumArgs() && "Invalid index for argument");
133 return Msg->getArg(i)->getType();
136 const Expr *getArgExpr(unsigned i) const {
137 assert(i < getNumArgs() && "Invalid index for argument");
138 return Msg->getArg(i);
141 SourceRange getArgSourceRange(unsigned i) const {
142 const Expr *argE = getArgExpr(i);
143 return argE->getSourceRange();
146 SourceRange getReceiverSourceRange() const {
148 if (PE->isObjectReceiver())
149 return PE->getBase()->getSourceRange();
152 return Msg->getReceiverRange();
155 // FIXME: This isn't a range.
156 return PE->getReceiverLocation();
160 /// \brief Common wrapper for a call expression, ObjC message, or C++
161 /// constructor, mainly to provide a common interface for their arguments.
162 class CallOrObjCMessage {
163 llvm::PointerUnion<const CallExpr *, const CXXConstructExpr *> CallE;
165 ProgramStateRef State;
166 const LocationContext *LCtx;
168 CallOrObjCMessage(const CallExpr *callE, ProgramStateRef state,
169 const LocationContext *lctx)
170 : CallE(callE), State(state), LCtx(lctx) {}
171 CallOrObjCMessage(const CXXConstructExpr *consE, ProgramStateRef state,
172 const LocationContext *lctx)
173 : CallE(consE), State(state), LCtx(lctx) {}
174 CallOrObjCMessage(const ObjCMessage &msg, ProgramStateRef state,
175 const LocationContext *lctx)
176 : CallE((CallExpr *)0), Msg(msg), State(state), LCtx(lctx) {}
178 QualType getResultType(ASTContext &ctx) const;
180 bool isFunctionCall() const {
181 return CallE && CallE.is<const CallExpr *>();
184 bool isCXXConstructExpr() const {
185 return CallE && CallE.is<const CXXConstructExpr *>();
188 bool isObjCMessage() const {
192 bool isCXXCall() const {
193 const CallExpr *ActualCallE = CallE.dyn_cast<const CallExpr *>();
194 return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE);
197 /// Check if the callee is declared in the system header.
198 bool isInSystemHeader() const {
199 if (const Decl *FD = getDecl()) {
200 const SourceManager &SM =
201 State->getStateManager().getContext().getSourceManager();
202 return SM.isInSystemHeader(FD->getLocation());
207 const Expr *getOriginExpr() const {
209 return Msg.getMessageExpr();
210 if (const CXXConstructExpr *Ctor =
211 CallE.dyn_cast<const CXXConstructExpr *>())
213 return CallE.get<const CallExpr *>();
216 SVal getFunctionCallee() const;
217 SVal getCXXCallee() const;
218 SVal getInstanceMessageReceiver(const LocationContext *LC) const;
220 /// Get the declaration of the function or method.
221 const Decl *getDecl() const;
223 unsigned getNumArgs() const {
225 return Msg.getNumArgs();
226 if (const CXXConstructExpr *Ctor =
227 CallE.dyn_cast<const CXXConstructExpr *>())
228 return Ctor->getNumArgs();
229 return CallE.get<const CallExpr *>()->getNumArgs();
232 SVal getArgSVal(unsigned i) const {
233 assert(i < getNumArgs());
235 return Msg.getArgSVal(i, LCtx, State);
236 return State->getSVal(getArg(i), LCtx);
239 const Expr *getArg(unsigned i) const {
240 assert(i < getNumArgs());
242 return Msg.getArgExpr(i);
243 if (const CXXConstructExpr *Ctor =
244 CallE.dyn_cast<const CXXConstructExpr *>())
245 return Ctor->getArg(i);
246 return CallE.get<const CallExpr *>()->getArg(i);
249 SourceRange getArgSourceRange(unsigned i) const {
250 assert(i < getNumArgs());
252 return getArg(i)->getSourceRange();
253 return Msg.getArgSourceRange(i);
256 SourceRange getReceiverSourceRange() const {
257 assert(isObjCMessage());
258 return Msg.getReceiverSourceRange();
261 /// \brief Check if the name corresponds to a CoreFoundation or CoreGraphics
262 /// function that allows objects to escape.
264 /// Many methods allow a tracked object to escape. For example:
266 /// CFMutableDictionaryRef x = CFDictionaryCreateMutable(..., customDeallocator);
267 /// CFDictionaryAddValue(y, key, x);
269 /// We handle this and similar cases with the following heuristic. If the
270 /// function name contains "InsertValue", "SetValue", "AddValue",
271 /// "AppendValue", or "SetAttribute", then we assume that arguments may
274 // TODO: To reduce false negatives here, we should track the container
275 // allocation site and check if a proper deallocator was set there.
276 static bool isCFCGAllowingEscape(StringRef FName) {
277 if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G'))
278 if (StrInStrNoCase(FName, "InsertValue") != StringRef::npos||
279 StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
280 StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
281 StrInStrNoCase(FName, "WithData") != StringRef::npos ||
282 StrInStrNoCase(FName, "AppendValue") != StringRef::npos||
283 StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) {