Skip to content

Show overriden functions when performing jump-to-definition on a dynamic call #977

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions Sources/LanguageServerProtocol/Requests/SymbolInfoRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,52 @@ public struct SymbolDetails: ResponseType, Hashable {
/// The kind of the symbol
public var kind: SymbolKind?

/// Whether the symbol is a dynamic call for which it isn't known which method will be invoked at runtime. This is
/// the case for protocol methods and class functions.
///
/// Optional because `clangd` does not return whether a symbol is dynamic.
public var isDynamic: Bool?

/// If the symbol is dynamic, the USRs of the types that might be called.
///
/// This is relevant in the following cases
/// ```swift
/// class A {
/// func doThing() {}
/// }
/// class B: A {}
/// class C: B {
/// override func doThing() {}
/// }
/// class D: A {
/// override func doThing() {}
/// }
/// func test(value: B) {
/// value.doThing()
/// }
/// ```
///
/// The USR of the called function in `value.doThing` is `A.doThing` (or its
/// mangled form) but it can never call `D.doThing`. In this case, the
/// receiver USR would be `B`, indicating that only overrides of subtypes in
/// `B` may be called dynamically.
public var receiverUsrs: [String]?

public init(
name: String?,
containerName: String? = nil,
containerName: String?,
usr: String?,
bestLocalDeclaration: Location? = nil,
kind: SymbolKind? = nil
bestLocalDeclaration: Location?,
kind: SymbolKind?,
isDynamic: Bool?,
receiverUsrs: [String]?
) {
self.name = name
self.containerName = containerName
self.usr = usr
self.bestLocalDeclaration = bestLocalDeclaration
self.kind = kind
self.isDynamic = isDynamic
self.receiverUsrs = receiverUsrs
}
}
21 changes: 21 additions & 0 deletions Sources/SourceKitD/SKDResponseArray.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,27 @@ public final class SKDResponseArray {
return true
}

public func map<T>(_ transform: (SKDResponseDictionary) -> T) -> [T] {
var result: [T] = []
result.reserveCapacity(self.count)
self.forEach { _, element in
result.append(transform(element))
return true
}
return result
}

public func compactMap<T>(_ transform: (SKDResponseDictionary) -> T?) -> [T] {
var result: [T] = []
self.forEach { _, element in
if let transformed = transform(element) {
result.append(transformed)
}
return true
}
return result
}

/// Attempt to access the item at `index` as a string.
public subscript(index: Int) -> String? {
if let cstr = sourcekitd.api.variant_array_get_string(array, index) {
Expand Down
4 changes: 4 additions & 0 deletions Sources/SourceKitD/sourcekitd_uids.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public struct sourcekitd_keys {
public let groupname: sourcekitd_uid_t
public let id: sourcekitd_uid_t
public let is_system: sourcekitd_uid_t
public let isDynamic: sourcekitd_uid_t
public let kind: sourcekitd_uid_t
public let length: sourcekitd_uid_t
public let line: sourcekitd_uid_t
Expand All @@ -56,6 +57,7 @@ public struct sourcekitd_keys {
public let num_bytes_to_erase: sourcekitd_uid_t
public let offset: sourcekitd_uid_t
public let ranges: sourcekitd_uid_t
public let receivers: sourcekitd_uid_t
public let refactor_actions: sourcekitd_uid_t
public let request: sourcekitd_uid_t
public let results: sourcekitd_uid_t
Expand Down Expand Up @@ -122,6 +124,7 @@ public struct sourcekitd_keys {
groupname = api.uid_get_from_cstr("key.groupname")!
id = api.uid_get_from_cstr("key.id")!
is_system = api.uid_get_from_cstr("key.is_system")!
isDynamic = api.uid_get_from_cstr("key.is_dynamic")!
kind = api.uid_get_from_cstr("key.kind")!
length = api.uid_get_from_cstr("key.length")!
line = api.uid_get_from_cstr("key.line")!
Expand All @@ -134,6 +137,7 @@ public struct sourcekitd_keys {
num_bytes_to_erase = api.uid_get_from_cstr("key.num_bytes_to_erase")!
offset = api.uid_get_from_cstr("key.offset")!
ranges = api.uid_get_from_cstr("key.ranges")!
receivers = api.uid_get_from_cstr("key.receivers")!
refactor_actions = api.uid_get_from_cstr("key.refactor_actions")!
request = api.uid_get_from_cstr("key.request")!
results = api.uid_get_from_cstr("key.results")!
Expand Down
Loading