#include #include namespace { using namespace clice; std::vector compileArgs = { "clang++", "-std=c++20", "main.cpp", "-resource-dir", "/home/ykiko/C++/clice2/build/lib/clang/20", }; struct Visitor : public clang::RecursiveASTVisitor { clang::QualType result; std::unique_ptr parsedAST; Visitor(const char* code) : parsedAST(ParsedAST::build("main.cpp", code, compileArgs)) {} bool VisitTypeAliasDecl(clang::TypeAliasDecl* decl) { if(decl->getName() == "result") { auto type = decl->getUnderlyingType(); { clang::Sema::CodeSynthesisContext context; context.Kind = clang::Sema::CodeSynthesisContext::TemplateInstantiation; context.Entity = decl; context.TemplateArgs = nullptr; parsedAST->sema.pushCodeSynthesisContext(context); } auto resolver = TemplateResolver(parsedAST->sema); result = resolver.resolve(type); } return true; } clang::QualType test() { auto decl = parsedAST->context.getTranslationUnitDecl(); TraverseDecl(decl); return result; } }; 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 struct type_list {}; template struct A { using type = type_list; }; template struct test { using result = typename A::type; }; )"; Visitor visitor(code); auto result = visitor.test(); match(result, "type_list", {"X"}); } TEST(DependentNameResolver, multi_level_dependent_name) { const char* code = R"( template struct type_list {}; template struct A { using type = type_list; }; template struct B { using type = typename A::type; }; template struct C { using type = typename B::type; }; template struct test { using result = typename C::type; }; )"; Visitor visitor(code); clang::QualType result = visitor.test(); match(result, "type_list", {"X"}); } TEST(DependentNameResolver, dependent_dependent_dependent_name) { const char* code = R"( template struct 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; }; )"; Visitor visitor(code); clang::QualType result = visitor.test(); match(result, "type_list", {"X"}); } TEST(DependentNameResolver, alias_dependent_name) { const char* code = R"( template struct type_list {}; template struct A { using type = type_list; }; template struct B { using base = A; using type = typename base::type; }; template struct test { using result = typename B::type; }; )"; Visitor visitor(code); clang::QualType result = visitor.test(); 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(); match(result, "type_list", {"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(); match(result, "type_list", {"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(); match(result, "type_list", {"X", "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(); match(result, "type_list", {"X", "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(); result.dump(); } 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(); match(result, "type_list", {"X"}); } TEST(DependentNameResolver, dependent_base_name_2) { const char* code = R"( template struct type_list {}; template struct A { using type = type_list; }; template struct test { using base = typename A::type; using result = base; }; )"; Visitor visitor(code); auto result = visitor.test(); llvm::outs() << "------------------------------------------\n"; result.dump(); match(result, "type_list", {"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(); llvm::outs() << "result is: { " << result.getAsString() << " }\n"; } 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(); llvm::outs() << "result is: { " << result.getAsString() << " }\n"; } } // namespace