@@ -15,8 +15,19 @@ import SourceKitD
15
15
import SwiftParser
16
16
import SwiftSyntax
17
17
18
+ // MARK: - Entry point
19
+
20
+ extension RequestInfo {
21
+ func reduceInputFile( using executor: SourceKitRequestExecutor ) async throws -> RequestInfo {
22
+ let reducer = SourceReducer ( sourcekitdExecutor: executor)
23
+ return try await reducer. run ( initialRequestInfo: self )
24
+ }
25
+ }
26
+
27
+ // MARK: - SourceReducer
28
+
18
29
/// Reduces an input source file while continuing to reproduce the crash
19
- class FileReducer {
30
+ fileprivate class SourceReducer {
20
31
/// The executor that is used to run a sourcekitd request and check whether it
21
32
/// still crashes.
22
33
private let sourcekitdExecutor : SourceKitRequestExecutor
@@ -32,7 +43,7 @@ class FileReducer {
32
43
/// Reduce the file contents in `initialRequest` to a smaller file that still reproduces a crash.
33
44
func run( initialRequestInfo: RequestInfo ) async throws -> RequestInfo {
34
45
var requestInfo = initialRequestInfo
35
- try await validateRequestInfoCrashes ( requestInfo: requestInfo)
46
+ try await validateRequestInfoReproucesIssue ( requestInfo: requestInfo)
36
47
37
48
requestInfo = try await fatalErrorFunctionBodies ( requestInfo)
38
49
requestInfo = try await removeMembersAndCodeBlockItemsBodies ( requestInfo)
@@ -51,12 +62,12 @@ class FileReducer {
51
62
return requestInfo
52
63
}
53
64
54
- // MARK: - Reduction steps
65
+ // MARK: Reduction steps
55
66
56
- private func validateRequestInfoCrashes ( requestInfo: RequestInfo) async throws {
67
+ private func validateRequestInfoReproucesIssue ( requestInfo: RequestInfo ) async throws {
57
68
let initialReproducer = try await runReductionStep ( requestInfo: requestInfo) { tree in [ ] }
58
69
if initialReproducer == nil {
59
- throw ReductionError ( " Initial request info did not crash " )
70
+ throw ReductionError ( " Initial request info did not reproduce the issue " )
60
71
}
61
72
}
62
73
@@ -110,7 +121,7 @@ class FileReducer {
110
121
}
111
122
}
112
123
113
- // MARK: - Primitives to run reduction steps
124
+ // MARK: Primitives to run reduction steps
114
125
115
126
func logSuccessfulReduction( _ requestInfo: RequestInfo ) {
116
127
print ( " Reduced source file to \( requestInfo. fileContents. utf8. count) bytes " )
@@ -191,15 +202,15 @@ class FileReducer {
191
202
192
203
// MARK: - Reduce functions
193
204
194
- /// See `FileReducer .runReductionStep`
195
- protocol StatefulReducer {
205
+ /// See `SourceReducer .runReductionStep`
206
+ fileprivate protocol StatefulReducer {
196
207
func reduce( tree: SourceFileSyntax ) -> [ SourceEdit ]
197
208
}
198
209
199
210
// MARK: Replace function bodies
200
211
201
212
/// Tries replacing one function body by `fatalError()` at a time.
202
- class ReplaceFunctionBodiesByFatalError: StatefulReducer {
213
+ fileprivate class ReplaceFunctionBodiesByFatalError : StatefulReducer {
203
214
/// The function bodies that should not be replaced by `fatalError()`.
204
215
///
205
216
/// When we tried replacing a function body by `fatalError`, it gets added to this list.
@@ -240,24 +251,23 @@ class ReplaceFunctionBodiesByFatalError: StatefulReducer {
240
251
}
241
252
if keepFunctionBodies. contains ( node. statements. description. trimmingCharacters ( in: . whitespacesAndNewlines) ) {
242
253
return . visitChildren
243
- } else {
244
- keepFunctionBodies. append ( node. statements. description. trimmingCharacters ( in: . whitespacesAndNewlines) )
245
- edits. append (
246
- SourceEdit (
247
- range: node. statements. position..< node. statements. endPosition,
248
- replacement: " \( node. statements. leadingTrivia) fatalError() "
249
- )
250
- )
251
- return . skipChildren
252
254
}
255
+ keepFunctionBodies. append ( node. statements. description. trimmingCharacters ( in: . whitespacesAndNewlines) )
256
+ edits. append (
257
+ SourceEdit (
258
+ range: node. statements. position..< node. statements. endPosition,
259
+ replacement: " \( node. statements. leadingTrivia) fatalError() "
260
+ )
261
+ )
262
+ return . skipChildren
253
263
}
254
264
}
255
265
}
256
266
257
267
// MARK: Remove members and code block items
258
268
259
269
/// Tries removing `MemberBlockItemSyntax` and `CodeBlockItemSyntax` one at a time.
260
- class RemoveMembersAndCodeBlockItems : StatefulReducer {
270
+ fileprivate class RemoveMembersAndCodeBlockItems : StatefulReducer {
261
271
/// The code block items / members that shouldn't be removed.
262
272
///
263
273
/// See `ReplaceFunctionBodiesByFatalError.keepFunctionBodies`.
@@ -323,7 +333,7 @@ class RemoveMembersAndCodeBlockItems: StatefulReducer {
323
333
}
324
334
325
335
/// Removes all comments from the source file.
326
- func removeComments( from tree: SourceFileSyntax ) -> [ SourceEdit ] {
336
+ fileprivate func removeComments( from tree: SourceFileSyntax ) -> [ SourceEdit ] {
327
337
class CommentRemover : SyntaxVisitor {
328
338
var edits : [ SourceEdit ] = [ ]
329
339
@@ -366,7 +376,7 @@ fileprivate extension TriviaPiece {
366
376
367
377
// MARK: Inline first include
368
378
369
- class FirstImportFinder : SyntaxAnyVisitor {
379
+ fileprivate class FirstImportFinder : SyntaxAnyVisitor {
370
380
var firstImport : ImportDeclSyntax ?
371
381
372
382
override func visitAny( _ node: Syntax ) -> SyntaxVisitorContinueKind {
@@ -391,24 +401,18 @@ class FirstImportFinder: SyntaxAnyVisitor {
391
401
}
392
402
}
393
403
394
- private func getSwiftInterface( _ moduleName: String , executor: SourceKitRequestExecutor , compilerArgs: [ String ] )
395
- async throws -> String
396
- {
397
- // FIXME: Use the sourcekitd specified on the command line once rdar://121676425 is fixed
398
- let sourcekitdPath =
399
- " /Applications/Geode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/sourcekitdInProc.framework/sourcekitdInProc "
400
- let executor = SourceKitRequestExecutor (
401
- sourcekitd: URL ( fileURLWithPath: sourcekitdPath) ,
402
- reproducerPredicate: nil
403
- )
404
-
404
+ fileprivate func getSwiftInterface(
405
+ _ moduleName: String ,
406
+ executor: SourceKitRequestExecutor ,
407
+ compilerArgs: [ String ]
408
+ ) async throws -> String {
405
409
// We use `RequestInfo` and its template to add the compiler arguments to the request.
406
410
let requestTemplate = """
407
411
{
408
412
key.request: source.request.editor.open.interface,
409
413
key.name: " fake " ,
410
414
key.compilerargs: [
411
- $COMPILERARGS
415
+ $COMPILER_ARGS
412
416
],
413
417
key.modulename: " \( moduleName) "
414
418
}
@@ -448,7 +452,7 @@ private func getSwiftInterface(_ moduleName: String, executor: SourceKitRequestE
448
452
return try JSONDecoder ( ) . decode ( String . self, from: sanitizedData)
449
453
}
450
454
451
- func inlineFirstImport(
455
+ fileprivate func inlineFirstImport(
452
456
in tree: SourceFileSyntax ,
453
457
executor: SourceKitRequestExecutor ,
454
458
compilerArgs: [ String ]
0 commit comments