Skip to content

Commit a3cd491

Browse files
authored
[SwiftFixIt] Allow filtering diagnostics by category (#8620)
### Motivation: Helps with applying only certain fix-its i.e. for features in migration mode or concurrency. ### Modifications: - Add `categories: Set<String>` parameter to `SwiftFixIt` initializers that is defaulted to `[]`. ### Result: `swift migrate` can use this to filter based on the feature categories to avoid applying unrelated fix-its.
1 parent 9688105 commit a3cd491

File tree

2 files changed

+108
-6
lines changed

2 files changed

+108
-6
lines changed

Sources/SwiftFixIt/SwiftFixit.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ package struct SwiftFixIt /*: ~Copyable */ {
8989

9090
package init(
9191
diagnosticFiles: [AbsolutePath],
92+
categories: Set<String> = [],
9293
fileSystem: any FileSystem
9394
) throws {
9495
// Deserialize the diagnostics.
@@ -97,11 +98,16 @@ package struct SwiftFixIt /*: ~Copyable */ {
9798
return try TSCUtility.SerializedDiagnostics(bytes: fileContents).diagnostics
9899
}.lazy.joined()
99100

100-
self = try SwiftFixIt(diagnostics: diagnostics, fileSystem: fileSystem)
101+
self = try SwiftFixIt(
102+
diagnostics: diagnostics,
103+
categories: categories,
104+
fileSystem: fileSystem
105+
)
101106
}
102107

103108
init(
104109
diagnostics: some Collection<some AnyDiagnostic>,
110+
categories: Set<String> = [],
105111
fileSystem: any FileSystem
106112
) throws {
107113
self.fileSystem = fileSystem
@@ -143,6 +149,14 @@ package struct SwiftFixIt /*: ~Copyable */ {
143149
continue
144150
}
145151

152+
if !categories.isEmpty {
153+
guard let category = convertedDiagnostic.diagMessage.category?.name,
154+
categories.contains(category)
155+
else {
156+
continue
157+
}
158+
}
159+
146160
diagnosticsPerFile[consume sourceFile, default: []].append(consume convertedDiagnostic)
147161
}
148162

Tests/SwiftFixItTests/SwiftFixItTests.swift

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,18 @@ final class SwiftFixItTests: XCTestCase {
5555

5656
private func _testAPI(
5757
_ sourceFilePathsAndEdits: [(AbsolutePath, SourceFileEdit)],
58-
_ diagnostics: [TestDiagnostic]
58+
_ diagnostics: [TestDiagnostic],
59+
_ categories: Set<String>,
5960
) throws {
6061
for (path, edit) in sourceFilePathsAndEdits {
6162
try localFileSystem.writeFileContents(path, string: edit.input)
6263
}
6364

64-
let swiftFixIt = try SwiftFixIt(diagnostics: diagnostics, fileSystem: localFileSystem)
65+
let swiftFixIt = try SwiftFixIt(
66+
diagnostics: diagnostics,
67+
categories: categories,
68+
fileSystem: localFileSystem
69+
)
6570
try swiftFixIt.applyFixIts()
6671

6772
for (path, edit) in sourceFilePathsAndEdits {
@@ -75,6 +80,7 @@ final class SwiftFixItTests: XCTestCase {
7580

7681
// Cannot use variadic generics: crashes.
7782
private func testAPI1File(
83+
categories: Set<String> = [],
7884
_ getTestCase: (String) -> TestCase<SourceFileEdit>
7985
) throws {
8086
try testWithTemporaryDirectory { fixturePath in
@@ -84,13 +90,15 @@ final class SwiftFixItTests: XCTestCase {
8490

8591
try self._testAPI(
8692
[(sourceFilePath, testCase.edits)],
87-
testCase.diagnostics
93+
testCase.diagnostics,
94+
categories
8895
)
8996
}
9097
}
9198

9299
private func testAPI2Files(
93-
_ getTestCase: (String, String) -> TestCase<(SourceFileEdit, SourceFileEdit)>
100+
categories: Set<String> = [],
101+
_ getTestCase: (String, String) -> TestCase<(SourceFileEdit, SourceFileEdit)>,
94102
) throws {
95103
try testWithTemporaryDirectory { fixturePath in
96104
let sourceFilePath1 = fixturePath.appending(self.uniqueSwiftFileName())
@@ -100,7 +108,8 @@ final class SwiftFixItTests: XCTestCase {
100108

101109
try self._testAPI(
102110
[(sourceFilePath1, testCase.edits.0), (sourceFilePath2, testCase.edits.1)],
103-
testCase.diagnostics
111+
testCase.diagnostics,
112+
categories
104113
)
105114
}
106115
}
@@ -129,6 +138,85 @@ extension SwiftFixItTests {
129138
}
130139
}
131140

141+
func testCategoryFiltering() throws {
142+
// Check that the fix-it gets ignored because category doesn't match
143+
try self.testAPI1File(categories: ["Test"]) { (filename: String) in
144+
.init(
145+
edits: .init(input: "var x = 1", result: "var x = 1"),
146+
diagnostics: [
147+
TestDiagnostic(
148+
text: "error",
149+
level: .error,
150+
location: .init(filename: filename, line: 1, column: 1, offset: 0),
151+
fixIts: [
152+
.init(
153+
start: .init(filename: filename, line: 1, column: 1, offset: 0),
154+
end: .init(filename: filename, line: 1, column: 4, offset: 0),
155+
text: "let"
156+
),
157+
]
158+
),
159+
]
160+
)
161+
}
162+
163+
// Check that the fix-it gets ignored because category doesn't match
164+
try self.testAPI1File(categories: ["Test"]) { (filename: String) in
165+
.init(
166+
edits: .init(input: "var x = 1", result: "var x = 1"),
167+
diagnostics: [
168+
TestDiagnostic(
169+
text: "error",
170+
level: .error,
171+
location: .init(filename: filename, line: 1, column: 1, offset: 0),
172+
category: "Other",
173+
fixIts: [
174+
.init(
175+
start: .init(filename: filename, line: 1, column: 1, offset: 0),
176+
end: .init(filename: filename, line: 1, column: 4, offset: 0),
177+
text: "let"
178+
),
179+
]
180+
),
181+
]
182+
)
183+
}
184+
185+
try self.testAPI1File(categories: ["Other", "Test"]) { (filename: String) in
186+
.init(
187+
edits: .init(input: "var x = 1", result: "let _ = 1"),
188+
diagnostics: [
189+
TestDiagnostic(
190+
text: "error",
191+
level: .error,
192+
location: .init(filename: filename, line: 1, column: 1, offset: 0),
193+
category: "Test",
194+
fixIts: [
195+
.init(
196+
start: .init(filename: filename, line: 1, column: 1, offset: 0),
197+
end: .init(filename: filename, line: 1, column: 4, offset: 0),
198+
text: "let"
199+
),
200+
]
201+
),
202+
TestDiagnostic(
203+
text: "error",
204+
level: .error,
205+
location: .init(filename: filename, line: 1, column: 4, offset: 0),
206+
category: "Other",
207+
fixIts: [
208+
.init(
209+
start: .init(filename: filename, line: 1, column: 5, offset: 0),
210+
end: .init(filename: filename, line: 1, column: 6, offset: 0),
211+
text: "_"
212+
),
213+
]
214+
),
215+
]
216+
)
217+
}
218+
}
219+
132220
func testFixItIgnoredDiagnostic() throws {
133221
try self.testAPI1File { (filename: String) in
134222
.init(

0 commit comments

Comments
 (0)