diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -100,7 +100,7 @@ std::vector getMembersReferencedViaDependentName( const Type *T, llvm::function_ref NameFactory, - bool IsNonstaticMember) { + llvm::function_ref Filter) { if (!T) return {}; if (auto *ET = T->getAs()) { @@ -113,17 +113,24 @@ 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 dyn_cast(D) != nullptr; +}; + +// 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 +148,7 @@ [](ASTContext &Ctx) { return Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow); }, - /*IsNonStaticMember=*/true); + NonStaticFilter); if (ArrowOps.empty()) return nullptr; @@ -187,13 +194,12 @@ } return getMembersReferencedViaDependentName( BaseType, [ME](ASTContext &) { return ME->getMember(); }, - /*IsNonstaticMember=*/true); + NonStaticFilter); } if (const auto *RE = dyn_cast(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(E)) { const auto *CalleeType = resolveExprToType(CE->getCallee()); @@ -291,7 +297,6 @@ // CXXDependentScopeMemberExpr, but some other constructs remain to be handled: // - DependentTemplateSpecializationType, // - DependentNameType -// - UnresolvedUsingValueDecl // - UnresolvedUsingTypenameDecl struct TargetFinder { using RelSet = DeclRelationSet; @@ -345,6 +350,15 @@ } else if (const auto *NAD = dyn_cast(D)) { add(NAD->getUnderlyingDecl(), Flags | Rel::Underlying); Flags |= Rel::Alias; // continue with the alias + } else if (const UnresolvedUsingValueDecl *UUVD = + dyn_cast(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(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 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -345,7 +345,7 @@ // Give the underlying decl if navigation is triggered on a non-renaming // alias. - if (llvm::isa(D)) { + if (llvm::isa(D) || llvm::isa(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/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -734,7 +734,17 @@ Fo^o * getFoo() { return 0; } - )objc"}; + )objc", + R"cpp(// Member of dependent base + template + struct Base { + void [[waldo]]() {} + }; + template + struct Derived : Base { + using Base::w^aldo; + }; + )cpp"}; for (const char *Test : Tests) { Annotations T(Test); llvm::Optional WantDecl;