Skip to content

Commit 01f4b0f

Browse files
authored
Add LSP types and server stubs for call hierarchy support (#377)
* Add LSP types and server stubs for call hierarchy support * Update CMakeLists.txt for new LSP types * Call hierarchy misc fixes * Minor PositionRangeArray fixes to simplify codable conformance * Add CodingTests for PositionRangeArray and CallHierarchy encoding
1 parent 0396844 commit 01f4b0f

12 files changed

+355
-1
lines changed

Sources/LanguageServerProtocol/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ add_library(LanguageServerProtocol
2222
Notifications/TextSynchronizationNotifications.swift
2323

2424
Requests/ApplyEditRequest.swift
25+
Requests/CallHierarchyIncomingCallsRequest.swift
26+
Requests/CallHierarchyOutgoingCallsRequest.swift
27+
Requests/CallHierarchyPrepareRequest.swift
2528
Requests/CodeActionRequest.swift
2629
Requests/ColorPresentationRequest.swift
2730
Requests/CompletionRequest.swift
@@ -45,6 +48,7 @@ add_library(LanguageServerProtocol
4548
Requests/WorkspaceFoldersRequest.swift
4649
Requests/WorkspaceSymbolsRequest.swift
4750

51+
SupportTypes/CallHierarchyItem.swift
4852
SupportTypes/ClientCapabilities.swift
4953
SupportTypes/CodeActionKind.swift
5054
SupportTypes/Command.swift

Sources/LanguageServerProtocol/Messages.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ public let builtinRequests: [_RequestType.Type] = [
2222
CompletionRequest.self,
2323
HoverRequest.self,
2424
WorkspaceSymbolsRequest.self,
25+
CallHierarchyIncomingCallsRequest.self,
26+
CallHierarchyOutgoingCallsRequest.self,
27+
CallHierarchyPrepareRequest.self,
2528
DefinitionRequest.self,
2629
ImplementationRequest.self,
2730
ReferencesRequest.self,

Sources/LanguageServerProtocol/PositionRange.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,34 @@ public struct PositionRange: CustomCodableWrapper {
4545
}
4646
}
4747

48+
/// An LSP-compatible encoding for `Array<Range<Position>>`, for use with `CustomCodable`.
49+
public struct PositionRangeArray: CustomCodableWrapper {
50+
public var wrappedValue: [Range<Position>]
51+
52+
public init(wrappedValue: [Range<Position>]) {
53+
self.wrappedValue = wrappedValue
54+
}
55+
56+
public init(from decoder: Decoder) throws {
57+
var values: [Range<Position>] = []
58+
var arrayContainer = try decoder.unkeyedContainer()
59+
values.reserveCapacity(arrayContainer.count ?? 1)
60+
61+
while !arrayContainer.isAtEnd {
62+
let range = try arrayContainer.decode(PositionRange.self)
63+
values.append(range.wrappedValue)
64+
}
65+
self.wrappedValue = values
66+
}
67+
68+
public func encode(to encoder: Encoder) throws {
69+
var arrayContainer = encoder.unkeyedContainer()
70+
for rangeValue in wrappedValue {
71+
try arrayContainer.encode(PositionRange(wrappedValue: rangeValue))
72+
}
73+
}
74+
}
75+
4876
extension Range: LSPAnyCodable where Bound == Position {
4977
public init?(fromLSPDictionary dictionary: [String : LSPAny]) {
5078
guard case .dictionary(let start)? = dictionary[PositionRange.CodingKeys.lowerBound.stringValue],
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// The request is sent from the client to the server to resolve the callers for
14+
/// a given call hierarchy item. It is only issued if a server registers for the
15+
/// `textDocument/prepareCallHierarchy` request.
16+
public struct CallHierarchyIncomingCallsRequest: RequestType {
17+
public static let method: String = "callHierarchy/incomingCalls"
18+
public typealias Response = [CallHierarchyIncomingCall]?
19+
20+
public var item: CallHierarchyItem
21+
22+
public init(item: CallHierarchyItem) {
23+
self.item = item
24+
}
25+
}
26+
27+
/// Represents a caller (an incoming call) - an item that makes a call of the original `item`.
28+
public struct CallHierarchyIncomingCall: ResponseType, Hashable {
29+
/// The item that makes the call.
30+
public var from: CallHierarchyItem
31+
32+
/// The range(s) of calls inside the caller (the item denoted by `from`).
33+
@CustomCodable<PositionRangeArray>
34+
public var fromRanges: [Range<Position>]
35+
36+
public init(from: CallHierarchyItem, fromRanges: [Range<Position>]) {
37+
self.from = from
38+
self.fromRanges = fromRanges
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// The request is sent from the client to the server to resolve callees for a given call hierarchy item.
14+
/// It is only issued if a server registers for the `textDocument/prepareCallHierarchy` request.
15+
public struct CallHierarchyOutgoingCallsRequest: RequestType {
16+
public static let method: String = "callHierarchy/outgoingCalls"
17+
public typealias Response = [CallHierarchyOutgoingCall]?
18+
19+
public var item: CallHierarchyItem
20+
21+
public init(item: CallHierarchyItem) {
22+
self.item = item
23+
}
24+
}
25+
26+
/// Represents a callee (an outgoing call) - an item that is called by the original `item`.
27+
public struct CallHierarchyOutgoingCall: ResponseType, Hashable {
28+
/// The item that is called.
29+
public var to: CallHierarchyItem
30+
31+
/// The range(s) at which this item is called by the caller (the item inside
32+
/// the `callHierarchy/outgoingCalls` request).
33+
@CustomCodable<PositionRangeArray>
34+
public var fromRanges: [Range<Position>]
35+
36+
public init(to: CallHierarchyItem, fromRanges: [Range<Position>]) {
37+
self.to = to
38+
self.fromRanges = fromRanges
39+
}
40+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// The call hierarchy request is sent from the client to the server to return a call hierarchy for the
14+
/// language element of the given text document positions.
15+
///
16+
/// The call hierarchy requests are executed in two steps:
17+
/// 1. A call hierarchy item is resolved for the given text document position
18+
/// (via `textDocument/prepareCallHierarchy`)
19+
/// 2. The incoming or outgoing call hierarchy items are resolved for a call hierarchy item
20+
/// (via `callHierarchy/incomingCalls` or `callHierarchy/outgoingCalls`)
21+
public struct CallHierarchyPrepareRequest: TextDocumentRequest, Hashable {
22+
public static let method: String = "textDocument/prepareCallHierarchy"
23+
public typealias Response = [CallHierarchyItem]?
24+
25+
/// The document in which to prepare the call hierarchy items.
26+
public var textDocument: TextDocumentIdentifier
27+
28+
/// The document location at which to prepare the call hierarchy items.
29+
public var position: Position
30+
31+
public init(textDocument: TextDocumentIdentifier, position: Position) {
32+
self.textDocument = textDocument
33+
self.position = position
34+
}
35+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// A single call hierarchy item.
14+
public struct CallHierarchyItem: ResponseType, Hashable {
15+
/// Name of this item.
16+
public var name: String
17+
18+
public var kind: SymbolKind
19+
public var tags: [SymbolTag]?
20+
21+
/// More detail for this item, e.g. the signature of a function.
22+
public var detail: String?
23+
24+
/// The resource identifier of this item.
25+
public var uri: DocumentURI
26+
27+
/// The range enclosing this symbol, excluding leading/trailing whitespace
28+
/// but including everything else, e.g. comments and code.
29+
@CustomCodable<PositionRange>
30+
public var range: Range<Position>
31+
32+
/// The range that should be selected and revealed when this symbol is being
33+
/// picked, e.g. the name of a function. Must be contained by the `range`.
34+
@CustomCodable<PositionRange>
35+
public var selectionRange: Range<Position>
36+
37+
/// A data entry field that is preserved between a call hierarchy prepare and
38+
/// incoming calls or outgoing calls requests.
39+
public var data: LSPAny?
40+
41+
public init(
42+
name: String,
43+
kind: SymbolKind,
44+
tags: [SymbolTag]?,
45+
detail: String? = nil,
46+
uri: DocumentURI,
47+
range: Range<Position>,
48+
selectionRange: Range<Position>,
49+
data: LSPAny? = nil
50+
) {
51+
self.name = name
52+
self.kind = kind
53+
self.tags = tags
54+
self.detail = detail
55+
self.uri = uri
56+
self.range = range
57+
self.selectionRange = selectionRange
58+
self.data = data
59+
}
60+
}

Sources/LanguageServerProtocol/SupportTypes/ClientCapabilities.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,8 @@ public struct TextDocumentClientCapabilities: Hashable, Codable {
438438

439439
public var foldingRange: FoldingRange? = nil
440440

441+
public var callHierarchy: DynamicRegistrationCapability? = nil
442+
441443
public init(synchronization: Synchronization? = nil,
442444
completion: Completion? = nil,
443445
hover: Hover? = nil,
@@ -458,7 +460,8 @@ public struct TextDocumentClientCapabilities: Hashable, Codable {
458460
colorProvider: DynamicRegistrationCapability? = nil,
459461
rename: DynamicRegistrationCapability? = nil,
460462
publishDiagnostics: PublishDiagnostics? = nil,
461-
foldingRange: FoldingRange? = nil) {
463+
foldingRange: FoldingRange? = nil,
464+
callHierarchy: DynamicRegistrationCapability? = nil) {
462465
self.synchronization = synchronization
463466
self.completion = completion
464467
self.hover = hover
@@ -480,5 +483,6 @@ public struct TextDocumentClientCapabilities: Hashable, Codable {
480483
self.rename = rename
481484
self.publishDiagnostics = publishDiagnostics
482485
self.foldingRange = foldingRange
486+
self.callHierarchy = callHierarchy
483487
}
484488
}

Sources/LanguageServerProtocol/SupportTypes/ServerCapabilities.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ public struct ServerCapabilities: Codable, Hashable {
8181

8282
public var workspace: WorkspaceServerCapabilities?
8383

84+
/// Whether the server provides `textDocument/prepareCallHierarchy` and related
85+
/// call hierarchy requests.
86+
public var callHierarchyProvider: ValueOrBool<TextDocumentAndStaticRegistrationOptions>?
87+
8488
public var experimental: LSPAny?
8589

8690
public init(
@@ -107,6 +111,7 @@ public struct ServerCapabilities: Codable, Hashable {
107111
declarationProvider: ValueOrBool<TextDocumentAndStaticRegistrationOptions>? = nil,
108112
executeCommandProvider: ExecuteCommandOptions? = nil,
109113
workspace: WorkspaceServerCapabilities? = nil,
114+
callHierarchyProvider: ValueOrBool<TextDocumentAndStaticRegistrationOptions>? = nil,
110115
experimental: LSPAny? = nil
111116
)
112117
{
@@ -133,6 +138,7 @@ public struct ServerCapabilities: Codable, Hashable {
133138
self.declarationProvider = declarationProvider
134139
self.executeCommandProvider = executeCommandProvider
135140
self.workspace = workspace
141+
self.callHierarchyProvider = callHierarchyProvider
136142
self.experimental = experimental
137143
}
138144
}

Sources/LanguageServerProtocol/SupportTypes/SymbolKind.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,17 @@ public struct SymbolKind: RawRepresentable, Codable, Hashable {
5353
public static let `operator`: SymbolKind = SymbolKind(rawValue: 25)
5454
public static let typeParameter: SymbolKind = SymbolKind(rawValue: 26)
5555
}
56+
57+
/// Symbol tags are extra annotations that tweak the rendering of a symbol.
58+
///
59+
/// In LSP, this is an integer, so we don't use a closed set.
60+
public struct SymbolTag: RawRepresentable, Codable, Hashable {
61+
public var rawValue: Int
62+
63+
public init(rawValue: Int) {
64+
self.rawValue = rawValue
65+
}
66+
67+
/// Render a symbol as obsolete, usually using a strike-out.
68+
public static let deprecated: SymbolTag = SymbolTag(rawValue: 1)
69+
}

0 commit comments

Comments
 (0)