Skip to content

Implement local rename within the current file #990

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 12, 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
4 changes: 4 additions & 0 deletions Sources/LanguageServerProtocol/Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ extension ResponseError {
public static func unknown(_ message: String) -> ResponseError {
return ResponseError(code: .unknownErrorCode, message: message)
}

public static func internalError(_ message: String) -> ResponseError {
return ResponseError(code: .internalError, message: message)
}
}

/// An error during message decoding.
Expand Down
10 changes: 10 additions & 0 deletions Sources/SKSupport/LineTable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ extension LineTable {
return lineAndUTF16ColumnOf(content.utf8.index(content.startIndex, offsetBy: utf8Offset))
}

@inlinable func lineAndUTF8ColumnOf(utf8Offset: Int) -> (line: Int, utf8Column: Int)? {
guard let (line, utf16Column) = lineAndUTF16ColumnOf(utf8Offset: utf8Offset) else {
return nil
}
guard let utf8Column = utf8ColumnAt(line: line, utf16Column: utf16Column) else {
return nil
}
return (line, utf8Column)
}

/// Returns UTF16 column offset at UTF8 version of logical position.
///
/// - parameter line: Line number (zero-based).
Expand Down
4 changes: 4 additions & 0 deletions Sources/SourceKitD/SKDRequestArray.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ public final class SKDRequestArray {
public func append(_ value: String) {
sourcekitd.api.request_array_set_string(array, -1, value)
}

public func append(_ value: SKDRequestDictionary) {
sourcekitd.api.request_array_set_value(array, -1, value.dict)
}
}

extension SKDRequestArray: CustomStringConvertible {
Expand Down
68 changes: 62 additions & 6 deletions Sources/SourceKitD/sourcekitd_uids.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ public struct sourcekitd_keys {
public let actionuid: sourcekitd_uid_t
public let annotated_decl: sourcekitd_uid_t
public let annotations: sourcekitd_uid_t
public let argindex: sourcekitd_uid_t
public let associated_usrs: sourcekitd_uid_t
public let bodylength: sourcekitd_uid_t
public let bodyoffset: sourcekitd_uid_t
public let cancelOnSubsequentRequest: sourcekitd_uid_t
public let categories: sourcekitd_uid_t
public let categorizededits: sourcekitd_uid_t
public let categorizedranges: sourcekitd_uid_t
public let category: sourcekitd_uid_t
public let column: sourcekitd_uid_t
public let compilerargs: sourcekitd_uid_t
public let context: sourcekitd_uid_t
Expand All @@ -33,52 +36,76 @@ public struct sourcekitd_keys {
public let doc_full_as_xml: sourcekitd_uid_t
public let edits: sourcekitd_uid_t
public let educational_note_paths: sourcekitd_uid_t
public let enablesyntaxmap: sourcekitd_uid_t
public let endcolumn: sourcekitd_uid_t
public let endline: sourcekitd_uid_t
public let expression_length: sourcekitd_uid_t
public let expression_offset: sourcekitd_uid_t
public let expression_type: sourcekitd_uid_t
public let expression_type_list: sourcekitd_uid_t
public let expression_type: sourcekitd_uid_t
public let filepath: sourcekitd_uid_t
public let fixits: sourcekitd_uid_t
public let groupname: sourcekitd_uid_t
public let id: sourcekitd_uid_t
public let includeNonEditableBaseNames: 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
public let locations: sourcekitd_uid_t
public let modulename: sourcekitd_uid_t
public let name: sourcekitd_uid_t
public let namelength: sourcekitd_uid_t
public let nameoffset: sourcekitd_uid_t
public let nameType: sourcekitd_uid_t
public let not_recommended: sourcekitd_uid_t
public let notification: sourcekitd_uid_t
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 renamelocations: sourcekitd_uid_t
public let renameRangeBase: sourcekitd_uid_t
public let renameRangeCallArgColon: sourcekitd_uid_t
public let renameRangeCallArgCombined: sourcekitd_uid_t
public let renameRangeCallArgLabel: sourcekitd_uid_t
public let renameRangeDeclArgLabel: sourcekitd_uid_t
public let renameRangeKeywordBase: sourcekitd_uid_t
public let renameRangeNoncollapsibleParam: sourcekitd_uid_t
public let renameRangeParam: sourcekitd_uid_t
public let renameRangeSelectorArgLabel: sourcekitd_uid_t
public let request: sourcekitd_uid_t
public let results: sourcekitd_uid_t
public let retrieve_refactor_actions: sourcekitd_uid_t
public let semantic_tokens: sourcekitd_uid_t
public let severity: sourcekitd_uid_t
public let sourceEditKindActive: sourcekitd_uid_t
public let sourceEditKindComment: sourcekitd_uid_t
public let sourceEditKindInactive: sourcekitd_uid_t
public let sourceEditKindMismatch: sourcekitd_uid_t
public let sourceEditKindSelector: sourcekitd_uid_t
public let sourceEditKindString: sourcekitd_uid_t
public let sourceEditKindUnknown: sourcekitd_uid_t
public let sourcefile: sourcekitd_uid_t
public let sourcetext: sourcekitd_uid_t
public let substructure: sourcekitd_uid_t
public let syntactic_only: sourcekitd_uid_t
public let syntacticRenameCall: sourcekitd_uid_t
public let syntacticRenameDefinition: sourcekitd_uid_t
public let syntacticRenameReference: sourcekitd_uid_t
public let syntacticRenameUnknown: sourcekitd_uid_t
public let syntaxmap: sourcekitd_uid_t
public let synthesizedextensions: sourcekitd_uid_t
public let enablesyntaxmap: sourcekitd_uid_t
public let text: sourcekitd_uid_t
public let typename: sourcekitd_uid_t
public let usr: sourcekitd_uid_t
public let variable_offset: sourcekitd_uid_t
public let variable_length: sourcekitd_uid_t
public let variable_type: sourcekitd_uid_t
public let variable_offset: sourcekitd_uid_t
public let variable_type_explicit: sourcekitd_uid_t
public let variable_type_list: sourcekitd_uid_t
public let variable_type: sourcekitd_uid_t

// Code Completion options.
public let codecomplete_options: sourcekitd_uid_t
Expand All @@ -97,12 +124,15 @@ public struct sourcekitd_keys {
actionuid = api.uid_get_from_cstr("key.actionuid")!
annotated_decl = api.uid_get_from_cstr("key.annotated_decl")!
annotations = api.uid_get_from_cstr("key.annotations")!
argindex = api.uid_get_from_cstr("key.argindex")!
associated_usrs = api.uid_get_from_cstr("key.associated_usrs")!
bodylength = api.uid_get_from_cstr("key.bodylength")!
bodyoffset = api.uid_get_from_cstr("key.bodyoffset")!
cancelOnSubsequentRequest = api.uid_get_from_cstr("key.cancel_on_subsequent_request")!
categories = api.uid_get_from_cstr("key.categories")!
category = api.uid_get_from_cstr("key.category")!
categorizededits = api.uid_get_from_cstr("key.categorizededits")!
categorizedranges = api.uid_get_from_cstr("key.categorizedranges")!
column = api.uid_get_from_cstr("key.column")!
compilerargs = api.uid_get_from_cstr("key.compilerargs")!
context = api.uid_get_from_cstr("key.context")!
Expand All @@ -113,6 +143,7 @@ public struct sourcekitd_keys {
doc_full_as_xml = api.uid_get_from_cstr("key.doc.full_as_xml")!
edits = api.uid_get_from_cstr("key.edits")!
educational_note_paths = api.uid_get_from_cstr("key.educational_note_paths")!
enablesyntaxmap = api.uid_get_from_cstr("key.enablesyntaxmap")!
endcolumn = api.uid_get_from_cstr("key.endcolumn")!
endline = api.uid_get_from_cstr("key.endline")!
expression_length = api.uid_get_from_cstr("key.expression_length")!
Expand All @@ -123,39 +154,62 @@ public struct sourcekitd_keys {
fixits = api.uid_get_from_cstr("key.fixits")!
groupname = api.uid_get_from_cstr("key.groupname")!
id = api.uid_get_from_cstr("key.id")!
includeNonEditableBaseNames = api.uid_get_from_cstr("key.include_non_editable_base_names")!
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")!
locations = api.uid_get_from_cstr("key.locations")!
modulename = api.uid_get_from_cstr("key.modulename")!
name = api.uid_get_from_cstr("key.name")!
namelength = api.uid_get_from_cstr("key.namelength")!
nameoffset = api.uid_get_from_cstr("key.nameoffset")!
nameType = api.uid_get_from_cstr("key.nametype")!
not_recommended = api.uid_get_from_cstr("key.not_recommended")!
notification = api.uid_get_from_cstr("key.notification")!
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")!
renamelocations = api.uid_get_from_cstr("key.renamelocations")!
renameRangeBase = api.uid_get_from_cstr("source.refactoring.range.kind.basename")!
renameRangeCallArgColon = api.uid_get_from_cstr("source.refactoring.range.kind.call-argument-colon")!
renameRangeCallArgCombined = api.uid_get_from_cstr("source.refactoring.range.kind.call-argument-combined")!
renameRangeCallArgLabel = api.uid_get_from_cstr("source.refactoring.range.kind.call-argument-label")!
renameRangeDeclArgLabel = api.uid_get_from_cstr("source.refactoring.range.kind.decl-argument-label")!
renameRangeKeywordBase = api.uid_get_from_cstr("source.refactoring.range.kind.keyword-basename")!
renameRangeNoncollapsibleParam = api.uid_get_from_cstr("source.refactoring.range.kind.noncollapsible-parameter")!
renameRangeParam = api.uid_get_from_cstr("source.refactoring.range.kind.parameter-and-whitespace")!
renameRangeSelectorArgLabel = api.uid_get_from_cstr("source.refactoring.range.kind.selector-argument-label")!
request = api.uid_get_from_cstr("key.request")!
results = api.uid_get_from_cstr("key.results")!
retrieve_refactor_actions = api.uid_get_from_cstr("key.retrieve_refactor_actions")!
semantic_tokens = api.uid_get_from_cstr("key.semantic_tokens")!
severity = api.uid_get_from_cstr("key.severity")!
sourceEditKindActive = api.uid_get_from_cstr("source.edit.kind.active")!
sourceEditKindComment = api.uid_get_from_cstr("source.edit.kind.comment")!
sourceEditKindInactive = api.uid_get_from_cstr("source.edit.kind.inactive")!
sourceEditKindMismatch = api.uid_get_from_cstr("source.edit.kind.mismatch")!
sourceEditKindSelector = api.uid_get_from_cstr("source.edit.kind.selector")!
sourceEditKindString = api.uid_get_from_cstr("source.edit.kind.string")!
sourceEditKindUnknown = api.uid_get_from_cstr("source.edit.kind.unknown")!
sourcefile = api.uid_get_from_cstr("key.sourcefile")!
sourcetext = api.uid_get_from_cstr("key.sourcetext")!
substructure = api.uid_get_from_cstr("key.substructure")!
syntactic_only = api.uid_get_from_cstr("key.syntactic_only")!
syntacticRenameCall = api.uid_get_from_cstr("source.syntacticrename.call")!
syntacticRenameDefinition = api.uid_get_from_cstr("source.syntacticrename.definition")!
syntacticRenameReference = api.uid_get_from_cstr("source.syntacticrename.reference")!
syntacticRenameUnknown = api.uid_get_from_cstr("source.syntacticrename.unknown")!
syntaxmap = api.uid_get_from_cstr("key.syntaxmap")!
enablesyntaxmap = api.uid_get_from_cstr("key.enablesyntaxmap")!
synthesizedextensions = api.uid_get_from_cstr("key.synthesizedextensions")!
text = api.uid_get_from_cstr("key.text")!
typename = api.uid_get_from_cstr("key.typename")!
usr = api.uid_get_from_cstr("key.usr")!
variable_offset = api.uid_get_from_cstr("key.variable_offset")!
variable_length = api.uid_get_from_cstr("key.variable_length")!
variable_offset = api.uid_get_from_cstr("key.variable_offset")!
variable_type = api.uid_get_from_cstr("key.variable_type")!
variable_type_explicit = api.uid_get_from_cstr("key.variable_type_explicit")!
variable_type_list = api.uid_get_from_cstr("key.variable_type_list")!
Expand Down Expand Up @@ -192,6 +246,7 @@ public struct sourcekitd_requests {
public let variable_type: sourcekitd_uid_t
public let relatedidents: sourcekitd_uid_t
public let semantic_refactoring: sourcekitd_uid_t
public let find_syntactic_rename_ranges: sourcekitd_uid_t

public init(api: sourcekitd_functions_t) {
crash_exit = api.uid_get_from_cstr("source.request.crash_exit")!
Expand All @@ -211,6 +266,7 @@ public struct sourcekitd_requests {
variable_type = api.uid_get_from_cstr("source.request.variable.type")!
relatedidents = api.uid_get_from_cstr("source.request.relatedidents")!
semantic_refactoring = api.uid_get_from_cstr("source.request.semantic.refactoring")!
find_syntactic_rename_ranges = api.uid_get_from_cstr("source.request.find-syntactic-rename-ranges")!
}
}

Expand Down
2 changes: 2 additions & 0 deletions Sources/SourceKitLSP/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ target_sources(SourceKitLSP PRIVATE
Swift/DocumentSymbols.swift
Swift/EditorPlaceholder.swift
Swift/OpenInterface.swift
Swift/RelatedIdentifiers.swift
Swift/Rename.swift
Swift/SemanticRefactorCommand.swift
Swift/SemanticRefactoring.swift
Swift/SemanticTokens.swift
Expand Down
4 changes: 4 additions & 0 deletions Sources/SourceKitLSP/Clang/ClangLanguageServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,10 @@ extension ClangLanguageServerShim {
func executeCommand(_ req: ExecuteCommandRequest) async throws -> LSPAny? {
return try await forwardRequestToClangd(req)
}

func rename(_ request: RenameRequest) async throws -> WorkspaceEdit? {
return try await forwardRequestToClangd(request)
}
}

/// Clang build settings derived from a `FileBuildSettingsChange`.
Expand Down
19 changes: 18 additions & 1 deletion Sources/SourceKitLSP/SourceKitServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,10 @@ fileprivate enum TaskMetadata: DependencyTracker {
self = .freestanding
case is PollIndexRequest:
self = .globalConfigurationChange
case is RenameRequest:
// Rename might touch multiple files. Make it a global configuration change so that edits to all files that might
// be affected have been processed.
self = .globalConfigurationChange
case is RegisterCapabilityRequest:
self = .globalConfigurationChange
case is ShowMessageRequest:
Expand Down Expand Up @@ -339,7 +343,7 @@ fileprivate enum TaskMetadata: DependencyTracker {
default:
logger.error(
"""
Unknown request \(type(of: request)). Treating as a freestanding notification. \
Unknown request \(type(of: request)). Treating as a freestanding request. \
This might lead to out-of-order request handling
"""
)
Expand Down Expand Up @@ -851,6 +855,8 @@ extension SourceKitServer: MessageHandler {
await request.reply { try await supertypes(request.params) }
case let request as RequestAndReply<TypeHierarchySubtypesRequest>:
await request.reply { try await subtypes(request.params) }
case let request as RequestAndReply<RenameRequest>:
await request.reply { try await rename(request.params) }
case let request as RequestAndReply<CompletionRequest>:
await self.handleRequest(for: request, requestHandler: self.completion)
case let request as RequestAndReply<HoverRequest>:
Expand Down Expand Up @@ -1645,6 +1651,17 @@ extension SourceKitServer {
return try await languageService.executeCommand(executeCommand)
}

func rename(_ request: RenameRequest) async throws -> WorkspaceEdit? {
let uri = request.textDocument.uri
guard let workspace = await workspaceForDocument(uri: uri) else {
throw ResponseError.workspaceNotOpen(uri)
}
guard let languageService = workspace.documentService[uri] else {
return nil
}
return try await languageService.rename(request)
}

func codeAction(
_ req: CodeActionRequest,
workspace: Workspace,
Expand Down
Loading