From 0e0553c90b1db99e10771cf5f6c017771d45a2cc Mon Sep 17 00:00:00 2001 From: malte_langkabel Date: Wed, 11 Mar 2015 15:50:07 +0100 Subject: [PATCH] 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. --- src/lib/data/parser/cxx/ASTVisitor.cpp | 42 ++- src/lib/data/parser/cxx/ASTVisitor.h | 5 +- src/test/CxxParserTestSuite.h | 363 +++++++++++++++++++++---- 3 files changed, 353 insertions(+), 57 deletions(-) diff --git a/src/lib/data/parser/cxx/ASTVisitor.cpp b/src/lib/data/parser/cxx/ASTVisitor.cpp index 66f58a8a..2f9d0f4f 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -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 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 diff --git a/src/lib/data/parser/cxx/ASTVisitor.h b/src/lib/data/parser/cxx/ASTVisitor.h index 6ba11c0c..2eb3d746 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.h +++ b/src/lib/data/parser/cxx/ASTVisitor.h @@ -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 getParameters(const clang::FunctionDecl* declaration) const; diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index fd2f83ec..ccfe1fd4 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -1252,13 +1252,54 @@ public: TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A::T <1:16 1:16>"); } + void test_cxx_parser_finds_non_type_custom_pointer_template_parameter_of_template_class() + { + std::shared_ptr client = parseCode( + "class P\n" + "{};\n" + "template \n" + "class A\n" + "{};\n" + ); + + TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A

::p <3:14 3:14>"); + } + + void test_cxx_parser_finds_non_type_custom_reference_template_parameter_of_template_class() + { + std::shared_ptr client = parseCode( + "class P\n" + "{};\n" + "template \n" + "class A\n" + "{};\n" + ); + + TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A

::p <3:14 3:14>"); + } + + void test_cxx_parser_finds_non_type_nullptr_template_parameter_of_template_class() + { + std::shared_ptr client = parseCode( + "#include \n" + "template \n" + "class A\n" + "{};\n" + ); + + TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A::T <2:26 2:26>"); + } + void test_cxx_parser_finds_template_template_parameter_of_template_class() { std::shared_ptr client = parseCode( "template \n" "class A\n" "{};\n" - "template typename T>\n" + "template 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::T <1:20 1:20>"); - TS_ASSERT_EQUALS(client->templateParameterTypes[1], "B typename T>::T <4:39 4:39>"); + TS_ASSERT_EQUALS(client->templateParameterTypes[1], "B 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 <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 client = parseCode( "template \n" @@ -1429,7 +1470,7 @@ public: "template \n" "class A\n" "{};\n" - "template typename T>\n" + "template class T>\n" "class B\n" "{};\n" "int main()\n" @@ -1506,13 +1547,66 @@ public: TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->bool <0:0 0:0>"); } + void test_cxx_parser_finds_non_type_custom_pointer_template_argument_of_explicit_template_specialization() + { + std::shared_ptr client = parseCode( + "class P\n" + "{};\n" + "template \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 client = parseCode( + "class P\n" + "{};\n" + "template \n" + "class A\n" + "{};\n" + "P p;\n" + "template <>\n" + "class A

\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 client = parseCode( + "#include \n" + "template \n" + "class A\n" + "{};\n" + "template <>\n" + "class A\n" + "{\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->nullptr_t <0:0 0:0>"); + } + void test_cxx_parser_finds_template_template_argument_of_explicit_template_specialization() { std::shared_ptr client = parseCode( "template \n" "class A\n" "{};\n" - "template typename T>\n" + "template 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 -> A <6:7 6:7>"); + TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A -> A <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->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 client = parseCode( - "template \n" + "template \n" "class A\n" "{\n" "};\n" - "template \n" + "template \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 client = parseCode( + "template \n" + "class A\n" + "{\n" + "};\n" + "template \n" "class A\n" "{\n" "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->bool <6:9 6:9>"); - TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A->A::U <6:15 6:15>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->bool <6:9 6:9>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A->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 client = parseCode( - "template \n" + "class P\n" + "{};\n" + "template \n" "class A\n" - "{\n" - "};\n" - "template \n" - "class A\n" + "{};\n" + "P p;\n" + "template \n" + "class A<&p, q>\n" "{\n" "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->bool <6:9 6:9>"); - TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A->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 client = parseCode( + "class P\n" + "{};\n" + "template \n" + "class A\n" + "{};\n" + "P p;\n" + "template \n" + "class A\n" + "{\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->P <8:9 8:9>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A->P <8:12 8:12>"); + } + + void test_cxx_parser_finds_non_type_nullptr_template_argument_of_explicit_partial_template_specialization() + { + std::shared_ptr client = parseCode( + "#include \n" + "template \n" + "class A\n" + "{};\n" + "template \n" + "class A\n" + "{\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->nullptr_t <6:9 6:9>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A->std::nullptr_t <6:18 6:18>"); + } + + void test_cxx_parser_finds_template_template_argument_of_explicit_partial_template_specialization() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{};\n" + "template class T, template class U>\n" + "class B\n" + "{};\n" + "template class U>\n" + "class B\n" + "{\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B typename U>->A <8:9 8:9>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "B typename U>->B 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 <5:1 <6:7 6:7> 8:1>"); } - void test_cxx_parser_finds_argument_of_explicit_template_specialization() - { - std::shared_ptr client = parseCode( - "template \n" - "class A\n" - "{\n" - "};\n" - "template <>\n" - "class A\n" - "{\n" - "};\n" - ); - TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->int <0:0 0:0>"); - } - void test_cxx_parser_finds_correct_field_member_name_of_template_class_in_declaration() { std::shared_ptr client = parseCode( @@ -1839,7 +1995,7 @@ public: TS_ASSERT_EQUALS(client->methods[0], "private A::T A::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 client = parseCode( "template \n" @@ -1852,30 +2008,36 @@ public: TS_ASSERT_EQUALS(client->templateDefaultArgumentTypes[0], "int -> A::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 client = parseCode( + "template \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 client = parseCode( - // "template \n" - // "class A\n" - // "{\n" - // "};\n" - // "template \n" - // "class A\n" - // "{\n" - // "};\n" - // ); + void test_cxx_parser_finds_template_template_default_argument_type_of_template_class() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{};\n" + "template class T = A>\n" + "class B\n" + "{};\n" + ); - // TS_ASSERT_EQUALS(client->classes.size(), 1); - // TS_ASSERT_EQUALS(client->classes[0], "A <2:1 <2:7 2:7> 4:1>"); - //} + TS_ASSERT_EQUALS(client->templateDefaultArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateDefaultArgumentTypes[0], "A -> B 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 client = parseCode( "template \n" @@ -1889,6 +2051,99 @@ public: TS_ASSERT_EQUALS(client->templateParameterTypes[0], "test::T <1:20 1:20>"); } + void test_cxx_parser_finds_non_type_int_template_parameter_of_template_function() + { + std::shared_ptr client = parseCode( + "template \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::T <1:15 1:15>"); + } + + void test_cxx_parser_finds_non_type_bool_template_parameter_of_template_function() + { + std::shared_ptr client = parseCode( + "template \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::T <1:16 1:16>"); + } + + void test_cxx_parser_finds_non_type_custom_pointer_template_parameter_of_template_function() + { + std::shared_ptr client = parseCode( + "class P\n" + "{};\n" + "template \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 <3:14 3:14>"); + } + + void test_cxx_parser_finds_non_type_custom_reference_template_parameter_of_template_function() + { + std::shared_ptr client = parseCode( + "class P\n" + "{};\n" + "template \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 <3:14 3:14>"); + } + + void test_cxx_parser_finds_non_type_nullptr_template_parameter_of_template_function() + { + std::shared_ptr client = parseCode( + "#include \n" + "template \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::T <2:26 2:26>"); + } + + void test_cxx_parser_finds_template_template_parameter_of_template_function() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{};\n" + "template 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::T <1:20 1:20>"); + TS_ASSERT_EQUALS(client->templateParameterTypes[1], "test typename T>::T <4:36 4:36>"); + } + void test_cxx_parser_finds_implicit_specialization_of_template_function() { std::shared_ptr client = parseCode(