#include #include using namespace clice; namespace { std::vector compileArgs = { "clang++", "-std=c++20", "main.cpp", "-resource-dir=../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"); } } // namespace