From e61171cc85a6d7542d5b563e1dbc60ec8e8cba78 Mon Sep 17 00:00:00 2001 From: malte_langkabel Date: Tue, 13 Oct 2015 13:29:36 +0200 Subject: [PATCH] data: Template Member Specialization Edge * Added a new edge that connects a method of an implicitly specialized template class to its definition in the unspecialized template class. * Added a test case for this. * Made methods that have an invalid source location stored as undefined. --- src/lib/data/Storage.cpp | 20 ++++++++- src/lib/data/Storage.h | 3 ++ src/lib/data/graph/Edge.cpp | 10 +++-- src/lib/data/graph/Edge.h | 37 ++++++++-------- src/lib/data/parser/ParserClient.h | 3 ++ src/lib/data/parser/cxx/ASTVisitor.cpp | 58 ++++++++++++++++++++------ src/lib/data/parser/cxx/ASTVisitor.h | 1 + src/test/CxxParserTestSuite.h | 41 +++++++++++++++--- 8 files changed, 133 insertions(+), 40 deletions(-) diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 217c155f..5a40da72 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -317,7 +317,7 @@ Id Storage::onMethodParsed( ){ log("method", method.getFullName(), location); - Id nodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_METHOD, method, true); + Id nodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_METHOD, method, location.isValid() && scopeLocation.isValid()); addSourceLocation(nodeId, location); addSourceLocation(nodeId, scopeLocation, true); addAccess(nodeId, access); @@ -621,6 +621,24 @@ Id Storage::onTemplateRecordSpecializationParsed( return specializedNodeId; } +Id Storage::onTemplateMemberFunctionSpecializationParsed( + const ParseLocation& location, const ParseFunction& instantiatedFunction, const ParseFunction& specializedFunction +){ + log( + "template member function specialization", + instantiatedFunction.getFullName() + " -> " + specializedFunction.getFullName(), + location + ); + + Id instantiatedFunctionNodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, instantiatedFunction, false); + + Id specializedFunctionNodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, specializedFunction, false); + + Id edgeId = addEdge(instantiatedFunctionNodeId, specializedFunctionNodeId, Edge::EDGE_TEMPLATE_MEMBER_SPECIALIZATION_OF, location); + + return edgeId; +} + Id Storage::onTemplateFunctionParameterTypeParsed( const ParseLocation& location, const NameHierarchy& templateParameterTypeNameHierarchy, const ParseFunction function ){ diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 57819375..31cce696 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -109,6 +109,9 @@ public: virtual Id onTemplateRecordSpecializationParsed( const ParseLocation& location, const NameHierarchy& specializedRecordNameHierarchy, const RecordType specializedRecordType, const NameHierarchy& specializedFromNameHierarchy); + virtual Id onTemplateMemberFunctionSpecializationParsed( + const ParseLocation& location, const ParseFunction& instantiatedFunction, const ParseFunction& specializedFunction); + virtual Id onTemplateFunctionParameterTypeParsed( const ParseLocation& location, const NameHierarchy& templateParameterTypeNameHierarchy, const ParseFunction function); virtual Id onTemplateFunctionSpecializationParsed( diff --git a/src/lib/data/graph/Edge.cpp b/src/lib/data/graph/Edge.cpp index 2392ade9..dbb552c8 100644 --- a/src/lib/data/graph/Edge.cpp +++ b/src/lib/data/graph/Edge.cpp @@ -46,10 +46,12 @@ Edge::EdgeType Edge::intToType(int value) case 0x2000: return EDGE_TEMPLATE_SPECIALIZATION_OF; case 0x4000: - return EDGE_INCLUDE; + return EDGE_TEMPLATE_MEMBER_SPECIALIZATION_OF; case 0x8000: - return EDGE_AGGREGATION; + return EDGE_INCLUDE; case 0x10000: + return EDGE_AGGREGATION; + case 0x20000: return EDGE_MACRO_USAGE; } @@ -194,6 +196,8 @@ std::string Edge::getTypeString(EdgeType type) return "template_default_argument"; case EDGE_TEMPLATE_SPECIALIZATION_OF: return "template_specialization"; + case EDGE_TEMPLATE_MEMBER_SPECIALIZATION_OF: + return "template_member_specialization"; case EDGE_INCLUDE: return "include"; case EDGE_AGGREGATION: @@ -236,7 +240,7 @@ std::ostream& operator<<(std::ostream& ostream, const Edge& edge) return ostream; } -bool Edge::checkType() const +bool Edge::checkType() const // TODO: remove this function { Node::NodeTypeMask complexTypeMask = Node::NODE_CLASS | Node::NODE_STRUCT | Node:: NODE_TEMPLATE_PARAMETER_TYPE; Node::NodeTypeMask typeMask = Node::NODE_ENUM | Node::NODE_TYPEDEF | complexTypeMask; diff --git a/src/lib/data/graph/Edge.h b/src/lib/data/graph/Edge.h index 92e5b7c9..a4286c22 100644 --- a/src/lib/data/graph/Edge.h +++ b/src/lib/data/graph/Edge.h @@ -18,26 +18,27 @@ public: typedef int EdgeTypeMask; enum EdgeType : EdgeTypeMask { - EDGE_NONE = 0x0, - EDGE_MEMBER = 0x1, - EDGE_TYPE_OF = 0x2, - EDGE_RETURN_TYPE_OF = 0x4, // unused: see Storage::addFunctionNode() - EDGE_PARAMETER_TYPE_OF = 0x8, // unused: see Storage::addFunctionNode() - EDGE_TYPE_USAGE = 0x10, - EDGE_USAGE = 0x20, - EDGE_CALL = 0x40, - EDGE_INHERITANCE = 0x80, - EDGE_OVERRIDE = 0x100, - EDGE_TYPEDEF_OF = 0x200, - EDGE_TEMPLATE_PARAMETER = 0x400, - EDGE_TEMPLATE_ARGUMENT = 0x800, - EDGE_TEMPLATE_DEFAULT_ARGUMENT = 0x1000, - EDGE_TEMPLATE_SPECIALIZATION_OF = 0x2000, + EDGE_NONE = 0x0, + EDGE_MEMBER = 0x1, + EDGE_TYPE_OF = 0x2, + EDGE_RETURN_TYPE_OF = 0x4, // unused: see Storage::addFunctionNode() + EDGE_PARAMETER_TYPE_OF = 0x8, // unused: see Storage::addFunctionNode() + EDGE_TYPE_USAGE = 0x10, + EDGE_USAGE = 0x20, + EDGE_CALL = 0x40, + EDGE_INHERITANCE = 0x80, + EDGE_OVERRIDE = 0x100, + EDGE_TYPEDEF_OF = 0x200, + EDGE_TEMPLATE_PARAMETER = 0x400, + EDGE_TEMPLATE_ARGUMENT = 0x800, + EDGE_TEMPLATE_DEFAULT_ARGUMENT = 0x1000, + EDGE_TEMPLATE_SPECIALIZATION_OF = 0x2000, + EDGE_TEMPLATE_MEMBER_SPECIALIZATION_OF = 0x4000, - EDGE_INCLUDE = 0x4000, + EDGE_INCLUDE = 0x8000, - EDGE_AGGREGATION = 0x8000, - EDGE_MACRO_USAGE = 0x10000, + EDGE_AGGREGATION = 0x10000, + EDGE_MACRO_USAGE = 0x20000, }; static int typeToInt(EdgeType type); diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index 08d5918d..b48b34f5 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -127,6 +127,9 @@ public: virtual Id onTemplateRecordSpecializationParsed( const ParseLocation& location, const NameHierarchy& specializedRecordNameHierarchy, const RecordType specializedRecordType, const NameHierarchy& specializedFromNameHierarchy) = 0; + virtual Id onTemplateMemberFunctionSpecializationParsed( + const ParseLocation& location, const ParseFunction& instantiatedFunction, const ParseFunction& specializedFunction) = 0; + virtual Id onTemplateFunctionParameterTypeParsed( const ParseLocation& location, const NameHierarchy& templateParameterTypeNameHierarchy, const ParseFunction function) = 0; diff --git a/src/lib/data/parser/cxx/ASTVisitor.cpp b/src/lib/data/parser/cxx/ASTVisitor.cpp index 00ce2cca..a4f0923b 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -173,16 +173,6 @@ bool ASTVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* declaration) { if (isLocatedInUnparsedProjectFile(declaration)) { - ParserClient::AbstractionType abstraction = ParserClient::ABSTRACTION_NONE; - if (declaration->isPure()) - { - abstraction = ParserClient::ABSTRACTION_PURE_VIRTUAL; - } - else if (declaration->isVirtual()) - { - abstraction = ParserClient::ABSTRACTION_VIRTUAL; - } - ParseFunction parseFunction = getParseFunction(declaration); ParseLocation location = getParseLocationForNamedDecl(declaration); @@ -190,7 +180,7 @@ bool ASTVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* declaration) location, parseFunction, convertAccessType(declaration->getAccess()), - abstraction, + getAbstractionType(declaration), getParseLocationOfFunctionBody(declaration) ); @@ -363,8 +353,9 @@ bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration) specializationParentNameHierarchy ); - std::string specializationFilePath = specializationLocation.filePath.str(); + // template arguments + std::string specializationFilePath = specializationLocation.filePath.str(); const clang::TemplateArgumentList &argList = specializationDecl->getTemplateArgs(); for (size_t i = 0; i < argList.size(); i++) { @@ -379,6 +370,35 @@ bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration) ); } } + + // template methods + if (specializationDecl->getSpecializationKind() == clang::TSK_ImplicitInstantiation) + { + for (clang::CXXRecordDecl::method_iterator methodIt = specializationDecl->method_begin(); methodIt != specializationDecl->method_end(); methodIt++) + { + clang::CXXMethodDecl* methodDecl = (*methodIt); + if (methodDecl->getTemplatedKind() == clang::FunctionDecl::TK_MemberSpecialization) + { + m_client->onMethodParsed( + getParseLocation(methodDecl->getMemberSpecializationInfo()->getPointOfInstantiation()), + getParseFunction(methodDecl), + convertAccessType(methodDecl->getAccess()), + getAbstractionType(methodDecl), + ParseLocation() + ); + + clang::NamedDecl* specializedNamedDecel = methodDecl->getMemberSpecializationInfo()->getInstantiatedFrom(); + if (clang::isa(specializedNamedDecel)) + { + m_client->onTemplateMemberFunctionSpecializationParsed( + getParseLocation(methodDecl->getMemberSpecializationInfo()->getPointOfInstantiation()), + getParseFunction(methodDecl), + getParseFunction(clang::dyn_cast(specializedNamedDecel)) + ); + } + } + } + } } } return true; @@ -799,6 +819,20 @@ ParserClient::AccessType ASTVisitor::convertAccessType(clang::AccessSpecifier ac } } +ParserClient::AbstractionType ASTVisitor::getAbstractionType(const clang::CXXMethodDecl* methodDecl) const +{ + ParserClient::AbstractionType abstraction = ParserClient::ABSTRACTION_NONE; + if (methodDecl->isPure()) + { + abstraction = ParserClient::ABSTRACTION_PURE_VIRTUAL; + } + else if (methodDecl->isVirtual()) + { + abstraction = ParserClient::ABSTRACTION_VIRTUAL; + } + return abstraction; +} + ParseLocation ASTVisitor::getParseLocation(const clang::SourceRange& sourceRange) const { if (sourceRange.isInvalid()) diff --git a/src/lib/data/parser/cxx/ASTVisitor.h b/src/lib/data/parser/cxx/ASTVisitor.h index 44e2ba49..aeac2a44 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.h +++ b/src/lib/data/parser/cxx/ASTVisitor.h @@ -64,6 +64,7 @@ private: bool isLocatedInProjectFile(const clang::Decl* declaration) const; ParserClient::AccessType convertAccessType(clang::AccessSpecifier) const; + ParserClient::AbstractionType getAbstractionType(const clang::CXXMethodDecl* methodDecl) const; ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const; ParseLocation getParseLocationForNamedDecl(const clang::NamedDecl* decl, const clang::SourceLocation& loc) const; diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 4bcb8254..42ddaecb 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -1599,6 +1599,24 @@ public: TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B->A <0:0 0:0>"); } + void test_cxx_parser_finds__of_implicit_template_specialization() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + "public:\n" + " T foo() {}\n" + "};\n" + "int main()\n" + "{\n" + " A a;\n" + "}\n" + ); + TS_ASSERT_EQUALS(client->templateMemberSpecializations.size(), 1); + TS_ASSERT_EQUALS(client->templateMemberSpecializations[0], "A::foo -> A::foo <0:0 0:0>"); + } + void test_cxx_parser_finds_explicit_template_specialization() { std::shared_ptr client = parseCode( @@ -2492,11 +2510,11 @@ private: { } - virtual void prepareParsingFile() + virtual void prepareParsingFile(const FilePath& filePath) { } - virtual void finishParsingFile() + virtual void finishParsingFile(const FilePath& filePath) { } @@ -2715,10 +2733,20 @@ private: const ParseLocation& location, const NameHierarchy& specializedRecordNameHierarchy, const RecordType specializedRecordType, const NameHierarchy& specializedFromNameHierarchy) { - templateSpecializations.push_back( - addLocationSuffix(std::string(specializedRecordType == ParserClient::RECORD_CLASS ? "class" : "struct") + " " + - specializedRecordNameHierarchy.getFullName() + " -> " + specializedFromNameHierarchy.getFullName(), location) - ); + templateSpecializations.push_back(addLocationSuffix( + std::string(specializedRecordType == ParserClient::RECORD_CLASS ? "class" : "struct") + " " + + specializedRecordNameHierarchy.getFullName() + " -> " + specializedFromNameHierarchy.getFullName(), location + )); + return 0; + } + + virtual Id onTemplateMemberFunctionSpecializationParsed( + const ParseLocation& location, const ParseFunction& instantiatedFunction, const ParseFunction& specializedFunction) + { + // needs to be implemented + templateMemberSpecializations.push_back(addLocationSuffix( + instantiatedFunction.getFullName() + " -> " + specializedFunction.getFullName(), location + )); return 0; } @@ -2791,6 +2819,7 @@ private: std::vector templateArgumentTypes; std::vector templateDefaultArgumentTypes; std::vector templateSpecializations; + std::vector templateMemberSpecializations; std::vector files; std::vector includes;