Skip to content

Commit ed410e6

Browse files
authored
Merge pull request #977 from ahoppen/ahoppen/jump-to-override
Show overriden functions when performing jump-to-definition on a dynamic call
2 parents f293741 + c7bd8c9 commit ed410e6

File tree

6 files changed

+332
-124
lines changed

6 files changed

+332
-124
lines changed

Sources/LanguageServerProtocol/Requests/SymbolInfoRequest.swift

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,52 @@ public struct SymbolDetails: ResponseType, Hashable {
8181
/// The kind of the symbol
8282
public var kind: SymbolKind?
8383

84+
/// Whether the symbol is a dynamic call for which it isn't known which method will be invoked at runtime. This is
85+
/// the case for protocol methods and class functions.
86+
///
87+
/// Optional because `clangd` does not return whether a symbol is dynamic.
88+
public var isDynamic: Bool?
89+
90+
/// If the symbol is dynamic, the USRs of the types that might be called.
91+
///
92+
/// This is relevant in the following cases
93+
/// ```swift
94+
/// class A {
95+
/// func doThing() {}
96+
/// }
97+
/// class B: A {}
98+
/// class C: B {
99+
/// override func doThing() {}
100+
/// }
101+
/// class D: A {
102+
/// override func doThing() {}
103+
/// }
104+
/// func test(value: B) {
105+
/// value.doThing()
106+
/// }
107+
/// ```
108+
///
109+
/// The USR of the called function in `value.doThing` is `A.doThing` (or its
110+
/// mangled form) but it can never call `D.doThing`. In this case, the
111+
/// receiver USR would be `B`, indicating that only overrides of subtypes in
112+
/// `B` may be called dynamically.
113+
public var receiverUsrs: [String]?
114+
84115
public init(
85116
name: String?,
86-
containerName: String? = nil,
117+
containerName: String?,
87118
usr: String?,
88-
bestLocalDeclaration: Location? = nil,
89-
kind: SymbolKind? = nil
119+
bestLocalDeclaration: Location?,
120+
kind: SymbolKind?,
121+
isDynamic: Bool?,
122+
receiverUsrs: [String]?
90123
) {
91124
self.name = name
92125
self.containerName = containerName
93126
self.usr = usr
94127
self.bestLocalDeclaration = bestLocalDeclaration
95128
self.kind = kind
129+
self.isDynamic = isDynamic
130+
self.receiverUsrs = receiverUsrs
96131
}
97132
}

Sources/SourceKitD/SKDResponseArray.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,27 @@ public final class SKDResponseArray {
5555
return true
5656
}
5757

58+
public func map<T>(_ transform: (SKDResponseDictionary) -> T) -> [T] {
59+
var result: [T] = []
60+
result.reserveCapacity(self.count)
61+
self.forEach { _, element in
62+
result.append(transform(element))
63+
return true
64+
}
65+
return result
66+
}
67+
68+
public func compactMap<T>(_ transform: (SKDResponseDictionary) -> T?) -> [T] {
69+
var result: [T] = []
70+
self.forEach { _, element in
71+
if let transformed = transform(element) {
72+
result.append(transformed)
73+
}
74+
return true
75+
}
76+
return result
77+
}
78+
5879
/// Attempt to access the item at `index` as a string.
5980
public subscript(index: Int) -> String? {
6081
if let cstr = sourcekitd.api.variant_array_get_string(array, index) {

Sources/SourceKitD/sourcekitd_uids.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public struct sourcekitd_keys {
4444
public let groupname: sourcekitd_uid_t
4545
public let id: sourcekitd_uid_t
4646
public let is_system: sourcekitd_uid_t
47+
public let isDynamic: sourcekitd_uid_t
4748
public let kind: sourcekitd_uid_t
4849
public let length: sourcekitd_uid_t
4950
public let line: sourcekitd_uid_t
@@ -56,6 +57,7 @@ public struct sourcekitd_keys {
5657
public let num_bytes_to_erase: sourcekitd_uid_t
5758
public let offset: sourcekitd_uid_t
5859
public let ranges: sourcekitd_uid_t
60+
public let receivers: sourcekitd_uid_t
5961
public let refactor_actions: sourcekitd_uid_t
6062
public let request: sourcekitd_uid_t
6163
public let results: sourcekitd_uid_t
@@ -122,6 +124,7 @@ public struct sourcekitd_keys {
122124
groupname = api.uid_get_from_cstr("key.groupname")!
123125
id = api.uid_get_from_cstr("key.id")!
124126
is_system = api.uid_get_from_cstr("key.is_system")!
127+
isDynamic = api.uid_get_from_cstr("key.is_dynamic")!
125128
kind = api.uid_get_from_cstr("key.kind")!
126129
length = api.uid_get_from_cstr("key.length")!
127130
line = api.uid_get_from_cstr("key.line")!
@@ -134,6 +137,7 @@ public struct sourcekitd_keys {
134137
num_bytes_to_erase = api.uid_get_from_cstr("key.num_bytes_to_erase")!
135138
offset = api.uid_get_from_cstr("key.offset")!
136139
ranges = api.uid_get_from_cstr("key.ranges")!
140+
receivers = api.uid_get_from_cstr("key.receivers")!
137141
refactor_actions = api.uid_get_from_cstr("key.refactor_actions")!
138142
request = api.uid_get_from_cstr("key.request")!
139143
results = api.uid_get_from_cstr("key.results")!

0 commit comments

Comments
 (0)