From 9d17e2e7e6fe960907a9d9d7879d7973bc3a9b6d Mon Sep 17 00:00:00 2001 From: mlangkabel Date: Tue, 14 Nov 2017 12:09:32 +0100 Subject: [PATCH] logic: fixed getting the parent of a Cxx template parameter's declaration * switched to getting the template parameter's parent from the ASTContext instead of using the DeclContext --- src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp | 12 +- .../cxx/name_resolver/CxxDeclNameResolver.cpp | 105 +++++++++++++----- .../cxx/name_resolver/CxxDeclNameResolver.h | 1 + .../cxx/name_resolver/CxxNameResolver.cpp | 23 +++- .../cxx/name_resolver/CxxNameResolver.h | 1 + src/lib_cxx/data/parser/cxx/utilityClang.h | 17 +++ src/test/CxxParserTestSuite.h | 94 ++++++++++++++-- 7 files changed, 203 insertions(+), 50 deletions(-) diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp index ed9c8b2f..6e227894 100644 --- a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp @@ -475,14 +475,12 @@ void CxxAstVisitor::traverseDeclContextHelper(clang::DeclContext* d) return; } - // Traverse children. - for (clang::DeclContext::decl_iterator it = d->decls_begin(), - itEnd = d->decls_end(); it != itEnd; ++it) - { - // BlockDecls are traversed through BlockExprs. - if (!llvm::isa(*it)) + for (auto* child : d->decls()) { + // BlockDecls and CapturedDecls are traversed through BlockExprs and + // CapturedStmts respectively. + if (!llvm::isa(child) && !llvm::isa(child)) { - TraverseDecl(*it); + TraverseDecl(child); } } } diff --git a/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp b/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp index f77f92f2..3aa8a59d 100644 --- a/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp @@ -36,17 +36,9 @@ CxxDeclNameResolver::~CxxDeclNameResolver() std::shared_ptr CxxDeclNameResolver::getName(const clang::NamedDecl* declaration) { - { - const clang::Decl* prev = declaration; - while (prev) - { - declaration = clang::dyn_cast_or_null(prev); - prev = prev->getPreviousDecl(); - } - } + declaration = utility::getFirstDecl(declaration); std::shared_ptr declName; - if ((declaration) && (clang::isa(declaration)) && (clang::dyn_cast(declaration)->isLambda())) @@ -77,6 +69,60 @@ std::shared_ptr CxxDeclNameResolver::getName(const clang::NamedDecl CxxSpecifierNameResolver specifierNameResolver(getCanonicalFilePathCache(), getIgnoredContextDecls()); declName->setParent(specifierNameResolver.getName(usingDecl->getQualifier())); } + else if ( + clang::isa(declaration) || + clang::isa(declaration) || + clang::isa(declaration) + ) { + clang::ASTContext& context = declaration->getASTContext(); + + clang::ASTContext::DynTypedNodeList parents = context.getParents(*declaration); + for (const clang::ast_type_traits::DynTypedNode* parent = parents.begin(); parent != parents.end(); parent++) + { + const clang::Decl* parentDecl = parent->get(); + while (parentDecl != nullptr) + { + parentDecl = utility::getFirstDecl(parentDecl); + + if (const clang::TemplateDecl* parentTemplateDecl = clang::dyn_cast_or_null(parentDecl)) + { + if (!ignoresContext(parentTemplateDecl) && !ignoresContext(parentTemplateDecl->getTemplatedDecl())) + { + declName->setParent(getName(parentTemplateDecl)); + } + break; + } + else if (const clang::ClassTemplatePartialSpecializationDecl* parentTemplateDecl = clang::dyn_cast_or_null(parentDecl)) + { + if (!ignoresContext(parentDecl)) + { + declName->setParent(getName(parentTemplateDecl)); + } + break; + } + + if (const clang::DeclContext* parentDeclContext = parentDecl->getDeclContext()) + { + if (ignoresContext(parentDeclContext)) + { + break; + } + parentDecl = clang::dyn_cast_or_null(parentDeclContext); + if (parentDecl) + { + if (clang::TemplateDecl* describedTemplate = parentDecl->getDescribedTemplate()) + { + parentDecl = describedTemplate; + } + } + } + else + { + break; + } + } + } + } else { declName->setParent(getContextName(declaration->getDeclContext())); @@ -215,20 +261,15 @@ std::shared_ptr CxxDeclNameResolver::getDeclName(const clang::Named } else if (clang::FunctionTemplateDecl* templateFunctionDeclaration = functionDecl->getDescribedFunctionTemplate()) { - std::shared_ptr templateDeclName = getDeclName(templateFunctionDeclaration); - functionName = templateDeclName->getName(); - templateArguments = templateDeclName->getTemplateParameterNames(); + templateArguments = getTemplateParameterStrings(templateFunctionDeclaration); } - else + else if (functionDecl->isFunctionTemplateSpecialization()) { - if (functionDecl->isFunctionTemplateSpecialization()) + const clang::TemplateArgumentList* templateArgumentList = functionDecl->getTemplateSpecializationArgs(); + for (size_t i = 0; i < templateArgumentList->size(); i++) { - const clang::TemplateArgumentList* templateArgumentList = functionDecl->getTemplateSpecializationArgs(); - for (size_t i = 0; i < templateArgumentList->size(); i++) - { - const clang::TemplateArgument& templateArgument = templateArgumentList->get(i); - templateArguments.push_back(getTemplateArgumentName(templateArgument)); - } + const clang::TemplateArgument& templateArgument = templateArgumentList->get(i); + templateArguments.push_back(getTemplateArgumentName(templateArgument)); } } @@ -276,15 +317,14 @@ std::shared_ptr CxxDeclNameResolver::getDeclName(const clang::Named isStatic ); } + else if (clang::isa(declaration)) + { + const clang::FunctionTemplateDecl* functionTemplateDecl = clang::dyn_cast(declaration); + return getDeclName(functionTemplateDecl->getTemplatedDecl()); + } else if (clang::isa(declaration)) // also triggers on TemplateTemplateParmDecl { - std::vector templateParameters; - clang::TemplateParameterList* parameterList = clang::dyn_cast(declaration)->getTemplateParameters(); - for (size_t i = 0; i < parameterList->size(); i++) - { - templateParameters.push_back(getTemplateParameterString(parameterList->getParam(i))); - } - return std::make_shared(declNameString, templateParameters); + return std::make_shared(declNameString, getTemplateParameterStrings(clang::dyn_cast(declaration))); } else if (clang::isa(declaration)) { @@ -410,6 +450,17 @@ std::string CxxDeclNameResolver::getNameForAnonymousSymbol(const std::string& sy return "anonymous " + symbolKindName; } +std::vector CxxDeclNameResolver::getTemplateParameterStrings(const clang::TemplateDecl* templateDecl) +{ + std::vector templateParameterStrings; + clang::TemplateParameterList* parameterList = templateDecl->getTemplateParameters(); + for (size_t i = 0; i < parameterList->size(); i++) + { + templateParameterStrings.push_back(getTemplateParameterString(parameterList->getParam(i))); + } + return templateParameterStrings; +} + std::string CxxDeclNameResolver::getTemplateParameterString(const clang::NamedDecl* parameter) { std::string templateParameterTypeString; diff --git a/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.h b/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.h index 92306b43..ffbf28bd 100644 --- a/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.h +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxDeclNameResolver.h @@ -25,6 +25,7 @@ private: std::string getTranslationUnitMainFileName(const clang::Decl* declaration); std::string getDeclarationFileName(const clang::Decl* declaration); std::string getNameForAnonymousSymbol(const std::string& symbolKindName, const clang::Decl* declaration); + std::vector getTemplateParameterStrings(const clang::TemplateDecl* templateDecl); std::string getTemplateParameterString(const clang::NamedDecl* parameter); std::string getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter); std::string getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter); diff --git a/src/lib_cxx/data/parser/cxx/name_resolver/CxxNameResolver.cpp b/src/lib_cxx/data/parser/cxx/name_resolver/CxxNameResolver.cpp index 90de103c..8b3109d8 100644 --- a/src/lib_cxx/data/parser/cxx/name_resolver/CxxNameResolver.cpp +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxNameResolver.cpp @@ -21,15 +21,26 @@ void CxxNameResolver::ignoreContextDecl(const clang::Decl* decl) } } +bool CxxNameResolver::ignoresContext(const clang::Decl* decl) +{ + if (decl) + { + for (size_t i = 0; i < m_ignoredContextDecls.size(); i++) + { + if (decl == m_ignoredContextDecls[i]) + { + return true; + } + } + } + return false; +} + bool CxxNameResolver::ignoresContext(const clang::DeclContext* declContext) { - const clang::Decl* decl = clang::dyn_cast(declContext); - for (size_t i = 0; i < m_ignoredContextDecls.size(); i++) + if (const clang::Decl* decl = clang::dyn_cast_or_null(declContext)) { - if (decl == m_ignoredContextDecls[i]) - { - return true; - } + return ignoresContext(decl); } return false; } diff --git a/src/lib_cxx/data/parser/cxx/name_resolver/CxxNameResolver.h b/src/lib_cxx/data/parser/cxx/name_resolver/CxxNameResolver.h index 05bdc085..91ef7d92 100644 --- a/src/lib_cxx/data/parser/cxx/name_resolver/CxxNameResolver.h +++ b/src/lib_cxx/data/parser/cxx/name_resolver/CxxNameResolver.h @@ -17,6 +17,7 @@ public: virtual ~CxxNameResolver(); void ignoreContextDecl(const clang::Decl* decl); + bool ignoresContext(const clang::Decl* decl); bool ignoresContext(const clang::DeclContext* declContext); protected: diff --git a/src/lib_cxx/data/parser/cxx/utilityClang.h b/src/lib_cxx/data/parser/cxx/utilityClang.h index 20a5d770..6072ed34 100644 --- a/src/lib_cxx/data/parser/cxx/utilityClang.h +++ b/src/lib_cxx/data/parser/cxx/utilityClang.h @@ -8,6 +8,8 @@ namespace utility { + template + const T* getFirstDecl(const T* decl); bool isImplicit(const clang::Decl* d); AccessKind convertAccessSpecifier(clang::AccessSpecifier access); SymbolKind convertTagKind(const clang::TagTypeKind tagKind); @@ -15,4 +17,19 @@ namespace utility std::string getFileNameOfFileEntry(const clang::FileEntry* entry); } +template +const T* utility::getFirstDecl(const T* decl) +{ + const clang::Decl* ret = decl; + { + const clang::Decl* prev = ret; + while (prev) + { + ret = prev; + prev = prev->getPreviousDecl(); + } + } + return clang::dyn_cast_or_null(ret); +} + #endif // UTILITY_CLANG_H diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 2ee5d213..2738f3dd 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -677,14 +677,18 @@ public: )); } - //void _test_cxx_parser_finds_template_argument_of_dependent_non_type_template_parameter() - //{ - // std::shared_ptr client = parseCode( - // "template class T1, T1& T2>\n" // test that t1 uses int - // "class A\n" - // "{};\n" - // ); - //} + void test_cxx_parser_finds_template_argument_of_dependent_non_type_template_parameter() + { + std::shared_ptr client = parseCode( + "template class T1, T1& T2>\n" + "class A\n" + "{};\n" + ); + + TS_ASSERT(utility::containsElement( + client->templateArgumentTypes, "A typename T1, T1 & T2>::T1 -> int <1:43 1:45>" + )); + } void test_cxx_parser_finds_template_template_parameter_of_template_class() { @@ -2431,7 +2435,77 @@ public: )); } - void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_specialized_with_concrete_type() + void test_cxx_parser_finds_usage_of_template_parameter_of_template_member_variable_declaration() + { + std::shared_ptr client = parseCode( + "template \n" + " struct IsBaseType {\n" + " static const bool value = true;\n" + "};\n" + "template \n" + "const bool IsBaseType::value;\n" + ); + + TS_ASSERT(utility::containsElement( + client->templateParameterTypes, "IsBaseType::T <1:20 1:20>" + )); + TS_ASSERT(utility::containsElement( + client->templateParameterTypes, "IsBaseType::T <5:20 5:20>" + )); + } + + void test_cxx_parser_finds_usage_of_template_parameters_with_different_depth_of_template_function() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + " template \n" + " void foo(Q q)\n" + " {\n" + " T t;\n" + " t.run(q);\n" + " }\n" + "};\n" + ); + + TS_ASSERT(utility::containsElement( + client->typeUses, "void A::foo(Q) -> A::T <7:3 7:3>" + )); + TS_ASSERT(utility::containsElement( + client->typeUses, "void A::foo(Q) -> A::foo::Q <5:11 5:11>" + )); + } + + void test_cxx_parser_finds_usage_of_template_parameters_with_different_depth_of_partial_template_specialization() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + " template \n" + " class B\n" + " {\n" + " T foo(Q q, R r);\n" + " };\n" + "\n" + " template \n" + " class B\n" + " {\n" + " T foo(R r);\n" + " };\n" + "};\n" + ); + + TS_ASSERT(utility::containsElement( + client->typeUses, "A::T A::B::foo(A::B::R) -> A::T <13:3 13:3>" + )); + TS_ASSERT(utility::containsElement( + client->typeUses, "A::T A::B::foo(A::B::R) -> A::B::R <13:9 13:9>" + )); + } + + void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_explicitly_instantiated_with_concrete_type_argument() { std::shared_ptr client = parseCode( "template \n" @@ -2450,7 +2524,7 @@ public: )); } - void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_specialized_with_template_type() + void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_explicitly_instantiated_with_template_type() { std::shared_ptr client = parseCode( "template \n"