From ad4cb444fbfd1f3f4747a0988a196120d3a0c208 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 30 Mar 2015 22:13:44 +0300 Subject: [PATCH] C++: Fix specialization resolution for nested types Use-cases: template struct Traits { typedef typename T::pointer pointer; }; template struct Traits<_Tp*> { typedef _Tp *pointer; }; struct Foo { int bar; }; // 1 template class Temp { protected: typedef Traits TraitsT; public: typedef typename TraitsT::pointer pointer; pointer p; }; void func() { Temp t; t.p-> // complete } // 2 class Temp2 { protected: typedef Foo *FooPtr; typedef Traits TraitsT; public: typedef typename TraitsT::pointer pointer; pointer p; }; void func2() { Temp2 t; t.p-> // complete } Task-number: QTCREATORBUG-14141 Change-Id: Id3459671117c0c81bcde7c9714b42750634c0225 Reviewed-by: Nikolai Kosjar --- src/libs/cplusplus/LookupContext.cpp | 89 +++++++++++++++---- src/libs/cplusplus/ResolveExpression.cpp | 4 +- src/libs/cplusplus/TypeResolver.cpp | 6 +- src/libs/cplusplus/TypeResolver.h | 4 +- src/plugins/cpptools/cppcompletion_test.cpp | 3 - .../checksymbols/tst_checksymbols.cpp | 2 - 6 files changed, 77 insertions(+), 31 deletions(-) diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index ced7dc5e646..93b576ffc7d 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -33,6 +33,7 @@ #include "ResolveExpression.h" #include "Overview.h" #include "CppRewriter.h" +#include "TypeResolver.h" #include #include @@ -525,6 +526,7 @@ public: ~LookupScopePrivate(); typedef std::map Table; + typedef std::map TypedefTable; typedef std::map TemplateNameIdTable; @@ -546,6 +548,7 @@ public: void addTodo(Symbol *symbol); void addSymbol(Symbol *symbol); void addUnscopedEnum(Enum *e); + void addTypedef(const Name *identifier, Declaration *d); void addUsing(LookupScope *u); void addNestedType(const Name *alias, LookupScope *e); @@ -561,11 +564,16 @@ public: LookupScope *findBlock_helper(Block *block, ProcessedSet *processed, bool searchInEnclosingScope); +private: + LookupScopePrivate *findNestedType(const Name *name, LookupScopePrivate *origin); + LookupScopePrivate *nestedType(const Name *name, LookupScopePrivate *origin); LookupScopePrivate *findSpecialization(const TemplateNameId *templId, - const TemplateNameIdTable &specializations); + const TemplateNameIdTable &specializations, + LookupScopePrivate *origin); +public: LookupScope *q; CreateBindings *_factory; @@ -573,6 +581,7 @@ public: QList _symbols; QList _usings; Table _nestedScopes; + TypedefTable _typedefs; QHash _blocks; QList _enums; QList _todo; @@ -589,9 +598,11 @@ public: AlreadyConsideredClassContainer _alreadyConsideredClasses; AlreadyConsideredClassContainer _alreadyConsideredTemplates; + QSet _alreadyConsideredTypedefs; Class *_rootClass; const Name *_name; // For debug + bool _hasTypedefs; }; class Instantiator @@ -702,6 +713,7 @@ LookupScopePrivate::LookupScopePrivate(LookupScope *q, CreateBindings *factory, , _instantiationOrigin(0) , _rootClass(0) , _name(0) + , _hasTypedefs(false) { Q_ASSERT(factory); } @@ -1136,7 +1148,7 @@ static LookupScopePrivate *findSpecializationWithMatchingTemplateArgument( } LookupScopePrivate *LookupScopePrivate::findSpecialization( - const TemplateNameId *templId, const TemplateNameIdTable &specializations) + const TemplateNameId *templId, const TemplateNameIdTable &specializations, LookupScopePrivate *origin) { // we go through all specialization and try to find that one with template argument as pointer for (TemplateNameIdTable::const_iterator cit = specializations.begin(); @@ -1152,8 +1164,11 @@ LookupScopePrivate *LookupScopePrivate::findSpecialization( for (unsigned i = 0; i < initializationTemplateArgumentCount; ++i) { const FullySpecifiedType &specializationTemplateArgument = specializationNameId->templateArgumentAt(i); - const FullySpecifiedType &initializationTemplateArgument + FullySpecifiedType initializationTemplateArgument = templId->templateArgumentAt(i); + TypeResolver typeResolver(*_factory); + Scope *scope = 0; + typeResolver.resolve(&initializationTemplateArgument, &scope, origin ? origin->q : 0); PointerType *specPointer = specializationTemplateArgument.type()->asPointerType(); // specialization and initialization argument have to be a pointer @@ -1197,8 +1212,33 @@ LookupScopePrivate *LookupScopePrivate::findOrCreateNestedAnonymousType( } } -LookupScopePrivate *LookupScopePrivate::nestedType( - const Name *name, LookupScopePrivate *origin) +LookupScopePrivate *LookupScopePrivate::findNestedType(const Name *name, LookupScopePrivate *origin) +{ + TypedefTable::const_iterator typedefit = _typedefs.find(name); + if (typedefit != _typedefs.end()) { + Declaration *decl = typedefit->second; + if (_alreadyConsideredTypedefs.contains(decl)) + return 0; + _alreadyConsideredTypedefs.insert(decl); + if (const NamedType *namedTy = decl->type()->asNamedType()) { + if (LookupScope *e = q->lookupType(namedTy->name())) + return e->d; + if (origin) { + if (LookupScope *e = origin->q->lookupType(namedTy->name())) + return e->d; + } + } + _alreadyConsideredTypedefs.remove(decl); + } + + auto it = _nestedScopes.find(name); + if (it != _nestedScopes.end()) + return it->second; + + return 0; +} + +LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScopePrivate *origin) { Q_ASSERT(name != 0); Q_ASSERT(name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()); @@ -1208,13 +1248,11 @@ LookupScopePrivate *LookupScopePrivate::nestedType( if (const AnonymousNameId *anonymousNameId = name->asAnonymousNameId()) return findOrCreateNestedAnonymousType(anonymousNameId); - Table::const_iterator it = _nestedScopes.find(name); - if (it == _nestedScopes.end()) + LookupScopePrivate *reference = findNestedType(name, origin); + if (!reference) return 0; - - LookupScopePrivate *reference = it->second; - LookupScopePrivate *baseTemplateClassReference = reference; reference->flush(); + LookupScopePrivate *baseTemplateClassReference = reference; const TemplateNameId *templId = name->asTemplateNameId(); if (templId) { @@ -1254,10 +1292,9 @@ LookupScopePrivate *LookupScopePrivate::nestedType( reference = cit->second; } else { LookupScopePrivate *specializationWithPointer - = findSpecialization(templId, specializations); + = findSpecialization(templId, specializations, origin); if (specializationWithPointer) reference = specializationWithPointer; - // TODO: find the best specialization(probably partial) for this instantiation } // let's instantiation be instantiation nonConstTemplId->setIsSpecialization(false); @@ -1340,6 +1377,9 @@ LookupScopePrivate *LookupScopePrivate::nestedType( templId->templateArgumentAt(i): cloner.type(tParam->type(), &subst); + TypeResolver typeResolver(*_factory); + Scope *scope = 0; + typeResolver.resolve(&ty, &scope, origin ? origin->q : 0); if (i < templSpecArgumentCount && templSpecId->templateArgumentAt(i)->isPointerType()) { if (PointerType *pointerType = ty->asPointerType()) @@ -1353,6 +1393,7 @@ LookupScopePrivate *LookupScopePrivate::nestedType( instantiator.instantiate(reference, instantiation); } else { instantiation->_symbols.append(reference->_symbols); + instantiation->_typedefs = reference->_typedefs; } QHash templParams; @@ -1427,6 +1468,7 @@ LookupScopePrivate *LookupScopePrivate::nestedType( } else { instantiation->_nestedScopes = reference->_nestedScopes; instantiation->_symbols.append(reference->_symbols); + instantiation->_typedefs = reference->_typedefs; } _alreadyConsideredTemplates.clear(templId); @@ -1472,6 +1514,13 @@ void Instantiator::instantiate(LookupScopePrivate *lookupScope, return; _alreadyConsideredInstantiations.insert(lookupScope); if (instantiation != lookupScope) { + auto typedefend = lookupScope->_typedefs.end(); + for (auto typedefit = lookupScope->_typedefs.begin(); + typedefit != typedefend; + ++typedefit) { + instantiation->_typedefs[typedefit->first] = + _cloner.symbol(typedefit->second, &_subst)->asDeclaration(); + } foreach (Symbol *s, lookupScope->_symbols) { Symbol *clone = _cloner.symbol(s, &_subst); if (!clone->enclosingScope()) // Not from the cache but just cloned. @@ -1560,6 +1609,11 @@ void LookupScopePrivate::addUnscopedEnum(Enum *e) _enums.append(e); } +void LookupScopePrivate::addTypedef(const Name *identifier, Declaration *d) +{ + _typedefs[identifier] = d; +} + void LookupScopePrivate::addUsing(LookupScope *u) { _usings.append(u); @@ -1783,17 +1837,13 @@ bool CreateBindings::visit(Enum *e) bool CreateBindings::visit(Declaration *decl) { if (decl->isTypedef()) { + _currentLookupScope->d->_hasTypedefs = true; FullySpecifiedType ty = decl->type(); const Identifier *typedefId = decl->identifier(); if (typedefId && ! (ty.isConst() || ty.isVolatile())) { - if (const NamedType *namedTy = ty->asNamedType()) { - if (LookupScope *e = _currentLookupScope->lookupType(namedTy->name())) { - _currentLookupScope->d->addNestedType(decl->name(), e); - } else if (false) { - Overview oo; - qDebug() << "found entity not found for" << oo.prettyName(namedTy->name()); - } + if (ty->isNamedType()) { + _currentLookupScope->d->addTypedef(typedefId, decl); } else if (Class *klass = ty->asClassType()) { if (const Identifier *nameId = decl->name()->asNameId()) { LookupScope *binding @@ -1849,6 +1899,7 @@ bool CreateBindings::visit(Block *block) if (! _currentLookupScope->d->_blocks.empty() || ! _currentLookupScope->d->_nestedScopes.empty() || ! _currentLookupScope->d->_enums.empty() + || _currentLookupScope->d->_hasTypedefs || ! _currentLookupScope->d->_anonymouses.empty()) { previous->d->_blocks[block] = binding; _entities.append(binding); diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 0a261c50d40..824e1770119 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -787,7 +787,7 @@ bool ResolveExpression::visit(ArrayAccessAST *ast) FullySpecifiedType ty = result.type().simplified(); Scope *scope = result.scope(); - TypeResolver typeResolver(_context); + TypeResolver typeResolver(*_context.bindings()); typeResolver.resolve(&ty, &scope, result.binding()); if (PointerType *ptrTy = ty->asPointerType()) { @@ -916,7 +916,7 @@ LookupScope *ResolveExpression::baseExpression(const QList &baseResu if (Q_UNLIKELY(debug)) qDebug() << "In ResolveExpression::baseExpression with" << baseResults.size() << "results..."; int i = 0; - TypeResolver typeResolver(_context); + TypeResolver typeResolver(*_context.bindings()); foreach (const LookupItem &r, baseResults) { if (!r.type().type() || !r.scope()) diff --git a/src/libs/cplusplus/TypeResolver.cpp b/src/libs/cplusplus/TypeResolver.cpp index 10c69864dbc..415418a0b10 100644 --- a/src/libs/cplusplus/TypeResolver.cpp +++ b/src/libs/cplusplus/TypeResolver.cpp @@ -79,7 +79,7 @@ QList TypeResolver::getNamedTypeItems(const Name *name, Scope *scope if (namedTypeItems.isEmpty()) { if (binding) namedTypeItems = binding->lookup(name); - if (LookupScope *scopeCon = _context.lookupType(scope)) { + if (LookupScope *scopeCon = _factory.lookupType(scope)) { if (scopeCon != binding) namedTypeItems += scopeCon->lookup(name); } @@ -140,10 +140,10 @@ bool TypeResolver::findTypedef(const QList &namedTypeItems, FullySpe // continue working with the typedefed type and scope if (type->type()->isPointerType()) { *type = FullySpecifiedType( - _context.bindings()->control()->pointerType(declaration->type())); + _factory.control()->pointerType(declaration->type())); } else if (type->type()->isReferenceType()) { *type = FullySpecifiedType( - _context.bindings()->control()->referenceType( + _factory.control()->referenceType( declaration->type(), declaration->type()->asReferenceType()->isRvalueReference())); } else { diff --git a/src/libs/cplusplus/TypeResolver.h b/src/libs/cplusplus/TypeResolver.h index 5aa33a54d8e..164d7e3ada1 100644 --- a/src/libs/cplusplus/TypeResolver.h +++ b/src/libs/cplusplus/TypeResolver.h @@ -38,7 +38,7 @@ namespace CPlusPlus { class TypeResolver { public: - TypeResolver(const LookupContext &context) : _context(context) {} + TypeResolver(CreateBindings &factory) : _factory(factory) {} void resolve(FullySpecifiedType *type, Scope **scope, LookupScope *binding); private: @@ -54,7 +54,7 @@ private: bool findTypedef(const QList& namedTypeItems, FullySpecifiedType *type, Scope **scope, QSet& visited); - const LookupContext &_context; + CreateBindings &_factory; // binding has to be remembered in case of resolving typedefs for templates LookupScope *_binding; }; diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index 628afccdbff..8bbcd458b3c 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -330,12 +330,9 @@ void CppToolsPlugin::test_completion() QEXPECT_FAIL("enum_in_function_in_struct_in_function_anon", "QTCREATORBUG-13757", Abort); QEXPECT_FAIL("enum_in_class_accessed_in_member_func_cxx11", "QTCREATORBUG-13757", Abort); QEXPECT_FAIL("enum_in_class_accessed_in_member_func_inline_cxx11", "QTCREATORBUG-13757", Abort); - QEXPECT_FAIL("pointer_indirect_specialization", "QTCREATORBUG-14141", Abort); - QEXPECT_FAIL("pointer_indirect_specialization_typedef", "QTCREATORBUG-14141", Abort); QEXPECT_FAIL("pointer_indirect_specialization_double_indirection", "QTCREATORBUG-14141", Abort); QEXPECT_FAIL("pointer_indirect_specialization_double_indirection_with_base", "QTCREATORBUG-14141", Abort); QEXPECT_FAIL("recursive_instantiation_of_template_type", "QTCREATORBUG-14237", Abort); - QEXPECT_FAIL("recursive_instantiation_of_template_type_2", "QTCREATORBUG-14141", Abort); QCOMPARE(actualCompletions, expectedCompletions); } diff --git a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp index 1766bf5e1d6..012fc1310b9 100644 --- a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp +++ b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp @@ -1202,13 +1202,11 @@ void tst_CheckSymbols::findField() source[position] = ' '; BaseTestCase tc(source); Use use = tc.findUse(line, column); - QEXPECT_FAIL("pointer_indirect_specialization", "QTCREATORBUG-14141", Abort); QEXPECT_FAIL("pointer_indirect_specialization_typedef", "QTCREATORBUG-14141", Abort); QEXPECT_FAIL("pointer_indirect_specialization_double_indirection", "QTCREATORBUG-14141", Abort); QEXPECT_FAIL("instantiation_of_pointer_typedef_in_block", "QTCREATORBUG-14141", Abort); QEXPECT_FAIL("pointer_indirect_specialization_double_indirection_with_base", "QTCREATORBUG-14141", Abort); QEXPECT_FAIL("recursive_instantiation_of_template_type", "QTCREATORBUG-14237", Abort); - QEXPECT_FAIL("recursive_instantiation_of_template_type_2", "QTCREATORBUG-14141", Abort); QVERIFY(use.isValid()); QVERIFY(use.kind == Highlighting::FieldUse); }