Skip to content

Commit 9034e62

Browse files
committed
SwiftFixIt: Skip duplicate insertion fix-its
There are various scenarios — most notably involving protocol compositions — where multiple different sites are diagnosed with the same insertion fix-it. For example, compiling the following code with `-enable-upcoming-feature InferIsolatedConformances:migrate` generates 2 warnings with equal fix-its for prepending `nonisolated` to the composition: ```swift protocol P {} protocol Q {} @mainactor struct S: P & Q {} ``` Applying both fix-its will produce invalid code: `@MainActor struct S: nonisolated nonisolated P & Q {}`.
1 parent 0c7ebf2 commit 9034e62

File tree

7 files changed

+33
-14
lines changed

7 files changed

+33
-14
lines changed

Fixtures/SwiftMigrate/ExistentialAnyMigration/Sources/Fixed/Test.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
protocol P {
22
}
3+
protocol Q {
4+
}
35

46
func test1(_: any P) {
57
}
@@ -14,3 +16,6 @@ func test3() {
1416
func test4() {
1517
var x = 42
1618
}
19+
20+
func test5(_: any P & Q) {
21+
}

Fixtures/SwiftMigrate/ExistentialAnyMigration/Sources/Test.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
protocol P {
22
}
3+
protocol Q {
4+
}
35

46
func test1(_: P) {
57
}
@@ -14,3 +16,6 @@ func test3() {
1416
func test4() {
1517
var x = 42
1618
}
19+
20+
func test5(_: P & Q) {
21+
}

Fixtures/SwiftMigrate/InferIsolatedConformancesMigration/Sources/Fixed/Test.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,9 @@ class C: nonisolated Equatable {
66
lhs.name == rhs.name
77
}
88
}
9+
10+
protocol P {}
11+
protocol Q {}
12+
13+
@MainActor
14+
struct S: nonisolated P & Q {}

Fixtures/SwiftMigrate/InferIsolatedConformancesMigration/Sources/Test.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,9 @@ class C: Equatable {
66
lhs.name == rhs.name
77
}
88
}
9+
10+
protocol P {}
11+
protocol Q {}
12+
13+
@MainActor
14+
struct S: P & Q {}

Sources/SwiftFixIt/SwiftFixIt.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,11 @@ extension SwiftFixIt {
301301
}
302302
}
303303

304-
let result = SwiftIDEUtils.FixItApplier.apply(edits: consume edits, to: sourceFile.syntax)
304+
let result = SwiftIDEUtils.FixItApplier.apply(
305+
edits: consume edits,
306+
to: sourceFile.syntax,
307+
allowDuplicateInsertions: false
308+
)
305309

306310
try self.fileSystem.writeFileContents(sourceFile.path, string: consume result)
307311
}

Tests/CommandsTests/PackageCommandTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,9 +2151,9 @@ class PackageCommandTestCase: CommandsBuildProviderTestCase {
21512151
}
21522152
}
21532153

2154-
try await doMigration(featureName: "ExistentialAny", expectedSummary: "Applied 3 fix-its in 1 file")
2154+
try await doMigration(featureName: "ExistentialAny", expectedSummary: "Applied 5 fix-its in 1 file")
21552155
try await doMigration(featureName: "StrictMemorySafety", expectedSummary: "Applied 1 fix-it in 1 file")
2156-
try await doMigration(featureName: "InferIsolatedConformances", expectedSummary: "Applied 1 fix-it in 1 file")
2156+
try await doMigration(featureName: "InferIsolatedConformances", expectedSummary: "Applied 3 fix-its in 1 file")
21572157
}
21582158

21592159
func testBuildToolPlugin() async throws {

Tests/SwiftFixItTests/FilteringTests.swift

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -412,19 +412,12 @@ struct FilteringTests {
412412
}
413413
}
414414

415-
@Test
416415
func testDuplicateInsertionFixIts() throws {
417-
withKnownIssue("FIXME: Filter out duplicate insertion fix-its") {
418-
try self._testDuplicateInsertionFixIts()
419-
}
420-
}
421-
422-
func _testDuplicateInsertionFixIts() throws {
423416
try testAPI1File { path in
424417
.init(
425418
edits: .init(input: "var x = 1", result: "@W var yx = 21"),
426419
summary: .init(
427-
// 4 because skipped by SwiftIDEUtils.FixItApplier, not SwiftFixIt.
420+
// 6 because skipped by SwiftIDEUtils.FixItApplier, not SwiftFixIt.
428421
numberOfFixItsApplied: 6,
429422
numberOfFilesChanged: 1
430423
),
@@ -470,7 +463,7 @@ struct FilteringTests {
470463
text: "error3_fixit1",
471464
location: .init(path: path, line: 1, column: 3),
472465
fixIts: [
473-
// FIXME: Should be skipped.
466+
// Skipped, duplicate insertion.
474467
.init(
475468
start: .init(path: path, line: 1, column: 1),
476469
end: .init(path: path, line: 1, column: 1),
@@ -500,7 +493,7 @@ struct FilteringTests {
500493
text: "error5_note1",
501494
location: .init(path: path, line: 1, column: 9),
502495
fixIts: [
503-
// FIXME: Should be skipped.
496+
// Skipped, duplicate insertion.
504497
.init(
505498
start: .init(path: path, line: 1, column: 9),
506499
end: .init(path: path, line: 1, column: 9),
@@ -519,7 +512,7 @@ struct FilteringTests {
519512
text: "error6_note1",
520513
location: .init(path: path, line: 1, column: 5),
521514
fixIts: [
522-
// FIXME: Should be skipped.
515+
// Skipped, duplicate insertion.
523516
.init(
524517
start: .init(path: path, line: 1, column: 5),
525518
end: .init(path: path, line: 1, column: 5),

0 commit comments

Comments
 (0)