#include "Test/Test.h" #include "Test/Tester.h" #include "clang/AST/RecursiveASTVisitor.h" namespace clice::testing { namespace { struct InputFinder : clang::RecursiveASTVisitor { CompilationUnit& unit; clang::QualType input; clang::QualType expect; using Base = clang::RecursiveASTVisitor; InputFinder(CompilationUnit& unit) : unit(unit) {} bool TraverseDecl(clang::Decl* decl) { if(decl && (llvm::isa(decl) || unit.file_id(decl->getLocation()) == unit.interested_file())) { Base::TraverseDecl(decl); } return true; } bool VisitTypedefNameDecl(const clang::TypedefNameDecl* decl) { if(decl->getName() == "input") { input = decl->getUnderlyingType(); } if(decl->getName() == "expect") { expect = decl->getUnderlyingType(); } return true; } }; TEST_SUITE(TemplateResolver) { void run(llvm::StringRef code) { Tester tester; tester.add_main("main.cpp", code); ASSERT_TRUE(tester.compile()); InputFinder finder(*tester.unit); finder.TraverseAST(tester.unit->context()); auto input = tester.unit->resolver().resolve(finder.input); auto target = finder.expect; ASSERT_FALSE(input.isNull() || target.isNull()); EXPECT_EQ(input.getCanonicalType(), target.getCanonicalType()); } TEST_CASE(TypeParameterType) { run(R"code( template struct A { using type = T; }; template struct test { using input = typename A::type; using expect = X; }; )code"); } TEST_CASE(SingleLevel) { run(R"code( template struct type_list {}; template struct A { using type = type_list; }; template struct test { using input = typename A::type; using expect = type_list; }; )code"); } TEST_CASE(SingleLevelNotDependent) { run(R"code( template struct A { using type = int; }; template struct test { using input = typename A::type; using expect = int; }; )code"); } TEST_CASE(MultiLevel) { run(R"code( 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; }; )code"); } TEST_CASE(MultiLevelNotDependent) { run(R"code( 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; }; )code"); } TEST_CASE(ArgumentDependent) { run(R"code( 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; }; )code"); } TEST_CASE(AliasArgument) { run(R"code( 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; }; )code"); } TEST_CASE(AliasDependent) { run(R"code( 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; }; )code"); } TEST_CASE(AliasTemplate) { run(R"code( 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; }; )code"); } TEST_CASE(BaseDependent) { run(R"code( 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; }; )code"); } TEST_CASE(MultiNested) { run(R"code( 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; }; )code"); } TEST_CASE(OuterDependentMemberClass) { run(R"code( 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; }; )code"); } TEST_CASE(InnerDependentMemberClass) { run(R"code( 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; }; )code"); } TEST_CASE(InnerDependentPartialMemberClass) { run(R"code( 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; }; )code"); } TEST_CASE(PartialSpecialization) { run(R"code( 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; }; )code"); } TEST_CASE(PartialDefaultArgument) { run(R"code( template struct X {}; template struct X { using type = T; }; template struct test { using input = typename X::type; using expect = T; }; )code"); } TEST_CASE(DefaultArgument) { run(R"code( 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; }; )code"); } TEST_CASE(PackExpansion) { run(R"code( template struct type_list {}; template struct X { using type = type_list; }; template struct test { using input = typename X::type; using expect = type_list; }; )code"); } TEST_CASE(BasePackExpansion) { run(R"code( 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; }; )code"); } TEST_CASE(Standard) { run(R"code( #include template struct test { using input = typename std::vector::reference; using expect = T&; }; )code"); }; }; // TEST_SUITE(TemplateResolver) } // namespace } // namespace clice::testing