[clang-tools-extra] e33ec9d - [clangd] Target member of dependent base made visible via a using-decl
Nathan Ridge via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 18 00:04:01 PDT 2020
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) {
More information about the cfe-commits
mailing list