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 @@ -21,6 +21,7 @@ #include "index/Relation.h" #include "index/SymbolLocation.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Attr.h" #include "clang/AST/Attrs.inc" #include "clang/AST/Decl.h" @@ -301,6 +302,14 @@ } } + // Give the underlying decla if navigation is triggered on a non-renaming + // alias. + if (llvm::isa(D)) { + llvm::for_each(targetDecl(ast_type_traits::DynTypedNode::create(*D), + DeclRelation::Underlying), + [&](const NamedDecl *UD) { AddResultDecl(UD); }); + } + // Otherwise the target declaration is the right one. AddResultDecl(D); } 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 @@ -45,6 +45,11 @@ MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } +MATCHER(DeclRange, "") { + const LocatedSymbol &Sym = ::testing::get<0>(arg); + const Range &Range = ::testing::get<1>(arg); + return Sym.PreferredDeclaration.range == Range; +} // Extracts ranges from an annotated example, and constructs a matcher for a // highlight set. Ranges should be named $read/$write as appropriate. @@ -660,17 +665,72 @@ Sym("baz", T.range("StaticOverload2")))); } -TEST(LocateSymbol, TemplateTypedefs) { - auto T = Annotations(R"cpp( - template struct function {}; - template using callback = function; +TEST(LocateSymbol, Alias) { + const char *Tests[] = { + R"cpp( + template struct function {}; + template using [[callback]] = function; - c^allback foo; - )cpp"); - auto AST = TestTU::withCode(T.code()).build(); - EXPECT_THAT(locateSymbolAt(AST, T.point()), ElementsAre(Sym("callback"))); + c^allback foo; + )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( + class Foo {}; + using [[Bar]] = Foo; // definition + Ba^r b; + )cpp", + + // triggered on definition of a non-renaming alias: should give underlying + // decls. + R"cpp( + namespace ns { class [[Foo]] {}; } + using ns::[[F^oo]]; + )cpp", + + // other cases that don't matter much. + R"cpp( + class Foo {}; + typedef Foo [[Ba^r]]; + )cpp", + R"cpp( + class Foo {}; + using [[B^ar]] = Foo; + )cpp", + R"cpp( + namespace ns { class [[Foo]] {}; } + using ns::Foo; + F^oo f; + )cpp", + }; + + for (const auto* Case : Tests) { + SCOPED_TRACE(Case); + auto T = Annotations(Case); + auto AST = TestTU::withCode(T.code()).build(); + EXPECT_THAT(locateSymbolAt(AST, T.point()), + ::testing::UnorderedPointwise(DeclRange(), T.ranges())); + } } +// TEST(LocateSymbol, TemplateTypedefs) { +// auto T = Annotations(R"cpp( +// template struct function {}; +// template using callback = function; + +// c^allback foo; +// )cpp"); +// auto AST = TestTU::withCode(T.code()).build(); +// EXPECT_THAT(locateSymbolAt(AST, T.point()), ElementsAre(Sym("callback"))); +// } + TEST(LocateSymbol, RelPathsInCompileCommand) { // The source is in "/clangd-test/src". // We build in "/clangd-test/build".