#include #include using namespace clice; namespace { 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 = DependentNameResolver(parsedAST->sema, parsedAST->context); result = resolver.resolve(type); } return true; } clang::QualType test() { auto decl = parsedAST->context.getTranslationUnitDecl(); TraverseDecl(decl); return result; } }; 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(); 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, 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(); 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_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(); 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, 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(); // 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, 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 {}; 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