blob: 1dd2178ad4e7a10df94731dab589448e14c5a1dc [file] [log] [blame]
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +00001//===--- Analyzer.cpp - Analysis for indexing information -------*- 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 implements the Analyzer interface.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Index/Analyzer.h"
15#include "clang/Index/Entity.h"
16#include "clang/Index/TranslationUnit.h"
17#include "clang/Index/Handlers.h"
18#include "clang/Index/ASTLocation.h"
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +000019#include "clang/Index/GlobalSelector.h"
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +000020#include "clang/Index/DeclReferenceMap.h"
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +000021#include "clang/Index/SelectorMap.h"
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +000022#include "clang/Index/IndexProvider.h"
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +000023#include "clang/AST/DeclObjC.h"
24#include "clang/AST/ExprObjC.h"
25#include "llvm/ADT/SmallSet.h"
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +000026#include "llvm/Support/Compiler.h"
27using namespace clang;
28using namespace idx;
29
30namespace {
31
32//===----------------------------------------------------------------------===//
33// DeclEntityAnalyzer Implementation
34//===----------------------------------------------------------------------===//
35
36class VISIBILITY_HIDDEN DeclEntityAnalyzer : public TranslationUnitHandler {
37 Entity Ent;
38 TULocationHandler &TULocHandler;
39
40public:
41 DeclEntityAnalyzer(Entity ent, TULocationHandler &handler)
42 : Ent(ent), TULocHandler(handler) { }
43
44 virtual void Handle(TranslationUnit *TU) {
45 assert(TU && "Passed null translation unit");
46
47 Decl *D = Ent.getDecl(TU->getASTContext());
48 assert(D && "Couldn't resolve Entity");
49
50 for (Decl::redecl_iterator I = D->redecls_begin(),
51 E = D->redecls_end(); I != E; ++I)
52 TULocHandler.Handle(TULocation(TU, ASTLocation(*I)));
53 }
54};
55
56//===----------------------------------------------------------------------===//
57// RefEntityAnalyzer Implementation
58//===----------------------------------------------------------------------===//
59
60class VISIBILITY_HIDDEN RefEntityAnalyzer : public TranslationUnitHandler {
61 Entity Ent;
62 TULocationHandler &TULocHandler;
63
64public:
65 RefEntityAnalyzer(Entity ent, TULocationHandler &handler)
66 : Ent(ent), TULocHandler(handler) { }
67
68 virtual void Handle(TranslationUnit *TU) {
69 assert(TU && "Passed null translation unit");
70
71 Decl *D = Ent.getDecl(TU->getASTContext());
72 assert(D && "Couldn't resolve Entity");
73 NamedDecl *ND = dyn_cast<NamedDecl>(D);
74 if (!ND)
75 return;
76
77 DeclReferenceMap &RefMap = TU->getDeclReferenceMap();
78 for (DeclReferenceMap::astlocation_iterator
79 I = RefMap.refs_begin(ND), E = RefMap.refs_end(ND); I != E; ++I)
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +000080 TULocHandler.Handle(TULocation(TU, *I));
81 }
82};
83
84//===----------------------------------------------------------------------===//
85// RefSelectorAnalyzer Implementation
86//===----------------------------------------------------------------------===//
87
88/// \brief Accepts an ObjC method and finds all message expressions that this
89/// method may respond to.
90class VISIBILITY_HIDDEN RefSelectorAnalyzer : public TranslationUnitHandler {
91 Program &Prog;
92 TULocationHandler &TULocHandler;
93
94 // The original ObjCInterface associated with the method.
95 Entity IFaceEnt;
96 GlobalSelector GlobSel;
97 bool IsInstanceMethod;
98
99 /// \brief Super classes of the ObjCInterface.
100 typedef llvm::SmallSet<Entity, 16> EntitiesSetTy;
101 EntitiesSetTy HierarchyEntities;
102
103public:
104 RefSelectorAnalyzer(ObjCMethodDecl *MD,
105 Program &prog, TULocationHandler &handler)
106 : Prog(prog), TULocHandler(handler) {
107 assert(MD);
108
109 // FIXME: Protocol methods.
110 assert(!isa<ObjCProtocolDecl>(MD->getDeclContext()) &&
111 "Protocol methods not supported yet");
112
113 ObjCInterfaceDecl *IFD = MD->getClassInterface();
114 assert(IFD);
115 IFaceEnt = Entity::get(IFD, Prog);
116 GlobSel = GlobalSelector::get(MD->getSelector(), Prog);
117 IsInstanceMethod = MD->isInstanceMethod();
118
119 for (ObjCInterfaceDecl *Cls = IFD->getSuperClass();
120 Cls; Cls = Cls->getSuperClass())
121 HierarchyEntities.insert(Entity::get(Cls, Prog));
122 }
123
124 virtual void Handle(TranslationUnit *TU) {
125 assert(TU && "Passed null translation unit");
126
127 ASTContext &Ctx = TU->getASTContext();
128 // Null means it doesn't exist in this translation unit.
129 ObjCInterfaceDecl *IFace =
130 cast_or_null<ObjCInterfaceDecl>(IFaceEnt.getDecl(Ctx));
131 Selector Sel = GlobSel.getSelector(Ctx);
132
133 SelectorMap &SelMap = TU->getSelectorMap();
134 for (SelectorMap::astlocation_iterator
135 I = SelMap.refs_begin(Sel), E = SelMap.refs_end(Sel); I != E; ++I) {
136 if (ValidReference(*I, IFace))
137 TULocHandler.Handle(TULocation(TU, *I));
138 }
139 }
140
141 /// \brief Determines whether the given message expression is likely to end
142 /// up at the given interface decl.
143 ///
144 /// It returns true "eagerly", meaning it will return false only if it can
145 /// "prove" statically that the interface cannot accept this message.
146 bool ValidReference(ASTLocation ASTLoc, ObjCInterfaceDecl *IFace) {
147 assert(ASTLoc.isValid());
148 assert(ASTLoc.isStmt());
149
150 // FIXME: Finding @selector references should be through another Analyzer
151 // method, like FindSelectors.
152 if (isa<ObjCSelectorExpr>(ASTLoc.getStmt()))
153 return false;
154
155 ObjCInterfaceDecl *MsgD = 0;
156 ObjCMessageExpr *Msg = cast<ObjCMessageExpr>(ASTLoc.getStmt());
157
158 if (Msg->getReceiver()) {
159 const ObjCObjectPointerType *OPT =
160 Msg->getReceiver()->getType()->getAsObjCInterfacePointerType();
161
162 // Can be anything! Accept it as a possibility..
163 if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType())
164 return true;
165
166 // Expecting class method.
167 if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType())
168 return !IsInstanceMethod;
169
170 MsgD = OPT->getInterfaceDecl();
171 assert(MsgD);
172
173 // Should be an instance method.
174 if (!IsInstanceMethod)
175 return false;
176
177 } else {
178 // Expecting class method.
179 if (IsInstanceMethod)
180 return false;
181
182 MsgD = Msg->getClassInfo().first;
183 // FIXME: Case when we only have an identifier.
184 assert(MsgD && "Identifier only");
185 }
186
187 assert(MsgD);
188
189 // Same interface ? We have a winner!
190 if (MsgD == IFace)
191 return true;
192
193 // If the message interface is a superclass of the original interface,
194 // accept this message as a possibility.
195 if (HierarchyEntities.count(Entity::get(MsgD, Prog)))
196 return true;
197
198 // If the message interface is a subclass of the original interface, accept
199 // the message unless there is a subclass in the hierarchy that will
200 // "steal" the message (thus the message "will go" to the subclass and not
201 /// the original interface).
202 if (IFace) {
203 Selector Sel = Msg->getSelector();
204 for (ObjCInterfaceDecl *Cls = MsgD; Cls; Cls = Cls->getSuperClass()) {
205 if (Cls == IFace)
206 return true;
207 if (Cls->getMethod(Sel, IsInstanceMethod))
208 return false;
209 }
210 }
211
212 // The interfaces are unrelated, don't accept the message.
213 return false;
214 }
215};
216
217//===----------------------------------------------------------------------===//
218// MessageAnalyzer Implementation
219//===----------------------------------------------------------------------===//
220
221/// \brief Accepts an ObjC message expression and finds all methods that may
222/// respond to it.
223class VISIBILITY_HIDDEN MessageAnalyzer : public TranslationUnitHandler {
224 Program &Prog;
225 TULocationHandler &TULocHandler;
226
227 // The ObjCInterface associated with the message. Can be null/invalid.
228 Entity MsgIFaceEnt;
229 GlobalSelector GlobSel;
230 bool CanBeInstanceMethod;
231 bool CanBeClassMethod;
232
233 /// \brief Super classes of the ObjCInterface.
234 typedef llvm::SmallSet<Entity, 16> EntitiesSetTy;
235 EntitiesSetTy HierarchyEntities;
236
237 /// \brief The interface in the message interface hierarchy that "intercepts"
238 /// the selector.
239 Entity ReceiverIFaceEnt;
240
241public:
242 MessageAnalyzer(ObjCMessageExpr *Msg,
243 Program &prog, TULocationHandler &handler)
244 : Prog(prog), TULocHandler(handler),
245 CanBeInstanceMethod(false),
246 CanBeClassMethod(false) {
247
248 assert(Msg);
249
250 ObjCInterfaceDecl *MsgD = 0;
251
252 while (true) {
253 if (Msg->getReceiver() == 0) {
254 CanBeClassMethod = true;
255 MsgD = Msg->getClassInfo().first;
256 // FIXME: Case when we only have an identifier.
257 assert(MsgD && "Identifier only");
258 break;
259 }
260
261 const ObjCObjectPointerType *OPT =
262 Msg->getReceiver()->getType()->getAsObjCInterfacePointerType();
263
264 if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) {
265 CanBeInstanceMethod = CanBeClassMethod = true;
266 break;
267 }
268
269 if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) {
270 CanBeClassMethod = true;
271 break;
272 }
273
274 MsgD = OPT->getInterfaceDecl();
275 assert(MsgD);
276 CanBeInstanceMethod = true;
277 break;
278 }
279
280 assert(CanBeInstanceMethod || CanBeClassMethod);
281
282 Selector sel = Msg->getSelector();
283 assert(!sel.isNull());
284
285 MsgIFaceEnt = Entity::get(MsgD, Prog);
286 GlobSel = GlobalSelector::get(sel, Prog);
287
288 if (MsgD) {
289 for (ObjCInterfaceDecl *Cls = MsgD->getSuperClass();
290 Cls; Cls = Cls->getSuperClass())
291 HierarchyEntities.insert(Entity::get(Cls, Prog));
292
293 // Find the interface in the hierarchy that "receives" the message.
294 for (ObjCInterfaceDecl *Cls = MsgD; Cls; Cls = Cls->getSuperClass()) {
295 bool isReceiver = false;
296
297 ObjCInterfaceDecl::lookup_const_iterator Meth, MethEnd;
298 for (llvm::tie(Meth, MethEnd) = Cls->lookup(sel);
299 Meth != MethEnd; ++Meth) {
300 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth))
301 if ((MD->isInstanceMethod() && CanBeInstanceMethod) ||
302 (MD->isClassMethod() && CanBeClassMethod)) {
303 isReceiver = true;
304 break;
305 }
306 }
307
308 if (isReceiver) {
309 ReceiverIFaceEnt = Entity::get(Cls, Prog);
310 break;
311 }
312 }
313 }
314 }
315
316 virtual void Handle(TranslationUnit *TU) {
317 assert(TU && "Passed null translation unit");
318 ASTContext &Ctx = TU->getASTContext();
319
320 // Null means it doesn't exist in this translation unit or there was no
321 // interface that was determined to receive the original message.
322 ObjCInterfaceDecl *ReceiverIFace =
323 cast_or_null<ObjCInterfaceDecl>(ReceiverIFaceEnt.getDecl(Ctx));
324
325 // No subclass for the original receiver interface, so it remains the
326 // receiver.
327 if (ReceiverIFaceEnt.isValid() && ReceiverIFace == 0)
328 return;
329
330 // Null means it doesn't exist in this translation unit or there was no
331 // interface associated with the message in the first place.
332 ObjCInterfaceDecl *MsgIFace =
333 cast_or_null<ObjCInterfaceDecl>(MsgIFaceEnt.getDecl(Ctx));
334
335 Selector Sel = GlobSel.getSelector(Ctx);
336 SelectorMap &SelMap = TU->getSelectorMap();
337 for (SelectorMap::method_iterator
338 I = SelMap.methods_begin(Sel), E = SelMap.methods_end(Sel);
339 I != E; ++I) {
340 ObjCMethodDecl *D = *I;
341 if (ValidMethod(D, MsgIFace, ReceiverIFace)) {
342 for (ObjCMethodDecl::redecl_iterator
343 RI = D->redecls_begin(), RE = D->redecls_end(); RI != RE; ++RI)
344 TULocHandler.Handle(TULocation(TU, ASTLocation(*RI)));
345 }
346 }
347 }
348
349 /// \brief Determines whether the given method is likely to accept the
350 /// original message.
351 ///
352 /// It returns true "eagerly", meaning it will return false only if it can
353 /// "prove" statically that the method cannot accept the original message.
354 bool ValidMethod(ObjCMethodDecl *D, ObjCInterfaceDecl *MsgIFace,
355 ObjCInterfaceDecl *ReceiverIFace) {
356 assert(D);
357
358 // FIXME: Protocol methods ?
359 if (isa<ObjCProtocolDecl>(D->getDeclContext()))
360 return false;
361
362 // No specific interface associated with the message. Can be anything.
363 if (MsgIFaceEnt.isInvalid())
364 return true;
365
Eli Friedmanbebc4672009-07-30 00:11:31 +0000366 if ((!CanBeInstanceMethod && D->isInstanceMethod()) ||
367 (!CanBeClassMethod && D->isClassMethod()))
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000368 return false;
369
370 ObjCInterfaceDecl *IFace = D->getClassInterface();
371 assert(IFace);
372
373 // If the original message interface is the same or a superclass of the
374 // given interface, accept the method as a possibility.
375 if (MsgIFace && MsgIFace->isSuperClassOf(IFace))
376 return true;
377
378 if (ReceiverIFace) {
379 // The given interface, "overrides" the receiver.
380 if (ReceiverIFace->isSuperClassOf(IFace))
381 return true;
382 } else {
383 // No receiver was found for the original message.
384 assert(ReceiverIFaceEnt.isInvalid());
385
386 // If the original message interface is a subclass of the given interface,
387 // accept the message.
388 if (HierarchyEntities.count(Entity::get(IFace, Prog)))
389 return true;
390 }
391
392 // The interfaces are unrelated, or the receiver interface wasn't
393 // "overriden".
394 return false;
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000395 }
396};
397
398} // end anonymous namespace
399
400//===----------------------------------------------------------------------===//
401// Analyzer Implementation
402//===----------------------------------------------------------------------===//
403
404void Analyzer::FindDeclarations(Decl *D, TULocationHandler &Handler) {
405 assert(D && "Passed null declaration");
406 Entity Ent = Entity::get(D, Prog);
407 if (Ent.isInvalid())
408 return;
409
410 DeclEntityAnalyzer DEA(Ent, Handler);
411 Idxer.GetTranslationUnitsFor(Ent, DEA);
412}
413
414void Analyzer::FindReferences(Decl *D, TULocationHandler &Handler) {
415 assert(D && "Passed null declaration");
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000416 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
417 RefSelectorAnalyzer RSA(MD, Prog, Handler);
418 GlobalSelector Sel = GlobalSelector::get(MD->getSelector(), Prog);
419 Idxer.GetTranslationUnitsFor(Sel, RSA);
420 return;
421 }
422
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000423 Entity Ent = Entity::get(D, Prog);
424 if (Ent.isInvalid())
425 return;
426
427 RefEntityAnalyzer REA(Ent, Handler);
428 Idxer.GetTranslationUnitsFor(Ent, REA);
429}
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000430
431/// \brief Find methods that may respond to the given message and pass them
432/// to Handler.
433void Analyzer::FindObjCMethods(ObjCMessageExpr *Msg,
434 TULocationHandler &Handler) {
435 assert(Msg);
436 MessageAnalyzer MsgAnalyz(Msg, Prog, Handler);
437 GlobalSelector GlobSel = GlobalSelector::get(Msg->getSelector(), Prog);
438 Idxer.GetTranslationUnitsFor(GlobSel, MsgAnalyz);
439}