OSDN Git Service

9af04e953c659b29329fc9badf639135a2d0c479
[qt-creator-jp/qt-creator-jp.git] / src / libs / cplusplus / ResolveExpression.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
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 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "ResolveExpression.h"
35 #include "LookupContext.h"
36 #include "Overview.h"
37 #include "DeprecatedGenTemplateInstance.h"
38 #include "CppRewriter.h"
39
40 #include <Control.h>
41 #include <AST.h>
42 #include <Scope.h>
43 #include <Names.h>
44 #include <Symbols.h>
45 #include <Literals.h>
46 #include <CoreTypes.h>
47 #include <TypeVisitor.h>
48 #include <NameVisitor.h>
49
50 #include <QtCore/QList>
51 #include <QtCore/QtDebug>
52
53 using namespace CPlusPlus;
54
55 namespace {
56
57 template <typename _Tp>
58 static QList<_Tp> removeDuplicates(const QList<_Tp> &results)
59 {
60     QList<_Tp> uniqueList;
61     QSet<_Tp> processed;
62     foreach (const _Tp &r, results) {
63         if (processed.contains(r))
64             continue;
65
66         processed.insert(r);
67         uniqueList.append(r);
68     }
69
70     return uniqueList;
71 }
72
73 } // end of anonymous namespace
74
75 /////////////////////////////////////////////////////////////////////
76 // ResolveExpression
77 /////////////////////////////////////////////////////////////////////
78 ResolveExpression::ResolveExpression(const LookupContext &context)
79     : ASTVisitor(context.expressionDocument()->translationUnit()),
80       _scope(0),
81       _context(context),
82       bind(context.expressionDocument()->translationUnit()),
83       _reference(false)
84 { }
85
86 ResolveExpression::~ResolveExpression()
87 { }
88
89 QList<LookupItem> ResolveExpression::operator()(ExpressionAST *ast, Scope *scope)
90 { return resolve(ast, scope); }
91
92 QList<LookupItem> ResolveExpression::reference(ExpressionAST *ast, Scope *scope)
93 { return resolve(ast, scope, true); }
94
95 QList<LookupItem> ResolveExpression::resolve(ExpressionAST *ast, Scope *scope, bool ref)
96 {
97     if (! scope)
98         return QList<LookupItem>();
99
100     std::swap(_scope, scope);
101     std::swap(_reference, ref);
102
103     const QList<LookupItem> result = expression(ast);
104
105     std::swap(_reference, ref);
106     std::swap(_scope, scope);
107
108     return result;
109 }
110
111 QList<LookupItem> ResolveExpression::expression(ExpressionAST *ast)
112 {
113     const QList<LookupItem> previousResults = switchResults(QList<LookupItem>());
114     accept(ast);
115     return removeDuplicates(switchResults(previousResults));
116 }
117
118 QList<LookupItem> ResolveExpression::switchResults(const QList<LookupItem> &results)
119 {
120     const QList<LookupItem> previousResults = _results;
121     _results = results;
122     return previousResults;
123 }
124
125 void ResolveExpression::addResults(const QList<Symbol *> &symbols)
126 {
127     foreach (Symbol *symbol, symbols) {
128         LookupItem item;
129         item.setType(symbol->type());
130         item.setScope(symbol->enclosingScope());
131         item.setDeclaration(symbol);
132         _results.append(item);
133     }
134 }
135
136 void ResolveExpression::addResults(const QList<LookupItem> &items)
137 {
138     _results += items;
139 }
140
141 void ResolveExpression::addResult(const FullySpecifiedType &ty, Scope *scope)
142 {
143     LookupItem item;
144     item.setType(ty);
145     item.setScope(scope);
146
147     _results.append(item);
148 }
149
150 bool ResolveExpression::visit(IdExpressionAST *ast)
151 {
152     accept(ast->name);
153     return false;
154 }
155
156 bool ResolveExpression::visit(BinaryExpressionAST *ast)
157 {
158     if (tokenKind(ast->binary_op_token) == T_COMMA && ast->right_expression && ast->right_expression->asQtMethod() != 0) {
159
160         if (ast->left_expression && ast->left_expression->asQtMethod() != 0)
161             thisObject();
162         else
163             accept(ast->left_expression);
164
165         QtMethodAST *qtMethod = ast->right_expression->asQtMethod();
166         if (DeclaratorAST *d = qtMethod->declarator) {
167             if (d->core_declarator) {
168                 if (DeclaratorIdAST *declaratorId = d->core_declarator->asDeclaratorId()) {
169                     if (NameAST *nameAST = declaratorId->name) {
170                         if (ClassOrNamespace *binding = baseExpression(_results, T_ARROW)) {
171                             _results.clear();
172                             addResults(binding->lookup(nameAST->name));
173                         }
174                     }
175                 }
176             }
177         }
178
179         return false;
180     }
181
182     accept(ast->left_expression);
183     return false;
184 }
185
186 bool ResolveExpression::visit(CastExpressionAST *ast)
187 {
188     Scope *dummyScope = _context.expressionDocument()->globalNamespace();
189     FullySpecifiedType ty = bind(ast->type_id, dummyScope);
190     addResult(ty, _scope);
191     return false;
192 }
193
194 bool ResolveExpression::visit(ConditionAST *)
195 {
196     // nothing to do.
197     return false;
198 }
199
200 bool ResolveExpression::visit(ConditionalExpressionAST *ast)
201 {
202     if (ast->left_expression)
203         accept(ast->left_expression);
204
205     else if (ast->right_expression)
206         accept(ast->right_expression);
207
208     return false;
209 }
210
211 bool ResolveExpression::visit(CppCastExpressionAST *ast)
212 {
213     Scope *dummyScope = _context.expressionDocument()->globalNamespace();
214     FullySpecifiedType ty = bind(ast->type_id, dummyScope);
215     addResult(ty, _scope);
216     return false;
217 }
218
219 bool ResolveExpression::visit(DeleteExpressionAST *)
220 {
221     FullySpecifiedType ty(control()->voidType());
222     addResult(ty, _scope);
223     return false;
224 }
225
226 bool ResolveExpression::visit(ArrayInitializerAST *)
227 {
228     // nothing to do.
229     return false;
230 }
231
232 bool ResolveExpression::visit(NewExpressionAST *ast)
233 {
234     if (ast->new_type_id) {
235         Scope *dummyScope = _context.expressionDocument()->globalNamespace();
236         FullySpecifiedType ty = bind(ast->new_type_id, dummyScope);
237         FullySpecifiedType ptrTy(control()->pointerType(ty));
238         addResult(ptrTy, _scope);
239     }
240     // nothing to do.
241     return false;
242 }
243
244 bool ResolveExpression::visit(TypeidExpressionAST *)
245 {
246     const Name *stdName = control()->identifier("std");
247     const Name *tiName = control()->identifier("type_info");
248     const Name *q = control()->qualifiedNameId(control()->qualifiedNameId(/* :: */ 0, stdName), tiName);
249
250     FullySpecifiedType ty(control()->namedType(q));
251     addResult(ty, _scope);
252
253     return false;
254 }
255
256 bool ResolveExpression::visit(TypenameCallExpressionAST *)
257 {
258     // nothing to do
259     return false;
260 }
261
262 bool ResolveExpression::visit(TypeConstructorCallAST *)
263 {
264     // nothing to do.
265     return false;
266 }
267
268 bool ResolveExpression::visit(SizeofExpressionAST *)
269 {
270     FullySpecifiedType ty(control()->integerType(IntegerType::Int));
271     ty.setUnsigned(true);
272     addResult(ty, _scope);
273     return false;
274 }
275
276 bool ResolveExpression::visit(NumericLiteralAST *ast)
277 {
278     const Token &tk = tokenAt(ast->literal_token);
279
280     Type *type = 0;
281     bool isUnsigned = false;
282
283     if (tk.is(T_CHAR_LITERAL))
284         type = control()->integerType(IntegerType::Char);
285     else if (tk.is(T_WIDE_CHAR_LITERAL))
286         type = control()->integerType(IntegerType::WideChar);
287     else if (const NumericLiteral *literal = numericLiteral(ast->literal_token)) {
288         isUnsigned = literal->isUnsigned();
289
290         if (literal->isInt())
291             type = control()->integerType(IntegerType::Int);
292         else if (literal->isLong())
293             type = control()->integerType(IntegerType::Long);
294         else if (literal->isLongLong())
295             type = control()->integerType(IntegerType::LongLong);
296         else if (literal->isFloat())
297             type = control()->floatType(FloatType::Float);
298         else if (literal->isDouble())
299             type = control()->floatType(FloatType::Double);
300         else if (literal->isLongDouble())
301             type = control()->floatType(FloatType::LongDouble);
302         else
303             type = control()->integerType(IntegerType::Int);
304     }
305
306     FullySpecifiedType ty(type);
307     ty.setUnsigned(isUnsigned);
308     addResult(ty, _scope);
309     return false;
310 }
311
312 bool ResolveExpression::visit(BoolLiteralAST *)
313 {
314     FullySpecifiedType ty(control()->integerType(IntegerType::Bool));
315     addResult(ty, _scope);
316     return false;
317 }
318
319 bool ResolveExpression::visit(ThisExpressionAST *)
320 {
321     thisObject();
322     return false;
323 }
324
325 void ResolveExpression::thisObject()
326 {
327     Scope *scope = _scope;
328     for (; scope; scope = scope->enclosingScope()) {
329         if (Function *fun = scope->asFunction()) {
330             if (Class *klass = scope->enclosingClass()) {
331                 FullySpecifiedType classTy(control()->namedType(klass->name()));
332                 FullySpecifiedType ptrTy(control()->pointerType(classTy));
333                 addResult(ptrTy, fun->enclosingScope());
334                 break;
335             } else if (const QualifiedNameId *q = fun->name()->asQualifiedNameId()) {
336                 if (q->base()) {
337                     FullySpecifiedType classTy(control()->namedType(q->base()));
338                     FullySpecifiedType ptrTy(control()->pointerType(classTy));
339                     addResult(ptrTy, fun->enclosingScope());
340                 }
341                 break;
342             }
343         }
344     }
345 }
346
347 bool ResolveExpression::visit(CompoundExpressionAST *ast)
348 {
349     CompoundStatementAST *cStmt = ast->statement;
350     if (cStmt && cStmt->statement_list) {
351         accept(cStmt->statement_list->lastValue());
352     }
353     return false;
354 }
355
356 bool ResolveExpression::visit(NestedExpressionAST *ast)
357 {
358     accept(ast->expression);
359     return false;
360 }
361
362 bool ResolveExpression::visit(StringLiteralAST *)
363 {
364     FullySpecifiedType charTy = control()->integerType(IntegerType::Char);
365     charTy.setConst(true);
366     FullySpecifiedType ty(control()->pointerType(charTy));
367     addResult(ty, _scope);
368     return false;
369 }
370
371 bool ResolveExpression::visit(ThrowExpressionAST *)
372 {
373     return false;
374 }
375
376 bool ResolveExpression::visit(TypeIdAST *)
377 {
378     return false;
379 }
380
381 bool ResolveExpression::visit(UnaryExpressionAST *ast)
382 {
383     accept(ast->expression);
384     unsigned unaryOp = tokenKind(ast->unary_op_token);
385     if (unaryOp == T_AMPER) {
386         QMutableListIterator<LookupItem > it(_results);
387         while (it.hasNext()) {
388             LookupItem p = it.next();
389             FullySpecifiedType ty = p.type();
390             ty.setType(control()->pointerType(ty));
391             p.setType(ty);
392             it.setValue(p);
393         }
394     } else if (unaryOp == T_STAR) {
395         QMutableListIterator<LookupItem > it(_results);
396         while (it.hasNext()) {
397             LookupItem p = it.next();
398             if (PointerType *ptrTy = p.type()->asPointerType()) {
399                 p.setType(ptrTy->elementType());
400                 it.setValue(p);
401             } else {
402                 it.remove();
403             }
404         }
405     }
406     return false;
407 }
408
409 bool ResolveExpression::visit(CompoundLiteralAST *ast)
410 {
411     accept(ast->type_id);
412     return false;
413 }
414
415 bool ResolveExpression::visit(QualifiedNameAST *ast)
416 {
417     if (const Name *name = ast->name) {
418         const QList<LookupItem> candidates = _context.lookup(name, _scope);
419         addResults(candidates);
420     }
421
422     return false;
423 }
424
425 bool ResolveExpression::visit(SimpleNameAST *ast)
426 {
427     const QList<LookupItem> candidates = _context.lookup(ast->name, _scope);
428     addResults(candidates);
429     return false;
430 }
431
432 bool ResolveExpression::visit(TemplateIdAST *ast)
433 {
434     const QList<LookupItem> candidates = _context.lookup(ast->name, _scope);
435     addResults(candidates);
436     return false;
437 }
438
439 bool ResolveExpression::visit(DestructorNameAST *)
440 {
441     FullySpecifiedType ty(control()->voidType());
442     addResult(ty, _scope);
443     return false;
444 }
445
446 bool ResolveExpression::visit(OperatorFunctionIdAST *)
447 {
448     return false;
449 }
450
451 bool ResolveExpression::visit(ConversionFunctionIdAST *)
452 {
453     return false;
454 }
455
456 bool ResolveExpression::maybeValidPrototype(Function *funTy, unsigned actualArgumentCount)
457 {
458     return funTy->maybeValidPrototype(actualArgumentCount);
459 }
460
461 bool ResolveExpression::implicitConversion(const FullySpecifiedType &sourceTy, const FullySpecifiedType &targetTy) const
462 {
463     if (sourceTy.isEqualTo(targetTy))
464         return true;
465     else if (sourceTy.simplified().isEqualTo(targetTy.simplified()))
466         return true;
467     return false;
468 }
469
470 bool ResolveExpression::visit(CallAST *ast)
471 {
472     const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope);
473
474     // Compute the types of the actual arguments.
475     unsigned actualArgumentCount = 0;
476
477     QList< QList<LookupItem> > arguments;
478     for (ExpressionListAST *exprIt = ast->expression_list; exprIt; exprIt = exprIt->next) {
479         if (_reference)
480             arguments.append(resolve(exprIt->value, _scope));
481
482         ++actualArgumentCount;
483     }
484
485     if (_reference) {
486         _results.clear();
487         foreach (const LookupItem &base, baseResults) {
488             if (Function *funTy = base.type()->asFunctionType()) {
489                 if (! maybeValidPrototype(funTy, actualArgumentCount))
490                     continue;
491
492                 int score = 0;
493
494                 for (unsigned i = 0; i < funTy->argumentCount(); ++i) {
495                     const FullySpecifiedType formalTy = funTy->argumentAt(i)->type();
496
497                     FullySpecifiedType actualTy;
498                     if (i < unsigned(arguments.size())) {
499                         const QList<LookupItem> actual = arguments.at(i);
500                         if (actual.isEmpty())
501                             continue;
502
503                         actualTy = actual.first().type();
504                     } else
505                         actualTy = formalTy;
506
507                     if (implicitConversion(actualTy, formalTy))
508                         ++score;
509                 }
510
511                 if (score)
512                     _results.prepend(base);
513                 else
514                     _results.append(base);
515             }
516         }
517
518         if (_results.isEmpty())
519             _results = baseResults;
520
521         return false;
522     }
523
524     const Name *functionCallOp = control()->operatorNameId(OperatorNameId::FunctionCallOp);
525
526     foreach (const LookupItem &result, baseResults) {
527         FullySpecifiedType ty = result.type().simplified();
528         Scope *scope = result.scope();
529
530         if (NamedType *namedTy = ty->asNamedType()) {
531             if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) {
532                 foreach (const LookupItem &r, b->find(functionCallOp)) {
533                     Symbol *overload = r.declaration();
534                     if (Function *funTy = overload->type()->asFunctionType()) {
535                         if (maybeValidPrototype(funTy, actualArgumentCount)) {
536                             if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType())
537                                 addResult(proto->returnType().simplified(), scope);
538                         }
539                     }
540                 }
541             }
542
543         } else if (Function *funTy = ty->asFunctionType()) {
544             if (maybeValidPrototype(funTy, actualArgumentCount))
545                 addResult(funTy->returnType().simplified(), scope);
546
547         } else if (Class *classTy = ty->asClassType()) {
548             // Constructor call
549             FullySpecifiedType ctorTy = control()->namedType(classTy->name());
550             addResult(ctorTy, scope);
551         }
552     }
553
554     return false;
555 }
556
557 bool ResolveExpression::visit(ArrayAccessAST *ast)
558 {
559     const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope);
560     const QList<LookupItem> indexResults = resolve(ast->expression, _scope);
561
562     const Name *arrayAccessOp = control()->operatorNameId(OperatorNameId::ArrayAccessOp);
563
564     foreach (const LookupItem &result, baseResults) {
565         FullySpecifiedType ty = result.type().simplified();
566         Scope *scope = result.scope();
567
568         if (PointerType *ptrTy = ty->asPointerType()) {
569             addResult(ptrTy->elementType().simplified(), scope);
570
571         } else if (ArrayType *arrTy = ty->asArrayType()) {
572             addResult(arrTy->elementType().simplified(), scope);
573
574         } else if (NamedType *namedTy = ty->asNamedType()) {
575             if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) {
576                 foreach (const LookupItem &r, b->find(arrayAccessOp)) {
577                     Symbol *overload = r.declaration();
578                     if (Function *funTy = overload->type()->asFunctionType()) {
579                         if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType())
580                             // ### TODO: check the actual arguments
581                             addResult(proto->returnType().simplified(), scope);
582                     }
583                 }
584
585             }
586         }
587     }
588     return false;
589 }
590
591 QList<LookupItem> ResolveExpression::getMembers(ClassOrNamespace *binding, const Name *memberName) const
592 {
593     Q_UNUSED(binding);
594     Q_UNUSED(memberName);
595
596     // ### port me
597     QList<LookupItem> members;
598 #if 0
599     const QList<LookupItem> originalMembers = binding->find(memberName);
600
601     foreach (const LookupItem &m, originalMembers) {
602         if (! m.binding() || ! m.binding()->templateId()) {
603             members.append(m);
604             continue;
605         }
606
607         Symbol *decl = m.declaration();
608
609         if (Class *klass = decl->scope()->asClass()) {
610             if (klass->templateParameters() != 0) {
611                 SubstitutionMap map;
612
613                 const TemplateNameId *templateId = m.binding()->templateId();
614                 unsigned count = qMin(klass->templateParameterCount(), templateId->templateArgumentCount());
615
616                 for (unsigned i = 0; i < count; ++i) {
617                     map.bind(klass->templateParameterAt(i)->name(), templateId->templateArgumentAt(i));
618                 }
619
620                 SubstitutionEnvironment env;
621                 if (m.scope())
622                     env.switchScope(m.scope());
623                 env.setContext(_context);
624
625                 env.enter(&map);
626                 FullySpecifiedType instantiatedTy = rewriteType(decl->type(), &env, _context.control().data());
627
628                 Overview oo;
629                 oo.setShowReturnTypes(true);
630                 oo.setShowFunctionSignatures(true);
631
632                 qDebug() << "original:" << oo(decl->type(), decl->name()) << "inst:" << oo(instantiatedTy, decl->name());
633
634                 LookupItem newItem;
635                 newItem = m;
636                 newItem.setType(instantiatedTy);
637                 members.append(newItem);
638             }
639         }
640     }
641 #endif
642
643     return members;
644 }
645
646 bool ResolveExpression::visit(MemberAccessAST *ast)
647 {
648     // The candidate types for the base expression are stored in
649     // _results.
650     const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope);
651
652     // Evaluate the expression-id that follows the access operator.
653     const Name *memberName = 0;
654     if (ast->member_name)
655         memberName = ast->member_name->name;
656
657     // Remember the access operator.
658     const int accessOp = tokenKind(ast->access_token);
659
660     if (ClassOrNamespace *binding = baseExpression(baseResults, accessOp))
661         addResults(binding->lookup(memberName));
662
663     return false;
664 }
665
666 ClassOrNamespace *ResolveExpression::findClass(const FullySpecifiedType &originalTy, Scope *scope) const
667 {
668     FullySpecifiedType ty = originalTy.simplified();
669     ClassOrNamespace *binding = 0;
670
671     if (Class *klass = ty->asClassType())
672         binding = _context.lookupType(klass);
673
674     else if (NamedType *namedTy = ty->asNamedType())
675         binding = _context.lookupType(namedTy->name(), scope);
676
677     else if (Function *funTy = ty->asFunctionType())
678         return findClass(funTy->returnType(), scope);
679
680     return binding;
681 }
682
683 ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &baseResults,
684                                                     int accessOp,
685                                                     bool *replacedDotOperator) const
686 {
687     foreach (const LookupItem &r, baseResults) {
688         FullySpecifiedType ty = r.type().simplified();
689         Scope *scope = r.scope();
690
691         if (accessOp == T_ARROW) {
692             if (PointerType *ptrTy = ty->asPointerType()) {
693                 if (ClassOrNamespace *binding = findClass(ptrTy->elementType(), scope))
694                     return binding;
695
696             } else if (ClassOrNamespace *binding = findClass(ty, scope)) {
697                 // lookup for overloads of operator->
698
699                 const OperatorNameId *arrowOp = control()->operatorNameId(OperatorNameId::ArrowOp);
700                 foreach (const LookupItem &r, binding->find(arrowOp)) {
701                     Symbol *overload = r.declaration();
702                     if (! overload)
703                         continue;
704
705                     if (overload->type()->isFunctionType()) {
706                         FullySpecifiedType overloadTy = instantiate(binding->templateId(), overload);
707                         Function *instantiatedFunction = overloadTy->asFunctionType();
708                         Q_ASSERT(instantiatedFunction != 0);
709
710                         FullySpecifiedType retTy = instantiatedFunction->returnType().simplified();
711
712                         if (PointerType *ptrTy = retTy->asPointerType()) {
713                             if (ClassOrNamespace *retBinding = findClass(ptrTy->elementType(), overload->enclosingScope()))
714                                 return retBinding;
715
716                             else if (scope != overload->enclosingScope()) {
717                                 if (ClassOrNamespace *retBinding = findClass(ptrTy->elementType(), scope))
718                                     return retBinding;
719                             }
720                         }
721                     }
722                 }
723
724             }
725         } else if (accessOp == T_DOT) {
726             if (replacedDotOperator) {
727                 if (PointerType *ptrTy = ty->asPointerType()) {
728                     // replace . with ->
729                     ty = ptrTy->elementType();
730                     *replacedDotOperator = true;
731                 }
732             }
733
734             if (ClassOrNamespace *binding = findClass(ty, scope))
735                 return binding;
736         }
737     }
738
739     return 0;
740 }
741
742 FullySpecifiedType ResolveExpression::instantiate(const Name *className, Symbol *candidate) const
743 {
744     return DeprecatedGenTemplateInstance::instantiate(className, candidate, _context.control());
745 }
746
747 bool ResolveExpression::visit(PostIncrDecrAST *ast)
748 {
749     const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope);
750     _results = baseResults;
751     return false;
752 }
753
754 bool ResolveExpression::visit(ObjCMessageExpressionAST *ast)
755 {
756     const QList<LookupItem> receiverResults = resolve(ast->receiver_expression, _scope);
757
758     foreach (const LookupItem &result, receiverResults) {
759         FullySpecifiedType ty = result.type().simplified();
760         ClassOrNamespace *binding = 0;
761
762         if (ObjCClass *clazz = ty->asObjCClassType()) {
763             // static access, e.g.:
764             //   [NSObject description];
765             binding = _context.lookupType(clazz);
766         } else if (PointerType *ptrTy = ty->asPointerType()) {
767             if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) {
768                 // dynamic access, e.g.:
769                 //   NSObject *obj = ...; [obj release];
770                 binding = _context.lookupType(namedTy->name(), result.scope());
771             }
772         }
773
774         if (binding) {
775             foreach (const LookupItem &r, binding->lookup(ast->selector->name)) {
776                 Symbol *s = r.declaration();
777                 if (ObjCMethod *m = s->asObjCMethod())
778                     addResult(m->returnType(), result.scope());
779             }
780         }
781     }
782
783     return false;
784 }
785
786 const LookupContext &ResolveExpression::context() const
787 {
788     return _context;
789 }