diff --git a/CMakeLists.txt b/CMakeLists.txt index c6b41677..70d0a5af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,5 +87,5 @@ if(CLICE_ENABLE_TEST) "${CMAKE_SOURCE_DIR}/src/Support/*.cpp" ) file(GLOB_RECURSE TEST_SRC_FILES "${CMAKE_SOURCE_DIR}/tests/*/*.cpp") - target_sources(clice_test PRIVATE ${AST_SRC_FILES} ${TEST_SRC_FILES}) + target_sources(clice_test PRIVATE ${AST_SRC_FILES} ${TEST_SRC_FILES} ${CMAKE_SOURCE_DIR}/tests/main.cpp) endif() diff --git a/tests/AST/Resolver.cpp b/tests/AST/Resolver.cpp index 41f83ded..22f9f1b8 100644 --- a/tests/AST/Resolver.cpp +++ b/tests/AST/Resolver.cpp @@ -1,4 +1,4 @@ -#include +#include "../Test.h" #include namespace { @@ -15,30 +15,28 @@ std::vector compileArgs = { struct Visitor : public clang::RecursiveASTVisitor { clang::QualType result; + clang::QualType expect; std::unique_ptr parsedAST; - Visitor(const char* code) : parsedAST(ParsedAST::build("main.cpp", code, compileArgs)) {} + Visitor(llvm::StringRef content) : parsedAST(ParsedAST::build("main.cpp", content, 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); + TemplateResolver resolver(parsedAST->sema); + result = resolver.resolve(decl->getUnderlyingType()); } + + if(decl->getName() == "expect") { + expect = decl->getUnderlyingType(); + } + return true; } - clang::QualType test() { + void test() { auto decl = parsedAST->context.getTranslationUnitDecl(); TraverseDecl(decl); - return result; + EXPECT_EQ(result.getCanonicalType(), expect.getCanonicalType()); } }; @@ -59,315 +57,24 @@ void match(clang::QualType type, std::string name, std::initializer_list -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(); - 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(); - match(result, "type_list", {"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(); - match(result, "type_list", {"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(); - match(result, "type_list", {"X", "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(); - match(result, "type_list", {"X", "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(); - result.dump(); -} - -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(); - - match(result, "type_list", {"X"}); -} - -TEST(DependentNameResolver, dependent_base_name_2) { - const char* code = R"( - template - struct type_list {}; - - template - struct A { - using type = type_list; - }; - - template - struct test { - using base = typename A::type; - using result = base; - }; -)"; - - Visitor visitor(code); - auto result = visitor.test(); - llvm::outs() << "------------------------------------------\n"; - result.dump(); - match(result, "type_list", {"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(); - llvm::outs() << "result is: { " << result.getAsString() << " }\n"; -} - -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(); - llvm::outs() << "result is: { " << result.getAsString() << " }\n"; +TEST(clice, TemplateResolver) { + // FIXME: more flexible + auto path = test_dir() + "/TemplateResolver"; + std::error_code error; + fs::directory_iterator iter(path, error); + fs::directory_iterator end; + while(!error && iter != end) { + auto file = iter->path(); + llvm::outs() << "test: " << file << " " << error.message() << "\n"; + auto buffer = llvm::MemoryBuffer::getFile(file); + if(!buffer) { + llvm::outs() << "failed to open file: " << buffer.getError().message() << file << "\n"; + } + auto content = buffer.get()->getBuffer(); + Visitor visitor(content); + visitor.test(); + iter.increment(error); + } } } // namespace diff --git a/tests/AST/TreeTransform.cpp b/tests/AST/TreeTransform.cpp deleted file mode 100644 index c5601e48..00000000 --- a/tests/AST/TreeTransform.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include -#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") { - TemplateResolver resolver(parsedAST->sema); - result = resolver.resolve(decl->getUnderlyingType()); - result.dump(); - } - return true; - } - - clang::QualType test() { - clang::TypeLocBuilder builder; - auto decl = parsedAST->context.getTranslationUnitDecl(); - TraverseDecl(decl); - return result; - } -}; - -TEST(Transform, test) { - - const char* code = R"( -template -struct type_list {}; - -template -struct A { - using type = type_list; -}; - -template > -struct test { - using base = A; - using result = typename base::type; -}; - -)"; - - Visitor visitor(code); - auto result = visitor.test(); -} - -} // namespace - diff --git a/tests/Source/TemplateResolver/alias-argument.cpp b/tests/Source/TemplateResolver/alias-argument.cpp new file mode 100644 index 00000000..56a9d6d5 --- /dev/null +++ b/tests/Source/TemplateResolver/alias-argument.cpp @@ -0,0 +1,19 @@ +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; + using expect = type_list; +}; diff --git a/tests/Source/TemplateResolver/alias-dependent.cpp b/tests/Source/TemplateResolver/alias-dependent.cpp new file mode 100644 index 00000000..d99dccfb --- /dev/null +++ b/tests/Source/TemplateResolver/alias-dependent.cpp @@ -0,0 +1,20 @@ +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; + using expect = type_list; +}; + diff --git a/tests/Source/TemplateResolver/alias-template.cpp b/tests/Source/TemplateResolver/alias-template.cpp new file mode 100644 index 00000000..122f8ca6 --- /dev/null +++ b/tests/Source/TemplateResolver/alias-template.cpp @@ -0,0 +1,19 @@ +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; + using expect = type_list; +}; diff --git a/tests/Source/TemplateResolver/base-dependent.cpp b/tests/Source/TemplateResolver/base-dependent.cpp new file mode 100644 index 00000000..b10128a6 --- /dev/null +++ b/tests/Source/TemplateResolver/base-dependent.cpp @@ -0,0 +1,16 @@ +template +struct type_list {}; + +template +struct A { + using type = type_list; +}; + +template +struct B : A {}; + +template +struct test { + using result = typename B::type; + using expect = type_list; +}; diff --git a/tests/Source/TemplateResolver/multi-level.cpp b/tests/Source/TemplateResolver/multi-level.cpp new file mode 100644 index 00000000..d5b31a4c --- /dev/null +++ b/tests/Source/TemplateResolver/multi-level.cpp @@ -0,0 +1,23 @@ +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; + using expect = type_list; +}; diff --git a/tests/Source/TemplateResolver/multi-nested.cpp b/tests/Source/TemplateResolver/multi-nested.cpp new file mode 100644 index 00000000..6c33e6da --- /dev/null +++ b/tests/Source/TemplateResolver/multi-nested.cpp @@ -0,0 +1,14 @@ +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; + using expect = type_list; +}; diff --git a/tests/Source/TemplateResolver/nested-template.cpp b/tests/Source/TemplateResolver/nested-template.cpp new file mode 100644 index 00000000..ac72c563 --- /dev/null +++ b/tests/Source/TemplateResolver/nested-template.cpp @@ -0,0 +1,19 @@ +template +struct type_list {}; + +template +struct A { + template + struct B { + template + struct C { + using type = type_list; + }; + }; +}; + +template +struct test { + using result = typename A::template B::template C::type; + using expect = type_list; +}; diff --git a/tests/Source/TemplateResolver/partial-dependent.cpp b/tests/Source/TemplateResolver/partial-dependent.cpp new file mode 100644 index 00000000..08061855 --- /dev/null +++ b/tests/Source/TemplateResolver/partial-dependent.cpp @@ -0,0 +1,19 @@ +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; + using expect = type_list; +}; diff --git a/tests/Source/TemplateResolver/single-level.cpp b/tests/Source/TemplateResolver/single-level.cpp new file mode 100644 index 00000000..7c7ec5ca --- /dev/null +++ b/tests/Source/TemplateResolver/single-level.cpp @@ -0,0 +1,13 @@ +template +struct type_list {}; + +template +struct A { + using type = type_list; +}; + +template +struct test { + using result = typename A::type; + using expect = type_list; +}; diff --git a/tests/Source/TemplateResolver/vector.cpp b/tests/Source/TemplateResolver/vector.cpp new file mode 100644 index 00000000..56adbc6a --- /dev/null +++ b/tests/Source/TemplateResolver/vector.cpp @@ -0,0 +1,7 @@ +#include + +template +struct test { + using result = typename std::vector::reference; + using expect = T&; +}; diff --git a/tests/Test.h b/tests/Test.h new file mode 100644 index 00000000..cbed29d4 --- /dev/null +++ b/tests/Test.h @@ -0,0 +1,5 @@ +#include + +#include + +std::string test_dir(); diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 00000000..ee85a7a0 --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,18 @@ +#include +#include + +llvm::cl::opt test_dir_path("test-dir", + llvm::cl::desc("specify the test source directory path"), + llvm::cl::value_desc("path"), + llvm::cl::Required); + +std::string test_dir() { + return test_dir_path; +} + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + llvm::cl::ParseCommandLineOptions(argc, argv, "clice test\n"); + return RUN_ALL_TESTS(); +} +