test: added missing template parameter tests

* Added tests for parameter parsing of template functions.
* Added missing tests for template parameters and arguments.
* Fixed warning when using the "typename" keyword in combination with template template arguments.
* Added code to handle template template default arguments and implemented test case.
This commit is contained in:
malte_langkabel
2015-03-11 15:50:07 +01:00
parent d6ad7614af
commit 0e0553c90b
3 changed files with 353 additions and 57 deletions
+40 -2
View File
@@ -293,6 +293,21 @@ bool ASTVisitor::VisitTemplateTypeParmDecl(clang::TemplateTypeParmDecl *declarat
return true;
}
bool ASTVisitor::VisitTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl *declaration)
{
if (isLocatedInUnparsedProjectFile(declaration) && declaration->hasDefaultArgument())
{
const clang::TemplateArgumentLoc& defaultArgumentLoc = declaration->getDefaultArgument();
clang::SourceRange sr = defaultArgumentLoc.getSourceRange();
DataType defaultArgumentDataType(utility::getDeclNameHierarchy(defaultArgumentLoc.getArgument().getAsTemplate().getAsTemplateDecl()));
m_client->onTemplateDefaultArgumentTypeParsed(
getParseTypeUsage(sr, defaultArgumentDataType),
utility::getDeclNameHierarchy(declaration)
);
}
return true;
}
bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration)
{
std::vector<std::string> rarchy = utility::getDeclNameHierarchy(declaration);
@@ -777,9 +792,14 @@ ParseLocation ASTVisitor::getParseLocationOfRecordBody(clang::CXXRecordDecl* dec
return ParseLocation();
}
ParseTypeUsage ASTVisitor::getParseTypeUsage(clang::TypeLoc typeLoc, const clang::QualType& type) const
ParseTypeUsage ASTVisitor::getParseTypeUsage(const clang::TypeLoc& typeLoc, const clang::QualType& type) const
{
DataType dataType = utility::qualTypeToDataType(type);
return getParseTypeUsage(typeLoc, dataType);
}
ParseTypeUsage ASTVisitor::getParseTypeUsage(const clang::TypeLoc& typeLoc, const DataType& type) const
{
ParseLocation parseLocation;
if (!typeLoc.isNull())
@@ -793,7 +813,25 @@ ParseTypeUsage ASTVisitor::getParseTypeUsage(clang::TypeLoc typeLoc, const clang
parseLocation.endColumnNumber -= 1;
}
return ParseTypeUsage(parseLocation, dataType);
return ParseTypeUsage(parseLocation, type);
}
ParseTypeUsage ASTVisitor::getParseTypeUsage(const clang::SourceRange& sourceRange, const DataType& type) const
{
ParseLocation parseLocation;
if (sourceRange.isValid())
{
clang::SourceRange sr(
sourceRange.getBegin(),
clang::Lexer::getLocForEndOfToken(sourceRange.getEnd(), 0, m_context->getSourceManager(), clang::LangOptions())
);
parseLocation = getParseLocation(sr);
parseLocation.endColumnNumber -= 1;
}
return ParseTypeUsage(parseLocation, type);
}
ParseTypeUsage ASTVisitor::getParseTypeUsageOfReturnType(const clang::FunctionDecl* declaration) const
+4 -1
View File
@@ -39,6 +39,7 @@ public:
virtual bool VisitEnumConstantDecl(clang::EnumConstantDecl* declaration); // enum fields
virtual bool VisitTemplateTypeParmDecl(clang::TemplateTypeParmDecl *declaration);
virtual bool VisitTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl *declaration);
virtual bool VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration);
virtual bool VisitClassTemplatePartialSpecializationDecl(clang::ClassTemplatePartialSpecializationDecl* declaration);
virtual bool VisitFunctionTemplateDecl(clang::FunctionTemplateDecl *declaration);
@@ -69,7 +70,9 @@ private:
ParseLocation getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const;
ParseLocation getParseLocationOfRecordBody(clang::CXXRecordDecl* decl) const;
ParseTypeUsage getParseTypeUsage(clang::TypeLoc typeLoc, const clang::QualType& type) const;
ParseTypeUsage getParseTypeUsage(const clang::TypeLoc& typeLoc, const clang::QualType& type) const;
ParseTypeUsage getParseTypeUsage(const clang::TypeLoc& typeLoc, const DataType& type) const;
ParseTypeUsage getParseTypeUsage(const clang::SourceRange& sourceRange, const DataType& type) const;
ParseTypeUsage getParseTypeUsageOfReturnType(const clang::FunctionDecl* declaration) const;
std::vector<ParseTypeUsage> getParameters(const clang::FunctionDecl* declaration) const;
+309 -54
View File
@@ -1252,13 +1252,54 @@ public:
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<bool T>::T <1:16 1:16>");
}
void test_cxx_parser_finds_non_type_custom_pointer_template_parameter_of_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"class P\n"
"{};\n"
"template <P* p>\n"
"class A\n"
"{};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<P * p>::p <3:14 3:14>");
}
void test_cxx_parser_finds_non_type_custom_reference_template_parameter_of_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"class P\n"
"{};\n"
"template <P& p>\n"
"class A\n"
"{};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<P & p>::p <3:14 3:14>");
}
void test_cxx_parser_finds_non_type_nullptr_template_parameter_of_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"#include <cstddef>\n"
"template <std::nullptr_t T>\n"
"class A\n"
"{};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<std::nullptr_t T>::T <2:26 2:26>");
}
void test_cxx_parser_finds_template_template_parameter_of_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{};\n"
"template <template<typename> typename T>\n"
"template <template<typename> class T>\n"
"class B\n"
"{};\n"
"int main()\n"
@@ -1269,7 +1310,7 @@ public:
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 2);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<typename T>::T <1:20 1:20>");
TS_ASSERT_EQUALS(client->templateParameterTypes[1], "B<template<typename> typename T>::T <4:39 4:39>");
TS_ASSERT_EQUALS(client->templateParameterTypes[1], "B<template<typename> typename T>::T <4:36 4:36>");
}
void test_cxx_parser_finds_type_template_parameters_of_template_class_with_multiple_parameters()
@@ -1299,7 +1340,7 @@ public:
TS_ASSERT_EQUALS(client->classes[0], "A<typename> <2:1 <2:7 2:7> 4:1>");
}
void test_cxx_parser_finds_template_parameter_of_template_method_definition_outside_template_class()
void test_cxx_parser_finds_type_template_parameter_of_template_method_definition_outside_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
@@ -1429,7 +1470,7 @@ public:
"template <typename T>\n"
"class A\n"
"{};\n"
"template <template<typename> typename T>\n"
"template <template<typename> class T>\n"
"class B\n"
"{};\n"
"int main()\n"
@@ -1506,13 +1547,66 @@ public:
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<true>->bool <0:0 0:0>");
}
void test_cxx_parser_finds_non_type_custom_pointer_template_argument_of_explicit_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"class P\n"
"{};\n"
"template <P* p>\n"
"class A\n"
"{};\n"
"P p;\n"
"template <>\n"
"class A<&p>\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<&p>->P <0:0 0:0>");
}
void test_cxx_parser_finds_non_type_custom_reference_template_argument_of_explicit_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"class P\n"
"{};\n"
"template <P& p>\n"
"class A\n"
"{};\n"
"P p;\n"
"template <>\n"
"class A<p>\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<&p>->P <0:0 0:0>");
}
void test_cxx_parser_finds_non_type_nullptr_template_argument_of_explicit_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"#include <cstddef>\n"
"template <std::nullptr_t T>\n"
"class A\n"
"{};\n"
"template <>\n"
"class A<nullptr>\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<nullptr>->nullptr_t <0:0 0:0>");
}
void test_cxx_parser_finds_template_template_argument_of_explicit_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{};\n"
"template <template<typename> typename T>\n"
"template <template<typename> class T>\n"
"class B\n"
"{};\n"
"template <>\n"
@@ -1538,7 +1632,7 @@ public:
"};\n"
);
TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1);
// TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A<typename T, int> -> A<typename T, typename U> <6:7 6:7>");
TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A<typename T, int> -> A<typename T, typename U> <6:7 6:7>");
}
void test_cxx_parser_finds_type_template_argument_of_explicit_partial_template_specialization()
@@ -1558,40 +1652,118 @@ public:
TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<typename T, int>->int <6:12 6:12>");
}
void test_cxx_parser_finds_specialized_non_type_bool_template_argument_of_explicit_partial_template_specialization()
void test_cxx_parser_finds_non_type_int_template_argument_of_explicit_partial_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <bool T, typename U>\n"
"template <int T, int U>\n"
"class A\n"
"{\n"
"};\n"
"template <typename U>\n"
"template <int U>\n"
"class A<3, U>\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<3, int U>->int <6:9 6:9>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<3, int U>->int <6:12 6:12>");
}
void test_cxx_parser_finds_non_type_bool_template_argument_of_explicit_partial_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <bool T, bool U>\n"
"class A\n"
"{\n"
"};\n"
"template <bool U>\n"
"class A<true, U>\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<true, typename U>->bool <6:9 6:9>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<true, typename U>->A<true, typename U>::U <6:15 6:15>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<true, bool U>->bool <6:9 6:9>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<true, bool U>->bool <6:15 6:15>");
}
void test_cxx_parser_finds_unspecialized_non_type_bool_template_argument_of_explicit_partial_template_specialization()
void test_cxx_parser_finds_non_type_custom_pointer_template_argument_of_explicit_partial_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <bool T, typename U>\n"
"class P\n"
"{};\n"
"template <P* p, P* q>\n"
"class A\n"
"{\n"
"};\n"
"template <bool T>\n"
"class A<T, int>\n"
"{};\n"
"P p;\n"
"template <P* q>\n"
"class A<&p, q>\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<bool T, int>->bool <6:9 6:9>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<bool T, int>->int <6:12 6:12>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<&p, P * q>->P <8:9 8:10>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<&p, P * q>->P <8:13 8:13>");
}
void test_cxx_parser_finds_non_type_custom_reference_template_argument_of_explicit_partial_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"class P\n"
"{};\n"
"template <P& p, P& q>\n"
"class A\n"
"{};\n"
"P p;\n"
"template <P& q>\n"
"class A<p, q>\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<p, P & q>->P <8:9 8:9>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<p, P & q>->P <8:12 8:12>");
}
void test_cxx_parser_finds_non_type_nullptr_template_argument_of_explicit_partial_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"#include <cstddef>\n"
"template <std::nullptr_t T, std::nullptr_t U>\n"
"class A\n"
"{};\n"
"template <std::nullptr_t U>\n"
"class A<nullptr, U>\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<nullptr, std::nullptr_t U>->nullptr_t <6:9 6:9>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<nullptr, std::nullptr_t U>->std::nullptr_t <6:18 6:18>");
}
void test_cxx_parser_finds_template_template_argument_of_explicit_partial_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{};\n"
"template <template<typename> class T, template<typename> class U>\n"
"class B\n"
"{};\n"
"template <template<typename> class U>\n"
"class B<A, U>\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2);
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B<A, template<typename> typename U>->A<typename T> <8:9 8:9>");
TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "B<A, template<typename> typename U>->B<A, template<typename> typename U>::U <8:12 8:12>");
}
void test_cxx_parser_finds_correct_name_of_explicit_template_specialization()
@@ -1611,22 +1783,6 @@ public:
TS_ASSERT_EQUALS(client->classes[1], "A<typename T, int> <5:1 <6:7 6:7> 8:1>");
}
void test_cxx_parser_finds_argument_of_explicit_template_specialization()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{\n"
"};\n"
"template <>\n"
"class A<int>\n"
"{\n"
"};\n"
);
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_correct_field_member_name_of_template_class_in_declaration()
{
std::shared_ptr<TestParserClient> client = parseCode(
@@ -1839,7 +1995,7 @@ public:
TS_ASSERT_EQUALS(client->methods[0], "private A<typename T>::T A<typename T>::foo() <4:4 4:6>");
}
void test_cxx_parser_finds_template_default_argument_type_of_template_class()
void test_cxx_parser_finds_type_template_default_argument_type_of_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T = int>\n"
@@ -1852,30 +2008,36 @@ public:
TS_ASSERT_EQUALS(client->templateDefaultArgumentTypes[0], "int -> A<typename T>::T <1:24 1:26>");
}
void test_cxx_parser_does_not_find_default_argument_type_for_non_type_bool_template_parameter_of_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <bool T = true>\n"
"class A\n"
"{\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateDefaultArgumentTypes.size(), 0);
}
//void ___test_cxx_parser_skips_creating_node_for_explicit_template_specialization_with_template_parameter_without_a_name() // i think this would not be valid code...
//{
// std::shared_ptr<TestParserClient> client = parseCode(
// "template <typename T>\n"
// "class A\n"
// "{\n"
// "};\n"
// "template <typename>\n"
// "class A<int>\n"
// "{\n"
// "};\n"
// );
void test_cxx_parser_finds_template_template_default_argument_type_of_template_class()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{};\n"
"template <template<typename> class T = A>\n"
"class B\n"
"{};\n"
);
// TS_ASSERT_EQUALS(client->classes.size(), 1);
// TS_ASSERT_EQUALS(client->classes[0], "A<typename> <2:1 <2:7 2:7> 4:1>");
//}
TS_ASSERT_EQUALS(client->templateDefaultArgumentTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateDefaultArgumentTypes[0], "A<typename T> -> B<template<typename> typename T>::T <4:40 4:40>");
}
void test_cxx_parser_finds_template_parameter_type_of_template_function()
void test_cxx_parser_finds_type_template_parameter_of_template_function()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
@@ -1889,6 +2051,99 @@ public:
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "test<typename T>::T <1:20 1:20>");
}
void test_cxx_parser_finds_non_type_int_template_parameter_of_template_function()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <int T>\n"
"int test(int a)\n"
"{\n"
" return a + T;\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "test<int T>::T <1:15 1:15>");
}
void test_cxx_parser_finds_non_type_bool_template_parameter_of_template_function()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <bool T>\n"
"int test(int a)\n"
"{\n"
" return T ? a : 0;\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "test<bool T>::T <1:16 1:16>");
}
void test_cxx_parser_finds_non_type_custom_pointer_template_parameter_of_template_function()
{
std::shared_ptr<TestParserClient> client = parseCode(
"class P\n"
"{};\n"
"template <P* p>\n"
"int test(int a)\n"
"{\n"
" return a;\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "test<P * p>::p <3:14 3:14>");
}
void test_cxx_parser_finds_non_type_custom_reference_template_parameter_of_template_function()
{
std::shared_ptr<TestParserClient> client = parseCode(
"class P\n"
"{};\n"
"template <P& p>\n"
"int test(int a)\n"
"{\n"
" return a;\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "test<P & p>::p <3:14 3:14>");
}
void test_cxx_parser_finds_non_type_nullptr_template_parameter_of_template_function()
{
std::shared_ptr<TestParserClient> client = parseCode(
"#include <cstddef>\n"
"template <std::nullptr_t T>\n"
"int test(int a)\n"
"{\n"
" return a;\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "test<std::nullptr_t T>::T <2:26 2:26>");
}
void test_cxx_parser_finds_template_template_parameter_of_template_function()
{
std::shared_ptr<TestParserClient> client = parseCode(
"template <typename T>\n"
"class A\n"
"{};\n"
"template <template<typename> class T>\n"
"int test(int a)\n"
"{\n"
" return a;\n"
"};\n"
);
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 2);
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<typename T>::T <1:20 1:20>");
TS_ASSERT_EQUALS(client->templateParameterTypes[1], "test<template<typename> typename T>::T <4:36 4:36>");
}
void test_cxx_parser_finds_implicit_specialization_of_template_function()
{
std::shared_ptr<TestParserClient> client = parseCode(