diff --git a/src/lib/data/parser/cxx/ASTVisitor.cpp b/src/lib/data/parser/cxx/ASTVisitor.cpp index 63b51134..1414a438 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -333,7 +333,7 @@ bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration) ) { clang::ClassTemplateSpecializationDecl* specializationDecl = *it; - NameHierarchy specializationNameHierarchy = utility::getDeclNameHierarchy(specializationDecl); // TODO: rename this! to specialization.. + NameHierarchy specializationNameHierarchy = utility::getDeclNameHierarchy(specializationDecl); ParseLocation specializationLocation = getParseLocationForNamedDecl(specializationDecl); if (specializationDecl->getSpecializationKind() == clang::TSK_ImplicitInstantiation) @@ -1119,7 +1119,7 @@ void ASTVisitor::saveClassTemplateArgumentTypeUsages(const clang::TypeSourceInfo for (size_t i = 0; i < templateSpecializationType->getNumArgs(); i++) { CxxTemplateArgumentNameResolver resolver; - std::shared_ptr argumentType = resolver.getTemplateArgumentType(templateSpecializationType->getArg(i)); + std::shared_ptr argumentType = utility::templateArgumentToDataType(templateSpecializationType->getArg(i)); if (argumentType->getFullTypeName().size() > 0) { m_client->onTypeUsageParsed(getParseTypeUsage(typeInfo->getTypeLoc(), argumentType), t); @@ -1141,7 +1141,7 @@ void ASTVisitor::saveFunctionTemplateArgumentTypeUsages( for (size_t i = 0; i < argumentList->size(); i++) { CxxTemplateArgumentNameResolver resolver; - std::shared_ptr argumentType = resolver.getTemplateArgumentType(argumentList->get(i)); + std::shared_ptr argumentType = utility::templateArgumentToDataType(argumentList->get(i)); if (argumentType->getFullTypeName().size() > 0) { m_client->onTypeUsageParsed(getParseTypeUsage(sourceRange, argumentType), t); diff --git a/src/lib/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp b/src/lib/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp index fc7f6299..a31be410 100644 --- a/src/lib/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp +++ b/src/lib/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp @@ -108,7 +108,7 @@ std::string CxxDeclNameResolver::getDeclName() for (int i = 0; i < templateArgumentCount; i++) { const clang::TemplateArgument& templateArgument = templateArgumentList.get(i); - if (templateArgument.isDependent()) // IMPORTANT_TODO: fix case when arg depends on template parameter of outer template class, or depends on first template parameter. + if (templateArgument.isDependent()) // IMPORTANT_TODO: fix case when arg depends on template parameter of outer template class, or depends on first template parameter. { if(currentParameterIndex < parameterList->size()) { @@ -239,12 +239,25 @@ std::string CxxDeclNameResolver::getTemplateParameterTypeString(const clang::Non { typeNameResolver.ignoreContextDecl(m_declaration); } - return typeNameResolver.qualTypeToDataType(parameter->getType())->getFullTypeName(); + + std::string typeString = typeNameResolver.qualTypeToDataType(parameter->getType())->getFullTypeName(); + + if (parameter->isTemplateParameterPack()) + { + typeString += "..."; + } + + return typeString; } std::string CxxDeclNameResolver::getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter) { - return (parameter->wasDeclaredWithTypename() ? "typename" : "class"); + std::string typeString = (parameter->wasDeclaredWithTypename() ? "typename" : "class"); + if (parameter->isTemplateParameterPack()) + { + typeString += "..."; + } + return typeString; } std::string CxxDeclNameResolver::getTemplateParameterTypeString(const clang::TemplateTemplateParmDecl* parameter) @@ -258,6 +271,12 @@ std::string CxxDeclNameResolver::getTemplateParameterTypeString(const clang::Tem } templateParameterTypeString += ">"; templateParameterTypeString += " typename"; // TODO: what if template template parameter is defined with class keyword? + + if (parameter->isTemplateParameterPack()) + { + templateParameterTypeString += "..."; + } + return templateParameterTypeString; } diff --git a/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp b/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp index de5e2c1b..2aa45246 100644 --- a/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp +++ b/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp @@ -22,11 +22,6 @@ CxxTemplateArgumentNameResolver::~CxxTemplateArgumentNameResolver() } std::string CxxTemplateArgumentNameResolver::getTemplateArgumentName(const clang::TemplateArgument& argument) -{ - return getTemplateArgumentType(argument)->getFullTypeName(); -} - -std::shared_ptr CxxTemplateArgumentNameResolver::getTemplateArgumentType(const clang::TemplateArgument& argument) { const clang::TemplateArgument::ArgKind kind = argument.getKind(); switch (kind) @@ -34,14 +29,14 @@ std::shared_ptr CxxTemplateArgumentNameResolver::getTemplateArgumentTy case clang::TemplateArgument::Type: { CxxTypeNameResolver typeNameResolver(getIgnoredContextDecls()); - return typeNameResolver.qualTypeToDataType(argument.getAsType()); + return typeNameResolver.qualTypeToDataType(argument.getAsType())->getFullTypeName(); } case clang::TemplateArgument::Integral: case clang::TemplateArgument::Null: case clang::TemplateArgument::Declaration: case clang::TemplateArgument::NullPtr: case clang::TemplateArgument::Template: - case clang::TemplateArgument::TemplateExpansion: + case clang::TemplateArgument::TemplateExpansion: // handled correctly? template template parameter... case clang::TemplateArgument::Expression: { clang::PrintingPolicy pp = clang::PrintingPolicy(clang::LangOptions()); @@ -53,16 +48,26 @@ std::shared_ptr CxxTemplateArgumentNameResolver::getTemplateArgumentTy argument.print(pp, os); const std::string typeName = os.str(); - NameHierarchy typeNameHerarchy; - typeNameHerarchy.push(std::make_shared(typeName)); - return std::make_shared(typeNameHerarchy); + return typeName; } case clang::TemplateArgument::Pack: - LOG_INFO("Type of template argument not handled: Pack"); - break; + { + std::string typeName = "<"; + argument.getPackAsArray(); + llvm::ArrayRef pack = argument.getPackAsArray(); + for (size_t i = 0; i < pack.size(); i++) + { + typeName += getTemplateArgumentName(pack[i]); + if (i < pack.size() - 1) + { + typeName += ", "; + } + } + typeName += ">"; + + return typeName; + } } - NameHierarchy typeNameHerarchy; - typeNameHerarchy.push(std::make_shared("")); - return std::make_shared(typeNameHerarchy); + return ""; } diff --git a/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h b/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h index c0b4d5ac..e6b0024a 100644 --- a/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h +++ b/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h @@ -15,7 +15,6 @@ public: ~CxxTemplateArgumentNameResolver(); std::string getTemplateArgumentName(const clang::TemplateArgument& argument); - std::shared_ptr getTemplateArgumentType(const clang::TemplateArgument& argument); }; #endif // CXX_TEMPLATE_ARGUMENT_NAME_RESOLVER_H diff --git a/src/lib/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp b/src/lib/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp index 93ccdb05..a78e2275 100644 --- a/src/lib/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp +++ b/src/lib/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp @@ -138,7 +138,7 @@ std::shared_ptr CxxTypeNameResolver::typeToDataType(const clang::Type* templateArgumentNamePart += ">"; std::string declName = typeNameHerarchy.back()->getFullName(); - declName = declName.substr(0, declName.rfind("<")); // remove template parameters - does not work for A> + declName = declName.substr(0, declName.rfind("<")); // remove template parameters - TODO: FIX: does not work for A> declName += templateArgumentNamePart; // add template arguments typeNameHerarchy.pop(); typeNameHerarchy.push(std::make_shared(declName)); @@ -166,12 +166,18 @@ std::shared_ptr CxxTypeNameResolver::typeToDataType(const clang::Type* { const clang::DependentNameType* dependentNameType = clang::dyn_cast(type); - NameHierarchy typeNameHerarchy = getNameHierarchy( dependentNameType->getQualifier()); + NameHierarchy typeNameHerarchy = getNameHierarchy(dependentNameType->getQualifier()); typeNameHerarchy.push(std::make_shared(dependentNameType->getIdentifier()->getName().str())); dataType = std::make_shared(typeNameHerarchy); break; } + case clang::Type::PackExpansion: + { + const clang::PackExpansionType* packExpansionType = clang::dyn_cast(type); + dataType = qualTypeToDataType(packExpansionType->getPattern()); + break; + } default: { LOG_INFO(std::string("Unhandled kind of type encountered: ") + type->getTypeClassName()); diff --git a/src/lib/data/parser/cxx/utilityCxx.cpp b/src/lib/data/parser/cxx/utilityCxx.cpp index 5f286de6..99fa9a2f 100644 --- a/src/lib/data/parser/cxx/utilityCxx.cpp +++ b/src/lib/data/parser/cxx/utilityCxx.cpp @@ -72,7 +72,24 @@ namespace utility case clang::TemplateArgument::Expression: return utility::qualTypeToDataType(argument.getAsExpr()->getType()); case clang::TemplateArgument::Pack: - LOG_ERROR("Type of template argument not handled: Pack"); + { + std::string typeName = "<"; + argument.getPackAsArray(); + llvm::ArrayRef pack = argument.getPackAsArray(); + for (size_t i = 0; i < pack.size(); i++) + { + typeName += templateArgumentToDataType(pack[i])->getFullTypeName(); + if (i < pack.size() - 1) + { + typeName += ", "; + } + } + typeName += ">"; + + NameHierarchy typeNameHerarchy; + typeNameHerarchy.push(std::make_shared(typeName)); + return std::make_shared(typeNameHerarchy); + } break; } return std::make_shared(NameHierarchy()); diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index d4086a9d..84cc3088 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -1263,6 +1263,19 @@ public: TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A::T <1:17 1:17>"); } + void test_cxx_parser_finds_type_template_parameter_pack_type_of_template_class() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A::T <1:23 1:23>"); + } + void test_cxx_parser_finds_non_type_int_template_parameter_of_template_class() { std::shared_ptr client = parseCode( @@ -1356,6 +1369,19 @@ public: TS_ASSERT_EQUALS(client->templateParameterTypes[1], "A typename T1, T1 & T2>::T2 <1:49 1:50>"); } + void test_cxx_parser_finds_non_type_int_template_parameter_pack_type_of_template_class() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A::T <1:18 1:18>"); + } + void test_cxx_parser_finds_template_template_parameter_of_template_class() { std::shared_ptr client = parseCode( @@ -1376,6 +1402,19 @@ public: TS_ASSERT_EQUALS(client->templateParameterTypes[1], "B typename T>::T <4:36 4:36>"); } + void test_cxx_parser_finds_template_template_parameter_pack_type_of_template_class() + { + std::shared_ptr client = parseCode( + "template typename... T>\n" + "class A\n" + "{\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A typename... T>::T <1:42 1:42>"); + } + void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_specialized_with_concrete_type() { std::shared_ptr client = parseCode( @@ -1502,6 +1541,22 @@ public: TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->int <0:0 0:0>"); } + void test_cxx_parser_finds_type_template_argument_for_parameter_pack_of_implicit_template_specialization() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + "};\n" + "int main()\n" + "{\n" + " A();\n" + "}\n" + ); + + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<>-> <0:0 0:0>"); + } void test_cxx_parser_finds_non_type_int_template_argument_of_implicit_template_specialization() { @@ -1590,6 +1645,23 @@ public: TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->nullptr_t <0:0 0:0>"); } + void test_cxx_parser_finds_non_type_int_template_argument_for_parameter_pack_of_implicit_template_specialization() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + "};\n" + "int main()\n" + "{\n" + " A<1, 2, 3>();\n" + "}\n" + ); + + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<<1, 2, 3>>-> <0:0 0:0>"); + } + void test_cxx_parser_finds_template_template_argument_of_implicit_template_specialization() { std::shared_ptr client = parseCode( @@ -1609,7 +1681,28 @@ public: TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B->A <0:0 0:0>"); } - void test_cxx_parser_finds__of_implicit_template_specialization() + void test_cxx_parser_finds_template_template_argument_for_parameter_pack_of_implicit_template_specialization() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + "};\n" + "template typename... T>\n" + "class B\n" + "{\n" + "};\n" + "int main()\n" + "{\n" + " B();\n" + "}\n" + ); + + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B<>->, A> <0:0 0:0>"); + } + + void test_cxx_parser_finds_template_member_specialization_of_implicit_template_specialization() { std::shared_ptr client = parseCode( "template \n"