dgoldman created this revision.
dgoldman added reviewers: kadircet, sammccall.
Herald added subscribers: usaxena95, arphaman.
Herald added a project: All.
dgoldman requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.
Add an optional declarationRange and definitionRange to SymbolDetails.
This will allow SourceKit-LSP to implement toggling between goto
definition/declaration based on whether the symbol at the cursor
is a definition or declaration.
In addition, make some minor fixes for ObjCMethodDecl:
- XRefs.cpp getDefinition now sees ObjC method defs but I've left a TODO to
implement proper searching for impls from a decl
- nameLocation for ObjC methods should point to foo in `- (void)foo`, not the -
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D130041
Files:
clang-tools-extra/clangd/AST.cpp
clang-tools-extra/clangd/Protocol.cpp
clang-tools-extra/clangd/Protocol.h
clang-tools-extra/clangd/XRefs.cpp
clang-tools-extra/clangd/test/symbol-info.test
clang-tools-extra/clangd/unittests/SymbolInfoTests.cpp
Index: clang-tools-extra/clangd/unittests/SymbolInfoTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/SymbolInfoTests.cpp
+++ clang-tools-extra/clangd/unittests/SymbolInfoTests.cpp
@@ -18,45 +18,79 @@
using ::testing::UnorderedElementsAreArray;
-auto CreateExpectedSymbolDetails = [](const std::string &Name,
- const std::string &Container,
- const std::string &USR) {
- return SymbolDetails{Name, Container, USR, SymbolID(USR)};
+// Partial SymbolDetails with the rest filled in at testing time.
+struct ExpectedSymbolDetails {
+ std::string Name;
+
+ std::string Container;
+
+ std::string USR;
+
+ const char *DeclMarker = nullptr;
+ const char *DefMarker = nullptr;
};
TEST(SymbolInfoTests, All) {
- std::pair<const char *, std::vector<SymbolDetails>>
+ std::pair<const char *, std::vector<ExpectedSymbolDetails>>
TestInputExpectedOutput[] = {
{
R"cpp( // Simple function reference - declaration
- void foo();
+ void $decl[[foo]]();
int bar() {
fo^o();
}
)cpp",
- {CreateExpectedSymbolDetails("foo", "", "c:@F@foo#")}},
+ {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "decl"}}},
{
R"cpp( // Simple function reference - definition
- void foo() {}
+ void $def[[foo]]() {}
+ int bar() {
+ fo^o();
+ }
+ )cpp",
+ {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "def", "def"}}},
+ {
+ R"cpp( // Simple function reference - decl and def
+ void $decl[[foo]]();
+ void $def[[foo]]() {}
int bar() {
fo^o();
}
)cpp",
- {CreateExpectedSymbolDetails("foo", "", "c:@F@foo#")}},
+ {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "decl", "def"}}},
+ {
+ R"cpp( // Simple class reference - decl and def
+ @interface $decl[[Foo]]
+ @end
+ @implementation $def[[Foo]]
+ @end
+ void doSomething(F^oo *obj) {}
+ )cpp",
+ {ExpectedSymbolDetails{"Foo", "", "c:objc(cs)Foo", "decl", "def"}}},
+ {
+ R"cpp( // Simple method reference - decl and def
+ @interface Foo
+ - (void)$decl[[foo]];
+ @end
+ @implementation Foo
+ - (void)$def[[fo^o]] {}
+ @end
+ )cpp",
+ {ExpectedSymbolDetails{"foo", "Foo::", "c:objc(cs)Foo(im)foo", "decl", "def"}}},
{
R"cpp( // Function in namespace reference
namespace bar {
- void foo();
+ void $decl[[foo]]();
int baz() {
fo^o();
}
}
)cpp",
- {CreateExpectedSymbolDetails("foo", "bar::", "c:@N@bar@F@foo#")}},
+ {ExpectedSymbolDetails{"foo", "bar::", "c:@N@bar@F@foo#", "decl"}}},
{
R"cpp( // Function in different namespace reference
namespace bar {
- void foo();
+ void $decl[[foo]]();
}
namespace barbar {
int baz() {
@@ -64,10 +98,10 @@
}
}
)cpp",
- {CreateExpectedSymbolDetails("foo", "bar::", "c:@N@bar@F@foo#")}},
+ {ExpectedSymbolDetails{"foo", "bar::", "c:@N@bar@F@foo#", "decl"}}},
{
R"cpp( // Function in global namespace reference
- void foo();
+ void $decl[[foo]]();
namespace Nbar {
namespace Nbaz {
int baz() {
@@ -76,11 +110,11 @@
}
}
)cpp",
- {CreateExpectedSymbolDetails("foo", "", "c:@F@foo#")}},
+ {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "decl"}}},
{
R"cpp( // Function in anonymous namespace reference
namespace {
- void foo();
+ void $decl[[foo]]();
}
namespace barbar {
int baz() {
@@ -88,13 +122,13 @@
}
}
)cpp",
- {CreateExpectedSymbolDetails("foo", "(anonymous)",
- "c:TestTU.cpp@aN@F@foo#")}},
+ {ExpectedSymbolDetails{"foo", "(anonymous)",
+ "c:TestTU.cpp@aN@F@foo#", "decl"}}},
{
R"cpp( // Function reference - ADL
namespace bar {
struct BarType {};
- void foo(const BarType&);
+ void $decl[[foo]](const BarType&);
}
namespace barbar {
int baz() {
@@ -103,67 +137,67 @@
}
}
)cpp",
- {CreateExpectedSymbolDetails(
- "foo", "bar::", "c:@N@bar@F@foo#&1$@N@bar@S@BarType#")}},
+ {ExpectedSymbolDetails{
+ "foo", "bar::", "c:@N@bar@F@foo#&1$@N@bar@S@BarType#", "decl"}}},
{
R"cpp( // Global value reference
- int value;
+ int $def[[value]];
void foo(int) { }
void bar() {
foo(val^ue);
}
)cpp",
- {CreateExpectedSymbolDetails("value", "", "c:@value")}},
+ {ExpectedSymbolDetails{"value", "", "c:@value", "def", "def"}}},
{
R"cpp( // Local value reference
- void foo() { int aaa; int bbb = aa^a; }
+ void foo() { int $def[[aaa]]; int bbb = aa^a; }
)cpp",
- {CreateExpectedSymbolDetails("aaa", "foo",
- "c:TestTU.cpp@49@F@foo#@aaa")}},
+ {ExpectedSymbolDetails{"aaa", "foo",
+ "c:TestTU.cpp@49@F@foo#@aaa", "def", "def"}}},
{
R"cpp( // Function param
- void bar(int aaa) {
+ void bar(int $def[[aaa]]) {
int bbb = a^aa;
}
)cpp",
- {CreateExpectedSymbolDetails("aaa", "bar",
- "c:TestTU.cpp@38@F@bar#I#@aaa")}},
+ {ExpectedSymbolDetails{"aaa", "bar",
+ "c:TestTU.cpp@38@F@bar#I#@aaa", "def", "def"}}},
{
R"cpp( // Lambda capture
void foo() {
- int ii;
+ int $def[[ii]];
auto lam = [ii]() {
return i^i;
};
}
)cpp",
- {CreateExpectedSymbolDetails("ii", "foo",
- "c:TestTU.cpp@54@F@foo#@ii")}},
+ {ExpectedSymbolDetails{"ii", "foo",
+ "c:TestTU.cpp@54@F@foo#@ii", "def", "def"}}},
{
R"cpp( // Macro reference
#define MACRO 5\nint i = MAC^RO;
)cpp",
- {CreateExpectedSymbolDetails("MACRO", "",
- "c:TestTU.cpp@38@macro@MACRO")}},
+ {ExpectedSymbolDetails{"MACRO", "",
+ "c:TestTU.cpp@38@macro@MACRO"}}},
{
R"cpp( // Macro reference
#define MACRO 5\nint i = MACRO^;
)cpp",
- {CreateExpectedSymbolDetails("MACRO", "",
- "c:TestTU.cpp@38@macro@MACRO")}},
+ {ExpectedSymbolDetails{"MACRO", "",
+ "c:TestTU.cpp@38@macro@MACRO"}}},
{
R"cpp( // Multiple symbols returned - using overloaded function name
- void foo() {}
- void foo(bool) {}
- void foo(int) {}
+ void $def[[foo]]() {}
+ void $def_bool[[foo]](bool) {}
+ void $def_int[[foo]](int) {}
namespace bar {
- using ::fo^o;
+ using ::$decl[[fo^o]];
}
)cpp",
- {CreateExpectedSymbolDetails("foo", "", "c:@F@foo#"),
- CreateExpectedSymbolDetails("foo", "", "c:@F@foo#b#"),
- CreateExpectedSymbolDetails("foo", "", "c:@F@foo#I#"),
- CreateExpectedSymbolDetails("foo", "bar::", "c:@N@bar@UD@foo")}},
+ {ExpectedSymbolDetails{"foo", "", "c:@F@foo#", "def", "def"},
+ ExpectedSymbolDetails{"foo", "", "c:@F@foo#b#", "def_bool", "def_bool"},
+ ExpectedSymbolDetails{"foo", "", "c:@F@foo#I#", "def_int", "def_int"},
+ ExpectedSymbolDetails{"foo", "bar::", "c:@N@bar@UD@foo", "decl"}}},
{
R"cpp( // Multiple symbols returned - implicit conversion
struct foo {};
@@ -172,133 +206,133 @@
};
void func_baz1(bar) {}
void func_baz2() {
- foo ff;
+ foo $def[[ff]];
func_baz1(f^f);
}
)cpp",
- {CreateExpectedSymbolDetails(
- "ff", "func_baz2", "c:TestTU.cpp@218@F@func_baz2#@ff")}},
+ {ExpectedSymbolDetails{
+ "ff", "func_baz2", "c:TestTU.cpp@218@F@func_baz2#@ff", "def", "def"}}},
{
R"cpp( // Type reference - declaration
- struct foo;
+ struct $decl[[foo]];
void bar(fo^o*);
)cpp",
- {CreateExpectedSymbolDetails("foo", "", "c:@S@foo")}},
+ {ExpectedSymbolDetails{"foo", "", "c:@S@foo", "decl"}}},
{
R"cpp( // Type reference - definition
- struct foo {};
+ struct $def[[foo]] {};
void bar(fo^o*);
)cpp",
- {CreateExpectedSymbolDetails("foo", "", "c:@S@foo")}},
+ {ExpectedSymbolDetails{"foo", "", "c:@S@foo", "def", "def"}}},
{
R"cpp( // Type Reference - template argument
- struct foo {};
+ struct $def[[foo]] {};
template<class T> struct bar {};
void baz() {
bar<fo^o> b;
}
)cpp",
- {CreateExpectedSymbolDetails("foo", "", "c:@S@foo")}},
+ {ExpectedSymbolDetails{"foo", "", "c:@S@foo", "def", "def"}}},
{
R"cpp( // Template parameter reference - type param
- template<class TT> struct bar {
+ template<class $def[[TT]]> struct bar {
T^T t;
};
)cpp",
- {CreateExpectedSymbolDetails("TT", "bar::", "c:TestTU.cpp@65")}},
+ {ExpectedSymbolDetails{"TT", "bar::", "c:TestTU.cpp@65", "def", "def"}}},
{
R"cpp( // Template parameter reference - type param
- template<int NN> struct bar {
+ template<int $def[[NN]]> struct bar {
int a = N^N;
};
)cpp",
- {CreateExpectedSymbolDetails("NN", "bar::", "c:TestTU.cpp@65")}},
+ {ExpectedSymbolDetails{"NN", "bar::", "c:TestTU.cpp@65", "def", "def"}}},
{
R"cpp( // Class member reference - objec
struct foo {
- int aa;
+ int $def[[aa]];
};
void bar() {
foo f;
f.a^a;
}
)cpp",
- {CreateExpectedSymbolDetails("aa", "foo::", "c:@S@foo@FI@aa")}},
+ {ExpectedSymbolDetails{"aa", "foo::", "c:@S@foo@FI@aa", "def", "def"}}},
{
R"cpp( // Class member reference - pointer
struct foo {
- int aa;
+ int $def[[aa]];
};
void bar() {
&foo::a^a;
}
)cpp",
- {CreateExpectedSymbolDetails("aa", "foo::", "c:@S@foo@FI@aa")}},
+ {ExpectedSymbolDetails{"aa", "foo::", "c:@S@foo@FI@aa", "def", "def"}}},
{
R"cpp( // Class method reference - objec
struct foo {
- void aa() {}
+ void $def[[aa]]() {}
};
void bar() {
foo f;
f.a^a();
}
)cpp",
- {CreateExpectedSymbolDetails("aa", "foo::", "c:@S@foo@F@aa#")}},
+ {ExpectedSymbolDetails{"aa", "foo::", "c:@S@foo@F@aa#", "def", "def"}}},
{
R"cpp( // Class method reference - pointer
struct foo {
- void aa() {}
+ void $def[[aa]]() {}
};
void bar() {
&foo::a^a;
}
)cpp",
- {CreateExpectedSymbolDetails("aa", "foo::", "c:@S@foo@F@aa#")}},
+ {ExpectedSymbolDetails{"aa", "foo::", "c:@S@foo@F@aa#", "def", "def"}}},
{
R"cpp( // Typedef
- typedef int foo;
+ typedef int $decl[[foo]];
void bar() {
fo^o a;
}
)cpp",
- {CreateExpectedSymbolDetails("foo", "", "c:TestTU.cpp@T@foo")}},
+ {ExpectedSymbolDetails{"foo", "", "c:TestTU.cpp@T@foo", "decl"}}},
{
R"cpp( // Type alias
- using foo = int;
+ using $decl[[foo]] = int;
void bar() {
fo^o a;
}
)cpp",
- {CreateExpectedSymbolDetails("foo", "", "c:@foo")}},
+ {ExpectedSymbolDetails{"foo", "", "c:@foo", "decl"}}},
{
R"cpp( // Namespace reference
- namespace foo {}
+ namespace $decl[[foo]] {}
using namespace fo^o;
)cpp",
- {CreateExpectedSymbolDetails("foo", "", "c:@N@foo")}},
+ {ExpectedSymbolDetails{"foo", "", "c:@N@foo", "decl"}}},
{
R"cpp( // Enum value reference
- enum foo { bar, baz };
+ enum foo { $def[[bar]], baz };
void f() {
foo fff = ba^r;
}
)cpp",
- {CreateExpectedSymbolDetails("bar", "foo", "c:@E@foo@bar")}},
+ {ExpectedSymbolDetails{"bar", "foo", "c:@E@foo@bar", "def", "def"}}},
{
R"cpp( // Enum class value reference
- enum class foo { bar, baz };
+ enum class foo { $def[[bar]], baz };
void f() {
foo fff = foo::ba^r;
}
)cpp",
- {CreateExpectedSymbolDetails("bar", "foo::", "c:@E@foo@bar")}},
+ {ExpectedSymbolDetails{"bar", "foo::", "c:@E@foo@bar", "def", "def"}}},
{
R"cpp( // Parameters in declarations
- void foo(int ba^r);
+ void foo(int $def[[ba^r]]);
)cpp",
- {CreateExpectedSymbolDetails("bar", "foo",
- "c:TestTU.cpp@50@F@foo#I#@bar")}},
+ {ExpectedSymbolDetails{"bar", "foo",
+ "c:TestTU.cpp@50@F@foo#I#@bar", "def", "def"}}},
{
R"cpp( // Type inference with auto keyword
struct foo {};
@@ -321,10 +355,23 @@
for (const auto &T : TestInputExpectedOutput) {
Annotations TestInput(T.first);
- auto AST = TestTU::withCode(TestInput.code()).build();
+ TestTU TU;
+ TU.Code = std::string(TestInput.code());
+ TU.ExtraArgs.push_back("-xobjective-c++");
+ auto AST = TU.build();
+
+ std::vector<SymbolDetails> Expected;
+ for (const auto &Sym : T.second) {
+ llvm::Optional<Location> Decl, Def;
+ if (Sym.DeclMarker)
+ Decl = Location{URIForFile::canonicalize(testPath(TU.Filename), ""), TestInput.range(Sym.DeclMarker)};
+ if (Sym.DefMarker)
+ Def = Location{URIForFile::canonicalize(testPath(TU.Filename), ""), TestInput.range(Sym.DefMarker)};
+ Expected.push_back({Sym.Name, Sym.Container, Sym.USR, SymbolID(Sym.USR), Decl, Def});
+ }
EXPECT_THAT(getSymbolInfo(AST, TestInput.point()),
- UnorderedElementsAreArray(T.second))
+ UnorderedElementsAreArray(Expected))
<< T.first;
}
}
Index: clang-tools-extra/clangd/test/symbol-info.test
===================================================================
--- clang-tools-extra/clangd/test/symbol-info.test
+++ clang-tools-extra/clangd/test/symbol-info.test
@@ -1,10 +1,23 @@
-# RUN: clangd -lit-test < %s | FileCheck %s
+# RUN: clangd -lit-test < %s | FileCheck %s --
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
---
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///simple.cpp","languageId":"cpp","version":1,"text":"void foo(); int main() { foo(); }\n"}}}
---
{"jsonrpc":"2.0","id":1,"method":"textDocument/symbolInfo","params":{"textDocument":{"uri":"test:///simple.cpp"},"position":{"line":0,"character":27}}}
# CHECK: "containerName": null,
+# CHECK-NEXT: "declarationRange": {
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 8,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 5,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "uri": "file:///clangd-test/simple.cpp"
+# CHECK-NEXT: },
# CHECK-NEXT: "id": "CA2EBE44A1D76D2A",
# CHECK-NEXT: "name": "foo",
# CHECK-NEXT: "usr": "c:@F@foo#"
Index: clang-tools-extra/clangd/XRefs.cpp
===================================================================
--- clang-tools-extra/clangd/XRefs.cpp
+++ clang-tools-extra/clangd/XRefs.cpp
@@ -83,6 +83,12 @@
if (const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
if (const auto *RD = CTD->getTemplatedDecl())
return RD->getDefinition();
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
+ if (MD->isThisDeclarationADefinition())
+ return MD;
+ // FIXME: We need to search impl objc containers like
+ // ObjCMethodDecl::getNextRedeclarationImpl().
+
// Objective-C classes can have three types of declarations:
//
// - forward declaration: @class MyClass;
@@ -1519,7 +1525,8 @@
llvm::consumeError(CurLoc.takeError());
return {};
}
-
+ auto MainFilePath =
+ getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
std::vector<SymbolDetails> Results;
// We also want the targets of using-decls, so we include
@@ -1543,6 +1550,15 @@
NewSymbol.USR = std::string(USR.str());
NewSymbol.ID = SymbolID(NewSymbol.USR);
}
+ if (MainFilePath) {
+ if (const NamedDecl *Def = getDefinition(D))
+ NewSymbol.definitionRange = makeLocation(
+ AST.getASTContext(), nameLocation(*Def, SM), *MainFilePath);
+ const NamedDecl *Decl = getPreferredDecl(D);
+ NewSymbol.declarationRange = makeLocation(
+ AST.getASTContext(), nameLocation(*Decl, SM), *MainFilePath);
+ }
+
Results.push_back(std::move(NewSymbol));
}
Index: clang-tools-extra/clangd/Protocol.h
===================================================================
--- clang-tools-extra/clangd/Protocol.h
+++ clang-tools-extra/clangd/Protocol.h
@@ -1093,6 +1093,10 @@
std::string USR;
SymbolID ID;
+
+ llvm::Optional<Location> declarationRange;
+
+ llvm::Optional<Location> definitionRange;
};
llvm::json::Value toJSON(const SymbolDetails &);
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const SymbolDetails &);
Index: clang-tools-extra/clangd/Protocol.cpp
===================================================================
--- clang-tools-extra/clangd/Protocol.cpp
+++ clang-tools-extra/clangd/Protocol.cpp
@@ -734,7 +734,9 @@
bool operator==(const SymbolDetails &LHS, const SymbolDetails &RHS) {
return LHS.name == RHS.name && LHS.containerName == RHS.containerName &&
- LHS.USR == RHS.USR && LHS.ID == RHS.ID;
+ LHS.USR == RHS.USR && LHS.ID == RHS.ID &&
+ LHS.declarationRange == RHS.declarationRange &&
+ LHS.definitionRange == RHS.definitionRange;
}
llvm::json::Value toJSON(const SymbolDetails &P) {
@@ -755,6 +757,12 @@
if (P.ID)
Result["id"] = P.ID.str();
+ if (P.declarationRange)
+ Result["declarationRange"] = *P.declarationRange;
+
+ if (P.definitionRange)
+ Result["definitionRange"] = *P.definitionRange;
+
// FIXME: workaround for older gcc/clang
return std::move(Result);
}
Index: clang-tools-extra/clangd/AST.cpp
===================================================================
--- clang-tools-extra/clangd/AST.cpp
+++ clang-tools-extra/clangd/AST.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExprCXX.h"
@@ -170,6 +171,9 @@
SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM) {
auto L = D.getLocation();
+ // Use the start of the first selector fragment instead of the -/+ location.
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(&D))
+ L = MD->getSelectorStartLoc();
if (isSpelledInSource(L, SM))
return SM.getSpellingLoc(L);
return SM.getExpansionLoc(L);
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits