From ed4b6546f0e5198a46b49e95f5051c8f0b8d75ca Mon Sep 17 00:00:00 2001 From: malte_langkabel Date: Tue, 8 Dec 2015 10:29:21 +0100 Subject: [PATCH] logic: template argument handling * now Coati will also parse the body of an instantiated template function and follow calls to other template functions there. * Coati will parse template arguments at the point of implicit or explicit template instantiation and explicit template specialization. * refactored template handling in storage. --- bin/test/data/log/test_log.txt | 8 + src/lib/data/Storage.cpp | 14 +- src/lib/data/Storage.h | 4 +- src/lib/data/parser/ParserClient.h | 4 +- src/lib/data/parser/cxx/ASTBodyVisitor.cpp | 40 +- src/lib/data/parser/cxx/ASTBodyVisitor.h | 2 + .../data/parser/cxx/ASTBodyVisitorClient.h | 6 + src/lib/data/parser/cxx/ASTVisitor.cpp | 502 ++++++++++-------- src/lib/data/parser/cxx/ASTVisitor.h | 25 +- src/test/CxxParserTestSuite.h | 241 +++++++-- 10 files changed, 565 insertions(+), 281 deletions(-) diff --git a/bin/test/data/log/test_log.txt b/bin/test/data/log/test_log.txt index adb71dc0..9b094086 100644 --- a/bin/test/data/log/test_log.txt +++ b/bin/test/data/log/test_log.txt @@ -163,6 +163,14 @@ ConfigManager.cpp WARNING: value source/header_search_paths/header_search_path i ConfigManager.cpp WARNING: value source/header_search_paths/header_search_path is not present in config. ConfigManager.cpp WARNING: value source/header_search_paths/header_search_path is not present in config. ConfigManager.cpp WARNING: value source/header_search_paths/header_search_path is not present in config. +ConfigManager.cpp WARNING: value source/header_search_paths/header_search_path is not present in config. +ConfigManager.cpp WARNING: value source/header_search_paths/header_search_path is not present in config. +ConfigManager.cpp WARNING: value source/header_search_paths/header_search_path is not present in config. +ConfigManager.cpp WARNING: value source/header_search_paths/header_search_path is not present in config. +ConfigManager.cpp WARNING: value source/header_search_paths/header_search_path is not present in config. +ConfigManager.cpp WARNING: value source/header_search_paths/header_search_path is not present in config. +ConfigManager.cpp WARNING: value source/header_search_paths/header_search_path is not present in config. +ConfigManager.cpp WARNING: value source/header_search_paths/header_search_path is not present in config. Token.cpp ERROR: Location Id was not referenced by this Token. Edge.cpp ERROR: Edge type_of can't go from Node undefined to Node undefined Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 5a38eb06..dc88851f 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -531,16 +531,16 @@ Id Storage::onTypeUsageParsed(const ParseTypeUsage& typeUsage, const ParseVariab } Id Storage::onTemplateArgumentTypeOfTemplateRecordParsed( - const ParseLocation& location, const NameHierarchy& argumentNameHierarchy, - const NameHierarchy& templateNameHierarchy) + const ParseLocation& location, const NameHierarchy& argumentTypeNameHierarchy, + const NameHierarchy& templateNameHierarchy) { log( "template argument type", - argumentNameHierarchy.getFullName() + " -> " + templateNameHierarchy.getFullName(), + argumentTypeNameHierarchy.getFullName() + " -> " + templateNameHierarchy.getFullName(), location ); - Id argumentNodeId = addNodeHierarchy(Node::NODE_TYPE, argumentNameHierarchy, false); + Id argumentNodeId = addNodeHierarchy(Node::NODE_TYPE, argumentTypeNameHierarchy, false); // does not need a source location because this type that is already defined (and therefore has a location). Id templateNodeId = addNodeHierarchy(Node::NODE_TYPE, templateNameHierarchy, false); @@ -551,16 +551,16 @@ Id Storage::onTemplateArgumentTypeOfTemplateRecordParsed( } Id Storage::onTemplateArgumentTypeOfTemplateFunctionParsed( - const ParseLocation& location, const NameHierarchy& argumentNameHierarchy, + const ParseLocation& location, const NameHierarchy& argumentTypeNameHierarchy, const ParseFunction& templateFunction) { log( "template argument type", - argumentNameHierarchy.getFullName() + " -> " + templateFunction.getFullName(), + argumentTypeNameHierarchy.getFullName() + " -> " + templateFunction.getFullName(), location ); - Id argumentNodeId = addNodeHierarchy(Node::NODE_TYPE, argumentNameHierarchy, false); + Id argumentNodeId = addNodeHierarchy(Node::NODE_TYPE, argumentTypeNameHierarchy, false); // does not need a source location because this type that is already defined (and therefore has a location). Id templateNodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, templateFunction, false); diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index e40e23b3..6b338bd0 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -101,10 +101,10 @@ public: virtual Id onTypeUsageParsed(const ParseTypeUsage& typeUsage, const ParseVariable& variable); virtual Id onTemplateArgumentTypeOfTemplateRecordParsed( - const ParseLocation& location, const NameHierarchy& argumentNameHierarchy, + const ParseLocation& location, const NameHierarchy& argumentTypeNameHierarchy, const NameHierarchy& templateNameHierarchy); virtual Id onTemplateArgumentTypeOfTemplateFunctionParsed( - const ParseLocation& location, const NameHierarchy& argumentNameHierarchy, + const ParseLocation& location, const NameHierarchy& argumentTypeNameHierarchy, const ParseFunction& templateFunction); virtual Id onTemplateDefaultArgumentTypeParsed( const ParseTypeUsage& defaultArgumentTypeUsage, const NameHierarchy& templateParameterNameHierarchy); diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index 0af8c6c2..60fdb301 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -117,10 +117,10 @@ public: virtual Id onTypeUsageParsed(const ParseTypeUsage& type, const ParseVariable& variable) = 0; virtual Id onTemplateArgumentTypeOfTemplateRecordParsed( - const ParseLocation& location, const NameHierarchy& argumentNameHierarchy, + const ParseLocation& location, const NameHierarchy& argumentTypeNameHierarchy, const NameHierarchy& templateNameHierarchy) = 0; virtual Id onTemplateArgumentTypeOfTemplateFunctionParsed( - const ParseLocation& location, const NameHierarchy& argumentNameHierarchy, + const ParseLocation& location, const NameHierarchy& argumentTypeNameHierarchy, const ParseFunction& templateFunction) = 0; virtual Id onTemplateDefaultArgumentTypeParsed( const ParseTypeUsage& type, const NameHierarchy& templateArgumentTypeNameHierarchy) = 0; diff --git a/src/lib/data/parser/cxx/ASTBodyVisitor.cpp b/src/lib/data/parser/cxx/ASTBodyVisitor.cpp index c0af6cd6..02488432 100644 --- a/src/lib/data/parser/cxx/ASTBodyVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTBodyVisitor.cpp @@ -81,6 +81,34 @@ void ASTBodyVisitor::VisitCXXConstructExpr(clang::CXXConstructExpr* expr) VisitStmt(expr); } +void ASTBodyVisitor::VisitExplicitCastExpr(clang::ExplicitCastExpr* expr) +{ + if (m_functionDecl) + { + m_client->VisitExplicitCastExprInDeclBody(m_functionDecl, expr); + } + else + { + m_client->VisitExplicitCastExprInDeclBody(m_varDecl, expr); + } + + VisitStmt(expr); +} + +void ASTBodyVisitor::VisitCXXTemporaryObjectExpr(clang::CXXTemporaryObjectExpr* expr) +{ + if (m_functionDecl) + { + m_client->VisitCXXTemporaryObjectExprInDeclBody(m_functionDecl, expr); + } + else + { + m_client->VisitCXXTemporaryObjectExprInDeclBody(m_varDecl, expr); + } + + VisitStmt(expr); +} + void ASTBodyVisitor::VisitCXXNewExpr(clang::CXXNewExpr* expr) { if (m_functionDecl) @@ -111,8 +139,17 @@ void ASTBodyVisitor::VisitMemberExpr(clang::make_ptr::type ex VisitStmt(expr); } -void ASTBodyVisitor::VisitDeclRefExpr(clang::make_ptr::type expr) +void ASTBodyVisitor::VisitDeclRefExpr(clang::DeclRefExpr* expr) { + if (m_functionDecl) + { + m_client->VisitDeclRefExprInDeclBody(m_functionDecl, expr); + } + else + { + m_client->VisitDeclRefExprInDeclBody(m_varDecl, expr); + } + if (expr->getDecl()->getKind() == clang::Decl::Var && expr->getDecl()->isDefinedOutsideFunctionOrMethod()) { if (m_functionDecl) @@ -135,6 +172,7 @@ void ASTBodyVisitor::VisitDeclRefExpr(clang::make_ptr::type m_client->VisitEnumExprInDeclBody(m_varDecl, expr); } } + VisitStmt(expr); } diff --git a/src/lib/data/parser/cxx/ASTBodyVisitor.h b/src/lib/data/parser/cxx/ASTBodyVisitor.h index 41087aa8..c509eb4b 100644 --- a/src/lib/data/parser/cxx/ASTBodyVisitor.h +++ b/src/lib/data/parser/cxx/ASTBodyVisitor.h @@ -15,6 +15,8 @@ public: void VisitChildren(clang::Stmt* stmt); void VisitCallExpr(clang::CallExpr* expr); void VisitCXXConstructExpr(clang::CXXConstructExpr* expr); + void VisitExplicitCastExpr(clang::ExplicitCastExpr* expr); + void VisitCXXTemporaryObjectExpr(clang::CXXTemporaryObjectExpr* expr); void VisitCXXNewExpr(clang::CXXNewExpr* expr); void VisitMemberExpr(clang::make_ptr::type expr); void VisitDeclRefExpr(clang::make_ptr::type expr); diff --git a/src/lib/data/parser/cxx/ASTBodyVisitorClient.h b/src/lib/data/parser/cxx/ASTBodyVisitorClient.h index 0aa0df26..21dd6d90 100644 --- a/src/lib/data/parser/cxx/ASTBodyVisitorClient.h +++ b/src/lib/data/parser/cxx/ASTBodyVisitorClient.h @@ -13,8 +13,14 @@ public: virtual void VisitCallExprInDeclBody(clang::FunctionDecl* decl, clang::CallExpr* expr) = 0; virtual void VisitCallExprInDeclBody(clang::DeclaratorDecl* decl, clang::CallExpr* expr) = 0; + virtual void VisitDeclRefExprInDeclBody(clang::FunctionDecl* decl, clang::DeclRefExpr* expr) = 0; + virtual void VisitDeclRefExprInDeclBody(clang::DeclaratorDecl* decl, clang::DeclRefExpr* expr) = 0; virtual void VisitCXXConstructExprInDeclBody(clang::FunctionDecl* decl, clang::CXXConstructExpr* expr) = 0; virtual void VisitCXXConstructExprInDeclBody(clang::DeclaratorDecl* decl, clang::CXXConstructExpr* expr) = 0; + virtual void VisitExplicitCastExprInDeclBody(clang::FunctionDecl* decl, clang::ExplicitCastExpr* expr) = 0; + virtual void VisitExplicitCastExprInDeclBody(clang::DeclaratorDecl* decl, clang::ExplicitCastExpr* expr) = 0; + virtual void VisitCXXTemporaryObjectExprInDeclBody(clang::FunctionDecl* decl, clang::CXXTemporaryObjectExpr* expr) = 0; + virtual void VisitCXXTemporaryObjectExprInDeclBody(clang::DeclaratorDecl* decl, clang::CXXTemporaryObjectExpr* expr) = 0; virtual void VisitCXXNewExprInDeclBody(clang::FunctionDecl* decl, clang::CXXNewExpr* expr) = 0; virtual void VisitCXXNewExprInDeclBody(clang::DeclaratorDecl* decl, clang::CXXNewExpr* expr) = 0; virtual void VisitMemberExprInDeclBody(clang::FunctionDecl* decl, clang::MemberExpr* expr) = 0; diff --git a/src/lib/data/parser/cxx/ASTVisitor.cpp b/src/lib/data/parser/cxx/ASTVisitor.cpp index d81bcc33..33baaaca 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -84,6 +84,8 @@ bool ASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* declaration) utility::qualTypeToDataType(it.getType())->getTypeNameHierarchy(), convertAccessType(it.getAccessSpecifier()) ); + + // TODO: check for template class and add arguments! } } } @@ -158,17 +160,21 @@ bool ASTVisitor::VisitFunctionDecl(clang::FunctionDecl* declaration) if (isLocatedInUnparsedProjectFile(declaration)) { - m_client->onFunctionParsed( - getParseLocationForNamedDecl(declaration), - getParseFunction(declaration), - getParseLocationOfFunctionBody(declaration) - ); + processFunctionDecl(declaration); + } - if (declaration->hasBody() && declaration->isThisDeclarationADefinition()) - { - ASTBodyVisitor bodyVisitor(this, declaration); - bodyVisitor.Visit(declaration->getBody()); - } + return true; +} + +bool ASTVisitor::VisitParmVarDecl(clang::ParmVarDecl* declaration) +{ + // todo: handle parameters here! + // maybe handle template args in visitvardecl to account for local variables and stuff... + clang::TypeLoc loc = declaration->getTypeSourceInfo()->getTypeLoc(); + clang::TypeLoc::TypeLocClass ssd = loc.getTypeLocClass(); + if (loc.getTypeLocClass() == clang::TypeLoc::TypeLocClass::TemplateSpecialization) + { + processTemplateArguments(loc.getAs()); } return true; @@ -195,7 +201,8 @@ bool ASTVisitor::VisitCXXMethodDecl(clang::CXXMethodDecl* declaration) m_client->onMethodOverrideParsed(location, getParseFunction(*it), parseFunction); } - if (declaration->hasBody() && declaration->getBody() != NULL && declaration->isThisDeclarationADefinition()) + if (declaration->hasBody() && declaration->getBody() != NULL && declaration->isThisDeclarationADefinition() && + !declaration->isDependentContext()) { ASTBodyVisitor bodyVisitor(this, declaration); bodyVisitor.Visit(declaration->getBody()); @@ -226,11 +233,9 @@ bool ASTVisitor::VisitCXXConstructorDecl(clang::CXXConstructorDecl* declaration) else if (init->isBaseInitializer()) { m_client->onTypeUsageParsed( - getParseTypeUsage(init->getTypeSourceInfo()->getTypeLoc(), init->getTypeSourceInfo()->getType()), + getParseTypeUsage(init->getTypeSourceInfo()->getTypeLoc(), init->getTypeSourceInfo()->getType()), // TODO: rewrite this to old! getParseFunction(declaration) ); - - saveClassTemplateArgumentTypeUsages(init->getTypeSourceInfo(), getParseFunction(declaration)); } ASTBodyVisitor bodyVisitor(this, declaration); @@ -246,7 +251,7 @@ bool ASTVisitor::VisitNamespaceDecl(clang::NamespaceDecl* declaration) if (isLocatedInUnparsedProjectFile(declaration)) { m_client->onNamespaceParsed( - declaration->isAnonymousNamespace() ? ParseLocation() : getParseLocationForNamedDecl(declaration), + declaration->isAnonymousNamespace() ? ParseLocation() : getParseLocationForNamedDecl(declaration), // TODO: why no real parse loc for anonymous namespace? utility::getDeclNameHierarchy(declaration), getParseLocation(declaration->getSourceRange()) ); @@ -298,7 +303,9 @@ bool ASTVisitor::VisitTemplateTemplateParmDecl(clang::TemplateTemplateParmDecl * { const clang::TemplateArgumentLoc& defaultArgumentLoc = declaration->getDefaultArgument(); clang::SourceRange sr = defaultArgumentLoc.getSourceRange(); - std::shared_ptr defaultArgumentDataType = std::make_shared(utility::getDeclNameHierarchy(defaultArgumentLoc.getArgument().getAsTemplate().getAsTemplateDecl())); + std::shared_ptr defaultArgumentDataType = std::make_shared( + utility::getDeclNameHierarchy(defaultArgumentLoc.getArgument().getAsTemplate().getAsTemplateDecl()) + ); m_client->onTemplateDefaultArgumentTypeParsed( getParseTypeUsage(sr, defaultArgumentDataType), utility::getDeclNameHierarchy(declaration) @@ -342,28 +349,9 @@ bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration) } // handling template arguments - std::string specializationFilePath = specializationLocation.filePath.str(); - if (!isLocatedInProjectFile(specializationLocation)) + if (isLocatedInUnparsedProjectFile(specializationDecl) && specializationDecl->isExplicitSpecialization()) { - specializationFilePath = ""; - } - - const clang::TemplateArgumentList& argList = specializationDecl->getTemplateArgs(); - for (size_t i = 0; i < argList.size(); i++) - { - const clang::TemplateArgument& argument = argList.get(i); - if (needsToAddTemplateArgument(argument, declaration)) - { - NameHierarchy argumentNameHierarchy = utility::templateArgumentToDataType(argument)->getTypeNameHierarchy(); - if (argumentNameHierarchy.size()) // FIXME: Some TemplateArgument kinds are not handled yet. - { - m_client->onTemplateArgumentTypeOfTemplateRecordParsed( - ParseLocation(specializationFilePath, 0, 0), // TODO: get a better location here! - argumentNameHierarchy, - specializationNameHierarchy - ); - } - } + processTemplateArgumentsOfExplicitSpecialization(specializationDecl); } if (isLocatedInProjectFile(declaration)) @@ -434,17 +422,7 @@ bool ASTVisitor::VisitClassTemplatePartialSpecializationDecl(clang::ClassTemplat } } - const clang::ASTTemplateArgumentListInfo* argumentInfoList = declaration->getTemplateArgsAsWritten(); - for (size_t i = 0; i < argumentInfoList->NumTemplateArgs; i++) - { - const clang::TemplateArgumentLoc& argumentLoc = argumentInfoList->operator[](i); - const clang::TemplateArgument& argument = argumentLoc.getArgument(); - - m_client->onTemplateArgumentTypeOfTemplateRecordParsed( - getParseLocation(argumentLoc.getSourceRange()), - utility::templateArgumentToDataType(argument)->getTypeNameHierarchy(), - specializedRecordNameHierarchy); - } + processTemplateArgumentsOfExplicitSpecialization(declaration); } return true; } @@ -471,108 +449,41 @@ bool ASTVisitor::VisitFunctionTemplateDecl(clang::FunctionTemplateDecl *declarat for (clang::FunctionTemplateDecl::spec_iterator it = declaration->specializations().begin(); it != declaration->specializations().end(); it++) { - const clang::FunctionDecl* specializationDecl = *it; - ParseLocation specializationLocation = getParseLocationForNamedDecl(specializationDecl); - ParseFunction specializationFunction = getParseFunction(specializationDecl); + clang::FunctionDecl* specializationDecl = *it; + bool needsToProcessSpecialization = false; if (specializationDecl->getTemplateSpecializationKind() == clang::TSK_ExplicitSpecialization) { if (isLocatedInUnparsedProjectFile(declaration)) { - m_client->onTemplateFunctionSpecializationParsed( - specializationLocation, - specializationFunction, - templateFunction - ); - } - if (specializationDecl->getTemplateSpecializationArgsAsWritten()) - { - const clang::ASTTemplateArgumentListInfo* argumentInfoList = specializationDecl->getTemplateSpecializationArgsAsWritten(); - for (size_t i = 0; i < argumentInfoList->NumTemplateArgs; i++) - { - const clang::TemplateArgumentLoc& argumentLoc = argumentInfoList->operator[](i); - - const clang::TemplateArgument& argument = argumentLoc.getArgument(); - if (needsToAddTemplateArgument(argument, declaration)) - { - NameHierarchy argumentNameHierarchy = utility::templateArgumentToDataType(argument)->getTypeNameHierarchy(); - if (argumentNameHierarchy.size()) // FIXME: Some TemplateArgument kinds are not handled yet. - { - m_client->onTemplateArgumentTypeOfTemplateFunctionParsed( - getParseLocation(argumentLoc.getSourceRange()), - argumentNameHierarchy, - specializationFunction - ); - } - } - } - } - else - { - const clang::TemplateArgumentList* argumentList = specializationDecl->getTemplateSpecializationArgs(); - for(size_t i = 0; i < argumentList->size(); ++i) - { - const clang::TemplateArgument& argument = argumentList->get(i); - const clang::TemplateArgumentLoc& argumentLoc = clang::TemplateArgumentLoc(argument, specializationDecl->getTypeSourceInfo()); - - if (needsToAddTemplateArgument(argument, declaration)) - { - NameHierarchy argumentNameHierarchy = utility::templateArgumentToDataType(argument)->getTypeNameHierarchy(); - if (argumentNameHierarchy.size()) // FIXME: Some TemplateArgument kinds are not handled yet. - { - m_client->onTemplateArgumentTypeOfTemplateFunctionParsed( - getParseLocation(argumentLoc.getSourceRange()), - argumentNameHierarchy, - specializationFunction - ); - } - } - } + processTemplateArgumentsOfExplicitSpecialization(specializationDecl); + needsToProcessSpecialization = true; } } - else // if (info->getTemplateSpecializationKind() == clang::TSK_ImplicitInstantiation) + else if (isLocatedInProjectFile(declaration)) { - if (isLocatedInProjectFile(declaration)) - { - m_client->onTemplateFunctionSpecializationParsed( - specializationLocation, - specializationFunction, - templateFunction - ); - } - - // handling template arguments - std::string specializationFilePath = specializationLocation.filePath.str(); - if (!isLocatedInProjectFile(specializationLocation)) - { - specializationFilePath = ""; - } - - const clang::TemplateArgumentList* argumentList = specializationDecl->getTemplateSpecializationArgs(); - for (size_t i = 0; i < argumentList->size(); i++) - { - const clang::TemplateArgument& argument = argumentList->get(i); - if (needsToAddTemplateArgument(argument, declaration)) - { - NameHierarchy argumentNameHierarchy = utility::templateArgumentToDataType(argument)->getTypeNameHierarchy(); - if (argumentNameHierarchy.size()) // FIXME: Some TemplateArgument kinds are not handled yet. - { - m_client->onTemplateArgumentTypeOfTemplateFunctionParsed( - ParseLocation(specializationFilePath, 0, 0), // TODO: get a better location here! - argumentNameHierarchy, - specializationFunction - ); - } - } - } + needsToProcessSpecialization = true; } + + if (needsToProcessSpecialization) + { + processFunctionDecl(specializationDecl); + + m_client->onTemplateFunctionSpecializationParsed( + getParseLocationForNamedDecl(specializationDecl), + getParseFunction(specializationDecl), + templateFunction + ); + } + } return true; } void ASTVisitor::VisitCallExprInDeclBody(clang::FunctionDecl* decl, clang::CallExpr* expr) { - if (!expr->getDirectCallee()) + clang::FunctionDecl* calleeFunctionDecl = expr->getDirectCallee(); + if (!calleeFunctionDecl) { // TODO: Save error at location. return; @@ -581,11 +492,8 @@ void ASTVisitor::VisitCallExprInDeclBody(clang::FunctionDecl* decl, clang::CallE m_client->onCallParsed( getParseLocation(expr->getSourceRange()), getParseFunction(decl), - getParseFunction(expr->getDirectCallee()) + getParseFunction(calleeFunctionDecl) ); - - saveFunctionTemplateArgumentTypeUsages( - expr->getDirectCallee(), expr->getSourceRange(), getParseFunction(decl)); } void ASTVisitor::VisitCallExprInDeclBody(clang::DeclaratorDecl* decl, clang::CallExpr* expr) @@ -601,13 +509,22 @@ void ASTVisitor::VisitCallExprInDeclBody(clang::DeclaratorDecl* decl, clang::Cal getParseVariable(decl), getParseFunction(expr->getDirectCallee()) ); +} - saveFunctionTemplateArgumentTypeUsages( - expr->getDirectCallee(), expr->getSourceRange(), getParseVariable(decl)); + +void ASTVisitor::VisitDeclRefExprInDeclBody(clang::FunctionDecl* decl, clang::DeclRefExpr* expr) +{ + processTemplateArguments(expr); +} + +void ASTVisitor::VisitDeclRefExprInDeclBody(clang::DeclaratorDecl* decl, clang::DeclRefExpr* expr) +{ + processTemplateArguments(expr); } void ASTVisitor::VisitCXXConstructExprInDeclBody(clang::FunctionDecl* decl, clang::CXXConstructExpr* expr) { + // TODO: refactor this code! std::string caller = decl->getNameAsString(); std::string callee = expr->getConstructor()->getNameAsString(); clang::SourceRange sourceRange = expr->getSourceRange(); @@ -659,9 +576,6 @@ void ASTVisitor::VisitCXXConstructExprInDeclBody(clang::FunctionDecl* decl, clan getParseFunction(decl), getParseFunction(expr->getConstructor()) ); - - saveFunctionTemplateArgumentTypeUsages( - expr->getConstructor(), expr->getSourceRange(), getParseFunction(decl)); } void ASTVisitor::VisitCXXConstructExprInDeclBody(clang::DeclaratorDecl* decl, clang::CXXConstructExpr* expr) @@ -671,9 +585,42 @@ void ASTVisitor::VisitCXXConstructExprInDeclBody(clang::DeclaratorDecl* decl, cl getParseVariable(decl), getParseFunction(expr->getConstructor()) ); +} - saveFunctionTemplateArgumentTypeUsages( - expr->getConstructor(), expr->getSourceRange(), getParseVariable(decl)); +void ASTVisitor::VisitExplicitCastExprInDeclBody(clang::FunctionDecl* decl, clang::ExplicitCastExpr* expr) +{ + clang::TypeLoc loc = expr->getTypeInfoAsWritten()->getTypeLoc(); + if (loc.getTypeLocClass() == clang::TypeLoc::TypeLocClass::TemplateSpecialization) + { + processTemplateArguments(loc.getAs()); + } +} + +void ASTVisitor::VisitExplicitCastExprInDeclBody(clang::DeclaratorDecl* decl, clang::ExplicitCastExpr* expr) +{ + clang::TypeLoc loc = expr->getTypeInfoAsWritten()->getTypeLoc(); + if (loc.getTypeLocClass() == clang::TypeLoc::TypeLocClass::TemplateSpecialization) + { + processTemplateArguments(loc.getAs()); + } +} + +void ASTVisitor::VisitCXXTemporaryObjectExprInDeclBody(clang::FunctionDecl* decl, clang::CXXTemporaryObjectExpr* expr) +{ + clang::TypeLoc loc = expr->getTypeSourceInfo()->getTypeLoc(); + if (loc.getTypeLocClass() == clang::TypeLoc::TypeLocClass::TemplateSpecialization) + { + processTemplateArguments(loc.getAs()); + } +} + +void ASTVisitor::VisitCXXTemporaryObjectExprInDeclBody(clang::DeclaratorDecl* decl, clang::CXXTemporaryObjectExpr* expr) +{ + clang::TypeLoc loc = expr->getTypeSourceInfo()->getTypeLoc(); + if (loc.getTypeLocClass() == clang::TypeLoc::TypeLocClass::TemplateSpecialization) + { + processTemplateArguments(loc.getAs()); + } } void ASTVisitor::VisitCXXNewExprInDeclBody(clang::FunctionDecl* decl, clang::CXXNewExpr* expr) @@ -683,7 +630,11 @@ void ASTVisitor::VisitCXXNewExprInDeclBody(clang::FunctionDecl* decl, clang::CXX getParseFunction(decl) ); - saveClassTemplateArgumentTypeUsages(expr->getAllocatedTypeSourceInfo(), getParseFunction(decl)); + clang::TypeLoc loc = expr->getAllocatedTypeSourceInfo()->getTypeLoc(); + if (loc.getTypeLocClass() == clang::TypeLoc::TypeLocClass::TemplateSpecialization) + { + processTemplateArguments(loc.getAs()); + } } void ASTVisitor::VisitCXXNewExprInDeclBody(clang::DeclaratorDecl* decl, clang::CXXNewExpr* expr) @@ -693,7 +644,11 @@ void ASTVisitor::VisitCXXNewExprInDeclBody(clang::DeclaratorDecl* decl, clang::C getParseVariable(decl) ); - saveClassTemplateArgumentTypeUsages(expr->getAllocatedTypeSourceInfo(), getParseVariable(decl)); + clang::TypeLoc loc = expr->getAllocatedTypeSourceInfo()->getTypeLoc(); + if (loc.getTypeLocClass() == clang::TypeLoc::TypeLocClass::TemplateSpecialization) + { + processTemplateArguments(loc.getAs()); + } } void ASTVisitor::VisitMemberExprInDeclBody(clang::FunctionDecl* decl, clang::MemberExpr* expr) @@ -787,7 +742,182 @@ void ASTVisitor::VisitVarDeclInDeclBody(clang::FunctionDecl* decl, clang::VarDec getParseFunction(decl) ); - saveClassTemplateArgumentTypeUsages(varDecl->getTypeSourceInfo(), getParseFunction(decl)); + clang::TypeLoc loc = varDecl->getTypeSourceInfo()->getTypeLoc(); + if (loc.getTypeLocClass() == clang::TypeLoc::TypeLocClass::TemplateSpecialization) + { + processTemplateArguments(loc.getAs()); + } +} + +void ASTVisitor::processFunctionDecl(clang::FunctionDecl* declaration) +{ + m_client->onFunctionParsed( + getParseLocationForNamedDecl(declaration), + getParseFunction(declaration), + getParseLocationOfFunctionBody(declaration) + ); + + // handle template arguments of return type. + clang::TypeLoc functionLoc = declaration->getTypeSourceInfo()->getTypeLoc(); + if (functionLoc.getTypeLocClass() == clang::TypeLoc::TypeLocClass::FunctionProto) + { + clang::TypeLoc returnLoc = functionLoc.getAs().getReturnLoc(); + if (returnLoc.getTypeLocClass() == clang::TypeLoc::TypeLocClass::TemplateSpecialization) + { + processTemplateArguments(returnLoc.getAs()); + } + } + + + if (declaration->hasBody() && + declaration->isThisDeclarationADefinition() && + !declaration->isDependentContext() + ) + { + ASTBodyVisitor bodyVisitor(this, declaration); + bodyVisitor.Visit(declaration->getBody()); + } +} + +void ASTVisitor::processTemplateArgumentsOfExplicitSpecialization(clang::FunctionDecl* specializationDecl) +{ + ParseFunction specializationFunction = getParseFunction(specializationDecl); + + if (specializationDecl->getTemplateSpecializationArgsAsWritten()) + { + const clang::ASTTemplateArgumentListInfo* argumentInfoList = specializationDecl->getTemplateSpecializationArgsAsWritten(); + for (size_t i = 0; i < argumentInfoList->NumTemplateArgs; i++) + { + const clang::TemplateArgumentLoc& argumentLoc = argumentInfoList->operator[](i); + + const clang::TemplateArgument& argument = argumentLoc.getArgument(); + NameHierarchy argumentNameHierarchy = utility::templateArgumentToDataType(argument)->getTypeNameHierarchy(); + if (argumentNameHierarchy.size()) // FIXME: Some TemplateArgument kinds are not handled yet. + { + m_client->onTemplateArgumentTypeOfTemplateFunctionParsed( + getParseLocation(argumentLoc.getSourceRange()), + argumentNameHierarchy, + specializationFunction + ); + } + } + } +} + +void ASTVisitor::processTemplateArgumentsOfExplicitSpecialization(clang::ClassTemplateSpecializationDecl* specializationDecl) +{ + NameHierarchy specializedRecordNameHierarchy = utility::getDeclNameHierarchy(specializationDecl); + if (clang::ClassTemplatePartialSpecializationDecl* partialSpecializationDecl = + clang::dyn_cast_or_null(specializationDecl)) + { + const clang::ASTTemplateArgumentListInfo* argumentInfoList = partialSpecializationDecl->getTemplateArgsAsWritten(); + for (size_t i = 0; i < argumentInfoList->NumTemplateArgs; i++) + { + const clang::TemplateArgumentLoc& argumentLoc = argumentInfoList->operator[](i); + const clang::TemplateArgument& argument = argumentLoc.getArgument(); + + NameHierarchy argumentNameHierarchy = utility::templateArgumentToDataType(argument)->getTypeNameHierarchy(); + if (argumentNameHierarchy.size()) // FIXME: Some TemplateArgument kinds are not handled yet. + { + m_client->onTemplateArgumentTypeOfTemplateRecordParsed( + getParseLocationForTokensInRange(argumentLoc.getSourceRange()), + argumentNameHierarchy, + specializedRecordNameHierarchy + ); + } + } + } + else + { + clang::TypeLoc loc = specializationDecl->getTypeAsWritten()->getTypeLoc(); + if (loc.getTypeLocClass() == clang::TypeLoc::TypeLocClass::TemplateSpecialization) + { + processTemplateArguments(loc.getAs()); + } + } +} + +void ASTVisitor::processTemplateArguments(clang::DeclRefExpr* expr) +{ + if (!isLocatedInProjectFile(getParseLocation(expr->getSourceRange()))) + { + return; + } + clang::FunctionDecl* specializationDecl = clang::dyn_cast_or_null(expr->getDecl()); + if (!specializationDecl) + { + return; + } + clang::FunctionTemplateDecl* specializedDecl = specializationDecl->getPrimaryTemplate(); // just to check if it is really a template.. can be done differently + if (!specializedDecl) + { + return; + } + + ParseFunction specializationFunction = getParseFunction(specializationDecl); + + if (expr->hasExplicitTemplateArgs()) // handle explicit template args + { + const clang::TemplateArgumentLoc* arguments = expr->getTemplateArgs(); + + for (unsigned int i = 0; i < expr->getNumTemplateArgs(); i++) + { + clang::TemplateArgument argument = arguments[i].getArgument(); + NameHierarchy argumentNameHierarchy = utility::templateArgumentToDataType(argument)->getTypeNameHierarchy(); + if (argumentNameHierarchy.size()) // FIXME: Some TemplateArgument kinds are not handled yet. + { + m_client->onTemplateArgumentTypeOfTemplateFunctionParsed( + getParseLocation(arguments[i].getSourceRange()), + argumentNameHierarchy, + specializationFunction + ); + } + } + } + else // handle implicit template args + { + const clang::TemplateArgumentList* argumentList = specializationDecl->getTemplateSpecializationArgs(); + for (size_t i = 0; i < argumentList->size(); ++i) + { + const clang::TemplateArgument& argument = argumentList->get(i); + NameHierarchy argumentNameHierarchy = utility::templateArgumentToDataType(argument)->getTypeNameHierarchy(); + if (argumentNameHierarchy.size()) // FIXME: Some TemplateArgument kinds are not handled yet. + { + const clang::SourceLocation argumentSourceLoc = clang::Lexer::getLocForEndOfToken( + expr->getLocEnd(), 1, m_context->getSourceManager(), clang::LangOptions() + ); + m_client->onTemplateArgumentTypeOfTemplateFunctionParsed( + getParseLocation(clang::SourceRange(argumentSourceLoc, argumentSourceLoc)), + argumentNameHierarchy, + specializationFunction + ); + } + } + } +} + +void ASTVisitor::processTemplateArguments(clang::TemplateSpecializationTypeLoc loc) +{ + NameHierarchy specializationNameHierarchy = utility::qualTypeToDataType(loc.getType())->getTypeNameHierarchy(); + + if (!isLocatedInProjectFile(getParseLocation(loc.getSourceRange()))) + { + return; + } + + for (unsigned int i = 0; i < loc.getNumArgs(); i++) + { + const clang::TemplateArgument& argument = loc.getArgLoc(i).getArgument(); + NameHierarchy argumentNameHierarchy = utility::templateArgumentToDataType(argument)->getTypeNameHierarchy(); + if (argumentNameHierarchy.size()) // FIXME: Some TemplateArgument kinds are not handled yet. + { + m_client->onTemplateArgumentTypeOfTemplateRecordParsed( + getParseLocationForTokensInRange(loc.getArgLoc(i).getSourceRange()), + argumentNameHierarchy, + specializationNameHierarchy + ); + } + } } bool ASTVisitor::isLocatedInUnparsedProjectFile(const clang::Decl* declaration) const @@ -828,23 +958,6 @@ bool ASTVisitor::isLocatedInProjectFile(const clang::Decl* declaration) const return false; } -bool ASTVisitor::needsToAddTemplateArgument(const clang::TemplateArgument& argument, const clang::Decl* specializedDecl) -{ - bool addArgument = isLocatedInProjectFile(specializedDecl); - if (!addArgument) - { - if (argument.getKind() == clang::TemplateArgument::Type) - { - clang::TagDecl *argumentDecl = argument.getAsType()->getAsTagDecl(); - if (argumentDecl && isLocatedInProjectFile(getParseLocation(argumentDecl->getSourceRange()))) - { - addArgument = true; - } - } - } - return addArgument; -} - ParserClient::AccessType ASTVisitor::convertAccessType(clang::AccessSpecifier access) const { switch (access) @@ -896,15 +1009,20 @@ ParseLocation ASTVisitor::getParseLocation(const clang::SourceRange& sourceRange ParseLocation ASTVisitor::getParseLocationForTokenAtLocation(const clang::SourceLocation& loc) const { - if (loc.isInvalid()) + return getParseLocationForTokensInRange(clang::SourceRange(loc, loc)); +} + +ParseLocation ASTVisitor::getParseLocationForTokensInRange(const clang::SourceRange& range) const +{ + if (range.isInvalid()) { return ParseLocation(); } const clang::SourceManager& sourceManager = m_context->getSourceManager(); - clang::SourceLocation startLoc = clang::Lexer::GetBeginningOfToken(loc, sourceManager, clang::LangOptions()); - clang::SourceLocation endLoc = clang::Lexer::getLocForEndOfToken(loc, 1, sourceManager, clang::LangOptions()); + clang::SourceLocation startLoc = clang::Lexer::GetBeginningOfToken(range.getBegin(), sourceManager, clang::LangOptions()); + clang::SourceLocation endLoc = clang::Lexer::getLocForEndOfToken(range.getEnd(), 1, sourceManager, clang::LangOptions()); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(startLoc); const clang::PresumedLoc& presumedEnd = sourceManager.getPresumedLoc(endLoc); @@ -1090,49 +1208,3 @@ ParseFunction ASTVisitor::getParseFunction(const clang::FunctionTemplateDecl* de { return getParseFunction(declaration->getTemplatedDecl()); } - -template -void ASTVisitor::saveClassTemplateArgumentTypeUsages(const clang::TypeSourceInfo* typeInfo, const T& t) -{ - const clang::Type* type = typeInfo->getType().getTypePtr(); - - if (type->getTypeClass() == clang::Type::Elaborated) - { - type = clang::dyn_cast(type)->getNamedType().getTypePtr(); - } - - if (type->getTypeClass() == clang::Type::TemplateSpecialization) - { - const clang::TemplateSpecializationType* templateSpecializationType = type->getAs(); - for (size_t i = 0; i < templateSpecializationType->getNumArgs(); i++) - { - CxxTemplateArgumentNameResolver resolver; - std::shared_ptr argumentType = utility::templateArgumentToDataType(templateSpecializationType->getArg(i)); - if (argumentType->getFullTypeName().size() > 0) - { - m_client->onTypeUsageParsed(getParseTypeUsage(typeInfo->getTypeLoc(), argumentType), t); - } - } - } -} - -template -void ASTVisitor::saveFunctionTemplateArgumentTypeUsages( - const clang::FunctionDecl* decl, const clang::SourceRange& sourceRange, const T& t -){ - const clang::TemplateArgumentList* argumentList = decl->getTemplateSpecializationArgs(); - if (!argumentList) - { - return; - } - - for (size_t i = 0; i < argumentList->size(); i++) - { - CxxTemplateArgumentNameResolver resolver; - std::shared_ptr argumentType = utility::templateArgumentToDataType(argumentList->get(i)); - if (argumentType->getFullTypeName().size() > 0) - { - m_client->onTypeUsageParsed(getParseTypeUsage(sourceRange, argumentType), t); - } - } -} diff --git a/src/lib/data/parser/cxx/ASTVisitor.h b/src/lib/data/parser/cxx/ASTVisitor.h index d6fa0565..8d2b9886 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.h +++ b/src/lib/data/parser/cxx/ASTVisitor.h @@ -32,6 +32,7 @@ public: virtual bool VisitVarDecl(clang::VarDecl* declaration); // global variables and static fields virtual bool VisitFieldDecl(clang::FieldDecl* declaration); // fields virtual bool VisitFunctionDecl(clang::FunctionDecl* declaration); // functions + virtual bool VisitParmVarDecl(clang::ParmVarDecl* declaration); virtual bool VisitCXXMethodDecl(clang::CXXMethodDecl* declaration); // methods virtual bool VisitCXXConstructorDecl(clang::CXXConstructorDecl* declaration); // initialization list virtual bool VisitNamespaceDecl(clang::NamespaceDecl* declaration); // namespaces @@ -47,8 +48,14 @@ public: // ASTBodyVisitorClient implementation virtual void VisitCallExprInDeclBody(clang::FunctionDecl* decl, clang::CallExpr* expr); // calls virtual void VisitCallExprInDeclBody(clang::DeclaratorDecl* decl, clang::CallExpr* expr); // calls in initialization of global variables + virtual void VisitDeclRefExprInDeclBody(clang::FunctionDecl* decl, clang::DeclRefExpr* expr); + virtual void VisitDeclRefExprInDeclBody(clang::DeclaratorDecl* decl, clang::DeclRefExpr* expr); virtual void VisitCXXConstructExprInDeclBody(clang::FunctionDecl* decl, clang::CXXConstructExpr* expr); // constructor calls virtual void VisitCXXConstructExprInDeclBody(clang::DeclaratorDecl* decl, clang::CXXConstructExpr* expr); // constructor calls of global variables + virtual void VisitExplicitCastExprInDeclBody(clang::FunctionDecl* decl, clang::ExplicitCastExpr* expr); + virtual void VisitExplicitCastExprInDeclBody(clang::DeclaratorDecl* decl, clang::ExplicitCastExpr* expr); + virtual void VisitCXXTemporaryObjectExprInDeclBody(clang::FunctionDecl* decl, clang::CXXTemporaryObjectExpr* expr); + virtual void VisitCXXTemporaryObjectExprInDeclBody(clang::DeclaratorDecl* decl, clang::CXXTemporaryObjectExpr* expr); virtual void VisitCXXNewExprInDeclBody(clang::FunctionDecl* decl, clang::CXXNewExpr* expr); // type use of new operator virtual void VisitCXXNewExprInDeclBody(clang::DeclaratorDecl* decl, clang::CXXNewExpr* expr); // type use of new operator in global space virtual void VisitMemberExprInDeclBody(clang::FunctionDecl* decl, clang::MemberExpr* expr); // field usages @@ -60,17 +67,24 @@ public: virtual void VisitVarDeclInDeclBody(clang::FunctionDecl* decl, clang::VarDecl* varDecl); // type usages private: + + void processFunctionDecl(clang::FunctionDecl* declaration); + void processTemplateArgumentsOfExplicitSpecialization(clang::FunctionDecl* declaration); + void processTemplateArgumentsOfExplicitSpecialization(clang::ClassTemplateSpecializationDecl* specializationDecl); + void processTemplateArguments(clang::DeclRefExpr* expr); + void processTemplateArguments(clang::TemplateSpecializationTypeLoc loc); + + bool isLocatedInUnparsedProjectFile(const clang::Decl* declaration) const; bool isLocatedInProjectFile(const ParseLocation& location) const; bool isLocatedInProjectFile(const clang::Decl* declaration) const; - bool needsToAddTemplateArgument(const clang::TemplateArgument& argument, const clang::Decl* specializedDecl); - ParserClient::AccessType convertAccessType(clang::AccessSpecifier) const; ParserClient::AbstractionType getAbstractionType(const clang::CXXMethodDecl* methodDecl) const; ParseLocation getParseLocation(const clang::SourceRange& sourceRange) const; ParseLocation getParseLocationForTokenAtLocation(const clang::SourceLocation& loc) const; + ParseLocation getParseLocationForTokensInRange(const clang::SourceRange& range) const; ParseLocation getParseLocationForNamedDecl(const clang::NamedDecl* decl) const; ParseLocation getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const; ParseLocation getParseLocationOfRecordBody(clang::CXXRecordDecl* decl) const; @@ -85,13 +99,6 @@ private: ParseFunction getParseFunction(const clang::FunctionDecl* declaration) const; ParseFunction getParseFunction(const clang::FunctionTemplateDecl* declaration) const; - template - void saveClassTemplateArgumentTypeUsages(const clang::TypeSourceInfo* typeInfo, const T& t); - - template - void saveFunctionTemplateArgumentTypeUsages( - const clang::FunctionDecl* decl, const clang::SourceRange& sourceRange, const T& t); - clang::ASTContext* m_context; ParserClient* m_client; FileRegister* m_fileRegister; diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 84cc3088..e21b50a0 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -199,7 +199,7 @@ public: std::shared_ptr client = parseCode( "int ceil(float a)\n" "{\n" - " return static_cast(a) + 1;\n" + " return 1;\n" "}\n" ); @@ -1539,9 +1539,9 @@ public: "}\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->int <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->int <7:4 7:6>"); } - void test_cxx_parser_finds_type_template_argument_for_parameter_pack_of_implicit_template_specialization() + void test_cxx_parser_finds_type_template_argument_for_parameter_pack_of_implicit_template_specialization() // actually this is an explicit template instantiation { std::shared_ptr client = parseCode( "template \n" @@ -1552,13 +1552,68 @@ public: "{\n" " A();\n" "}\n" - ); + ); - TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<>-> <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<>->int <7:6 7:8>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<>->float <7:11 7:15>"); } - void test_cxx_parser_finds_non_type_int_template_argument_of_implicit_template_specialization() + void test_cxx_parser_finds_type_template_argument_for_parameter_of_implicit_template_s______tion_of_non_default_constructor() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + "public:\n" + " A(int data){}\n" + "};\n" + "int main()\n" + "{\n" + " A(5);\n" + "}\n" + ); + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->int <9:4 9:6>"); + } + + void test_cxx_parser_finds_type_template_argument_for_parameter_of_implicit_template_s___kk_tion_of_call_to_default_constructor() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + "public:\n" + " A(){}\n" + "};\n" + "int main()\n" + "{\n" + " A();\n" + "}\n" + ); + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->int <9:4 9:6>"); + } + + void test_cxx_parser_finds_type_template_argument_for_parameter_of_implicit_temple_of_new_expression() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + "public:\n" + " A(){}\n" + "};\n" + "int main()\n" + "{\n" + " new A();\n" + "}\n" + ); + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->int <9:8 9:10>"); + } + + void test_cxx_parser_finds_non_type_int_template_argument_of_implicit_template_instantiation() { std::shared_ptr client = parseCode( "template \n" @@ -1570,11 +1625,25 @@ public: " A<1> a;\n" " return 0;\n" "}\n" - ); + ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<1>->int <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<1>->int <7:4 7:4>"); } + //void _____test_cxx_parser_finds_type_template_argument_of_static_cast_expression() + //{ + // std::shared_ptr client = parseCode( + // "int main()\n" + // "{\n" + // " return static_cast(4.0f);" + // "}\n" + // ); + // TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + // TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<1>->int <0:0 0:0>"); + //} + + + void test_cxx_parser_finds_non_type_bool_template_argument_of_implicit_template_specialization() { std::shared_ptr client = parseCode( @@ -1589,7 +1658,7 @@ public: "}\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->bool <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->bool <7:4 7:7>"); } void test_cxx_parser_finds_non_type_custom_pointer_template_argument_of_implicit_template_specialization() @@ -1607,7 +1676,7 @@ public: "}\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<&p>->P <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<&p>->P <9:4 9:5>"); } void test_cxx_parser_finds_non_type_custom_reference_template_argument_of_implicit_template_specialization() @@ -1625,7 +1694,7 @@ public: "}\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<&p>->P <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<&p>->P <9:4 9:4>"); } void test_cxx_parser_finds_non_type_nullptr_template_argument_of_implicit_template_specialization() @@ -1642,7 +1711,7 @@ public: ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->nullptr_t <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->nullptr_t <7:4 7:10>"); } void test_cxx_parser_finds_non_type_int_template_argument_for_parameter_pack_of_implicit_template_specialization() @@ -1654,12 +1723,14 @@ public: "};\n" "int main()\n" "{\n" - " A<1, 2, 3>();\n" + " A<1, 2, 33>();\n" "}\n" ); - TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<<1, 2, 3>>-> <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 3); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<<1, 2, 33>>->int <7:6 7:6>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<<1, 2, 33>>->int <7:9 7:9>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[2], "A<<1, 2, 33>>->int <7:12 7:13>"); } void test_cxx_parser_finds_template_template_argument_of_implicit_template_specialization() @@ -1678,7 +1749,7 @@ public: ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B->A <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B->A <9:4 9:4>"); } void test_cxx_parser_finds_template_template_argument_for_parameter_pack_of_implicit_template_specialization() @@ -1694,12 +1765,12 @@ public: "};\n" "int main()\n" "{\n" - " B();\n" + " B();\n" "}\n" ); - TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B<>->, A> <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B<>->A <11:4 11:4>"); } void test_cxx_parser_finds_template_member_specialization_of_implicit_template_specialization() @@ -1749,7 +1820,7 @@ public: "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->int <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->int <6:9 6:11>"); } void test_cxx_parser_finds_non_type_int_template_argument_of_explicit_template_specialization() @@ -1765,7 +1836,7 @@ public: "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<1>->int <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<1>->int <6:9 6:9>"); } void test_cxx_parser_finds_non_type_bool_template_argument_of_explicit_template_specialization() @@ -1781,7 +1852,7 @@ public: "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->bool <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->bool <6:9 6:12>"); } void test_cxx_parser_finds_non_type_custom_pointer_template_argument_of_explicit_template_specialization() @@ -1799,7 +1870,7 @@ public: "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<&p>->P <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<&p>->P <8:9 8:10>"); } void test_cxx_parser_finds_non_type_custom_reference_template_argument_of_explicit_template_specialization() @@ -1817,7 +1888,7 @@ public: "};\n" ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<&p>->P <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<&p>->P <8:9 8:9>"); } void test_cxx_parser_finds_non_type_nullptr_template_argument_of_explicit_template_specialization() @@ -1834,7 +1905,7 @@ public: ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->nullptr_t <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->nullptr_t <6:9 6:15>"); } void test_cxx_parser_finds_template_template_argument_of_explicit_template_specialization() @@ -1853,7 +1924,7 @@ public: ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B->A <0:0 0:0>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "B->A <8:9 8:9>"); } void test_cxx_parser_finds_explicit_partial_template_specialization() @@ -1886,7 +1957,7 @@ public: ); 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>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A->int <6:12 6:14>"); } void test_cxx_parser_finds_non_type_int_template_argument_of_explicit_partial_template_specialization() @@ -1921,7 +1992,7 @@ public: ); TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 2); - TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->bool <6:9 6:9>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A->bool <6:9 6:12>"); TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A->bool <6:15 6:15>"); } @@ -1979,7 +2050,7 @@ public: ); 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[0], "A->nullptr_t <6:9 6:15>"); TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A->std::nullptr_t <6:18 6:18>"); } @@ -2019,8 +2090,8 @@ public: TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 3); TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<3, typename T2, T2 T3>->int <6:9 6:9>"); - TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<3, typename T2, T2 T3>->A<3, typename T2, T2 T3>::T2 <6:12 6:12>"); - TS_ASSERT_EQUALS(client->templateArgumentTypes[2], "A<3, typename T2, T2 T3>->A<3, typename T2, T2 T3>::T2 <6:16 6:16>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<3, typename T2, T2 T3>->A<3, typename T2, T2 T3>::T2 <6:12 6:13>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[2], "A<3, typename T2, T2 T3>->A<3, typename T2, T2 T3>::T2 <6:16 6:17>"); } void test_cxx_parser_finds_non_type_template_argument_that_depends_on_template_template_parameter_of_explicit_partial_template_specialization() @@ -2038,8 +2109,8 @@ public: TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 3); TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<3, template typename T2, T2 T3>->int <6:9 6:9>"); - TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<3, template typename T2, T2 T3>->A<3, template typename T2, T2 T3>::T2 <6:12 6:12>"); - TS_ASSERT_EQUALS(client->templateArgumentTypes[2], "A<3, template typename T2, T2 T3>->A<3, template typename T2, T2 T3>::T2 <6:16 6:16>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<3, template typename T2, T2 T3>->A<3, template typename T2, T2 T3>::T2 <6:12 6:13>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[2], "A<3, template typename T2, T2 T3>->A<3, template typename T2, T2 T3>::T2 <6:16 6:17>"); } void test_cxx_parser_finds_correct_name_of_explicit_template_specialization() @@ -2459,7 +2530,7 @@ public: 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() + void test_cxx_parser_finds_explicit_type_template_argument_of_explicit_specialization_of_template_function() { std::shared_ptr client = parseCode( "template \n" @@ -2476,24 +2547,104 @@ public: 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() + void test_cxx_parser_finds_explicit_type_template_argument_of_function_call_in_function() { std::shared_ptr client = parseCode( "template \n" - "void test()\n" - "{\n" - "};\n" + "void test(){}\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>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test->int <6:7 6:7>"); } + void test_cxx_parser_finds_explicit_non_type_template_argument_of_function_call_in_function() + { + std::shared_ptr client = parseCode( + "template \n" + "void test(){}\n" + "\n" + "int main()\n" + "{\n" + " test<33>();\n" + " return 1;\n" + "};\n" + ); + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test<33>->int <6:7 6:7>"); + } + + void test_cxx_parser_finds_explicit_template_template_argument_of_function_call_in_function() + { + std::shared_ptr client = parseCode( + "template \n" + "class A {};\n" + "template class T>\n" + "void test(){};\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->A <7:7 7:7>"); + } + + void test_cxx_parser_finds_implicit_type_template_argument_of_function_call_in_function() + { + std::shared_ptr client = parseCode( + "template \n" + "void test(T data){}\n" + "\n" + "int main()\n" + "{\n" + " test(1);\n" + " return 1;\n" + "};\n" + ); + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test->int <6:5 6:5>"); + } + + void test_cxx_parser_finds_explicit_type_template_argument_of_function_call_in_var_decl() + { + std::shared_ptr client = parseCode( + "template \n" + "T test(){ return 1; }\n" + "\n" + "class A\n" + "{\n" + " int foo = test();\n" + "};\n" + ); + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test->int <6:17 6:17>"); + } + + void test_cxx_parser_finds_implicit_type_template_argument_of_function_call_in_var_decl() + { + std::shared_ptr client = parseCode( + "template \n" + "T test(T i){ return i; }\n" + "\n" + "class A\n" + "{\n" + " int foo = test(1);\n" + "};\n" + ); + TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 1); + TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "test->int <6:15 6:15>"); + } + + + + void test_cxx_parser_finds_type_template_default_argument_type_of_template_function() { std::shared_ptr client = parseCode( @@ -2860,21 +3011,21 @@ private: } virtual Id onTemplateArgumentTypeOfTemplateRecordParsed( - const ParseLocation& location, const NameHierarchy& argumentNameHierarchy, + const ParseLocation& location, const NameHierarchy& argumentTypeNameHierarchy, const NameHierarchy& templateNameHierarchy) { templateArgumentTypes.push_back( - addLocationSuffix(templateNameHierarchy.getFullName() + "->" + argumentNameHierarchy.getFullName(), location) + addLocationSuffix(templateNameHierarchy.getFullName() + "->" + argumentTypeNameHierarchy.getFullName(), location) ); return 0; } virtual Id onTemplateArgumentTypeOfTemplateFunctionParsed( - const ParseLocation& location, const NameHierarchy& argumentNameHierarchy, + const ParseLocation& location, const NameHierarchy& argumentTypeNameHierarchy, const ParseFunction& templateFunction) { templateArgumentTypes.push_back( - addLocationSuffix(templateFunction.getFullName() + "->" + argumentNameHierarchy.getFullName(), location) + addLocationSuffix(templateFunction.getFullName() + "->" + argumentTypeNameHierarchy.getFullName(), location) ); return 0; }