C++: Support default template argument lookup for specialization

This fixes std::vector, although it doesn't really resolve numeric
template arguments. It just picks the first specialization.

Use-case:
class Foo {};
template<class T1 = Foo> class Temp;
template<> class Temp<Foo> { int var; };
void func()
{
    Temp<> t;
    t.var; // var not highlighted
}

Task-number: QTCREATORBUG-8922
Change-Id: I593515beb3a6d901b6088db8bc1b8e16c39083d3
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
Orgad Shaneh
2015-06-07 11:47:50 +03:00
committed by Orgad Shaneh
parent 1c7e465c30
commit 97d3d9ac09
3 changed files with 74 additions and 40 deletions

View File

@@ -569,7 +569,7 @@ private:
LookupScopePrivate *nestedType(const Name *name, LookupScopePrivate *origin); LookupScopePrivate *nestedType(const Name *name, LookupScopePrivate *origin);
LookupScopePrivate *findSpecialization(const TemplateNameId *templId, LookupScopePrivate *findSpecialization(const Template *baseTemplate, const TemplateNameId *templId,
const TemplateNameIdTable &specializations, const TemplateNameIdTable &specializations,
LookupScopePrivate *origin); LookupScopePrivate *origin);
@@ -1201,28 +1201,25 @@ static bool matchTypes(const FullySpecifiedType &instantiation,
} }
LookupScopePrivate *LookupScopePrivate::findSpecialization( LookupScopePrivate *LookupScopePrivate::findSpecialization(
const Template *baseTemplate,
const TemplateNameId *templId, const TemplateNameId *templId,
const TemplateNameIdTable &specializations, const TemplateNameIdTable &specializations,
LookupScopePrivate *origin) LookupScopePrivate *origin)
{ {
Clone cloner(_factory->control().data());
for (TemplateNameIdTable::const_iterator cit = specializations.begin(); for (TemplateNameIdTable::const_iterator cit = specializations.begin();
cit != specializations.end(); ++cit) { cit != specializations.end(); ++cit) {
const TemplateNameId *specializationNameId = cit->first; const TemplateNameId *specializationNameId = cit->first;
const unsigned specializationTemplateArgumentCount const unsigned specializationTemplateArgumentCount
= specializationNameId->templateArgumentCount(); = specializationNameId->templateArgumentCount();
const unsigned initializationTemplateArgumentCount = templId->templateArgumentCount(); Subst subst(_factory->control().data());
// for now it works only when we have the same number of arguments in specialization
// and initialization(in future it should be more clever)
if (specializationTemplateArgumentCount != initializationTemplateArgumentCount)
continue;
bool match = true; bool match = true;
for (unsigned i = 0; i < initializationTemplateArgumentCount && match; ++i) { for (unsigned i = 0; i < specializationTemplateArgumentCount && match; ++i) {
const FullySpecifiedType &specializationTemplateArgument const FullySpecifiedType &specializationTemplateArgument
= specializationNameId->templateArgumentAt(i); = specializationNameId->templateArgumentAt(i);
FullySpecifiedType initializationTemplateArgument = templId->templateArgumentAt(i); FullySpecifiedType initializationTemplateArgument =
TypeResolver typeResolver(*_factory); _factory->resolveTemplateArgument(cloner, subst, origin ? origin->q : 0,
Scope *scope = 0; baseTemplate, templId, i);
typeResolver.resolve(&initializationTemplateArgument, &scope, origin ? origin->q : 0);
// specialization and initialization argument have to be a pointer // specialization and initialization argument have to be a pointer
// additionally type of pointer argument of specialization has to be namedType // additionally type of pointer argument of specialization has to be namedType
if (findTemplateArgument(dereference(specializationTemplateArgument), cit->second)) { if (findTemplateArgument(dereference(specializationTemplateArgument), cit->second)) {
@@ -1340,8 +1337,17 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope
// we found full specialization // we found full specialization
reference = cit->second; reference = cit->second;
} else { } else {
Template *baseTemplate = 0;
foreach (Symbol *s, reference->_symbols) {
if (Class *clazz = s->asClass())
baseTemplate = clazz->enclosingTemplate();
else if (ForwardClassDeclaration *forward = s->asForwardClassDeclaration())
baseTemplate = forward->enclosingTemplate();
if (baseTemplate)
break;
}
if (LookupScopePrivate *specialization = if (LookupScopePrivate *specialization =
findSpecialization(templId, specializations, origin)) { findSpecialization(baseTemplate, templId, specializations, origin)) {
reference = specialization; reference = specialization;
if (Q_UNLIKELY(debug)) { if (Q_UNLIKELY(debug)) {
Overview oo; Overview oo;
@@ -2088,40 +2094,50 @@ bool CreateBindings::visit(ObjCMethod *)
return false; return false;
} }
FullySpecifiedType CreateBindings::resolveTemplateArgument(Clone &cloner,
Subst &subst,
LookupScope *origin,
const Template *specialization,
const TemplateNameId *instantiation,
unsigned index)
{
FullySpecifiedType ty;
const TypenameArgument *tParam
= specialization->templateParameterAt(index)->asTypenameArgument();
if (!tParam)
return ty;
if (index < instantiation->templateArgumentCount())
ty = instantiation->templateArgumentAt(index);
else
ty = cloner.type(tParam->type(), &subst);
TypeResolver typeResolver(*this);
Scope *resolveScope = specialization->enclosingScope();
typeResolver.resolve(&ty, &resolveScope, origin);
const TemplateNameId *templSpecId = specialization->name()->asTemplateNameId();
const unsigned templSpecArgumentCount = templSpecId ? templSpecId->templateArgumentCount() : 0;
if (index < templSpecArgumentCount && templSpecId->templateArgumentAt(index)->isPointerType()) {
if (PointerType *pointerType = ty->asPointerType())
ty = pointerType->elementType();
}
if (const Name *name = tParam->name())
subst.bind(cloner.name(name, &subst), ty);
return ty;
}
void CreateBindings::initializeSubst(Clone &cloner, void CreateBindings::initializeSubst(Clone &cloner,
Subst &subst, Subst &subst,
LookupScope *origin, LookupScope *origin,
Template *specialization, const Template *specialization,
const TemplateNameId *instantiation) const TemplateNameId *instantiation)
{ {
const unsigned argumentCountOfInitialization = instantiation->templateArgumentCount();
const unsigned argumentCountOfSpecialization = specialization->templateParameterCount(); const unsigned argumentCountOfSpecialization = specialization->templateParameterCount();
const TemplateNameId *templSpecId = specialization->name()->asTemplateNameId(); for (unsigned i = 0; i < argumentCountOfSpecialization; ++i)
const unsigned templSpecArgumentCount = templSpecId ? templSpecId->templateArgumentCount() : 0; resolveTemplateArgument(cloner, subst, origin, specialization, instantiation, i);
for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) {
const TypenameArgument *tParam
= specialization->templateParameterAt(i)->asTypenameArgument();
if (!tParam)
continue;
const Name *name = tParam->name();
if (!name)
continue;
FullySpecifiedType ty = (i < argumentCountOfInitialization) ?
instantiation->templateArgumentAt(i):
cloner.type(tParam->type(), &subst);
TypeResolver typeResolver(*this);
Scope *resolveScope = specialization->enclosingScope();
typeResolver.resolve(&ty, &resolveScope, origin);
if (i < templSpecArgumentCount && templSpecId->templateArgumentAt(i)->isPointerType()) {
if (PointerType *pointerType = ty->asPointerType())
ty = pointerType->elementType();
}
subst.bind(cloner.name(name, &subst), ty);
}
} }
} // namespace CPlusPlus } // namespace CPlusPlus

View File

@@ -150,8 +150,13 @@ public:
/// \internal /// \internal
LookupScope *allocLookupScope(LookupScope *parent, const Name *name); LookupScope *allocLookupScope(LookupScope *parent, const Name *name);
FullySpecifiedType resolveTemplateArgument(Clone &cloner, Subst &subst,
LookupScope *origin,
const Template *specialization,
const TemplateNameId *instantiation,
unsigned index);
void initializeSubst(Clone &cloner, Subst &subst, LookupScope *origin, void initializeSubst(Clone &cloner, Subst &subst, LookupScope *origin,
Template *specialization, const TemplateNameId *instantiation); const Template *specialization, const TemplateNameId *instantiation);
protected: protected:
using SymbolVisitor::visit; using SymbolVisitor::visit;

View File

@@ -2689,6 +2689,19 @@ void CppToolsPlugin::test_completion_data()
<< QLatin1String("f") << QLatin1String("f")
<< QLatin1String("and_type")); << QLatin1String("and_type"));
QTest::newRow("specialization_with_default_value") << _(
"class Foo {};\n"
"template<class T1 = Foo> class Temp;\n"
"template<> class Temp<Foo> { int var; };\n"
"void func()\n"
"{\n"
" Temp<> t;\n"
" @\n"
"}\n"
) << _("t.") << (QStringList()
<< QLatin1String("var")
<< QLatin1String("Temp"));
QTest::newRow("auto_declaration_in_if_condition") << _( QTest::newRow("auto_declaration_in_if_condition") << _(
"struct Foo { int bar; };\n" "struct Foo { int bar; };\n"
"void fun() {\n" "void fun() {\n"