|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt Mobility Components. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "LookupContext.h" |
|
43 #include "ResolveExpression.h" |
|
44 #include "Overview.h" |
|
45 #include "CppBindings.h" |
|
46 |
|
47 #include <CoreTypes.h> |
|
48 #include <Symbols.h> |
|
49 #include <Literals.h> |
|
50 #include <Names.h> |
|
51 #include <Scope.h> |
|
52 #include <Control.h> |
|
53 |
|
54 #include <QtDebug> |
|
55 |
|
56 uint CPlusPlus::qHash(const CPlusPlus::LookupItem &key) |
|
57 { |
|
58 const uint h1 = QT_PREPEND_NAMESPACE(qHash)(key.type().type()); |
|
59 const uint h2 = QT_PREPEND_NAMESPACE(qHash)(key.lastVisibleSymbol()); |
|
60 return ((h1 << 16) | (h1 >> 16)) ^ h2; |
|
61 } |
|
62 |
|
63 using namespace CPlusPlus; |
|
64 |
|
65 ///////////////////////////////////////////////////////////////////// |
|
66 // LookupContext |
|
67 ///////////////////////////////////////////////////////////////////// |
|
68 LookupContext::LookupContext(Control *control) |
|
69 : _control(control), |
|
70 _symbol(0) |
|
71 { } |
|
72 |
|
73 LookupContext::LookupContext(Symbol *symbol, |
|
74 Document::Ptr expressionDocument, |
|
75 Document::Ptr thisDocument, |
|
76 const Snapshot &snapshot) |
|
77 : _symbol(symbol), |
|
78 _expressionDocument(expressionDocument), |
|
79 _thisDocument(thisDocument), |
|
80 _snapshot(snapshot) |
|
81 { |
|
82 _control = _expressionDocument->control(); |
|
83 _visibleScopes = buildVisibleScopes(); |
|
84 } |
|
85 |
|
86 bool LookupContext::isValid() const |
|
87 { return _control != 0; } |
|
88 |
|
89 Control *LookupContext::control() const |
|
90 { return _control; } |
|
91 |
|
92 Symbol *LookupContext::symbol() const |
|
93 { return _symbol; } |
|
94 |
|
95 Document::Ptr LookupContext::expressionDocument() const |
|
96 { return _expressionDocument; } |
|
97 |
|
98 Document::Ptr LookupContext::thisDocument() const |
|
99 { return _thisDocument; } |
|
100 |
|
101 Document::Ptr LookupContext::document(const QString &fileName) const |
|
102 { return _snapshot.document(fileName); } |
|
103 |
|
104 Snapshot LookupContext::snapshot() const |
|
105 { return _snapshot; } |
|
106 |
|
107 bool LookupContext::maybeValidSymbol(Symbol *symbol, |
|
108 ResolveMode mode, |
|
109 const QList<Symbol *> &candidates) |
|
110 { |
|
111 if (((mode & ResolveNamespace) && symbol->isNamespace()) || |
|
112 ((mode & ResolveClass) && symbol->isClass()) || |
|
113 ((mode & ResolveObjCClass) && symbol->isObjCClass()) || |
|
114 ((mode & ResolveObjCProtocol) && symbol->isObjCProtocol()) || |
|
115 (mode & ResolveSymbol)) { |
|
116 return ! candidates.contains(symbol); |
|
117 } |
|
118 |
|
119 return false; |
|
120 } |
|
121 |
|
122 QList<Scope *> LookupContext::resolveNestedNameSpecifier(const QualifiedNameId *q, |
|
123 const QList<Scope *> &visibleScopes) const |
|
124 { |
|
125 QList<Symbol *> candidates; |
|
126 QList<Scope *> scopes = visibleScopes; |
|
127 |
|
128 for (unsigned i = 0; i < q->nameCount() - 1; ++i) { |
|
129 const Name *name = q->nameAt(i); |
|
130 |
|
131 candidates = resolveClassOrNamespace(name, scopes); |
|
132 |
|
133 if (candidates.isEmpty()) |
|
134 break; |
|
135 |
|
136 scopes.clear(); |
|
137 |
|
138 foreach (Symbol *candidate, candidates) { |
|
139 ScopedSymbol *scoped = candidate->asScopedSymbol(); |
|
140 Scope *members = scoped->members(); |
|
141 |
|
142 if (! scopes.contains(members)) |
|
143 scopes.append(members); |
|
144 } |
|
145 } |
|
146 |
|
147 return scopes; |
|
148 } |
|
149 |
|
150 QList<Symbol *> LookupContext::resolveQualifiedNameId(const QualifiedNameId *q, |
|
151 const QList<Scope *> &visibleScopes, |
|
152 ResolveMode mode) const |
|
153 { |
|
154 QList<Symbol *> candidates; |
|
155 |
|
156 if (true || mode & ResolveClass) { |
|
157 for (int i = 0; i < visibleScopes.size(); ++i) { |
|
158 Scope *scope = visibleScopes.at(i); |
|
159 |
|
160 for (Symbol *symbol = scope->lookat(q); symbol; symbol = symbol->next()) { |
|
161 if (! symbol->name()) |
|
162 continue; |
|
163 else if (! symbol->isClass()) |
|
164 continue; |
|
165 |
|
166 const QualifiedNameId *qq = symbol->name()->asQualifiedNameId(); |
|
167 |
|
168 if (! qq) |
|
169 continue; |
|
170 else if (! maybeValidSymbol(symbol, mode, candidates)) |
|
171 continue; |
|
172 |
|
173 if (! q->unqualifiedNameId()->isEqualTo(qq->unqualifiedNameId())) |
|
174 continue; |
|
175 |
|
176 else if (qq->nameCount() == q->nameCount()) { |
|
177 unsigned j = 0; |
|
178 |
|
179 for (; j < q->nameCount(); ++j) { |
|
180 const Name *classOrNamespaceName1 = q->nameAt(j); |
|
181 const Name *classOrNamespaceName2 = qq->nameAt(j); |
|
182 |
|
183 if (! classOrNamespaceName1->isEqualTo(classOrNamespaceName2)) |
|
184 break; |
|
185 } |
|
186 |
|
187 if (j == q->nameCount()) |
|
188 candidates.append(symbol); |
|
189 } |
|
190 } |
|
191 } |
|
192 } |
|
193 |
|
194 QList<Scope *> scopes; |
|
195 |
|
196 if (q->nameCount() == 1) |
|
197 scopes = visibleScopes; // ### handle global scope lookup |
|
198 else |
|
199 scopes = resolveNestedNameSpecifier(q, visibleScopes); |
|
200 |
|
201 QList<Scope *> expanded; |
|
202 foreach (Scope *scope, scopes) { |
|
203 expanded.append(scope); |
|
204 |
|
205 for (unsigned i = 0; i < scope->symbolCount(); ++i) { |
|
206 Symbol *member = scope->symbolAt(i); |
|
207 |
|
208 if (ScopedSymbol *scopedSymbol = member->asScopedSymbol()) |
|
209 expandEnumOrAnonymousSymbol(scopedSymbol, &expanded); |
|
210 } |
|
211 } |
|
212 |
|
213 candidates += resolve(q->unqualifiedNameId(), expanded, mode); |
|
214 |
|
215 return candidates; |
|
216 } |
|
217 |
|
218 QList<Symbol *> LookupContext::resolveOperatorNameId(const OperatorNameId *opId, |
|
219 const QList<Scope *> &visibleScopes, |
|
220 ResolveMode) const |
|
221 { |
|
222 QList<Symbol *> candidates; |
|
223 |
|
224 for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) { |
|
225 Scope *scope = visibleScopes.at(scopeIndex); |
|
226 |
|
227 for (Symbol *symbol = scope->lookat(opId->kind()); symbol; symbol = symbol->next()) { |
|
228 if (! opId->isEqualTo(symbol->name())) |
|
229 continue; |
|
230 |
|
231 if (! candidates.contains(symbol)) |
|
232 candidates.append(symbol); |
|
233 } |
|
234 } |
|
235 |
|
236 return candidates; |
|
237 } |
|
238 |
|
239 QList<Symbol *> LookupContext::resolve(const Name *name, const QList<Scope *> &visibleScopes, |
|
240 ResolveMode mode) const |
|
241 { |
|
242 QList<Symbol *> candidates; |
|
243 |
|
244 if (!name) |
|
245 return candidates; // nothing to do, the symbol is anonymous. |
|
246 |
|
247 else if (const QualifiedNameId *q = name->asQualifiedNameId()) |
|
248 return resolveQualifiedNameId(q, visibleScopes, mode); |
|
249 |
|
250 else if (const OperatorNameId *opId = name->asOperatorNameId()) |
|
251 return resolveOperatorNameId(opId, visibleScopes, mode); |
|
252 |
|
253 else if (const Identifier *id = name->identifier()) { |
|
254 for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) { |
|
255 Scope *scope = visibleScopes.at(scopeIndex); |
|
256 |
|
257 for (Symbol *symbol = scope->lookat(id); symbol; symbol = symbol->next()) { |
|
258 if (! symbol->name()) |
|
259 continue; // nothing to do, the symbol is anonymous. |
|
260 |
|
261 else if (! maybeValidSymbol(symbol, mode, candidates)) |
|
262 continue; // skip it, we're not looking for this kind of symbols |
|
263 |
|
264 else if (const Identifier *symbolId = symbol->identifier()) { |
|
265 if (! symbolId->isEqualTo(id)) |
|
266 continue; // skip it, the symbol's id is not compatible with this lookup. |
|
267 } |
|
268 |
|
269 if (const QualifiedNameId *q = symbol->name()->asQualifiedNameId()) { |
|
270 |
|
271 if (name->isDestructorNameId() != q->unqualifiedNameId()->isDestructorNameId()) |
|
272 continue; |
|
273 |
|
274 else if (q->nameCount() > 1) { |
|
275 const Name *classOrNamespaceName = control()->qualifiedNameId(q->names(), |
|
276 q->nameCount() - 1); |
|
277 |
|
278 if (const Identifier *classOrNamespaceNameId = identifier(classOrNamespaceName)) { |
|
279 if (classOrNamespaceNameId->isEqualTo(id)) |
|
280 continue; |
|
281 } |
|
282 |
|
283 const QList<Symbol *> resolvedClassOrNamespace = |
|
284 resolveClassOrNamespace(classOrNamespaceName, visibleScopes); |
|
285 |
|
286 bool good = false; |
|
287 foreach (Symbol *classOrNamespace, resolvedClassOrNamespace) { |
|
288 ScopedSymbol *scoped = classOrNamespace->asScopedSymbol(); |
|
289 if (visibleScopes.contains(scoped->members())) { |
|
290 good = true; |
|
291 break; |
|
292 } |
|
293 } |
|
294 |
|
295 if (! good) |
|
296 continue; |
|
297 } |
|
298 } else if (symbol->name()->isDestructorNameId() != name->isDestructorNameId()) { |
|
299 // ### FIXME: this is wrong! |
|
300 continue; |
|
301 } |
|
302 |
|
303 if (! candidates.contains(symbol)) |
|
304 candidates.append(symbol); |
|
305 } |
|
306 } |
|
307 } |
|
308 |
|
309 return candidates; |
|
310 } |
|
311 |
|
312 const Identifier *LookupContext::identifier(const Name *name) const |
|
313 { |
|
314 if (name) |
|
315 return name->identifier(); |
|
316 |
|
317 return 0; |
|
318 } |
|
319 |
|
320 void LookupContext::buildVisibleScopes_helper(Document::Ptr doc, QList<Scope *> *scopes, |
|
321 QSet<QString> *processed) |
|
322 { |
|
323 if (doc && ! processed->contains(doc->fileName())) { |
|
324 processed->insert(doc->fileName()); |
|
325 |
|
326 if (doc->globalSymbolCount()) |
|
327 scopes->append(doc->globalSymbols()); |
|
328 |
|
329 foreach (const Document::Include &incl, doc->includes()) { |
|
330 buildVisibleScopes_helper(_snapshot.document(incl.fileName()), |
|
331 scopes, processed); |
|
332 } |
|
333 } |
|
334 } |
|
335 |
|
336 QList<Scope *> LookupContext::buildVisibleScopes() |
|
337 { |
|
338 QList<Scope *> scopes; |
|
339 |
|
340 if (_symbol) { |
|
341 Scope *scope = _symbol->scope(); |
|
342 |
|
343 if (Function *fun = _symbol->asFunction()) |
|
344 scope = fun->members(); // handle ctor initializers. |
|
345 |
|
346 for (; scope; scope = scope->enclosingScope()) { |
|
347 if (scope == _thisDocument->globalSymbols()) |
|
348 break; |
|
349 |
|
350 scopes.append(scope); |
|
351 } |
|
352 } |
|
353 |
|
354 QSet<QString> processed; |
|
355 buildVisibleScopes_helper(_thisDocument, &scopes, &processed); |
|
356 |
|
357 while (true) { |
|
358 QList<Scope *> expandedScopes; |
|
359 expand(scopes, &expandedScopes); |
|
360 |
|
361 if (expandedScopes.size() == scopes.size()) |
|
362 return expandedScopes; |
|
363 |
|
364 scopes = expandedScopes; |
|
365 } |
|
366 |
|
367 return scopes; |
|
368 } |
|
369 |
|
370 QList<Scope *> LookupContext::visibleScopes(const LookupItem &result) const |
|
371 { return visibleScopes(result.lastVisibleSymbol()); } |
|
372 |
|
373 QList<Scope *> LookupContext::visibleScopes(Symbol *symbol) const |
|
374 { |
|
375 QList<Scope *> scopes; |
|
376 if (symbol) { |
|
377 for (Scope *scope = symbol->scope(); scope; scope = scope->enclosingScope()) |
|
378 scopes.append(scope); |
|
379 } |
|
380 scopes += visibleScopes(); |
|
381 scopes = expand(scopes); |
|
382 return scopes; |
|
383 } |
|
384 |
|
385 void LookupContext::expandEnumOrAnonymousSymbol(ScopedSymbol *scopedSymbol, |
|
386 QList<Scope *> *expandedScopes) const |
|
387 { |
|
388 if (! scopedSymbol || expandedScopes->contains(scopedSymbol->members())) |
|
389 return; |
|
390 |
|
391 Scope *members = scopedSymbol->members(); |
|
392 |
|
393 if (scopedSymbol->isEnum()) |
|
394 expandedScopes->append(members); |
|
395 else if (! scopedSymbol->name() && (scopedSymbol->isClass() || scopedSymbol->isNamespace())) { |
|
396 // anonymous class or namespace |
|
397 |
|
398 expandedScopes->append(members); |
|
399 |
|
400 for (unsigned i = 0; i < members->symbolCount(); ++i) { |
|
401 Symbol *member = members->symbolAt(i); |
|
402 |
|
403 if (ScopedSymbol *nested = member->asScopedSymbol()) { |
|
404 expandEnumOrAnonymousSymbol(nested, expandedScopes); |
|
405 } |
|
406 } |
|
407 } |
|
408 } |
|
409 |
|
410 QList<Scope *> LookupContext::expand(const QList<Scope *> &scopes) const |
|
411 { |
|
412 QList<Scope *> expanded; |
|
413 expand(scopes, &expanded); |
|
414 return expanded; |
|
415 } |
|
416 |
|
417 void LookupContext::expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const |
|
418 { |
|
419 for (int i = 0; i < scopes.size(); ++i) { |
|
420 expand(scopes.at(i), scopes, expandedScopes); |
|
421 } |
|
422 } |
|
423 |
|
424 void LookupContext::expandNamespace(Namespace *ns, |
|
425 const QList<Scope *> &visibleScopes, |
|
426 QList<Scope *> *expandedScopes) const |
|
427 { |
|
428 //qDebug() << "*** expand namespace:" << ns->fileName() << ns->line() << ns->column(); |
|
429 |
|
430 if (Scope *encl = ns->enclosingNamespaceScope()) |
|
431 expand(encl, visibleScopes, expandedScopes); |
|
432 |
|
433 if (const Name *nsName = ns->name()) { |
|
434 const QList<Symbol *> namespaceList = resolveNamespace(nsName, visibleScopes); |
|
435 foreach (Symbol *otherNs, namespaceList) { |
|
436 if (otherNs == ns) |
|
437 continue; |
|
438 expand(otherNs->asNamespace()->members(), visibleScopes, expandedScopes); |
|
439 } |
|
440 } |
|
441 |
|
442 for (unsigned i = 0; i < ns->memberCount(); ++i) { // ### make me fast |
|
443 Symbol *symbol = ns->memberAt(i); |
|
444 if (Namespace *otherNs = symbol->asNamespace()) { |
|
445 if (! otherNs->name()) { |
|
446 expand(otherNs->members(), visibleScopes, expandedScopes); |
|
447 } |
|
448 } else if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) { |
|
449 const QList<Symbol *> candidates = resolveNamespace(u->name(), visibleScopes); |
|
450 for (int j = 0; j < candidates.size(); ++j) { |
|
451 expand(candidates.at(j)->asNamespace()->members(), |
|
452 visibleScopes, expandedScopes); |
|
453 } |
|
454 } else if (Enum *e = symbol->asEnum()) { |
|
455 expand(e->members(), visibleScopes, expandedScopes); |
|
456 } |
|
457 } |
|
458 } |
|
459 |
|
460 void LookupContext::expandClass(Class *klass, |
|
461 const QList<Scope *> &visibleScopes, |
|
462 QList<Scope *> *expandedScopes) const |
|
463 { |
|
464 for (TemplateParameters *params = klass->templateParameters(); params; params = params->previous()) |
|
465 expand(params->scope(), visibleScopes, expandedScopes); |
|
466 |
|
467 for (unsigned i = 0; i < klass->memberCount(); ++i) { |
|
468 Symbol *symbol = klass->memberAt(i); |
|
469 if (Class *nestedClass = symbol->asClass()) { |
|
470 if (! nestedClass->name()) { |
|
471 expand(nestedClass->members(), visibleScopes, expandedScopes); |
|
472 } |
|
473 } else if (Enum *e = symbol->asEnum()) { |
|
474 expand(e->members(), visibleScopes, expandedScopes); |
|
475 } |
|
476 } |
|
477 |
|
478 if (klass->baseClassCount()) { |
|
479 QList<Scope *> classVisibleScopes = visibleScopes; |
|
480 for (Scope *scope = klass->scope(); scope; scope = scope->enclosingScope()) { |
|
481 if (scope->isNamespaceScope()) { |
|
482 Namespace *enclosingNamespace = scope->owner()->asNamespace(); |
|
483 if (enclosingNamespace->name()) { |
|
484 const QList<Symbol *> nsList = resolveNamespace(enclosingNamespace->name(), |
|
485 visibleScopes); |
|
486 foreach (Symbol *ns, nsList) { |
|
487 expand(ns->asNamespace()->members(), classVisibleScopes, |
|
488 &classVisibleScopes); |
|
489 } |
|
490 } |
|
491 } |
|
492 } |
|
493 |
|
494 for (unsigned i = 0; i < klass->baseClassCount(); ++i) { |
|
495 BaseClass *baseClass = klass->baseClassAt(i); |
|
496 const Name *baseClassName = baseClass->name(); |
|
497 const QList<Symbol *> baseClassCandidates = resolveClass(baseClassName, |
|
498 classVisibleScopes); |
|
499 |
|
500 for (int j = 0; j < baseClassCandidates.size(); ++j) { |
|
501 if (Class *baseClassSymbol = baseClassCandidates.at(j)->asClass()) |
|
502 expand(baseClassSymbol->members(), visibleScopes, expandedScopes); |
|
503 } |
|
504 } |
|
505 } |
|
506 } |
|
507 |
|
508 void LookupContext::expandBlock(Block *blockSymbol, |
|
509 const QList<Scope *> &visibleScopes, |
|
510 QList<Scope *> *expandedScopes) const |
|
511 { |
|
512 for (unsigned i = 0; i < blockSymbol->memberCount(); ++i) { |
|
513 Symbol *symbol = blockSymbol->memberAt(i); |
|
514 if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) { |
|
515 const QList<Symbol *> candidates = resolveNamespace(u->name(), |
|
516 visibleScopes); |
|
517 for (int j = 0; j < candidates.size(); ++j) { |
|
518 expand(candidates.at(j)->asNamespace()->members(), |
|
519 visibleScopes, expandedScopes); |
|
520 } |
|
521 } |
|
522 |
|
523 } |
|
524 } |
|
525 |
|
526 void LookupContext::expandFunction(Function *function, |
|
527 const QList<Scope *> &visibleScopes, |
|
528 QList<Scope *> *expandedScopes) const |
|
529 { |
|
530 for (TemplateParameters *params = function->templateParameters(); params; params = params->previous()) |
|
531 expand(params->scope(), visibleScopes, expandedScopes); |
|
532 |
|
533 if (! expandedScopes->contains(function->arguments())) |
|
534 expandedScopes->append(function->arguments()); |
|
535 |
|
536 if (const QualifiedNameId *q = function->name()->asQualifiedNameId()) { |
|
537 const Name *nestedNameSpec = 0; |
|
538 if (q->nameCount() == 1) |
|
539 nestedNameSpec = q->nameAt(0); |
|
540 else |
|
541 nestedNameSpec = control()->qualifiedNameId(q->names(), q->nameCount() - 1, |
|
542 q->isGlobal()); |
|
543 const QList<Symbol *> candidates = resolveClassOrNamespace(nestedNameSpec, visibleScopes); |
|
544 for (int j = 0; j < candidates.size(); ++j) { |
|
545 if (ScopedSymbol *scopedSymbol = candidates.at(j)->asScopedSymbol()) |
|
546 expand(scopedSymbol->members(), visibleScopes, expandedScopes); |
|
547 } |
|
548 } |
|
549 } |
|
550 |
|
551 void LookupContext::expandObjCMethod(ObjCMethod *method, |
|
552 const QList<Scope *> &, |
|
553 QList<Scope *> *expandedScopes) const |
|
554 { |
|
555 if (! expandedScopes->contains(method->arguments())) |
|
556 expandedScopes->append(method->arguments()); |
|
557 } |
|
558 |
|
559 void LookupContext::expandObjCClass(ObjCClass *klass, |
|
560 const QList<Scope *> &visibleScopes, |
|
561 QList<Scope *> *expandedScopes) const |
|
562 { |
|
563 {// expand other @interfaces, @implementations and categories for this class: |
|
564 const QList<Symbol *> classList = resolveObjCClass(klass->name(), visibleScopes); |
|
565 foreach (Symbol *otherClass, classList) { |
|
566 if (otherClass == klass) |
|
567 continue; |
|
568 expand(otherClass->asObjCClass()->members(), visibleScopes, expandedScopes); |
|
569 } |
|
570 } |
|
571 |
|
572 // expand definitions in the currect class: |
|
573 for (unsigned i = 0; i < klass->memberCount(); ++i) { |
|
574 Symbol *symbol = klass->memberAt(i); |
|
575 if (Class *nestedClass = symbol->asClass()) { |
|
576 if (! nestedClass->name()) { |
|
577 expand(nestedClass->members(), visibleScopes, expandedScopes); |
|
578 } |
|
579 } else if (Enum *e = symbol->asEnum()) { |
|
580 expand(e->members(), visibleScopes, expandedScopes); |
|
581 } |
|
582 } |
|
583 |
|
584 // expand the base class: |
|
585 if (ObjCBaseClass *baseClass = klass->baseClass()) { |
|
586 const Name *baseClassName = baseClass->name(); |
|
587 const QList<Symbol *> baseClassCandidates = resolveObjCClass(baseClassName, |
|
588 visibleScopes); |
|
589 |
|
590 for (int j = 0; j < baseClassCandidates.size(); ++j) { |
|
591 if (ObjCClass *baseClassSymbol = baseClassCandidates.at(j)->asObjCClass()) |
|
592 expand(baseClassSymbol->members(), visibleScopes, expandedScopes); |
|
593 } |
|
594 } |
|
595 |
|
596 // expand the protocols: |
|
597 for (unsigned i = 0; i < klass->protocolCount(); ++i) { |
|
598 const Name *protocolName = klass->protocolAt(i)->name(); |
|
599 const QList<Symbol *> protocolCandidates = resolveObjCProtocol(protocolName, visibleScopes); |
|
600 for (int j = 0; j < protocolCandidates.size(); ++j) { |
|
601 if (ObjCProtocol *protocolSymbol = protocolCandidates.at(j)->asObjCProtocol()) |
|
602 expandObjCProtocol(protocolSymbol, visibleScopes, expandedScopes); |
|
603 } |
|
604 } |
|
605 } |
|
606 |
|
607 void LookupContext::expandObjCProtocol(ObjCProtocol *protocol, const QList<Scope *> &visibleScopes, QList<Scope *> *expandedScopes) const |
|
608 { |
|
609 // First expand the protocol itself |
|
610 expand(protocol->members(), visibleScopes, expandedScopes); |
|
611 |
|
612 // Then do the same for any incorporated protocol |
|
613 for (unsigned i = 0; i < protocol->protocolCount(); ++i) { |
|
614 ObjCBaseProtocol *baseProtocol = protocol->protocolAt(i); |
|
615 const QList<Symbol *> protocolList = resolveObjCProtocol(baseProtocol->name(), visibleScopes); |
|
616 foreach (Symbol *symbol, protocolList) |
|
617 if (ObjCProtocol *protocolSymbol = symbol->asObjCProtocol()) |
|
618 expandObjCProtocol(protocolSymbol, visibleScopes, expandedScopes); |
|
619 } |
|
620 } |
|
621 |
|
622 void LookupContext::expand(Scope *scope, |
|
623 const QList<Scope *> &visibleScopes, |
|
624 QList<Scope *> *expandedScopes) const |
|
625 { |
|
626 if (expandedScopes->contains(scope)) |
|
627 return; |
|
628 |
|
629 expandedScopes->append(scope); |
|
630 |
|
631 if (Namespace *ns = scope->owner()->asNamespace()) { |
|
632 expandNamespace(ns, visibleScopes, expandedScopes); |
|
633 } else if (Class *klass = scope->owner()->asClass()) { |
|
634 expandClass(klass, visibleScopes, expandedScopes); |
|
635 } else if (Block *block = scope->owner()->asBlock()) { |
|
636 expandBlock(block, visibleScopes, expandedScopes); |
|
637 } else if (Function *fun = scope->owner()->asFunction()) { |
|
638 expandFunction(fun, visibleScopes, expandedScopes); |
|
639 } else if (ObjCMethod *meth = scope->owner()->asObjCMethod()) { |
|
640 expandObjCMethod(meth, visibleScopes, expandedScopes); |
|
641 } else if (ObjCClass *objcKlass = scope->owner()->asObjCClass()) { |
|
642 expandObjCClass(objcKlass, visibleScopes, expandedScopes); |
|
643 } |
|
644 } |
|
645 |
|
646 static void visibleClassBindings_helper(ClassBinding *classBinding, |
|
647 QList<ClassBinding *> *allClassBindings, |
|
648 QSet<ClassBinding *> *processed) |
|
649 { |
|
650 if (! classBinding) |
|
651 return; |
|
652 |
|
653 else if (processed->contains(classBinding)) |
|
654 return; |
|
655 |
|
656 processed->insert(classBinding); |
|
657 |
|
658 foreach (ClassBinding *baseClassBinding, classBinding->baseClassBindings) |
|
659 visibleClassBindings_helper(baseClassBinding, allClassBindings, processed); |
|
660 |
|
661 allClassBindings->append(classBinding); |
|
662 } |
|
663 |
|
664 static QList<ClassBinding *> visibleClassBindings(Symbol *symbol, NamespaceBinding *globalNamespace) |
|
665 { |
|
666 QList<ClassBinding *> classBindings; |
|
667 |
|
668 if (! symbol) |
|
669 return classBindings; |
|
670 |
|
671 else if (Class *klass = symbol->asClass()) { |
|
672 QSet<ClassBinding *> processed; |
|
673 |
|
674 visibleClassBindings_helper(NamespaceBinding::find(klass, globalNamespace), |
|
675 &classBindings, &processed); |
|
676 } |
|
677 |
|
678 return classBindings; |
|
679 } |
|
680 |
|
681 Symbol *LookupContext::canonicalSymbol(Symbol *symbol, |
|
682 NamespaceBinding *globalNamespace) |
|
683 { |
|
684 Symbol *canonicalSymbol = LookupContext::canonicalSymbol(symbol); |
|
685 if (! canonicalSymbol) |
|
686 return 0; |
|
687 |
|
688 if (const Identifier *symbolId = canonicalSymbol->identifier()) { |
|
689 if (symbolId && canonicalSymbol->type()->isFunctionType()) { |
|
690 Class *enclosingClass = canonicalSymbol->scope()->owner()->asClass(); |
|
691 const QList<ClassBinding *> classBindings = visibleClassBindings(enclosingClass, globalNamespace); |
|
692 |
|
693 foreach (ClassBinding *baseClassBinding, classBindings) { |
|
694 if (! baseClassBinding) |
|
695 continue; |
|
696 |
|
697 foreach (Class *baseClass, baseClassBinding->symbols) { |
|
698 if (! baseClass) |
|
699 continue; |
|
700 |
|
701 for (Symbol *c = baseClass->members()->lookat(symbolId); c; c = c->next()) { |
|
702 if (! symbolId->isEqualTo(c->identifier())) |
|
703 continue; |
|
704 else if (Function *f = c->type()->asFunctionType()) { |
|
705 if (f->isVirtual()) |
|
706 return LookupContext::canonicalSymbol(f); |
|
707 } |
|
708 } |
|
709 } |
|
710 } |
|
711 } |
|
712 } |
|
713 |
|
714 return canonicalSymbol; |
|
715 } |
|
716 |
|
717 Symbol *LookupContext::canonicalSymbol(const QList<Symbol *> &candidates, |
|
718 NamespaceBinding *globalNamespaceBinding) |
|
719 { |
|
720 if (candidates.isEmpty()) |
|
721 return 0; |
|
722 |
|
723 return canonicalSymbol(candidates.first(), globalNamespaceBinding); |
|
724 } |
|
725 |
|
726 Symbol *LookupContext::canonicalSymbol(const QList<LookupItem> &results, |
|
727 NamespaceBinding *globalNamespaceBinding) |
|
728 { |
|
729 QList<Symbol *> candidates; |
|
730 |
|
731 foreach (const LookupItem &result, results) |
|
732 candidates.append(result.lastVisibleSymbol()); // ### not exactly. |
|
733 |
|
734 return canonicalSymbol(candidates, globalNamespaceBinding); |
|
735 } |
|
736 |
|
737 |
|
738 Symbol *LookupContext::canonicalSymbol(Symbol *symbol) |
|
739 { |
|
740 Symbol *canonical = symbol; |
|
741 Class *canonicalClass = 0; |
|
742 ObjCClass *canonicalObjCClass = 0; |
|
743 ObjCProtocol *canonicalObjCProto = 0; |
|
744 |
|
745 for (; symbol; symbol = symbol->next()) { |
|
746 if (symbol->identifier() == canonical->identifier()) { |
|
747 canonical = symbol; |
|
748 |
|
749 if (Class *klass = symbol->asClass()) |
|
750 canonicalClass = klass; |
|
751 else if (ObjCClass *clazz = symbol->asObjCClass()) |
|
752 canonicalObjCClass = clazz; |
|
753 else if (ObjCProtocol *proto = symbol->asObjCProtocol()) |
|
754 canonicalObjCProto = proto; |
|
755 } |
|
756 } |
|
757 |
|
758 if (canonicalClass) { |
|
759 Q_ASSERT(canonical != 0); |
|
760 |
|
761 if (canonical->isForwardClassDeclaration()) |
|
762 return canonicalClass; // prefer class declarations when available. |
|
763 } else if (canonicalObjCClass) { |
|
764 Q_ASSERT(canonical != 0); |
|
765 |
|
766 if (canonical->isObjCForwardClassDeclaration()) |
|
767 return canonicalObjCClass; |
|
768 } else if (canonicalObjCProto) { |
|
769 Q_ASSERT(canonical != 0); |
|
770 |
|
771 if (canonical->isObjCForwardProtocolDeclaration()) |
|
772 return canonicalObjCProto; |
|
773 } |
|
774 |
|
775 if (canonical && canonical->scope()->isClassScope()) { |
|
776 Class *enclosingClass = canonical->scope()->owner()->asClass(); |
|
777 |
|
778 if (enclosingClass->identifier() == canonical->identifier()) |
|
779 return enclosingClass; |
|
780 } |
|
781 |
|
782 return canonical; |
|
783 } |