#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(); 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 {}; // // 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