logic: fixed infinite recursion while solving c++ template parameter names (issue #553)
This commit is contained in:
@@ -37,6 +37,8 @@ add_files(
|
||||
data/parser/cxx/name_resolver/CxxSpecifierNameResolver.h
|
||||
data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp
|
||||
data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h
|
||||
data/parser/cxx/name_resolver/CxxTemplateParameterStringResolver.cpp
|
||||
data/parser/cxx/name_resolver/CxxTemplateParameterStringResolver.h
|
||||
data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp
|
||||
data/parser/cxx/name_resolver/CxxTypeNameResolver.h
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "data/parser/cxx/name/CxxStaticFunctionDeclName.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxSpecifierNameResolver.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxTemplateParameterStringResolver.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
|
||||
#include "data/parser/cxx/CanonicalFilePathCache.h"
|
||||
#include "data/parser/cxx/utilityClang.h"
|
||||
@@ -29,10 +30,6 @@ CxxDeclNameResolver::CxxDeclNameResolver(
|
||||
{
|
||||
}
|
||||
|
||||
CxxDeclNameResolver::~CxxDeclNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<CxxDeclName> CxxDeclNameResolver::getName(const clang::NamedDecl* declaration)
|
||||
{
|
||||
declaration = utility::getFirstDecl(declaration);
|
||||
@@ -480,89 +477,18 @@ std::vector<std::wstring> CxxDeclNameResolver::getTemplateParameterStrings(const
|
||||
|
||||
std::wstring CxxDeclNameResolver::getTemplateParameterString(const clang::NamedDecl* parameter)
|
||||
{
|
||||
std::wstring templateParameterTypeString;
|
||||
|
||||
if (parameter)
|
||||
CxxTemplateParameterStringResolver parameterStringResolver(getCanonicalFilePathCache(), getIgnoredContextDecls());
|
||||
if (clang::isa<clang::TemplateDecl>(m_currentDecl) && clang::dyn_cast<clang::TemplateDecl>(m_currentDecl)->getTemplatedDecl())
|
||||
{
|
||||
const clang::Decl::Kind templateParameterKind = parameter->getKind();
|
||||
switch (templateParameterKind)
|
||||
{
|
||||
case clang::Decl::NonTypeTemplateParm:
|
||||
templateParameterTypeString = getTemplateParameterTypeString(clang::dyn_cast<clang::NonTypeTemplateParmDecl>(parameter));
|
||||
break;
|
||||
case clang::Decl::TemplateTypeParm:
|
||||
templateParameterTypeString = getTemplateParameterTypeString(clang::dyn_cast<clang::TemplateTypeParmDecl>(parameter));
|
||||
break;
|
||||
case clang::Decl::TemplateTemplateParm:
|
||||
templateParameterTypeString = getTemplateParameterTypeString(clang::dyn_cast<clang::TemplateTemplateParmDecl>(parameter));
|
||||
break;
|
||||
default:
|
||||
// LOG_ERROR("Unhandled kind of template parameter.");
|
||||
break;
|
||||
}
|
||||
|
||||
std::wstring parameterName = utility::decodeFromUtf8(parameter->getName());
|
||||
if (!parameterName.empty())
|
||||
{
|
||||
templateParameterTypeString += L" " + parameterName;
|
||||
}
|
||||
}
|
||||
return templateParameterTypeString;
|
||||
}
|
||||
|
||||
std::wstring CxxDeclNameResolver::getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter)
|
||||
{
|
||||
CxxTypeNameResolver typeNameResolver(getCanonicalFilePathCache(), getIgnoredContextDecls());
|
||||
|
||||
if (clang::isa<clang::TemplateDecl>(m_currentDecl))
|
||||
{
|
||||
typeNameResolver.ignoreContextDecl(clang::dyn_cast<clang::TemplateDecl>(m_currentDecl)->getTemplatedDecl());
|
||||
parameterStringResolver.ignoreContextDecl(clang::dyn_cast<clang::TemplateDecl>(m_currentDecl)->getTemplatedDecl());
|
||||
}
|
||||
else // works for partial template specializations
|
||||
{
|
||||
typeNameResolver.ignoreContextDecl(m_currentDecl);
|
||||
parameterStringResolver.ignoreContextDecl(m_currentDecl);
|
||||
}
|
||||
parameterStringResolver.ignoreContextDecl(parameter);
|
||||
|
||||
std::wstring typeString;
|
||||
|
||||
std::shared_ptr<CxxTypeName> typeName = CxxTypeName::makeUnsolvedIfNull(typeNameResolver.getName(parameter->getType()));
|
||||
typeString = typeName->toString();
|
||||
|
||||
if (parameter->isTemplateParameterPack())
|
||||
{
|
||||
typeString += L"...";
|
||||
}
|
||||
return typeString;
|
||||
}
|
||||
|
||||
std::wstring CxxDeclNameResolver::getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter)
|
||||
{
|
||||
std::wstring typeString = (parameter->wasDeclaredWithTypename() ? L"typename" : L"class");
|
||||
if (parameter->isTemplateParameterPack())
|
||||
{
|
||||
typeString += L"...";
|
||||
}
|
||||
return typeString;
|
||||
}
|
||||
|
||||
std::wstring CxxDeclNameResolver::getTemplateParameterTypeString(const clang::TemplateTemplateParmDecl* parameter)
|
||||
{
|
||||
std::wstring templateParameterTypeString = L"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) ? L", " : L"";
|
||||
}
|
||||
templateParameterTypeString += L">";
|
||||
templateParameterTypeString += L" typename"; // TODO: what if template template parameter is defined with class keyword?
|
||||
|
||||
if (parameter->isTemplateParameterPack())
|
||||
{
|
||||
templateParameterTypeString += L"...";
|
||||
}
|
||||
|
||||
return templateParameterTypeString;
|
||||
return parameterStringResolver.getTemplateParameterString(parameter);
|
||||
}
|
||||
|
||||
std::wstring CxxDeclNameResolver::getTemplateArgumentName(const clang::TemplateArgument& argument)
|
||||
@@ -570,3 +496,5 @@ std::wstring CxxDeclNameResolver::getTemplateArgumentName(const clang::TemplateA
|
||||
CxxTemplateArgumentNameResolver resolver(getCanonicalFilePathCache(), getIgnoredContextDecls());
|
||||
return resolver.getTemplateArgumentName(argument);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ public:
|
||||
std::shared_ptr<CanonicalFilePathCache> canonicalFilePathCache,
|
||||
std::vector<const clang::Decl*> ignoredContextDecls
|
||||
);
|
||||
virtual ~CxxDeclNameResolver();
|
||||
|
||||
std::shared_ptr<CxxDeclName> getName(const clang::NamedDecl* declaration);
|
||||
|
||||
@@ -30,9 +29,6 @@ private:
|
||||
template <typename T>
|
||||
std::vector<std::wstring> getTemplateParameterStringsOfPatrialSpecialitarion(const T* templateDecl);
|
||||
std::wstring getTemplateParameterString(const clang::NamedDecl* parameter);
|
||||
std::wstring getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter);
|
||||
std::wstring getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter);
|
||||
std::wstring getTemplateParameterTypeString(const clang::TemplateTemplateParmDecl* parameter);
|
||||
std::wstring getTemplateArgumentName(const clang::TemplateArgument& argument);
|
||||
|
||||
const clang::NamedDecl* m_currentDecl;
|
||||
|
||||
@@ -9,10 +9,6 @@ CxxNameResolver::CxxNameResolver(
|
||||
{
|
||||
}
|
||||
|
||||
CxxNameResolver::~CxxNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
void CxxNameResolver::ignoreContextDecl(const clang::Decl* decl)
|
||||
{
|
||||
if (decl)
|
||||
|
||||
@@ -14,7 +14,7 @@ public:
|
||||
std::shared_ptr<CanonicalFilePathCache> canonicalFilePathCache,
|
||||
std::vector<const clang::Decl*> ignoredContextDecls
|
||||
);
|
||||
virtual ~CxxNameResolver();
|
||||
virtual ~CxxNameResolver() = default;
|
||||
|
||||
void ignoreContextDecl(const clang::Decl* decl);
|
||||
bool ignoresContext(const clang::Decl* decl);
|
||||
|
||||
@@ -21,10 +21,6 @@ CxxSpecifierNameResolver::CxxSpecifierNameResolver(
|
||||
{
|
||||
}
|
||||
|
||||
CxxSpecifierNameResolver::~CxxSpecifierNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<CxxName> CxxSpecifierNameResolver::getName(const clang::NestedNameSpecifier* nestedNameSpecifier)
|
||||
{
|
||||
std::shared_ptr<CxxName> name;
|
||||
|
||||
@@ -15,7 +15,6 @@ public:
|
||||
std::shared_ptr<CanonicalFilePathCache> canonicalFilePathCache,
|
||||
std::vector<const clang::Decl*> ignoredContextDecls
|
||||
);
|
||||
virtual ~CxxSpecifierNameResolver();
|
||||
|
||||
std::shared_ptr<CxxName> getName(const clang::NestedNameSpecifier* nestedNameSpecifier);
|
||||
};
|
||||
|
||||
@@ -19,10 +19,6 @@ CxxTemplateArgumentNameResolver::CxxTemplateArgumentNameResolver(
|
||||
{
|
||||
}
|
||||
|
||||
CxxTemplateArgumentNameResolver::~CxxTemplateArgumentNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
std::wstring CxxTemplateArgumentNameResolver::getTemplateArgumentName(const clang::TemplateArgument& argument)
|
||||
{
|
||||
// This doesn't work correctly if the template argument is dependent.
|
||||
|
||||
@@ -15,7 +15,6 @@ public:
|
||||
std::shared_ptr<CanonicalFilePathCache> canonicalFilePathCache,
|
||||
std::vector<const clang::Decl*> ignoredContextDecls
|
||||
);
|
||||
virtual ~CxxTemplateArgumentNameResolver();
|
||||
|
||||
std::wstring getTemplateArgumentName(const clang::TemplateArgument& argument);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
#include "data/parser/cxx/name_resolver/CxxTemplateParameterStringResolver.h"
|
||||
|
||||
#include <clang/AST/PrettyPrinter.h>
|
||||
#include <clang/AST/DeclTemplate.h>
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
|
||||
#include "utility/utilityString.h"
|
||||
|
||||
CxxTemplateParameterStringResolver::CxxTemplateParameterStringResolver(std::shared_ptr<CanonicalFilePathCache> canonicalFilePathCache)
|
||||
: CxxNameResolver(canonicalFilePathCache, std::vector<const clang::Decl*>())
|
||||
{
|
||||
}
|
||||
|
||||
CxxTemplateParameterStringResolver::CxxTemplateParameterStringResolver(
|
||||
std::shared_ptr<CanonicalFilePathCache> canonicalFilePathCache,
|
||||
std::vector<const clang::Decl*> ignoredContextDecls
|
||||
)
|
||||
: CxxNameResolver(canonicalFilePathCache, ignoredContextDecls)
|
||||
{
|
||||
}
|
||||
|
||||
std::wstring CxxTemplateParameterStringResolver::getTemplateParameterString(const clang::NamedDecl* parameter)
|
||||
{
|
||||
std::wstring templateParameterTypeString;
|
||||
|
||||
if (parameter)
|
||||
{
|
||||
const std::wstring parameterName = utility::decodeFromUtf8(parameter->getName());
|
||||
|
||||
const clang::Decl::Kind templateParameterKind = parameter->getKind();
|
||||
switch (templateParameterKind)
|
||||
{
|
||||
case clang::Decl::NonTypeTemplateParm:
|
||||
templateParameterTypeString = getTemplateParameterTypeString(clang::dyn_cast<clang::NonTypeTemplateParmDecl>(parameter));
|
||||
break;
|
||||
case clang::Decl::TemplateTypeParm:
|
||||
templateParameterTypeString = getTemplateParameterTypeString(clang::dyn_cast<clang::TemplateTypeParmDecl>(parameter));
|
||||
break;
|
||||
case clang::Decl::TemplateTemplateParm:
|
||||
templateParameterTypeString = getTemplateParameterTypeString(clang::dyn_cast<clang::TemplateTemplateParmDecl>(parameter));
|
||||
break;
|
||||
default:
|
||||
// LOG_ERROR("Unhandled kind of template parameter.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parameterName.empty())
|
||||
{
|
||||
templateParameterTypeString += L" " + parameterName;
|
||||
}
|
||||
}
|
||||
return templateParameterTypeString;
|
||||
}
|
||||
|
||||
std::wstring CxxTemplateParameterStringResolver::getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter)
|
||||
{
|
||||
CxxTypeNameResolver typeNameResolver(getCanonicalFilePathCache(), getIgnoredContextDecls());
|
||||
std::shared_ptr<CxxTypeName> typeName = CxxTypeName::makeUnsolvedIfNull(typeNameResolver.getName(parameter->getType()));
|
||||
|
||||
std::wstring typeString = typeName->toString();
|
||||
|
||||
if (parameter->isTemplateParameterPack())
|
||||
{
|
||||
typeString += L"...";
|
||||
}
|
||||
|
||||
return typeString;
|
||||
}
|
||||
|
||||
std::wstring CxxTemplateParameterStringResolver::getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter)
|
||||
{
|
||||
std::wstring typeString = (parameter->wasDeclaredWithTypename() ? L"typename" : L"class");
|
||||
|
||||
if (parameter->isTemplateParameterPack())
|
||||
{
|
||||
typeString += L"...";
|
||||
}
|
||||
|
||||
return typeString;
|
||||
}
|
||||
|
||||
std::wstring CxxTemplateParameterStringResolver::getTemplateParameterTypeString(const clang::TemplateTemplateParmDecl* parameter)
|
||||
{
|
||||
std::wstring templateParameterTypeString = L"template<";
|
||||
clang::TemplateParameterList* parameterList = parameter->getTemplateParameters();
|
||||
for (size_t i = 0; i < parameterList->size(); i++)
|
||||
{
|
||||
CxxTemplateParameterStringResolver parameterStringResolver(getCanonicalFilePathCache(), getIgnoredContextDecls());
|
||||
parameterStringResolver.ignoreContextDecl(parameterList->getParam(i));
|
||||
|
||||
templateParameterTypeString += parameterStringResolver.getTemplateParameterString(parameterList->getParam(i));
|
||||
templateParameterTypeString += (i < parameterList->size() - 1) ? L", " : L"";
|
||||
}
|
||||
templateParameterTypeString += L">";
|
||||
templateParameterTypeString += L" typename"; // TODO: what if template template parameter is defined with class keyword?
|
||||
|
||||
if (parameter->isTemplateParameterPack())
|
||||
{
|
||||
templateParameterTypeString += L"...";
|
||||
}
|
||||
|
||||
return templateParameterTypeString;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef CXX_TEMPLATE_PARAMETER_STRING_RESOLVER_H
|
||||
#define CXX_TEMPLATE_PARAMETER_STRING_RESOLVER_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxNameResolver.h"
|
||||
|
||||
class DataType;
|
||||
|
||||
class CxxTemplateParameterStringResolver: public CxxNameResolver
|
||||
{
|
||||
public:
|
||||
CxxTemplateParameterStringResolver(std::shared_ptr<CanonicalFilePathCache> canonicalFilePathCache);
|
||||
CxxTemplateParameterStringResolver(
|
||||
std::shared_ptr<CanonicalFilePathCache> canonicalFilePathCache,
|
||||
std::vector<const clang::Decl*> ignoredContextDecls
|
||||
);
|
||||
|
||||
std::wstring getTemplateParameterString(const clang::NamedDecl* parameter);
|
||||
std::wstring getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter);
|
||||
std::wstring getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter);
|
||||
std::wstring getTemplateParameterTypeString(const clang::TemplateTemplateParmDecl* parameter);
|
||||
};
|
||||
|
||||
#endif // CXX_TEMPLATE_PARAMETER_STRING_RESOLVER_H
|
||||
@@ -23,10 +23,6 @@ CxxTypeNameResolver::CxxTypeNameResolver(
|
||||
{
|
||||
}
|
||||
|
||||
CxxTypeNameResolver::~CxxTypeNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<CxxTypeName> CxxTypeNameResolver::getName(const clang::QualType& qualType)
|
||||
{
|
||||
std::shared_ptr<CxxTypeName> typeName = getName(qualType.getTypePtr());
|
||||
|
||||
@@ -12,7 +12,6 @@ public:
|
||||
std::shared_ptr<CanonicalFilePathCache> canonicalFilePathCache,
|
||||
std::vector<const clang::Decl*> ignoredContextDecls
|
||||
);
|
||||
virtual ~CxxTypeNameResolver();
|
||||
|
||||
std::shared_ptr<CxxTypeName> getName(const clang::QualType& qualType);
|
||||
std::shared_ptr<CxxTypeName> getName(const clang::Type* type);
|
||||
|
||||
@@ -860,6 +860,20 @@ public:
|
||||
));
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_non_type_template_parameter_that_depends_on_type_template_parameter_of_template_template_parameter()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
"template <template<typename T, T R>typename S>\n"
|
||||
"class A\n"
|
||||
"{\n"
|
||||
"};\n"
|
||||
);
|
||||
|
||||
TS_ASSERT(utility::containsElement<std::wstring>(
|
||||
client->templateParameterTypes, L"A<template<typename T, T R> typename S>::S<typename T, T R> <1:45 1:45>"
|
||||
));
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_template_argument_of_dependent_non_type_template_parameter()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
|
||||
Reference in New Issue
Block a user