@@ -40,19 +40,19 @@ fileprivate struct CompoundDeclName {
40
40
/// The parameter of a compound decl name, which can either be the parameter's name or `_` to indicate that the
41
41
/// parameter is unnamed.
42
42
enum Parameter : Equatable {
43
- case label ( String )
43
+ case named ( String )
44
44
case wildcard
45
45
46
46
var stringOrWildcard : String {
47
47
switch self {
48
- case . label ( let str) : return str
48
+ case . named ( let str) : return str
49
49
case . wildcard: return " _ "
50
50
}
51
51
}
52
52
53
53
var stringOrEmpty : String {
54
54
switch self {
55
- case . label ( let str) : return str
55
+ case . named ( let str) : return str
56
56
case . wildcard: return " "
57
57
}
58
58
}
@@ -83,7 +83,7 @@ fileprivate struct CompoundDeclName {
83
83
parameters = parameterStrings. map {
84
84
switch $0 {
85
85
case " " , " _ " : return . wildcard
86
- default : return . label ( String ( $0) )
86
+ default : return . named ( String ( $0) )
87
87
}
88
88
}
89
89
}
@@ -434,18 +434,19 @@ extension SwiftLanguageServer {
434
434
public func rename( _ request: RenameRequest ) async throws -> ( edits: WorkspaceEdit , usr: String ? , oldName: String ? ) {
435
435
let snapshot = try self . documentManager. latestSnapshot ( request. textDocument. uri)
436
436
437
- let relatedIdentifiers = try await self . relatedIdentifiers (
437
+ let relatedIdentifiersResponse = try await self . relatedIdentifiers (
438
438
at: request. position,
439
439
in: snapshot,
440
440
includeNonEditableBaseNames: true
441
441
)
442
- guard let oldName = relatedIdentifiers . name else {
442
+ guard let oldName = relatedIdentifiersResponse . name else {
443
443
throw ResponseError . unknown ( " Running sourcekit-lsp with a version of sourcekitd that does not support rename " )
444
444
}
445
445
446
446
try Task . checkCancellation ( )
447
447
448
- let renameLocations = relatedIdentifiers. relatedIdentifiers. compactMap { ( relatedIdentifier) -> RenameLocation ? in
448
+ let renameLocations = relatedIdentifiersResponse. relatedIdentifiers. compactMap {
449
+ ( relatedIdentifier) -> RenameLocation ? in
449
450
let position = relatedIdentifier. range. lowerBound
450
451
guard let utf8Column = snapshot. lineTable. utf8ColumnAt ( line: position. line, utf16Column: position. utf16index)
451
452
else {
@@ -473,6 +474,69 @@ extension SwiftLanguageServer {
473
474
return ( edits: WorkspaceEdit ( changes: [ snapshot. uri: edits] ) , usr: usr, oldName: oldName)
474
475
}
475
476
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
+
476
540
public func editsToRename(
477
541
locations renameLocations: [ RenameLocation ] ,
478
542
in snapshot: DocumentSnapshot ,
@@ -520,63 +584,13 @@ extension SwiftLanguageServer {
520
584
// renaming `func foo(a: Int, b: Int)` and the user specified `bar(x:)` as the new name.
521
585
return nil
522
586
}
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
+ )
580
594
}
581
595
}
582
596
}
0 commit comments