Commit 37217333 authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh

C++: Fix explicit typedef from base type in templated class

Use-case:

struct Foo { int bar; };

template<typename T>
struct Base { typedef T F; };

template<typename T>
struct Derived : Base<T>
{
    typedef typename Base<T>::F F;
    F f;
};

void func()
{
    Derived<Foo> d;
    d.f.bar; // bar not highlighted
}

Task-number: QTCREATORBUG-14218
Change-Id: Ic0b22b2f8adf80ff88a2f8b7359c276a744f89e8
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@theqtcompany.com>
parent cf66beff
......@@ -612,7 +612,10 @@ public:
: _cloner(cloner)
, _subst(subst)
{}
void instantiate(LookupScopePrivate *lookupScope, LookupScopePrivate *instantiation);
void instantiate(LookupScopePrivate *lookupScope,
LookupScopePrivate *instantiation,
bool includeSymbols);
LookupScopePrivate *maybeInstantiate(LookupScopePrivate *lookupScope);
private:
bool isInstantiationNeeded(LookupScopePrivate *lookupScope) const;
......@@ -1356,7 +1359,6 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope
// The instantiation should have all symbols, enums, and usings from the reference.
instantiation->_enums = reference->_enums;
instantiation->_usings = reference->_usings;
instantiation->_rootClass = reference->_rootClass;
......@@ -1400,8 +1402,9 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope
}
Instantiator instantiator(cloner, subst);
instantiator.instantiate(reference, instantiation);
instantiator.instantiate(reference, instantiation, true);
} else {
instantiation->_usings = reference->_usings;
instantiation->_symbols.append(reference->_symbols);
instantiation->_typedefs = reference->_typedefs;
}
......@@ -1477,6 +1480,7 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope
}
} else {
instantiation->_nestedScopes = reference->_nestedScopes;
instantiation->_usings = reference->_usings;
instantiation->_symbols.append(reference->_symbols);
instantiation->_typedefs = reference->_typedefs;
}
......@@ -1517,8 +1521,34 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope
return reference;
}
LookupScopePrivate *Instantiator::maybeInstantiate(LookupScopePrivate *lookupScope)
{
lookupScope->flush();
LookupScopePrivate *instantiation = lookupScope;
bool hasTemplateSymbols = isInstantiationNeeded(lookupScope);
bool hasTemplateUsings = false;
if (!hasTemplateSymbols) {
foreach (LookupScope *usingLookupScope, lookupScope->_usings) {
if (isInstantiationNeeded(usingLookupScope->d)) {
hasTemplateUsings = true;
break;
}
}
}
if (hasTemplateSymbols || hasTemplateUsings) {
instantiation = lookupScope->allocateChild(lookupScope->_name);
instantiation->_enums = lookupScope->_enums;
instantiation->_instantiationOrigin = lookupScope;
instantiate(lookupScope, instantiation, hasTemplateSymbols);
}
return instantiation;
}
void Instantiator::instantiate(LookupScopePrivate *lookupScope,
LookupScopePrivate *instantiation)
LookupScopePrivate *instantiation,
bool includeSymbols)
{
if (_alreadyConsideredInstantiations.contains(lookupScope))
return;
......@@ -1531,52 +1561,48 @@ void Instantiator::instantiate(LookupScopePrivate *lookupScope,
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.
clone->setEnclosingScope(s->enclosingScope());
instantiation->_symbols.append(clone);
if (s == instantiation->_rootClass) {
clone->setName(instantiation->_name);
instantiation->_rootClass = clone->asClass();
}
if (Q_UNLIKELY(debug)) {
Overview oo;
oo.showFunctionSignatures = true;
oo.showReturnTypes = true;
oo.showTemplateParameters = true;
qDebug() << "cloned" << oo(clone->type());
if (Class *klass = clone->asClass()) {
const unsigned klassMemberCount = klass->memberCount();
for (unsigned i = 0; i < klassMemberCount; ++i){
Symbol *klassMemberAsSymbol = klass->memberAt(i);
if (klassMemberAsSymbol->isTypedef()) {
if (Declaration *declaration = klassMemberAsSymbol->asDeclaration())
qDebug() << "Member: " << oo(declaration->type(), declaration->name());
foreach (LookupScope *usingLookupScope, lookupScope->_usings)
instantiation->_usings.append(maybeInstantiate(usingLookupScope->d)->q);
if (includeSymbols) {
foreach (Symbol *s, lookupScope->_symbols) {
Symbol *clone = _cloner.symbol(s, &_subst);
if (!clone->enclosingScope()) // Not from the cache but just cloned.
clone->setEnclosingScope(s->enclosingScope());
instantiation->_symbols.append(clone);
if (s == instantiation->_rootClass) {
clone->setName(instantiation->_name);
instantiation->_rootClass = clone->asClass();
}
if (Q_UNLIKELY(debug)) {
Overview oo;
oo.showFunctionSignatures = true;
oo.showReturnTypes = true;
oo.showTemplateParameters = true;
qDebug() << "cloned" << oo(clone->type());
if (Class *klass = clone->asClass()) {
const unsigned klassMemberCount = klass->memberCount();
for (unsigned i = 0; i < klassMemberCount; ++i){
Symbol *klassMemberAsSymbol = klass->memberAt(i);
if (klassMemberAsSymbol->isTypedef()) {
if (Declaration *declaration = klassMemberAsSymbol->asDeclaration())
qDebug() << "Member: " << oo(declaration->type(), declaration->name());
}
}
}
}
}
} else {
instantiation->_symbols = lookupScope->_symbols;
}
}
auto cit = lookupScope->_nestedScopes.begin();
for (; cit != lookupScope->_nestedScopes.end(); ++cit) {
const Name *nestedName = cit->first;
LookupScopePrivate *nestedLookupScope = cit->second;
LookupScopePrivate *nestedInstantiation = nestedLookupScope;
nestedLookupScope->flush();
const bool instantiationNeeded = isInstantiationNeeded(nestedInstantiation);
if (instantiationNeeded) {
nestedInstantiation = nestedLookupScope->allocateChild(nestedName);
nestedInstantiation->_enums = nestedLookupScope->_enums;
nestedInstantiation->_usings = nestedLookupScope->_usings;
nestedInstantiation->_instantiationOrigin = nestedLookupScope;
}
LookupScopePrivate *nestedInstantiation = maybeInstantiate(nestedLookupScope);
if (isNestedInstantiationEnclosingTemplate(nestedInstantiation, lookupScope))
nestedInstantiation->_parent = instantiation;
instantiate(nestedLookupScope, nestedInstantiation);
instantiation->_nestedScopes[nestedName] = nestedInstantiation;
}
......
......@@ -326,13 +326,13 @@ void CppToolsPlugin::test_completion()
actualCompletions.sort();
expectedCompletions.sort();
QEXPECT_FAIL("template_as_base: explicit typedef from base", "QTCREATORBUG-14218", Abort);
QEXPECT_FAIL("template_as_base: typedef not available in derived",
"We can live with that...", Abort);
QEXPECT_FAIL("enum_in_function_in_struct_in_function", "QTCREATORBUG-13757", Abort);
QEXPECT_FAIL("enum_in_function_in_struct_in_function_cxx11", "QTCREATORBUG-13757", Abort);
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_double_indirection_with_base", "QTCREATORBUG-14141", Abort);
QEXPECT_FAIL("recursive_instantiation_of_template_type", "QTCREATORBUG-14237", Abort);
QCOMPARE(actualCompletions, expectedCompletions);
}
......
......@@ -1203,7 +1203,6 @@ void tst_CheckSymbols::findField()
source[position] = ' ';
BaseTestCase tc(source);
Use use = tc.findUse(line, column);
QEXPECT_FAIL("pointer_indirect_specialization_double_indirection_with_base", "QTCREATORBUG-14141", Abort);
QEXPECT_FAIL("recursive_instantiation_of_template_type", "QTCREATORBUG-14237", 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