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:
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user