]> CyberLeo.Net >> Repos - FreeBSD/releng/9.1.git/blob - contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
Copy stable/9 to releng/9.1 as part of the 9.1-RELEASE release process.
[FreeBSD/releng/9.1.git] / contrib / llvm / tools / clang / include / clang / StaticAnalyzer / Core / PathSensitive / ObjCMessage.h
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 "clang/Basic/SourceManager.h"
23 #include "llvm/ADT/PointerUnion.h"
24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/Support/Compiler.h"
26
27 namespace clang {
28 namespace ento {
29 using llvm::StrInStrNoCase;
30
31 /// \brief Represents both explicit ObjC message expressions and implicit
32 /// messages that are sent for handling properties in dot syntax.
33 class ObjCMessage {
34   const ObjCMessageExpr *Msg;
35   const ObjCPropertyRefExpr *PE;
36   const bool IsPropSetter;
37 public:
38   ObjCMessage() : Msg(0), PE(0), IsPropSetter(false) {}
39
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");
44   }
45
46   bool isValid() const { return Msg; }
47   
48   bool isPureMessageExpr() const { return !PE; }
49
50   bool isPropertyGetter() const { return PE && !IsPropSetter; }
51
52   bool isPropertySetter() const {
53     return IsPropSetter;
54   }
55
56   const Expr *getMessageExpr() const { 
57     return Msg;
58   }
59
60   QualType getType(ASTContext &ctx) const {
61     return Msg->getType();
62   }
63
64   QualType getResultType(ASTContext &ctx) const {
65     if (const ObjCMethodDecl *MD = Msg->getMethodDecl())
66       return MD->getResultType();
67     return getType(ctx);
68   }
69
70   ObjCMethodFamily getMethodFamily() const {
71     return Msg->getMethodFamily();
72   }
73
74   Selector getSelector() const {
75     return Msg->getSelector();
76   }
77
78   const Expr *getInstanceReceiver() const {
79     return Msg->getInstanceReceiver();
80   }
81
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);
88
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));
94   }
95
96   bool isInstanceMessage() const {
97     return Msg->isInstanceMessage();
98   }
99
100   const ObjCMethodDecl *getMethodDecl() const {
101     return Msg->getMethodDecl();
102   }
103
104   const ObjCInterfaceDecl *getReceiverInterface() const {
105     return Msg->getReceiverInterface();
106   }
107
108   SourceLocation getSuperLoc() const {
109     if (PE)
110       return PE->getReceiverLocation();
111     return Msg->getSuperLoc();
112   }  
113
114   SourceRange getSourceRange() const LLVM_READONLY {
115     if (PE)
116       return PE->getSourceRange();
117     return Msg->getSourceRange();
118   }
119
120   unsigned getNumArgs() const {
121     return Msg->getNumArgs();
122   }
123
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);
129   }
130
131   QualType getArgType(unsigned i) const {
132     assert(i < getNumArgs() && "Invalid index for argument");
133     return Msg->getArg(i)->getType();
134   }
135
136   const Expr *getArgExpr(unsigned i) const {
137     assert(i < getNumArgs() && "Invalid index for argument");
138     return Msg->getArg(i);
139   }
140
141   SourceRange getArgSourceRange(unsigned i) const {
142     const Expr *argE = getArgExpr(i);
143     return argE->getSourceRange();
144   }
145
146   SourceRange getReceiverSourceRange() const {
147     if (PE) {
148       if (PE->isObjectReceiver())
149         return PE->getBase()->getSourceRange();
150     }
151     else {
152       return Msg->getReceiverRange();
153     }
154
155     // FIXME: This isn't a range.
156     return PE->getReceiverLocation();
157   }
158 };
159
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;
164   ObjCMessage Msg;
165   ProgramStateRef State;
166   const LocationContext *LCtx;
167 public:
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) {}
177
178   QualType getResultType(ASTContext &ctx) const;
179   
180   bool isFunctionCall() const {
181     return CallE && CallE.is<const CallExpr *>();
182   }
183
184   bool isCXXConstructExpr() const {
185     return CallE && CallE.is<const CXXConstructExpr *>();
186   }
187
188   bool isObjCMessage() const {
189     return !CallE;
190   }
191
192   bool isCXXCall() const {
193     const CallExpr *ActualCallE = CallE.dyn_cast<const CallExpr *>();
194     return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE);
195   }
196
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());
203     }
204     return false;
205   }
206
207   const Expr *getOriginExpr() const {
208     if (!CallE)
209       return Msg.getMessageExpr();
210     if (const CXXConstructExpr *Ctor =
211           CallE.dyn_cast<const CXXConstructExpr *>())
212       return Ctor;
213     return CallE.get<const CallExpr *>();
214   }
215   
216   SVal getFunctionCallee() const;
217   SVal getCXXCallee() const;
218   SVal getInstanceMessageReceiver(const LocationContext *LC) const;
219
220   /// Get the declaration of the function or method.
221   const Decl *getDecl() const;
222
223   unsigned getNumArgs() const {
224     if (!CallE)
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();
230   }
231
232   SVal getArgSVal(unsigned i) const {
233     assert(i < getNumArgs());
234     if (!CallE)
235       return Msg.getArgSVal(i, LCtx, State);
236     return State->getSVal(getArg(i), LCtx);
237   }
238
239   const Expr *getArg(unsigned i) const {
240     assert(i < getNumArgs());
241     if (!CallE)
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);
247   }
248
249   SourceRange getArgSourceRange(unsigned i) const {
250     assert(i < getNumArgs());
251     if (CallE)
252       return getArg(i)->getSourceRange();
253     return Msg.getArgSourceRange(i);
254   }
255
256   SourceRange getReceiverSourceRange() const {
257     assert(isObjCMessage());
258     return Msg.getReceiverSourceRange();
259   }
260
261   /// \brief Check if the name corresponds to a CoreFoundation or CoreGraphics 
262   /// function that allows objects to escape.
263   ///
264   /// Many methods allow a tracked object to escape.  For example:
265   ///
266   ///   CFMutableDictionaryRef x = CFDictionaryCreateMutable(..., customDeallocator);
267   ///   CFDictionaryAddValue(y, key, x);
268   ///
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
272   /// escape.
273   //
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) {
284          return true;
285        }
286     return false;
287   }
288 };
289
290 }
291 }
292
293 #endif