#include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h" #include #include #include "data/parser/cxx/name/CxxFunctionDeclName.h" #include "data/parser/cxx/name_resolver/CxxSpecifierNameResolver.h" #include "data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h" #include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h" #include "utility/file/FilePath.h" #include "utility/logging/logging.h" #include "utility/ScopedSwitcher.h" CxxDeclNameResolver::CxxDeclNameResolver() : CxxNameResolver(std::vector()) , m_currentDecl(nullptr) { } CxxDeclNameResolver::CxxDeclNameResolver(std::vector ignoredContextDecls) : CxxNameResolver(ignoredContextDecls) , m_currentDecl(nullptr) { } CxxDeclNameResolver::~CxxDeclNameResolver() { } std::shared_ptr CxxDeclNameResolver::getName(const clang::NamedDecl* declaration) { { const clang::Decl* prev = declaration; while (prev) { declaration = clang::dyn_cast_or_null(prev); prev = prev->getPreviousDecl(); } } std::shared_ptr declName; if (declaration) { declName = getDeclName(clang::dyn_cast(declaration)); if (declName) { if (const clang::UsingDecl* usingDecl = clang::dyn_cast_or_null(declaration)) { CxxSpecifierNameResolver specifierNameResolver(getIgnoredContextDecls()); declName->setParent(specifierNameResolver.getName(usingDecl->getQualifier())); } else { declName->setParent(getContextName(declaration->getDeclContext())); } } } return declName; } std::shared_ptr CxxDeclNameResolver::getContextName(const clang::DeclContext* declContext) { std::shared_ptr contextDeclName; if (declContext && !ignoresContext(declContext)) { if (const clang::NamedDecl* contextNamedDecl = clang::dyn_cast_or_null(declContext)) { contextDeclName = getDeclName(contextNamedDecl); if (contextDeclName) { contextDeclName->setParent(getContextName(declContext->getParent())); } else { contextDeclName = getContextName(declContext->getParent()); } } } return contextDeclName; } std::shared_ptr CxxDeclNameResolver::getDeclName(const clang::NamedDecl* declaration) { ScopedSwitcher switcher(m_currentDecl, declaration); std::string declNameString = declaration->getNameAsString(); if (const clang::TypeAliasDecl* typeAliasDecl = clang::dyn_cast_or_null(declaration)) { clang::TypeAliasTemplateDecl* templatedDeclaration = typeAliasDecl->getDescribedAliasTemplate(); if (templatedDeclaration) { return getDeclName(templatedDeclaration); } } if (const clang::CXXRecordDecl* recordDecl = clang::dyn_cast_or_null(declaration)) { clang::ClassTemplateDecl* templateClassDeclaration = recordDecl->getDescribedClassTemplate(); if (templateClassDeclaration) { return getDeclName(templateClassDeclaration); } else if (clang::isa(declaration)) { const clang::ClassTemplatePartialSpecializationDecl* partialSpecializationDecl = clang::dyn_cast(declaration); clang::TemplateParameterList* parameterList = partialSpecializationDecl->getTemplateParameters(); unsigned int currentParameterIndex = 0; std::vector templateParameters; const clang::TemplateArgumentList& templateArgumentList = partialSpecializationDecl->getTemplateArgs(); const int templateArgumentCount = templateArgumentList.size(); for (int i = 0; i < templateArgumentCount; i++) { const clang::TemplateArgument& templateArgument = templateArgumentList.get(i); if (templateArgument.isDependent()) // IMPORTANT_TODO: fix case when arg depends on template parameter of outer template class, or depends on first template parameter. { if(currentParameterIndex < parameterList->size()) { templateParameters.push_back(getTemplateParameterString(parameterList->getParam(currentParameterIndex))); } else { //this if fixes the crash, but not the problem TODO // const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); // LOG_ERROR("Template getParam out of Range " + declaration->getLocation().printToString(sourceManager)); } currentParameterIndex++; } else { templateParameters.push_back(getTemplateArgumentName(templateArgument)); } } return std::make_shared(declNameString, templateParameters); } else if (clang::isa(declaration)) { std::vector templateArguments; const clang::TemplateArgumentList& templateArgumentList = clang::dyn_cast(declaration)->getTemplateArgs(); for (size_t i = 0; i < templateArgumentList.size(); i++) { templateArguments.push_back(getTemplateArgumentName(templateArgumentList.get(i))); } return std::make_shared(declNameString, templateArguments); } else if (recordDecl->isLambda()) { // we skip this node because its child (the lambda call operator) has already been recorded. return std::shared_ptr(); } else if (declNameString.size() == 0) { const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); const std::string symbolKindName = (recordDecl->isStruct() ? "struct" : "class"); return std::make_shared(getNameForAnonymousSymbol(symbolKindName, presumedBegin), std::vector()); } } else if (clang::isa(declaration)) { const clang::FunctionDecl* functionDecl = clang::dyn_cast(declaration); std::string functionName = declNameString; std::vector templateArguments; if ((clang::dyn_cast_or_null(functionDecl)) && (clang::dyn_cast_or_null(functionDecl)->getParent()->isLambda())) { const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(clang::dyn_cast_or_null(functionDecl)->getParent()->getLocStart()); functionName = "lambda at " + std::to_string(presumedBegin.getLine()) + ":" + std::to_string(presumedBegin.getColumn()); } else if (clang::FunctionTemplateDecl* templateFunctionDeclaration = functionDecl->getDescribedFunctionTemplate()) { std::shared_ptr templateDeclName = getDeclName(templateFunctionDeclaration); functionName = templateDeclName->getName(); templateArguments = templateDeclName->getTemplateParameterNames(); } else { if (functionDecl->isFunctionTemplateSpecialization()) { const clang::TemplateArgumentList* templateArgumentList = functionDecl->getTemplateSpecializationArgs(); for (size_t i = 0; i < templateArgumentList->size(); i++) { const clang::TemplateArgument& templateArgument = templateArgumentList->get(i); templateArguments.push_back(getTemplateArgumentName(templateArgument)); } } } bool isStatic = false; bool isConst = false; if (clang::isa(declaration)) { const clang::CXXMethodDecl* methodDecl = clang::dyn_cast(declaration); isStatic = methodDecl->isStatic(); isConst = methodDecl->isConst(); } else { isStatic = functionDecl->getStorageClass() == clang::SC_Static; } CxxTypeNameResolver typenNameResolver(getIgnoredContextDecls()); typenNameResolver.ignoreContextDecl(functionDecl); std::shared_ptr returnTypeName = typenNameResolver.getName(functionDecl->getReturnType()); std::vector> parameterTypeNames; for (unsigned int i = 0; i < functionDecl->param_size(); i++) { parameterTypeNames.push_back(typenNameResolver.getName(functionDecl->parameters()[i]->getType())); } return std::make_shared( functionName, templateArguments, returnTypeName, parameterTypeNames, isConst, isStatic ); } else if (clang::isa(declaration)) // also triggers on TemplateTemplateParmDecl { std::vector templateParameters; clang::TemplateParameterList* parameterList = clang::dyn_cast(declaration)->getTemplateParameters(); for (size_t i = 0; i < parameterList->size(); i++) { templateParameters.push_back(getTemplateParameterString(parameterList->getParam(i))); } return std::make_shared(declNameString, templateParameters); } else if (clang::isa(declaration) && clang::dyn_cast(declaration)->isAnonymousNamespace()) { const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); return std::make_shared(getNameForAnonymousSymbol("namespace", presumedBegin), std::vector()); } else if (clang::isa(declaration) && declNameString.size() == 0) { const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); return std::make_shared(getNameForAnonymousSymbol("enum", presumedBegin), std::vector()); } else if ( ( clang::isa(declaration) || clang::isa(declaration) || clang::isa(declaration) ) && declNameString.size() == 0) { const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); return std::make_shared(getNameForAnonymousSymbol("template parameter", presumedBegin), std::vector()); } else if (clang::isa(declaration) && declNameString.size() == 0) { const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); return std::make_shared(getNameForAnonymousSymbol("parameter", presumedBegin), std::vector()); } if (declNameString.size() > 0) { return std::make_shared(declNameString, std::vector(), std::shared_ptr()); } const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager(); const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart()); // LOG_ERROR("could not resolve name of decl at: " + declaration->getLocation().printToString(sourceManager)); return std::make_shared(getNameForAnonymousSymbol("symbol", presumedBegin), std::vector()); } std::string CxxDeclNameResolver::getNameForAnonymousSymbol(const std::string& symbolKindName, const clang::PresumedLoc& presumedBegin) { return "anonymous " + symbolKindName + " (" + FilePath(presumedBegin.getFilename()).fileName() + "<" + std::to_string(presumedBegin.getLine()) + ":" + std::to_string(presumedBegin.getColumn()) + ">)"; } std::string CxxDeclNameResolver::getTemplateParameterString(const clang::NamedDecl* parameter) { std::string templateParameterTypeString = ""; clang::Decl::Kind templateParameterKind = parameter->getKind(); switch (templateParameterKind) { case clang::Decl::NonTypeTemplateParm: templateParameterTypeString = getTemplateParameterTypeString(clang::dyn_cast(parameter)); break; case clang::Decl::TemplateTypeParm: templateParameterTypeString = getTemplateParameterTypeString(clang::dyn_cast(parameter)); break; case clang::Decl::TemplateTemplateParm: templateParameterTypeString = getTemplateParameterTypeString(clang::dyn_cast(parameter)); break; default: // LOG_ERROR("Unhandled kind of template parameter."); break; } std::string parameterName = parameter->getName(); if (!parameterName.empty()) { templateParameterTypeString += " " + parameterName; } return templateParameterTypeString; } std::string CxxDeclNameResolver::getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter) { CxxTypeNameResolver typeNameResolver(getIgnoredContextDecls()); if (clang::isa(m_currentDecl)) { typeNameResolver.ignoreContextDecl(clang::dyn_cast(m_currentDecl)->getTemplatedDecl()); } else // works for partial template specializations { typeNameResolver.ignoreContextDecl(m_currentDecl); } std::string typeString = typeNameResolver.getName(parameter->getType())->toString(); if (parameter->isTemplateParameterPack()) { typeString += "..."; } return typeString; } std::string CxxDeclNameResolver::getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter) { std::string typeString = (parameter->wasDeclaredWithTypename() ? "typename" : "class"); if (parameter->isTemplateParameterPack()) { typeString += "..."; } return typeString; } std::string CxxDeclNameResolver::getTemplateParameterTypeString(const clang::TemplateTemplateParmDecl* parameter) { std::string templateParameterTypeString = "template<"; clang::TemplateParameterList* parameterList = parameter->getTemplateParameters(); for (size_t i = 0; i < parameterList->size(); i++) { templateParameterTypeString += getTemplateParameterString(parameterList->getParam(i)); templateParameterTypeString += (i < parameterList->size() - 1) ? ", " : ""; } templateParameterTypeString += ">"; templateParameterTypeString += " typename"; // TODO: what if template template parameter is defined with class keyword? if (parameter->isTemplateParameterPack()) { templateParameterTypeString += "..."; } return templateParameterTypeString; } std::string CxxDeclNameResolver::getTemplateArgumentName(const clang::TemplateArgument& argument) { CxxTemplateArgumentNameResolver resolver(getIgnoredContextDecls()); return resolver.getTemplateArgumentName(argument); }