diff options
Diffstat (limited to 'src/libs/cplusplus/ResolveExpression.cpp')
-rw-r--r-- | src/libs/cplusplus/ResolveExpression.cpp | 415 |
1 files changed, 347 insertions, 68 deletions
diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 43887b2995..adaac12ab5 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -32,9 +32,9 @@ #include "LookupContext.h" #include "Overview.h" +#include "DeprecatedGenTemplateInstance.h" #include "CppRewriter.h" #include "TypeOfExpression.h" -#include "TypeResolver.h" #include <cplusplus/Control.h> #include <cplusplus/AST.h> @@ -75,6 +75,131 @@ static QList<T> removeDuplicates(const QList<T> &results) return uniqueList; } +class TypedefsResolver +{ +public: + TypedefsResolver(const LookupContext &context) : _context(context) {} + void resolve(FullySpecifiedType *type, Scope **scope, ClassOrNamespace *binding) + { + QSet<Symbol *> visited; + _binding = binding; + // Use a hard limit when trying to resolve typedefs. Typedefs in templates can refer to + // each other, each time enhancing the template argument and thus making it impossible to + // use an "alreadyResolved" container. FIXME: We might overcome this by resolving the + // template parameters. + unsigned maxDepth = 15; + for (NamedType *namedTy = 0; maxDepth && (namedTy = getNamedType(*type)); --maxDepth) { + QList<LookupItem> namedTypeItems = getNamedTypeItems(namedTy->name(), *scope, _binding); + + if (Q_UNLIKELY(debug)) + qDebug() << "-- we have" << namedTypeItems.size() << "candidates"; + + if (!findTypedef(namedTypeItems, type, scope, visited)) + break; + } + } + +private: + NamedType *getNamedType(FullySpecifiedType& type) const + { + NamedType *namedTy = type->asNamedType(); + if (! namedTy) { + if (PointerType *pointerTy = type->asPointerType()) + namedTy = pointerTy->elementType()->asNamedType(); + } + return namedTy; + } + + QList<LookupItem> getNamedTypeItems(const Name *name, Scope *scope, + ClassOrNamespace *binding) const + { + QList<LookupItem> namedTypeItems = typedefsFromScopeUpToFunctionScope(name, scope); + if (namedTypeItems.isEmpty()) { + if (binding) + namedTypeItems = binding->lookup(name); + if (ClassOrNamespace *scopeCon = _context.lookupType(scope)) + namedTypeItems += scopeCon->lookup(name); + } + + return namedTypeItems; + } + + /// Return all typedefs with given name from given scope up to function scope. + static QList<LookupItem> typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope) + { + QList<LookupItem> results; + if (!scope) + return results; + Scope *enclosingBlockScope = 0; + for (Block *block = scope->asBlock(); block; + block = enclosingBlockScope ? enclosingBlockScope->asBlock() : 0) { + const unsigned memberCount = block->memberCount(); + for (unsigned i = 0; i < memberCount; ++i) { + Symbol *symbol = block->memberAt(i); + if (Declaration *declaration = symbol->asDeclaration()) { + if (isTypedefWithName(declaration, name)) { + LookupItem item; + item.setDeclaration(declaration); + item.setScope(block); + item.setType(declaration->type()); + results.append(item); + } + } + } + enclosingBlockScope = block->enclosingScope(); + } + return results; + } + + static bool isTypedefWithName(const Declaration *declaration, const Name *name) + { + if (declaration->isTypedef()) { + const Identifier *identifier = declaration->name()->identifier(); + if (name->identifier()->match(identifier)) + return true; + } + return false; + } + + bool findTypedef(const QList<LookupItem>& namedTypeItems, FullySpecifiedType *type, + Scope **scope, QSet<Symbol *>& visited) + { + bool foundTypedef = false; + foreach (const LookupItem &it, namedTypeItems) { + Symbol *declaration = it.declaration(); + if (declaration && declaration->isTypedef()) { + if (visited.contains(declaration)) + break; + visited.insert(declaration); + + // continue working with the typedefed type and scope + if (type->type()->isPointerType()) { + *type = FullySpecifiedType( + _context.bindings()->control()->pointerType(declaration->type())); + } else if (type->type()->isReferenceType()) { + *type = FullySpecifiedType( + _context.bindings()->control()->referenceType( + declaration->type(), + declaration->type()->asReferenceType()->isRvalueReference())); + } else { + *type = declaration->type(); + } + + *scope = it.scope(); + _binding = it.binding(); + foundTypedef = true; + break; + } + } + + return foundTypedef; + } + + const LookupContext &_context; + // binding has to be remembered in case of resolving typedefs for templates + ClassOrNamespace *_binding; +}; + static int evaluateFunctionArgument(const FullySpecifiedType &actualTy, const FullySpecifiedType &formalTy) { @@ -176,7 +301,7 @@ void ResolveExpression::addResults(const QList<LookupItem> &items) } void ResolveExpression::addResult(const FullySpecifiedType &ty, Scope *scope, - LookupScope *binding) + ClassOrNamespace *binding) { LookupItem item; item.setType(ty); @@ -206,7 +331,7 @@ bool ResolveExpression::visit(BinaryExpressionAST *ast) if (d->core_declarator) { if (DeclaratorIdAST *declaratorId = d->core_declarator->asDeclaratorId()) { if (NameAST *nameAST = declaratorId->name) { - if (LookupScope *binding = baseExpression(_results, T_ARROW)) { + if (ClassOrNamespace *binding = baseExpression(_results, T_ARROW)) { _results.clear(); addResults(binding->lookup(nameAST->name)); } @@ -487,17 +612,19 @@ bool ResolveExpression::visit(UnaryExpressionAST *ast) added = true; } else if (namedTy != 0) { const Name *starOp = control()->operatorNameId(OperatorNameId::StarOp); - if (LookupScope *b = _context.lookupType(namedTy->name(), p.scope(), p.binding())) { + if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), p.scope(), p.binding())) { foreach (const LookupItem &r, b->find(starOp)) { Symbol *overload = r.declaration(); if (Function *funTy = overload->type()->asFunctionType()) { if (maybeValidPrototype(funTy, 0)) { - FullySpecifiedType retTy = funTy->returnType().simplified(); - p.setType(retTy); - p.setScope(funTy->enclosingScope()); - it.setValue(p); - added = true; - break; + if (Function *proto = instantiate(b->templateId(), funTy)->asFunctionType()) { + FullySpecifiedType retTy = proto->returnType().simplified(); + p.setType(retTy); + p.setScope(proto->enclosingScope()); + it.setValue(p); + added = true; + break; + } } } } @@ -526,6 +653,48 @@ bool ResolveExpression::visit(QualifiedNameAST *ast) return false; } +namespace { + +class DeduceAutoCheck : public ASTVisitor +{ +public: + DeduceAutoCheck(const Identifier *id, TranslationUnit *tu) + : ASTVisitor(tu), _id(id), _block(false) + { + accept(tu->ast()); + } + + virtual bool preVisit(AST *) + { + if (_block) + return false; + + return true; + } + + virtual bool visit(SimpleNameAST *ast) + { + if (ast->name + && ast->name->identifier() + && strcmp(ast->name->identifier()->chars(), _id->chars()) == 0) { + _block = true; + } + + return false; + } + + virtual bool visit(MemberAccessAST *ast) + { + accept(ast->base_expression); + return false; + } + + const Identifier *_id; + bool _block; +}; + +} // namespace anonymous + bool ResolveExpression::visit(SimpleNameAST *ast) { QList<LookupItem> candidates = _context.lookup(ast->name, _scope); @@ -539,7 +708,7 @@ bool ResolveExpression::visit(SimpleNameAST *ast) if (item.declaration() == 0) continue; - if (item.type().isAuto() || item.type().isDecltype()) { + if (item.type().isAuto()) { const Declaration *decl = item.declaration()->asDeclaration(); if (!decl) continue; @@ -548,10 +717,53 @@ bool ResolveExpression::visit(SimpleNameAST *ast) if (_autoDeclarationsBeingResolved.contains(decl)) continue; - newCandidates += - TypeResolver::resolveDeclInitializer(*_context.bindings(), decl, - _autoDeclarationsBeingResolved << decl, - ast->name->identifier()); + const StringLiteral *initializationString = decl->getInitializer(); + if (initializationString == 0) + continue; + + const QByteArray &initializer = + QByteArray::fromRawData(initializationString->chars(), + initializationString->size()).trimmed(); + + // Skip lambda-function initializers + if (initializer.length() > 0 && initializer[0] == '[') + continue; + + TypeOfExpression exprTyper; + exprTyper.setExpandTemplates(true); + Document::Ptr doc = _context.snapshot().document(QString::fromLocal8Bit(decl->fileName())); + exprTyper.init(doc, _context.snapshot(), _context.bindings(), + QSet<const Declaration* >(_autoDeclarationsBeingResolved) << decl); + + Document::Ptr exprDoc = + documentForExpression(exprTyper.preprocessedExpression(initializer)); + exprDoc->check(); + + DeduceAutoCheck deduceAuto(ast->name->identifier(), exprDoc->translationUnit()); + if (deduceAuto._block) + continue; + + const QList<LookupItem> &typeItems = exprTyper(extractExpressionAST(exprDoc), exprDoc, + decl->enclosingScope()); + if (typeItems.empty()) + continue; + + Clone cloner(_context.bindings()->control().data()); + + for (int n = 0; n < typeItems.size(); ++ n) { + FullySpecifiedType newType = cloner.type(typeItems[n].type(), 0); + if (n == 0) { + item.setType(newType); + item.setScope(typeItems[n].scope()); + item.setBinding(typeItems[n].binding()); + } else { + LookupItem newItem(item); + newItem.setType(newType); + newItem.setScope(typeItems[n].scope()); + newItem.setBinding(typeItems[n].binding()); + newCandidates.push_back(newItem); + } + } } else { item.setType(item.declaration()->type()); item.setScope(item.declaration()->enclosingScope()); @@ -661,12 +873,14 @@ bool ResolveExpression::visit(CallAST *ast) Scope *scope = result.scope(); if (NamedType *namedTy = ty->asNamedType()) { - if (LookupScope *b = _context.lookupType(namedTy->name(), scope)) { + if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) { foreach (const LookupItem &r, b->find(functionCallOp)) { Symbol *overload = r.declaration(); if (Function *funTy = overload->type()->asFunctionType()) { - if (maybeValidPrototype(funTy, actualArgumentCount)) - addResult(funTy->returnType().simplified(), scope); + if (maybeValidPrototype(funTy, actualArgumentCount)) { + if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType()) + addResult(proto->returnType().simplified(), scope); + } } } } @@ -679,6 +893,14 @@ bool ResolveExpression::visit(CallAST *ast) // Constructor call FullySpecifiedType ctorTy = control()->namedType(classTy->name()); addResult(ctorTy, scope); + } else if (Template *templateTy = ty->asTemplateType()) { + // template function + if (Symbol *declaration = templateTy->declaration()) { + if (Function *funTy = declaration->asFunction()) { + if (maybeValidPrototype(funTy, actualArgumentCount)) + addResult(funTy->returnType().simplified(), scope); + } + } } } @@ -694,8 +916,8 @@ bool ResolveExpression::visit(ArrayAccessAST *ast) FullySpecifiedType ty = result.type().simplified(); Scope *scope = result.scope(); - TypeResolver typeResolver(*_context.bindings()); - typeResolver.resolve(&ty, &scope, result.binding()); + TypedefsResolver typedefsResolver(_context); + typedefsResolver.resolve(&ty, &scope, result.binding()); if (PointerType *ptrTy = ty->asPointerType()) { addResult(ptrTy->elementType().simplified(), scope); @@ -704,12 +926,13 @@ bool ResolveExpression::visit(ArrayAccessAST *ast) addResult(arrTy->elementType().simplified(), scope); } else if (NamedType *namedTy = ty->asNamedType()) { - if (LookupScope *b = _context.lookupType(namedTy->name(), scope)) { + if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) { foreach (const LookupItem &r, b->find(arrayAccessOp)) { Symbol *overload = r.declaration(); if (Function *funTy = overload->type()->asFunctionType()) { - // ### TODO: check the actual arguments - addResult(funTy->returnType().simplified(), scope); + if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType()) + // ### TODO: check the actual arguments + addResult(proto->returnType().simplified(), scope); } } @@ -719,7 +942,7 @@ bool ResolveExpression::visit(ArrayAccessAST *ast) return false; } -QList<LookupItem> ResolveExpression::getMembers(LookupScope *binding, const Name *memberName) const +QList<LookupItem> ResolveExpression::getMembers(ClassOrNamespace *binding, const Name *memberName) const { Q_UNUSED(binding); Q_UNUSED(memberName); @@ -788,17 +1011,17 @@ bool ResolveExpression::visit(MemberAccessAST *ast) // Remember the access operator. const int accessOp = tokenKind(ast->access_token); - if (LookupScope *binding = baseExpression(baseResults, accessOp)) + if (ClassOrNamespace *binding = baseExpression(baseResults, accessOp)) addResults(binding->find(memberName)); return false; } -LookupScope *ResolveExpression::findClass(const FullySpecifiedType &originalTy, Scope *scope, - LookupScope *enclosingBinding) const +ClassOrNamespace *ResolveExpression::findClass(const FullySpecifiedType &originalTy, Scope *scope, + ClassOrNamespace *enclosingBinding) const { FullySpecifiedType ty = originalTy.simplified(); - LookupScope *binding = 0; + ClassOrNamespace *binding = 0; if (Class *klass = ty->asClassType()) { if (scope->isBlock()) @@ -816,14 +1039,15 @@ LookupScope *ResolveExpression::findClass(const FullySpecifiedType &originalTy, return binding; } -LookupScope *ResolveExpression::baseExpression(const QList<LookupItem> &baseResults, - int accessOp, - bool *replacedDotOperator) const +ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &baseResults, + int accessOp, + bool *replacedDotOperator) const { if (Q_UNLIKELY(debug)) qDebug() << "In ResolveExpression::baseExpression with" << baseResults.size() << "results..."; int i = 0; - TypeResolver typeResolver(*_context.bindings()); + Overview oo; + TypedefsResolver typedefsResolver(_context); foreach (const LookupItem &r, baseResults) { if (!r.type().type() || !r.scope()) @@ -832,55 +1056,80 @@ LookupScope *ResolveExpression::baseExpression(const QList<LookupItem> &baseResu FullySpecifiedType originalType = ty; Scope *scope = r.scope(); - if (Q_UNLIKELY(debug)) + if (Q_UNLIKELY(debug)) { qDebug("trying result #%d", ++i); + qDebug() << "- before typedef resolving we have:" << oo(ty); + } + + typedefsResolver.resolve(&ty, &scope, r.binding()); - typeResolver.resolve(&ty, &scope, r.binding()); + if (Q_UNLIKELY(debug)) + qDebug() << "- after typedef resolving:" << oo(ty); if (accessOp == T_ARROW) { if (PointerType *ptrTy = ty->asPointerType()) { FullySpecifiedType type = ptrTy->elementType(); - if (LookupScope *binding = findClass(type, scope)) + if (ClassOrNamespace *binding + = findClassForTemplateParameterInExpressionScope(r.binding(), + type)) { + return binding; + } + if (ClassOrNamespace *binding = findClass(type, scope)) return binding; - } else if (LookupScope *binding = findClass(ty, scope, r.binding())) { - // lookup for overloads of operator-> - - const OperatorNameId *arrowOp - = control()->operatorNameId(OperatorNameId::ArrowOp); - foreach (const LookupItem &r, binding->find(arrowOp)) { - Symbol *overload = r.declaration(); - if (! overload) - continue; - Scope *functionScope = overload->enclosingScope(); + } else { + ClassOrNamespace *binding + = findClassForTemplateParameterInExpressionScope(r.binding(), + ty); - if (Function *funTy = overload->type()->asFunctionType()) { - FullySpecifiedType retTy = funTy->returnType().simplified(); + if (! binding) + binding = findClass(ty, scope, r.binding()); - typeResolver.resolve(&retTy, &functionScope, r.binding()); + if (binding){ + // lookup for overloads of operator-> - if (! retTy->isPointerType() && ! retTy->isNamedType()) + const OperatorNameId *arrowOp + = control()->operatorNameId(OperatorNameId::ArrowOp); + foreach (const LookupItem &r, binding->find(arrowOp)) { + Symbol *overload = r.declaration(); + if (! overload) continue; + Scope *functionScope = overload->enclosingScope(); + + if (overload->type()->isFunctionType()) { + FullySpecifiedType overloadTy + = instantiate(binding->templateId(), overload); + Function *instantiatedFunction = overloadTy->asFunctionType(); + Q_ASSERT(instantiatedFunction != 0); + + FullySpecifiedType retTy + = instantiatedFunction->returnType().simplified(); + + typedefsResolver.resolve(&retTy, &functionScope, r.binding()); - if (PointerType *ptrTy = retTy->asPointerType()) - retTy = ptrTy->elementType(); + if (! retTy->isPointerType() && ! retTy->isNamedType()) + continue; - if (LookupScope *retBinding = findClass(retTy, functionScope)) - return retBinding; + if (PointerType *ptrTy = retTy->asPointerType()) + retTy = ptrTy->elementType(); - if (scope != functionScope) { - if (LookupScope *retBinding = findClass(retTy, scope)) + if (ClassOrNamespace *retBinding = findClass(retTy, functionScope)) return retBinding; - } - if (LookupScope *origin = binding->instantiationOrigin()) { - foreach (Symbol *originSymbol, origin->symbols()) { - Scope *originScope = originSymbol->asScope(); - if (originScope && originScope != scope - && originScope != functionScope) { - if (LookupScope *retBinding - = findClass(retTy, originScope)) - return retBinding; + if (scope != functionScope) { + if (ClassOrNamespace *retBinding = findClass(retTy, scope)) + return retBinding; + } + + if (ClassOrNamespace *origin = binding->instantiationOrigin()) { + foreach (Symbol *originSymbol, origin->symbols()) { + Scope *originScope = originSymbol->asScope(); + if (originScope && originScope != scope + && originScope != functionScope) { + if (ClassOrNamespace *retBinding + = findClass(retTy, originScope)) + return retBinding; + } } } } @@ -894,13 +1143,19 @@ LookupScope *ResolveExpression::baseExpression(const QList<LookupItem> &baseResu ty = ptrTy->elementType(); } - LookupScope *enclosingBinding = 0; - if (LookupScope *binding = r.binding()) { + if (ClassOrNamespace *binding + = findClassForTemplateParameterInExpressionScope(r.binding(), + ty)) { + return binding; + } + + ClassOrNamespace *enclosingBinding = 0; + if (ClassOrNamespace *binding = r.binding()) { if (binding->instantiationOrigin()) enclosingBinding = binding; } - if (LookupScope *binding = findClass(ty, scope, enclosingBinding)) + if (ClassOrNamespace *binding = findClass(ty, scope, enclosingBinding)) return binding; } } @@ -908,6 +1163,30 @@ LookupScope *ResolveExpression::baseExpression(const QList<LookupItem> &baseResu return 0; } +ClassOrNamespace *ResolveExpression::findClassForTemplateParameterInExpressionScope( + ClassOrNamespace *resultBinding, + const FullySpecifiedType &ty) const +{ + if (resultBinding) { + if (ClassOrNamespace *origin = resultBinding->instantiationOrigin()) { + foreach (Symbol *originSymbol, origin->symbols()) { + if (Scope *originScope = originSymbol->asScope()) { + if (ClassOrNamespace *retBinding = findClass(ty, originScope)) + return retBinding; + } + } + } + } + + return 0; +} + +FullySpecifiedType ResolveExpression::instantiate(const Name *className, Symbol *candidate) const +{ + return DeprecatedGenTemplateInstance::instantiate(className, candidate, + _context.bindings()->control()); +} + bool ResolveExpression::visit(PostIncrDecrAST *ast) { const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope); @@ -921,7 +1200,7 @@ bool ResolveExpression::visit(ObjCMessageExpressionAST *ast) foreach (const LookupItem &result, receiverResults) { FullySpecifiedType ty = result.type().simplified(); - LookupScope *binding = 0; + ClassOrNamespace *binding = 0; if (ObjCClass *clazz = ty->asObjCClassType()) { // static access, e.g.: |