From de68ac54073cc3389abcc4cdaa0131bca7a44874 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 18 May 2015 23:19:32 +0300 Subject: C++: fix code completion for decltyped type example: struct Foo { int bar; }; Foo foo() { return Foo; } typedef decltype(foo()) TypedefedFooWithDecltype; void fun() { decltype(foo()) decltypeFoo; decltypeFoo.;// code completion should work here TypedefedFooWithDecltype typedefedFooWithDecltype; typedefedFooWithDecltype.;// code completion should work here } Started-by: Przemyslaw Gorszkowski Task-number: QTCREATORBUG-14483 Change-Id: I296ceed9d896c68cf0651265afb08a1fc42f9a68 Reviewed-by: Nikolai Kosjar --- src/libs/3rdparty/cplusplus/Bind.cpp | 17 ++++ src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp | 6 ++ src/libs/3rdparty/cplusplus/FullySpecifiedType.h | 4 + src/libs/cplusplus/LookupContext.h | 8 +- src/libs/cplusplus/ResolveExpression.cpp | 77 ++---------------- src/libs/cplusplus/TypeResolver.cpp | 93 +++++++++++++++++++++- src/libs/cplusplus/TypeResolver.h | 4 + 7 files changed, 135 insertions(+), 74 deletions(-) (limited to 'src/libs') diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index a0a0e1a065..e3fd96de98 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -1921,9 +1921,22 @@ bool Bind::visit(SimpleDeclarationAST *ast) methodKey = methodKeyForInvokableToken(tokenKind(ast->qt_invokable_token)); // unsigned qt_invokable_token = ast->qt_invokable_token; + unsigned declTypeStartOfExpression = 0; + unsigned declTypeEndOfExpression = 0; + bool isTypedef = false; FullySpecifiedType type; for (SpecifierListAST *it = ast->decl_specifier_list; it; it = it->next) { type = this->specifier(it->value, type); + if (type.isTypedef()) + isTypedef = true; + + type.setTypedef(isTypedef); + if (type.isDecltype()) { + if (DecltypeSpecifierAST *decltypeSpec = it->value->asDecltypeSpecifier()) { + declTypeStartOfExpression = decltypeSpec->expression->firstToken(); + declTypeEndOfExpression = decltypeSpec->expression->lastToken(); + } + } } List **symbolTail = &ast->symbols; @@ -1982,6 +1995,9 @@ bool Bind::visit(SimpleDeclarationAST *ast) unsigned endOfExpression = initializer->lastToken(); decl->setInitializer(asStringLiteral(startOfExpression, endOfExpression)); } + } else if (declTy.isDecltype()) { + decl->setInitializer(asStringLiteral(declTypeStartOfExpression, + declTypeEndOfExpression)); } if (_scope->isClass()) { @@ -3028,6 +3044,7 @@ bool Bind::visit(TypeofSpecifierAST *ast) bool Bind::visit(DecltypeSpecifierAST *ast) { _type = this->expression(ast->expression); + _type.setDecltype(true); return false; } diff --git a/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp b/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp index f78e4e9338..ea88140314 100644 --- a/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp +++ b/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp @@ -100,6 +100,12 @@ bool FullySpecifiedType::isAuto() const void FullySpecifiedType::setAuto(bool isAuto) { f._isAuto = isAuto; } +bool FullySpecifiedType::isDecltype() const +{ return f._isDecltype; } + +void FullySpecifiedType::setDecltype(bool isDecltype) +{ f._isDecltype = isDecltype; } + bool FullySpecifiedType::isRegister() const { return f._isRegister; } diff --git a/src/libs/3rdparty/cplusplus/FullySpecifiedType.h b/src/libs/3rdparty/cplusplus/FullySpecifiedType.h index 7526a923c9..498e190330 100644 --- a/src/libs/3rdparty/cplusplus/FullySpecifiedType.h +++ b/src/libs/3rdparty/cplusplus/FullySpecifiedType.h @@ -58,6 +58,9 @@ public: bool isAuto() const; void setAuto(bool isAuto); + bool isDecltype() const; + void setDecltype(bool isDecltype); + bool isRegister() const; void setRegister(bool isRegister); @@ -125,6 +128,7 @@ private: // storage class specifiers unsigned _isFriend: 1; unsigned _isAuto: 1; + unsigned _isDecltype: 1; unsigned _isRegister: 1; unsigned _isStatic: 1; unsigned _isExtern: 1; diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index 1eeb2367b6..3e39e31504 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -99,7 +100,9 @@ private: friend class CreateBindings; }; -class CPLUSPLUS_EXPORT CreateBindings: protected SymbolVisitor +class CPLUSPLUS_EXPORT CreateBindings + : protected SymbolVisitor + , public QEnableSharedFromThis { Q_DISABLE_COPY(CreateBindings) @@ -119,6 +122,9 @@ public: QSharedPointer control() const { return _control; } + Snapshot &snapshot() + { return _snapshot; } + /// Adds an expression document in order to keep their symbols and names alive void addExpressionDocument(Document::Ptr document) { _expressionDocuments.append(document); } diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index c32dacbb1c..7612e7f51d 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -526,48 +526,6 @@ 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 candidates = _context.lookup(ast->name, _scope); @@ -581,7 +539,7 @@ bool ResolveExpression::visit(SimpleNameAST *ast) if (item.declaration() == 0) continue; - if (item.type().isAuto()) { + if (item.type().isAuto() || item.type().isDecltype()) { const Declaration *decl = item.declaration()->asDeclaration(); if (!decl) continue; @@ -590,35 +548,10 @@ bool ResolveExpression::visit(SimpleNameAST *ast) if (_autoDeclarationsBeingResolved.contains(decl)) continue; - 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.document(QString::fromLocal8Bit(decl->fileName())); - exprTyper.init(doc, _context.snapshot(), _context.bindings(), - QSet(_autoDeclarationsBeingResolved) << decl); - - Document::Ptr exprDoc = - documentForExpression(exprTyper.preprocessedExpression(initializer)); - exprDoc->check(); - _context.bindings()->addExpressionDocument(exprDoc); - - DeduceAutoCheck deduceAuto(ast->name->identifier(), exprDoc->translationUnit()); - if (deduceAuto._block) - continue; - - newCandidates += exprTyper(extractExpressionAST(exprDoc), exprDoc, - decl->enclosingScope()); + newCandidates += + TypeResolver::resolveDeclInitializer(*_context.bindings(), decl, + _autoDeclarationsBeingResolved << decl, + ast->name->identifier()); } else { item.setType(item.declaration()->type()); item.setScope(item.declaration()->enclosingScope()); diff --git a/src/libs/cplusplus/TypeResolver.cpp b/src/libs/cplusplus/TypeResolver.cpp index fcc21662a4..dab2016b38 100644 --- a/src/libs/cplusplus/TypeResolver.cpp +++ b/src/libs/cplusplus/TypeResolver.cpp @@ -30,6 +30,7 @@ #include "TypeResolver.h" #include "Overview.h" +#include "TypeOfExpression.h" #include @@ -37,6 +38,48 @@ static const bool debug = ! qgetenv("QTC_LOOKUPCONTEXT_DEBUG").isEmpty(); namespace CPlusPlus { +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 + void TypeResolver::resolve(FullySpecifiedType *type, Scope **scope, LookupScope *binding) { QSet visited; @@ -115,6 +158,43 @@ QList TypeResolver::typedefsFromScopeUpToFunctionScope(const Name *n return results; } +// Resolves auto and decltype initializer string +QList TypeResolver::resolveDeclInitializer( + CreateBindings &factory, const Declaration *decl, + const QSet &declarationsBeingResolved, + const Identifier *id) +{ + const StringLiteral *initializationString = decl->getInitializer(); + if (initializationString == 0) + return QList(); + + const QByteArray &initializer = + QByteArray::fromRawData(initializationString->chars(), + initializationString->size()).trimmed(); + + // Skip lambda-function initializers + if (initializer.length() > 0 && initializer[0] == '[') + return QList(); + + TypeOfExpression exprTyper; + exprTyper.setExpandTemplates(true); + Document::Ptr doc = factory.snapshot().document(QString::fromLocal8Bit(decl->fileName())); + exprTyper.init(doc, factory.snapshot(), factory.sharedFromThis(), declarationsBeingResolved); + + Document::Ptr exprDoc = + documentForExpression(exprTyper.preprocessedExpression(initializer)); + factory.addExpressionDocument(exprDoc); + exprDoc->check(); + + if (id) { + DeduceAutoCheck deduceAuto(id, exprDoc->translationUnit()); + if (deduceAuto._block) + return QList(); + } + + return exprTyper(extractExpressionAST(exprDoc), exprDoc, decl->enclosingScope()); +} + bool TypeResolver::isTypedefWithName(const Declaration *declaration, const Name *name) { if (declaration->isTypedef()) { @@ -130,7 +210,7 @@ bool TypeResolver::findTypedef(const QList &namedTypeItems, FullySpe { foreach (const LookupItem &it, namedTypeItems) { Symbol *declaration = it.declaration(); - if (!declaration || !declaration->isTypedef()) + if (!declaration || (!declaration->isTypedef() && !declaration->type().isDecltype())) continue; if (visited.contains(declaration)) break; @@ -145,6 +225,17 @@ bool TypeResolver::findTypedef(const QList &namedTypeItems, FullySpe _factory.control()->referenceType( declaration->type(), declaration->type()->asReferenceType()->isRvalueReference())); + } else if (declaration->type().isDecltype()) { + Declaration *decl = declaration->asDeclaration(); + const QList resolved = + resolveDeclInitializer(_factory, decl, QSet() << decl); + if (!resolved.isEmpty()) { + LookupItem item = resolved.first(); + *type = item.type(); + *scope = item.scope(); + _binding = item.binding(); + return true; + } } else { *type = declaration->type(); } diff --git a/src/libs/cplusplus/TypeResolver.h b/src/libs/cplusplus/TypeResolver.h index 164d7e3ada..bf25e468c6 100644 --- a/src/libs/cplusplus/TypeResolver.h +++ b/src/libs/cplusplus/TypeResolver.h @@ -40,6 +40,10 @@ class TypeResolver public: TypeResolver(CreateBindings &factory) : _factory(factory) {} void resolve(FullySpecifiedType *type, Scope **scope, LookupScope *binding); + static QList resolveDeclInitializer( + CreateBindings &factory, const Declaration *decl, + const QSet &declarationsBeingResolved, + const Identifier *id = 0); private: NamedType *getNamedType(FullySpecifiedType& type) const; -- cgit v1.2.3