Skip to content

Commit 2d2bac8

Browse files
authored
Merge pull request #1471 from ahoppen/enum-case-rename
Adjust test cases for fixed enum case rename
2 parents 5fb71b7 + 7a61ff9 commit 2d2bac8

File tree

3 files changed

+125
-45
lines changed

3 files changed

+125
-45
lines changed

Sources/SKTestSupport/SkipUnless.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,31 @@ public actor SkipUnless {
156156
}
157157
}
158158

159+
/// Checks whether the sourcekitd contains a fix to rename labels of enum cases correctly
160+
/// (https://github.com/apple/swift/pull/74241).
161+
public static func sourcekitdCanRenameEnumCaseLabels(
162+
file: StaticString = #filePath,
163+
line: UInt = #line
164+
) async throws {
165+
return try await shared.skipUnlessSupportedByToolchain(swiftVersion: SwiftVersion(6, 0), file: file, line: line) {
166+
let testClient = try await TestSourceKitLSPClient()
167+
let uri = DocumentURI(for: .swift)
168+
let positions = testClient.openDocument(
169+
"""
170+
enum MyEnum {
171+
case 1️⃣myCase(2️⃣String)
172+
}
173+
""",
174+
uri: uri
175+
)
176+
177+
let renameResult = try await testClient.send(
178+
RenameRequest(textDocument: TextDocumentIdentifier(uri), position: positions["1️⃣"], newName: "myCase(label:)")
179+
)
180+
return renameResult?.changes == [uri: [TextEdit(range: Range(positions["2️⃣"]), newText: "label: ")]]
181+
}
182+
}
183+
159184
/// Whether clangd has support for the `workspace/indexedRename` request.
160185
public static func clangdSupportsIndexBasedRename(
161186
file: StaticString = #filePath,

Sources/SourceKitLSP/Rename.swift

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,24 +1003,6 @@ extension SwiftLanguageService {
10031003
return nil
10041004
}
10051005

1006-
/// Returns `true` if the given position is inside an `EnumCaseDeclSyntax`.
1007-
fileprivate func isInsideEnumCaseDecl(position: Position, snapshot: DocumentSnapshot) async -> Bool {
1008-
let syntaxTree = await syntaxTreeManager.syntaxTree(for: snapshot)
1009-
var node = Syntax(syntaxTree.token(at: snapshot.absolutePosition(of: position)))
1010-
1011-
while let parent = node?.parent {
1012-
if parent.is(EnumCaseDeclSyntax.self) {
1013-
return true
1014-
}
1015-
if parent.is(MemberBlockItemSyntax.self) || parent.is(CodeBlockItemSyntax.self) {
1016-
// `MemberBlockItemSyntax` and `CodeBlockItemSyntax` can't be nested inside an EnumCaseDeclSyntax. Early exit.
1017-
return false
1018-
}
1019-
node = parent
1020-
}
1021-
return false
1022-
}
1023-
10241006
/// When the user requested a rename at `position` in `snapshot`, determine the position at which the rename should be
10251007
/// performed internally, the USR of the symbol to rename and the range to rename that should be returned to the
10261008
/// editor.
@@ -1095,17 +1077,8 @@ extension SwiftLanguageService {
10951077

10961078
try Task.checkCancellation()
10971079

1098-
var requestedNewName = request.newName
1099-
if let openParenIndex = requestedNewName.firstIndex(of: "("),
1100-
await isInsideEnumCaseDecl(position: renamePosition, snapshot: snapshot)
1101-
{
1102-
// We don't support renaming enum parameter labels at the moment
1103-
// (https://github.com/apple/sourcekit-lsp/issues/1228)
1104-
requestedNewName = String(requestedNewName[..<openParenIndex])
1105-
}
1106-
11071080
let oldName = CrossLanguageName(clangName: nil, swiftName: oldNameString, definitionLanguage: .swift)
1108-
let newName = CrossLanguageName(clangName: nil, swiftName: requestedNewName, definitionLanguage: .swift)
1081+
let newName = CrossLanguageName(clangName: nil, swiftName: request.newName, definitionLanguage: .swift)
11091082
var edits = try await editsToRename(
11101083
locations: renameLocations,
11111084
in: snapshot,
@@ -1398,13 +1371,6 @@ extension SwiftLanguageService {
13981371
if name.hasSuffix("()") {
13991372
name = String(name.dropLast(2))
14001373
}
1401-
if let openParenIndex = name.firstIndex(of: "("),
1402-
await isInsideEnumCaseDecl(position: renamePosition, snapshot: snapshot)
1403-
{
1404-
// We don't support renaming enum parameter labels at the moment
1405-
// (https://github.com/apple/sourcekit-lsp/issues/1228)
1406-
name = String(name[..<openParenIndex])
1407-
}
14081374
guard let relatedIdentRange = response.relatedIdentifiers.first(where: { $0.range.contains(renamePosition) })?.range
14091375
else {
14101376
return nil

Tests/SourceKitLSPTests/RenameTests.swift

Lines changed: 99 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,14 +1170,15 @@ final class RenameTests: XCTestCase {
11701170
}
11711171

11721172
func testRenameEnumCaseWithUnlabeledAssociatedValue() async throws {
1173+
try await SkipUnless.sourcekitdCanRenameEnumCaseLabels()
11731174
try await assertSingleFileRename(
11741175
"""
11751176
enum MyEnum {
11761177
case 1️⃣myCase(String)
11771178
}
11781179
""",
11791180
newName: "newName",
1180-
expectedPrepareRenamePlaceholder: "myCase",
1181+
expectedPrepareRenamePlaceholder: "myCase(_:)",
11811182
expected: """
11821183
enum MyEnum {
11831184
case newName(String)
@@ -1187,39 +1188,127 @@ final class RenameTests: XCTestCase {
11871188
}
11881189

11891190
func testAddLabelToEnumCase() async throws {
1190-
// We don't support renaming enum parameter labels at the moment
1191-
// (https://github.com/apple/sourcekit-lsp/issues/1228)
1191+
try await SkipUnless.sourcekitdCanRenameEnumCaseLabels()
11921192
try await assertSingleFileRename(
11931193
"""
11941194
enum MyEnum {
11951195
case 1️⃣myCase(String)
11961196
}
11971197
""",
11981198
newName: "newName(newLabel:)",
1199-
expectedPrepareRenamePlaceholder: "myCase",
1199+
expectedPrepareRenamePlaceholder: "myCase(_:)",
12001200
expected: """
12011201
enum MyEnum {
1202-
case newName(String)
1202+
case newName(newLabel: String)
12031203
}
12041204
"""
12051205
)
12061206
}
12071207

1208-
func testRemoveLabelToEnumCase() async throws {
1209-
// We don't support renaming enum parameter labels at the moment
1210-
// (https://github.com/apple/sourcekit-lsp/issues/1228)
1208+
func testRemoveLabelFromEnumCase() async throws {
1209+
try await SkipUnless.sourcekitdCanRenameEnumCaseLabels()
12111210
try await assertSingleFileRename(
12121211
"""
12131212
enum MyEnum {
1214-
case 1️⃣myCase(label: String)
1213+
case myCase(label: String)
1214+
}
1215+
1216+
func test() {
1217+
_ = MyEnum.2️⃣myCase(label: "abc")
12151218
}
12161219
""",
12171220
newName: "newName(_:)",
1218-
expectedPrepareRenamePlaceholder: "myCase",
1221+
expectedPrepareRenamePlaceholder: "myCase(label:)",
1222+
expected: """
1223+
enum MyEnum {
1224+
case newName(_ label: String)
1225+
}
1226+
1227+
func test() {
1228+
_ = MyEnum.newName("abc")
1229+
}
1230+
"""
1231+
)
1232+
}
1233+
1234+
func testRenameEnumCaseWithUnderscoreLabel() async throws {
1235+
try await SkipUnless.sourcekitdCanRenameEnumCaseLabels()
1236+
try await assertSingleFileRename(
1237+
"""
1238+
enum MyEnum {
1239+
case myCase(_ label: String)
1240+
}
1241+
1242+
func test() {
1243+
_ = MyEnum.2️⃣myCase("abc")
1244+
}
1245+
""",
1246+
newName: "newName(_:)",
1247+
expectedPrepareRenamePlaceholder: "myCase(_:)",
1248+
expected: """
1249+
enum MyEnum {
1250+
case newName(_ label: String)
1251+
}
1252+
1253+
func test() {
1254+
_ = MyEnum.newName("abc")
1255+
}
1256+
"""
1257+
)
1258+
}
1259+
1260+
func testRenameEnumCaseWithUnderscoreToLabelMatchingInternalName() async throws {
1261+
try await SkipUnless.sourcekitdCanRenameEnumCaseLabels()
1262+
try await assertSingleFileRename(
1263+
"""
1264+
enum MyEnum {
1265+
case myCase(_ label: String)
1266+
}
1267+
1268+
func test() {
1269+
_ = MyEnum.2️⃣myCase("abc")
1270+
}
1271+
""",
1272+
newName: "newName(label:)",
1273+
expectedPrepareRenamePlaceholder: "myCase(_:)",
12191274
expected: """
12201275
enum MyEnum {
12211276
case newName(label: String)
12221277
}
1278+
1279+
func test() {
1280+
_ = MyEnum.newName(label: "abc")
1281+
}
1282+
"""
1283+
)
1284+
}
1285+
1286+
func testRenameEnumCaseWithUnderscoreToLabelNotMatchingInternalName() async throws {
1287+
try await SkipUnless.sourcekitdCanRenameEnumCaseLabels()
1288+
// Note that the renamed code doesn't compile because enum cases can't have an external and internal parameter name.
1289+
// But it's probably the best thing we can do because we don't want to erase the user-specified internal name, which
1290+
// they didn't request to rename. Also, this is a pretty niche case and having a special case for it is probably not
1291+
// worth it.
1292+
try await assertSingleFileRename(
1293+
"""
1294+
enum MyEnum {
1295+
case myCase(_ label: String)
1296+
}
1297+
1298+
func test() {
1299+
_ = MyEnum.2️⃣myCase("abc")
1300+
}
1301+
""",
1302+
newName: "newName(publicLabel:)",
1303+
expectedPrepareRenamePlaceholder: "myCase(_:)",
1304+
expected: """
1305+
enum MyEnum {
1306+
case newName(publicLabel label: String)
1307+
}
1308+
1309+
func test() {
1310+
_ = MyEnum.newName(publicLabel: "abc")
1311+
}
12231312
"""
12241313
)
12251314
}

0 commit comments

Comments
 (0)