Skip to content

Commit 06e0161

Browse files
committed
Use string based SourceLocationConverter init because it's faster.
I'm not sure why, but the string based initializer for `SourceLocationConverter` is substantially faster than the syntax tree based initializer. The impact is a few hundred ms per file, so it is substantial when formatting many files. Results: - swift-protobuf 21.4 seconds before, 17.9 seconds after - 10k LOC file - 2.5 seconds before, 2.2 seconds after
1 parent 34ccba1 commit 06e0161

File tree

3 files changed

+22
-12
lines changed

3 files changed

+22
-12
lines changed

Sources/SwiftFormat/SwiftFormatter.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ public final class SwiftFormatter {
5858
throw SwiftFormatError.isDirectory
5959
}
6060
let sourceFile = try SyntaxParser.parse(url)
61-
try format(syntax: sourceFile, assumingFileURL: url, to: &outputStream)
61+
let source = try String(contentsOf: url, encoding: .utf8)
62+
try format(syntax: sourceFile, assumingFileURL: url, source: source, to: &outputStream)
6263
}
6364

6465
/// Formats the given Swift source code and writes the result to an output stream.
@@ -75,7 +76,7 @@ public final class SwiftFormatter {
7576
source: String, assumingFileURL url: URL?, to outputStream: inout Output
7677
) throws {
7778
let sourceFile = try SyntaxParser.parse(source: source)
78-
try format(syntax: sourceFile, assumingFileURL: url, to: &outputStream)
79+
try format(syntax: sourceFile, assumingFileURL: url, source: source, to: &outputStream)
7980
}
8081

8182
/// Formats the given Swift syntax tree and writes the result to an output stream.
@@ -85,11 +86,14 @@ public final class SwiftFormatter {
8586
/// - url: A file URL denoting the filename/path that should be assumed for this syntax tree,
8687
/// which is associated with any diagnostics emitted during formatting. If this is nil, a
8788
/// dummy value will be used.
89+
/// - source: The Swift source code. This can be provided to improve the formatter's
90+
/// performance.
8891
/// - outputStream: A value conforming to `TextOutputStream` to which the formatted output will
8992
/// be written.
9093
/// - Throws: If an unrecoverable error occurs when formatting the code.
9194
public func format<Output: TextOutputStream>(
92-
syntax: SourceFileSyntax, assumingFileURL url: URL?, to outputStream: inout Output
95+
syntax: SourceFileSyntax, assumingFileURL url: URL?, source: String? = nil,
96+
to outputStream: inout Output
9397
) throws {
9498
if let position = firstInvalidSyntaxPosition(in: Syntax(syntax)) {
9599
throw SwiftFormatError.fileContainsInvalidSyntax(position: position)
@@ -98,7 +102,7 @@ public final class SwiftFormatter {
98102
let assumedURL = url ?? URL(fileURLWithPath: "source")
99103
let context = Context(
100104
configuration: configuration, diagnosticEngine: diagnosticEngine, fileURL: assumedURL,
101-
sourceFileSyntax: syntax)
105+
sourceFileSyntax: syntax, source: source)
102106
let pipeline = FormatPipeline(context: context)
103107
let transformedSyntax = pipeline.visit(Syntax(syntax))
104108

Sources/SwiftFormat/SwiftLinter.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ public final class SwiftLinter {
5454
throw SwiftFormatError.isDirectory
5555
}
5656
let sourceFile = try SyntaxParser.parse(url)
57-
try lint(syntax: sourceFile, assumingFileURL: url)
57+
let source = try String(contentsOf: url, encoding: .utf8)
58+
try lint(syntax: sourceFile, assumingFileURL: url, source: source)
5859
}
5960

6061
/// Lints the given Swift source code.
@@ -65,23 +66,26 @@ public final class SwiftLinter {
6566
/// - Throws: If an unrecoverable error occurs when formatting the code.
6667
public func lint(source: String, assumingFileURL url: URL) throws {
6768
let sourceFile = try SyntaxParser.parse(source: source)
68-
try lint(syntax: sourceFile, assumingFileURL: url)
69+
try lint(syntax: sourceFile, assumingFileURL: url, source: source)
6970
}
7071

7172
/// Lints the given Swift syntax tree.
7273
///
7374
/// - Parameters:
7475
/// - syntax: The Swift syntax tree to be converted to be linted.
7576
/// - url: A file URL denoting the filename/path that should be assumed for this syntax tree.
77+
/// - source: The Swift source code. This can be provided to improve the linter's performance.
7678
/// - Throws: If an unrecoverable error occurs when formatting the code.
77-
public func lint(syntax: SourceFileSyntax, assumingFileURL url: URL) throws {
79+
public func lint(
80+
syntax: SourceFileSyntax, assumingFileURL url: URL, source: String? = nil
81+
) throws {
7882
if let position = firstInvalidSyntaxPosition(in: Syntax(syntax)) {
7983
throw SwiftFormatError.fileContainsInvalidSyntax(position: position)
8084
}
81-
85+
8286
let context = Context(
8387
configuration: configuration, diagnosticEngine: diagnosticEngine, fileURL: url,
84-
sourceFileSyntax: syntax)
88+
sourceFileSyntax: syntax, source: source)
8589
let pipeline = LintPipeline(context: context)
8690
pipeline.walk(Syntax(syntax))
8791

Sources/SwiftFormatCore/Context.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,16 @@ public class Context {
5757
configuration: Configuration,
5858
diagnosticEngine: DiagnosticEngine?,
5959
fileURL: URL,
60-
sourceFileSyntax: SourceFileSyntax
60+
sourceFileSyntax: SourceFileSyntax,
61+
source: String? = nil
6162
) {
6263
self.configuration = configuration
6364
self.diagnosticEngine = diagnosticEngine
6465
self.fileURL = fileURL
6566
self.importsXCTest = .notDetermined
66-
self.sourceLocationConverter = SourceLocationConverter(
67-
file: fileURL.path, tree: sourceFileSyntax)
67+
self.sourceLocationConverter =
68+
source.map { SourceLocationConverter(file: fileURL.path, source: $0) }
69+
?? SourceLocationConverter(file: fileURL.path, tree: sourceFileSyntax)
6870
self.ruleMask = RuleMask(
6971
syntaxNode: Syntax(sourceFileSyntax),
7072
sourceLocationConverter: sourceLocationConverter

0 commit comments

Comments
 (0)