@@ -196,7 +196,10 @@ fileprivate class SourceReducer {
196
196
197
197
/// Replace the first `import` declaration in the source file by the contents of the Swift interface.
198
198
private func inlineFirstImport( _ requestInfo: RequestInfo ) async throws -> RequestInfo ? {
199
- let reductionResult = try await runReductionStep ( requestInfo: requestInfo) { tree in
199
+ // Don't report progress after inlining an import because it might increase the file size before we have a chance
200
+ // to increase `fileSizeAfterLastImportInline`. Progress will get updated again on the next successful reduction
201
+ // step.
202
+ let reductionResult = try await runReductionStep ( requestInfo: requestInfo, reportProgress: false ) { tree in
200
203
let edits = await Diagnose . inlineFirstImport (
201
204
in: tree,
202
205
executor: sourcekitdExecutor,
@@ -216,15 +219,22 @@ fileprivate class SourceReducer {
216
219
// MARK: Primitives to run reduction steps
217
220
218
221
private func logSuccessfulReduction( _ requestInfo: RequestInfo , tree: SourceFileSyntax ) {
219
- let numberOfImports = tree. numberOfImports
222
+ // The number of imports can grow if inlining a single module adds more than 1 new import.
223
+ // To keep progress between 0 and 1, clamp the number of imports to the initial import count.
224
+ let numberOfImports = min ( tree. numberOfImports, initialImportCount)
220
225
let fileSize = requestInfo. fileContents. utf8. count
221
226
222
227
let progressPerRemovedImport = Double ( 1 ) / Double( initialImportCount + 1 )
223
228
let removeImportProgress = Double ( initialImportCount - numberOfImports) * progressPerRemovedImport
224
229
let fileReductionProgress =
225
230
( 1 - Double( fileSize) / Double( fileSizeAfterLastImportInline) ) * progressPerRemovedImport
226
- let progress = removeImportProgress + fileReductionProgress
227
- precondition ( progress >= 0 && progress <= 1 )
231
+ var progress = removeImportProgress + fileReductionProgress
232
+ if progress < 0 || progress > 1 {
233
+ logger. fault (
234
+ " Trying to report progress \( progress) from remove import progress \( removeImportProgress) and file reduction progress \( fileReductionProgress) "
235
+ )
236
+ progress = max ( min ( progress, 1 ) , 0 )
237
+ }
228
238
progressUpdate ( progress, " Reduced to \( numberOfImports) imports and \( fileSize) bytes " )
229
239
}
230
240
@@ -234,6 +244,7 @@ fileprivate class SourceReducer {
234
244
/// Otherwise, return `nil`
235
245
private func runReductionStep(
236
246
requestInfo: RequestInfo ,
247
+ reportProgress: Bool = true ,
237
248
reduce: ( _ tree: SourceFileSyntax ) async throws -> ReducerResult
238
249
) async throws -> ReductionStepResult {
239
250
let tree = Parser . parse ( source: requestInfo. fileContents)
@@ -263,7 +274,9 @@ fileprivate class SourceReducer {
263
274
let result = try await sourcekitdExecutor. run ( request: reducedRequestInfo)
264
275
if case . reproducesIssue = result {
265
276
logger. debug ( " Reduction successful " )
266
- logSuccessfulReduction ( reducedRequestInfo, tree: tree)
277
+ if reportProgress {
278
+ logSuccessfulReduction ( reducedRequestInfo, tree: tree)
279
+ }
267
280
return . reduced( reducedRequestInfo)
268
281
} else {
269
282
logger. debug ( " Reduction did not reproduce the issue " )
0 commit comments