Commit 97d3d9ac authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh

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: default avatarNikolai Kosjar <nikolai.kosjar@theqtcompany.com>
parent 1c7e465c
......@@ -569,7 +569,7 @@ private:
LookupScopePrivate *nestedType(const Name *name, LookupScopePrivate *origin);
LookupScopePrivate *findSpecialization(const TemplateNameId *templId,
LookupScopePrivate *findSpecialization(const Template *baseTemplate, const TemplateNameId *templId,
const TemplateNameIdTable &specializations,
LookupScopePrivate *origin);
......@@ -1201,28 +1201,25 @@ static bool matchTypes(const FullySpecifiedType &instantiation,
}
LookupScopePrivate *LookupScopePrivate::findSpecialization(
const Template *baseTemplate,
const TemplateNameId *templId,
const TemplateNameIdTable &specializations,
LookupScopePrivate *origin)
{
Clone cloner(_factory->control().data());
for (TemplateNameIdTable::const_iterator cit = specializations.begin();
cit != specializations.end(); ++cit) {
const TemplateNameId *specializationNameId = cit->first;
const unsigned specializationTemplateArgumentCount
= specializationNameId->templateArgumentCount();
const unsigned initializationTemplateArgumentCount = templId->templateArgumentCount();
// 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;
Subst subst(_factory->control().data());
bool match = true;
for (unsigned i = 0; i < initializationTemplateArgumentCount && match; ++i) {
for (unsigned i = 0; i < specializationTemplateArgumentCount && match; ++i) {
const FullySpecifiedType &specializationTemplateArgument
= specializationNameId->templateArgumentAt(i);
FullySpecifiedType initializationTemplateArgument = templId->templateArgumentAt(i);
TypeResolver typeResolver(*_factory);
Scope *scope = 0;
typeResolver.resolve(&initializationTemplateArgument, &scope, origin ? origin->q : 0);
FullySpecifiedType initializationTemplateArgument =
_factory->resolveTemplateArgument(cloner, subst, origin ? origin->q : 0,
baseTemplate, templId, i);
// specialization and initialization argument have to be a pointer
// additionally type of pointer argument of specialization has to be namedType
if (findTemplateArgument(dereference(specializationTemplateArgument), cit->second)) {
......@@ -1340,8 +1337,17 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope
// we found full specialization
reference = cit->second;
} 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 =
findSpecialization(templId, specializations, origin)) {
findSpecialization(baseTemplate, templId, specializations, origin)) {
reference = specialization;
if (Q_UNLIKELY(debug)) {
Overview oo;
......@@ -2088,40 +2094,50 @@ bool CreateBindings::visit(ObjCMethod *)
return false;
}
void CreateBindings::initializeSubst(Clone &cloner,
Subst &subst,
LookupScope *origin,
Template *specialization,
const TemplateNameId *instantiation)
FullySpecifiedType CreateBindings::resolveTemplateArgument(Clone &cloner,
Subst &subst,
LookupScope *origin,
const Template *specialization,
const TemplateNameId *instantiation,
unsigned index)
{
const unsigned argumentCountOfInitialization = instantiation->templateArgumentCount();
const unsigned argumentCountOfSpecialization = specialization->templateParameterCount();
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;
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;
if (index < templSpecArgumentCount && templSpecId->templateArgumentAt(index)->isPointerType()) {
if (PointerType *pointerType = ty->asPointerType())
ty = pointerType->elementType();
}
FullySpecifiedType ty = (i < argumentCountOfInitialization) ?
instantiation->templateArgumentAt(i):
cloner.type(tParam->type(), &subst);
if (const Name *name = tParam->name())
subst.bind(cloner.name(name, &subst), ty);
return ty;
}
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();
}
void CreateBindings::initializeSubst(Clone &cloner,
Subst &subst,
LookupScope *origin,
const Template *specialization,
const TemplateNameId *instantiation)
{
const unsigned argumentCountOfSpecialization = specialization->templateParameterCount();
subst.bind(cloner.name(name, &subst), ty);
}
for (unsigned i = 0; i < argumentCountOfSpecialization; ++i)
resolveTemplateArgument(cloner, subst, origin, specialization, instantiation, i);
}
} // namespace CPlusPlus
......@@ -150,8 +150,13 @@ public:
/// \internal
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,
Template *specialization, const TemplateNameId *instantiation);
const Template *specialization, const TemplateNameId *instantiation);
protected:
using SymbolVisitor::visit;
......
......@@ -2689,6 +2689,19 @@ void CppToolsPlugin::test_completion_data()
<< QLatin1String("f")
<< 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") << _(
"struct Foo { int bar; };\n"
"void fun() {\n"
......
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