Skip to content

Commit 052997a

Browse files
committed
Address stylistic review comments from #990
1 parent 997ef38 commit 052997a

File tree

1 file changed

+78
-64
lines changed

1 file changed

+78
-64
lines changed

Sources/SourceKitLSP/Rename.swift

Lines changed: 78 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,19 @@ fileprivate struct CompoundDeclName {
4040
/// The parameter of a compound decl name, which can either be the parameter's name or `_` to indicate that the
4141
/// parameter is unnamed.
4242
enum Parameter: Equatable {
43-
case label(String)
43+
case named(String)
4444
case wildcard
4545

4646
var stringOrWildcard: String {
4747
switch self {
48-
case .label(let str): return str
48+
case .named(let str): return str
4949
case .wildcard: return "_"
5050
}
5151
}
5252

5353
var stringOrEmpty: String {
5454
switch self {
55-
case .label(let str): return str
55+
case .named(let str): return str
5656
case .wildcard: return ""
5757
}
5858
}
@@ -83,7 +83,7 @@ fileprivate struct CompoundDeclName {
8383
parameters = parameterStrings.map {
8484
switch $0 {
8585
case "", "_": return .wildcard
86-
default: return .label(String($0))
86+
default: return .named(String($0))
8787
}
8888
}
8989
}
@@ -434,18 +434,19 @@ extension SwiftLanguageServer {
434434
public func rename(_ request: RenameRequest) async throws -> (edits: WorkspaceEdit, usr: String?, oldName: String?) {
435435
let snapshot = try self.documentManager.latestSnapshot(request.textDocument.uri)
436436

437-
let relatedIdentifiers = try await self.relatedIdentifiers(
437+
let relatedIdentifiersResponse = try await self.relatedIdentifiers(
438438
at: request.position,
439439
in: snapshot,
440440
includeNonEditableBaseNames: true
441441
)
442-
guard let oldName = relatedIdentifiers.name else {
442+
guard let oldName = relatedIdentifiersResponse.name else {
443443
throw ResponseError.unknown("Running sourcekit-lsp with a version of sourcekitd that does not support rename")
444444
}
445445

446446
try Task.checkCancellation()
447447

448-
let renameLocations = relatedIdentifiers.relatedIdentifiers.compactMap { (relatedIdentifier) -> RenameLocation? in
448+
let renameLocations = relatedIdentifiersResponse.relatedIdentifiers.compactMap {
449+
(relatedIdentifier) -> RenameLocation? in
449450
let position = relatedIdentifier.range.lowerBound
450451
guard let utf8Column = snapshot.lineTable.utf8ColumnAt(line: position.line, utf16Column: position.utf16index)
451452
else {
@@ -473,6 +474,69 @@ extension SwiftLanguageServer {
473474
return (edits: WorkspaceEdit(changes: [snapshot.uri: edits]), usr: usr, oldName: oldName)
474475
}
475476

477+
/// Return the edit that needs to be performed for the given syntactic rename piece to rename it from
478+
/// `oldParameter` to `newParameter`.
479+
/// Returns `nil` if no edit needs to be performed.
480+
private func textEdit(
481+
for piece: SyntacticRenamePiece,
482+
in snapshot: DocumentSnapshot,
483+
oldParameter: CompoundDeclName.Parameter,
484+
newParameter: CompoundDeclName.Parameter
485+
) -> TextEdit? {
486+
switch piece.kind {
487+
case .parameterName:
488+
if newParameter == .wildcard, piece.range.isEmpty, case .named(let oldParameterName) = oldParameter {
489+
// We are changing a named parameter to an unnamed one. If the parameter didn't have an internal parameter
490+
// name, we need to transfer the previously external parameter name to be the internal one.
491+
// E.g. `func foo(a: Int)` becomes `func foo(_ a: Int)`.
492+
return TextEdit(range: piece.range, newText: " " + oldParameterName)
493+
}
494+
if let original = snapshot.lineTable[piece.range],
495+
case .named(let newParameterLabel) = newParameter,
496+
newParameterLabel.trimmingCharacters(in: .whitespaces) == original.trimmingCharacters(in: .whitespaces)
497+
{
498+
// We are changing the external parameter name to be the same one as the internal parameter name. The
499+
// internal name is thus no longer needed. Drop it.
500+
// Eg. an old declaration `func foo(_ a: Int)` becomes `func foo(a: Int)` when renaming the parameter to `a`
501+
return TextEdit(range: piece.range, newText: "")
502+
}
503+
// In all other cases, don't touch the internal parameter name. It's not part of the public API.
504+
return nil
505+
case .noncollapsibleParameterName:
506+
// Noncollapsible parameter names should never be renamed because they are the same as `parameterName` but
507+
// never fall into one of the two categories above.
508+
return nil
509+
case .declArgumentLabel:
510+
if piece.range.isEmpty {
511+
// If we are inserting a new external argument label where there wasn't one before, add a space after it to
512+
// separate it from the internal name.
513+
// E.g. `subscript(a: Int)` becomes `subscript(a a: Int)`.
514+
return TextEdit(range: piece.range, newText: newParameter.stringOrWildcard + " ")
515+
}
516+
// Otherwise, just update the name.
517+
return TextEdit(range: piece.range, newText: newParameter.stringOrWildcard)
518+
case .callArgumentLabel:
519+
// Argument labels of calls are just updated.
520+
return TextEdit(range: piece.range, newText: newParameter.stringOrEmpty)
521+
case .callArgumentColon:
522+
if case .wildcard = newParameter {
523+
// If the parameter becomes unnamed, remove the colon after the argument name.
524+
return TextEdit(range: piece.range, newText: "")
525+
}
526+
return nil
527+
case .callArgumentCombined:
528+
if case .named(let newParameterName) = newParameter {
529+
// If an unnamed parameter becomes named, insert the new name and a colon.
530+
return TextEdit(range: piece.range, newText: newParameterName + ": ")
531+
}
532+
return nil
533+
case .selectorArgumentLabel:
534+
return TextEdit(range: piece.range, newText: newParameter.stringOrWildcard)
535+
case .baseName, .keywordBaseName:
536+
preconditionFailure("Handled above")
537+
}
538+
}
539+
476540
public func editsToRename(
477541
locations renameLocations: [RenameLocation],
478542
in snapshot: DocumentSnapshot,
@@ -520,63 +584,13 @@ extension SwiftLanguageServer {
520584
// renaming `func foo(a: Int, b: Int)` and the user specified `bar(x:)` as the new name.
521585
return nil
522586
}
523-
let newParameterName = newName.parameters[parameterIndex]
524-
let oldParameterName = oldName.parameters[parameterIndex]
525-
switch piece.kind {
526-
case .parameterName:
527-
if newParameterName == .wildcard, piece.range.isEmpty, case .label(let oldParameterLabel) = oldParameterName {
528-
// We are changing a named parameter to an unnamed one. If the parameter didn't have an internal parameter
529-
// name, we need to transfer the previously external parameter name to be the internal one.
530-
// E.g. `func foo(a: Int)` becomes `func foo(_ a: Int)`.
531-
return TextEdit(range: piece.range, newText: " " + oldParameterLabel)
532-
} else if let original = snapshot.lineTable[piece.range],
533-
case .label(let newParameterLabel) = newParameterName,
534-
newParameterLabel.trimmingCharacters(in: .whitespaces) == original.trimmingCharacters(in: .whitespaces)
535-
{
536-
// We are changing the external parameter name to be the same one as the internal parameter name. The
537-
// internal name is thus no longer needed. Drop it.
538-
// Eg. an old declaration `func foo(_ a: Int)` becomes `func foo(a: Int)` when renaming the parameter to `a`
539-
return TextEdit(range: piece.range, newText: "")
540-
} else {
541-
// In all other cases, don't touch the internal parameter name. It's not part of the public API.
542-
return nil
543-
}
544-
case .noncollapsibleParameterName:
545-
// Noncollapsible parameter names should never be renamed because they are the same as `parameterName` but
546-
// never fall into one of the two categories above.
547-
return nil
548-
case .declArgumentLabel:
549-
if piece.range.isEmpty {
550-
// If we are inserting a new external argument label where there wasn't one before, add a space after it to
551-
// separate it from the internal name.
552-
// E.g. `subscript(a: Int)` becomes `subscript(a a: Int)`.
553-
return TextEdit(range: piece.range, newText: newParameterName.stringOrWildcard + " ")
554-
} else {
555-
// Otherwise, just update the name.
556-
return TextEdit(range: piece.range, newText: newParameterName.stringOrWildcard)
557-
}
558-
case .callArgumentLabel:
559-
// Argument labels of calls are just updated.
560-
return TextEdit(range: piece.range, newText: newParameterName.stringOrEmpty)
561-
case .callArgumentColon:
562-
if case .wildcard = newParameterName {
563-
// If the parameter becomes unnamed, remove the colon after the argument name.
564-
return TextEdit(range: piece.range, newText: "")
565-
} else {
566-
return nil
567-
}
568-
case .callArgumentCombined:
569-
if case .label(let newParameterLabel) = newParameterName {
570-
// If an unnamed parameter becomes named, insert the new name and a colon.
571-
return TextEdit(range: piece.range, newText: newParameterLabel + ": ")
572-
} else {
573-
return nil
574-
}
575-
case .selectorArgumentLabel:
576-
return TextEdit(range: piece.range, newText: newParameterName.stringOrWildcard)
577-
case .baseName, .keywordBaseName:
578-
preconditionFailure("Handled above")
579-
}
587+
588+
return self.textEdit(
589+
for: piece,
590+
in: snapshot,
591+
oldParameter: oldName.parameters[parameterIndex],
592+
newParameter: newName.parameters[parameterIndex]
593+
)
580594
}
581595
}
582596
}

0 commit comments

Comments
 (0)