Author: Nathan Ridge Date: 2020-08-18T03:03:49-04:00 New Revision: e33ec9d90400a906314ccbd5821dbe05d070108a
URL: https://github.com/llvm/llvm-project/commit/e33ec9d90400a906314ccbd5821dbe05d070108a DIFF: https://github.com/llvm/llvm-project/commit/e33ec9d90400a906314ccbd5821dbe05d070108a.diff LOG: [clangd] Target member of dependent base made visible via a using-decl Fixes https://github.com/clangd/clangd/issues/307 Differential Revision: https://reviews.llvm.org/D86047 Added: Modified: clang-tools-extra/clangd/FindTarget.cpp clang-tools-extra/clangd/XRefs.cpp clang-tools-extra/clangd/unittests/FindTargetTests.cpp clang-tools-extra/clangd/unittests/XRefsTests.cpp Removed: ################################################################################ diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index f73a6e584972..9db814368a02 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -100,7 +100,7 @@ CXXRecordDecl *resolveTypeToRecordDecl(const Type *T) { std::vector<const NamedDecl *> getMembersReferencedViaDependentName( const Type *T, llvm::function_ref<DeclarationName(ASTContext &)> NameFactory, - bool IsNonstaticMember) { + llvm::function_ref<bool(const NamedDecl *ND)> Filter) { if (!T) return {}; if (auto *ET = T->getAs<EnumType>()) { @@ -113,17 +113,22 @@ std::vector<const NamedDecl *> getMembersReferencedViaDependentName( return {}; RD = RD->getDefinition(); DeclarationName Name = NameFactory(RD->getASTContext()); - return RD->lookupDependentName(Name, [=](const NamedDecl *D) { - return IsNonstaticMember ? D->isCXXInstanceMember() - : !D->isCXXInstanceMember(); - }); + return RD->lookupDependentName(Name, Filter); } return {}; } -// Given the type T of a dependent expression that appears of the LHS of a "->", -// heuristically find a corresponding pointee type in whose scope we could look -// up the name appearing on the RHS. +const auto NonStaticFilter = [](const NamedDecl *D) { + return D->isCXXInstanceMember(); +}; +const auto StaticFilter = [](const NamedDecl *D) { + return !D->isCXXInstanceMember(); +}; +const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); }; + +// Given the type T of a dependent expression that appears of the LHS of a +// "->", heuristically find a corresponding pointee type in whose scope we +// could look up the name appearing on the RHS. const Type *getPointeeType(const Type *T) { if (!T) return nullptr; @@ -141,7 +146,7 @@ const Type *getPointeeType(const Type *T) { [](ASTContext &Ctx) { return Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow); }, - /*IsNonStaticMember=*/true); + NonStaticFilter); if (ArrowOps.empty()) return nullptr; @@ -187,13 +192,12 @@ std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E) { } return getMembersReferencedViaDependentName( BaseType, [ME](ASTContext &) { return ME->getMember(); }, - /*IsNonstaticMember=*/true); + NonStaticFilter); } if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) { return getMembersReferencedViaDependentName( RE->getQualifier()->getAsType(), - [RE](ASTContext &) { return RE->getDeclName(); }, - /*IsNonstaticMember=*/false); + [RE](ASTContext &) { return RE->getDeclName(); }, StaticFilter); } if (const auto *CE = dyn_cast<CallExpr>(E)) { const auto *CalleeType = resolveExprToType(CE->getCallee()); @@ -291,7 +295,6 @@ const NamedDecl *getTemplatePattern(const NamedDecl *D) { // CXXDependentScopeMemberExpr, but some other constructs remain to be handled: // - DependentTemplateSpecializationType, // - DependentNameType -// - UnresolvedUsingValueDecl // - UnresolvedUsingTypenameDecl struct TargetFinder { using RelSet = DeclRelationSet; @@ -345,6 +348,15 @@ struct TargetFinder { } else if (const auto *NAD = dyn_cast<NamespaceAliasDecl>(D)) { add(NAD->getUnderlyingDecl(), Flags | Rel::Underlying); Flags |= Rel::Alias; // continue with the alias + } else if (const UnresolvedUsingValueDecl *UUVD = + dyn_cast<UnresolvedUsingValueDecl>(D)) { + for (const NamedDecl *Target : getMembersReferencedViaDependentName( + UUVD->getQualifier()->getAsType(), + [UUVD](ASTContext &) { return UUVD->getNameInfo().getName(); }, + ValueFilter)) { + add(Target, Flags | Rel::Underlying); + } + Flags |= Rel::Alias; // continue with the alias } else if (const UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) { // Include the using decl, but don't traverse it. This may end up // including *all* shadows, which we don't want. diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index 9936c67cb6e5..031a9c7bf5da 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -345,7 +345,7 @@ locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier, // Give the underlying decl if navigation is triggered on a non-renaming // alias. - if (llvm::isa<UsingDecl>(D)) { + if (llvm::isa<UsingDecl>(D) || llvm::isa<UnresolvedUsingValueDecl>(D)) { // FIXME: address more complicated cases. TargetDecl(... Underlying) gives // all overload candidates, we only want the targeted one if the cursor is // on an using-alias usage, workround it with getDeclAtPosition. diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp index 2507932c5cda..5bfdaaf6c343 100644 --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -207,6 +207,19 @@ TEST_F(TargetDeclTest, UsingDecl) { )cpp"; EXPECT_DECLS("MemberExpr", {"using X::foo", Rel::Alias}, {"int foo()", Rel::Underlying}); + + Code = R"cpp( + template <typename T> + struct Base { + void waldo() {} + }; + template <typename T> + struct Derived : Base<T> { + using Base<T>::[[waldo]]; + }; + )cpp"; + EXPECT_DECLS("UnresolvedUsingValueDecl", {"using Base<T>::waldo", Rel::Alias}, + {"void waldo()", Rel::Underlying}); } TEST_F(TargetDeclTest, ConstructorInitList) { diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp index 63e8c96daab8..d2337dcbd7b3 100644 --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -1087,66 +1087,78 @@ TEST(LocateSymbol, TextualDependent) { TEST(LocateSymbol, Alias) { const char *Tests[] = { - R"cpp( + R"cpp( template <class T> struct function {}; template <class T> using [[callback]] = function<T()>; c^allback<int> foo; )cpp", - // triggered on non-definition of a renaming alias: should not give any - // underlying decls. - R"cpp( + // triggered on non-definition of a renaming alias: should not give any + // underlying decls. + R"cpp( class Foo {}; typedef Foo [[Bar]]; B^ar b; )cpp", - R"cpp( + R"cpp( class Foo {}; using [[Bar]] = Foo; // definition Ba^r b; )cpp", - // triggered on the underlying decl of a renaming alias. - R"cpp( + // triggered on the underlying decl of a renaming alias. + R"cpp( class [[Foo]]; using Bar = Fo^o; )cpp", - // triggered on definition of a non-renaming alias: should give underlying - // decls. - R"cpp( + // triggered on definition of a non-renaming alias: should give underlying + // decls. + R"cpp( namespace ns { class [[Foo]] {}; } using ns::F^oo; )cpp", - R"cpp( + R"cpp( namespace ns { int [[x]](char); int [[x]](double); } using ns::^x; )cpp", - R"cpp( + R"cpp( namespace ns { int [[x]](char); int x(double); } using ns::x; int y = ^x('a'); )cpp", - R"cpp( + R"cpp( namespace ns { class [[Foo]] {}; } using ns::Foo; F^oo f; )cpp", - // other cases that don't matter much. - R"cpp( + // other cases that don't matter much. + R"cpp( class Foo {}; typedef Foo [[Ba^r]]; )cpp", - R"cpp( + R"cpp( class Foo {}; using [[B^ar]] = Foo; )cpp", + + // Member of dependent base + R"cpp( + template <typename T> + struct Base { + void [[waldo]]() {} + }; + template <typename T> + struct Derived : Base<T> { + using Base<T>::w^aldo; + }; + )cpp", }; for (const auto* Case : Tests) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits