logic: fixed infinite recursion while solving c++ template parameter names (issue #553)

This commit is contained in:
mlangkabel
2018-03-20 18:47:42 +01:00
parent b5f9e77154
commit 4c92d51b63
14 changed files with 154 additions and 105 deletions
+2
View File
@@ -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);
+14
View File
@@ -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(