#include "../Test.h" #include #include namespace { using namespace clice; namespace testing {} // namespace testing struct TemplateResolverTester : public clang::RecursiveASTVisitor { TemplateResolverTester(llvm::StringRef code) { compileArgs = { "clang++", "-std=c++20", "main.cpp", "-resource-dir", "/home/ykiko/C++/clice2/build/lib/clang/20", }; compiler = std::make_unique("main.cpp", code, compileArgs); compiler->buildAST(); test(); } bool VisitTypeAliasDecl(clang::TypeAliasDecl* decl) { if(decl->getName() == "input") { input = decl->getUnderlyingType(); } if(decl->getName() == "expect") { expect = decl->getUnderlyingType(); } return true; } void test(std::source_location location = std::source_location::current()) { TraverseDecl(compiler->tu()); EXPECT_FALSE(input.isNull()); EXPECT_FALSE(expect.isNull()); auto& resolver = compiler->resolver(); clang::QualType result = resolver.resolve(input); EXPECT_EQ(result.getCanonicalType(), expect.getCanonicalType()); if(result.getCanonicalType() != expect.getCanonicalType()) { result.dump(); expect.dump(); } /// Test whether cache works. clang::QualType result2 = resolver.resolve(input); EXPECT_EQ(result, result2); } clang::QualType input; clang::QualType expect; std::vector compileArgs; std::unique_ptr compiler; }; TEST(TemplateResolver, TypeParameterType) { TemplateResolverTester tester(R"cpp( template struct A { using type = T; }; template struct test { using input = typename A::type; using expect = X; }; )cpp"); } TEST(TemplateResolver, SingleLevel) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct A { using type = type_list; }; template struct test { using input = typename A::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, SingleLevelNotDependent) { TemplateResolverTester tester(R"cpp( template struct A { using type = int; }; template struct test { using input = typename A::type; using expect = int; }; )cpp"); } TEST(TemplateResolver, MultiLevel) { TemplateResolverTester tester(R"cpp( 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 input = typename C::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, MultiLevelNotDependent) { TemplateResolverTester tester(R"cpp( template struct A { using type = int; }; template struct B { using type = typename A::type; }; template struct C { using type = typename B::type; }; template struct test { using input = typename C::type; using expect = int; }; )cpp"); } TEST(TemplateResolver, ArgumentDependent) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct A { using type = T1; }; template struct B { using type = type_list; }; template struct test { using input = typename B::type>::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, AliasArgument) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct A { using type = T1; }; template struct B { using base = A; using type = type_list; }; template struct test { using input = typename B::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, AliasDependent) { TemplateResolverTester tester(R"cpp( 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 input = typename B::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, AliasTemplate) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct A { using type = type_list; }; template struct B { template using type = typename A::type; }; template struct test { using input = typename B::template type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, BaseDependent) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct A { using type = type_list; }; template struct B : A {}; template struct test { using input = typename B::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, MultiNested) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct A { using self = A; using type = type_list; }; template struct test { using input = typename A::self::self::self::self::self::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, OuterDependentMemberClass) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct A { template struct B { template struct C { using type = type_list; }; }; }; template struct test { using input = typename A::template B::template C::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, InnerDependentMemberClass) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct test { template struct B { using type = type_list; }; using input = typename B<1, T>::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, InnerDependentPartialMemberClass) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct test {}; template struct test { template struct A { using type = type_list; }; using input = typename A<1, T>::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, PartialSpecialization) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct A {}; template struct B {}; template typename HKT> struct B> { using type = type_list; }; template struct test { using input = typename B>::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, PartialDefaultArgument) { TemplateResolverTester tester(R"cpp( template struct X {}; template struct X { using type = T; }; template struct test { using input = typename X::type; using expect = T; }; )cpp"); } TEST(TemplateResolver, DefaultArgument) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct A { using type = type_list; }; template > struct B { using type = typename U2::type; }; template struct test { using input = typename B::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, PackExpansion) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct X { using type = type_list; }; template struct test { using input = typename X::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, BasePackExpansion) { TemplateResolverTester tester(R"cpp( template struct type_list {}; template struct X { using type = type_list; }; template struct Y : X {}; template struct test { using input = typename Y::type; using expect = type_list; }; )cpp"); } TEST(TemplateResolver, Standard) { TemplateResolverTester tester(R"cpp( #include template struct test { using input = typename std::vector::reference; using expect = T&; }; )cpp"); } } // namespace