Commit ad4cb444 authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh
Browse files

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: default avatarNikolai Kosjar <nikolai.kosjar@theqtcompany.com>
parent aa893918
......@@ -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);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment