From e17341fc434cb0ae56c77178a10ecb0f7962ff8b Mon Sep 17 00:00:00 2001 From: malte_langkabel Date: Tue, 3 Feb 2015 13:10:56 +0100 Subject: [PATCH] data: parse partial template specializations * fixed: implicit template specializations will be found even if the original template definition is located in a different file (that gets included). * implemented correct extraction of template parameters, template arguments and template specialization edges. * added token locations for template parameters of partial template specializations. * graph view displays full names of template parameters and template arguments. * added test code for features --- bin/app/data/src/test2/header.h | 16 ++ bin/app/data/src/test2/main.cpp | 9 + src/lib/data/Storage.cpp | 27 ++- src/lib/data/Storage.h | 7 +- src/lib/data/graph/Edge.cpp | 2 + src/lib/data/graph/Edge.h | 5 +- src/lib/data/graph/Node.cpp | 6 - src/lib/data/graph/Node.h | 1 - .../token_component/TokenComponentName.cpp | 12 +- .../token_component/TokenComponentName.h | 4 +- src/lib/data/parser/ParserClient.h | 5 +- src/lib/data/parser/cxx/ASTVisitor.cpp | 92 +++++---- src/lib/data/parser/cxx/utilityCxx.cpp | 54 +++++- src/lib/data/parser/cxx/utilityCxx.h | 2 + src/lib/data/search/SearchNode.cpp | 12 ++ src/lib/data/search/SearchNode.h | 1 + src/test/CxxParserTestSuite.h | 179 +++++++++++++++--- src/test/GraphTestSuite.h | 55 +++--- 18 files changed, 363 insertions(+), 126 deletions(-) create mode 100644 bin/app/data/src/test2/header.h create mode 100644 bin/app/data/src/test2/main.cpp diff --git a/bin/app/data/src/test2/header.h b/bin/app/data/src/test2/header.h new file mode 100644 index 00000000..efe15fc3 --- /dev/null +++ b/bin/app/data/src/test2/header.h @@ -0,0 +1,16 @@ +template +class TemplateTestClass +{ +}; + +template +class TemplateTestClass +{ + int foo; +}; + +template<> +class TemplateTestClass +{ + int foo; +}; \ No newline at end of file diff --git a/bin/app/data/src/test2/main.cpp b/bin/app/data/src/test2/main.cpp new file mode 100644 index 00000000..443517fc --- /dev/null +++ b/bin/app/data/src/test2/main.cpp @@ -0,0 +1,9 @@ +#include "header.h" + + +int main() +{ + TemplateTestClass t2; +// TemplateTestClass t3; + return 0; +} \ No newline at end of file diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 3b94d3bd..8e01c7e5 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -388,25 +388,38 @@ Id Storage::onTemplateRecordParameterTypeParsed( const std::vector& templateRecordNameHierarchy ) { - log("class template type parameter", templateParameterTypeName, location); + log("template record type parameter", templateParameterTypeName, location); std::vector templateParameterTypeNameHierarchy = templateRecordNameHierarchy; templateParameterTypeNameHierarchy.back() += "::" + templateParameterTypeName; Node* templateParameterNode = addNodeHierarchy(Node::NODE_TEMPLATE_PARAMETER_TYPE, templateParameterTypeNameHierarchy); addTokenLocation(templateParameterNode, location); Node* templateRecordNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateRecordNameHierarchy); - Edge* edge = m_graph.createEdge(Edge::EDGE_TEMPLATE_PARAMETER_OF, templateParameterNode, templateRecordNode); - //addTokenLocation(edge, location); return 0; } +Id Storage::onTemplateRecordArgumentTypeParsed( + const ParseLocation& location, const std::vector& templateArgumentTypeNameHierarchy, + const std::vector& templateRecordNameHierarchy) +{ + log("template record argument", utility::join(templateArgumentTypeNameHierarchy, "::") + " -> " + utility::join(templateRecordNameHierarchy, "::"), location); + Node* templateArgumentNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateArgumentTypeNameHierarchy); + Node* templateRecordNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateRecordNameHierarchy); + Edge* edge = m_graph.createEdge(Edge::EDGE_TEMPLATE_ARGUMENT_OF, templateArgumentNode, templateRecordNode); + if (location.isValid()) + { + addTokenLocation(templateArgumentNode, location); + } + return 0; +} + Id Storage::onTemplateRecordSpecializationParsed( const ParseLocation& location, const std::vector& specializedRecordNameHierarchy, - const RecordType specializedRecordType, const std::vector& templateRecordNameHierarchy) + const RecordType specializedRecordType, const std::vector& specializedFromNameHierarchy) { - log("class template specialization", utility::join(specializedRecordNameHierarchy, "::") + " -> " + utility::join(templateRecordNameHierarchy, "::"), location); + log("template record specialization", utility::join(specializedRecordNameHierarchy, "::") + " -> " + utility::join(specializedFromNameHierarchy, "::"), location); Node::NodeType specializedRecordNodeType = Node::NODE_CLASS; if (specializedRecordType == ParserClient::RECORD_STRUCT) @@ -415,7 +428,7 @@ Id Storage::onTemplateRecordSpecializationParsed( } Node* specializedRecordNode = addNodeHierarchy(specializedRecordNodeType, specializedRecordNameHierarchy); - Node* templateRecordNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateRecordNameHierarchy); + Node* templateRecordNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, specializedFromNameHierarchy); Edge* edge = m_graph.createEdge(Edge::EDGE_TEMPLATE_SPECIALIZATION_OF, specializedRecordNode, templateRecordNode); //addTokenLocation(edge, location); @@ -555,7 +568,7 @@ std::shared_ptr Storage::getGraphForActiveTokenIds(const std::vector& else if (tokenIds.size() == 1) { Token* token = m_graph.getTokenById(tokenIds[0]); - + if (!token) { LOG_ERROR_STREAM(<< "Token with id " << tokenIds[0] << " was not found"); diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 6e309f1a..9cfbad6c 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -83,9 +83,14 @@ public: virtual Id onTemplateRecordParameterTypeParsed( const ParseLocation& location, const std::string& templateParameterTypeName, const std::vector& templateRecordNameHierarchy); + virtual Id onTemplateRecordArgumentTypeParsed( + const ParseLocation& location, const std::vector& templateArgumentTypeNameHierarchy, + const std::vector& templateRecordNameHierarchy); + virtual Id onTemplateRecordSpecializationParsed( const ParseLocation& location, const std::vector& specializedRecordNameHierarchy, - const RecordType specializedRecordType, const std::vector& templateRecordNameHierarchy); + const RecordType specializedRecordType, const std::vector& specializedFromNameHierarchy); + virtual Id onTemplateFunctionParameterTypeParsed( const ParseLocation& location, const std::string& templateParameterTypeName, const ParseFunction function); virtual Id onTemplateFunctionSpecializationParsed( diff --git a/src/lib/data/graph/Edge.cpp b/src/lib/data/graph/Edge.cpp index 22af22c7..f7ebd4a5 100644 --- a/src/lib/data/graph/Edge.cpp +++ b/src/lib/data/graph/Edge.cpp @@ -133,6 +133,8 @@ std::string Edge::getTypeString(EdgeType type) const return "typedef"; case EDGE_TEMPLATE_PARAMETER_OF: return "template parameter"; + case EDGE_TEMPLATE_ARGUMENT_OF: + return "template argument"; case EDGE_TEMPLATE_SPECIALIZATION_OF: return "template specialization"; case EDGE_AGGREGATION: diff --git a/src/lib/data/graph/Edge.h b/src/lib/data/graph/Edge.h index c18174fc..35d017ed 100644 --- a/src/lib/data/graph/Edge.h +++ b/src/lib/data/graph/Edge.h @@ -27,9 +27,10 @@ public: EDGE_INHERITANCE = 0x80, EDGE_TYPEDEF_OF = 0x100, EDGE_TEMPLATE_PARAMETER_OF = 0x200, - EDGE_TEMPLATE_SPECIALIZATION_OF = 0x400, + EDGE_TEMPLATE_ARGUMENT_OF = 0x400, + EDGE_TEMPLATE_SPECIALIZATION_OF = 0x800, - EDGE_AGGREGATION = 0x800 + EDGE_AGGREGATION = 0x1000 }; Edge(EdgeType type, Node* from, Node* to); diff --git a/src/lib/data/graph/Node.cpp b/src/lib/data/graph/Node.cpp index a10fec85..cd14e6cc 100644 --- a/src/lib/data/graph/Node.cpp +++ b/src/lib/data/graph/Node.cpp @@ -9,12 +9,6 @@ #include "data/graph/token_component/TokenComponentSignature.h" #include "utility/logging/logging.h" -Node::Node(NodeType type, const std::string& name) - : m_type(type) - , m_nameComponent(std::make_shared(name)) -{ -} - Node::Node(NodeType type, std::shared_ptr nameComponent) : m_type(type) , m_nameComponent(nameComponent) diff --git a/src/lib/data/graph/Node.h b/src/lib/data/graph/Node.h index 3e44f0e9..fb868061 100644 --- a/src/lib/data/graph/Node.h +++ b/src/lib/data/graph/Node.h @@ -38,7 +38,6 @@ public: NODE_TEMPLATE_PARAMETER_TYPE = 0x2000 }; - Node(NodeType type, const std::string& name); Node(NodeType type, std::shared_ptr nameComponent); Node(const Node& other); virtual ~Node(); diff --git a/src/lib/data/graph/token_component/TokenComponentName.cpp b/src/lib/data/graph/token_component/TokenComponentName.cpp index 296b52ef..5c27c92f 100644 --- a/src/lib/data/graph/token_component/TokenComponentName.cpp +++ b/src/lib/data/graph/token_component/TokenComponentName.cpp @@ -29,7 +29,7 @@ TokenComponentNameReferenced::~TokenComponentNameReferenced() std::shared_ptr TokenComponentNameReferenced::copy() const { - return std::make_shared(getFullName()); + return std::make_shared(m_searchNode->getNameHierarchy()); } std::string TokenComponentNameReferenced::getName() const @@ -47,8 +47,8 @@ const SearchNode* TokenComponentNameReferenced::getSearchNode() const return m_searchNode; } -TokenComponentNameCached::TokenComponentNameCached(const std::string& fullName) - : m_fullName(fullName) +TokenComponentNameCached::TokenComponentNameCached(const std::vector& nameHierarchy) + : m_nameHierarchy(nameHierarchy) { } @@ -58,17 +58,17 @@ TokenComponentNameCached::~TokenComponentNameCached() std::shared_ptr TokenComponentNameCached::copy() const { - return std::make_shared(m_fullName); + return std::make_shared(m_nameHierarchy); } std::string TokenComponentNameCached::getName() const { - return utility::split(m_fullName, SearchIndex::DELIMITER).back(); + return m_nameHierarchy.back(); } std::string TokenComponentNameCached::getFullName() const { - return m_fullName; + return utility::join(m_nameHierarchy, "::"); } const SearchNode* TokenComponentNameCached::getSearchNode() const diff --git a/src/lib/data/graph/token_component/TokenComponentName.h b/src/lib/data/graph/token_component/TokenComponentName.h index a5d48aaf..2bf05652 100644 --- a/src/lib/data/graph/token_component/TokenComponentName.h +++ b/src/lib/data/graph/token_component/TokenComponentName.h @@ -45,7 +45,7 @@ class TokenComponentNameCached : public TokenComponentName { public: - TokenComponentNameCached(const std::string& fullName); + TokenComponentNameCached(const std::vector& nameHierarchy); virtual ~TokenComponentNameCached(); virtual std::shared_ptr copy() const; @@ -56,7 +56,7 @@ public: virtual const SearchNode* getSearchNode() const; private: - const std::string m_fullName; + const std::vector m_nameHierarchy; }; #endif // TOKEN_COMPONENT_NAME_H diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index 51a8a492..9a40a276 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -100,9 +100,12 @@ public: virtual Id onTemplateRecordParameterTypeParsed( const ParseLocation& location, const std::string& templateParameterTypeName, const std::vector& templateRecordNameHierarchy) = 0; + virtual Id onTemplateRecordArgumentTypeParsed( + const ParseLocation& location, const std::vector& templateArgumentTypeNameHierarchy, + const std::vector& templateRecordNameHierarchy) = 0; virtual Id onTemplateRecordSpecializationParsed( const ParseLocation& location, const std::vector& specializedRecordNameHierarchy, - const RecordType specializedRecordType, const std::vector& templateRecordNameHierarchy) = 0; + const RecordType specializedRecordType, const std::vector& specializedFromNameHierarchy) = 0; virtual Id onTemplateFunctionParameterTypeParsed( const ParseLocation& location, const std::string& templateParameterTypeName, const ParseFunction function) = 0; diff --git a/src/lib/data/parser/cxx/ASTVisitor.cpp b/src/lib/data/parser/cxx/ASTVisitor.cpp index 739058df..6338ad92 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -275,36 +275,44 @@ bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration) if (hasValidLocation(declaration)) { std::vector templateRecordNameHierarchy = utility::getDeclNameHierarchy(declaration); - clang::TemplateParameterList* parameterList = declaration->getTemplateParameters(); for (size_t i = 0; i < parameterList->size(); i++) { clang::NamedDecl* namedDecl = parameterList->getParam(i); - if (hasValidLocation(namedDecl)) { - std::string templateParameterTypeName = namedDecl->getNameAsString(); - m_client->onTemplateRecordParameterTypeParsed( getParseLocationForNamedDecl(namedDecl), - templateParameterTypeName, + namedDecl->getNameAsString(), templateRecordNameHierarchy ); } } - - for (clang::ClassTemplateDecl::spec_iterator it = declaration->specializations().begin(); // template argument as parameter does not work - it != declaration->specializations().end(); it++ - ) - { - ParserClient::RecordType specializedRecordType = it->isStruct() ? ParserClient::RECORD_STRUCT : ParserClient::RECORD_CLASS; - std::vector specializedRecordNameHierarchy = utility::getDeclNameHierarchy(*(it)); - m_client->onTemplateRecordSpecializationParsed( - getParseLocationForNamedDecl(*it), specializedRecordNameHierarchy, specializedRecordType, templateRecordNameHierarchy - ); - } } + // for implicit template specializations we do not need a valid location of the original template class definition (since that file could be included) + // handles explicit specializations and implicit specializations but no explicit partial specializations + for (clang::ClassTemplateDecl::spec_iterator it = declaration->specializations().begin(); + it != declaration->specializations().end(); it++ + ) + { + clang::ClassTemplateSpecializationDecl* specializationDecl = *it; + + std::vector specializationParentNameHierarchy = utility::getTemplateSpecializationParentNameHierarchy(specializationDecl); + + ParserClient::RecordType specializedRecordType = specializationDecl->isStruct() ? ParserClient::RECORD_STRUCT : ParserClient::RECORD_CLASS; + std::vector specializedRecordNameHierarchy = utility::getDeclNameHierarchy(specializationDecl); + m_client->onTemplateRecordSpecializationParsed( + getParseLocationForNamedDecl(*it), specializedRecordNameHierarchy, specializedRecordType, specializationParentNameHierarchy + ); + + const clang::TemplateArgumentList &argList = specializationDecl->getTemplateArgs(); + for (int i = 0; i < argList.size(); i++) + { + std::vector argumentNameHierarchy = utility::qualTypeToDataType(argList.get(i).getAsType()).getTypeNameHierarchy(); + m_client->onTemplateRecordArgumentTypeParsed(ParseLocation(), argumentNameHierarchy, specializedRecordNameHierarchy); // TODO: What about the ParseLocation + } + } return true; } @@ -312,32 +320,40 @@ bool ASTVisitor::VisitClassTemplatePartialSpecializationDecl(clang::ClassTemplat { if (hasValidLocation(declaration)) { - //std::vector templateRecordNameHierarchy = utility::splitToVector( - // declaration->getQualifiedNameAsString(), "::" - //); + std::vector specializedRecordNameHierarchy = utility::getDeclNameHierarchy(declaration); + std::vector specializationParentNameHierarchy = utility::getTemplateSpecializationParentNameHierarchy(declaration); - //clang::ClassTemplateDecl* baseTemplateDecl = declaration->getSpecializedTemplate(); + ParserClient::RecordType specializedRecordType = declaration->isStruct() ? ParserClient::RECORD_STRUCT : ParserClient::RECORD_CLASS; + m_client->onTemplateRecordSpecializationParsed( + getParseLocationForNamedDecl(declaration), specializedRecordNameHierarchy, specializedRecordType, specializationParentNameHierarchy + ); - //std::string specializedParameterNamePart = "<"; - //const clang::TemplateArgumentList& templateArgumentList = declaration->getTemplateArgs(); - //for (int i = 0; i < templateArgumentList.size(); i++) - //{ - // DataType datatype = utility::qualTypeToDataType(templateArgumentList.get(i).getAsType()); - // if (datatype.isTemplateParameterType()) - // { - // specializedParameterNamePart += baseTemplateDecl->getTemplateParameters()->getParam(i)->getNameAsString(); - // } - // else - // { - // specializedParameterNamePart += datatype.getFullTypeName(); - // } - // specializedParameterNamePart += (i < templateArgumentList.size() - 1) ? ", " : ""; - //} - //specializedParameterNamePart += ">"; + clang::TemplateParameterList* parameterList = declaration->getTemplateParameters(); + for (size_t i = 0; i < parameterList->size(); i++) + { + clang::NamedDecl* namedDecl = parameterList->getParam(i); + if (hasValidLocation(namedDecl)) + { + m_client->onTemplateRecordParameterTypeParsed( + getParseLocationForNamedDecl(namedDecl), + namedDecl->getNameAsString(), + specializedRecordNameHierarchy + ); + } + } - //int foo = 0; + const clang::ASTTemplateArgumentListInfo* argumentInfoList = declaration->getTemplateArgsAsWritten(); + for (int i = 0; i < argumentInfoList->NumTemplateArgs; i++) + { + const clang::TemplateArgumentLoc& argumentLoc = argumentInfoList->operator[](i); + const clang::QualType argumentType = argumentLoc.getArgument().getAsType(); + + m_client->onTemplateRecordArgumentTypeParsed( + getParseLocation(argumentLoc.getSourceRange()), + utility::qualTypeToDataType(argumentType).getTypeNameHierarchy(), + specializedRecordNameHierarchy); + } } - return true; } diff --git a/src/lib/data/parser/cxx/utilityCxx.cpp b/src/lib/data/parser/cxx/utilityCxx.cpp index e397e6b7..b1ef2bf2 100644 --- a/src/lib/data/parser/cxx/utilityCxx.cpp +++ b/src/lib/data/parser/cxx/utilityCxx.cpp @@ -107,18 +107,22 @@ namespace utility std::vector getDeclNameHierarchy(clang::Decl* declaration) { - std::string declName = ""; + std::vector contextNameHierarchy; + if (declaration) + { + std::string declName = ""; - if (clang::isa(declaration)) - { - declName = getDeclName(clang::dyn_cast(declaration)); + if (clang::isa(declaration)) + { + declName = getDeclName(clang::dyn_cast(declaration)); + } + else + { + LOG_ERROR("unhandled declaration type"); + } + contextNameHierarchy = getContextNameHierarchy(declaration->getDeclContext()); + contextNameHierarchy.push_back(declName); } - else - { - LOG_ERROR("unhandled declaration type"); - } - std::vector contextNameHierarchy = getContextNameHierarchy(declaration->getDeclContext()); - contextNameHierarchy.push_back(declName); return contextNameHierarchy; } @@ -154,6 +158,19 @@ namespace utility { declName = getDeclName(templateClassDeclaration); } + else if (clang::isa(declaration)) + { + int templateArgumentCount = clang::dyn_cast(declaration)->getTemplateArgs().size(); + const clang::ASTTemplateArgumentListInfo* templateArgumentListInfo = clang::dyn_cast(declaration)->getTemplateArgsAsWritten(); + std::string specializedParameterNamePart = "<"; + for (int i = 0; i < templateArgumentCount; i++) + { + specializedParameterNamePart += templateArgumentListInfo->getTemplateArgs()[i].getArgument().getAsType().getAsString(); + specializedParameterNamePart += (i < templateArgumentCount - 1) ? ", " : ""; + } + specializedParameterNamePart += ">"; + declName += specializedParameterNamePart; + } else if (clang::isa(declaration)) { std::string specializedParameterNamePart = "<"; @@ -188,4 +205,21 @@ namespace utility } return declName; } + + std::vector getTemplateSpecializationParentNameHierarchy(clang::ClassTemplateSpecializationDecl* declaration) + { + std::vector specializationParentNameHierarchy; + llvm::PointerUnion pu = declaration->getSpecializedTemplateOrPartial(); + if (pu.is()) + { + clang::ClassTemplateDecl* specializedFromDecl = pu.get(); + specializationParentNameHierarchy = utility::getDeclNameHierarchy(specializedFromDecl); + } + else if (pu.is()) + { + clang::ClassTemplatePartialSpecializationDecl* specializedFromDecl = pu.get(); + specializationParentNameHierarchy = utility::getDeclNameHierarchy(specializedFromDecl); + } + return specializationParentNameHierarchy; + } } diff --git a/src/lib/data/parser/cxx/utilityCxx.h b/src/lib/data/parser/cxx/utilityCxx.h index 2220c642..c1149d53 100644 --- a/src/lib/data/parser/cxx/utilityCxx.h +++ b/src/lib/data/parser/cxx/utilityCxx.h @@ -7,6 +7,7 @@ #include "clang/AST/Type.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclTemplate.h" class DataType; @@ -17,6 +18,7 @@ namespace utility std::vector getDeclNameHierarchy(clang::Decl* declaration); std::vector getContextNameHierarchy(clang::DeclContext* declaration); std::string getDeclName(clang::NamedDecl* declaration); + std::vector getTemplateSpecializationParentNameHierarchy(clang::ClassTemplateSpecializationDecl* declaration); } #endif // UTILITY_CLANG_H diff --git a/src/lib/data/search/SearchNode.cpp b/src/lib/data/search/SearchNode.cpp index 882b6997..b5ccf14a 100644 --- a/src/lib/data/search/SearchNode.cpp +++ b/src/lib/data/search/SearchNode.cpp @@ -24,6 +24,18 @@ const std::string& SearchNode::getName() const return m_name; } +std::vector SearchNode::getNameHierarchy() const +{ + std::vector nameHierarchy; + const SearchNode* parent = getParent(); + if (parent) + { + nameHierarchy = parent->getNameHierarchy(); + } + nameHierarchy.push_back(getName()); + return nameHierarchy; +} + std::string SearchNode::getFullName() const { if (m_parent && m_parent->m_nameId) diff --git a/src/lib/data/search/SearchNode.h b/src/lib/data/search/SearchNode.h index f93f6493..1dad5d89 100644 --- a/src/lib/data/search/SearchNode.h +++ b/src/lib/data/search/SearchNode.h @@ -23,6 +23,7 @@ public: ~SearchNode(); const std::string& getName() const; + std::vector getNameHierarchy() const; std::string getFullName() const; Id getNameId() const; diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index d26040e3..c2351e47 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -1134,6 +1134,105 @@ public: TS_ASSERT_EQUALS(client->templateParameterTypes[1], "A::U <1:32 1:32>"); } + void test_cxx_parser_finds_template_argument_of_implicit_template_specialization() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + "};\n" + "int main()\n" + "{\n" + " A a;\n" + " return 0;\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_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->templateSpecializations.size(), 1); + TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A -> A <6:7 6:7>"); + } + + void test_cxx_parser_finds_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->templateSpecializations.size(), 1); + TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A -> A <6:7 6:7>"); + } + + void test_cxx_parser_finds_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->A::T <6:9 6:9>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A->int <6:12 6:12>"); + } + + void test_cxx_parser_finds_correct_name_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->classes.size(), 2); + TS_ASSERT_EQUALS(client->classes[0], "A <2:1 <2:7 2:7> 4:1>"); + 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( @@ -1148,7 +1247,7 @@ public: TS_ASSERT_EQUALS(client->fields[0], "private int A::foo <4:6 4:8>"); } - void test_cxx_parser_finds_correct_field_member_type_of_template_class_in_declaration() + void test_cxx_parser_finds_correct_type_of_field_member_of_template_class_in_declaration() { std::shared_ptr client = parseCode( "template \n" @@ -1162,7 +1261,7 @@ public: TS_ASSERT_EQUALS(client->fields[0], "private A::T A::foo <4:4 4:6>"); } - void test_cxx_parser_finds_template_class_specialization_with_non_template_argument() + void test_cxx_parser_finds_implicit_template_class_specialization() { std::shared_ptr client = parseCode( "template \n" @@ -1178,7 +1277,7 @@ public: TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A -> A <2:7 2:7>"); } - void test_cxx_parser_finds_class_inheritance_from_specialized_template_class() + void test_cxx_parser_finds_class_inheritance_from_implicit_template_class_specialization() { std::shared_ptr client = parseCode( "template \n" @@ -1196,7 +1295,7 @@ public: TS_ASSERT_EQUALS(client->inheritances[0], "B : public A <7:10 7:22>"); } - //void _____test_cxx_parser_finds_template_class_specialization_with_template_argument() + //___void test_cxx_parser_finds_template_class_specialization_with_template_argument() //{ // std::shared_ptr client = parseCode( // "template \n" @@ -1209,10 +1308,11 @@ public: // "class B: public A\n" // "{\n" // "};\n" + // "B bar;" // ); - - // TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1); - // TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A -> A <2:7 2:7>"); + // int i = 0; + // //TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1); + // //TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A -> A <2:7 2:7>"); //} void test_cxx_parser_finds_template_class_constructor_usage_of_field() @@ -1286,22 +1386,36 @@ public: TS_ASSERT_EQUALS(client->enumFields[1], "A::TestType::TEST_TWO <7:3 7:3>"); } - //void _____test_cxx_parser_finds_correct_field_member_type_of_nested_template_class_in_declaration() - //{ - // std::shared_ptr client = parseCode( - // "template \n" - // "class A\n" - // "{\n" - // " class B\n" - // " {\n" - // " T foo;\n" - // " };\n" - // "};\n" - // ); + void test_cxx_parser_finds_correct_field_member_type_of_nested_template_class_in_declaration_____typedef() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + " typedef T TempType;" + "};\n" + ); - // TS_ASSERT_EQUALS(client->fields.size(), 1); - // TS_ASSERT_EQUALS(client->fields[0], "private A::T A::B::foo <4:4 4:6>"); - //} + TS_ASSERT_EQUALS(client->typedefs.size(), 1); + TS_ASSERT_EQUALS(client->typedefs[0], "private A::T -> A::TempType <4:12 4:19>"); + } + + void test_cxx_parser_finds_correct_field_member_type_of_nested_template_class_in_declaration() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + " class B\n" + " {\n" + " T foo;\n" + " };\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->fields.size(), 1); + TS_ASSERT_EQUALS(client->fields[0], "private A::T A::B::foo <6:5 6:7>"); + } void test_cxx_parser_finds_correct_method_member_name_of_template_class_in_declaration() { @@ -1317,7 +1431,7 @@ public: TS_ASSERT_EQUALS(client->methods[0], "private int A::foo() <4:6 4:8>"); } - void test_cxx_parser_finds_correct_method_member_return_type_of_template_class_in_declaration() + void test_cxx_parser_finds_correct_method_return_type_of_template_class_in_declaration() { std::shared_ptr client = parseCode( "template \n" @@ -1331,6 +1445,10 @@ public: TS_ASSERT_EQUALS(client->methods[0], "private A::T A::foo() <4:4 4:6>"); } + + + + void test_cxx_parser_finds_template_parameter_type_of_template_function() { std::shared_ptr client = parseCode( @@ -1597,13 +1715,23 @@ private: return 0; } + virtual Id onTemplateRecordArgumentTypeParsed( + const ParseLocation& location, const std::vector& templateArgumentTypeNameHierarchy, + const std::vector& templateRecordNameHierarchy) + { + templateArgumentTypes.push_back( + addLocationSuffix(utility::join(templateRecordNameHierarchy, "::") + "->" + utility::join(templateArgumentTypeNameHierarchy, "::"), location) + ); + return 0; + } + virtual Id onTemplateRecordSpecializationParsed( const ParseLocation& location, const std::vector& specializedRecordNameHierarchy, - const RecordType specializedRecordType, const std::vector& templateRecordNameHierarchy) + const RecordType specializedRecordType, const std::vector& specializedFromNameHierarchy) { templateSpecializations.push_back( addLocationSuffix(std::string(specializedRecordType == ParserClient::RECORD_CLASS ? "class" : "struct") + " " + - utility::join(specializedRecordNameHierarchy, "::") + " -> " + utility::join(templateRecordNameHierarchy, "::"), location) + utility::join(specializedRecordNameHierarchy, "::") + " -> " + utility::join(specializedFromNameHierarchy, "::"), location) ); return 0; } @@ -1645,6 +1773,7 @@ private: std::vector usages; // for variables std::vector typeUses; // for types std::vector templateParameterTypes; + std::vector templateArgumentTypes; std::vector templateSpecializations; private: diff --git a/src/test/GraphTestSuite.h b/src/test/GraphTestSuite.h index a8a8ff5e..f4e79a72 100644 --- a/src/test/GraphTestSuite.h +++ b/src/test/GraphTestSuite.h @@ -1,6 +1,7 @@ #include "cxxtest/TestSuite.h" #include "data/graph/Graph.h" +#include "data/graph/token_component/TokenComponentName.h" class GraphTestSuite : public CxxTest::TestSuite { @@ -101,7 +102,7 @@ public: void test_nodes_are_nodes() { - Node a(Node::NODE_UNDEFINED, "A"); + Node a(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); TS_ASSERT(a.isNode()); TS_ASSERT(!a.isEdge()); @@ -109,8 +110,8 @@ public: void test_edges_are_edges() { - Node a(Node::NODE_UNDEFINED, "A"); - Node b(Node::NODE_UNDEFINED, "B"); + Node a(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); + Node b(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("B", "::"))); Edge e(Edge::EDGE_TYPE_OF, &a, &b); TS_ASSERT(!e.isNode()); @@ -119,27 +120,27 @@ public: void test_set_type_of_node_from_constructor() { - Node n(Node::NODE_FUNCTION, "A"); + Node n(Node::NODE_FUNCTION, std::make_shared(utility::splitToVector("A", "::"))); TS_ASSERT_EQUALS(Node::NODE_FUNCTION, n.getType()); } void test_set_type_of_node_from_undefined() { - Node n(Node::NODE_UNDEFINED, "A"); + Node n(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); n.setType(Node::NODE_CLASS); TS_ASSERT_EQUALS(Node::NODE_CLASS, n.getType()); } void test_can_not_change_type_of_node_after_it_was_set() { - Node n(Node::NODE_NAMESPACE, "A"); + Node n(Node::NODE_NAMESPACE, std::make_shared(utility::splitToVector("A", "::"))); n.setType(Node::NODE_CLASS); TS_ASSERT_DIFFERS(Node::NODE_CLASS, n.getType()); } void test_node_can_be_copied_and_keeps_same_id() { - Node n(Node::NODE_NAMESPACE, "A"); + Node n(Node::NODE_NAMESPACE, std::make_shared(utility::splitToVector("A", "::"))); Node n2(n); TS_ASSERT_DIFFERS(&n, &n2); @@ -150,15 +151,15 @@ public: void test_node_type_bit_masking() { - Node n(Node::NODE_NAMESPACE, "A"); + Node n(Node::NODE_NAMESPACE, std::make_shared(utility::splitToVector("A", "::"))); TS_ASSERT(n.isType(Node::NODE_FUNCTION | Node::NODE_NAMESPACE | Node::NODE_CLASS)); TS_ASSERT(!n.isType(Node::NODE_FUNCTION | Node::NODE_METHOD | Node::NODE_CLASS)); } void test_get_type_of_edges() { - Node a(Node::NODE_UNDEFINED, "A"); - Node b(Node::NODE_UNDEFINED, "B"); + Node a(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); + Node b(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("B", "::"))); Edge e(Edge::EDGE_TYPE_OF, &a, &b); TS_ASSERT_EQUALS(Edge::EDGE_TYPE_OF, e.getType()); @@ -166,8 +167,8 @@ public: void test_edge_can_be_copied_and_keeps_same_id() { - Node a(Node::NODE_UNDEFINED, "A"); - Node b(Node::NODE_UNDEFINED, "B"); + Node a(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); + Node b(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("B", "::"))); Edge e(Edge::EDGE_TYPE_OF, &a, &b); Edge e2(e, &a, &b); @@ -178,8 +179,8 @@ public: void test_edge_type_bit_masking() { - Node a(Node::NODE_UNDEFINED, "A"); - Node b(Node::NODE_UNDEFINED, "B"); + Node a(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); + Node b(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("B", "::"))); Edge e(Edge::EDGE_TYPE_OF, &a, &b); TS_ASSERT(e.isType(Edge::EDGE_MEMBER | Edge::EDGE_CALL | Edge::EDGE_TYPE_OF)); @@ -188,9 +189,9 @@ public: void test_node_finds_child_node() { - Node a(Node::NODE_UNDEFINED, "A"); - Node b(Node::NODE_UNDEFINED, "B"); - Node c(Node::NODE_UNDEFINED, "C"); + Node a(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); + Node b(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("B", "::"))); + Node c(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("C", "::"))); Edge e(Edge::EDGE_MEMBER, &a, &b); Edge e2(Edge::EDGE_MEMBER, &a, &c); @@ -207,9 +208,9 @@ public: void test_node_can_not_find_child_node() { - Node a(Node::NODE_UNDEFINED, "A"); - Node b(Node::NODE_UNDEFINED, "B"); - Node c(Node::NODE_UNDEFINED, "C"); + Node a(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); + Node b(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("B", "::"))); + Node c(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("C", "::"))); Edge e(Edge::EDGE_MEMBER, &a, &b); Edge e2(Edge::EDGE_MEMBER, &a, &c); @@ -225,9 +226,9 @@ public: void test_node_visits_child_nodes() { - Node a(Node::NODE_UNDEFINED, "A"); - Node b(Node::NODE_UNDEFINED, "B"); - Node c(Node::NODE_UNDEFINED, "C"); + Node a(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); + Node b(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("B", "::"))); + Node c(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("C", "::"))); Edge e(Edge::EDGE_MEMBER, &a, &b); Edge e2(Edge::EDGE_MEMBER, &a, &c); @@ -247,8 +248,8 @@ public: void test_graph_saves_nodes() { Graph graph; - Node a(Node::NODE_UNDEFINED, "A"); - Node b(Node::NODE_UNDEFINED, "B"); + Node a(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("A", "::"))); + Node b(Node::NODE_UNDEFINED, std::make_shared(utility::splitToVector("B", "::"))); graph.addNode(&a); graph.addNode(&b); @@ -269,8 +270,8 @@ public: { Graph graph; - Node a(Node::NODE_FUNCTION, "A"); - Node b(Node::NODE_FUNCTION, "B"); + Node a(Node::NODE_FUNCTION, std::make_shared(utility::splitToVector("A", "::"))); + Node b(Node::NODE_FUNCTION, std::make_shared(utility::splitToVector("B", "::"))); Edge e(Edge::EDGE_CALL, &a, &b);