diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 2d312ada..92f6a7db 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -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 diff --git a/src/lib/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp b/src/lib/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp new file mode 100644 index 00000000..6d2bd463 --- /dev/null +++ b/src/lib/data/parser/cxx/name_resolver/CxxDeclNameResolver.cpp @@ -0,0 +1,254 @@ +#include "data/parser/cxx/name_resolver/CxxDeclNameResolver.h" + +#include +#include + +#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()) + , m_declaration(declaration) +{ +} + +CxxDeclNameResolver::CxxDeclNameResolver(const clang::Decl* declaration, std::vector ignoredContextDecls) + : CxxNameResolver(ignoredContextDecls) + , m_declaration(declaration) +{ +} + +CxxDeclNameResolver::~CxxDeclNameResolver() +{ +} + +NameHierarchy CxxDeclNameResolver::getDeclNameHierarchy() +{ + NameHierarchy contextNameHierarchy; + if (m_declaration) + { + std::string declName = ""; + + if (clang::isa(m_declaration)) + { + declName = getDeclName(clang::dyn_cast(m_declaration)); + } + else + { + LOG_ERROR("unhandled declaration type: " + std::string(m_declaration->getDeclKindName())); + } + + contextNameHierarchy = getContextNameHierarchy(m_declaration->getDeclContext()); + + if ((clang::isa(m_declaration) || + clang::isa(m_declaration) || + clang::isa(m_declaration)) && + contextNameHierarchy.size() > 0) + { + std::string lastContextElementName = contextNameHierarchy.back()->getFullName(); + contextNameHierarchy.pop(); + contextNameHierarchy.push(std::make_shared(lastContextElementName + "::" + declName)); + } + else + { + contextNameHierarchy.push(std::make_shared(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(declContext)) + { + std::string declName = getDeclName(clang::dyn_cast(declContext)); + if (declName != "") + { + contextNameHierarchy.push(std::make_shared(declName)); + } + } + } + return contextNameHierarchy; +} + +std::string CxxDeclNameResolver::getDeclName() +{ + const clang::NamedDecl* declaration = clang::dyn_cast(m_declaration); + std::string declName = declaration->getNameAsString(); + clang::Decl::Kind kind = declaration->getKind(); + if (clang::isa(declaration)) + { + clang::ClassTemplateDecl* templateClassDeclaration = clang::dyn_cast(declaration)->getDescribedClassTemplate(); + if (templateClassDeclaration) + { + declName = getDeclName(templateClassDeclaration); + } + else if (clang::isa(declaration)) + { + const clang::ClassTemplatePartialSpecializationDecl* partialSpecializationDecl = + clang::dyn_cast(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(declaration)) + { + std::string templateArgumentNamePart = "<"; + const clang::TemplateArgumentList& templateArgumentList = clang::dyn_cast(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(declaration)) + { + clang::FunctionTemplateDecl* templateFunctionDeclaration = clang::dyn_cast(declaration)->getDescribedFunctionTemplate(); + if (templateFunctionDeclaration) + { + declName = getDeclName(templateFunctionDeclaration); + } + else if (clang::dyn_cast(declaration)->isFunctionTemplateSpecialization()) + { + std::string templateArgumentNamePart = "<"; + const clang::TemplateArgumentList* templateArgumentList = clang::dyn_cast(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(declaration)) // also triggers on TemplateTemplateParmDecl + { + std::string templateParameterNamePart = "<"; + clang::TemplateParameterList* parameterList = clang::dyn_cast(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(declaration) && clang::dyn_cast(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(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."); + } + + 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_declaration)) + { + typeNameResolver.ignoreContextDecl(clang::dyn_cast(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); +} + diff --git a/src/lib/data/parser/cxx/name_resolver/CxxDeclNameResolver.h b/src/lib/data/parser/cxx/name_resolver/CxxDeclNameResolver.h new file mode 100644 index 00000000..2363fef9 --- /dev/null +++ b/src/lib/data/parser/cxx/name_resolver/CxxDeclNameResolver.h @@ -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 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 diff --git a/src/lib/data/parser/cxx/name_resolver/CxxNameResolver.cpp b/src/lib/data/parser/cxx/name_resolver/CxxNameResolver.cpp new file mode 100644 index 00000000..13783747 --- /dev/null +++ b/src/lib/data/parser/cxx/name_resolver/CxxNameResolver.cpp @@ -0,0 +1,33 @@ +#include "data/parser/cxx/name_resolver/CxxNameResolver.h" + +CxxNameResolver::CxxNameResolver(std::vector 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(declContext); + for (int i = 0; i < m_ignoredContextDecls.size(); i++) + { + if (decl == m_ignoredContextDecls[i]) + { + return true; + } + } + return false; +} + +std::vector CxxNameResolver::getIgnoredContextDecls() const +{ + return m_ignoredContextDecls; +} diff --git a/src/lib/data/parser/cxx/name_resolver/CxxNameResolver.h b/src/lib/data/parser/cxx/name_resolver/CxxNameResolver.h new file mode 100644 index 00000000..5ccdd884 --- /dev/null +++ b/src/lib/data/parser/cxx/name_resolver/CxxNameResolver.h @@ -0,0 +1,24 @@ +#ifndef CXX_NAME_RESOLVER_H +#define CXX_NAME_RESOLVER_H + +#include + +#include "clang/AST/Decl.h" + +class CxxNameResolver +{ +public: + CxxNameResolver(std::vector ignoredContextDecls); + ~CxxNameResolver(); + + void ignoreContextDecl(const clang::Decl* decl); + bool ignoresContext(const clang::DeclContext* declContext); + +protected: + std::vector getIgnoredContextDecls() const; + +private: + std::vector m_ignoredContextDecls; +}; + +#endif // CXX_NAME_RESOLVER_H diff --git a/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp b/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp new file mode 100644 index 00000000..86c3e855 --- /dev/null +++ b/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.cpp @@ -0,0 +1,58 @@ +#include "data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h" + +#include +#include + +#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h" +#include "utility/logging/logging.h" + +CxxTemplateArgumentNameResolver::CxxTemplateArgumentNameResolver() + : CxxNameResolver(std::vector()) +{ +} + +CxxTemplateArgumentNameResolver::CxxTemplateArgumentNameResolver(std::vector 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(); +} diff --git a/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h b/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h new file mode 100644 index 00000000..29763dbb --- /dev/null +++ b/src/lib/data/parser/cxx/name_resolver/CxxTemplateArgumentNameResolver.h @@ -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 ignoredContextDecls); + ~CxxTemplateArgumentNameResolver(); + + std::string getTemplateArgumentName(const clang::TemplateArgument& argument); +}; + +#endif // CXX_TEMPLATE_ARGUMENT_NAME_RESOLVER_H diff --git a/src/lib/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp b/src/lib/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp new file mode 100644 index 00000000..c629cc39 --- /dev/null +++ b/src/lib/data/parser/cxx/name_resolver/CxxTypeNameResolver.cpp @@ -0,0 +1,228 @@ +#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h" + +#include +#include +#include + +#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()) +{ +} + +CxxTypeNameResolver::CxxTypeNameResolver(std::vector ignoredContextDecls) + : CxxNameResolver(ignoredContextDecls) +{ +} + +CxxTypeNameResolver::~CxxTypeNameResolver() +{ +} + +std::shared_ptr CxxTypeNameResolver::qualTypeToDataType(clang::QualType qualType) +{ + std::shared_ptr dataType = typeToDataType(qualType.getTypePtr()); + if (qualType.isConstQualified()) + { + dataType->addQualifier(DataType::QUALIFIER_CONST); + } + return dataType; +} + +std::shared_ptr CxxTypeNameResolver::typeToDataType(const clang::Type* type) +{ + std::shared_ptr dataType; + + switch (type->getTypeClass()) + { + case clang::Type::Paren: + { + dataType = qualTypeToDataType(type->getAs()->getInnerType()); + break; + } + case clang::Type::Typedef: + { + CxxDeclNameResolver declNameResolver(type->getAs()->getDecl(), getIgnoredContextDecls()); + dataType = std::make_shared(declNameResolver.getDeclNameHierarchy()); + break; + } + case clang::Type::MemberPointer: + { + int ogogo = 0; // test this case! + } + case clang::Type::Pointer: + { + std::shared_ptr innerType = qualTypeToDataType(type->getPointeeType()); + dataType = std::make_shared(innerType); + break; + } + case clang::Type::ConstantArray: + case clang::Type::VariableArray: + case clang::Type::DependentSizedArray: + case clang::Type::IncompleteArray: + { + std::shared_ptr innerType = qualTypeToDataType(clang::dyn_cast(type)->getElementType()); + dataType = std::make_shared(innerType); + break; + } + case clang::Type::LValueReference: + case clang::Type::RValueReference: + { + std::shared_ptr innerType = qualTypeToDataType(type->getPointeeType()); + dataType = std::make_shared(innerType); + break; + } + case clang::Type::Elaborated: + { + dataType = qualTypeToDataType(clang::dyn_cast(type)->getNamedType()); + break; + } + case clang::Type::Enum: + case clang::Type::Record: + { + CxxDeclNameResolver declNameResolver(type->getAs()->getDecl(), getIgnoredContextDecls()); + dataType = std::make_shared(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(typeName)); + + dataType = std::make_shared(typeNameHerarchy); + break; + } + case clang::Type::TemplateSpecialization: + { + NameHierarchy typeNameHerarchy; + + const clang::TagType* tagType = type->getAs(); // 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(); + 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> + declName += templateArgumentNamePart; // add template arguments + typeNameHerarchy.pop(); + typeNameHerarchy.push(std::make_shared(declName)); + } + } + dataType = std::make_shared(typeNameHerarchy); + break; + } + case clang::Type::TemplateTypeParm: + { + clang::TemplateTypeParmDecl* templateTypeParmDecl = clang::dyn_cast(type)->getDecl(); + + CxxDeclNameResolver declNameResolver(templateTypeParmDecl, getIgnoredContextDecls()); + NameHierarchy typeNameHerarchy = declNameResolver.getDeclNameHierarchy(); + + dataType = std::make_shared(typeNameHerarchy); + break; + } + case clang::Type::SubstTemplateTypeParm: + { + dataType = qualTypeToDataType(type->getAs()->getReplacementType()); + break; + } + case clang::Type::DependentName: + { + const clang::DependentNameType* dependentNameType = clang::dyn_cast(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(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(dependentNameType->getIdentifier()->getName().str())); + + dataType = std::make_shared(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(typeName)); + + dataType = std::make_shared(typeNameHerarchy); + break; + } + } + return dataType; +} diff --git a/src/lib/data/parser/cxx/name_resolver/CxxTypeNameResolver.h b/src/lib/data/parser/cxx/name_resolver/CxxTypeNameResolver.h new file mode 100644 index 00000000..3f9bb3d9 --- /dev/null +++ b/src/lib/data/parser/cxx/name_resolver/CxxTypeNameResolver.h @@ -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 ignoredContextDecls); + ~CxxTypeNameResolver(); + + std::shared_ptr qualTypeToDataType(clang::QualType qualType); + +private: + std::shared_ptr typeToDataType(const clang::Type* type); +}; + +#endif // CXX_TYPE_NAME_RESOLVER_H diff --git a/src/lib/data/parser/cxx/utilityCxx.cpp b/src/lib/data/parser/cxx/utilityCxx.cpp index 6fa97d44..038eb8fa 100644 --- a/src/lib/data/parser/cxx/utilityCxx.cpp +++ b/src/lib/data/parser/cxx/utilityCxx.cpp @@ -1,378 +1,22 @@ #include "data/parser/cxx/utilityCxx.h" -#include -#include -#include - -#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 qualTypeToDataType(clang::QualType qualType) { - std::shared_ptr dataType = typeToDataType(qualType.getTypePtr()); - if (qualType.isConstQualified()) - { - dataType->addQualifier(DataType::QUALIFIER_CONST); - } - return dataType; - } - - std::shared_ptr typeToDataType(const clang::Type* type) - { - std::shared_ptr dataType; - - switch (type->getTypeClass()) - { - case clang::Type::Paren: - { - dataType = qualTypeToDataType(type->getAs()->getInnerType()); - break; - } - case clang::Type::Typedef: - { - dataType = std::make_shared(getDeclNameHierarchy(type->getAs()->getDecl())); - break; - } - case clang::Type::MemberPointer: - { - int ogogo = 0; // test this case! - } - case clang::Type::Pointer: - { - std::shared_ptr innerType = qualTypeToDataType(type->getPointeeType()); - dataType = std::make_shared(innerType); - break; - } - case clang::Type::ConstantArray: - case clang::Type::VariableArray: - case clang::Type::DependentSizedArray: - case clang::Type::IncompleteArray: - { - std::shared_ptr innerType = qualTypeToDataType(clang::dyn_cast(type)->getElementType()); - dataType = std::make_shared(innerType); - break; - } - case clang::Type::LValueReference: - case clang::Type::RValueReference: - { - std::shared_ptr innerType = qualTypeToDataType(type->getPointeeType()); - dataType = std::make_shared(innerType); - break; - } - case clang::Type::Elaborated: - { - dataType = qualTypeToDataType(clang::dyn_cast(type)->getNamedType()); - break; - } - case clang::Type::Enum: - case clang::Type::Record: - { - dataType = std::make_shared(getDeclNameHierarchy(type->getAs()->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(typeName)); - - dataType = std::make_shared(typeNameHerarchy); - break; - } - case clang::Type::TemplateSpecialization: - { - NameHierarchy typeNameHerarchy; - - const clang::TagType* tagType = type->getAs(); // 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(); - 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> - declName += templateArgumentPart; // add template arguments - typeNameHerarchy.pop(); - typeNameHerarchy.push(std::make_shared(declName)); - } - } - dataType = std::make_shared(typeNameHerarchy); - break; - } - case clang::Type::TemplateTypeParm: - { - clang::TemplateTypeParmDecl* templateTypeParmDecl = clang::dyn_cast(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(typeName)); - } - else - { - std::string lastContextElementName = typeNameHerarchy.back()->getFullName(); - typeNameHerarchy.pop(); - typeNameHerarchy.push(std::make_shared(lastContextElementName + "::" + typeName)); - } - dataType = std::make_shared(typeNameHerarchy); - break; - } - case clang::Type::SubstTemplateTypeParm: - { - dataType = qualTypeToDataType(type->getAs()->getReplacementType()); - break; - } - case clang::Type::DependentName: - { - const clang::DependentNameType* dependentNameType = clang::dyn_cast(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(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(dependentNameType->getIdentifier()->getName().str())); - - dataType = std::make_shared(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(typeName)); - - dataType = std::make_shared(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(declaration)) - { - declName = getDeclName(clang::dyn_cast(declaration)); - } - else - { - LOG_ERROR("unhandled declaration type: " + std::string(declaration->getDeclKindName())); - } - contextNameHierarchy = getContextNameHierarchy(declaration->getDeclContext()); - if (clang::isa(declaration) || - clang::isa(declaration) || - clang::isa(declaration)) - { - std::string lastContextElementName = contextNameHierarchy.back()->getFullName(); - contextNameHierarchy.pop(); - contextNameHierarchy.push(std::make_shared(lastContextElementName + "::" + declName)); - - } - else - { - contextNameHierarchy.push(std::make_shared(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(declContext)) - { - std::string declName = getDeclName(clang::dyn_cast(declContext)); - if (declName != "") - { - contextNameHierarchy.push(std::make_shared(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(parentNode)) - { - const clang::NamedDecl* parentNamedDecl = clang::dyn_cast(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(declaration)) - { - clang::ClassTemplateDecl* templateClassDeclaration = clang::dyn_cast(declaration)->getDescribedClassTemplate(); - if (templateClassDeclaration) - { - declName = getDeclName(templateClassDeclaration); - } - else if (clang::isa(declaration)) - { - const clang::ClassTemplatePartialSpecializationDecl* partialSpecializationDecl = - clang::dyn_cast(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(declaration)) - { - std::string specializedParameterNamePart = "<"; - const clang::TemplateArgumentList& templateArgumentList = clang::dyn_cast(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(declaration)) - { - clang::FunctionTemplateDecl* templateFunctionDeclaration = clang::dyn_cast(declaration)->getDescribedFunctionTemplate(); - if (templateFunctionDeclaration) - { - declName = getDeclName(templateFunctionDeclaration); - } - else if (clang::dyn_cast(declaration)->isFunctionTemplateSpecialization()) - { - std::string specializedParameterNamePart = "<"; - const clang::TemplateArgumentList* templateArgumentList = clang::dyn_cast(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(declaration)) // also triggers on TemplateTemplateParmDecl - { - std::string templateParameterNamePart = "<"; - clang::TemplateParameterList* parameterList = clang::dyn_cast(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(declaration) && clang::dyn_cast(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(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(parameter)); - break; - case clang::Decl::TemplateTypeParm: - templateParameterString = getTemplateParameterTypeString(clang::dyn_cast(parameter)); - break; - case clang::Decl::TemplateTemplateParm: - templateParameterString = getTemplateParameterTypeString(clang::dyn_cast(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(parmeterType)->getDecl(); - if (haveAstAncestorRelation(getAstParentDecl(parameter), parmeterTypeDecl)) - { - templateParameterTypeString = getDeclName(parmeterTypeDecl); - } - } - else if (parmeterTypeClass == clang::Type::DependentName) - { - clang::NestedNameSpecifier* nns = clang::dyn_cast(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(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(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 parents = astContext.getParents(*(decl)); - if (parents.size() > 0) // usually this list contains just one parent node. - { - return parents[0].get(); // use the fist parent node. - } - return nullptr; - } } - - diff --git a/src/lib/data/parser/cxx/utilityCxx.h b/src/lib/data/parser/cxx/utilityCxx.h index 0d607714..a1bdb1d7 100644 --- a/src/lib/data/parser/cxx/utilityCxx.h +++ b/src/lib/data/parser/cxx/utilityCxx.h @@ -15,22 +15,10 @@ class NameHierarchy; namespace utility { std::shared_ptr qualTypeToDataType(clang::QualType qualType); - std::shared_ptr 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 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 diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 8d3ed80d..806a47f9 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -1295,6 +1295,32 @@ public: TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A::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 client = parseCode( + "template \n" + "class A\n" + "{};\n" + ); + + TS_ASSERT_EQUALS(client->templateParameterTypes.size(), 2); + TS_ASSERT_EQUALS(client->templateParameterTypes[0], "A::T1 <1:20 1:21>"); + TS_ASSERT_EQUALS(client->templateParameterTypes[1], "A::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 client = parseCode( + "template class 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:36 1:37>"); + TS_ASSERT_EQUALS(client->templateParameterTypes[1], "A typename T1, T1 & T2>::T2 <1:49 1:50>"); + } + void test_cxx_parser_finds_template_template_parameter_of_template_class() { std::shared_ptr client = parseCode( @@ -1354,19 +1380,7 @@ public: TS_ASSERT_EQUALS(client->typeUses[1], "B typename T>::T typename T>::foo::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 client = parseCode( "template \n" @@ -1390,41 +1404,6 @@ public: TS_ASSERT_EQUALS(client->typedefs[1], "public A::U>::type -> B::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 client = parseCode( - "template \n" - "class A\n" - "{\n" - "};\n" - - ); - int zz2 = 0; - TS_ASSERT_EQUALS(client->classes.size(), 1); - TS_ASSERT_EQUALS(client->classes[0], "A <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 client = parseCode( - "template \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 client = parseCode( @@ -1878,6 +1857,45 @@ public: TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "B typename U>->B typename U>::U <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 client = parseCode( + "template \n" + "class A\n" + "{\n" + "};\n" + "template \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 client = parseCode( + "template class T2, T2 T3>\n" + "class A\n" + "{\n" + "};\n" + "template class 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, template typename T2, T2 T3>->int <6:9 6:9>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[1], "A<3, template typename T2, T2 T3>->A<3, template typename T2, T2 T3>::T2 <6:12 6:12>"); + TS_ASSERT_EQUALS(client->templateArgumentTypes[2], "A<3, template typename T2, T2 T3>->A<3, template typename T2, T2 T3>::T2 <6:16 6:16>"); + } + void test_cxx_parser_finds_correct_name_of_explicit_template_specialization() { std::shared_ptr client = parseCode( @@ -1957,25 +1975,24 @@ public: TS_ASSERT_EQUALS(client->inheritances[0], "B : public A <7:10 7:22>"); } - //___void test_cxx_parser_finds_template_class_specialization_with_template_argument() - //{ - // std::shared_ptr client = parseCode( - // "template \n" - // "class A\n" - // "{\n" - // " T foo;\n" - // "};\n" - // "\n" - // "template \n" - // "class B: public A\n" - // "{\n" - // "};\n" - // "B bar;" - // ); - // int i = 0; - // //TS_ASSERT_EQUALS(client->templateSpecializations.size(), 1); - // //TS_ASSERT_EQUALS(client->templateSpecializations[0], "class A -> A <2:7 2:7>"); - //} + void test_cxx_parser_finds_template_class_specialization_with_template_argument() + { + std::shared_ptr client = parseCode( + "template \n" + "class A\n" + "{\n" + " T foo;\n" + "};\n" + "\n" + "template \n" + "class B: public A\n" + "{\n" + "};\n" + ); + + TS_ASSERT_EQUALS(client->inheritances.size(), 1); + TS_ASSERT_EQUALS(client->inheritances[0], "B : public A::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 client = parseCode( + "template class> class T>\n" + "class A {\n" + "T<>\n" + "};\n" + "template class T>\n" + "class B {};\n" + "template \n" + "class C {};\n" + "A a;\n" + ); + int ofo = 0; + } + private: class TestParserClient: public ParserClient {