data: name resolving refactored
* Created CxxNameResolver classes that take care of resolving the name hierarchies of clang components. * NameResolvers store clang::Decls they ignore when traversing the hierarchy of DeclContext nodes. This approach is used to avoid infinite loops when parsing template parameters of a template class that depends on it's template parameters that depend on the template class.... <description>
This commit is contained in:
@@ -1,6 +1,15 @@
|
||||
add_files(
|
||||
CLANG_FILES
|
||||
|
||||
data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp
|
||||
data/parser/cxx/name_resolver/CxxDeclNameResolver.h
|
||||
data/parser/cxx/name_resolver/CxxNameResolver.cpp
|
||||
data/parser/cxx/name_resolver/CxxNameResolver.h
|
||||
data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp
|
||||
data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h
|
||||
data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp
|
||||
data/parser/cxx/name_resolver/CxxTypeNameResolver.h
|
||||
|
||||
data/parser/cxx/ASTAction.cpp
|
||||
data/parser/cxx/ASTAction.h
|
||||
data/parser/cxx/ASTActionFactory.cpp
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
#include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h"
|
||||
|
||||
#include <clang/AST/DeclTemplate.h>
|
||||
#include <clang/AST/ASTContext.h>
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
|
||||
#include "utility/logging/logging.h"
|
||||
|
||||
CxxDeclNameResolver::CxxDeclNameResolver(const clang::Decl* declaration)
|
||||
: CxxNameResolver(std::vector<const clang::Decl*>())
|
||||
, m_declaration(declaration)
|
||||
{
|
||||
}
|
||||
|
||||
CxxDeclNameResolver::CxxDeclNameResolver(const clang::Decl* declaration, std::vector<const clang::Decl*> ignoredContextDecls)
|
||||
: CxxNameResolver(ignoredContextDecls)
|
||||
, m_declaration(declaration)
|
||||
{
|
||||
}
|
||||
|
||||
CxxDeclNameResolver::~CxxDeclNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
NameHierarchy CxxDeclNameResolver::getDeclNameHierarchy()
|
||||
{
|
||||
NameHierarchy contextNameHierarchy;
|
||||
if (m_declaration)
|
||||
{
|
||||
std::string declName = "";
|
||||
|
||||
if (clang::isa<clang::NamedDecl>(m_declaration))
|
||||
{
|
||||
declName = getDeclName(clang::dyn_cast<const clang::NamedDecl>(m_declaration));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("unhandled declaration type: " + std::string(m_declaration->getDeclKindName()));
|
||||
}
|
||||
|
||||
contextNameHierarchy = getContextNameHierarchy(m_declaration->getDeclContext());
|
||||
|
||||
if ((clang::isa<clang::NonTypeTemplateParmDecl>(m_declaration) ||
|
||||
clang::isa<clang::TemplateTypeParmDecl>(m_declaration) ||
|
||||
clang::isa<clang::TemplateTemplateParmDecl>(m_declaration)) &&
|
||||
contextNameHierarchy.size() > 0)
|
||||
{
|
||||
std::string lastContextElementName = contextNameHierarchy.back()->getFullName();
|
||||
contextNameHierarchy.pop();
|
||||
contextNameHierarchy.push(std::make_shared<NameElement>(lastContextElementName + "::" + declName));
|
||||
}
|
||||
else
|
||||
{
|
||||
contextNameHierarchy.push(std::make_shared<NameElement>(declName));
|
||||
}
|
||||
}
|
||||
return contextNameHierarchy;
|
||||
}
|
||||
|
||||
NameHierarchy CxxDeclNameResolver::getContextNameHierarchy(const clang::DeclContext* declContext)
|
||||
{
|
||||
NameHierarchy contextNameHierarchy;
|
||||
|
||||
if (!ignoresContext(declContext))
|
||||
{
|
||||
const clang::DeclContext* parentContext = declContext->getParent();
|
||||
if (parentContext)
|
||||
{
|
||||
contextNameHierarchy = getContextNameHierarchy(parentContext);
|
||||
}
|
||||
|
||||
if (clang::isa<clang::NamedDecl>(declContext))
|
||||
{
|
||||
std::string declName = getDeclName(clang::dyn_cast<clang::NamedDecl>(declContext));
|
||||
if (declName != "")
|
||||
{
|
||||
contextNameHierarchy.push(std::make_shared<NameElement>(declName));
|
||||
}
|
||||
}
|
||||
}
|
||||
return contextNameHierarchy;
|
||||
}
|
||||
|
||||
std::string CxxDeclNameResolver::getDeclName()
|
||||
{
|
||||
const clang::NamedDecl* declaration = clang::dyn_cast<clang::NamedDecl>(m_declaration);
|
||||
std::string declName = declaration->getNameAsString();
|
||||
clang::Decl::Kind kind = declaration->getKind();
|
||||
if (clang::isa<clang::CXXRecordDecl>(declaration))
|
||||
{
|
||||
clang::ClassTemplateDecl* templateClassDeclaration = clang::dyn_cast<clang::CXXRecordDecl>(declaration)->getDescribedClassTemplate();
|
||||
if (templateClassDeclaration)
|
||||
{
|
||||
declName = getDeclName(templateClassDeclaration);
|
||||
}
|
||||
else if (clang::isa<clang::ClassTemplatePartialSpecializationDecl>(declaration))
|
||||
{
|
||||
const clang::ClassTemplatePartialSpecializationDecl* partialSpecializationDecl =
|
||||
clang::dyn_cast<clang::ClassTemplatePartialSpecializationDecl>(declaration);
|
||||
|
||||
clang::TemplateParameterList* parameterList = partialSpecializationDecl->getTemplateParameters();
|
||||
int currentParameterIndex = 0;
|
||||
|
||||
std::string specializedParameterNamePart = "<";
|
||||
int templateArgumentCount = partialSpecializationDecl->getTemplateArgs().size();
|
||||
const clang::TemplateArgumentList& templateArgumentList = partialSpecializationDecl->getTemplateArgs();
|
||||
for (int i = 0; i < templateArgumentCount; i++)
|
||||
{
|
||||
const clang::TemplateArgument& templateArgument = templateArgumentList.get(i);
|
||||
if (templateArgument.isDependent()) // TODO: fix case when arg depends on template parameter of outer template class.
|
||||
{
|
||||
specializedParameterNamePart += getTemplateParameterString(parameterList->getParam(currentParameterIndex));
|
||||
currentParameterIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
specializedParameterNamePart += getTemplateArgumentName(templateArgument);
|
||||
}
|
||||
specializedParameterNamePart += (i < templateArgumentCount - 1) ? ", " : "";
|
||||
}
|
||||
specializedParameterNamePart += ">";
|
||||
declName += specializedParameterNamePart;
|
||||
}
|
||||
else if (clang::isa<clang::ClassTemplateSpecializationDecl>(declaration))
|
||||
{
|
||||
std::string templateArgumentNamePart = "<";
|
||||
const clang::TemplateArgumentList& templateArgumentList = clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(declaration)->getTemplateArgs();
|
||||
for (size_t i = 0; i < templateArgumentList.size(); i++)
|
||||
{
|
||||
templateArgumentNamePart += getTemplateArgumentName(templateArgumentList.get(i));
|
||||
templateArgumentNamePart += (i < templateArgumentList.size() - 1) ? ", " : "";
|
||||
}
|
||||
templateArgumentNamePart += ">";
|
||||
declName += templateArgumentNamePart;
|
||||
}
|
||||
}
|
||||
else if (clang::isa<clang::FunctionDecl>(declaration))
|
||||
{
|
||||
clang::FunctionTemplateDecl* templateFunctionDeclaration = clang::dyn_cast<clang::FunctionDecl>(declaration)->getDescribedFunctionTemplate();
|
||||
if (templateFunctionDeclaration)
|
||||
{
|
||||
declName = getDeclName(templateFunctionDeclaration);
|
||||
}
|
||||
else if (clang::dyn_cast<clang::FunctionDecl>(declaration)->isFunctionTemplateSpecialization())
|
||||
{
|
||||
std::string templateArgumentNamePart = "<";
|
||||
const clang::TemplateArgumentList* templateArgumentList = clang::dyn_cast<clang::FunctionDecl>(declaration)->getTemplateSpecializationArgs();
|
||||
for (size_t i = 0; i < templateArgumentList->size(); i++)
|
||||
{
|
||||
const clang::TemplateArgument& templateArgument = templateArgumentList->get(i);
|
||||
templateArgumentNamePart += getTemplateArgumentName(templateArgument);
|
||||
templateArgumentNamePart += (i < templateArgumentList->size() - 1) ? ", " : "";
|
||||
}
|
||||
templateArgumentNamePart += ">";
|
||||
declName += templateArgumentNamePart;
|
||||
}
|
||||
}
|
||||
else if (clang::isa<clang::TemplateDecl>(declaration)) // also triggers on TemplateTemplateParmDecl
|
||||
{
|
||||
std::string templateParameterNamePart = "<";
|
||||
clang::TemplateParameterList* parameterList = clang::dyn_cast<clang::TemplateDecl>(declaration)->getTemplateParameters();
|
||||
for (size_t i = 0; i < parameterList->size(); i++)
|
||||
{
|
||||
templateParameterNamePart += getTemplateParameterString(parameterList->getParam(i));
|
||||
templateParameterNamePart += (i < parameterList->size() - 1) ? ", " : "";
|
||||
}
|
||||
templateParameterNamePart += ">";
|
||||
declName += templateParameterNamePart;
|
||||
}
|
||||
else if (clang::isa<clang::NamespaceDecl>(declaration) && clang::dyn_cast<clang::NamespaceDecl>(declaration)->isAnonymousNamespace())
|
||||
{
|
||||
const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
|
||||
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart());
|
||||
declName = "anonymous namespace (" + std::string(presumedBegin.getFilename()) + ")";
|
||||
}
|
||||
|
||||
return declName;
|
||||
}
|
||||
|
||||
std::string CxxDeclNameResolver::getDeclName(const clang::NamedDecl* declaration)
|
||||
{
|
||||
CxxDeclNameResolver resolver(declaration);
|
||||
return resolver.getDeclName();
|
||||
}
|
||||
|
||||
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<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.");
|
||||
}
|
||||
|
||||
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<clang::TemplateDecl>(m_declaration))
|
||||
{
|
||||
typeNameResolver.ignoreContextDecl(clang::dyn_cast<clang::TemplateDecl>(m_declaration)->getTemplatedDecl());
|
||||
}
|
||||
else // works for partial template specializations
|
||||
{
|
||||
typeNameResolver.ignoreContextDecl(m_declaration);
|
||||
}
|
||||
return typeNameResolver.qualTypeToDataType(parameter->getType())->getFullTypeName();
|
||||
}
|
||||
|
||||
std::string CxxDeclNameResolver::getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter)
|
||||
{
|
||||
return (parameter->wasDeclaredWithTypename() ? "typename" : "class");
|
||||
}
|
||||
|
||||
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?
|
||||
return templateParameterTypeString;
|
||||
}
|
||||
|
||||
std::string CxxDeclNameResolver::getTemplateArgumentName(const clang::TemplateArgument& argument)
|
||||
{
|
||||
CxxTemplateArgumentNameResolver resolver(getIgnoredContextDecls());
|
||||
return resolver.getTemplateArgumentName(argument);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef CXX_DECL_NAME_RESOLVER_H
|
||||
#define CXX_DECL_NAME_RESOLVER_H
|
||||
|
||||
#include "data/name/NameHierarchy.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxNameResolver.h"
|
||||
|
||||
class CxxDeclNameResolver: public CxxNameResolver
|
||||
{
|
||||
public:
|
||||
CxxDeclNameResolver(const clang::Decl* declaration);
|
||||
CxxDeclNameResolver(const clang::Decl* declaration, std::vector<const clang::Decl*> ignoredContextDecls);
|
||||
~CxxDeclNameResolver();
|
||||
|
||||
NameHierarchy getDeclNameHierarchy();
|
||||
std::string getDeclName();
|
||||
|
||||
private:
|
||||
NameHierarchy getContextNameHierarchy(const clang::DeclContext* declaration);
|
||||
std::string getDeclName(const clang::NamedDecl* declaration);
|
||||
std::string getTemplateParameterString(const clang::NamedDecl* parameter);
|
||||
std::string getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter);
|
||||
std::string getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter);
|
||||
std::string getTemplateParameterTypeString(const clang::TemplateTemplateParmDecl* parameter);
|
||||
std::string getTemplateArgumentName(const clang::TemplateArgument& argument);
|
||||
|
||||
const clang::Decl* m_declaration;
|
||||
};
|
||||
|
||||
#endif // CXX_DECL_NAME_RESOLVER_H
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "data/parser/cxx/name_resolver/CxxNameResolver.h"
|
||||
|
||||
CxxNameResolver::CxxNameResolver(std::vector<const clang::Decl*> ignoredContextDecls)
|
||||
: m_ignoredContextDecls(ignoredContextDecls)
|
||||
{
|
||||
}
|
||||
|
||||
CxxNameResolver::~CxxNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
void CxxNameResolver::ignoreContextDecl(const clang::Decl* decl)
|
||||
{
|
||||
m_ignoredContextDecls.push_back(decl);
|
||||
}
|
||||
|
||||
bool CxxNameResolver::ignoresContext(const clang::DeclContext* declContext)
|
||||
{
|
||||
const clang::Decl* decl = clang::dyn_cast<clang::Decl>(declContext);
|
||||
for (int i = 0; i < m_ignoredContextDecls.size(); i++)
|
||||
{
|
||||
if (decl == m_ignoredContextDecls[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<const clang::Decl*> CxxNameResolver::getIgnoredContextDecls() const
|
||||
{
|
||||
return m_ignoredContextDecls;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef CXX_NAME_RESOLVER_H
|
||||
#define CXX_NAME_RESOLVER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
|
||||
class CxxNameResolver
|
||||
{
|
||||
public:
|
||||
CxxNameResolver(std::vector<const clang::Decl*> ignoredContextDecls);
|
||||
~CxxNameResolver();
|
||||
|
||||
void ignoreContextDecl(const clang::Decl* decl);
|
||||
bool ignoresContext(const clang::DeclContext* declContext);
|
||||
|
||||
protected:
|
||||
std::vector<const clang::Decl*> getIgnoredContextDecls() const;
|
||||
|
||||
private:
|
||||
std::vector<const clang::Decl*> m_ignoredContextDecls;
|
||||
};
|
||||
|
||||
#endif // CXX_NAME_RESOLVER_H
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h"
|
||||
|
||||
#include <clang/AST/PrettyPrinter.h>
|
||||
#include <clang/AST/DeclTemplate.h>
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
|
||||
#include "utility/logging/logging.h"
|
||||
|
||||
CxxTemplateArgumentNameResolver::CxxTemplateArgumentNameResolver()
|
||||
: CxxNameResolver(std::vector<const clang::Decl*>())
|
||||
{
|
||||
}
|
||||
|
||||
CxxTemplateArgumentNameResolver::CxxTemplateArgumentNameResolver(std::vector<const clang::Decl*> ignoredContextDecls)
|
||||
: CxxNameResolver(ignoredContextDecls)
|
||||
{
|
||||
}
|
||||
|
||||
CxxTemplateArgumentNameResolver::~CxxTemplateArgumentNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
std::string CxxTemplateArgumentNameResolver::getTemplateArgumentName(const clang::TemplateArgument& argument)
|
||||
{
|
||||
const clang::TemplateArgument::ArgKind kind = argument.getKind();
|
||||
switch (kind)
|
||||
{
|
||||
case clang::TemplateArgument::Type:
|
||||
{
|
||||
CxxTypeNameResolver typeNameResolver(getIgnoredContextDecls());
|
||||
return typeNameResolver.qualTypeToDataType(argument.getAsType())->getFullTypeName();
|
||||
}
|
||||
case clang::TemplateArgument::Integral:
|
||||
case clang::TemplateArgument::Null:
|
||||
case clang::TemplateArgument::Declaration:
|
||||
case clang::TemplateArgument::NullPtr:
|
||||
case clang::TemplateArgument::Template:
|
||||
case clang::TemplateArgument::TemplateExpansion:
|
||||
case clang::TemplateArgument::Expression:
|
||||
{
|
||||
clang::PrintingPolicy pp = clang::PrintingPolicy(clang::LangOptions());
|
||||
pp.SuppressTagKeyword = true; // value "true": for a class A it prints "A" instead of "class A"
|
||||
pp.Bool = true; // value "true": prints bool type as "bool" instead of "_Bool"
|
||||
|
||||
std::string buf;
|
||||
llvm::raw_string_ostream os(buf);
|
||||
argument.print(pp, os);
|
||||
return os.str();
|
||||
}
|
||||
case clang::TemplateArgument::Pack:
|
||||
LOG_ERROR("Type of template argument not handled: Pack");
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Type of template argument not handled." + argument.getKind());
|
||||
break;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef CXX_TEMPLATE_ARGUMENT_NAME_RESOLVER_H
|
||||
#define CXX_TEMPLATE_ARGUMENT_NAME_RESOLVER_H
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxNameResolver.h"
|
||||
|
||||
class CxxTemplateArgumentNameResolver: public CxxNameResolver
|
||||
{
|
||||
public:
|
||||
CxxTemplateArgumentNameResolver();
|
||||
CxxTemplateArgumentNameResolver(std::vector<const clang::Decl*> ignoredContextDecls);
|
||||
~CxxTemplateArgumentNameResolver();
|
||||
|
||||
std::string getTemplateArgumentName(const clang::TemplateArgument& argument);
|
||||
};
|
||||
|
||||
#endif // CXX_TEMPLATE_ARGUMENT_NAME_RESOLVER_H
|
||||
@@ -0,0 +1,228 @@
|
||||
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
|
||||
|
||||
#include <clang/AST/PrettyPrinter.h>
|
||||
#include <clang/AST/DeclTemplate.h>
|
||||
#include <clang/AST/ASTContext.h>
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h"
|
||||
#include "data/type/DataType.h"
|
||||
#include "data/type/NamedDataType.h"
|
||||
#include "data/type/ArrayModifiedDataType.h"
|
||||
#include "data/type/PointerModifiedDataType.h"
|
||||
#include "data/type/ReferenceModifiedDataType.h"
|
||||
#include "utility/logging/logging.h"
|
||||
|
||||
CxxTypeNameResolver::CxxTypeNameResolver()
|
||||
: CxxNameResolver(std::vector<const clang::Decl*>())
|
||||
{
|
||||
}
|
||||
|
||||
CxxTypeNameResolver::CxxTypeNameResolver(std::vector<const clang::Decl*> ignoredContextDecls)
|
||||
: CxxNameResolver(ignoredContextDecls)
|
||||
{
|
||||
}
|
||||
|
||||
CxxTypeNameResolver::~CxxTypeNameResolver()
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<DataType> CxxTypeNameResolver::qualTypeToDataType(clang::QualType qualType)
|
||||
{
|
||||
std::shared_ptr<DataType> dataType = typeToDataType(qualType.getTypePtr());
|
||||
if (qualType.isConstQualified())
|
||||
{
|
||||
dataType->addQualifier(DataType::QUALIFIER_CONST);
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
std::shared_ptr<DataType> CxxTypeNameResolver::typeToDataType(const clang::Type* type)
|
||||
{
|
||||
std::shared_ptr<DataType> dataType;
|
||||
|
||||
switch (type->getTypeClass())
|
||||
{
|
||||
case clang::Type::Paren:
|
||||
{
|
||||
dataType = qualTypeToDataType(type->getAs<clang::ParenType>()->getInnerType());
|
||||
break;
|
||||
}
|
||||
case clang::Type::Typedef:
|
||||
{
|
||||
CxxDeclNameResolver declNameResolver(type->getAs<clang::TypedefType>()->getDecl(), getIgnoredContextDecls());
|
||||
dataType = std::make_shared<NamedDataType>(declNameResolver.getDeclNameHierarchy());
|
||||
break;
|
||||
}
|
||||
case clang::Type::MemberPointer:
|
||||
{
|
||||
int ogogo = 0; // test this case!
|
||||
}
|
||||
case clang::Type::Pointer:
|
||||
{
|
||||
std::shared_ptr<DataType> innerType = qualTypeToDataType(type->getPointeeType());
|
||||
dataType = std::make_shared<PointerModifiedDataType>(innerType);
|
||||
break;
|
||||
}
|
||||
case clang::Type::ConstantArray:
|
||||
case clang::Type::VariableArray:
|
||||
case clang::Type::DependentSizedArray:
|
||||
case clang::Type::IncompleteArray:
|
||||
{
|
||||
std::shared_ptr<DataType> innerType = qualTypeToDataType(clang::dyn_cast<clang::ArrayType>(type)->getElementType());
|
||||
dataType = std::make_shared<ArrayModifiedDataType>(innerType);
|
||||
break;
|
||||
}
|
||||
case clang::Type::LValueReference:
|
||||
case clang::Type::RValueReference:
|
||||
{
|
||||
std::shared_ptr<DataType> innerType = qualTypeToDataType(type->getPointeeType());
|
||||
dataType = std::make_shared<ReferenceModifiedDataType>(innerType);
|
||||
break;
|
||||
}
|
||||
case clang::Type::Elaborated:
|
||||
{
|
||||
dataType = qualTypeToDataType(clang::dyn_cast<clang::ElaboratedType>(type)->getNamedType());
|
||||
break;
|
||||
}
|
||||
case clang::Type::Enum:
|
||||
case clang::Type::Record:
|
||||
{
|
||||
CxxDeclNameResolver declNameResolver(type->getAs<clang::TagType>()->getDecl(), getIgnoredContextDecls());
|
||||
dataType = std::make_shared<NamedDataType>(declNameResolver.getDeclNameHierarchy());
|
||||
break;
|
||||
}
|
||||
case clang::Type::Builtin:
|
||||
{
|
||||
clang::PrintingPolicy pp = clang::PrintingPolicy(clang::LangOptions());
|
||||
pp.SuppressTagKeyword = true; // value "true": for a class A it prints "A" instead of "class A"
|
||||
pp.Bool = true; // value "true": prints bool type as "bool" instead of "_Bool"
|
||||
|
||||
clang::SmallString<64> Buf;
|
||||
llvm::raw_svector_ostream StrOS(Buf);
|
||||
clang::QualType::print(type, clang::Qualifiers(), StrOS, pp, clang::Twine());
|
||||
std::string typeName = StrOS.str();
|
||||
|
||||
NameHierarchy typeNameHerarchy;
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(typeName));
|
||||
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
case clang::Type::TemplateSpecialization:
|
||||
{
|
||||
NameHierarchy typeNameHerarchy;
|
||||
|
||||
const clang::TagType* tagType = type->getAs<clang::TagType>(); // remove this case when NameHierarchy is split into namepart and parameter part
|
||||
if (tagType)
|
||||
{
|
||||
CxxDeclNameResolver declNameResolver(tagType->getDecl(), getIgnoredContextDecls());
|
||||
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
|
||||
}
|
||||
else // specialization of a template template parameter (no concrete class)
|
||||
{
|
||||
const clang::TemplateSpecializationType* templateSpecializationType = type->getAs<clang::TemplateSpecializationType>();
|
||||
CxxDeclNameResolver declNameResolver(templateSpecializationType->getTemplateName().getAsTemplateDecl(), getIgnoredContextDecls());
|
||||
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
|
||||
|
||||
if (typeNameHerarchy.size() > 0)
|
||||
{
|
||||
std::string templateArgumentNamePart = "<";
|
||||
CxxTemplateArgumentNameResolver resolver(getIgnoredContextDecls());
|
||||
for (int i = 0; i < templateSpecializationType->getNumArgs(); i++)
|
||||
{
|
||||
templateArgumentNamePart += resolver.getTemplateArgumentName(templateSpecializationType->getArg(i));
|
||||
if (i < templateSpecializationType->getNumArgs() - 1)
|
||||
templateArgumentNamePart += ", ";
|
||||
}
|
||||
templateArgumentNamePart += ">";
|
||||
|
||||
std::string declName = typeNameHerarchy.back()->getFullName();
|
||||
declName = declName.substr(0, declName.rfind("<")); // remove template parameters - does not work for A<ajaj<ajsj>>
|
||||
declName += templateArgumentNamePart; // add template arguments
|
||||
typeNameHerarchy.pop();
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(declName));
|
||||
}
|
||||
}
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
case clang::Type::TemplateTypeParm:
|
||||
{
|
||||
clang::TemplateTypeParmDecl* templateTypeParmDecl = clang::dyn_cast<clang::TemplateTypeParmType>(type)->getDecl();
|
||||
|
||||
CxxDeclNameResolver declNameResolver(templateTypeParmDecl, getIgnoredContextDecls());
|
||||
NameHierarchy typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
|
||||
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
case clang::Type::SubstTemplateTypeParm:
|
||||
{
|
||||
dataType = qualTypeToDataType(type->getAs<clang::SubstTemplateTypeParmType>()->getReplacementType());
|
||||
break;
|
||||
}
|
||||
case clang::Type::DependentName:
|
||||
{
|
||||
const clang::DependentNameType* dependentNameType = clang::dyn_cast<clang::DependentNameType>(type);
|
||||
clang::NestedNameSpecifier* nns = dependentNameType->getQualifier();
|
||||
clang::NestedNameSpecifier::SpecifierKind nnsKind = nns->getKind();
|
||||
NameHierarchy typeNameHerarchy;
|
||||
switch (nnsKind)
|
||||
{
|
||||
case clang::NestedNameSpecifier::Identifier:
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(nns->getAsIdentifier()->getName())); // TODO: Test this one.
|
||||
break;
|
||||
case clang::NestedNameSpecifier::Namespace:
|
||||
{
|
||||
CxxDeclNameResolver declNameResolver(nns->getAsNamespace(), getIgnoredContextDecls());
|
||||
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
|
||||
}
|
||||
break;
|
||||
case clang::NestedNameSpecifier::NamespaceAlias:
|
||||
{
|
||||
CxxDeclNameResolver declNameResolver(nns->getAsNamespaceAlias(), getIgnoredContextDecls());
|
||||
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
|
||||
}
|
||||
break;
|
||||
case clang::NestedNameSpecifier::TypeSpec:
|
||||
case clang::NestedNameSpecifier::TypeSpecWithTemplate:
|
||||
typeNameHerarchy = typeToDataType(nns->getAsType())->getTypeNameHierarchy();
|
||||
break;
|
||||
case clang::NestedNameSpecifier::Global:
|
||||
// no context name hierarchy needed.
|
||||
break;
|
||||
case clang::NestedNameSpecifier::Super:
|
||||
{
|
||||
CxxDeclNameResolver declNameResolver(nns->getAsRecordDecl(), getIgnoredContextDecls());
|
||||
typeNameHerarchy = declNameResolver.getDeclNameHierarchy();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(dependentNameType->getIdentifier()->getName().str()));
|
||||
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(std::string("Unhandled kind of type encountered: ") + type->getTypeClassName());
|
||||
clang::PrintingPolicy pp = clang::PrintingPolicy(clang::LangOptions());
|
||||
pp.SuppressTagKeyword = true; // value "true": for a class A it prints "A" instead of "class A"
|
||||
pp.Bool = true; // value "true": prints bool type as "bool" instead of "_Bool"
|
||||
|
||||
clang::SmallString<64> Buf;
|
||||
llvm::raw_svector_ostream StrOS(Buf);
|
||||
clang::QualType::print(type, clang::Qualifiers(), StrOS, pp, clang::Twine());
|
||||
std::string typeName = StrOS.str();
|
||||
|
||||
NameHierarchy typeNameHerarchy;
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(typeName));
|
||||
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef CXX_TYPE_NAME_RESOLVER_H
|
||||
#define CXX_TYPE_NAME_RESOLVER_H
|
||||
|
||||
#include "data/parser/cxx/name_resolver/CxxNameResolver.h"
|
||||
#include "data/type/DataType.h"
|
||||
|
||||
class CxxTypeNameResolver: public CxxNameResolver
|
||||
{
|
||||
public:
|
||||
CxxTypeNameResolver();
|
||||
CxxTypeNameResolver(std::vector<const clang::Decl*> ignoredContextDecls);
|
||||
~CxxTypeNameResolver();
|
||||
|
||||
std::shared_ptr<DataType> qualTypeToDataType(clang::QualType qualType);
|
||||
|
||||
private:
|
||||
std::shared_ptr<DataType> typeToDataType(const clang::Type* type);
|
||||
};
|
||||
|
||||
#endif // CXX_TYPE_NAME_RESOLVER_H
|
||||
@@ -1,378 +1,22 @@
|
||||
#include "data/parser/cxx/utilityCxx.h"
|
||||
|
||||
#include <clang/AST/PrettyPrinter.h>
|
||||
#include <clang/AST/DeclTemplate.h>
|
||||
#include <clang/AST/ASTContext.h>
|
||||
|
||||
#include "data/type/DataType.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h"
|
||||
#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h"
|
||||
#include "data/type/NamedDataType.h"
|
||||
#include "data/type/ArrayModifiedDataType.h"
|
||||
#include "data/type/PointerModifiedDataType.h"
|
||||
#include "data/type/ReferenceModifiedDataType.h"
|
||||
|
||||
#include "utility/utilityString.h"
|
||||
#include "utility/logging/logging.h"
|
||||
|
||||
namespace utility
|
||||
{
|
||||
std::shared_ptr<DataType> qualTypeToDataType(clang::QualType qualType)
|
||||
{
|
||||
std::shared_ptr<DataType> dataType = typeToDataType(qualType.getTypePtr());
|
||||
if (qualType.isConstQualified())
|
||||
{
|
||||
dataType->addQualifier(DataType::QUALIFIER_CONST);
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
std::shared_ptr<DataType> typeToDataType(const clang::Type* type)
|
||||
{
|
||||
std::shared_ptr<DataType> dataType;
|
||||
|
||||
switch (type->getTypeClass())
|
||||
{
|
||||
case clang::Type::Paren:
|
||||
{
|
||||
dataType = qualTypeToDataType(type->getAs<clang::ParenType>()->getInnerType());
|
||||
break;
|
||||
}
|
||||
case clang::Type::Typedef:
|
||||
{
|
||||
dataType = std::make_shared<NamedDataType>(getDeclNameHierarchy(type->getAs<clang::TypedefType>()->getDecl()));
|
||||
break;
|
||||
}
|
||||
case clang::Type::MemberPointer:
|
||||
{
|
||||
int ogogo = 0; // test this case!
|
||||
}
|
||||
case clang::Type::Pointer:
|
||||
{
|
||||
std::shared_ptr<DataType> innerType = qualTypeToDataType(type->getPointeeType());
|
||||
dataType = std::make_shared<PointerModifiedDataType>(innerType);
|
||||
break;
|
||||
}
|
||||
case clang::Type::ConstantArray:
|
||||
case clang::Type::VariableArray:
|
||||
case clang::Type::DependentSizedArray:
|
||||
case clang::Type::IncompleteArray:
|
||||
{
|
||||
std::shared_ptr<DataType> innerType = qualTypeToDataType(clang::dyn_cast<clang::ArrayType>(type)->getElementType());
|
||||
dataType = std::make_shared<ArrayModifiedDataType>(innerType);
|
||||
break;
|
||||
}
|
||||
case clang::Type::LValueReference:
|
||||
case clang::Type::RValueReference:
|
||||
{
|
||||
std::shared_ptr<DataType> innerType = qualTypeToDataType(type->getPointeeType());
|
||||
dataType = std::make_shared<ReferenceModifiedDataType>(innerType);
|
||||
break;
|
||||
}
|
||||
case clang::Type::Elaborated:
|
||||
{
|
||||
dataType = qualTypeToDataType(clang::dyn_cast<clang::ElaboratedType>(type)->getNamedType());
|
||||
break;
|
||||
}
|
||||
case clang::Type::Enum:
|
||||
case clang::Type::Record:
|
||||
{
|
||||
dataType = std::make_shared<NamedDataType>(getDeclNameHierarchy(type->getAs<clang::TagType>()->getDecl()));
|
||||
break;
|
||||
}
|
||||
case clang::Type::Builtin:
|
||||
{
|
||||
clang::PrintingPolicy pp = clang::PrintingPolicy(clang::LangOptions());
|
||||
pp.SuppressTagKeyword = true; // value "true": for a class A it prints "A" instead of "class A"
|
||||
pp.Bool = true; // value "true": prints bool type as "bool" instead of "_Bool"
|
||||
|
||||
clang::SmallString<64> Buf;
|
||||
llvm::raw_svector_ostream StrOS(Buf);
|
||||
clang::QualType::print(type, clang::Qualifiers(), StrOS, pp, clang::Twine());
|
||||
std::string typeName = StrOS.str();
|
||||
|
||||
NameHierarchy typeNameHerarchy;
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(typeName));
|
||||
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
case clang::Type::TemplateSpecialization:
|
||||
{
|
||||
NameHierarchy typeNameHerarchy;
|
||||
|
||||
const clang::TagType* tagType = type->getAs<clang::TagType>(); // remove this case when NameHierarchy is split into namepart and parameter part
|
||||
if (tagType)
|
||||
{
|
||||
typeNameHerarchy = getDeclNameHierarchy(tagType->getDecl());
|
||||
}
|
||||
else // specialization depends on template template parameter type
|
||||
{
|
||||
const clang::TemplateSpecializationType* templateSpecializationType = type->getAs<clang::TemplateSpecializationType>();
|
||||
typeNameHerarchy = getDeclNameHierarchy(templateSpecializationType->getTemplateName().getAsTemplateDecl());
|
||||
|
||||
if (typeNameHerarchy.size() > 0)
|
||||
{
|
||||
std::string templateArgumentPart = "<";
|
||||
for (int i = 0; i < templateSpecializationType->getNumArgs(); i++)
|
||||
{
|
||||
templateArgumentPart += getTemplateArgumentName(templateSpecializationType->getArg(i));
|
||||
if (i < templateSpecializationType->getNumArgs() - 1)
|
||||
templateArgumentPart += ", ";
|
||||
}
|
||||
templateArgumentPart += ">";
|
||||
|
||||
std::string declName = typeNameHerarchy.back()->getFullName();
|
||||
declName = declName.substr(0, declName.rfind("<")); // remove template parameters - does not work for A<ajaj<ajsj>>
|
||||
declName += templateArgumentPart; // add template arguments
|
||||
typeNameHerarchy.pop();
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(declName));
|
||||
}
|
||||
}
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
case clang::Type::TemplateTypeParm:
|
||||
{
|
||||
clang::TemplateTypeParmDecl* templateTypeParmDecl = clang::dyn_cast<clang::TemplateTypeParmType>(type)->getDecl();
|
||||
|
||||
std::string typeName = getDeclName(templateTypeParmDecl);
|
||||
NameHierarchy typeNameHerarchy = getContextNameHierarchyOfTemplateParameter(templateTypeParmDecl);
|
||||
|
||||
if (typeNameHerarchy.size() == 0)
|
||||
{
|
||||
LOG_ERROR("Unable to resolve type name hierarchy for template parameter \"" + typeName + "\"");
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(typeName));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string lastContextElementName = typeNameHerarchy.back()->getFullName();
|
||||
typeNameHerarchy.pop();
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(lastContextElementName + "::" + typeName));
|
||||
}
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
case clang::Type::SubstTemplateTypeParm:
|
||||
{
|
||||
dataType = qualTypeToDataType(type->getAs<clang::SubstTemplateTypeParmType>()->getReplacementType());
|
||||
break;
|
||||
}
|
||||
case clang::Type::DependentName:
|
||||
{
|
||||
const clang::DependentNameType* dependentNameType = clang::dyn_cast<clang::DependentNameType>(type);
|
||||
clang::NestedNameSpecifier* nns = dependentNameType->getQualifier();
|
||||
clang::NestedNameSpecifier::SpecifierKind nnsKind = nns->getKind();
|
||||
NameHierarchy typeNameHerarchy;
|
||||
switch (nnsKind)
|
||||
{
|
||||
case clang::NestedNameSpecifier::Identifier:
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(nns->getAsIdentifier()->getName()));
|
||||
LOG_ERROR("Unable to resolve name of nested name specifier of kind: Identifier"); // this one is not tested yet. tell malte if you get this log error.
|
||||
break;
|
||||
case clang::NestedNameSpecifier::Namespace:
|
||||
typeNameHerarchy = getDeclNameHierarchy(nns->getAsNamespace());
|
||||
break;
|
||||
case clang::NestedNameSpecifier::NamespaceAlias:
|
||||
typeNameHerarchy = getDeclNameHierarchy(nns->getAsNamespaceAlias());
|
||||
break;
|
||||
case clang::NestedNameSpecifier::TypeSpec:
|
||||
case clang::NestedNameSpecifier::TypeSpecWithTemplate:
|
||||
typeNameHerarchy = typeToDataType(nns->getAsType())->getTypeNameHierarchy();
|
||||
break;
|
||||
case clang::NestedNameSpecifier::Global:
|
||||
// no context name hierarchy needed.
|
||||
break;
|
||||
case clang::NestedNameSpecifier::Super:
|
||||
typeNameHerarchy = getDeclNameHierarchy(nns->getAsRecordDecl());
|
||||
break;
|
||||
}
|
||||
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(dependentNameType->getIdentifier()->getName().str()));
|
||||
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(std::string("Unhandled kind of type encountered: ") + type->getTypeClassName());
|
||||
clang::PrintingPolicy pp = clang::PrintingPolicy(clang::LangOptions());
|
||||
pp.SuppressTagKeyword = true; // value "true": for a class A it prints "A" instead of "class A"
|
||||
pp.Bool = true; // value "true": prints bool type as "bool" instead of "_Bool"
|
||||
|
||||
clang::SmallString<64> Buf;
|
||||
llvm::raw_svector_ostream StrOS(Buf);
|
||||
clang::QualType::print(type, clang::Qualifiers(), StrOS, pp, clang::Twine());
|
||||
std::string typeName = StrOS.str();
|
||||
|
||||
NameHierarchy typeNameHerarchy;
|
||||
typeNameHerarchy.push(std::make_shared<NameElement>(typeName));
|
||||
|
||||
dataType = std::make_shared<NamedDataType>(typeNameHerarchy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dataType;
|
||||
CxxTypeNameResolver resolver;
|
||||
return resolver.qualTypeToDataType(qualType);
|
||||
}
|
||||
|
||||
NameHierarchy getDeclNameHierarchy(const clang::Decl* declaration)
|
||||
{
|
||||
NameHierarchy contextNameHierarchy;
|
||||
if (declaration)
|
||||
{
|
||||
std::string declName = "";
|
||||
|
||||
if (clang::isa<clang::NamedDecl>(declaration))
|
||||
{
|
||||
declName = getDeclName(clang::dyn_cast<const clang::NamedDecl>(declaration));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("unhandled declaration type: " + std::string(declaration->getDeclKindName()));
|
||||
}
|
||||
contextNameHierarchy = getContextNameHierarchy(declaration->getDeclContext());
|
||||
if (clang::isa<clang::NonTypeTemplateParmDecl>(declaration) ||
|
||||
clang::isa<clang::TemplateTypeParmDecl>(declaration) ||
|
||||
clang::isa<clang::TemplateTemplateParmDecl>(declaration))
|
||||
{
|
||||
std::string lastContextElementName = contextNameHierarchy.back()->getFullName();
|
||||
contextNameHierarchy.pop();
|
||||
contextNameHierarchy.push(std::make_shared<NameElement>(lastContextElementName + "::" + declName));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
contextNameHierarchy.push(std::make_shared<NameElement>(declName));
|
||||
}
|
||||
}
|
||||
return contextNameHierarchy;
|
||||
}
|
||||
|
||||
NameHierarchy getContextNameHierarchy(const clang::DeclContext* declContext)
|
||||
{
|
||||
NameHierarchy contextNameHierarchy;
|
||||
|
||||
const clang::DeclContext* parentContext = declContext->getParent();
|
||||
if (parentContext)
|
||||
{
|
||||
contextNameHierarchy = getContextNameHierarchy(parentContext);
|
||||
}
|
||||
|
||||
if (clang::isa<clang::NamedDecl>(declContext))
|
||||
{
|
||||
std::string declName = getDeclName(clang::dyn_cast<clang::NamedDecl>(declContext));
|
||||
if (declName != "")
|
||||
{
|
||||
contextNameHierarchy.push(std::make_shared<NameElement>(declName));
|
||||
}
|
||||
}
|
||||
return contextNameHierarchy;
|
||||
}
|
||||
|
||||
NameHierarchy getContextNameHierarchyOfTemplateParameter(const clang::NamedDecl* templateParmDecl) // why do we need this??
|
||||
{
|
||||
NameHierarchy contextNameHierarchy;
|
||||
|
||||
const clang::Decl* parentNode = getAstParentDecl(templateParmDecl);
|
||||
if (parentNode && clang::isa<clang::NamedDecl>(parentNode))
|
||||
{
|
||||
const clang::NamedDecl* parentNamedDecl = clang::dyn_cast<clang::NamedDecl>(parentNode);
|
||||
contextNameHierarchy = getDeclNameHierarchy(parentNamedDecl);
|
||||
}
|
||||
|
||||
return contextNameHierarchy;
|
||||
}
|
||||
|
||||
std::string getDeclName(const clang::NamedDecl* declaration)
|
||||
{
|
||||
std::string declName = declaration->getNameAsString();
|
||||
clang::Decl::Kind kind = declaration->getKind();
|
||||
if (clang::isa<clang::CXXRecordDecl>(declaration))
|
||||
{
|
||||
clang::ClassTemplateDecl* templateClassDeclaration = clang::dyn_cast<clang::CXXRecordDecl>(declaration)->getDescribedClassTemplate();
|
||||
if (templateClassDeclaration)
|
||||
{
|
||||
declName = getDeclName(templateClassDeclaration);
|
||||
}
|
||||
else if (clang::isa<clang::ClassTemplatePartialSpecializationDecl>(declaration))
|
||||
{
|
||||
const clang::ClassTemplatePartialSpecializationDecl* partialSpecializationDecl =
|
||||
clang::dyn_cast<clang::ClassTemplatePartialSpecializationDecl>(declaration);
|
||||
|
||||
clang::TemplateParameterList* parameterList = partialSpecializationDecl->getTemplateParameters();
|
||||
int currentParameterIndex = 0;
|
||||
|
||||
std::string specializedParameterNamePart = "<";
|
||||
int templateArgumentCount = partialSpecializationDecl->getTemplateArgs().size();
|
||||
const clang::TemplateArgumentList& templateArgumentList = partialSpecializationDecl->getTemplateArgs();
|
||||
for (int i = 0; i < templateArgumentCount; i++)
|
||||
{
|
||||
const clang::TemplateArgument& templateArgument = templateArgumentList.get(i);
|
||||
if (templateArgument.isDependent()) // TODO: fix case when arg depends on template parameter of outer template class.
|
||||
{
|
||||
specializedParameterNamePart += getTemplateParameterString(parameterList->getParam(currentParameterIndex));
|
||||
currentParameterIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
specializedParameterNamePart += getTemplateArgumentName(templateArgument);
|
||||
}
|
||||
specializedParameterNamePart += (i < templateArgumentCount - 1) ? ", " : "";
|
||||
}
|
||||
specializedParameterNamePart += ">";
|
||||
declName += specializedParameterNamePart;
|
||||
}
|
||||
else if (clang::isa<clang::ClassTemplateSpecializationDecl>(declaration))
|
||||
{
|
||||
std::string specializedParameterNamePart = "<";
|
||||
const clang::TemplateArgumentList& templateArgumentList = clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(declaration)->getTemplateArgs();
|
||||
for (size_t i = 0; i < templateArgumentList.size(); i++)
|
||||
{
|
||||
specializedParameterNamePart += getTemplateArgumentName(templateArgumentList.get(i));
|
||||
specializedParameterNamePart += (i < templateArgumentList.size() - 1) ? ", " : "";
|
||||
}
|
||||
specializedParameterNamePart += ">";
|
||||
declName += specializedParameterNamePart;
|
||||
}
|
||||
}
|
||||
else if (clang::isa<clang::FunctionDecl>(declaration))
|
||||
{
|
||||
clang::FunctionTemplateDecl* templateFunctionDeclaration = clang::dyn_cast<clang::FunctionDecl>(declaration)->getDescribedFunctionTemplate();
|
||||
if (templateFunctionDeclaration)
|
||||
{
|
||||
declName = getDeclName(templateFunctionDeclaration);
|
||||
}
|
||||
else if (clang::dyn_cast<clang::FunctionDecl>(declaration)->isFunctionTemplateSpecialization())
|
||||
{
|
||||
std::string specializedParameterNamePart = "<";
|
||||
const clang::TemplateArgumentList* templateArgumentList = clang::dyn_cast<clang::FunctionDecl>(declaration)->getTemplateSpecializationArgs();
|
||||
for (size_t i = 0; i < templateArgumentList->size(); i++)
|
||||
{
|
||||
const clang::TemplateArgument& templateArgument = templateArgumentList->get(i);
|
||||
specializedParameterNamePart += templateArgumentToDataType(templateArgument)->getFullTypeName();
|
||||
specializedParameterNamePart += (i < templateArgumentList->size() - 1) ? ", " : "";
|
||||
}
|
||||
specializedParameterNamePart += ">";
|
||||
declName += specializedParameterNamePart;
|
||||
}
|
||||
}
|
||||
else if (clang::isa<clang::TemplateDecl>(declaration)) // also triggers on TemplateTemplateParmDecl
|
||||
{
|
||||
std::string templateParameterNamePart = "<";
|
||||
clang::TemplateParameterList* parameterList = clang::dyn_cast<clang::TemplateDecl>(declaration)->getTemplateParameters();
|
||||
for (size_t i = 0; i < parameterList->size(); i++)
|
||||
{
|
||||
templateParameterNamePart += getTemplateParameterString(parameterList->getParam(i));
|
||||
templateParameterNamePart += (i < parameterList->size() - 1) ? ", " : "";
|
||||
}
|
||||
templateParameterNamePart += ">";
|
||||
declName += templateParameterNamePart;
|
||||
}
|
||||
else if (clang::isa<clang::NamespaceDecl>(declaration) && clang::dyn_cast<clang::NamespaceDecl>(declaration)->isAnonymousNamespace())
|
||||
{
|
||||
const clang::SourceManager& sourceManager = declaration->getASTContext().getSourceManager();
|
||||
const clang::PresumedLoc& presumedBegin = sourceManager.getPresumedLoc(declaration->getLocStart());
|
||||
declName = "anonymous namespace (" + std::string(presumedBegin.getFilename()) + ")";
|
||||
}
|
||||
return declName;
|
||||
CxxDeclNameResolver resolver(declaration);
|
||||
return resolver.getDeclNameHierarchy();
|
||||
}
|
||||
|
||||
NameHierarchy getTemplateSpecializationParentNameHierarchy(clang::ClassTemplateSpecializationDecl* declaration)
|
||||
@@ -437,185 +81,4 @@ namespace utility
|
||||
}
|
||||
return std::make_shared<NamedDataType>(NameHierarchy());
|
||||
}
|
||||
|
||||
std::string getTemplateParameterString(const clang::NamedDecl* parameter)
|
||||
{
|
||||
std::string templateParameterString = "";
|
||||
|
||||
clang::Decl::Kind templateParameterKind = parameter->getKind();
|
||||
switch (templateParameterKind)
|
||||
{
|
||||
case clang::Decl::NonTypeTemplateParm:
|
||||
templateParameterString = getTemplateParameterTypeString(clang::dyn_cast<clang::NonTypeTemplateParmDecl>(parameter));
|
||||
break;
|
||||
case clang::Decl::TemplateTypeParm:
|
||||
templateParameterString = getTemplateParameterTypeString(clang::dyn_cast<clang::TemplateTypeParmDecl>(parameter));
|
||||
break;
|
||||
case clang::Decl::TemplateTemplateParm:
|
||||
templateParameterString = getTemplateParameterTypeString(clang::dyn_cast<clang::TemplateTemplateParmDecl>(parameter));
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Unhandled kind of template parameter.");
|
||||
}
|
||||
|
||||
std::string parameterName = parameter->getName();
|
||||
if (!parameterName.empty())
|
||||
{
|
||||
templateParameterString += " " + parameterName;
|
||||
}
|
||||
return templateParameterString;
|
||||
}
|
||||
|
||||
std::string getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter)
|
||||
{
|
||||
std::string templateParameterTypeString = "";
|
||||
|
||||
const clang::QualType parmeterType = parameter->getType();
|
||||
clang::Type::TypeClass parmeterTypeClass = parmeterType->getTypeClass();
|
||||
if (parmeterTypeClass == clang::Type::TemplateTypeParm)
|
||||
{
|
||||
clang::TemplateTypeParmDecl* parmeterTypeDecl = clang::dyn_cast<clang::TemplateTypeParmType>(parmeterType)->getDecl();
|
||||
if (haveAstAncestorRelation(getAstParentDecl(parameter), parmeterTypeDecl))
|
||||
{
|
||||
templateParameterTypeString = getDeclName(parmeterTypeDecl);
|
||||
}
|
||||
}
|
||||
else if (parmeterTypeClass == clang::Type::DependentName)
|
||||
{
|
||||
clang::NestedNameSpecifier* nns = clang::dyn_cast<clang::DependentNameType>(parmeterType)->getQualifier();
|
||||
clang::NamedDecl* typeParent;
|
||||
switch (nns->getKind())
|
||||
{
|
||||
case clang::NestedNameSpecifier::Identifier:
|
||||
{
|
||||
clang::PrintingPolicy pp = clang::PrintingPolicy(clang::LangOptions());
|
||||
pp.SuppressTagKeyword = true; // value "true": for a class A it prints "A" instead of "class A"
|
||||
pp.Bool = true; // value "true": prints bool type as "bool" instead of "_Bool"
|
||||
templateParameterTypeString = parmeterType.getAsString(pp);
|
||||
}
|
||||
break;
|
||||
case clang::NestedNameSpecifier::Namespace:
|
||||
typeParent = nns->getAsNamespace();
|
||||
break;
|
||||
case clang::NestedNameSpecifier::NamespaceAlias:
|
||||
typeParent = nns->getAsNamespaceAlias();
|
||||
break;
|
||||
case clang::NestedNameSpecifier::TypeSpec:
|
||||
case clang::NestedNameSpecifier::TypeSpecWithTemplate:
|
||||
{
|
||||
const clang::Type* ssswd = nns->getAsType();
|
||||
clang::Type::TypeClass szz = ssswd->getTypeClass();
|
||||
switch (ssswd->getTypeClass())
|
||||
{
|
||||
case clang::Type::TemplateTypeParm:
|
||||
typeParent = clang::dyn_cast<clang::TemplateTypeParmType>(ssswd)->getDecl();
|
||||
break;
|
||||
default:
|
||||
typeParent = nullptr;
|
||||
LOG_ERROR("aahhh");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case clang::NestedNameSpecifier::Global:
|
||||
typeParent = nullptr;
|
||||
break;
|
||||
case clang::NestedNameSpecifier::Super:
|
||||
typeParent = nns->getAsRecordDecl();
|
||||
break;
|
||||
}
|
||||
if (typeParent && haveAstAncestorRelation(getAstParentDecl(parameter), typeParent))
|
||||
{
|
||||
templateParameterTypeString = getDeclName(typeParent);
|
||||
templateParameterTypeString += "::" + clang::dyn_cast<clang::DependentNameType>(parmeterType)->getIdentifier()->getName().str();
|
||||
}
|
||||
}
|
||||
|
||||
if (templateParameterTypeString.empty()) // this is the default case
|
||||
{
|
||||
templateParameterTypeString = qualTypeToDataType(parmeterType)->getFullTypeName();
|
||||
}
|
||||
return templateParameterTypeString;
|
||||
}
|
||||
|
||||
std::string getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter)
|
||||
{
|
||||
return (parameter->wasDeclaredWithTypename() ? "typename" : "class");
|
||||
}
|
||||
|
||||
std::string 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?
|
||||
return templateParameterTypeString;
|
||||
}
|
||||
|
||||
std::string getTemplateArgumentName(const clang::TemplateArgument& argument)
|
||||
{
|
||||
const clang::TemplateArgument::ArgKind kind = argument.getKind();
|
||||
switch (kind)
|
||||
{
|
||||
case clang::TemplateArgument::Type:
|
||||
return utility::qualTypeToDataType(argument.getAsType())->getFullTypeName();
|
||||
case clang::TemplateArgument::Integral:
|
||||
case clang::TemplateArgument::Null:
|
||||
case clang::TemplateArgument::Declaration:
|
||||
case clang::TemplateArgument::NullPtr:
|
||||
case clang::TemplateArgument::Template:
|
||||
case clang::TemplateArgument::TemplateExpansion:
|
||||
case clang::TemplateArgument::Expression:
|
||||
{
|
||||
clang::PrintingPolicy pp = clang::PrintingPolicy(clang::LangOptions());
|
||||
pp.SuppressTagKeyword = true; // value "true": for a class A it prints "A" instead of "class A"
|
||||
pp.Bool = true; // value "true": prints bool type as "bool" instead of "_Bool"
|
||||
|
||||
std::string buf;
|
||||
llvm::raw_string_ostream os(buf);
|
||||
argument.print(pp, os);
|
||||
return os.str();
|
||||
}
|
||||
case clang::TemplateArgument::Pack:
|
||||
LOG_ERROR("Type of template argument not handled: Pack");
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Type of template argument not handled." + argument.getKind());
|
||||
break;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
bool haveAstAncestorRelation(const clang::Decl* parent, const clang::Decl* child)
|
||||
{
|
||||
if (parent)
|
||||
{
|
||||
while (child)
|
||||
{
|
||||
if (parent == child)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
child = getAstParentDecl(child);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const clang::Decl* getAstParentDecl(const clang::Decl* decl)
|
||||
{
|
||||
clang::ASTContext& astContext = decl->getASTContext();
|
||||
llvm::ArrayRef<clang::ast_type_traits::DynTypedNode> parents = astContext.getParents<clang::Decl>(*(decl));
|
||||
if (parents.size() > 0) // usually this list contains just one parent node.
|
||||
{
|
||||
return parents[0].get<clang::Decl>(); // use the fist parent node.
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,22 +15,10 @@ class NameHierarchy;
|
||||
namespace utility
|
||||
{
|
||||
std::shared_ptr<DataType> qualTypeToDataType(clang::QualType qualType);
|
||||
std::shared_ptr<DataType> typeToDataType(const clang::Type* type);
|
||||
|
||||
NameHierarchy getDeclNameHierarchy(const clang::Decl* declaration);
|
||||
NameHierarchy getContextNameHierarchy(const clang::DeclContext* declaration);
|
||||
NameHierarchy getContextNameHierarchyOfTemplateParameter(const clang::NamedDecl* templateParmDecl);
|
||||
std::string getDeclName(const clang::NamedDecl* declaration);
|
||||
NameHierarchy getTemplateSpecializationParentNameHierarchy(clang::ClassTemplateSpecializationDecl* declaration);
|
||||
std::shared_ptr<DataType> templateArgumentToDataType(const clang::TemplateArgument& argument);
|
||||
std::string getTemplateParameterString(const clang::NamedDecl* parameter);
|
||||
std::string getTemplateParameterTypeString(const clang::NonTypeTemplateParmDecl* parameter);
|
||||
std::string getTemplateParameterTypeString(const clang::TemplateTypeParmDecl* parameter);
|
||||
std::string getTemplateParameterTypeString(const clang::TemplateTemplateParmDecl* parameter);
|
||||
std::string getTemplateArgumentName(const clang::TemplateArgument& argument);
|
||||
|
||||
bool haveAstAncestorRelation(const clang::Decl* parent, const clang::Decl* child);
|
||||
const clang::Decl* getAstParentDecl(const clang::Decl* decl);
|
||||
NameHierarchy getTemplateSpecializationParentNameHierarchy(clang::ClassTemplateSpecializationDecl* declaration);
|
||||
}
|
||||
|
||||
#endif // UTILITY_CLANG_H
|
||||
|
||||
+101
-67
@@ -1295,6 +1295,32 @@ public:
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<std::nullptr_t T>::T <2:26 2:26>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_non_type_template_parameter_that_depends_on_type_template_parameter_of_template_class()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
"template <typename T1, T1& T2>\n"
|
||||
"class A\n"
|
||||
"{};\n"
|
||||
);
|
||||
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 2);
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<typename T1, T1 & T2>::T1 <1:20 1:21>");
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes[1], "A<typename T1, T1 & T2>::T2 <1:28 1:29>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_non_type_template_parameter_that_depends_on_template_template_parameter_of_template_class()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
"template <template<typename> class T1, T1<int>& T2>\n"
|
||||
"class A\n"
|
||||
"{};\n"
|
||||
);
|
||||
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 2);
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A<template<typename> typename T1, T1<int> & T2>::T1<typename> <1:36 1:37>");
|
||||
TS_ASSERT_EQUALS(client->templateParameterTypes[1], "A<template<typename> typename T1, T1<int> & T2>::T2 <1:49 1:50>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_template_template_parameter_of_template_class()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
@@ -1354,19 +1380,7 @@ public:
|
||||
TS_ASSERT_EQUALS(client->typeUses[1], "B<template<typename> typename T>::T<B<template<typename> typename T>::foo<typename U>::U> <8:11 8:14>");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_specialized_with_template_type00000000000666666666666()
|
||||
void test_cxx_parser_finds_typedef_in_other_class_that_depends_on_own_template_parameter()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
"template <typename T>\n"
|
||||
@@ -1390,41 +1404,6 @@ public:
|
||||
TS_ASSERT_EQUALS(client->typedefs[1], "public A<B<typename U>::U>::type -> B<typename U>::type <9:37 9:40>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_specialized_with_template_type00ss000666666666666()
|
||||
{
|
||||
int zz1 = 0;
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
"template <typename T, T test>\n"
|
||||
"class A\n"
|
||||
"{\n"
|
||||
"};\n"
|
||||
|
||||
);
|
||||
int zz2 = 0;
|
||||
TS_ASSERT_EQUALS(client->classes.size(), 1);
|
||||
TS_ASSERT_EQUALS(client->classes[0], "A<typename T, T test> <2:1 <2:7 2:7> 4:1>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_usage_of_template_template_parameter_of_template_class_specialized_with_template_type00sstt000666666666666()
|
||||
{
|
||||
int zz1 = 0;
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
"template <typename T, typename T::type test>\n"
|
||||
"class A\n"
|
||||
"{\n"
|
||||
"};\n"
|
||||
|
||||
);
|
||||
int zz2 = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void test_cxx_parser_finds_type_template_parameters_of_template_class_with_multiple_parameters()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
@@ -1878,6 +1857,45 @@ public:
|
||||
TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "B<A, template<typename> typename U>->B<A, template<typename> typename U>::U<typename> <8:12 8:12>");
|
||||
}
|
||||
|
||||
|
||||
void test_cxx_parser_finds_non_type_template_argument_that_depends_on_type_template_parameter_of_explicit_partial_template_specialization()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
"template <int T1, typename T2, T2 T3>\n"
|
||||
"class A\n"
|
||||
"{\n"
|
||||
"};\n"
|
||||
"template <typename T2, T2 T3>\n"
|
||||
"class A<3, T2, T3>\n"
|
||||
"{\n"
|
||||
"};\n"
|
||||
);
|
||||
|
||||
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>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_non_type_template_argument_that_depends_on_template_template_parameter_of_explicit_partial_template_specialization()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
"template <int T1, template<typename> class T2, T2<int> T3>\n"
|
||||
"class A\n"
|
||||
"{\n"
|
||||
"};\n"
|
||||
"template <template<typename> class T2, T2<int> T3>\n"
|
||||
"class A<3, T2, T3>\n"
|
||||
"{\n"
|
||||
"};\n"
|
||||
);
|
||||
|
||||
TS_ASSERT_EQUALS(client->templateArgumentTypes.size(), 3);
|
||||
TS_ASSERT_EQUALS(client->templateArgumentTypes[0], "A<3, template<typename> typename T2, T2<int> T3>->int <6:9 6:9>");
|
||||
TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<3, template<typename> typename T2, T2<int> T3>->A<3, template<typename> typename T2, T2<int> T3>::T2<typename> <6:12 6:12>");
|
||||
TS_ASSERT_EQUALS(client->templateArgumentTypes[2], "A<3, template<typename> typename T2, T2<int> T3>->A<3, template<typename> typename T2, T2<int> T3>::T2<int> <6:16 6:16>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_correct_name_of_explicit_template_specialization()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
@@ -1957,25 +1975,24 @@ public:
|
||||
TS_ASSERT_EQUALS(client->inheritances[0], "B : public A<int> <7:10 7:22>");
|
||||
}
|
||||
|
||||
//___void test_cxx_parser_finds_template_class_specialization_with_template_argument()
|
||||
//{
|
||||
// std::shared_ptr<TestParserClient> client = parseCode(
|
||||
// "template <typename T>\n"
|
||||
// "class A\n"
|
||||
// "{\n"
|
||||
// " T foo;\n"
|
||||
// "};\n"
|
||||
// "\n"
|
||||
// "template <typename U>\n"
|
||||
// "class B: public A<U>\n"
|
||||
// "{\n"
|
||||
// "};\n"
|
||||
// "B<int> bar;"
|
||||
// );
|
||||
// int i = 0;
|
||||
// //TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1);
|
||||
// //TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A<U> -> A<T> <2:7 2:7>");
|
||||
//}
|
||||
void test_cxx_parser_finds_template_class_specialization_with_template_argument()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
"template <typename T>\n"
|
||||
"class A\n"
|
||||
"{\n"
|
||||
" T foo;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"template <typename U>\n"
|
||||
"class B: public A<U>\n"
|
||||
"{\n"
|
||||
"};\n"
|
||||
);
|
||||
|
||||
TS_ASSERT_EQUALS(client->inheritances.size(), 1);
|
||||
TS_ASSERT_EQUALS(client->inheritances[0], "B<typename U> : public A<B<typename U>::U> <8:10 8:20>");
|
||||
}
|
||||
|
||||
void test_cxx_parser_finds_template_class_constructor_usage_of_field()
|
||||
{
|
||||
@@ -2420,6 +2437,23 @@ public:
|
||||
TS_ASSERT_EQUALS(client->errors[0], "use of undeclared identifier \'b\' <1:9 1:9>");
|
||||
}
|
||||
|
||||
|
||||
void ___test_TEST()
|
||||
{
|
||||
std::shared_ptr<TestParserClient> client = parseCode(
|
||||
"template <template<template<typename> class> class T>\n"
|
||||
"class A {\n"
|
||||
"T<>\n"
|
||||
"};\n"
|
||||
"template <template<typename> class T>\n"
|
||||
"class B {};\n"
|
||||
"template <typename T>\n"
|
||||
"class C {};\n"
|
||||
"A<B> a;\n"
|
||||
);
|
||||
int ofo = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
class TestParserClient: public ParserClient
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user