diff --git a/include/AST/Resolver.h b/include/AST/Resolver.h index 0bd00a01..a05db5ca 100644 --- a/include/AST/Resolver.h +++ b/include/AST/Resolver.h @@ -40,8 +40,14 @@ public: const clang::IdentifierInfo* II, llvm::ArrayRef 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`, 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 { diff --git a/src/AST/Resolver.cpp b/src/AST/Resolver.cpp index d2e8ed8d..2767a36a 100644 --- a/src/AST/Resolver.cpp +++ b/src/AST/Resolver.cpp @@ -3,11 +3,10 @@ namespace clice { clang::QualType DependentNameResolver::resolve(clang::NamedDecl* ND) { - auto decl = substitute(ND); - if(auto TAD = llvm::dyn_cast(decl)) { - return resolve(TAD->getUnderlyingType()); - } else if(auto TND = llvm::dyn_cast(decl)) { - return resolve(TND->getUnderlyingType()); + if(auto TAD = llvm::dyn_cast(ND)) { + return resolve(substitute(TAD->getUnderlyingType())); + } else if(auto TND = llvm::dyn_cast(ND)) { + return resolve(substitute(TND->getUnderlyingType())); } else { std::terminate(); } @@ -127,7 +126,40 @@ bool DependentNameResolver::lookup(llvm::SmallVector& 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()) { + return true; + } else if(auto DNT = type->getAs()) { + return false; + } else if(auto DNT = type->getAs()) { + 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()) { + return dealias(TAT->getDecl()->getUnderlyingType()); + } else if(auto DNT = type->getAs()) { + 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; diff --git a/tests/Resolver.cpp b/tests/Resolver.cpp index 293732d6..e159cf4c 100644 --- a/tests/Resolver.cpp +++ b/tests/Resolver.cpp @@ -97,7 +97,6 @@ template struct test { using result = typename C::type; }; - )"; Visitor visitor(code); clang::QualType result = visitor.test(); @@ -129,7 +128,6 @@ template struct test { using result = typename A::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 +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(); + // result->dump(); + auto TST = result->getAs(); + 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(args[0].getAsType()); + ASSERT_TRUE(T); + ASSERT_EQ(T->getDecl()->getName(), "X"); +} + } // namespace