Commit 858cb6e3 authored by Przemyslaw Gorszkowski's avatar Przemyslaw Gorszkowski Committed by Erik Verbruggen

C++: instantiate template with default argument

Fix code completion for instantiation of template with default argument

Change-Id: I57b0306cc4540400ae83724db6c8b6b1aa67c255
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@digia.com>
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@digia.com>
parent 2c7347b8
......@@ -801,20 +801,27 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
// It gets a bit complicated if the reference is actually a class template because we
// now must worry about dependent names in base classes.
if (Template *templ = referenceClass->enclosingTemplate()) {
const unsigned argumentCount = templId->templateArgumentCount();
if (Template *templateSpecialization = referenceClass->enclosingTemplate()) {
const unsigned argumentCountOfInitialization = templId->templateArgumentCount();
const unsigned argumentCountOfSpecialization
= templateSpecialization->templateParameterCount();
if (_factory->expandTemplates()) {
Clone cloner(_control.data());
Subst subst(_control.data());
for (unsigned i = 0, ei = std::min(argumentCount, templ->templateParameterCount()); i < ei; ++i) {
const TypenameArgument *tParam = templ->templateParameterAt(i)->asTypenameArgument();
for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) {
const TypenameArgument *tParam
= templateSpecialization->templateParameterAt(i)->asTypenameArgument();
if (!tParam)
continue;
const Name *name = tParam->name();
if (!name)
continue;
const FullySpecifiedType &ty = templId->templateArgumentAt(i);
FullySpecifiedType ty = (i < argumentCountOfInitialization) ?
templId->templateArgumentAt(i):
cloner.type(tParam->type(), &subst);
subst.bind(cloner.name(name, &subst), ty);
}
......@@ -822,7 +829,9 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
Symbol *clone = cloner.symbol(s, &subst);
instantiation->_symbols.append(clone);
#ifdef DEBUG_LOOKUP
Overview oo;oo.showFunctionSignatures = true;oo.showReturnTypes = true; oo.showTemplateParameters = true;
Overview oo;oo.showFunctionSignatures = true;
oo.showReturnTypes = true;
oo.showTemplateParameters = true;
qDebug()<<"cloned"<<oo(clone->type());
#endif // DEBUG_LOOKUP
}
......@@ -832,8 +841,8 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
}
QHash<const Name*, unsigned> templParams;
for (unsigned i = 0; i < templ->templateParameterCount(); ++i)
templParams.insert(templ->templateParameterAt(i)->name(), i);
for (unsigned i = 0; i < argumentCountOfSpecialization; ++i)
templParams.insert(templateSpecialization->templateParameterAt(i)->name(), i);
foreach (const Name *baseName, allBases) {
ClassOrNamespace *baseBinding = 0;
......@@ -843,7 +852,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
// Ex.: template <class T> class A : public T {};
if (templParams.contains(nameId)) {
const unsigned parameterIndex = templParams.value(nameId);
if (parameterIndex < argumentCount) {
if (parameterIndex < argumentCountOfInitialization) {
const FullySpecifiedType &fullType =
templId->templateArgumentAt(parameterIndex);
if (fullType.isValid()) {
......@@ -855,9 +864,9 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
} else {
SubstitutionMap map;
for (unsigned i = 0;
i < templ->templateParameterCount() && i < argumentCount;
i < argumentCountOfSpecialization && i < argumentCountOfInitialization;
++i) {
map.bind(templ->templateParameterAt(i)->name(),
map.bind(templateSpecialization->templateParameterAt(i)->name(),
templId->templateArgumentAt(i));
}
SubstitutionEnvironment env;
......@@ -876,7 +885,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
ClassOrNamespace *binding = this;
if (const Name *qualification = qBaseName->base()) {
const TemplateNameId *baseTemplName = qualification->asTemplateNameId();
if (!baseTemplName || !compareName(baseTemplName, templ->name()))
if (!baseTemplName || !compareName(baseTemplName, templateSpecialization->name()))
binding = lookupType(qualification);
}
baseName = qBaseName->name();
......
......@@ -1328,6 +1328,79 @@ void CppToolsPlugin::test_completion_instantiate_nested_of_nested_class_when_enc
QVERIFY(completions.contains(QLatin1String("foo_i")));
}
void CppToolsPlugin::test_completion_instantiate_template_with_default_argument_type()
{
TestData data;
data.srcText = "\n"
"struct Foo\n"
"{\n"
" int bar;\n"
"};\n"
"\n"
"template <typename T = Foo>\n"
"struct Template\n"
"{\n"
" T t;\n"
"};\n"
"\n"
"Template<> templateWithDefaultTypeOfArgument;\n"
"@\n"
;
setup(&data);
Utils::ChangeSet change;
QString txt = QLatin1String("templateWithDefaultTypeOfArgument.t.");
change.insert(data.pos, txt);
QTextCursor cursor(data.doc);
change.apply(&cursor);
data.pos += txt.length();
QStringList completions = getCompletions(data);
QCOMPARE(completions.size(), 2);
QVERIFY(completions.contains(QLatin1String("Foo")));
QVERIFY(completions.contains(QLatin1String("bar")));
}
void CppToolsPlugin::test_completion_instantiate_template_with_default_argument_type_as_template()
{
TestData data;
data.srcText = "\n"
"struct Foo\n"
"{\n"
" int bar;\n"
"};\n"
"\n"
"template <typename T>\n"
"struct TemplateArg\n"
"{\n"
" T t;\n"
"};\n"
"template <typename T, typename S = TemplateArg<T> >\n"
"struct Template\n"
"{\n"
" S s;\n"
"};\n"
"\n"
"Template<Foo> templateWithDefaultTypeOfArgument;\n"
"@\n"
;
setup(&data);
Utils::ChangeSet change;
QString txt = QLatin1String("templateWithDefaultTypeOfArgument.s.t.");
change.insert(data.pos, txt);
QTextCursor cursor(data.doc);
change.apply(&cursor);
data.pos += txt.length();
QStringList completions = getCompletions(data);
QCOMPARE(completions.size(), 2);
QVERIFY(completions.contains(QLatin1String("Foo")));
QVERIFY(completions.contains(QLatin1String("bar")));
}
void CppToolsPlugin::test_completion_member_access_operator_1()
{
TestData data;
......
......@@ -113,6 +113,8 @@ private slots:
void test_completion_enclosing_template_class_data();
void test_completion_instantiate_nested_class_when_enclosing_is_template();
void test_completion_instantiate_nested_of_nested_class_when_enclosing_is_template();
void test_completion_instantiate_template_with_default_argument_type();
void test_completion_instantiate_template_with_default_argument_type_as_template();
void test_completion_member_access_operator_1();
void test_completion_typedef_of_type_and_replace_access_operator();
void test_completion_typedef_of_pointer_of_type_and_replace_access_operator();
......
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