Skip to content

Commit 532a37b

Browse files
committed
Show container name in call hierarchy item name instead of detail field
The container name isn’t displayed very prominently and it’s easy to miss. I think the call hierarchy looks nicer when we prepend the container name with language-specific logic. rdar://128396648
1 parent 98718d4 commit 532a37b

File tree

2 files changed

+119
-9
lines changed

2 files changed

+119
-9
lines changed

Sources/SourceKitLSP/SourceKitLSPServer.swift

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,11 +1851,28 @@ extension SourceKitLSPServer {
18511851
containerName: String?,
18521852
location: Location
18531853
) -> CallHierarchyItem {
1854-
CallHierarchyItem(
1855-
name: symbol.name,
1854+
let name: String
1855+
if let containerName {
1856+
switch symbol.language {
1857+
case .objc where symbol.kind == .instanceMethod || symbol.kind == .instanceProperty:
1858+
name = "-[\(containerName) \(symbol.name)]"
1859+
case .objc where symbol.kind == .classMethod || symbol.kind == .classProperty:
1860+
name = "+[\(containerName) \(symbol.name)]"
1861+
case .cxx, .c, .objc:
1862+
// C shouldn't have container names for call hierarchy and Objective-C should be covered above.
1863+
// Fall back to using the C++ notation using `::`.
1864+
name = "\(containerName)::\(symbol.name)"
1865+
case .swift:
1866+
name = "\(containerName).\(symbol.name)"
1867+
}
1868+
} else {
1869+
name = symbol.name
1870+
}
1871+
return CallHierarchyItem(
1872+
name: name,
18561873
kind: symbol.kind.asLspSymbolKind(),
18571874
tags: nil,
1858-
detail: containerName,
1875+
detail: nil,
18591876
uri: location.uri,
18601877
range: location.range,
18611878
selectionRange: location.range,
@@ -2289,8 +2306,15 @@ extension IndexSymbolKind {
22892306
return .struct
22902307
case .parameter:
22912308
return .typeParameter
2292-
2293-
default:
2309+
case .module, .namespace:
2310+
return .namespace
2311+
case .field:
2312+
return .property
2313+
case .constructor:
2314+
return .constructor
2315+
case .destructor:
2316+
return .null
2317+
case .commentTag, .concept, .extension, .macro, .namespaceAlias, .typealias, .union, .unknown, .using:
22942318
return .null
22952319
}
22962320
}

Tests/SourceKitLSPTests/CallHierarchyTests.swift

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,9 @@ final class CallHierarchyTests: XCTestCase {
212212
result,
213213
[
214214
CallHierarchyItem(
215-
name: "foo",
215+
name: "FilePathIndex::foo",
216216
kind: .method,
217217
tags: nil,
218-
detail: "FilePathIndex",
219218
uri: try project.uri(for: "lib.cpp"),
220219
range: try Range(project.position(of: "2️⃣", in: "lib.cpp")),
221220
selectionRange: try Range(project.position(of: "2️⃣", in: "lib.cpp")),
@@ -583,10 +582,9 @@ final class CallHierarchyTests: XCTestCase {
583582
[
584583
CallHierarchyIncomingCall(
585584
from: CallHierarchyItem(
586-
name: "foo()",
585+
name: "MyClass.foo()",
587586
kind: .method,
588587
tags: nil,
589-
detail: "MyClass",
590588
uri: project.fileURI,
591589
range: Range(project.positions["1️⃣"]),
592590
selectionRange: Range(project.positions["1️⃣"]),
@@ -764,4 +762,92 @@ final class CallHierarchyTests: XCTestCase {
764762
]
765763
)
766764
}
765+
766+
func testInitializerInCallHierarchy() async throws {
767+
try await SkipUnless.indexOnlyHasContainedByRelationsToIndexedDecls()
768+
let project = try await IndexedSingleSwiftFileTestProject(
769+
"""
770+
func 1️⃣foo() {}
771+
772+
struct Bar {
773+
2️⃣init() {
774+
3️⃣foo()
775+
}
776+
}
777+
"""
778+
)
779+
let prepare = try await project.testClient.send(
780+
CallHierarchyPrepareRequest(
781+
textDocument: TextDocumentIdentifier(project.fileURI),
782+
position: project.positions["1️⃣"]
783+
)
784+
)
785+
let initialItem = try XCTUnwrap(prepare?.only)
786+
let calls = try await project.testClient.send(CallHierarchyIncomingCallsRequest(item: initialItem))
787+
XCTAssertEqual(
788+
calls,
789+
[
790+
CallHierarchyIncomingCall(
791+
from: CallHierarchyItem(
792+
name: "Bar.init()",
793+
kind: .constructor,
794+
tags: nil,
795+
uri: project.fileURI,
796+
range: Range(project.positions["2️⃣"]),
797+
selectionRange: Range(project.positions["2️⃣"]),
798+
data: .dictionary([
799+
"usr": .string("s:4test3BarVACycfc"),
800+
"uri": .string(project.fileURI.stringValue),
801+
])
802+
),
803+
fromRanges: [Range(project.positions["3️⃣"])]
804+
)
805+
]
806+
)
807+
}
808+
809+
func testCallHierarchyOfNestedClass() async throws {
810+
try await SkipUnless.indexOnlyHasContainedByRelationsToIndexedDecls()
811+
let project = try await IndexedSingleSwiftFileTestProject(
812+
"""
813+
func 1️⃣foo() {}
814+
815+
struct Outer {
816+
struct Bar {
817+
2️⃣init() {
818+
3️⃣foo()
819+
}
820+
}
821+
}
822+
"""
823+
)
824+
let prepare = try await project.testClient.send(
825+
CallHierarchyPrepareRequest(
826+
textDocument: TextDocumentIdentifier(project.fileURI),
827+
position: project.positions["1️⃣"]
828+
)
829+
)
830+
let initialItem = try XCTUnwrap(prepare?.only)
831+
let calls = try await project.testClient.send(CallHierarchyIncomingCallsRequest(item: initialItem))
832+
XCTAssertEqual(
833+
calls,
834+
[
835+
CallHierarchyIncomingCall(
836+
from: CallHierarchyItem(
837+
name: "Bar.init()",
838+
kind: .constructor,
839+
tags: nil,
840+
uri: project.fileURI,
841+
range: Range(project.positions["2️⃣"]),
842+
selectionRange: Range(project.positions["2️⃣"]),
843+
data: .dictionary([
844+
"usr": .string("s:4test5OuterV3BarVAEycfc"),
845+
"uri": .string(project.fileURI.stringValue),
846+
])
847+
),
848+
fromRanges: [Range(project.positions["3️⃣"])]
849+
)
850+
]
851+
)
852+
}
767853
}

0 commit comments

Comments
 (0)