Commit ea321915 authored by Przemyslaw Gorszkowski's avatar Przemyslaw Gorszkowski Committed by Erik Verbruggen

C++: fix instantiation of template special. with pointer argument

Fixed code completion for instantiation of template specialization
with argument as pointer, e.g.:
template <typename T>
struct Template
{ T variable; };
template <typename T>
struct Template<T *>
{ T *pointer; };
Template<int*> templ;
templ.pointer;

Change-Id: I7c79fe0cd7119b1208f064aece0cafdf50e1a012
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@digia.com>
parent 195d3924
......@@ -703,6 +703,40 @@ ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
return 0;
}
ClassOrNamespace *ClassOrNamespace::findSpecializationWithPointer(const TemplateNameId *templId,
const TemplateNameIdTable &specializations)
{
// we go through all specialization and try to find that one with template argument as pointer
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) {
for (unsigned i = 0; i < initializationTemplateArgumentCount; ++i) {
const FullySpecifiedType &specializationTemplateArgument
= specializationNameId->templateArgumentAt(i);
const FullySpecifiedType &initializationTemplateArgument
= templId->templateArgumentAt(i);
PointerType *specPointer
= specializationTemplateArgument.type()->asPointerType();
// specialization and initialization argument have to be a pointer
// additionally type of pointer argument of specialization has to be namedType
if (specPointer && initializationTemplateArgument.type()->isPointerType()
&& specPointer->elementType().type()->isNamedType()) {
return cit->second;
}
}
}
}
return 0;
}
ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespace *origin)
{
Q_ASSERT(name != 0);
......@@ -740,11 +774,16 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
// make this instantiation looks like specialization which help to find
// full specialization for this instantiation
nonConstTemplId->setIsSpecialization(true);
TemplateNameIdTable::const_iterator cit = reference->_specializations.find(templId);
if (cit != reference->_specializations.end()) {
const TemplateNameIdTable &specializations = reference->_specializations;
TemplateNameIdTable::const_iterator cit = specializations.find(templId);
if (cit != specializations.end()) {
// we found full specialization
reference = cit->second;
} else {
ClassOrNamespace *specializationWithPointer
= findSpecializationWithPointer(templId, specializations);
if (specializationWithPointer)
reference = specializationWithPointer;
// TODO: find the best specialization(probably partial) for this instantiation
}
// let's instantiation be instantiation
......
......@@ -69,6 +69,9 @@ public:
ClassOrNamespace *findType(const Name *name);
private:
typedef std::map<const Name *, ClassOrNamespace *, Name::Compare> Table;
typedef std::map<const TemplateNameId *, ClassOrNamespace *, TemplateNameId::Compare> TemplateNameIdTable;
/// \internal
void flush();
......@@ -98,10 +101,8 @@ private:
Subst &subst,
ClassOrNamespace *enclosingTemplateClassInstantiation);
bool isInstantiateNestedClassNeeded(const QList<Symbol *>& symbols, const Subst &subst) const;
private:
typedef std::map<const Name *, ClassOrNamespace *, Name::Compare> Table;
typedef std::map<const TemplateNameId *, ClassOrNamespace *, TemplateNameId::Compare> TemplateNameIdTable;
ClassOrNamespace *findSpecializationWithPointer(const TemplateNameId *templId,
const TemplateNameIdTable &specializations);
CreateBindings *_factory;
ClassOrNamespace *_parent;
......
......@@ -1613,3 +1613,36 @@ void CppToolsPlugin::test_completion_resolve_complex_typedef_with_template()
QVERIFY(completions.contains(QLatin1String("bar")));
QVERIFY(completions.contains(QLatin1String("Template1")));
}
void CppToolsPlugin::test_completion_template_specialization_with_pointer()
{
TestData data;
data.srcText = "\n"
"template <typename T>\n"
"struct Template\n"
"{\n"
" T variable;\n"
"};\n"
"template <typename T>\n"
"struct Template<T *>\n"
"{\n"
" T *pointer;\n"
"};\n"
"Template<int*> templ;\n"
"@\n"
;
setup(&data);
Utils::ChangeSet change;
QString txt = QLatin1String("templ.");
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("Template")));
QVERIFY(completions.contains(QLatin1String("pointer")));
}
......@@ -123,6 +123,7 @@ private slots:
void test_completion_typedef_of_pointer_inside_function();
void test_completion_typedef_is_inside_function_before_declaration_block();
void test_completion_resolve_complex_typedef_with_template();
void test_completion_template_specialization_with_pointer();
void test_format_pointerdeclaration_in_simpledeclarations();
void test_format_pointerdeclaration_in_simpledeclarations_data();
......
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