#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())) { return 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; } }; struct TemplateResolver : TestFixture { void run(llvm::StringRef code, LocationChain chain = LocationChain()) { add_main("main.cpp", code); compile(); InputFinder finder(*unit); finder.TraverseAST(unit->context()); auto input = unit->resolver().resolve(finder.input); auto expect = finder.expect; EXPECT_EQ(input.isNull(), false, chain); EXPECT_EQ(expect.isNull(), false, chain); EXPECT_EQ(input.getCanonicalType(), expect.getCanonicalType(), chain); } }; TEST_F(TemplateResolver, TypeParameterType) { run(R"cpp( template struct A { using type = T; }; template struct test { using input = typename A::type; using expect = X; }; )cpp"); } TEST_F(TemplateResolver, SingleLevel) { run(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_F(TemplateResolver, SingleLevelNotDependent) { run(R"cpp( template struct A { using type = int; }; template struct test { using input = typename A::type; using expect = int; }; )cpp"); } TEST_F(TemplateResolver, MultiLevel) { run(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_F(TemplateResolver, MultiLevelNotDependent) { run(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_F(TemplateResolver, ArgumentDependent) { run(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_F(TemplateResolver, AliasArgument) { run(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_F(TemplateResolver, AliasDependent) { run(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_F(TemplateResolver, AliasTemplate) { run(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_F(TemplateResolver, BaseDependent) { run(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_F(TemplateResolver, MultiNested) { run(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_F(TemplateResolver, OuterDependentMemberClass) { run(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_F(TemplateResolver, InnerDependentMemberClass) { run(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_F(TemplateResolver, InnerDependentPartialMemberClass) { run(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_F(TemplateResolver, PartialSpecialization) { run(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_F(TemplateResolver, PartialDefaultArgument) { run(R"cpp( template struct X {}; template struct X { using type = T; }; template struct test { using input = typename X::type; using expect = T; }; )cpp"); } TEST_F(TemplateResolver, DefaultArgument) { run(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_F(TemplateResolver, PackExpansion) { run(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_F(TemplateResolver, BasePackExpansion) { run(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"); } /// FIXME: headers not found /// /// TEST_F(TemplateResolver, Standard) { /// run(R"cpp( /// #include /// /// template /// struct test { /// using input = typename std::vector::reference; /// using expect = T&; /// }; /// )cpp"); /// } } // namespace } // namespace clice::testing