forked from qt-creator/qt-creator
C++: Fix specialization resolution for nested types
Use-cases: template<typename T> struct Traits { typedef typename T::pointer pointer; }; template<typename _Tp> struct Traits<_Tp*> { typedef _Tp *pointer; }; struct Foo { int bar; }; // 1 template<typename T> class Temp { protected: typedef Traits<T> TraitsT; public: typedef typename TraitsT::pointer pointer; pointer p; }; void func() { Temp<Foo *> t; t.p-> // complete } // 2 class Temp2 { protected: typedef Foo *FooPtr; typedef Traits<FooPtr> 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 <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
committed by
Orgad Shaneh
parent
aa893918c1
commit
ad4cb444fb
@@ -33,6 +33,7 @@
|
||||
#include "ResolveExpression.h"
|
||||
#include "Overview.h"
|
||||
#include "CppRewriter.h"
|
||||
#include "TypeResolver.h"
|
||||
|
||||
#include <cplusplus/CoreTypes.h>
|
||||
#include <cplusplus/Symbols.h>
|
||||
@@ -525,6 +526,7 @@ public:
|
||||
~LookupScopePrivate();
|
||||
|
||||
typedef std::map<const Name *, LookupScopePrivate *, Name::Compare> Table;
|
||||
typedef std::map<const Name *, Declaration *, Name::Compare> TypedefTable;
|
||||
typedef std::map<const TemplateNameId *,
|
||||
LookupScopePrivate *,
|
||||
TemplateNameId::Compare> 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<Symbol *> _symbols;
|
||||
QList<LookupScope *> _usings;
|
||||
Table _nestedScopes;
|
||||
TypedefTable _typedefs;
|
||||
QHash<Block *, LookupScope *> _blocks;
|
||||
QList<Enum *> _enums;
|
||||
QList<Symbol *> _todo;
|
||||
@@ -589,9 +598,11 @@ public:
|
||||
|
||||
AlreadyConsideredClassContainer<Class> _alreadyConsideredClasses;
|
||||
AlreadyConsideredClassContainer<TemplateNameId> _alreadyConsideredTemplates;
|
||||
QSet<const Declaration *> _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<const Name*, unsigned> 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);
|
||||
|
@@ -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<LookupItem> &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())
|
||||
|
@@ -79,7 +79,7 @@ QList<LookupItem> 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<LookupItem> &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 {
|
||||
|
@@ -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<LookupItem>& namedTypeItems, FullySpecifiedType *type,
|
||||
Scope **scope, QSet<Symbol *>& visited);
|
||||
|
||||
const LookupContext &_context;
|
||||
CreateBindings &_factory;
|
||||
// binding has to be remembered in case of resolving typedefs for templates
|
||||
LookupScope *_binding;
|
||||
};
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user