From 61c6f3dd8a176bc221b1b3995dbf34b9d86cf3c8 Mon Sep 17 00:00:00 2001 From: ykiko Date: Wed, 2 Oct 2024 17:01:19 +0800 Subject: [PATCH] Update `TemplateResolver`. --- include/Compiler/Resolver.h | 10 + src/Compiler/Resolver.cpp | 225 ++++++++++++++- tests/AST/Resolver.cpp | 562 +++++++++++++++++------------------- tests/AST/TreeTransform.cpp | 95 +----- 4 files changed, 515 insertions(+), 377 deletions(-) diff --git a/include/Compiler/Resolver.h b/include/Compiler/Resolver.h index 92504f7d..d09b2695 100644 --- a/include/Compiler/Resolver.h +++ b/include/Compiler/Resolver.h @@ -7,6 +7,16 @@ namespace clice { +class TemplateResolver { +public: + TemplateResolver(clang::Sema& sema) : sema(sema) {} + + clang::QualType resolve(clang::QualType type); + +private: + clang::Sema& sema; +}; + /// This class is used to resolve dependent names in the AST. /// For dependent names, we cannot know the any information about the name until /// the template is instantiated. This can be frustrating, you cannot get diff --git a/src/Compiler/Resolver.cpp b/src/Compiler/Resolver.cpp index 29d94f8d..c5c21cd3 100644 --- a/src/Compiler/Resolver.cpp +++ b/src/Compiler/Resolver.cpp @@ -5,10 +5,233 @@ namespace clice { namespace { -class TemplateResolver {}; +class TemplateResolverImpl : public clang::TreeTransform { +private: + struct Frame { + clang::NamedDecl* decl; + llvm::ArrayRef arguments; + }; + + using Names = llvm::SmallVector; + using Base = clang::TreeTransform; + +public: + TemplateResolverImpl(clang::Sema& sema) : TreeTransform(sema), sema(sema), context(sema.getASTContext()) {} + + /// Because Sema::SubsType does not handle alias types, meaning that if the aliased + /// type contains template parameters, it will not substitute them either, so we need + /// to remove the alias ourselves. + clang::QualType TransformTypedefType(clang::TypeLocBuilder& TLB, clang::TypedefTypeLoc TL) { + if(clang::TypedefNameDecl* TND = TL.getTypedefNameDecl()) { + auto TSI = TransformType(TND->getTypeSourceInfo()); + TLB.pushTrivial(context, TSI->getType(), {}); + return TSI->getType(); + } + + return clang::QualType(); + } + + /// Sometimes the outer argument is just a simple type `T` and actually cannot make + /// instantiation continue. In this case, we try to use its default to replace it, which + /// may make the instantiation continue. + clang::QualType TransformTemplateTypeParmType(clang::TypeLocBuilder& TLB, + clang::TemplateTypeParmTypeLoc TL, + bool SuppressObjCLifetime = false) { + if(clang::TemplateTypeParmDecl* TTPD = TL.getDecl()) { + if(TTPD->hasDefaultArgument()) { + const clang::TemplateArgument& argument = TTPD->getDefaultArgument().getArgument(); + clang::QualType type = TransformType(argument.getAsType()); + TLB.pushTrivial(context, type, {}); + return type; + } + } + + TLB.push(TL.getType()); + return TL.getType(); + } + + /// `TransformDependentNameType` is the most important function in `TemplateResolver`. + /// Everytime we meet a `DependentNameType`, we try to resolve it to a simpler type. + clang::QualType TransformDependentNameType(clang::TypeLocBuilder& TLB, + clang::DependentNameTypeLoc TL, + bool DeducedTSTContext = false) { + auto NNS = TransformNestedNameSpecifierLoc(TL.getQualifierLoc()).getNestedNameSpecifier(); + auto II = TL.getTypePtr()->getIdentifier(); + + Names names; + if(lookup(names, NNS, II) && names.size() == 1) { + clang::QualType type = TransformType(substitute(names.front())); + TLB.pushTrivial(context, type, {}); + return type; + } + return clang::QualType(); + } + + // clang::QualType TransformDependentTemplateSpecializationType(clang::TypeLocBuilder& TLB, + // clang::DependentTemplateSpecializationTypeLoc TL, + // bool DeducedTSTContext = false) { + // // Base::TransformDependentTemplateSpecializationType() + // // DependentNameResolver resolver(sema, context); + // // auto result = resolver.resolve(TL.getType()); + // // TLB.pushTrivial(context, result, {}); + // // TODO: + // } + + bool lookup(Names& names, clang::QualType type, const clang::IdentifierInfo* II) { + type = TransformType(type); + + llvm::outs() << "lookup {" + II->getName() + "} in {" + type.getAsString() + "}\n"; + + clang::TemplateDecl* TD; + llvm::ArrayRef args; + + if(auto TST = type->getAs()) { + TD = TST->getTemplateName().getAsTemplateDecl(); + args = TST->template_arguments(); + } else if(auto DTST = type->getAs()) { + Names members; + if(lookup(members, DTST->getQualifier(), DTST->getIdentifier()) && members.size() == 1) { + TD = llvm::dyn_cast(members.front()); + args = DTST->template_arguments(); + } else { + return false; + } + } + + if(auto CTD = llvm::dyn_cast(TD)) { + return lookup(names, CTD, II, args); + } else if(auto TATD = llvm::dyn_cast(TD)) { + frames.emplace_back(TATD, args); + return lookup(names, substitute(TATD->getTemplatedDecl()->getUnderlyingType()), II); + } + + return true; + } + + bool lookup(Names& names, const clang::NestedNameSpecifier* NNS, const clang::IdentifierInfo* II) { + switch(NNS->getKind()) { + case clang::NestedNameSpecifier::Identifier: { + Names members; + if(lookup(members, NNS->getPrefix(), NNS->getAsIdentifier()) && members.size() == 1) { + return lookup(names, substitute(members.front()), II); + } + } + + case clang::NestedNameSpecifier::TypeSpec: + case clang::NestedNameSpecifier::TypeSpecWithTemplate: { + return lookup(names, clang::QualType(NNS->getAsType(), 0), II); + } + + default: { + break; + } + } + return false; + } + + bool lookup(Names& names, + clang::ClassTemplateDecl* CTD, + const clang::IdentifierInfo* II, + llvm::ArrayRef arguments) { + // main template first + auto decls = CTD->getTemplatedDecl()->lookup(II); + if(!decls.empty()) { + std::size_t count = 0; + for(auto decl: decls) { + names.push_back(decl); + } + + frames.emplace_back(CTD, arguments); + return true; + } + + for(auto base: CTD->getTemplatedDecl()->bases()) { + // store the current state + auto copy = frames; + + // try to find the member in the base class + frames.emplace_back(CTD, arguments); + if(lookup(names, substitute(base.getType()), II)) { + return true; + } + + // if failed, restore the state + frames = std::move(copy); + } + + // if failed, try partial specializations + llvm::SmallVector partials; + CTD->getPartialSpecializations(partials); + + for(auto partial: partials) { + clang::sema::TemplateDeductionInfo info(partial->getLocation()); + if(sema.DeduceTemplateArguments(partial, arguments, info) != clang::TemplateDeductionResult::Success) { + break; + } + + auto decls = partial->lookup(II); + if(decls.empty()) { + break; + } + + for(auto decl: decls) { + names.push_back(decl); + } + + // NOTE: takeSugared will take the ownership of the list + auto list = info.takeSugared(); + frames.emplace_back(partial, list->asArray()); + // FIXME: should we delete the list? + // delete list; + return true; + } + + return false; + } + + clang::QualType substitute(clang::QualType type) { + type = TransformType(type); + + clang::MultiLevelTemplateArgumentList list; + for(auto begin = frames.rbegin(), end = frames.rend(); begin != end; ++begin) { + list.addOuterTemplateArguments(begin->decl, begin->arguments, true); + } + + for(auto frame: frames) { + clang::Sema::CodeSynthesisContext context; + context.Entity = frame.decl; + context.TemplateArgs = frame.arguments.data(); + context.Kind = clang::Sema::CodeSynthesisContext::TemplateInstantiation; + sema.pushCodeSynthesisContext(context); + } + + auto result = sema.SubstType(type, list, {}, {}); + llvm::outs() << "substitute {" + type.getAsString() + "} to {" + result.getAsString() + "}\n"; + frames.clear(); + return result; + } + + clang::QualType substitute(clang::NamedDecl* decl) { + if(auto TND = llvm::dyn_cast(decl)) { + return substitute(TND->getUnderlyingType()); + } + + return clang::QualType(); + } + +private: + clang::Sema& sema; + clang::ASTContext& context; + std::vector frames; +}; } // namespace +clang::QualType TemplateResolver::resolve(clang::QualType type) { + TemplateResolverImpl resolver(sema); + return resolver.TransformType(type); +} + clang::QualType DependentNameResolver::resolve(clang::NamedDecl* ND) { if(auto TAD = llvm::dyn_cast(ND)) { return resolve(substitute(TAD->getUnderlyingType())); diff --git a/tests/AST/Resolver.cpp b/tests/AST/Resolver.cpp index a02ea1cd..ef3acdb6 100644 --- a/tests/AST/Resolver.cpp +++ b/tests/AST/Resolver.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace { @@ -29,7 +29,7 @@ struct Visitor : public clang::RecursiveASTVisitor { context.TemplateArgs = nullptr; parsedAST->sema.pushCodeSynthesisContext(context); } - auto resolver = DependentNameResolver(parsedAST->sema, parsedAST->context); + auto resolver = TemplateResolver(parsedAST->sema); result = resolver.resolve(type); } return true; @@ -42,6 +42,23 @@ struct Visitor : public clang::RecursiveASTVisitor { } }; +void match(clang::QualType type, std::string name, std::initializer_list args) { + auto TST = type->getAs(); + ASSERT_TRUE(TST); + ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), name); + + auto template_args = TST->template_arguments(); + ASSERT_EQ(template_args.size(), args.size()); + + auto iter = args.begin(); + for(auto arg: template_args) { + auto T = llvm::dyn_cast(arg.getAsType()); + ASSERT_TRUE(T); + ASSERT_EQ(T->getDecl()->getName(), *iter); + ++iter; + } +} + TEST(DependentNameResolver, single_level_dependent_name) { const char* code = R"( template @@ -58,20 +75,9 @@ struct test { }; )"; - Visitor visitor(code); auto result = visitor.test(); - - auto TST = result->getAs(); - ASSERT_TRUE(TST); - ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); - - auto args = TST->template_arguments(); - ASSERT_EQ(args.size(), 1); - - auto T = llvm::dyn_cast(args[0].getAsType()); - ASSERT_TRUE(T); - ASSERT_EQ(T->getDecl()->getName(), "X"); + match(result, "type_list", {"X"}); } TEST(DependentNameResolver, multi_level_dependent_name) { @@ -102,327 +108,301 @@ struct test { Visitor visitor(code); clang::QualType result = visitor.test(); - auto TST = result->getAs(); - ASSERT_TRUE(TST); - ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); - - auto args = TST->template_arguments(); - ASSERT_EQ(args.size(), 1); - - auto T = llvm::dyn_cast(args[0].getAsType()); - ASSERT_TRUE(T); - ASSERT_EQ(T->getDecl()->getName(), "X"); + match(result, "type_list", {"X"}); } TEST(DependentNameResolver, dependent_dependent_dependent_name) { const char* code = R"( -template -struct type_list {}; + template + struct type_list {}; -template -struct A { - using self = A; - using type = type_list; -}; + template + struct A { + using self = A; + using type = type_list; + }; -template -struct test { - using result = typename A::self::self::self::self::self::type; -}; + template + struct test { + using result = typename A::self::self::self::self::self::type; + }; )"; Visitor visitor(code); clang::QualType result = visitor.test(); - auto TST = result->getAs(); - ASSERT_TRUE(TST); - ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); - - auto args = TST->template_arguments(); - ASSERT_EQ(args.size(), 1); - - auto T = llvm::dyn_cast(args[0].getAsType()); - ASSERT_TRUE(T); - ASSERT_EQ(T->getDecl()->getName(), "X"); + match(result, "type_list", {"X"}); } TEST(DependentNameResolver, alias_dependent_name) { const char* code = R"( -template -struct type_list {}; + template + struct type_list {}; -template -struct A { - using type = type_list; -}; + template + struct A { + using type = type_list; + }; -template -struct B { - using base = A; - using type = typename base::type; -}; + template + struct B { + using base = A; + using type = typename base::type; + }; -template -struct test { - using result = typename B::type; -}; + template + struct test { + using result = typename B::type; + }; )"; Visitor visitor(code); clang::QualType result = visitor.test(); - // result->dump(); - auto TST = result->getAs(); - ASSERT_TRUE(TST); - ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); - - auto args = TST->template_arguments(); - ASSERT_EQ(args.size(), 1); - - auto T = llvm::dyn_cast(args[0].getAsType()); - ASSERT_TRUE(T); - ASSERT_EQ(T->getDecl()->getName(), "X"); + result->dump(); + match(result, "type_list", {"X"}); } -TEST(DependentNameResolver, alias_template_dependent_name) { - const char* code = R"( -template -struct type_list {}; - -template -struct A { - using type = T1; -}; - -template -struct B { - using base = A; - using type = type_list; -}; - -template -struct test { - using result = typename B::type; -}; -)"; - Visitor visitor(code); - clang::QualType result = visitor.test(); - - auto TST = result->getAs(); - ASSERT_TRUE(TST); - ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); - - auto args = TST->template_arguments(); - ASSERT_EQ(args.size(), 1); - - auto T = llvm::dyn_cast(args[0].getAsType()); - ASSERT_TRUE(T); - ASSERT_EQ(T->getDecl()->getName(), "X"); -} - -TEST(DependentNameResolver, template_alias_dependent_name) { - const char* code = R"( -template -struct type_list {}; - -template -struct A { - using type = type_list; -}; - -template -using B = A; - -template -struct test { - using result = typename B::type; -}; -)"; - Visitor visitor(code); - clang::QualType result = visitor.test(); - // result->dump(); - auto TST = result->getAs(); - ASSERT_TRUE(TST); - ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); - - auto args = TST->template_arguments(); - ASSERT_EQ(args.size(), 1); - - auto T = llvm::dyn_cast(args[0].getAsType()); - ASSERT_TRUE(T); - ASSERT_EQ(T->getDecl()->getName(), "X"); -} - -TEST(DependentNameResolver, dependent_member_template) { - const char* code = R"( -template -struct type_list {}; - -template -struct A { - using type = type_list; -}; - -template -struct B { - template - using type = typename A::type; -}; - -template -struct test { - using result = typename B::template type; -}; -)"; - Visitor visitor(code); - clang::QualType result = visitor.test(); - auto TST = result->getAs(); - ASSERT_TRUE(TST); - ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); - - auto args = TST->template_arguments(); - ASSERT_EQ(args.size(), 2); - - auto X = llvm::dyn_cast(args[0].getAsType()); - ASSERT_TRUE(X); - ASSERT_EQ(X->getDecl()->getName(), "X"); - - auto Y = llvm::dyn_cast(args[1].getAsType()); - ASSERT_TRUE(Y); - ASSERT_EQ(Y->getDecl()->getName(), "Y"); -} - -TEST(DependentNameResolver, dependent_member_class_template) { - const char* code = R"( -template -struct type_list {}; - -template -struct A { - template - struct B { - using type = type_list; - }; -}; - -template -struct test { - using result = typename A::template B::type; -}; -)"; - - Visitor visitor(code); - clang::QualType result = visitor.test(); - - auto TST = result->getAs(); - ASSERT_TRUE(TST); - ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); - - auto args = TST->template_arguments(); - ASSERT_EQ(args.size(), 2); - - auto X = llvm::dyn_cast(args[0].getAsType()); - ASSERT_TRUE(X); - ASSERT_EQ(X->getDecl()->getName(), "X"); - - auto Y = llvm::dyn_cast(args[1].getAsType()); - ASSERT_TRUE(Y); - ASSERT_EQ(Y->getDecl()->getName(), "Y"); -} - -TEST(DependentNameResolver, dependent_partial_name) { - const char* code = R"( -template -struct type_list {}; - -template -struct A {}; - -template -struct B {}; - -template typename HKT> -struct B> { - using type = type_list; -}; - -template -struct test { - using result = typename B>::type; -}; -)"; - - Visitor visitor(code); - clang::QualType result = visitor.test(); - - // FIXME: resugar the result -} - -TEST(DependentNameResolver, dependent_base_name) { - const char* code = R"( -template -struct type_list {}; - -template -struct A { - using type = type_list; -}; - -template -struct B : A {}; - -template -struct test { - using result = typename B::type; -}; -)"; - - Visitor visitor(code); - auto result = visitor.test(); - - auto TST = result->getAs(); - ASSERT_TRUE(TST); - ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); - - auto args = TST->template_arguments(); - ASSERT_EQ(args.size(), 1); - - auto T = llvm::dyn_cast(args[0].getAsType()); - ASSERT_TRUE(T); - ASSERT_EQ(T->getDecl()->getName(), "X"); -} - -// TEST(DependentNameResolver, std_vector) { -// const char* code = R"( -// #include // -// template -// struct A {}; +// TEST(DependentNameResolver, alias_template_dependent_name) { +// const char* code = R"( +// template +// struct type_list {}; +// +// template +// struct A { +// using type = T1; +// }; +// +// template +// struct B { +// using base = A; +// using type = type_list; +// }; // // template // struct test { -// using result = typename std::vector>::reference; +// using result = typename B::type; // }; //)"; +// Visitor visitor(code); +// clang::QualType result = visitor.test(); // +// auto TST = result->getAs(); +// ASSERT_TRUE(TST); +// ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); +// +// auto args = TST->template_arguments(); +// ASSERT_EQ(args.size(), 1); +// +// auto T = llvm::dyn_cast(args[0].getAsType()); +// ASSERT_TRUE(T); +// ASSERT_EQ(T->getDecl()->getName(), "X"); +// } +// +// TEST(DependentNameResolver, template_alias_dependent_name) { +// const char* code = R"( +// template +// struct type_list {}; +// +// template +// struct A { +// using type = type_list; +// }; +// +// template +// using B = A; +// +// template +// struct test { +// using result = typename B::type; +// }; +//)"; // Visitor visitor(code); // clang::QualType result = visitor.test(); // // result->dump(); +// auto TST = result->getAs(); +// ASSERT_TRUE(TST); +// ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); +// +// auto args = TST->template_arguments(); +// ASSERT_EQ(args.size(), 1); +// +// auto T = llvm::dyn_cast(args[0].getAsType()); +// ASSERT_TRUE(T); +// ASSERT_EQ(T->getDecl()->getName(), "X"); // } // -// TEST(DependentNameResolver, std_list) { +// TEST(DependentNameResolver, dependent_member_template) { // const char* code = R"( -// #include +// template +// struct type_list {}; // -// template -// struct A {}; +// template +// struct A { +// using type = type_list; +// }; // -// template +// template +// struct B { +// template +// using type = typename A::type; +// }; +// +// template // struct test { -// using result = typename std::list>::reference; +// using result = typename B::template type; +// }; +//)"; +// Visitor visitor(code); +// clang::QualType result = visitor.test(); +// auto TST = result->getAs(); +// ASSERT_TRUE(TST); +// ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); +// +// auto args = TST->template_arguments(); +// ASSERT_EQ(args.size(), 2); +// +// auto X = llvm::dyn_cast(args[0].getAsType()); +// ASSERT_TRUE(X); +// ASSERT_EQ(X->getDecl()->getName(), "X"); +// +// auto Y = llvm::dyn_cast(args[1].getAsType()); +// ASSERT_TRUE(Y); +// ASSERT_EQ(Y->getDecl()->getName(), "Y"); +// } +// +// TEST(DependentNameResolver, dependent_member_class_template) { +// const char* code = R"( +// template +// struct type_list {}; +// +// template +// struct A { +// template +// struct B { +// using type = type_list; +// }; +// }; +// +// template +// struct test { +// using result = typename A::template B::type; // }; //)"; // // Visitor visitor(code); // clang::QualType result = visitor.test(); +// +// auto TST = result->getAs(); +// ASSERT_TRUE(TST); +// ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); +// +// auto args = TST->template_arguments(); +// ASSERT_EQ(args.size(), 2); +// +// auto X = llvm::dyn_cast(args[0].getAsType()); +// ASSERT_TRUE(X); +// ASSERT_EQ(X->getDecl()->getName(), "X"); +// +// auto Y = llvm::dyn_cast(args[1].getAsType()); +// ASSERT_TRUE(Y); +// ASSERT_EQ(Y->getDecl()->getName(), "Y"); // } +// +// TEST(DependentNameResolver, dependent_partial_name) { +// const char* code = R"( +// template +// struct type_list {}; +// +// template +// struct A {}; +// +// template +// struct B {}; +// +// template typename HKT> +// struct B> { +// using type = type_list; +// }; +// +// template +// struct test { +// using result = typename B>::type; +// }; +//)"; +// +// Visitor visitor(code); +// clang::QualType result = visitor.test(); +// +// // FIXME: resugar the result +// } +// +// TEST(DependentNameResolver, dependent_base_name) { +// const char* code = R"( +// template +// struct type_list {}; +// +// template +// struct A { +// using type = type_list; +// }; +// +// template +// struct B : A {}; +// +// template +// struct test { +// using result = typename B::type; +// }; +//)"; +// +// Visitor visitor(code); +// auto result = visitor.test(); +// +// auto TST = result->getAs(); +// ASSERT_TRUE(TST); +// ASSERT_EQ(TST->getTemplateName().getAsTemplateDecl()->getName(), "type_list"); +// +// auto args = TST->template_arguments(); +// ASSERT_EQ(args.size(), 1); +// +// auto T = llvm::dyn_cast(args[0].getAsType()); +// ASSERT_TRUE(T); +// ASSERT_EQ(T->getDecl()->getName(), "X"); +// } +// +// TEST(DependentNameResolver, std_vector) { +// const char* code = R"( +// #include +// +// template +// struct A {}; +// +// template +// struct test { +// using result = typename std::vector>::reference; +// }; +//)"; +// +// Visitor visitor(code); +// clang::QualType result = visitor.test(); +// // result->dump(); +// } +// +// TEST(DependentNameResolver, std_list) { +// const char* code = R"( +// #include +// +// template +// struct A {}; +// +// template +// struct test { +// using result = typename std::list>::reference; +// }; +//)"; +// +// Visitor visitor(code); +// clang::QualType result = visitor.test(); +// } } // namespace diff --git a/tests/AST/TreeTransform.cpp b/tests/AST/TreeTransform.cpp index 1540f5de..c5601e48 100644 --- a/tests/AST/TreeTransform.cpp +++ b/tests/AST/TreeTransform.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include namespace { @@ -14,81 +14,6 @@ std::vector compileArgs = { "/home/ykiko/C++/clice2/build/lib/clang/20", }; -class TemplateResolver : public clang::TreeTransform { - using Base = clang::TreeTransform; - - struct Frame { - clang::NamedDecl* decl; - std::vector arguments; - }; - -public: - TemplateResolver(clang::Sema& sema, clang::ASTContext& context) : TreeTransform(sema), context(context) {} - -private: - std::vector frames; - clang::ASTContext& context; -}; - -class Replacer : public clang::TreeTransform { - clang::ASTContext& context; - - using Base = clang::TreeTransform; - -public: - Replacer(clang::Sema& sema, clang::ASTContext& context) : TreeTransform{sema}, context(context) {} - -public: - bool TransformTemplateArguments(const clang::TemplateArgumentLoc* Inputs, - unsigned NumInputs, - clang::TemplateArgumentListInfo& Outputs, - bool Uneval = false) { - return TransformTemplateArguments(Inputs, Inputs + NumInputs, Outputs, Uneval); - } - - template - bool TransformTemplateArguments(InputIterator First, - InputIterator Last, - clang::TemplateArgumentListInfo& Outputs, - bool Uneval = false) { - llvm::outs() << "template\n"; - for(auto it = First; it != Last; ++it) { - it->getArgument().dump(); - } - return Base::TransformTemplateArguments(First, Last, Outputs, Uneval); - } - - clang::NestedNameSpecifierLoc TransformNestedNameSpecifierLoc(clang::NestedNameSpecifierLoc NNS, - clang::QualType ObjectType = clang::QualType(), - clang::NamedDecl* FirstQualifierInScope = nullptr) { - llvm::outs() << "nested\n"; - return Base::TransformNestedNameSpecifierLoc(NNS, ObjectType, FirstQualifierInScope); - } - - clang::QualType TransformDependentNameType(clang::TypeLocBuilder& TLB, - clang::DependentNameTypeLoc TL, - bool DeducedTSTContext = false) { - - DependentNameResolver resolver{getSema(), context}; - auto NNS = TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); - auto DNT = context.getDependentNameType(TL.getTypePtr()->getKeyword(), - NNS.getNestedNameSpecifier(), - TL.getTypePtr()->getIdentifier()); - auto result = resolver.resolve(DNT); - result->dump(); - llvm::outs() << "--------------------------------------------\n"; - - switch(clang::TypeLoc(result, nullptr).getTypeLocClass()) { -#define ABSTRACT_TYPELOC(CLASS, PARENT) -#define TYPELOC(CLASS, PARENT) \ - case clang::TypeLoc::CLASS: TLB.push(result); break; -#include "clang/AST/TypeLocNodes.def" - } - - return result; - } -}; - struct Visitor : public clang::RecursiveASTVisitor { clang::QualType result; std::unique_ptr parsedAST; @@ -97,10 +22,9 @@ struct Visitor : public clang::RecursiveASTVisitor { bool VisitTypeAliasDecl(clang::TypeAliasDecl* decl) { if(decl->getName() == "result") { - Replacer replacer(parsedAST->sema, parsedAST->context); - // decl->getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getType().dump(); - auto result = replacer.TransformType(decl->getTypeSourceInfo()); - // result->getType().dump(); + TemplateResolver resolver(parsedAST->sema); + result = resolver.resolve(decl->getUnderlyingType()); + result.dump(); } return true; } @@ -119,14 +43,15 @@ TEST(Transform, test) { template struct type_list {}; -template +template struct A { - using type = type_list; + using type = type_list; }; -template +template > struct test { - using result = typename A::type>::type&; + using base = A; + using result = typename base::type; }; )";