|
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 "ResolveExpression.h" |
|
43 #include "LookupContext.h" |
|
44 #include "Overview.h" |
|
45 #include "GenTemplateInstance.h" |
|
46 |
|
47 #include <Control.h> |
|
48 #include <AST.h> |
|
49 #include <Scope.h> |
|
50 #include <Names.h> |
|
51 #include <Symbols.h> |
|
52 #include <Literals.h> |
|
53 #include <CoreTypes.h> |
|
54 #include <TypeVisitor.h> |
|
55 #include <NameVisitor.h> |
|
56 |
|
57 #include <QtCore/QList> |
|
58 #include <QtCore/QVarLengthArray> |
|
59 #include <QtCore/QtDebug> |
|
60 |
|
61 using namespace CPlusPlus; |
|
62 |
|
63 namespace { |
|
64 |
|
65 template <typename _Tp> |
|
66 static QList<_Tp> removeDuplicates(const QList<_Tp> &results) |
|
67 { |
|
68 QList<_Tp> uniqueList; |
|
69 QSet<_Tp> processed; |
|
70 foreach (const _Tp &r, results) { |
|
71 if (processed.contains(r)) |
|
72 continue; |
|
73 |
|
74 processed.insert(r); |
|
75 uniqueList.append(r); |
|
76 } |
|
77 |
|
78 return uniqueList; |
|
79 } |
|
80 |
|
81 } // end of anonymous namespace |
|
82 |
|
83 ///////////////////////////////////////////////////////////////////// |
|
84 // ResolveExpression |
|
85 ///////////////////////////////////////////////////////////////////// |
|
86 ResolveExpression::ResolveExpression(const LookupContext &context) |
|
87 : ASTVisitor(context.expressionDocument()->translationUnit()), |
|
88 _context(context), |
|
89 sem(context.expressionDocument()->translationUnit()) |
|
90 { } |
|
91 |
|
92 ResolveExpression::~ResolveExpression() |
|
93 { } |
|
94 |
|
95 QList<LookupItem> ResolveExpression::operator()(ExpressionAST *ast) |
|
96 { |
|
97 const QList<LookupItem> previousResults = switchResults(QList<LookupItem>()); |
|
98 accept(ast); |
|
99 return removeDuplicates(switchResults(previousResults)); |
|
100 } |
|
101 |
|
102 QList<LookupItem> |
|
103 ResolveExpression::switchResults(const QList<LookupItem> &results) |
|
104 { |
|
105 const QList<LookupItem> previousResults = _results; |
|
106 _results = results; |
|
107 return previousResults; |
|
108 } |
|
109 |
|
110 void ResolveExpression::addResults(const QList<LookupItem> &results) |
|
111 { |
|
112 foreach (const LookupItem r, results) |
|
113 addResult(r); |
|
114 } |
|
115 |
|
116 void ResolveExpression::addResult(const FullySpecifiedType &ty, Symbol *symbol) |
|
117 { return addResult(LookupItem(ty, symbol)); } |
|
118 |
|
119 void ResolveExpression::addResult(const LookupItem &r) |
|
120 { |
|
121 LookupItem p = r; |
|
122 |
|
123 if (! p.lastVisibleSymbol()) |
|
124 p.setLastVisibleSymbol(_context.symbol()); |
|
125 |
|
126 if (! _results.contains(p)) |
|
127 _results.append(p); |
|
128 } |
|
129 |
|
130 QList<Scope *> ResolveExpression::visibleScopes(const LookupItem &result) const |
|
131 { return _context.visibleScopes(result); } |
|
132 |
|
133 bool ResolveExpression::visit(BinaryExpressionAST *ast) |
|
134 { |
|
135 accept(ast->left_expression); |
|
136 return false; |
|
137 } |
|
138 |
|
139 bool ResolveExpression::visit(CastExpressionAST *ast) |
|
140 { |
|
141 addResult(sem.check(ast->type_id, _context.expressionDocument()->globalSymbols())); |
|
142 return false; |
|
143 } |
|
144 |
|
145 bool ResolveExpression::visit(ConditionAST *) |
|
146 { |
|
147 // nothing to do. |
|
148 return false; |
|
149 } |
|
150 |
|
151 bool ResolveExpression::visit(ConditionalExpressionAST *ast) |
|
152 { |
|
153 if (ast->left_expression) |
|
154 accept(ast->left_expression); |
|
155 |
|
156 else if (ast->right_expression) |
|
157 accept(ast->right_expression); |
|
158 |
|
159 return false; |
|
160 } |
|
161 |
|
162 bool ResolveExpression::visit(CppCastExpressionAST *ast) |
|
163 { |
|
164 addResult(sem.check(ast->type_id, _context.expressionDocument()->globalSymbols())); |
|
165 return false; |
|
166 } |
|
167 |
|
168 bool ResolveExpression::visit(DeleteExpressionAST *) |
|
169 { |
|
170 FullySpecifiedType ty(control()->voidType()); |
|
171 addResult(ty); |
|
172 return false; |
|
173 } |
|
174 |
|
175 bool ResolveExpression::visit(ArrayInitializerAST *) |
|
176 { |
|
177 // nothing to do. |
|
178 return false; |
|
179 } |
|
180 |
|
181 bool ResolveExpression::visit(NewExpressionAST *ast) |
|
182 { |
|
183 if (ast->new_type_id) { |
|
184 Scope *scope = _context.expressionDocument()->globalSymbols(); |
|
185 FullySpecifiedType ty = sem.check(ast->new_type_id->type_specifier_list, scope); |
|
186 ty = sem.check(ast->new_type_id->ptr_operator_list, ty, scope); |
|
187 FullySpecifiedType ptrTy(control()->pointerType(ty)); |
|
188 addResult(ptrTy); |
|
189 } |
|
190 // nothing to do. |
|
191 return false; |
|
192 } |
|
193 |
|
194 bool ResolveExpression::visit(TypeidExpressionAST *) |
|
195 { |
|
196 const Name *std_type_info[2]; |
|
197 std_type_info[0] = control()->nameId(control()->findOrInsertIdentifier("std")); |
|
198 std_type_info[1] = control()->nameId(control()->findOrInsertIdentifier("type_info")); |
|
199 |
|
200 const Name *q = control()->qualifiedNameId(std_type_info, 2, /*global=*/ true); |
|
201 FullySpecifiedType ty(control()->namedType(q)); |
|
202 addResult(ty); |
|
203 |
|
204 return false; |
|
205 } |
|
206 |
|
207 bool ResolveExpression::visit(TypenameCallExpressionAST *) |
|
208 { |
|
209 // nothing to do |
|
210 return false; |
|
211 } |
|
212 |
|
213 bool ResolveExpression::visit(TypeConstructorCallAST *) |
|
214 { |
|
215 // nothing to do. |
|
216 return false; |
|
217 } |
|
218 |
|
219 bool ResolveExpression::visit(PostfixExpressionAST *ast) |
|
220 { |
|
221 accept(ast->base_expression); |
|
222 |
|
223 for (PostfixListAST *it = ast->postfix_expression_list; it; it = it->next) { |
|
224 accept(it->value); |
|
225 } |
|
226 |
|
227 return false; |
|
228 } |
|
229 |
|
230 bool ResolveExpression::visit(SizeofExpressionAST *) |
|
231 { |
|
232 FullySpecifiedType ty(control()->integerType(IntegerType::Int)); |
|
233 ty.setUnsigned(true); |
|
234 addResult(ty); |
|
235 return false; |
|
236 } |
|
237 |
|
238 bool ResolveExpression::visit(NumericLiteralAST *ast) |
|
239 { |
|
240 Type *type = 0; |
|
241 const NumericLiteral *literal = numericLiteral(ast->literal_token); |
|
242 |
|
243 if (literal->isChar()) |
|
244 type = control()->integerType(IntegerType::Char); |
|
245 else if (literal->isWideChar()) |
|
246 type = control()->integerType(IntegerType::WideChar); |
|
247 else if (literal->isInt()) |
|
248 type = control()->integerType(IntegerType::Int); |
|
249 else if (literal->isLong()) |
|
250 type = control()->integerType(IntegerType::Long); |
|
251 else if (literal->isLongLong()) |
|
252 type = control()->integerType(IntegerType::LongLong); |
|
253 else if (literal->isFloat()) |
|
254 type = control()->floatType(FloatType::Float); |
|
255 else if (literal->isDouble()) |
|
256 type = control()->floatType(FloatType::Double); |
|
257 else if (literal->isLongDouble()) |
|
258 type = control()->floatType(FloatType::LongDouble); |
|
259 else |
|
260 type = control()->integerType(IntegerType::Int); |
|
261 |
|
262 FullySpecifiedType ty(type); |
|
263 if (literal->isUnsigned()) |
|
264 ty.setUnsigned(true); |
|
265 |
|
266 addResult(ty); |
|
267 return false; |
|
268 } |
|
269 |
|
270 bool ResolveExpression::visit(BoolLiteralAST *) |
|
271 { |
|
272 FullySpecifiedType ty(control()->integerType(IntegerType::Bool)); |
|
273 addResult(ty); |
|
274 return false; |
|
275 } |
|
276 |
|
277 bool ResolveExpression::visit(ThisExpressionAST *) |
|
278 { |
|
279 if (! _context.symbol()) |
|
280 return false; |
|
281 |
|
282 Scope *scope = _context.symbol()->scope(); |
|
283 for (; scope; scope = scope->enclosingScope()) { |
|
284 if (scope->isFunctionScope()) { |
|
285 Function *fun = scope->owner()->asFunction(); |
|
286 if (Scope *cscope = scope->enclosingClassScope()) { |
|
287 Class *klass = cscope->owner()->asClass(); |
|
288 FullySpecifiedType classTy(control()->namedType(klass->name())); |
|
289 FullySpecifiedType ptrTy(control()->pointerType(classTy)); |
|
290 addResult(ptrTy, fun); |
|
291 break; |
|
292 } else if (const QualifiedNameId *q = fun->name()->asQualifiedNameId()) { |
|
293 const Name *nestedNameSpecifier = 0; |
|
294 if (q->nameCount() == 1 && q->isGlobal()) |
|
295 nestedNameSpecifier = q->nameAt(0); |
|
296 else |
|
297 nestedNameSpecifier = control()->qualifiedNameId(q->names(), q->nameCount() - 1); |
|
298 FullySpecifiedType classTy(control()->namedType(nestedNameSpecifier)); |
|
299 FullySpecifiedType ptrTy(control()->pointerType(classTy)); |
|
300 addResult(ptrTy, fun); |
|
301 break; |
|
302 } |
|
303 } |
|
304 } |
|
305 return false; |
|
306 } |
|
307 |
|
308 bool ResolveExpression::visit(NestedExpressionAST *ast) |
|
309 { |
|
310 accept(ast->expression); |
|
311 return false; |
|
312 } |
|
313 |
|
314 bool ResolveExpression::visit(StringLiteralAST *) |
|
315 { |
|
316 FullySpecifiedType charTy = control()->integerType(IntegerType::Char); |
|
317 charTy.setConst(true); |
|
318 FullySpecifiedType ty(control()->pointerType(charTy)); |
|
319 addResult(ty); |
|
320 return false; |
|
321 } |
|
322 |
|
323 bool ResolveExpression::visit(ThrowExpressionAST *) |
|
324 { |
|
325 return false; |
|
326 } |
|
327 |
|
328 bool ResolveExpression::visit(TypeIdAST *) |
|
329 { |
|
330 return false; |
|
331 } |
|
332 |
|
333 bool ResolveExpression::visit(UnaryExpressionAST *ast) |
|
334 { |
|
335 accept(ast->expression); |
|
336 unsigned unaryOp = tokenKind(ast->unary_op_token); |
|
337 if (unaryOp == T_AMPER) { |
|
338 QMutableListIterator<LookupItem > it(_results); |
|
339 while (it.hasNext()) { |
|
340 LookupItem p = it.next(); |
|
341 FullySpecifiedType ty = p.type(); |
|
342 ty.setType(control()->pointerType(ty)); |
|
343 p.setType(ty); |
|
344 it.setValue(p); |
|
345 } |
|
346 } else if (unaryOp == T_STAR) { |
|
347 QMutableListIterator<LookupItem > it(_results); |
|
348 while (it.hasNext()) { |
|
349 LookupItem p = it.next(); |
|
350 if (PointerType *ptrTy = p.type()->asPointerType()) { |
|
351 p.setType(ptrTy->elementType()); |
|
352 it.setValue(p); |
|
353 } else { |
|
354 it.remove(); |
|
355 } |
|
356 } |
|
357 } |
|
358 return false; |
|
359 } |
|
360 |
|
361 bool ResolveExpression::visit(CompoundLiteralAST *ast) |
|
362 { |
|
363 accept(ast->type_id); |
|
364 return false; |
|
365 } |
|
366 |
|
367 bool ResolveExpression::visit(QualifiedNameAST *ast) |
|
368 { |
|
369 ResolveClass resolveClass; |
|
370 const Name *name = ast->name; |
|
371 |
|
372 QList<Symbol *> symbols = _context.resolve(name); |
|
373 foreach (Symbol *symbol, symbols) { |
|
374 if (symbol->isTypedef()) { |
|
375 if (NamedType *namedTy = symbol->type()->asNamedType()) { |
|
376 const LookupItem r(namedTy, symbol); |
|
377 const QList<Symbol *> resolvedClasses = |
|
378 resolveClass(namedTy->name(), r, _context); |
|
379 if (resolvedClasses.count()) { |
|
380 foreach (Symbol *s, resolvedClasses) { |
|
381 addResult(s->type(), s); |
|
382 } |
|
383 continue; |
|
384 } |
|
385 } |
|
386 } |
|
387 addResult(symbol->type(), symbol); |
|
388 } |
|
389 return false; |
|
390 } |
|
391 |
|
392 bool ResolveExpression::visit(OperatorFunctionIdAST *) |
|
393 { |
|
394 return false; |
|
395 } |
|
396 |
|
397 bool ResolveExpression::visit(ConversionFunctionIdAST *) |
|
398 { |
|
399 return false; |
|
400 } |
|
401 |
|
402 bool ResolveExpression::visit(SimpleNameAST *ast) |
|
403 { |
|
404 QList<Symbol *> symbols = _context.resolve(ast->name); |
|
405 foreach (Symbol *symbol, symbols) |
|
406 addResult(symbol->type(), symbol); |
|
407 |
|
408 return false; |
|
409 } |
|
410 |
|
411 bool ResolveExpression::visit(DestructorNameAST *) |
|
412 { |
|
413 FullySpecifiedType ty(control()->voidType()); |
|
414 addResult(ty); |
|
415 return false; |
|
416 } |
|
417 |
|
418 bool ResolveExpression::visit(TemplateIdAST *ast) |
|
419 { |
|
420 QList<Symbol *> symbols = _context.resolve(ast->name); |
|
421 foreach (Symbol *symbol, symbols) |
|
422 addResult(symbol->type(), symbol); |
|
423 |
|
424 return false; |
|
425 } |
|
426 |
|
427 bool ResolveExpression::maybeValidPrototype(Function *funTy, unsigned actualArgumentCount) const |
|
428 { |
|
429 unsigned minNumberArguments = 0; |
|
430 |
|
431 for (; minNumberArguments < funTy->argumentCount(); ++minNumberArguments) { |
|
432 Argument *arg = funTy->argumentAt(minNumberArguments)->asArgument(); |
|
433 |
|
434 if (arg->hasInitializer()) |
|
435 break; |
|
436 } |
|
437 |
|
438 if (actualArgumentCount < minNumberArguments) { |
|
439 // not enough arguments. |
|
440 return false; |
|
441 |
|
442 } else if (! funTy->isVariadic() && actualArgumentCount > funTy->argumentCount()) { |
|
443 // too many arguments. |
|
444 return false; |
|
445 } |
|
446 |
|
447 return true; |
|
448 } |
|
449 |
|
450 bool ResolveExpression::visit(CallAST *ast) |
|
451 { |
|
452 ResolveClass resolveClass; |
|
453 |
|
454 const QList<LookupItem> baseResults = _results; |
|
455 _results.clear(); |
|
456 |
|
457 // Compute the types of the actual arguments. |
|
458 int actualArgumentCount = 0; |
|
459 |
|
460 //QList< QList<Result> > arguments; |
|
461 for (ExpressionListAST *exprIt = ast->expression_list; exprIt; exprIt = exprIt->next) { |
|
462 //arguments.append(operator()(exprIt->expression)); |
|
463 ++actualArgumentCount; |
|
464 } |
|
465 |
|
466 const Name *functionCallOp = control()->operatorNameId(OperatorNameId::FunctionCallOp); |
|
467 |
|
468 foreach (const LookupItem &result, baseResults) { |
|
469 FullySpecifiedType ty = result.type().simplified(); |
|
470 Symbol *lastVisibleSymbol = result.lastVisibleSymbol(); |
|
471 |
|
472 if (NamedType *namedTy = ty->asNamedType()) { |
|
473 const QList<Symbol *> classObjectCandidates = resolveClass(namedTy->name(), result, _context); |
|
474 |
|
475 foreach (Symbol *classObject, classObjectCandidates) { |
|
476 const QList<LookupItem> overloads = resolveMember(functionCallOp, classObject->asClass(), namedTy->name()); |
|
477 |
|
478 foreach (const LookupItem &o, overloads) { |
|
479 FullySpecifiedType overloadTy = o.type().simplified(); |
|
480 |
|
481 if (Function *funTy = overloadTy->asFunctionType()) { |
|
482 if (maybeValidPrototype(funTy, actualArgumentCount)) |
|
483 addResult(funTy->returnType().simplified(), lastVisibleSymbol); |
|
484 } |
|
485 } |
|
486 } |
|
487 |
|
488 } else if (Function *funTy = ty->asFunctionType()) { |
|
489 if (maybeValidPrototype(funTy, actualArgumentCount)) |
|
490 addResult(funTy->returnType().simplified(), lastVisibleSymbol); |
|
491 |
|
492 } else if (Class *classTy = ty->asClassType()) { |
|
493 // Constructor call |
|
494 FullySpecifiedType ctorTy = control()->namedType(classTy->name()); |
|
495 addResult(ctorTy, lastVisibleSymbol); |
|
496 } |
|
497 } |
|
498 |
|
499 return false; |
|
500 } |
|
501 |
|
502 bool ResolveExpression::visit(ArrayAccessAST *ast) |
|
503 { |
|
504 const QList<LookupItem> baseResults = _results; |
|
505 _results.clear(); |
|
506 |
|
507 const QList<LookupItem> indexResults = operator()(ast->expression); |
|
508 ResolveClass resolveClass; |
|
509 |
|
510 const Name *arrayAccessOp = control()->operatorNameId(OperatorNameId::ArrayAccessOp); |
|
511 |
|
512 foreach (const LookupItem &result, baseResults) { |
|
513 FullySpecifiedType ty = result.type().simplified(); |
|
514 Symbol *contextSymbol = result.lastVisibleSymbol(); |
|
515 |
|
516 if (PointerType *ptrTy = ty->asPointerType()) { |
|
517 addResult(ptrTy->elementType().simplified(), contextSymbol); |
|
518 |
|
519 } else if (ArrayType *arrTy = ty->asArrayType()) { |
|
520 addResult(arrTy->elementType().simplified(), contextSymbol); |
|
521 |
|
522 } else if (NamedType *namedTy = ty->asNamedType()) { |
|
523 const QList<Symbol *> classObjectCandidates = |
|
524 resolveClass(namedTy->name(), result, _context); |
|
525 |
|
526 foreach (Symbol *classObject, classObjectCandidates) { |
|
527 Q_ASSERT(classObject->isClass()); |
|
528 |
|
529 const QList<LookupItem> overloads = |
|
530 resolveMember(arrayAccessOp, classObject->asClass(), namedTy->name()); |
|
531 |
|
532 foreach (LookupItem r, overloads) { |
|
533 FullySpecifiedType ty = r.type().simplified(); |
|
534 if (Function *funTy = ty->asFunctionType()) { |
|
535 ty = funTy->returnType().simplified(); |
|
536 addResult(ty, funTy); |
|
537 } |
|
538 } |
|
539 } |
|
540 } |
|
541 } |
|
542 return false; |
|
543 } |
|
544 |
|
545 bool ResolveExpression::visit(MemberAccessAST *ast) |
|
546 { |
|
547 // The candidate types for the base expression are stored in |
|
548 // _results. |
|
549 QList<LookupItem> baseResults = _results; |
|
550 |
|
551 // Evaluate the expression-id that follows the access operator. |
|
552 const Name *memberName = 0; |
|
553 if (ast->member_name) |
|
554 memberName = ast->member_name->name; |
|
555 |
|
556 // Remember the access operator. |
|
557 const int accessOp = tokenKind(ast->access_token); |
|
558 |
|
559 _results = resolveMemberExpression(baseResults, accessOp, memberName); |
|
560 |
|
561 return false; |
|
562 } |
|
563 |
|
564 QList<LookupItem> |
|
565 ResolveExpression::resolveBaseExpression(const QList<LookupItem> &baseResults, int accessOp, |
|
566 bool *replacedDotOperator) const |
|
567 { |
|
568 QList<LookupItem> results; |
|
569 |
|
570 if (baseResults.isEmpty()) |
|
571 return results; |
|
572 |
|
573 LookupItem result = baseResults.first(); |
|
574 FullySpecifiedType ty = result.type().simplified(); |
|
575 Symbol *lastVisibleSymbol = result.lastVisibleSymbol(); |
|
576 |
|
577 if (Function *funTy = ty->asFunctionType()) { |
|
578 if (funTy->isAmbiguous()) |
|
579 ty = funTy->returnType().simplified(); |
|
580 } |
|
581 |
|
582 if (accessOp == T_ARROW) { |
|
583 if (lastVisibleSymbol && ty->isClassType() && ! lastVisibleSymbol->isClass()) { |
|
584 // ### remove ! lastVisibleSymbol->isClass() from the condition. |
|
585 results.append(LookupItem(ty, lastVisibleSymbol)); |
|
586 |
|
587 } else if (NamedType *namedTy = ty->asNamedType()) { |
|
588 // ### This code is pretty slow. |
|
589 const QList<Symbol *> candidates = _context.resolve(namedTy->name()); |
|
590 |
|
591 foreach (Symbol *candidate, candidates) { |
|
592 if (candidate->isTypedef()) { |
|
593 FullySpecifiedType declTy = candidate->type().simplified(); |
|
594 const LookupItem r(declTy, candidate); |
|
595 |
|
596 // update the result |
|
597 result = r; |
|
598 |
|
599 // refresh the cached ty and lastVisibileSymbol. |
|
600 ty = result.type().simplified(); |
|
601 lastVisibleSymbol = result.lastVisibleSymbol(); |
|
602 break; |
|
603 } |
|
604 } |
|
605 } |
|
606 |
|
607 if (NamedType *namedTy = ty->asNamedType()) { |
|
608 ResolveClass resolveClass; |
|
609 const Name *arrowAccessOp = control()->operatorNameId(OperatorNameId::ArrowOp); |
|
610 const QList<Symbol *> candidates = resolveClass(namedTy->name(), result, _context); |
|
611 |
|
612 foreach (Symbol *classObject, candidates) { |
|
613 const QList<LookupItem> overloads = resolveMember(arrowAccessOp, classObject->asClass(), |
|
614 namedTy->name()); |
|
615 |
|
616 foreach (const LookupItem &r, overloads) { |
|
617 FullySpecifiedType typeOfOverloadFunction = r.type().simplified(); |
|
618 Symbol *lastVisibleSymbol = r.lastVisibleSymbol(); |
|
619 Function *funTy = typeOfOverloadFunction->asFunctionType(); |
|
620 if (! funTy) |
|
621 continue; |
|
622 |
|
623 typeOfOverloadFunction = funTy->returnType().simplified(); |
|
624 |
|
625 if (PointerType *ptrTy = typeOfOverloadFunction->asPointerType()) { |
|
626 FullySpecifiedType elementTy = ptrTy->elementType().simplified(); |
|
627 |
|
628 if (elementTy->isNamedType()) |
|
629 results.append(LookupItem(elementTy, lastVisibleSymbol)); |
|
630 } |
|
631 } |
|
632 } |
|
633 } else if (PointerType *ptrTy = ty->asPointerType()) { |
|
634 FullySpecifiedType elementTy = ptrTy->elementType().simplified(); |
|
635 |
|
636 if (elementTy->isNamedType() || elementTy->isClassType()) |
|
637 results.append(LookupItem(elementTy, lastVisibleSymbol)); |
|
638 } |
|
639 } else if (accessOp == T_DOT) { |
|
640 if (replacedDotOperator) { |
|
641 if (PointerType *ptrTy = ty->asPointerType()) { |
|
642 *replacedDotOperator = true; |
|
643 ty = ptrTy->elementType().simplified(); |
|
644 } else if (ArrayType *arrTy = ty->asArrayType()) { |
|
645 *replacedDotOperator = true; |
|
646 ty = arrTy->elementType().simplified(); |
|
647 } |
|
648 } |
|
649 |
|
650 if (NamedType *namedTy = ty->asNamedType()) { |
|
651 const QList<Scope *> visibleScopes = _context.visibleScopes(result); |
|
652 const QList<Symbol *> candidates = _context.resolve(namedTy->name(), visibleScopes); |
|
653 foreach (Symbol *candidate, candidates) { |
|
654 if (candidate->isTypedef() && candidate->type()->isNamedType()) { |
|
655 ty = candidate->type(); |
|
656 lastVisibleSymbol = candidate; |
|
657 break; |
|
658 } else if (TypenameArgument *arg = candidate->asTypenameArgument()) { |
|
659 ty = arg->type(); |
|
660 lastVisibleSymbol = candidate; |
|
661 break; |
|
662 } |
|
663 } |
|
664 |
|
665 results.append(LookupItem(ty, lastVisibleSymbol)); |
|
666 |
|
667 } else if (Function *fun = ty->asFunctionType()) { |
|
668 Scope *funScope = fun->scope(); |
|
669 |
|
670 if (funScope && (funScope->isBlockScope() || funScope->isNamespaceScope())) { |
|
671 FullySpecifiedType retTy = fun->returnType().simplified(); |
|
672 results.append(LookupItem(retTy, lastVisibleSymbol)); |
|
673 } |
|
674 } |
|
675 } |
|
676 |
|
677 return removeDuplicates(results); |
|
678 } |
|
679 |
|
680 QList<LookupItem> |
|
681 ResolveExpression::resolveMemberExpression(const QList<LookupItem> &baseResults, |
|
682 unsigned accessOp, |
|
683 const Name *memberName, |
|
684 bool *replacedDotOperator) const |
|
685 { |
|
686 ResolveClass resolveClass; |
|
687 QList<LookupItem> results; |
|
688 |
|
689 const QList<LookupItem> classObjectResults = resolveBaseExpression(baseResults, accessOp, replacedDotOperator); |
|
690 foreach (const LookupItem &r, classObjectResults) { |
|
691 FullySpecifiedType ty = r.type(); |
|
692 |
|
693 if (Class *klass = ty->asClassType()) |
|
694 results += resolveMember(memberName, klass); |
|
695 |
|
696 else if (NamedType *namedTy = ty->asNamedType()) { |
|
697 const Name *className = namedTy->name(); |
|
698 const QList<Symbol *> classes = resolveClass(className, r, _context); |
|
699 |
|
700 foreach (Symbol *c, classes) { |
|
701 if (Class *klass = c->asClass()) |
|
702 results += resolveMember(memberName, klass, className); |
|
703 } |
|
704 } |
|
705 } |
|
706 |
|
707 return removeDuplicates(results); |
|
708 } |
|
709 |
|
710 QList<LookupItem> |
|
711 ResolveExpression::resolveMember(const Name *memberName, Class *klass, |
|
712 const Name *className) const |
|
713 { |
|
714 QList<LookupItem> results; |
|
715 |
|
716 if (! className) |
|
717 className = klass->name(); |
|
718 |
|
719 if (! className) |
|
720 return results; |
|
721 |
|
722 QList<Scope *> scopes; |
|
723 _context.expand(klass->members(), _context.visibleScopes(), &scopes); |
|
724 |
|
725 const QList<Symbol *> candidates = _context.resolve(memberName, scopes); |
|
726 |
|
727 foreach (Symbol *candidate, candidates) { |
|
728 FullySpecifiedType ty = candidate->type(); |
|
729 const Name *unqualifiedNameId = className; |
|
730 |
|
731 if (const QualifiedNameId *q = className->asQualifiedNameId()) |
|
732 unqualifiedNameId = q->unqualifiedNameId(); |
|
733 |
|
734 if (const TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) { |
|
735 GenTemplateInstance::Substitution subst; |
|
736 |
|
737 for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) { |
|
738 FullySpecifiedType templArgTy = templId->templateArgumentAt(i); |
|
739 |
|
740 if (i < klass->templateParameterCount()) { |
|
741 const Name *templArgName = klass->templateParameterAt(i)->name(); |
|
742 if (templArgName && templArgName->identifier()) { |
|
743 const Identifier *templArgId = templArgName->identifier(); |
|
744 subst.append(qMakePair(templArgId, templArgTy)); |
|
745 } |
|
746 } |
|
747 } |
|
748 |
|
749 GenTemplateInstance inst(_context, subst); |
|
750 ty = inst(candidate); |
|
751 } |
|
752 |
|
753 results.append(LookupItem(ty, candidate)); |
|
754 } |
|
755 |
|
756 return removeDuplicates(results); |
|
757 } |
|
758 |
|
759 |
|
760 QList<LookupItem> |
|
761 ResolveExpression::resolveMember(const Name *memberName, ObjCClass *klass) const |
|
762 { |
|
763 QList<LookupItem> results; |
|
764 |
|
765 if (!memberName || !klass) |
|
766 return results; |
|
767 |
|
768 QList<Scope *> scopes; |
|
769 _context.expand(klass->members(), _context.visibleScopes(), &scopes); |
|
770 |
|
771 QList<Symbol *> candidates = _context.resolve(memberName, scopes); |
|
772 |
|
773 foreach (Symbol *candidate, candidates) { |
|
774 FullySpecifiedType ty = candidate->type(); |
|
775 |
|
776 results.append(LookupItem(ty, candidate)); |
|
777 } |
|
778 |
|
779 return removeDuplicates(results); |
|
780 } |
|
781 |
|
782 bool ResolveExpression::visit(PostIncrDecrAST *) |
|
783 { |
|
784 return false; |
|
785 } |
|
786 |
|
787 bool ResolveExpression::visit(ObjCMessageExpressionAST *ast) |
|
788 { |
|
789 QList<LookupItem> receiverResults = operator()(ast->receiver_expression); |
|
790 |
|
791 if (!receiverResults.isEmpty()) { |
|
792 LookupItem result = receiverResults.first(); |
|
793 FullySpecifiedType ty = result.type().simplified(); |
|
794 const Name *klassName = 0; |
|
795 |
|
796 if (const ObjCClass *classTy = ty->asObjCClassType()) { |
|
797 // static access, e.g.: |
|
798 // [NSObject description]; |
|
799 klassName = classTy->name(); |
|
800 } else if (const PointerType *ptrTy = ty->asPointerType()) { |
|
801 const FullySpecifiedType pointeeTy = ptrTy->elementType(); |
|
802 if (pointeeTy && pointeeTy->isNamedType()) { |
|
803 // dynamic access, e.g.: |
|
804 // NSObject *obj = ...; [obj release]; |
|
805 klassName = pointeeTy->asNamedType()->name(); |
|
806 } |
|
807 } |
|
808 |
|
809 if (klassName&&ast->selector && ast->selector->selector_name) { |
|
810 ResolveObjCClass resolveObjCClass; |
|
811 QList<Symbol *> resolvedSymbols = resolveObjCClass(klassName, result, _context); |
|
812 foreach (Symbol *resolvedSymbol, resolvedSymbols) |
|
813 if (ObjCClass *klass = resolvedSymbol->asObjCClass()) |
|
814 _results.append(resolveMember(ast->selector->selector_name, klass)); |
|
815 } |
|
816 } |
|
817 |
|
818 return false; |
|
819 } |
|
820 |
|
821 //////////////////////////////////////////////////////////////////////////////// |
|
822 ResolveClass::ResolveClass() |
|
823 { } |
|
824 |
|
825 QList<Symbol *> ResolveClass::operator()(const Name *name, |
|
826 const LookupItem &p, |
|
827 const LookupContext &context) |
|
828 { |
|
829 const QList<LookupItem> previousBlackList = _blackList; |
|
830 const QList<Symbol *> symbols = resolveClass(name, p, context); |
|
831 _blackList = previousBlackList; |
|
832 return symbols; |
|
833 } |
|
834 |
|
835 QList<Symbol *> ResolveClass::resolveClass(const Name *name, |
|
836 const LookupItem &p, |
|
837 const LookupContext &context) |
|
838 { |
|
839 QList<Symbol *> resolvedSymbols; |
|
840 |
|
841 if (_blackList.contains(p)) |
|
842 return resolvedSymbols; |
|
843 |
|
844 _blackList.append(p); |
|
845 |
|
846 const QList<Symbol *> candidates = |
|
847 context.resolve(name, context.visibleScopes(p)); |
|
848 |
|
849 foreach (Symbol *candidate, candidates) { |
|
850 if (Class *klass = candidate->asClass()) { |
|
851 if (resolvedSymbols.contains(klass)) |
|
852 continue; // we already know about `klass' |
|
853 resolvedSymbols.append(klass); |
|
854 } else if (candidate->isTypedef()) { |
|
855 if (Declaration *decl = candidate->asDeclaration()) { |
|
856 if (Class *asClass = decl->type()->asClassType()) { |
|
857 // typedef struct { } Point; |
|
858 // Point pt; |
|
859 // pt. |
|
860 resolvedSymbols.append(asClass); |
|
861 } else { |
|
862 // typedef Point Boh; |
|
863 // Boh b; |
|
864 // b. |
|
865 FullySpecifiedType declType = decl->type().simplified(); |
|
866 if (NamedType *namedTy = declType->asNamedType()) { |
|
867 const LookupItem r(declType, decl); |
|
868 resolvedSymbols += resolveClass(namedTy->name(), r, context); |
|
869 } |
|
870 } |
|
871 } |
|
872 } else if (Declaration *decl = candidate->asDeclaration()) { |
|
873 if (Function *funTy = decl->type()->asFunctionType()) { |
|
874 // QString foo("ciao"); |
|
875 // foo. |
|
876 if (funTy->scope() && (funTy->scope()->isBlockScope() || funTy->scope()->isNamespaceScope())) { |
|
877 FullySpecifiedType retTy = funTy->returnType().simplified(); |
|
878 if (NamedType *namedTy = retTy->asNamedType()) { |
|
879 const LookupItem r(retTy, decl); |
|
880 resolvedSymbols += resolveClass(namedTy->name(), r, context); |
|
881 } |
|
882 } |
|
883 } |
|
884 } |
|
885 } |
|
886 |
|
887 return resolvedSymbols; |
|
888 } |
|
889 |
|
890 ResolveObjCClass::ResolveObjCClass() |
|
891 {} |
|
892 |
|
893 QList<Symbol *> ResolveObjCClass::operator ()(const Name *name, |
|
894 const LookupItem &p, |
|
895 const LookupContext &context) |
|
896 { |
|
897 QList<Symbol *> resolvedSymbols; |
|
898 |
|
899 const QList<Symbol *> candidates = |
|
900 context.resolve(name, context.visibleScopes(p)); |
|
901 |
|
902 foreach (Symbol *candidate, candidates) { |
|
903 if (ObjCClass *klass = candidate->asObjCClass()) { |
|
904 if (resolvedSymbols.contains(klass)) |
|
905 continue; // we already know about `klass' |
|
906 resolvedSymbols.append(klass); |
|
907 } else if (candidate->isTypedef()) { |
|
908 if (Declaration *decl = candidate->asDeclaration()) { |
|
909 if (decl->type()->isObjCClassType()) { |
|
910 ObjCClass *klass = decl->type()->asObjCClassType(); |
|
911 if (resolvedSymbols.contains(klass)) |
|
912 continue; |
|
913 resolvedSymbols.append(klass); |
|
914 } |
|
915 } |
|
916 } |
|
917 } |
|
918 |
|
919 return resolvedSymbols; |
|
920 } |