From 97d3d9ac0946f3be0e036b70401352e3ddaeb8fc Mon Sep 17 00:00:00 2001 From: Orgad Shaneh <orgad.shaneh@audiocodes.com> Date: Sun, 7 Jun 2015 11:47:50 +0300 Subject: [PATCH] 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> --- src/libs/cplusplus/LookupContext.cpp | 94 ++++++++++++--------- src/libs/cplusplus/LookupContext.h | 7 +- src/plugins/cpptools/cppcompletion_test.cpp | 13 +++ 3 files changed, 74 insertions(+), 40 deletions(-) diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 031afb4004b..38093f8b47b 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -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 diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index f68ff829057..0308388a3d5 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -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; diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index 563a6b9a1ce..3bf0904c652 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -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" -- GitLab