blob: 300a469220566d95a91055a237cc692a81c83510 [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;
Mike Stump1eb44332009-09-09 15:08:12 +000039
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +000040public:
41 DeclEntityAnalyzer(Entity ent, TULocationHandler &handler)
42 : Ent(ent), TULocHandler(handler) { }
Mike Stump1eb44332009-09-09 15:08:12 +000043
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +000044 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;
Mike Stump1eb44332009-09-09 15:08:12 +000063
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +000064public:
65 RefEntityAnalyzer(Entity ent, TULocationHandler &handler)
66 : Ent(ent), TULocHandler(handler) { }
Mike Stump1eb44332009-09-09 15:08:12 +000067
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +000068 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();
Mike Stump1eb44332009-09-09 15:08:12 +0000118
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000119 for (ObjCInterfaceDecl *Cls = IFD->getSuperClass();
120 Cls; Cls = Cls->getSuperClass())
121 HierarchyEntities.insert(Entity::get(Cls, Prog));
122 }
Mike Stump1eb44332009-09-09 15:08:12 +0000123
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000124 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) {
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000147 assert(ASTLoc.isStmt());
148
149 // FIXME: Finding @selector references should be through another Analyzer
150 // method, like FindSelectors.
Argyrios Kyrtzidisf4526e32009-09-29 19:44:27 +0000151 if (isa<ObjCSelectorExpr>(ASTLoc.AsStmt()))
Mike Stump1eb44332009-09-09 15:08:12 +0000152 return false;
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000153
154 ObjCInterfaceDecl *MsgD = 0;
Argyrios Kyrtzidisf4526e32009-09-29 19:44:27 +0000155 ObjCMessageExpr *Msg = cast<ObjCMessageExpr>(ASTLoc.AsStmt());
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000156
157 if (Msg->getReceiver()) {
158 const ObjCObjectPointerType *OPT =
159 Msg->getReceiver()->getType()->getAsObjCInterfacePointerType();
160
161 // Can be anything! Accept it as a possibility..
162 if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType())
163 return true;
164
165 // Expecting class method.
166 if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType())
167 return !IsInstanceMethod;
168
169 MsgD = OPT->getInterfaceDecl();
170 assert(MsgD);
171
172 // Should be an instance method.
173 if (!IsInstanceMethod)
174 return false;
175
176 } else {
177 // Expecting class method.
178 if (IsInstanceMethod)
179 return false;
180
181 MsgD = Msg->getClassInfo().first;
182 // FIXME: Case when we only have an identifier.
Mike Stump1eb44332009-09-09 15:08:12 +0000183 assert(MsgD && "Identifier only");
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000184 }
185
186 assert(MsgD);
187
188 // Same interface ? We have a winner!
189 if (MsgD == IFace)
190 return true;
191
192 // If the message interface is a superclass of the original interface,
193 // accept this message as a possibility.
194 if (HierarchyEntities.count(Entity::get(MsgD, Prog)))
195 return true;
196
197 // If the message interface is a subclass of the original interface, accept
198 // the message unless there is a subclass in the hierarchy that will
199 // "steal" the message (thus the message "will go" to the subclass and not
200 /// the original interface).
201 if (IFace) {
202 Selector Sel = Msg->getSelector();
203 for (ObjCInterfaceDecl *Cls = MsgD; Cls; Cls = Cls->getSuperClass()) {
204 if (Cls == IFace)
205 return true;
206 if (Cls->getMethod(Sel, IsInstanceMethod))
207 return false;
208 }
209 }
210
211 // The interfaces are unrelated, don't accept the message.
212 return false;
213 }
214};
215
216//===----------------------------------------------------------------------===//
217// MessageAnalyzer Implementation
218//===----------------------------------------------------------------------===//
219
220/// \brief Accepts an ObjC message expression and finds all methods that may
221/// respond to it.
222class VISIBILITY_HIDDEN MessageAnalyzer : public TranslationUnitHandler {
223 Program &Prog;
224 TULocationHandler &TULocHandler;
225
226 // The ObjCInterface associated with the message. Can be null/invalid.
227 Entity MsgIFaceEnt;
228 GlobalSelector GlobSel;
229 bool CanBeInstanceMethod;
230 bool CanBeClassMethod;
231
232 /// \brief Super classes of the ObjCInterface.
233 typedef llvm::SmallSet<Entity, 16> EntitiesSetTy;
234 EntitiesSetTy HierarchyEntities;
Mike Stump1eb44332009-09-09 15:08:12 +0000235
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000236 /// \brief The interface in the message interface hierarchy that "intercepts"
237 /// the selector.
238 Entity ReceiverIFaceEnt;
239
240public:
241 MessageAnalyzer(ObjCMessageExpr *Msg,
242 Program &prog, TULocationHandler &handler)
243 : Prog(prog), TULocHandler(handler),
244 CanBeInstanceMethod(false),
245 CanBeClassMethod(false) {
246
247 assert(Msg);
248
249 ObjCInterfaceDecl *MsgD = 0;
250
251 while (true) {
252 if (Msg->getReceiver() == 0) {
253 CanBeClassMethod = true;
254 MsgD = Msg->getClassInfo().first;
255 // FIXME: Case when we only have an identifier.
Mike Stump1eb44332009-09-09 15:08:12 +0000256 assert(MsgD && "Identifier only");
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000257 break;
258 }
259
260 const ObjCObjectPointerType *OPT =
261 Msg->getReceiver()->getType()->getAsObjCInterfacePointerType();
262
263 if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) {
264 CanBeInstanceMethod = CanBeClassMethod = true;
265 break;
266 }
267
268 if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) {
269 CanBeClassMethod = true;
270 break;
271 }
272
273 MsgD = OPT->getInterfaceDecl();
274 assert(MsgD);
275 CanBeInstanceMethod = true;
276 break;
277 }
Mike Stump1eb44332009-09-09 15:08:12 +0000278
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000279 assert(CanBeInstanceMethod || CanBeClassMethod);
280
281 Selector sel = Msg->getSelector();
282 assert(!sel.isNull());
283
284 MsgIFaceEnt = Entity::get(MsgD, Prog);
285 GlobSel = GlobalSelector::get(sel, Prog);
286
287 if (MsgD) {
288 for (ObjCInterfaceDecl *Cls = MsgD->getSuperClass();
289 Cls; Cls = Cls->getSuperClass())
290 HierarchyEntities.insert(Entity::get(Cls, Prog));
291
292 // Find the interface in the hierarchy that "receives" the message.
293 for (ObjCInterfaceDecl *Cls = MsgD; Cls; Cls = Cls->getSuperClass()) {
294 bool isReceiver = false;
295
296 ObjCInterfaceDecl::lookup_const_iterator Meth, MethEnd;
297 for (llvm::tie(Meth, MethEnd) = Cls->lookup(sel);
298 Meth != MethEnd; ++Meth) {
299 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth))
300 if ((MD->isInstanceMethod() && CanBeInstanceMethod) ||
301 (MD->isClassMethod() && CanBeClassMethod)) {
302 isReceiver = true;
303 break;
304 }
305 }
Mike Stump1eb44332009-09-09 15:08:12 +0000306
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000307 if (isReceiver) {
308 ReceiverIFaceEnt = Entity::get(Cls, Prog);
309 break;
310 }
311 }
312 }
313 }
Mike Stump1eb44332009-09-09 15:08:12 +0000314
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000315 virtual void Handle(TranslationUnit *TU) {
316 assert(TU && "Passed null translation unit");
317 ASTContext &Ctx = TU->getASTContext();
318
319 // Null means it doesn't exist in this translation unit or there was no
320 // interface that was determined to receive the original message.
321 ObjCInterfaceDecl *ReceiverIFace =
322 cast_or_null<ObjCInterfaceDecl>(ReceiverIFaceEnt.getDecl(Ctx));
323
324 // No subclass for the original receiver interface, so it remains the
325 // receiver.
326 if (ReceiverIFaceEnt.isValid() && ReceiverIFace == 0)
327 return;
328
329 // Null means it doesn't exist in this translation unit or there was no
330 // interface associated with the message in the first place.
331 ObjCInterfaceDecl *MsgIFace =
332 cast_or_null<ObjCInterfaceDecl>(MsgIFaceEnt.getDecl(Ctx));
333
334 Selector Sel = GlobSel.getSelector(Ctx);
335 SelectorMap &SelMap = TU->getSelectorMap();
336 for (SelectorMap::method_iterator
337 I = SelMap.methods_begin(Sel), E = SelMap.methods_end(Sel);
338 I != E; ++I) {
339 ObjCMethodDecl *D = *I;
340 if (ValidMethod(D, MsgIFace, ReceiverIFace)) {
341 for (ObjCMethodDecl::redecl_iterator
342 RI = D->redecls_begin(), RE = D->redecls_end(); RI != RE; ++RI)
343 TULocHandler.Handle(TULocation(TU, ASTLocation(*RI)));
344 }
345 }
346 }
347
348 /// \brief Determines whether the given method is likely to accept the
349 /// original message.
350 ///
351 /// It returns true "eagerly", meaning it will return false only if it can
352 /// "prove" statically that the method cannot accept the original message.
353 bool ValidMethod(ObjCMethodDecl *D, ObjCInterfaceDecl *MsgIFace,
354 ObjCInterfaceDecl *ReceiverIFace) {
355 assert(D);
356
357 // FIXME: Protocol methods ?
358 if (isa<ObjCProtocolDecl>(D->getDeclContext()))
359 return false;
360
361 // No specific interface associated with the message. Can be anything.
362 if (MsgIFaceEnt.isInvalid())
363 return true;
364
Eli Friedmanbebc4672009-07-30 00:11:31 +0000365 if ((!CanBeInstanceMethod && D->isInstanceMethod()) ||
366 (!CanBeClassMethod && D->isClassMethod()))
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000367 return false;
368
369 ObjCInterfaceDecl *IFace = D->getClassInterface();
370 assert(IFace);
371
372 // If the original message interface is the same or a superclass of the
373 // given interface, accept the method as a possibility.
374 if (MsgIFace && MsgIFace->isSuperClassOf(IFace))
375 return true;
376
377 if (ReceiverIFace) {
378 // The given interface, "overrides" the receiver.
379 if (ReceiverIFace->isSuperClassOf(IFace))
380 return true;
381 } else {
382 // No receiver was found for the original message.
383 assert(ReceiverIFaceEnt.isInvalid());
384
385 // If the original message interface is a subclass of the given interface,
386 // accept the message.
387 if (HierarchyEntities.count(Entity::get(IFace, Prog)))
388 return true;
389 }
390
391 // The interfaces are unrelated, or the receiver interface wasn't
392 // "overriden".
393 return false;
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000394 }
395};
396
397} // end anonymous namespace
398
399//===----------------------------------------------------------------------===//
400// Analyzer Implementation
401//===----------------------------------------------------------------------===//
402
403void Analyzer::FindDeclarations(Decl *D, TULocationHandler &Handler) {
404 assert(D && "Passed null declaration");
405 Entity Ent = Entity::get(D, Prog);
406 if (Ent.isInvalid())
407 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000408
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000409 DeclEntityAnalyzer DEA(Ent, Handler);
410 Idxer.GetTranslationUnitsFor(Ent, DEA);
411}
412
413void Analyzer::FindReferences(Decl *D, TULocationHandler &Handler) {
414 assert(D && "Passed null declaration");
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000415 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
416 RefSelectorAnalyzer RSA(MD, Prog, Handler);
417 GlobalSelector Sel = GlobalSelector::get(MD->getSelector(), Prog);
418 Idxer.GetTranslationUnitsFor(Sel, RSA);
419 return;
420 }
421
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000422 Entity Ent = Entity::get(D, Prog);
423 if (Ent.isInvalid())
424 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000425
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000426 RefEntityAnalyzer REA(Ent, Handler);
427 Idxer.GetTranslationUnitsFor(Ent, REA);
428}
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000429
430/// \brief Find methods that may respond to the given message and pass them
431/// to Handler.
432void Analyzer::FindObjCMethods(ObjCMessageExpr *Msg,
433 TULocationHandler &Handler) {
434 assert(Msg);
435 MessageAnalyzer MsgAnalyz(Msg, Prog, Handler);
436 GlobalSelector GlobSel = GlobalSelector::get(Msg->getSelector(), Prog);
437 Idxer.GetTranslationUnitsFor(GlobSel, MsgAnalyz);
438}