diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 90a86b4c..7de310f7 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -490,43 +490,26 @@ Id Storage::onTypeUsageParsed(const ParseTypeUsage& type, const ParseVariable& v return edge->getId(); } -Id Storage::onTemplateRecordParameterTypeParsed( - const ParseLocation& location, const std::string& templateParameterTypeName, - const std::vector& templateRecordNameHierarchy -){ - 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); - m_graph.createEdge(Edge::EDGE_TEMPLATE_PARAMETER_OF, templateParameterNode, templateRecordNode); - - return templateParameterNode->getId(); -} - -Id Storage::onTemplateRecordArgumentTypeParsed( - const ParseLocation& location, const std::vector& templateArgumentTypeNameHierarchy, - const std::vector& templateRecordNameHierarchy -){ +Id Storage::onTemplateArgumentParsed( + const ParseLocation& location, const std::vector& argumentNameHierarchy, + const std::vector& templateNameHierarchy) +{ log( - "template record argument", - utility::join(templateArgumentTypeNameHierarchy, "::") + " -> " + utility::join(templateRecordNameHierarchy, "::"), + "template argument", + utility::join(argumentNameHierarchy, "::") + " -> " + utility::join(templateNameHierarchy, "::"), location ); - Node* templateArgumentNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateArgumentTypeNameHierarchy); - Node* templateRecordNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateRecordNameHierarchy); - m_graph.createEdge(Edge::EDGE_TEMPLATE_ARGUMENT_OF, templateArgumentNode, templateRecordNode); + Node* argumentNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, argumentNameHierarchy); + Node* templateNode = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateNameHierarchy); + m_graph.createEdge(Edge::EDGE_TEMPLATE_ARGUMENT_OF, argumentNode, templateNode); if (location.isValid()) { - addTokenLocation(templateArgumentNode, location); + addTokenLocation(argumentNode, location); } - return templateArgumentNode->getId(); + return argumentNode->getId(); } Id Storage::onTemplateDefaultArgumentTypeParsed( @@ -550,6 +533,23 @@ Id Storage::onTemplateDefaultArgumentTypeParsed( return templateDefaultArgumentNode->getId(); } +Id Storage::onTemplateRecordParameterTypeParsed( + const ParseLocation& location, const std::string& templateParameterTypeName, + const std::vector& templateRecordNameHierarchy +){ + 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); + m_graph.createEdge(Edge::EDGE_TEMPLATE_PARAMETER_OF, templateParameterNode, templateRecordNode); + + return templateParameterNode->getId(); +} + Id Storage::onTemplateRecordSpecializationParsed( const ParseLocation& location, const std::vector& specializedRecordNameHierarchy, const RecordType specializedRecordType, const std::vector& specializedFromNameHierarchy @@ -578,7 +578,7 @@ Id Storage::onTemplateRecordSpecializationParsed( Id Storage::onTemplateFunctionParameterTypeParsed( const ParseLocation& location, const std::string& templateParameterTypeName, const ParseFunction function ){ - log("function template type parameter", templateParameterTypeName, location); + log("template function type parameter", templateParameterTypeName, location); std::vector templateParameterTypeNameHierarchy; templateParameterTypeNameHierarchy.push_back(function.getFullName() + "::"+ templateParameterTypeName); diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 08e86de9..41c3bd06 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -84,19 +84,17 @@ public: virtual Id onTypeUsageParsed(const ParseTypeUsage& type, const ParseFunction& function); virtual Id onTypeUsageParsed(const ParseTypeUsage& type, const ParseVariable& variable); + virtual Id onTemplateArgumentParsed( + const ParseLocation& location, const std::vector& argumentNameHierarchy, + const std::vector& templateNameHierarchy); + virtual Id onTemplateDefaultArgumentTypeParsed( + const ParseTypeUsage& type, const std::vector& templateArgumentTypeNameHierarchy); 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 onTemplateDefaultArgumentTypeParsed( - const ParseTypeUsage& type, const std::vector& templateArgumentTypeNameHierarchy); - virtual Id onTemplateRecordSpecializationParsed( const ParseLocation& location, const std::vector& specializedRecordNameHierarchy, 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/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index 39305ae7..eae22cae 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -100,14 +100,14 @@ public: virtual Id onTypeUsageParsed(const ParseTypeUsage& type, const ParseFunction& function) = 0; virtual Id onTypeUsageParsed(const ParseTypeUsage& type, const ParseVariable& variable) = 0; + virtual Id onTemplateArgumentParsed( + const ParseLocation& location, const std::vector& argumentNameHierarchy, + const std::vector& templateNameHierarchy) = 0; + virtual Id onTemplateDefaultArgumentTypeParsed( + const ParseTypeUsage& type, const std::vector& templateArgumentTypeNameHierarchy) = 0; 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 onTemplateDefaultArgumentTypeParsed( - const ParseTypeUsage& type, const std::vector& templateArgumentTypeNameHierarchy) = 0; virtual Id onTemplateRecordSpecializationParsed( const ParseLocation& location, const std::vector& specializedRecordNameHierarchy, const RecordType specializedRecordType, const std::vector& specializedFromNameHierarchy) = 0; diff --git a/src/lib/data/parser/cxx/ASTVisitor.cpp b/src/lib/data/parser/cxx/ASTVisitor.cpp index 26a6a363..c05e181c 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -322,6 +322,7 @@ bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration) { clang::ClassTemplateSpecializationDecl* specializationDecl = *it; + // The specializationParent can be an indirect specialization of the ClassTemplate (by specializing a partial specialization). std::vector specializationParentNameHierarchy = utility::getTemplateSpecializationParentNameHierarchy(specializationDecl); ParserClient::RecordType specializedRecordType = specializationDecl->isStruct() ? ParserClient::RECORD_STRUCT : ParserClient::RECORD_CLASS; @@ -336,7 +337,7 @@ bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration) std::vector argumentNameHierarchy = utility::templateArgumentToDataType(argList.get(i)).getTypeNameHierarchy(); if (argumentNameHierarchy.size()) // FIXME: Some TemplateArgument kinds are not handled yet. { - m_client->onTemplateRecordArgumentTypeParsed( + m_client->onTemplateArgumentParsed( ParseLocation(), // TODO: Find a valid ParseLocation here! argumentNameHierarchy, specializedRecordNameHierarchy @@ -380,7 +381,7 @@ bool ASTVisitor::VisitClassTemplatePartialSpecializationDecl(clang::ClassTemplat const clang::TemplateArgumentLoc& argumentLoc = argumentInfoList->operator[](i); const clang::QualType argumentType = argumentLoc.getArgument().getAsType(); - m_client->onTemplateRecordArgumentTypeParsed( + m_client->onTemplateArgumentParsed( getParseLocation(argumentLoc.getSourceRange()), utility::qualTypeToDataType(argumentType).getTypeNameHierarchy(), specializedRecordNameHierarchy); @@ -391,21 +392,9 @@ bool ASTVisitor::VisitClassTemplatePartialSpecializationDecl(clang::ClassTemplat bool ASTVisitor::VisitFunctionTemplateDecl(clang::FunctionTemplateDecl *declaration) { + const ParseFunction templateFunction = getParseFunction(declaration); if (isLocatedInMainFile(declaration)) { - const ParseFunction templateFunction = getParseFunction(declaration->getTemplatedDecl()); - for (clang::FunctionTemplateDecl::spec_iterator it = declaration->specializations().begin(); it != declaration->specializations().end(); it++) - { - ParseLocation specializedFunctionLocation = getParseLocationForNamedDecl(*(it)); - ParseFunction specializedFunction = getParseFunction(*(it)); - m_client->onTemplateFunctionSpecializationParsed( - specializedFunctionLocation, - specializedFunction, - templateFunction); - - m_client->onFunctionParsed(specializedFunctionLocation, specializedFunction, getParseLocationOfFunctionBody(*(it))); - } - clang::TemplateParameterList* parameterList = declaration->getTemplateParameters(); for (size_t i = 0; i < parameterList->size(); i++) { @@ -423,7 +412,58 @@ bool ASTVisitor::VisitFunctionTemplateDecl(clang::FunctionTemplateDecl *declarat } } } + if (isLocatedInSourceFile(declaration)) + { + for (clang::FunctionTemplateDecl::spec_iterator it = declaration->specializations().begin(); it != declaration->specializations().end(); it++) + { + const clang::FunctionDecl* specializedFunctionDecl = *it; + ParseLocation specializedFunctionLocation = getParseLocationForNamedDecl(specializedFunctionDecl); + ParseFunction specializedFunction = getParseFunction(specializedFunctionDecl); + clang::FunctionTemplateSpecializationInfo* info = specializedFunctionDecl->getTemplateSpecializationInfo(); + if (info->getTemplateSpecializationKind() == clang::TSK_ExplicitSpecialization) + { + if (isLocatedInMainFile(declaration)) + { + m_client->onTemplateFunctionSpecializationParsed( + specializedFunctionLocation, + specializedFunction, + templateFunction); + + const clang::ASTTemplateArgumentListInfo* argumentInfoList = specializedFunctionDecl->getTemplateSpecializationArgsAsWritten(); + for (size_t i = 0; i < argumentInfoList->NumTemplateArgs; i++) + { + const clang::TemplateArgumentLoc& argumentLoc = argumentInfoList->operator[](i); + const clang::QualType argumentType = argumentLoc.getArgument().getAsType(); + + m_client->onTemplateArgumentParsed( + getParseLocation(argumentLoc.getSourceRange()), + utility::qualTypeToDataType(argumentType).getTypeNameHierarchy(), + specializedFunction.nameHierarchy); + } + } + } + else // info->getTemplateSpecializationKind() == clang::TSK_ImplicitInstantiation + { + m_client->onTemplateFunctionSpecializationParsed( + specializedFunctionLocation, + specializedFunction, + templateFunction); + + const clang::TemplateArgumentList* argumentList = specializedFunctionDecl->getTemplateSpecializationArgs(); + for (size_t i = 0; i < argumentList->size(); i++) + { + const clang::TemplateArgument& argument = argumentList->get(i); + const clang::QualType argumentType = argument.getAsType(); + + m_client->onTemplateArgumentParsed( + ParseLocation(), // TODO: get ParseLocation + utility::qualTypeToDataType(argumentType).getTypeNameHierarchy(), + specializedFunction.nameHierarchy); + } + } + } + } return true; } @@ -682,7 +722,7 @@ ParseLocation ASTVisitor::getParseLocation(const clang::SourceRange& sourceRange ); } -ParseLocation ASTVisitor::getParseLocationForNamedDecl(clang::NamedDecl* decl, const clang::SourceLocation& loc) const +ParseLocation ASTVisitor::getParseLocationForNamedDecl(const clang::NamedDecl* decl, const clang::SourceLocation& loc) const { const clang::SourceManager& sourceManager = m_context->getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(loc); @@ -696,12 +736,12 @@ ParseLocation ASTVisitor::getParseLocationForNamedDecl(clang::NamedDecl* decl, c ); } -ParseLocation ASTVisitor::getParseLocationForNamedDecl(clang::NamedDecl* decl) const +ParseLocation ASTVisitor::getParseLocationForNamedDecl(const clang::NamedDecl* decl) const { return getParseLocationForNamedDecl(decl, decl->getLocation()); } -ParseLocation ASTVisitor::getParseLocationOfFunctionBody(clang::FunctionDecl* decl) const +ParseLocation ASTVisitor::getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const { if (decl->hasBody() && decl->isThisDeclarationADefinition()) { @@ -818,3 +858,29 @@ ParseFunction ASTVisitor::getParseFunction(const clang::FunctionDecl* declaratio isConst ); } + +ParseFunction ASTVisitor::getParseFunction(const clang::FunctionTemplateDecl* declaration) const +{ + bool isStatic = false; + bool isConst = false; + + const clang::FunctionDecl* templatedDecl = declaration->getTemplatedDecl(); + if (clang::isa(templatedDecl)) + { + const clang::CXXMethodDecl* methodDecl = clang::dyn_cast(templatedDecl); + isStatic = methodDecl->isStatic(); + isConst = methodDecl->isConst(); + } + else + { + isStatic = templatedDecl->getStorageClass() == clang::SC_Static; + } + + return ParseFunction( + getParseTypeUsageOfReturnType(templatedDecl), + utility::getDeclNameHierarchy(declaration), + getParameters(templatedDecl), + isStatic, + isConst + ); +} diff --git a/src/lib/data/parser/cxx/ASTVisitor.h b/src/lib/data/parser/cxx/ASTVisitor.h index 1f5a5815..a25df801 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.h +++ b/src/lib/data/parser/cxx/ASTVisitor.h @@ -62,9 +62,9 @@ private: ParserClient::AccessType convertAccessType(clang::AccessSpecifier) const; ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const; - ParseLocation getParseLocationForNamedDecl(clang::NamedDecl* decl, const clang::SourceLocation& loc) const; - ParseLocation getParseLocationForNamedDecl(clang::NamedDecl* decl) const; - ParseLocation getParseLocationOfFunctionBody(clang::FunctionDecl* decl) const; + ParseLocation getParseLocationForNamedDecl(const clang::NamedDecl* decl, const clang::SourceLocation& loc) const; + ParseLocation getParseLocationForNamedDecl(const clang::NamedDecl* decl) const; + ParseLocation getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const; ParseLocation getParseLocationOfRecordBody(clang::CXXRecordDecl* decl) const; ParseTypeUsage getParseTypeUsage(clang::TypeLoc typeLoc, const clang::QualType& type) const; @@ -73,6 +73,7 @@ private: ParseVariable getParseVariable(const clang::DeclaratorDecl* declaration) const; ParseFunction getParseFunction(const clang::FunctionDecl* declaration) const; + ParseFunction getParseFunction(const clang::FunctionTemplateDecl* declaration) const; clang::ASTContext* m_context; ParserClient* m_client; diff --git a/src/lib/data/parser/cxx/utilityCxx.cpp b/src/lib/data/parser/cxx/utilityCxx.cpp index 3a6710a0..6a75c754 100644 --- a/src/lib/data/parser/cxx/utilityCxx.cpp +++ b/src/lib/data/parser/cxx/utilityCxx.cpp @@ -255,6 +255,27 @@ namespace utility declName += specializedParameterNamePart; } } + else if (clang::isa(declaration)) + { + clang::FunctionTemplateDecl* templateFunctionDeclaration = clang::dyn_cast(declaration)->getDescribedFunctionTemplate(); + if (templateFunctionDeclaration) + { + declName = getDeclName(templateFunctionDeclaration); + } + else if (clang::dyn_cast(declaration)->isFunctionTemplateSpecialization()) + { + std::string specializedParameterNamePart = "<"; + const clang::TemplateArgumentList* templateArgumentList = clang::dyn_cast(declaration)->getTemplateSpecializationArgs(); + for (size_t i = 0; i < templateArgumentList->size(); i++) + { + const clang::TemplateArgument& templateArgument = templateArgumentList->get(i); + specializedParameterNamePart += templateArgumentToDataType(templateArgument).getFullTypeName(); + specializedParameterNamePart += (i < templateArgumentList->size() - 1) ? ", " : ""; + } + specializedParameterNamePart += ">"; + declName += specializedParameterNamePart; + } + } else if (clang::isa(declaration)) { std::string templateParameterNamePart = "<"; diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 87e76975..e764b863 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -1564,7 +1564,7 @@ public: ); TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateParameterTypes[0], "test::T <1:20 1:20>"); + TS_ASSERT_EQUALS(client->templateParameterTypes[0], "test::T <1:20 1:20>"); } void test_cxx_parser_finds_implicit_specialization_of_template_function() @@ -1583,7 +1583,7 @@ public: ); TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1); - TS_ASSERT_EQUALS(client->templateSpecializations[0], "test -> test <2:3 2:6>"); + TS_ASSERT_EQUALS(client->templateSpecializations[0], "test -> test <2:3 2:6>"); } void test_cxx_parser_finds_explicit_specialization_of_template_function() @@ -1603,9 +1603,61 @@ public: ); TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1); - TS_ASSERT_EQUALS(client->templateSpecializations[0], "test -> test <8:5 8:8>"); + TS_ASSERT_EQUALS(client->templateSpecializations[0], "test -> test <8:5 8:8>"); } + void test_cxx_parser_finds_template_argument_of_explicit_specialization_of_template_function() + { + std::shared_ptr client = parseCode( + "template \n" + "void test()\n" + "{\n" + "};\n" + "\n" + "template <>\n" + "void test()\n" + "{\n" + "};\n" + ); + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test->int <7:11 7:11>"); + } + + void test_cxx_parser_finds_template_argument_of_implicit_specialization_of_template_function() + { + std::shared_ptr client = parseCode( + "template \n" + "void test()\n" + "{\n" + "};\n" + "\n" + "int main()\n" + "{\n" + " test();\n" + " return 1;\n" + "};\n" + ); + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test->int <0:0 0:0>"); + } + + void test_cxx_parser_finds_template_default_argument_type_of_template_function() + { + std::shared_ptr client = parseCode( + "template \n" + "void test()\n" + "{\n" + "};\n" + "\n" + "int main()\n" + "{\n" + " test();\n" + " return 1;\n" + "};\n" + ); + TS_ASSERT_EQUALS(client->templateDefaultArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateDefaultArgumentTypes[0], "int -> test::T <1:24 1:26>"); + } @@ -1823,17 +1875,7 @@ private: return 0; } - virtual Id onTemplateRecordParameterTypeParsed( - const ParseLocation& location, const std::string& templateParameterTypeName, - const std::vector& templateRecordNameHierarchy) - { - templateParameterTypes.push_back( - addLocationSuffix(utility::join(templateRecordNameHierarchy, "::") + "::" + templateParameterTypeName, location) - ); - return 0; - } - - virtual Id onTemplateRecordArgumentTypeParsed( + virtual Id onTemplateArgumentParsed( const ParseLocation& location, const std::vector& templateArgumentTypeNameHierarchy, const std::vector& templateRecordNameHierarchy) { @@ -1852,6 +1894,16 @@ private: return 0; } + virtual Id onTemplateRecordParameterTypeParsed( + const ParseLocation& location, const std::string& templateParameterTypeName, + const std::vector& templateRecordNameHierarchy) + { + templateParameterTypes.push_back( + addLocationSuffix(utility::join(templateRecordNameHierarchy, "::") + "::" + templateParameterTypeName, location) + ); + return 0; + } + virtual Id onTemplateRecordSpecializationParsed( const ParseLocation& location, const std::vector& specializedRecordNameHierarchy, const RecordType specializedRecordType, const std::vector& specializedFromNameHierarchy)