add dealias for Resolver.
This commit is contained in:
@@ -40,8 +40,14 @@ public:
|
||||
const clang::IdentifierInfo* II,
|
||||
llvm::ArrayRef<clang::TemplateArgument> arguments);
|
||||
|
||||
// replace the template arguments in the type, using the arguments in the frame
|
||||
clang::Decl* substitute(clang::Decl* decl);
|
||||
/// we use `Sema::SubstType` to substitute the template arguments in dependent type.
|
||||
/// but it doesn't substitute the template arguments in alias type.
|
||||
/// i.e. `typename base::type`, when base is `std::vector<T>`, it will ignore the `T`.
|
||||
/// so before actually substituting the type, we need to dealias the type.
|
||||
clang::QualType dealias(clang::QualType type);
|
||||
|
||||
/// replace the template arguments in the type, using the arguments in the frame
|
||||
clang::QualType substitute(clang::QualType type);
|
||||
|
||||
private:
|
||||
struct Frame {
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
namespace clice {
|
||||
|
||||
clang::QualType DependentNameResolver::resolve(clang::NamedDecl* ND) {
|
||||
auto decl = substitute(ND);
|
||||
if(auto TAD = llvm::dyn_cast<clang::TypeAliasDecl>(decl)) {
|
||||
return resolve(TAD->getUnderlyingType());
|
||||
} else if(auto TND = llvm::dyn_cast<clang::TypedefNameDecl>(decl)) {
|
||||
return resolve(TND->getUnderlyingType());
|
||||
if(auto TAD = llvm::dyn_cast<clang::TypeAliasDecl>(ND)) {
|
||||
return resolve(substitute(TAD->getUnderlyingType()));
|
||||
} else if(auto TND = llvm::dyn_cast<clang::TypedefNameDecl>(ND)) {
|
||||
return resolve(substitute(TND->getUnderlyingType()));
|
||||
} else {
|
||||
std::terminate();
|
||||
}
|
||||
@@ -127,7 +126,40 @@ bool DependentNameResolver::lookup(llvm::SmallVector<clang::NamedDecl*>& result,
|
||||
return false;
|
||||
}
|
||||
|
||||
clang::Decl* DependentNameResolver::substitute(clang::Decl* decl) {
|
||||
// FIXME: handle more case
|
||||
static bool isalias(clang::QualType type) {
|
||||
if(!type->isDependentType()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(auto TAT = type->getAs<clang::TypedefType>()) {
|
||||
return true;
|
||||
} else if(auto DNT = type->getAs<clang::TemplateSpecializationType>()) {
|
||||
return false;
|
||||
} else if(auto DNT = type->getAs<clang::DependentNameType>()) {
|
||||
return isalias(clang::QualType(DNT->getQualifier()->getAsType(), 0));
|
||||
} else {
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
clang::QualType DependentNameResolver::dealias(clang::QualType type) {
|
||||
if(!isalias(type)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
if(auto TAT = type->getAs<clang::TypedefType>()) {
|
||||
return dealias(TAT->getDecl()->getUnderlyingType());
|
||||
} else if(auto DNT = type->getAs<clang::DependentNameType>()) {
|
||||
auto type = dealias(clang::QualType(DNT->getQualifier()->getAsType(), 0));
|
||||
auto prefix = clang::NestedNameSpecifier::Create(context, nullptr, false, type.getTypePtr());
|
||||
return context.getDependentNameType(DNT->getKeyword(), prefix, DNT->getIdentifier());
|
||||
} else {
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
clang::QualType DependentNameResolver::substitute(clang::QualType type) {
|
||||
clang::MultiLevelTemplateArgumentList list;
|
||||
for(auto begin = frames.rbegin(), end = frames.rend(); begin != end; ++begin) {
|
||||
list.addOuterTemplateArguments(begin->decl, begin->arguments, true);
|
||||
@@ -141,10 +173,7 @@ clang::Decl* DependentNameResolver::substitute(clang::Decl* decl) {
|
||||
sema.pushCodeSynthesisContext(context);
|
||||
}
|
||||
|
||||
// FIXME: use global TU may result misunderstanding result
|
||||
// create some fake namespace to avoid this
|
||||
auto result = sema.SubstDecl(decl, context.getTranslationUnitDecl(), list);
|
||||
|
||||
auto result = sema.SubstType(dealias(type), list, {}, {});
|
||||
frames.clear();
|
||||
|
||||
return result;
|
||||
|
||||
@@ -97,7 +97,6 @@ template <typename X>
|
||||
struct test {
|
||||
using result = typename C<X>::type;
|
||||
};
|
||||
|
||||
)";
|
||||
Visitor visitor(code);
|
||||
clang::QualType result = visitor.test();
|
||||
@@ -129,7 +128,6 @@ template <typename X>
|
||||
struct test {
|
||||
using result = typename A<X>::self::self::self::self::self::type;
|
||||
};
|
||||
|
||||
)";
|
||||
Visitor visitor(code);
|
||||
clang::QualType result = visitor.test();
|
||||
@@ -146,5 +144,41 @@ struct test {
|
||||
ASSERT_EQ(T->getDecl()->getName(), "X");
|
||||
}
|
||||
|
||||
TEST(DependentNameResolver, 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>
|
||||
struct B {
|
||||
using base = A<T2>;
|
||||
using type = typename base::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");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
Reference in New Issue
Block a user