logic: Template Parameter Packs

* implemented handling of template parameter packs.
* added tests for these cases.
* refactored some areas of the template code.
* fixed the names of template arguments that get parsed when they occur in a function's/declarator's body.
This commit is contained in:
malte_langkabel
2015-11-25 15:43:59 +01:00
parent f29a966504
commit 622972cd28
7 changed files with 165 additions and 26 deletions
+3 -3
View File
@@ -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<DataType> argumentType = resolver.getTemplateArgumentType(templateSpecializationType->getArg(i));
std::shared_ptr<DataType> 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<DataType> argumentType = resolver.getTemplateArgumentType(argumentList->get(i));
std::shared_ptr<DataType> argumentType = utility::templateArgumentToDataType(argumentList->get(i));
if (argumentType->getFullTypeName().size() > 0)
{
m_client->onTypeUsageParsed(getParseTypeUsage(sourceRange, argumentType), t);
@@ -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;
}
@@ -22,11 +22,6 @@ CxxTemplateArgumentNameResolver::~CxxTemplateArgumentNameResolver()
}
std::string CxxTemplateArgumentNameResolver::getTemplateArgumentName(const clang::TemplateArgument& argument)
{
return getTemplateArgumentType(argument)->getFullTypeName();
}
std::shared_ptr<DataType> CxxTemplateArgumentNameResolver::getTemplateArgumentType(const clang::TemplateArgument& argument)
{
const clang::TemplateArgument::ArgKind kind = argument.getKind();
switch (kind)
@@ -34,14 +29,14 @@ std::shared_ptr<DataType> 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<DataType> CxxTemplateArgumentNameResolver::getTemplateArgumentTy
argument.print(pp, os);
const std::string typeName = os.str();
NameHierarchy typeNameHerarchy;
typeNameHerarchy.push(std::make_shared<NameElement>(typeName));
return std::make_shared<NamedDataType>(typeNameHerarchy);
return typeName;
}
case clang::TemplateArgument::Pack:
LOG_INFO("Type of template argument not handled: Pack");
break;
{
std::string typeName = "<";
argument.getPackAsArray();
llvm::ArrayRef<clang::TemplateArgument> 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<NameElement>(""));
return std::make_shared<NamedDataType>(typeNameHerarchy);
return "";
}
@@ -15,7 +15,6 @@ public:
~CxxTemplateArgumentNameResolver();
std::string getTemplateArgumentName(const clang::TemplateArgument& argument);
std::shared_ptr<DataType> getTemplateArgumentType(const clang::TemplateArgument& argument);
};
#endif // CXX_TEMPLATE_ARGUMENT_NAME_RESOLVER_H
@@ -138,7 +138,7 @@ std::shared_ptr<DataType> 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<ajaj<ajsj>>
declName = declName.substr(0, declName.rfind("<")); // remove template parameters - TODO: FIX: does not work for A<ajaj<ajsj>>
declName += templateArgumentNamePart; // add template arguments
typeNameHerarchy.pop();
typeNameHerarchy.push(std::make_shared<NameElement>(declName));
@@ -166,12 +166,18 @@ std::shared_ptr<DataType> CxxTypeNameResolver::typeToDataType(const clang::Type*
{
const clang::DependentNameType* dependentNameType = clang::dyn_cast<clang::DependentNameType>(type);
NameHierarchy typeNameHerarchy = getNameHierarchy( dependentNameType->getQualifier());
NameHierarchy typeNameHerarchy = getNameHierarchy(dependentNameType->getQualifier());
typeNameHerarchy.push(std::make_shared<NameElement>(dependentNameType->getIdentifier()->getName().str()));
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
break;
}
case clang::Type::PackExpansion:
{
const clang::PackExpansionType* packExpansionType = clang::dyn_cast<clang::PackExpansionType>(type);
dataType = qualTypeToDataType(packExpansionType->getPattern());
break;
}
default:
{
LOG_INFO(std::string("Unhandled kind of type encountered: ") + type->getTypeClassName());
+18 -1
View File
@@ -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<clang::TemplateArgument> 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<NameElement>(typeName));
return std::make_shared<NamedDataType>(typeNameHerarchy);
}
break;
}
return std::make_shared<NamedDataType>(NameHierarchy());
+94 -1
View File
@@ -1263,6 +1263,19 @@ public:
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<class T>::T <1:17 1:17>");
}
void test_cxx_parser_finds_type_template_parameter_pack_type_of_template_class()
{
std::shared_ptr<TestParserClient> 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:23 1:23>");
}
void test_cxx_parser_finds_non_type_int_template_parameter_of_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
@@ -1356,6 +1369,19 @@ public:
TS_ASSERT_EQUALS(client->templateParameterTypes[1], "A<template<typename> typename T1, T1<int> & T2>::T2 <1:49 1:50>");
}
void test_cxx_parser_finds_non_type_int_template_parameter_pack_type_of_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <int... T>\n"
"class A\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<int... T>::T <1:18 1:18>");
}
void test_cxx_parser_finds_template_template_parameter_of_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
@@ -1376,6 +1402,19 @@ public:
TS_ASSERT_EQUALS(client->templateParameterTypes[1], "B<template<typename> typename T>::T<typename> <4:36 4:36>");
}
void test_cxx_parser_finds_template_template_parameter_pack_type_of_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <template<typename> typename... T>\n"
"class A\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<template<typename> typename... T>::T<typename> <1:42 1:42>");
}
void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_specialized_with_concrete_type()
{
std::shared_ptr<TestParserClient> client = parseCode(
@@ -1502,6 +1541,22 @@ public:
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<int>->int <0:0 0:0>");
}
void test_cxx_parser_finds_type_template_argument_for_parameter_pack_of_implicit_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename... T>\n"
"class A\n"
"{\n"
"};\n"
"int main()\n"
"{\n"
" A<int, float>();\n"
"}\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<<int, float>>-><int, float> <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>->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<TestParserClient> client = parseCode(
"template <int... T>\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>>-><int, int, int> <0:0 0:0>");
}
void test_cxx_parser_finds_template_template_argument_of_implicit_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
@@ -1609,7 +1681,28 @@ public:
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B<A>->A<typename T> <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<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
"};\n"
"template <template<typename> typename... T>\n"
"class B\n"
"{\n"
"};\n"
"int main()\n"
"{\n"
" B<A, A>();\n"
"}\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B<<A, A>>-><A<typename T>, A<typename T>> <0:0 0:0>");
}
void test_cxx_parser_finds_template_member_specialization_of_implicit_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"