1 /***************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Qt Software Information (qt-info@nokia.com)
10 ** Non-Open Source Usage
12 ** Licensees may use this file in accordance with the Qt Beta Version
13 ** License Agreement, Agreement version 2.2 provided with the Software or,
14 ** alternatively, in accordance with the terms contained in a written
15 ** agreement between you and Nokia.
17 ** GNU General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU General
20 ** Public License versions 2.0 or 3.0 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.GPL included in the packaging
22 ** of this file. Please review the following information to ensure GNU
23 ** General Public Licensing requirements will be met:
25 ** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
26 ** http://www.gnu.org/copyleft/gpl.html.
28 ** In addition, as a special exception, Nokia gives you certain additional
29 ** rights. These rights are described in the Nokia Qt GPL Exception
30 ** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
32 ***************************************************************************/
34 #include "ResolveExpression.h"
35 #include "LookupContext.h"
44 #include <CoreTypes.h>
45 #include <TypeVisitor.h>
46 #include <NameVisitor.h>
48 #include <QtCore/QList>
49 #include <QtCore/QtDebug>
51 using namespace CPlusPlus
;
55 typedef QList
< QPair
<Name
*, FullySpecifiedType
> > Substitution
;
57 class Instantiation
: protected TypeVisitor
, protected NameVisitor
60 FullySpecifiedType _type
;
61 const Substitution _substitution
;
64 Instantiation(Control
*control
, const Substitution
&substitution
)
66 _substitution(substitution
)
69 FullySpecifiedType
operator()(const FullySpecifiedType
&ty
)
73 FullySpecifiedType
subst(Name
*name
)
75 for (int i
= 0; i
< _substitution
.size(); ++i
) {
76 const QPair
<Name
*, FullySpecifiedType
> s
= _substitution
.at(i
);
77 if (name
->isEqualTo(s
.first
))
81 return _control
->namedType(name
);
84 FullySpecifiedType
subst(const FullySpecifiedType
&ty
)
86 FullySpecifiedType previousType
= switchType(ty
);
87 TypeVisitor::accept(ty
.type());
88 return switchType(previousType
);
91 FullySpecifiedType
switchType(const FullySpecifiedType
&type
)
93 FullySpecifiedType previousType
= _type
;
99 virtual void visit(PointerToMemberType
* /*ty*/)
104 virtual void visit(PointerType
*ty
)
106 FullySpecifiedType elementType
= subst(ty
->elementType());
107 _type
.setType(_control
->pointerType(elementType
));
110 virtual void visit(ReferenceType
*ty
)
112 FullySpecifiedType elementType
= subst(ty
->elementType());
113 _type
.setType(_control
->referenceType(elementType
));
116 virtual void visit(ArrayType
*ty
)
118 FullySpecifiedType elementType
= subst(ty
->elementType());
119 _type
.setType(_control
->arrayType(elementType
, ty
->size()));
122 virtual void visit(NamedType
*ty
)
123 { _type
.setType(subst(ty
->name()).type()); } // ### merge the specifiers
125 virtual void visit(Function
*ty
)
127 Name
*name
= ty
->name();
128 FullySpecifiedType returnType
= subst(ty
->returnType());
130 Function
*fun
= _control
->newFunction(0, name
);
131 fun
->setScope(ty
->scope());
132 fun
->setReturnType(returnType
);
133 for (unsigned i
= 0; i
< ty
->argumentCount(); ++i
) {
134 Symbol
*arg
= ty
->argumentAt(i
);
135 FullySpecifiedType argTy
= subst(arg
->type());
136 Argument
*newArg
= _control
->newArgument(0, arg
->name());
137 newArg
->setType(argTy
);
138 fun
->arguments()->enterSymbol(newArg
);
143 virtual void visit(VoidType
*)
144 { /* nothing to do*/ }
146 virtual void visit(IntegerType
*)
147 { /* nothing to do*/ }
149 virtual void visit(FloatType
*)
150 { /* nothing to do*/ }
152 virtual void visit(Namespace
*)
155 virtual void visit(Class
*)
158 virtual void visit(Enum
*)
162 virtual void visit(NameId
*)
165 virtual void visit(TemplateNameId
*)
168 virtual void visit(DestructorNameId
*)
171 virtual void visit(OperatorNameId
*)
174 virtual void visit(ConversionNameId
*)
177 virtual void visit(QualifiedNameId
*)
181 } // end of anonymous namespace
183 /////////////////////////////////////////////////////////////////////
185 /////////////////////////////////////////////////////////////////////
186 ResolveExpression::ResolveExpression(const LookupContext
&context
)
187 : ASTVisitor(context
.expressionDocument()->control()),
189 sem(_context
.control())
192 ResolveExpression::~ResolveExpression()
195 QList
<ResolveExpression::Result
> ResolveExpression::operator()(ExpressionAST
*ast
)
197 const QList
<Result
> previousResults
= switchResults(QList
<Result
>());
199 return switchResults(previousResults
);
202 QList
<ResolveExpression::Result
>
203 ResolveExpression::switchResults(const QList
<ResolveExpression::Result
> &results
)
205 const QList
<Result
> previousResults
= _results
;
207 return previousResults
;
210 void ResolveExpression::addResults(const QList
<Result
> &results
)
212 foreach (const Result r
, results
)
216 void ResolveExpression::addResult(const FullySpecifiedType
&ty
, Symbol
*symbol
)
217 { return addResult(Result(ty
, symbol
)); }
219 void ResolveExpression::addResult(const Result
&r
)
223 p
.second
= _context
.symbol();
225 if (! _results
.contains(p
))
229 QList
<Scope
*> ResolveExpression::visibleScopes(const Result
&result
) const
230 { return _context
.visibleScopes(result
); }
232 bool ResolveExpression::visit(ExpressionListAST
*)
238 bool ResolveExpression::visit(BinaryExpressionAST
*ast
)
240 accept(ast
->left_expression
);
244 bool ResolveExpression::visit(CastExpressionAST
*ast
)
247 addResult(sem
.check(ast
->type_id
, &dummy
));
251 bool ResolveExpression::visit(ConditionAST
*)
257 bool ResolveExpression::visit(ConditionalExpressionAST
*)
263 bool ResolveExpression::visit(CppCastExpressionAST
*ast
)
266 addResult(sem
.check(ast
->type_id
, &dummy
));
270 bool ResolveExpression::visit(DeleteExpressionAST
*)
276 bool ResolveExpression::visit(ArrayInitializerAST
*)
282 bool ResolveExpression::visit(NewExpressionAST
*)
288 bool ResolveExpression::visit(TypeidExpressionAST
*)
290 Name
*std_type_info
[2];
291 std_type_info
[0] = control()->nameId(control()->findOrInsertIdentifier("std"));
292 std_type_info
[1] = control()->nameId(control()->findOrInsertIdentifier("type_info"));
294 Name
*q
= control()->qualifiedNameId(std_type_info
, 2, /*global=*/ true);
295 FullySpecifiedType
ty(control()->namedType(q
));
301 bool ResolveExpression::visit(TypenameCallExpressionAST
*)
307 bool ResolveExpression::visit(TypeConstructorCallAST
*)
313 bool ResolveExpression::visit(PostfixExpressionAST
*ast
)
315 accept(ast
->base_expression
);
317 for (PostfixAST
*fx
= ast
->postfix_expressions
; fx
; fx
= fx
->next
) {
324 bool ResolveExpression::visit(SizeofExpressionAST
*)
326 FullySpecifiedType
ty(control()->integerType(IntegerType::Int
));
327 ty
.setUnsigned(true);
332 bool ResolveExpression::visit(NumericLiteralAST
*)
334 FullySpecifiedType
ty(control()->integerType(IntegerType::Int
));
339 bool ResolveExpression::visit(BoolLiteralAST
*)
341 FullySpecifiedType
ty(control()->integerType(IntegerType::Bool
));
346 bool ResolveExpression::visit(ThisExpressionAST
*)
348 if (! _context
.symbol())
351 Scope
*scope
= _context
.symbol()->scope();
352 for (; scope
; scope
= scope
->enclosingScope()) {
353 if (scope
->isFunctionScope()) {
354 Function
*fun
= scope
->owner()->asFunction();
355 if (Scope
*cscope
= scope
->enclosingClassScope()) {
356 Class
*klass
= cscope
->owner()->asClass();
357 FullySpecifiedType
classTy(control()->namedType(klass
->name()));
358 FullySpecifiedType
ptrTy(control()->pointerType(classTy
));
359 addResult(ptrTy
, fun
);
361 } else if (QualifiedNameId
*q
= fun
->name()->asQualifiedNameId()) {
362 Name
*nestedNameSpecifier
= 0;
363 if (q
->nameCount() == 1 && q
->isGlobal())
364 nestedNameSpecifier
= q
->nameAt(0);
366 nestedNameSpecifier
= control()->qualifiedNameId(q
->names(), q
->nameCount() - 1);
367 FullySpecifiedType
classTy(control()->namedType(nestedNameSpecifier
));
368 FullySpecifiedType
ptrTy(control()->pointerType(classTy
));
369 addResult(ptrTy
, fun
);
377 bool ResolveExpression::visit(NestedExpressionAST
*ast
)
379 accept(ast
->expression
);
383 bool ResolveExpression::visit(StringLiteralAST
*)
385 FullySpecifiedType charTy
= control()->integerType(IntegerType::Char
);
386 charTy
.setConst(true);
387 FullySpecifiedType
ty(control()->pointerType(charTy
));
392 bool ResolveExpression::visit(ThrowExpressionAST
*)
397 bool ResolveExpression::visit(TypeIdAST
*)
402 bool ResolveExpression::visit(UnaryExpressionAST
*ast
)
404 accept(ast
->expression
);
405 unsigned unaryOp
= tokenKind(ast
->unary_op_token
);
406 if (unaryOp
== T_AMPER
) {
407 QMutableListIterator
<Result
> it(_results
);
408 while (it
.hasNext()) {
409 Result p
= it
.next();
410 p
.first
.setType(control()->pointerType(p
.first
));
413 } else if (unaryOp
== T_STAR
) {
414 QMutableListIterator
<Result
> it(_results
);
415 while (it
.hasNext()) {
416 Result p
= it
.next();
417 if (PointerType
*ptrTy
= p
.first
->asPointerType()) {
418 p
.first
= ptrTy
->elementType();
428 bool ResolveExpression::visit(CompoundLiteralAST
*ast
)
430 accept(ast
->type_id
);
434 bool ResolveExpression::visit(QualifiedNameAST
*ast
)
436 ResolveClass resolveClass
;
438 Name
*name
= sem
.check(ast
, &dummy
);
440 QList
<Symbol
*> symbols
= _context
.resolve(name
);
441 foreach (Symbol
*symbol
, symbols
) {
442 if (symbol
->isTypedef()) {
443 if (NamedType
*namedTy
= symbol
->type()->asNamedType()) {
444 LookupContext
symbolContext(symbol
, _context
);
445 const Result
r(namedTy
, symbol
);
446 const QList
<Symbol
*> resolvedClasses
=
447 resolveClass(r
, _context
);
448 if (resolvedClasses
.count()) {
449 foreach (Symbol
*s
, resolvedClasses
) {
450 addResult(s
->type(), s
);
456 addResult(symbol
->type(), symbol
);
461 bool ResolveExpression::visit(OperatorFunctionIdAST
*)
466 bool ResolveExpression::visit(ConversionFunctionIdAST
*)
471 bool ResolveExpression::visit(SimpleNameAST
*ast
)
474 Name
*name
= sem
.check(ast
, &dummy
);
476 QList
<Symbol
*> symbols
= _context
.resolve(name
);
477 foreach (Symbol
*symbol
, symbols
)
478 addResult(symbol
->type(), symbol
);
483 bool ResolveExpression::visit(DestructorNameAST
*)
485 FullySpecifiedType
ty(control()->voidType());
490 bool ResolveExpression::visit(TemplateIdAST
*ast
)
493 Name
*name
= sem
.check(ast
, &dummy
);
495 QList
<Symbol
*> symbols
= _context
.resolve(name
);
496 foreach (Symbol
*symbol
, symbols
)
497 addResult(symbol
->type(), symbol
);
502 bool ResolveExpression::visit(CallAST
*ast
)
504 // Compute the types of the actual arguments.
505 QList
< QList
<Result
> > arguments
;
506 for (ExpressionListAST
*exprIt
= ast
->expression_list
; exprIt
;
507 exprIt
= exprIt
->next
) {
508 arguments
.append(operator()(exprIt
->expression
));
511 QList
<Result
> baseResults
= _results
;
514 foreach (Result p
, baseResults
) {
515 if (Function
*funTy
= p
.first
->asFunction()) {
516 unsigned minNumberArguments
= 0;
517 for (; minNumberArguments
< funTy
->argumentCount(); ++minNumberArguments
) {
518 Argument
*arg
= funTy
->argumentAt(minNumberArguments
)->asArgument();
519 if (arg
->hasInitializer())
522 const unsigned actualArgumentCount
= arguments
.count();
523 if (actualArgumentCount
< minNumberArguments
) {
524 // not enough arguments.
525 } else if (! funTy
->isVariadic() && actualArgumentCount
> funTy
->argumentCount()) {
526 // too many arguments.
528 p
.first
= funTy
->returnType();
531 } else if (Class
*classTy
= p
.first
->asClass()) {
533 p
.first
= control()->namedType(classTy
->name());
541 bool ResolveExpression::visit(ArrayAccessAST
*ast
)
543 const QList
<Result
> baseResults
= _results
;
546 const QList
<Result
> indexResults
= operator()(ast
->expression
);
547 ResolveClass symbolsForDotAcccess
;
549 foreach (Result p
, baseResults
) {
550 FullySpecifiedType ty
= p
.first
;
551 Symbol
*contextSymbol
= p
.second
;
553 if (ReferenceType
*refTy
= ty
->asReferenceType())
554 ty
= refTy
->elementType();
556 if (PointerType
*ptrTy
= ty
->asPointerType()) {
557 addResult(ptrTy
->elementType(), contextSymbol
);
558 } else if (ArrayType
*arrTy
= ty
->asArrayType()) {
559 addResult(arrTy
->elementType(), contextSymbol
);
560 } else if (NamedType
*namedTy
= ty
->asNamedType()) {
561 const QList
<Symbol
*> classObjectCandidates
=
562 symbolsForDotAcccess(p
, _context
);
564 foreach (Symbol
*classObject
, classObjectCandidates
) {
565 const QList
<Result
> overloads
=
566 resolveArrayOperator(p
, namedTy
, classObject
->asClass());
567 foreach (Result r
, overloads
) {
568 FullySpecifiedType ty
= r
.first
;
569 Function
*funTy
= ty
->asFunction();
573 ty
= funTy
->returnType();
574 addResult(ty
, funTy
);
582 bool ResolveExpression::visit(MemberAccessAST
*ast
)
584 // The candidate types for the base expression are stored in
586 QList
<Result
> baseResults
= _results
;
588 // Evaluate the expression-id that follows the access operator.
590 Name
*memberName
= sem
.check(ast
->member_name
, &dummy
);
592 // Remember the access operator.
593 const unsigned accessOp
= tokenKind(ast
->access_token
);
595 _results
= resolveMemberExpression(baseResults
, accessOp
, memberName
);
600 QList
<ResolveExpression::Result
>
601 ResolveExpression::resolveMemberExpression(const QList
<Result
> &baseResults
,
603 Name
*memberName
) const
605 ResolveClass resolveClass
;
606 QList
<Result
> results
;
608 if (accessOp
== T_ARROW
) {
609 foreach (Result p
, baseResults
) {
610 FullySpecifiedType ty
= p
.first
;
612 if (ReferenceType
*refTy
= ty
->asReferenceType())
613 ty
= refTy
->elementType();
615 if (NamedType
*namedTy
= ty
->asNamedType()) {
616 const QList
<Symbol
*> classObjectCandidates
=
617 resolveClass(namedTy
, p
, _context
);
619 foreach (Symbol
*classObject
, classObjectCandidates
) {
620 const QList
<Result
> overloads
= resolveArrowOperator(p
, namedTy
,
621 classObject
->asClass());
622 foreach (Result r
, overloads
) {
623 FullySpecifiedType ty
= r
.first
;
624 Function
*funTy
= ty
->asFunction();
628 ty
= funTy
->returnType();
630 if (ReferenceType
*refTy
= ty
->asReferenceType())
631 ty
= refTy
->elementType();
633 if (PointerType
*ptrTy
= ty
->asPointerType()) {
634 if (NamedType
*namedTy
= ptrTy
->elementType()->asNamedType())
635 results
+= resolveMember(r
, memberName
, namedTy
);
639 } else if (PointerType
*ptrTy
= ty
->asPointerType()) {
640 if (NamedType
*namedTy
= ptrTy
->elementType()->asNamedType())
641 results
+= resolveMember(p
, memberName
, namedTy
);
644 } else if (accessOp
== T_DOT
) {
645 // The base expression shall be a "class object" of a complete type.
646 foreach (Result p
, baseResults
) {
647 FullySpecifiedType ty
= p
.first
;
649 if (ReferenceType
*refTy
= ty
->asReferenceType())
650 ty
= refTy
->elementType();
652 if (NamedType
*namedTy
= ty
->asNamedType())
653 results
+= resolveMember(p
, memberName
, namedTy
);
654 else if (Function
*fun
= ty
->asFunction()) {
655 if (fun
->scope()->isBlockScope() || fun
->scope()->isNamespaceScope()) {
656 ty
= fun
->returnType();
658 if (ReferenceType
*refTy
= ty
->asReferenceType())
659 ty
= refTy
->elementType();
661 if (NamedType
*namedTy
= ty
->asNamedType())
662 results
+= resolveMember(p
, memberName
, namedTy
);
672 QList
<ResolveExpression::Result
>
673 ResolveExpression::resolveMember(const Result
&p
,
675 NamedType
*namedTy
) const
677 ResolveClass resolveClass
;
679 const QList
<Symbol
*> classObjectCandidates
=
680 resolveClass(namedTy
, p
, _context
);
682 QList
<Result
> results
;
683 foreach (Symbol
*classObject
, classObjectCandidates
) {
684 results
+= resolveMember(p
, memberName
, namedTy
,
685 classObject
->asClass());
690 QList
<ResolveExpression::Result
>
691 ResolveExpression::resolveMember(const Result
&,
696 QList
<Scope
*> scopes
;
697 _context
.expand(klass
->members(), _context
.visibleScopes(), &scopes
);
698 QList
<Result
> results
;
700 QList
<Symbol
*> candidates
= _context
.resolve(memberName
, scopes
);
701 foreach (Symbol
*candidate
, candidates
) {
702 FullySpecifiedType ty
= candidate
->type();
703 Name
*unqualifiedNameId
= namedTy
->name();
704 if (QualifiedNameId
*q
= namedTy
->name()->asQualifiedNameId())
705 unqualifiedNameId
= q
->unqualifiedNameId();
706 if (TemplateNameId
*templId
= unqualifiedNameId
->asTemplateNameId()) {
708 for (unsigned i
= 0; i
< templId
->templateArgumentCount(); ++i
) {
709 FullySpecifiedType templArgTy
= templId
->templateArgumentAt(i
);
710 if (i
< klass
->templateParameterCount()) {
711 subst
.append(qMakePair(klass
->templateParameterAt(i
)->name(),
715 Instantiation
inst(control(), subst
);
719 const Result
result(ty
, candidate
);
720 if (! results
.contains(result
))
721 results
.append(result
);
727 QList
<ResolveExpression::Result
>
728 ResolveExpression::resolveArrowOperator(const Result
&,
732 QList
<Scope
*> scopes
;
733 _context
.expand(klass
->members(), _context
.visibleScopes(), &scopes
);
734 QList
<Result
> results
;
736 Name
*memberName
= control()->operatorNameId(OperatorNameId::ArrowOp
);
737 QList
<Symbol
*> candidates
= _context
.resolve(memberName
, scopes
);
738 foreach (Symbol
*candidate
, candidates
) {
739 FullySpecifiedType ty
= candidate
->type();
740 Name
*unqualifiedNameId
= namedTy
->name();
741 if (QualifiedNameId
*q
= namedTy
->name()->asQualifiedNameId())
742 unqualifiedNameId
= q
->unqualifiedNameId();
743 if (TemplateNameId
*templId
= unqualifiedNameId
->asTemplateNameId()) {
745 for (unsigned i
= 0; i
< templId
->templateArgumentCount(); ++i
) {
746 FullySpecifiedType templArgTy
= templId
->templateArgumentAt(i
);
747 if (i
< klass
->templateParameterCount()) {
748 subst
.append(qMakePair(klass
->templateParameterAt(i
)->name(),
752 Instantiation
inst(control(), subst
);
756 const Result
result(ty
, candidate
);
757 if (! results
.contains(result
))
758 results
.append(result
);
764 QList
<ResolveExpression::Result
>
765 ResolveExpression::resolveArrayOperator(const Result
&,
769 // ### todo handle index expressions.
771 QList
<Scope
*> scopes
;
772 _context
.expand(klass
->members(), _context
.visibleScopes(), &scopes
);
773 QList
<Result
> results
;
775 Name
*memberName
= control()->operatorNameId(OperatorNameId::ArrayAccessOp
);
776 QList
<Symbol
*> candidates
= _context
.resolve(memberName
, scopes
);
777 foreach (Symbol
*candidate
, candidates
) {
778 FullySpecifiedType ty
= candidate
->type();
779 Name
*unqualifiedNameId
= namedTy
->name();
780 if (QualifiedNameId
*q
= namedTy
->name()->asQualifiedNameId())
781 unqualifiedNameId
= q
->unqualifiedNameId();
782 if (TemplateNameId
*templId
= unqualifiedNameId
->asTemplateNameId()) {
784 for (unsigned i
= 0; i
< templId
->templateArgumentCount(); ++i
) {
785 FullySpecifiedType templArgTy
= templId
->templateArgumentAt(i
);
786 if (i
< klass
->templateParameterCount()) {
787 subst
.append(qMakePair(klass
->templateParameterAt(i
)->name(),
791 Instantiation
inst(control(), subst
);
795 const Result
result(ty
, candidate
);
796 if (! results
.contains(result
))
797 results
.append(result
);
803 bool ResolveExpression::visit(PostIncrDecrAST
*)
808 ////////////////////////////////////////////////////////////////////////////////
809 ResolveClass::ResolveClass()
812 QList
<Symbol
*> ResolveClass::operator()(NamedType
*namedTy
,
813 ResolveExpression::Result p
,
814 const LookupContext
&context
)
816 const QList
<ResolveExpression::Result
> previousBlackList
= _blackList
;
817 const QList
<Symbol
*> symbols
= resolveClass(namedTy
, p
, context
);
818 _blackList
= previousBlackList
;
822 QList
<Symbol
*> ResolveClass::operator()(ResolveExpression::Result p
,
823 const LookupContext
&context
)
825 const QList
<ResolveExpression::Result
> previousBlackList
= _blackList
;
826 const QList
<Symbol
*> symbols
= resolveClass(p
, context
);
827 _blackList
= previousBlackList
;
831 QList
<Symbol
*> ResolveClass::resolveClass(NamedType
*namedTy
,
832 ResolveExpression::Result p
,
833 const LookupContext
&context
)
835 QList
<Symbol
*> resolvedSymbols
;
837 if (_blackList
.contains(p
))
838 return resolvedSymbols
;
840 _blackList
.append(p
);
842 const QList
<Symbol
*> candidates
=
843 context
.resolve(namedTy
->name(), context
.visibleScopes(p
));
845 foreach (Symbol
*candidate
, candidates
) {
846 if (Class
*klass
= candidate
->asClass()) {
847 if (resolvedSymbols
.contains(klass
))
848 continue; // we already know about `klass'
849 resolvedSymbols
.append(klass
);
850 } else if (candidate
->isTypedef()) {
851 if (Declaration
*decl
= candidate
->asDeclaration()) {
852 if (Class
*asClass
= decl
->type()->asClass()) {
853 // typedef struct { } Point;
856 resolvedSymbols
.append(asClass
);
858 // typedef Point Boh;
861 const ResolveExpression::Result
r(decl
->type(), decl
);
862 resolvedSymbols
+= resolveClass(r
, context
);
865 } else if (Declaration
*decl
= candidate
->asDeclaration()) {
866 if (Function
*funTy
= decl
->type()->asFunction()) {
867 // QString foo("ciao");
869 if (funTy
->scope()->isBlockScope() || funTy
->scope()->isNamespaceScope()) {
870 const ResolveExpression::Result
r(funTy
->returnType(), decl
);
871 resolvedSymbols
+= resolveClass(r
, context
);
877 return resolvedSymbols
;
880 QList
<Symbol
*> ResolveClass::resolveClass(ResolveExpression::Result p
,
881 const LookupContext
&context
)
883 FullySpecifiedType ty
= p
.first
;
885 if (NamedType
*namedTy
= ty
->asNamedType()) {
886 return resolveClass(namedTy
, p
, context
);
887 } else if (ReferenceType
*refTy
= ty
->asReferenceType()) {
888 const ResolveExpression::Result
e(refTy
->elementType(), p
.second
);
889 return resolveClass(e
, context
);
892 return QList
<Symbol
*>();