Update TemplateResolver.

This commit is contained in:
ykiko
2024-10-02 17:01:19 +08:00
parent f42618be7b
commit 61c6f3dd8a
4 changed files with 515 additions and 377 deletions

View File

@@ -1,5 +1,5 @@
#include <gtest/gtest.h>
#include <AST/Resolver.h>
#include <Compiler/Resolver.h>
namespace {
@@ -29,7 +29,7 @@ struct Visitor : public clang::RecursiveASTVisitor<Visitor> {
context.TemplateArgs = nullptr;
parsedAST->sema.pushCodeSynthesisContext(context);
}
auto resolver = DependentNameResolver(parsedAST->sema, parsedAST->context);
auto resolver = TemplateResolver(parsedAST->sema);
result = resolver.resolve(type);
}
return true;
@@ -42,6 +42,23 @@ struct Visitor : public clang::RecursiveASTVisitor<Visitor> {
}
};
void match(clang::QualType type, std::string name, std::initializer_list<std::string> args) {
auto TST = type->getAs<clang::TemplateSpecializationType>();
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<clang::TemplateTypeParmType>(arg.getAsType());
ASSERT_TRUE(T);
ASSERT_EQ(T->getDecl()->getName(), *iter);
++iter;
}
}
TEST(DependentNameResolver, single_level_dependent_name) {
const char* code = R"(
template <typename ...Ts>
@@ -58,20 +75,9 @@ struct test {
};
)";
Visitor visitor(code);
auto result = visitor.test();
auto TST = result->getAs<clang::TemplateSpecializationType>();
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<clang::TemplateTypeParmType>(args[0].getAsType());
ASSERT_TRUE(T);
ASSERT_EQ(T->getDecl()->getName(), "X");
match(result, "type_list", {"X"});
}
TEST(DependentNameResolver, multi_level_dependent_name) {
@@ -102,327 +108,301 @@ struct test {
Visitor visitor(code);
clang::QualType result = visitor.test();
auto TST = result->getAs<clang::TemplateSpecializationType>();
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<clang::TemplateTypeParmType>(args[0].getAsType());
ASSERT_TRUE(T);
ASSERT_EQ(T->getDecl()->getName(), "X");
match(result, "type_list", {"X"});
}
TEST(DependentNameResolver, dependent_dependent_dependent_name) {
const char* code = R"(
template <typename ...Ts>
struct type_list {};
template <typename ...Ts>
struct type_list {};
template <typename T1>
struct A {
using self = A<T1>;
using type = type_list<T1>;
};
template <typename T1>
struct A {
using self = A<T1>;
using type = type_list<T1>;
};
template <typename X>
struct test {
using result = typename A<X>::self::self::self::self::self::type;
};
template <typename X>
struct test {
using result = typename A<X>::self::self::self::self::self::type;
};
)";
Visitor visitor(code);
clang::QualType result = visitor.test();
auto TST = result->getAs<clang::TemplateSpecializationType>();
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<clang::TemplateTypeParmType>(args[0].getAsType());
ASSERT_TRUE(T);
ASSERT_EQ(T->getDecl()->getName(), "X");
match(result, "type_list", {"X"});
}
TEST(DependentNameResolver, alias_dependent_name) {
const char* code = R"(
template <typename ...Ts>
struct type_list {};
template <typename ...Ts>
struct type_list {};
template <typename T1>
struct A {
using type = type_list<T1>;
};
template <typename T1>
struct A {
using type = type_list<T1>;
};
template <typename T2>
struct B {
using base = A<T2>;
using type = typename base::type;
};
template <typename T2>
struct B {
using base = A<T2>;
using type = typename base::type;
};
template <typename X>
struct test {
using result = typename B<X>::type;
};
template <typename X>
struct test {
using result = typename B<X>::type;
};
)";
Visitor visitor(code);
clang::QualType result = visitor.test();
// result->dump();
auto TST = result->getAs<clang::TemplateSpecializationType>();
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<clang::TemplateTypeParmType>(args[0].getAsType());
ASSERT_TRUE(T);
ASSERT_EQ(T->getDecl()->getName(), "X");
result->dump();
match(result, "type_list", {"X"});
}
TEST(DependentNameResolver, alias_template_dependent_name) {
const char* code = R"(
template <typename ...Ts>
struct type_list {};
template <typename T1>
struct A {
using type = T1;
};
template <typename T2>
struct B {
using base = A<T2>;
using type = type_list<typename base::type>;
};
template <typename X>
struct test {
using result = typename B<X>::type;
};
)";
Visitor visitor(code);
clang::QualType result = visitor.test();
auto TST = result->getAs<clang::TemplateSpecializationType>();
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<clang::TemplateTypeParmType>(args[0].getAsType());
ASSERT_TRUE(T);
ASSERT_EQ(T->getDecl()->getName(), "X");
}
TEST(DependentNameResolver, template_alias_dependent_name) {
const char* code = R"(
template <typename ...Ts>
struct type_list {};
template <typename T1>
struct A {
using type = type_list<T1>;
};
template <typename T2>
using B = A<T2>;
template <typename X>
struct test {
using result = typename B<X>::type;
};
)";
Visitor visitor(code);
clang::QualType result = visitor.test();
// result->dump();
auto TST = result->getAs<clang::TemplateSpecializationType>();
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<clang::TemplateTypeParmType>(args[0].getAsType());
ASSERT_TRUE(T);
ASSERT_EQ(T->getDecl()->getName(), "X");
}
TEST(DependentNameResolver, dependent_member_template) {
const char* code = R"(
template <typename... Ts>
struct type_list {};
template <typename T1, typename U1>
struct A {
using type = type_list<T1, U1>;
};
template <typename T2>
struct B {
template <typename U2>
using type = typename A<T2, U2>::type;
};
template <typename X, typename Y>
struct test {
using result = typename B<X>::template type<Y>;
};
)";
Visitor visitor(code);
clang::QualType result = visitor.test();
auto TST = result->getAs<clang::TemplateSpecializationType>();
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<clang::TemplateTypeParmType>(args[0].getAsType());
ASSERT_TRUE(X);
ASSERT_EQ(X->getDecl()->getName(), "X");
auto Y = llvm::dyn_cast<clang::TemplateTypeParmType>(args[1].getAsType());
ASSERT_TRUE(Y);
ASSERT_EQ(Y->getDecl()->getName(), "Y");
}
TEST(DependentNameResolver, dependent_member_class_template) {
const char* code = R"(
template <typename... Ts>
struct type_list {};
template <typename T1>
struct A {
template <typename U1>
struct B {
using type = type_list<T1, U1>;
};
};
template <typename X, typename Y>
struct test {
using result = typename A<X>::template B<Y>::type;
};
)";
Visitor visitor(code);
clang::QualType result = visitor.test();
auto TST = result->getAs<clang::TemplateSpecializationType>();
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<clang::TemplateTypeParmType>(args[0].getAsType());
ASSERT_TRUE(X);
ASSERT_EQ(X->getDecl()->getName(), "X");
auto Y = llvm::dyn_cast<clang::TemplateTypeParmType>(args[1].getAsType());
ASSERT_TRUE(Y);
ASSERT_EQ(Y->getDecl()->getName(), "Y");
}
TEST(DependentNameResolver, dependent_partial_name) {
const char* code = R"(
template <typename... Ts>
struct type_list {};
template <typename T1>
struct A {};
template <typename U2>
struct B {};
template <typename U2, template <typename...> typename HKT>
struct B<HKT<U2>> {
using type = type_list<U2>;
};
template <typename X>
struct test {
using result = typename B<A<X>>::type;
};
)";
Visitor visitor(code);
clang::QualType result = visitor.test();
// FIXME: resugar the result
}
TEST(DependentNameResolver, dependent_base_name) {
const char* code = R"(
template <typename... Ts>
struct type_list {};
template <typename T1>
struct A {
using type = type_list<T1>;
};
template <typename U2>
struct B : A<U2> {};
template <typename X>
struct test {
using result = typename B<X>::type;
};
)";
Visitor visitor(code);
auto result = visitor.test();
auto TST = result->getAs<clang::TemplateSpecializationType>();
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<clang::TemplateTypeParmType>(args[0].getAsType());
ASSERT_TRUE(T);
ASSERT_EQ(T->getDecl()->getName(), "X");
}
// TEST(DependentNameResolver, std_vector) {
// const char* code = R"(
// #include <vector>
//
// template <typename T>
// struct A {};
// TEST(DependentNameResolver, alias_template_dependent_name) {
// const char* code = R"(
// template <typename ...Ts>
// struct type_list {};
//
// template <typename T1>
// struct A {
// using type = T1;
// };
//
// template <typename T2>
// struct B {
// using base = A<T2>;
// using type = type_list<typename base::type>;
// };
//
// template <typename X>
// struct test {
// using result = typename std::vector<A<X>>::reference;
// using result = typename B<X>::type;
// };
//)";
// Visitor visitor(code);
// clang::QualType result = visitor.test();
//
// auto TST = result->getAs<clang::TemplateSpecializationType>();
// 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<clang::TemplateTypeParmType>(args[0].getAsType());
// ASSERT_TRUE(T);
// ASSERT_EQ(T->getDecl()->getName(), "X");
// }
//
// TEST(DependentNameResolver, template_alias_dependent_name) {
// const char* code = R"(
// template <typename ...Ts>
// struct type_list {};
//
// template <typename T1>
// struct A {
// using type = type_list<T1>;
// };
//
// template <typename T2>
// using B = A<T2>;
//
// template <typename X>
// struct test {
// using result = typename B<X>::type;
// };
//)";
// Visitor visitor(code);
// clang::QualType result = visitor.test();
// // result->dump();
// auto TST = result->getAs<clang::TemplateSpecializationType>();
// 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<clang::TemplateTypeParmType>(args[0].getAsType());
// ASSERT_TRUE(T);
// ASSERT_EQ(T->getDecl()->getName(), "X");
// }
//
// TEST(DependentNameResolver, std_list) {
// TEST(DependentNameResolver, dependent_member_template) {
// const char* code = R"(
// #include <list>
// template <typename... Ts>
// struct type_list {};
//
// template <typename T>
// struct A {};
// template <typename T1, typename U1>
// struct A {
// using type = type_list<T1, U1>;
// };
//
// template <typename X>
// template <typename T2>
// struct B {
// template <typename U2>
// using type = typename A<T2, U2>::type;
// };
//
// template <typename X, typename Y>
// struct test {
// using result = typename std::list<A<X>>::reference;
// using result = typename B<X>::template type<Y>;
// };
//)";
// Visitor visitor(code);
// clang::QualType result = visitor.test();
// auto TST = result->getAs<clang::TemplateSpecializationType>();
// 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<clang::TemplateTypeParmType>(args[0].getAsType());
// ASSERT_TRUE(X);
// ASSERT_EQ(X->getDecl()->getName(), "X");
//
// auto Y = llvm::dyn_cast<clang::TemplateTypeParmType>(args[1].getAsType());
// ASSERT_TRUE(Y);
// ASSERT_EQ(Y->getDecl()->getName(), "Y");
// }
//
// TEST(DependentNameResolver, dependent_member_class_template) {
// const char* code = R"(
// template <typename... Ts>
// struct type_list {};
//
// template <typename T1>
// struct A {
// template <typename U1>
// struct B {
// using type = type_list<T1, U1>;
// };
// };
//
// template <typename X, typename Y>
// struct test {
// using result = typename A<X>::template B<Y>::type;
// };
//)";
//
// Visitor visitor(code);
// clang::QualType result = visitor.test();
//
// auto TST = result->getAs<clang::TemplateSpecializationType>();
// 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<clang::TemplateTypeParmType>(args[0].getAsType());
// ASSERT_TRUE(X);
// ASSERT_EQ(X->getDecl()->getName(), "X");
//
// auto Y = llvm::dyn_cast<clang::TemplateTypeParmType>(args[1].getAsType());
// ASSERT_TRUE(Y);
// ASSERT_EQ(Y->getDecl()->getName(), "Y");
// }
//
// TEST(DependentNameResolver, dependent_partial_name) {
// const char* code = R"(
// template <typename... Ts>
// struct type_list {};
//
// template <typename T1>
// struct A {};
//
// template <typename U2>
// struct B {};
//
// template <typename U2, template <typename...> typename HKT>
// struct B<HKT<U2>> {
// using type = type_list<U2>;
// };
//
// template <typename X>
// struct test {
// using result = typename B<A<X>>::type;
// };
//)";
//
// Visitor visitor(code);
// clang::QualType result = visitor.test();
//
// // FIXME: resugar the result
// }
//
// TEST(DependentNameResolver, dependent_base_name) {
// const char* code = R"(
// template <typename... Ts>
// struct type_list {};
//
// template <typename T1>
// struct A {
// using type = type_list<T1>;
// };
//
// template <typename U2>
// struct B : A<U2> {};
//
// template <typename X>
// struct test {
// using result = typename B<X>::type;
// };
//)";
//
// Visitor visitor(code);
// auto result = visitor.test();
//
// auto TST = result->getAs<clang::TemplateSpecializationType>();
// 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<clang::TemplateTypeParmType>(args[0].getAsType());
// ASSERT_TRUE(T);
// ASSERT_EQ(T->getDecl()->getName(), "X");
// }
//
// TEST(DependentNameResolver, std_vector) {
// const char* code = R"(
// #include <vector>
//
// template <typename T>
// struct A {};
//
// template <typename X>
// struct test {
// using result = typename std::vector<A<X>>::reference;
// };
//)";
//
// Visitor visitor(code);
// clang::QualType result = visitor.test();
// // result->dump();
// }
//
// TEST(DependentNameResolver, std_list) {
// const char* code = R"(
// #include <list>
//
// template <typename T>
// struct A {};
//
// template <typename X>
// struct test {
// using result = typename std::list<A<X>>::reference;
// };
//)";
//
// Visitor visitor(code);
// clang::QualType result = visitor.test();
// }
} // namespace