From ea32191542ad0d2f9f02ad77ad38f94b5152e04e Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Tue, 19 Feb 2013 08:44:44 +0100 Subject: [PATCH] C++: fix instantiation of template special. with pointer argument Fixed code completion for instantiation of template specialization with argument as pointer, e.g.: template struct Template { T variable; }; template struct Template { T *pointer; }; Template templ; templ.pointer; Change-Id: I7c79fe0cd7119b1208f064aece0cafdf50e1a012 Reviewed-by: Erik Verbruggen --- src/libs/cplusplus/LookupContext.cpp | 43 ++++++++++++++++++++- src/libs/cplusplus/LookupContext.h | 9 +++-- src/plugins/cpptools/cppcompletion_test.cpp | 33 ++++++++++++++++ src/plugins/cpptools/cpptoolsplugin.h | 1 + 4 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 68586bff8bd..c20e85459ee 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -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 diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index 70dafc03b57..87efcefbb70 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -69,6 +69,9 @@ public: ClassOrNamespace *findType(const Name *name); private: + typedef std::map Table; + typedef std::map TemplateNameIdTable; + /// \internal void flush(); @@ -98,10 +101,8 @@ private: Subst &subst, ClassOrNamespace *enclosingTemplateClassInstantiation); bool isInstantiateNestedClassNeeded(const QList& symbols, const Subst &subst) const; - -private: - typedef std::map Table; - typedef std::map TemplateNameIdTable; + ClassOrNamespace *findSpecializationWithPointer(const TemplateNameId *templId, + const TemplateNameIdTable &specializations); CreateBindings *_factory; ClassOrNamespace *_parent; diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index fb61faec0db..34ea48fee28 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -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 \n" + "struct Template\n" + "{\n" + " T variable;\n" + "};\n" + "template \n" + "struct Template\n" + "{\n" + " T *pointer;\n" + "};\n" + "Template 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"))); +} diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index e7eae03882a..fd9f18b7e8c 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -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();