Skip to content

Commit ce9fdf9

Browse files
authored
Merge pull request #990 from ahoppen/ahoppen/rename
Implement local rename within the current file
2 parents 4f3bdf9 + 6b5842f commit ce9fdf9

File tree

12 files changed

+1179
-49
lines changed

12 files changed

+1179
-49
lines changed

Sources/LanguageServerProtocol/Error.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ extension ResponseError {
118118
public static func unknown(_ message: String) -> ResponseError {
119119
return ResponseError(code: .unknownErrorCode, message: message)
120120
}
121+
122+
public static func internalError(_ message: String) -> ResponseError {
123+
return ResponseError(code: .internalError, message: message)
124+
}
121125
}
122126

123127
/// An error during message decoding.

Sources/SKSupport/LineTable.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,16 @@ extension LineTable {
166166
return lineAndUTF16ColumnOf(content.utf8.index(content.startIndex, offsetBy: utf8Offset))
167167
}
168168

169+
@inlinable func lineAndUTF8ColumnOf(utf8Offset: Int) -> (line: Int, utf8Column: Int)? {
170+
guard let (line, utf16Column) = lineAndUTF16ColumnOf(utf8Offset: utf8Offset) else {
171+
return nil
172+
}
173+
guard let utf8Column = utf8ColumnAt(line: line, utf16Column: utf16Column) else {
174+
return nil
175+
}
176+
return (line, utf8Column)
177+
}
178+
169179
/// Returns UTF16 column offset at UTF8 version of logical position.
170180
///
171181
/// - parameter line: Line number (zero-based).

Sources/SourceKitD/SKDRequestArray.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ public final class SKDRequestArray {
3636
public func append(_ value: String) {
3737
sourcekitd.api.request_array_set_string(array, -1, value)
3838
}
39+
40+
public func append(_ value: SKDRequestDictionary) {
41+
sourcekitd.api.request_array_set_value(array, -1, value.dict)
42+
}
3943
}
4044

4145
extension SKDRequestArray: CustomStringConvertible {

Sources/SourceKitD/sourcekitd_uids.swift

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ public struct sourcekitd_keys {
1717
public let actionuid: sourcekitd_uid_t
1818
public let annotated_decl: sourcekitd_uid_t
1919
public let annotations: sourcekitd_uid_t
20+
public let argindex: sourcekitd_uid_t
2021
public let associated_usrs: sourcekitd_uid_t
2122
public let bodylength: sourcekitd_uid_t
2223
public let bodyoffset: sourcekitd_uid_t
2324
public let cancelOnSubsequentRequest: sourcekitd_uid_t
2425
public let categories: sourcekitd_uid_t
2526
public let categorizededits: sourcekitd_uid_t
27+
public let categorizedranges: sourcekitd_uid_t
28+
public let category: sourcekitd_uid_t
2629
public let column: sourcekitd_uid_t
2730
public let compilerargs: sourcekitd_uid_t
2831
public let context: sourcekitd_uid_t
@@ -33,52 +36,76 @@ public struct sourcekitd_keys {
3336
public let doc_full_as_xml: sourcekitd_uid_t
3437
public let edits: sourcekitd_uid_t
3538
public let educational_note_paths: sourcekitd_uid_t
39+
public let enablesyntaxmap: sourcekitd_uid_t
3640
public let endcolumn: sourcekitd_uid_t
3741
public let endline: sourcekitd_uid_t
3842
public let expression_length: sourcekitd_uid_t
3943
public let expression_offset: sourcekitd_uid_t
40-
public let expression_type: sourcekitd_uid_t
4144
public let expression_type_list: sourcekitd_uid_t
45+
public let expression_type: sourcekitd_uid_t
4246
public let filepath: sourcekitd_uid_t
4347
public let fixits: sourcekitd_uid_t
4448
public let groupname: sourcekitd_uid_t
4549
public let id: sourcekitd_uid_t
50+
public let includeNonEditableBaseNames: sourcekitd_uid_t
4651
public let is_system: sourcekitd_uid_t
4752
public let isDynamic: sourcekitd_uid_t
4853
public let kind: sourcekitd_uid_t
4954
public let length: sourcekitd_uid_t
5055
public let line: sourcekitd_uid_t
56+
public let locations: sourcekitd_uid_t
5157
public let modulename: sourcekitd_uid_t
5258
public let name: sourcekitd_uid_t
5359
public let namelength: sourcekitd_uid_t
5460
public let nameoffset: sourcekitd_uid_t
61+
public let nameType: sourcekitd_uid_t
5562
public let not_recommended: sourcekitd_uid_t
5663
public let notification: sourcekitd_uid_t
5764
public let num_bytes_to_erase: sourcekitd_uid_t
5865
public let offset: sourcekitd_uid_t
5966
public let ranges: sourcekitd_uid_t
6067
public let receivers: sourcekitd_uid_t
6168
public let refactor_actions: sourcekitd_uid_t
69+
public let renamelocations: sourcekitd_uid_t
70+
public let renameRangeBase: sourcekitd_uid_t
71+
public let renameRangeCallArgColon: sourcekitd_uid_t
72+
public let renameRangeCallArgCombined: sourcekitd_uid_t
73+
public let renameRangeCallArgLabel: sourcekitd_uid_t
74+
public let renameRangeDeclArgLabel: sourcekitd_uid_t
75+
public let renameRangeKeywordBase: sourcekitd_uid_t
76+
public let renameRangeNoncollapsibleParam: sourcekitd_uid_t
77+
public let renameRangeParam: sourcekitd_uid_t
78+
public let renameRangeSelectorArgLabel: sourcekitd_uid_t
6279
public let request: sourcekitd_uid_t
6380
public let results: sourcekitd_uid_t
6481
public let retrieve_refactor_actions: sourcekitd_uid_t
6582
public let semantic_tokens: sourcekitd_uid_t
6683
public let severity: sourcekitd_uid_t
84+
public let sourceEditKindActive: sourcekitd_uid_t
85+
public let sourceEditKindComment: sourcekitd_uid_t
86+
public let sourceEditKindInactive: sourcekitd_uid_t
87+
public let sourceEditKindMismatch: sourcekitd_uid_t
88+
public let sourceEditKindSelector: sourcekitd_uid_t
89+
public let sourceEditKindString: sourcekitd_uid_t
90+
public let sourceEditKindUnknown: sourcekitd_uid_t
6791
public let sourcefile: sourcekitd_uid_t
6892
public let sourcetext: sourcekitd_uid_t
6993
public let substructure: sourcekitd_uid_t
7094
public let syntactic_only: sourcekitd_uid_t
95+
public let syntacticRenameCall: sourcekitd_uid_t
96+
public let syntacticRenameDefinition: sourcekitd_uid_t
97+
public let syntacticRenameReference: sourcekitd_uid_t
98+
public let syntacticRenameUnknown: sourcekitd_uid_t
7199
public let syntaxmap: sourcekitd_uid_t
72100
public let synthesizedextensions: sourcekitd_uid_t
73-
public let enablesyntaxmap: sourcekitd_uid_t
74101
public let text: sourcekitd_uid_t
75102
public let typename: sourcekitd_uid_t
76103
public let usr: sourcekitd_uid_t
77-
public let variable_offset: sourcekitd_uid_t
78104
public let variable_length: sourcekitd_uid_t
79-
public let variable_type: sourcekitd_uid_t
105+
public let variable_offset: sourcekitd_uid_t
80106
public let variable_type_explicit: sourcekitd_uid_t
81107
public let variable_type_list: sourcekitd_uid_t
108+
public let variable_type: sourcekitd_uid_t
82109

83110
// Code Completion options.
84111
public let codecomplete_options: sourcekitd_uid_t
@@ -97,12 +124,15 @@ public struct sourcekitd_keys {
97124
actionuid = api.uid_get_from_cstr("key.actionuid")!
98125
annotated_decl = api.uid_get_from_cstr("key.annotated_decl")!
99126
annotations = api.uid_get_from_cstr("key.annotations")!
127+
argindex = api.uid_get_from_cstr("key.argindex")!
100128
associated_usrs = api.uid_get_from_cstr("key.associated_usrs")!
101129
bodylength = api.uid_get_from_cstr("key.bodylength")!
102130
bodyoffset = api.uid_get_from_cstr("key.bodyoffset")!
103131
cancelOnSubsequentRequest = api.uid_get_from_cstr("key.cancel_on_subsequent_request")!
104132
categories = api.uid_get_from_cstr("key.categories")!
133+
category = api.uid_get_from_cstr("key.category")!
105134
categorizededits = api.uid_get_from_cstr("key.categorizededits")!
135+
categorizedranges = api.uid_get_from_cstr("key.categorizedranges")!
106136
column = api.uid_get_from_cstr("key.column")!
107137
compilerargs = api.uid_get_from_cstr("key.compilerargs")!
108138
context = api.uid_get_from_cstr("key.context")!
@@ -113,6 +143,7 @@ public struct sourcekitd_keys {
113143
doc_full_as_xml = api.uid_get_from_cstr("key.doc.full_as_xml")!
114144
edits = api.uid_get_from_cstr("key.edits")!
115145
educational_note_paths = api.uid_get_from_cstr("key.educational_note_paths")!
146+
enablesyntaxmap = api.uid_get_from_cstr("key.enablesyntaxmap")!
116147
endcolumn = api.uid_get_from_cstr("key.endcolumn")!
117148
endline = api.uid_get_from_cstr("key.endline")!
118149
expression_length = api.uid_get_from_cstr("key.expression_length")!
@@ -123,39 +154,62 @@ public struct sourcekitd_keys {
123154
fixits = api.uid_get_from_cstr("key.fixits")!
124155
groupname = api.uid_get_from_cstr("key.groupname")!
125156
id = api.uid_get_from_cstr("key.id")!
157+
includeNonEditableBaseNames = api.uid_get_from_cstr("key.include_non_editable_base_names")!
126158
is_system = api.uid_get_from_cstr("key.is_system")!
127159
isDynamic = api.uid_get_from_cstr("key.is_dynamic")!
128160
kind = api.uid_get_from_cstr("key.kind")!
129161
length = api.uid_get_from_cstr("key.length")!
130162
line = api.uid_get_from_cstr("key.line")!
163+
locations = api.uid_get_from_cstr("key.locations")!
131164
modulename = api.uid_get_from_cstr("key.modulename")!
132165
name = api.uid_get_from_cstr("key.name")!
133166
namelength = api.uid_get_from_cstr("key.namelength")!
134167
nameoffset = api.uid_get_from_cstr("key.nameoffset")!
168+
nameType = api.uid_get_from_cstr("key.nametype")!
135169
not_recommended = api.uid_get_from_cstr("key.not_recommended")!
136170
notification = api.uid_get_from_cstr("key.notification")!
137171
num_bytes_to_erase = api.uid_get_from_cstr("key.num_bytes_to_erase")!
138172
offset = api.uid_get_from_cstr("key.offset")!
139173
ranges = api.uid_get_from_cstr("key.ranges")!
140174
receivers = api.uid_get_from_cstr("key.receivers")!
141175
refactor_actions = api.uid_get_from_cstr("key.refactor_actions")!
176+
renamelocations = api.uid_get_from_cstr("key.renamelocations")!
177+
renameRangeBase = api.uid_get_from_cstr("source.refactoring.range.kind.basename")!
178+
renameRangeCallArgColon = api.uid_get_from_cstr("source.refactoring.range.kind.call-argument-colon")!
179+
renameRangeCallArgCombined = api.uid_get_from_cstr("source.refactoring.range.kind.call-argument-combined")!
180+
renameRangeCallArgLabel = api.uid_get_from_cstr("source.refactoring.range.kind.call-argument-label")!
181+
renameRangeDeclArgLabel = api.uid_get_from_cstr("source.refactoring.range.kind.decl-argument-label")!
182+
renameRangeKeywordBase = api.uid_get_from_cstr("source.refactoring.range.kind.keyword-basename")!
183+
renameRangeNoncollapsibleParam = api.uid_get_from_cstr("source.refactoring.range.kind.noncollapsible-parameter")!
184+
renameRangeParam = api.uid_get_from_cstr("source.refactoring.range.kind.parameter-and-whitespace")!
185+
renameRangeSelectorArgLabel = api.uid_get_from_cstr("source.refactoring.range.kind.selector-argument-label")!
142186
request = api.uid_get_from_cstr("key.request")!
143187
results = api.uid_get_from_cstr("key.results")!
144188
retrieve_refactor_actions = api.uid_get_from_cstr("key.retrieve_refactor_actions")!
145189
semantic_tokens = api.uid_get_from_cstr("key.semantic_tokens")!
146190
severity = api.uid_get_from_cstr("key.severity")!
191+
sourceEditKindActive = api.uid_get_from_cstr("source.edit.kind.active")!
192+
sourceEditKindComment = api.uid_get_from_cstr("source.edit.kind.comment")!
193+
sourceEditKindInactive = api.uid_get_from_cstr("source.edit.kind.inactive")!
194+
sourceEditKindMismatch = api.uid_get_from_cstr("source.edit.kind.mismatch")!
195+
sourceEditKindSelector = api.uid_get_from_cstr("source.edit.kind.selector")!
196+
sourceEditKindString = api.uid_get_from_cstr("source.edit.kind.string")!
197+
sourceEditKindUnknown = api.uid_get_from_cstr("source.edit.kind.unknown")!
147198
sourcefile = api.uid_get_from_cstr("key.sourcefile")!
148199
sourcetext = api.uid_get_from_cstr("key.sourcetext")!
149200
substructure = api.uid_get_from_cstr("key.substructure")!
150201
syntactic_only = api.uid_get_from_cstr("key.syntactic_only")!
202+
syntacticRenameCall = api.uid_get_from_cstr("source.syntacticrename.call")!
203+
syntacticRenameDefinition = api.uid_get_from_cstr("source.syntacticrename.definition")!
204+
syntacticRenameReference = api.uid_get_from_cstr("source.syntacticrename.reference")!
205+
syntacticRenameUnknown = api.uid_get_from_cstr("source.syntacticrename.unknown")!
151206
syntaxmap = api.uid_get_from_cstr("key.syntaxmap")!
152-
enablesyntaxmap = api.uid_get_from_cstr("key.enablesyntaxmap")!
153207
synthesizedextensions = api.uid_get_from_cstr("key.synthesizedextensions")!
154208
text = api.uid_get_from_cstr("key.text")!
155209
typename = api.uid_get_from_cstr("key.typename")!
156210
usr = api.uid_get_from_cstr("key.usr")!
157-
variable_offset = api.uid_get_from_cstr("key.variable_offset")!
158211
variable_length = api.uid_get_from_cstr("key.variable_length")!
212+
variable_offset = api.uid_get_from_cstr("key.variable_offset")!
159213
variable_type = api.uid_get_from_cstr("key.variable_type")!
160214
variable_type_explicit = api.uid_get_from_cstr("key.variable_type_explicit")!
161215
variable_type_list = api.uid_get_from_cstr("key.variable_type_list")!
@@ -192,6 +246,7 @@ public struct sourcekitd_requests {
192246
public let variable_type: sourcekitd_uid_t
193247
public let relatedidents: sourcekitd_uid_t
194248
public let semantic_refactoring: sourcekitd_uid_t
249+
public let find_syntactic_rename_ranges: sourcekitd_uid_t
195250

196251
public init(api: sourcekitd_functions_t) {
197252
crash_exit = api.uid_get_from_cstr("source.request.crash_exit")!
@@ -211,6 +266,7 @@ public struct sourcekitd_requests {
211266
variable_type = api.uid_get_from_cstr("source.request.variable.type")!
212267
relatedidents = api.uid_get_from_cstr("source.request.relatedidents")!
213268
semantic_refactoring = api.uid_get_from_cstr("source.request.semantic.refactoring")!
269+
find_syntactic_rename_ranges = api.uid_get_from_cstr("source.request.find-syntactic-rename-ranges")!
214270
}
215271
}
216272

Sources/SourceKitLSP/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ target_sources(SourceKitLSP PRIVATE
2424
Swift/DocumentSymbols.swift
2525
Swift/EditorPlaceholder.swift
2626
Swift/OpenInterface.swift
27+
Swift/RelatedIdentifiers.swift
28+
Swift/Rename.swift
2729
Swift/SemanticRefactorCommand.swift
2830
Swift/SemanticRefactoring.swift
2931
Swift/SemanticTokens.swift

Sources/SourceKitLSP/Clang/ClangLanguageServer.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,10 @@ extension ClangLanguageServerShim {
597597
func executeCommand(_ req: ExecuteCommandRequest) async throws -> LSPAny? {
598598
return try await forwardRequestToClangd(req)
599599
}
600+
601+
func rename(_ request: RenameRequest) async throws -> WorkspaceEdit? {
602+
return try await forwardRequestToClangd(request)
603+
}
600604
}
601605

602606
/// Clang build settings derived from a `FileBuildSettingsChange`.

Sources/SourceKitLSP/SourceKitServer.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ fileprivate enum TaskMetadata: DependencyTracker {
308308
self = .freestanding
309309
case is PollIndexRequest:
310310
self = .globalConfigurationChange
311+
case is RenameRequest:
312+
// Rename might touch multiple files. Make it a global configuration change so that edits to all files that might
313+
// be affected have been processed.
314+
self = .globalConfigurationChange
311315
case is RegisterCapabilityRequest:
312316
self = .globalConfigurationChange
313317
case is ShowMessageRequest:
@@ -341,7 +345,7 @@ fileprivate enum TaskMetadata: DependencyTracker {
341345
default:
342346
logger.error(
343347
"""
344-
Unknown request \(type(of: request)). Treating as a freestanding notification. \
348+
Unknown request \(type(of: request)). Treating as a freestanding request. \
345349
This might lead to out-of-order request handling
346350
"""
347351
)
@@ -857,6 +861,8 @@ extension SourceKitServer: MessageHandler {
857861
await request.reply { try await supertypes(request.params) }
858862
case let request as RequestAndReply<TypeHierarchySubtypesRequest>:
859863
await request.reply { try await subtypes(request.params) }
864+
case let request as RequestAndReply<RenameRequest>:
865+
await request.reply { try await rename(request.params) }
860866
case let request as RequestAndReply<CompletionRequest>:
861867
await self.handleRequest(for: request, requestHandler: self.completion)
862868
case let request as RequestAndReply<HoverRequest>:
@@ -1628,6 +1634,17 @@ extension SourceKitServer {
16281634
return try await languageService.executeCommand(executeCommand)
16291635
}
16301636

1637+
func rename(_ request: RenameRequest) async throws -> WorkspaceEdit? {
1638+
let uri = request.textDocument.uri
1639+
guard let workspace = await workspaceForDocument(uri: uri) else {
1640+
throw ResponseError.workspaceNotOpen(uri)
1641+
}
1642+
guard let languageService = workspace.documentService[uri] else {
1643+
return nil
1644+
}
1645+
return try await languageService.rename(request)
1646+
}
1647+
16311648
func codeAction(
16321649
_ req: CodeActionRequest,
16331650
workspace: Workspace,

0 commit comments

Comments
 (0)