diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index adaac12ab5f..e38d634b8cd 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -35,6 +35,7 @@ #include "DeprecatedGenTemplateInstance.h" #include "CppRewriter.h" #include "TypeOfExpression.h" +#include "TypeResolver.h" #include #include @@ -75,131 +76,6 @@ static QList removeDuplicates(const QList &results) return uniqueList; } -class TypedefsResolver -{ -public: - TypedefsResolver(const LookupContext &context) : _context(context) {} - void resolve(FullySpecifiedType *type, Scope **scope, ClassOrNamespace *binding) - { - QSet 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 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 getNamedTypeItems(const Name *name, Scope *scope, - ClassOrNamespace *binding) const - { - QList 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 typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope) - { - QList 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& namedTypeItems, FullySpecifiedType *type, - Scope **scope, QSet& 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) { @@ -916,8 +792,8 @@ bool ResolveExpression::visit(ArrayAccessAST *ast) FullySpecifiedType ty = result.type().simplified(); Scope *scope = result.scope(); - TypedefsResolver typedefsResolver(_context); - typedefsResolver.resolve(&ty, &scope, result.binding()); + TypeResolver typeResolver(_context); + typeResolver.resolve(&ty, &scope, result.binding()); if (PointerType *ptrTy = ty->asPointerType()) { addResult(ptrTy->elementType().simplified(), scope); @@ -1047,7 +923,7 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList &bas qDebug() << "In ResolveExpression::baseExpression with" << baseResults.size() << "results..."; int i = 0; Overview oo; - TypedefsResolver typedefsResolver(_context); + TypeResolver typeResolver(_context); foreach (const LookupItem &r, baseResults) { if (!r.type().type() || !r.scope()) @@ -1056,15 +932,10 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList &bas FullySpecifiedType originalType = ty; Scope *scope = r.scope(); - if (Q_UNLIKELY(debug)) { - qDebug("trying result #%d", ++i); - qDebug() << "- before typedef resolving we have:" << oo(ty); - } - - typedefsResolver.resolve(&ty, &scope, r.binding()); - if (Q_UNLIKELY(debug)) - qDebug() << "- after typedef resolving:" << oo(ty); + qDebug("trying result #%d", ++i); + + typeResolver.resolve(&ty, &scope, r.binding()); if (accessOp == T_ARROW) { if (PointerType *ptrTy = ty->asPointerType()) { @@ -1105,7 +976,7 @@ ClassOrNamespace *ResolveExpression::baseExpression(const QList &bas FullySpecifiedType retTy = instantiatedFunction->returnType().simplified(); - typedefsResolver.resolve(&retTy, &functionScope, r.binding()); + typeResolver.resolve(&retTy, &functionScope, r.binding()); if (! retTy->isPointerType() && ! retTy->isNamedType()) continue; diff --git a/src/libs/cplusplus/TypeResolver.cpp b/src/libs/cplusplus/TypeResolver.cpp new file mode 100644 index 00000000000..80ae16f2efd --- /dev/null +++ b/src/libs/cplusplus/TypeResolver.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "TypeResolver.h" +#include "Overview.h" + +#include + +static const bool debug = ! qgetenv("QTC_LOOKUPCONTEXT_DEBUG").isEmpty(); + +namespace CPlusPlus { + +void TypeResolver::resolve(FullySpecifiedType *type, Scope **scope, ClassOrNamespace *binding) +{ + QSet 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; + Overview oo; + if (Q_UNLIKELY(debug)) + qDebug() << "- before typedef resolving we have:" << oo(*type); + for (NamedType *namedTy = 0; maxDepth && (namedTy = getNamedType(*type)); --maxDepth) { + QList namedTypeItems = getNamedTypeItems(namedTy->name(), *scope, _binding); + + if (Q_UNLIKELY(debug)) + qDebug() << "-- we have" << namedTypeItems.size() << "candidates"; + + if (!findTypedef(namedTypeItems, type, scope, visited)) + break; + } + if (Q_UNLIKELY(debug)) + qDebug() << "- after typedef resolving:" << oo(*type); +} + +NamedType *TypeResolver::getNamedType(FullySpecifiedType &type) const +{ + NamedType *namedTy = type->asNamedType(); + if (! namedTy) { + if (PointerType *pointerTy = type->asPointerType()) + namedTy = pointerTy->elementType()->asNamedType(); + } + return namedTy; +} + +QList TypeResolver::getNamedTypeItems(const Name *name, Scope *scope, + ClassOrNamespace *binding) const +{ + QList 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. +QList TypeResolver::typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope) +{ + QList 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; +} + +bool TypeResolver::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 TypeResolver::findTypedef(const QList &namedTypeItems, FullySpecifiedType *type, + Scope **scope, QSet &visited) +{ + bool foundTypedef = false; + foreach (const LookupItem &it, namedTypeItems) { + Symbol *declaration = it.declaration(); + if (!declaration || !declaration->isTypedef()) + continue; + 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; +} + +} // namespace CPlusPlus diff --git a/src/libs/cplusplus/TypeResolver.h b/src/libs/cplusplus/TypeResolver.h new file mode 100644 index 00000000000..85f54ab54af --- /dev/null +++ b/src/libs/cplusplus/TypeResolver.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef TYPERESOLVER_H +#define TYPERESOLVER_H + +#include "LookupContext.h" + +namespace CPlusPlus { + +class TypeResolver +{ +public: + TypeResolver(const LookupContext &context) : _context(context) {} + void resolve(FullySpecifiedType *type, Scope **scope, ClassOrNamespace *binding); + +private: + NamedType *getNamedType(FullySpecifiedType& type) const; + + QList getNamedTypeItems(const Name *name, Scope *scope, + ClassOrNamespace *binding) const; + + static QList typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope); + + static bool isTypedefWithName(const Declaration *declaration, const Name *name); + + bool findTypedef(const QList& namedTypeItems, FullySpecifiedType *type, + Scope **scope, QSet& visited); + + const LookupContext &_context; + // binding has to be remembered in case of resolving typedefs for templates + ClassOrNamespace *_binding; +}; + +} // namespace CPlusPlus + +#endif // TYPERESOLVER_H diff --git a/src/libs/cplusplus/cplusplus-lib.pri b/src/libs/cplusplus/cplusplus-lib.pri index 826d9dfa10c..f58256e4d68 100644 --- a/src/libs/cplusplus/cplusplus-lib.pri +++ b/src/libs/cplusplus/cplusplus-lib.pri @@ -36,6 +36,7 @@ HEADERS += \ $$PWD/NamePrettyPrinter.h \ $$PWD/TypeOfExpression.h \ $$PWD/TypePrettyPrinter.h \ + $$PWD/TypeResolver.h \ $$PWD/ResolveExpression.h \ $$PWD/LookupItem.h \ $$PWD/AlreadyConsideredClassContainer.h \ @@ -68,6 +69,7 @@ SOURCES += \ $$PWD/NamePrettyPrinter.cpp \ $$PWD/TypeOfExpression.cpp \ $$PWD/TypePrettyPrinter.cpp \ + $$PWD/TypeResolver.cpp \ $$PWD/ResolveExpression.cpp \ $$PWD/LookupItem.cpp \ $$PWD/LookupContext.cpp \ diff --git a/src/libs/cplusplus/cplusplus.qbs b/src/libs/cplusplus/cplusplus.qbs index de6f93eb5dc..9891aeb4aba 100644 --- a/src/libs/cplusplus/cplusplus.qbs +++ b/src/libs/cplusplus/cplusplus.qbs @@ -118,6 +118,7 @@ QtcLibrary { "SymbolNameVisitor.cpp", "SymbolNameVisitor.h", "TypeOfExpression.cpp", "TypeOfExpression.h", "TypePrettyPrinter.cpp", "TypePrettyPrinter.h", + "TypeResolver.cpp", "TypeResolver.h", "cplusplus.qrc", "findcdbbreakpoint.cpp", "findcdbbreakpoint.h", "pp-cctype.h",