diff --git a/Package.swift b/Package.swift index 6d0903660..26cf44f30 100644 --- a/Package.swift +++ b/Package.swift @@ -1,9 +1,9 @@ -// swift-tools-version: 5.9 +// swift-tools-version: 6.0 //===----------------------------------------------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -47,7 +47,11 @@ var targets: [Target] = [ + swiftSyntaxDependencies([ "SwiftOperators", "SwiftParser", "SwiftParserDiagnostics", "SwiftSyntax", "SwiftSyntaxBuilder", ]), - exclude: ["CMakeLists.txt"] + exclude: ["CMakeLists.txt"], + swiftSettings: [ + // TODO: Does not compile with Swift 6 in Swift 6 mode due to Swift concurrency bugs. Remove once swift-tools-version is bumped to 6.1. + .swiftLanguageMode(.v5) + ] ), .target( name: "_SwiftFormatTestSupport", @@ -121,6 +125,34 @@ var targets: [Target] = [ ), ] +// Apply global Swift settings to targets. +do { + var globalSwiftSettings: [SwiftSetting] = [ + // Swift 7 mode upcoming features. These must be compatible with 'swift-tools-version'. + .enableUpcomingFeature("ExistentialAny"), + .enableUpcomingFeature("InternalImportsByDefault"), + .enableUpcomingFeature("MemberImportVisibility"), + .enableUpcomingFeature("NonisolatedNonsendingByDefault"), + ] + + #if compiler(>=6.1) + globalSwiftSettings.append( + .unsafeFlags(["-Werror", "ExistentialAny"]) + ) + #endif + + globalSwiftSettings += [] // avoid unused warning + + for target in targets where target.type != .plugin { + if let swiftSettings = target.swiftSettings { + // Target-specific settings should come last. + target.swiftSettings = globalSwiftSettings + swiftSettings + } else { + target.swiftSettings = globalSwiftSettings + } + } +} + if buildOnlyTests { products = [] let allowedNames: Set = ["_SwiftFormatTestSupport", "_GenerateSwiftFormat"] @@ -146,9 +178,11 @@ let package = Package( ], products: products, dependencies: dependencies, - targets: targets + targets: targets, + swiftLanguageModes: [.v5, .v6] ) +@MainActor func swiftSyntaxDependencies(_ names: [String]) -> [Target.Dependency] { if buildDynamicSwiftSyntaxLibrary { return [.product(name: "_SwiftSyntaxDynamic", package: "swift-syntax")] diff --git a/Sources/SwiftFormat/API/Configuration.swift b/Sources/SwiftFormat/API/Configuration.swift index 8fef820c5..e733db61f 100644 --- a/Sources/SwiftFormat/API/Configuration.swift +++ b/Sources/SwiftFormat/API/Configuration.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import Foundation +public import Foundation /// A version number that can be specified in the configuration file, which allows us to change the /// format in the future if desired and still support older files. @@ -22,7 +22,7 @@ import Foundation internal let highestSupportedConfigurationVersion = 1 /// Holds the complete set of configured values and defaults. -public struct Configuration: Codable, Equatable { +public struct Configuration: Codable, Equatable, Sendable { private enum CodingKeys: CodingKey { case version @@ -176,7 +176,7 @@ public struct Configuration: Codable, Equatable { public var noAssignmentInExpressions: NoAssignmentInExpressionsConfiguration /// Determines how trailing commas in comma-separated lists should be handled during formatting. - public enum MultilineTrailingCommaBehavior: String, Codable { + public enum MultilineTrailingCommaBehavior: String, Codable, Sendable { case alwaysUsed case neverUsed case keptAsWritten @@ -215,7 +215,7 @@ public struct Configuration: Codable, Equatable { public var multiElementCollectionTrailingCommas: Bool /// Determines how multiline string literals should reflow when formatted. - public enum MultilineStringReflowBehavior: String, Codable { + public enum MultilineStringReflowBehavior: String, Codable, Sendable { /// Never reflow multiline string literals. case never /// Reflow lines in string literal that exceed the maximum line length. For example with a line length of 10: @@ -320,7 +320,7 @@ public struct Configuration: Codable, Equatable { self = try jsonDecoder.decode(Configuration.self, from: data) } - public init(from decoder: Decoder) throws { + public init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // If the version number is not present, assume it is 1. @@ -463,7 +463,7 @@ public struct Configuration: Codable, Equatable { ?? defaults.rules } - public func encode(to encoder: Encoder) throws { + public func encode(to encoder: any Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(version, forKey: .version) @@ -524,8 +524,8 @@ public struct Configuration: Codable, Equatable { } /// Configuration for the `FileScopedDeclarationPrivacy` rule. -public struct FileScopedDeclarationPrivacyConfiguration: Codable, Equatable { - public enum AccessLevel: String, Codable { +public struct FileScopedDeclarationPrivacyConfiguration: Codable, Equatable, Sendable { + public enum AccessLevel: String, Codable, Sendable { /// Private file-scoped declarations should be declared `private`. /// /// If a file-scoped declaration is declared `fileprivate`, it will be diagnosed (in lint mode) @@ -547,7 +547,7 @@ public struct FileScopedDeclarationPrivacyConfiguration: Codable, Equatable { } /// Configuration for the `NoAssignmentInExpressions` rule. -public struct NoAssignmentInExpressionsConfiguration: Codable, Equatable { +public struct NoAssignmentInExpressionsConfiguration: Codable, Equatable, Sendable { /// A list of function names where assignments are allowed to be embedded in expressions that are /// passed as parameters to that function. public var allowedFunctions: [String] = [ @@ -561,7 +561,7 @@ public struct NoAssignmentInExpressionsConfiguration: Codable, Equatable { } /// Configuration for the `OrderedImports` rule. -public struct OrderedImportsConfiguration: Codable, Equatable { +public struct OrderedImportsConfiguration: Codable, Equatable, Sendable { /// Determines whether imports within conditional compilation blocks should be ordered. public var includeConditionalImports: Bool = false diff --git a/Sources/SwiftFormat/API/DebugOptions.swift b/Sources/SwiftFormat/API/DebugOptions.swift index e12790df0..074bad198 100644 --- a/Sources/SwiftFormat/API/DebugOptions.swift +++ b/Sources/SwiftFormat/API/DebugOptions.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ /// Advanced options that are useful when debugging and developing the formatter, but are otherwise /// not meant for general use. -public struct DebugOptions: OptionSet { +public struct DebugOptions: OptionSet, Sendable { /// Disables the pretty-printer pass entirely, executing only the syntax-transforming rules in the /// pipeline. diff --git a/Sources/SwiftFormat/API/Finding.swift b/Sources/SwiftFormat/API/Finding.swift index 7a9399cb9..f29058ef7 100644 --- a/Sources/SwiftFormat/API/Finding.swift +++ b/Sources/SwiftFormat/API/Finding.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -39,7 +39,7 @@ public struct Finding { /// an `extension` of the `Finding.Message` type and add `static` properties or functions of type /// `Finding.Message`; these can be initialized using string literals or string interpolations. public struct Message: - CustomStringConvertible, ExpressibleByStringLiteral, ExpressibleByStringInterpolation + CustomStringConvertible, ExpressibleByStringLiteral, ExpressibleByStringInterpolation, Sendable { /// The message text of the diagnostic. public var text: String @@ -71,7 +71,7 @@ public struct Finding { } /// The category associated with the finding. - public let category: FindingCategorizing + public let category: any FindingCategorizing /// The finding's message. public let message: Message @@ -85,7 +85,7 @@ public struct Finding { /// Creates a new finding with the given category, message, optional location, and /// notes. init( - category: FindingCategorizing, + category: any FindingCategorizing, message: Message, location: Location? = nil, notes: [Note] = [] diff --git a/Sources/SwiftFormat/API/Indent.swift b/Sources/SwiftFormat/API/Indent.swift index 5039da135..55c2b0618 100644 --- a/Sources/SwiftFormat/API/Indent.swift +++ b/Sources/SwiftFormat/API/Indent.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// /// Represents an indentation unit that is applied to lines that are pretty-printed. -public enum Indent: Hashable, Codable { +public enum Indent: Hashable, Codable, Sendable { /// An indentation unit equal to the given number of tab characters. /// @@ -27,7 +27,7 @@ public enum Indent: Hashable, Codable { case spaces } - public init(from decoder: Decoder) throws { + public init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let spacesCount = try container.decodeIfPresent(Int.self, forKey: .spaces) let tabsCount = try container.decodeIfPresent(Int.self, forKey: .tabs) @@ -57,7 +57,7 @@ public enum Indent: Hashable, Codable { ) } - public func encode(to encoder: Encoder) throws { + public func encode(to encoder: any Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .tabs(let count): diff --git a/Sources/SwiftFormat/API/Selection.swift b/Sources/SwiftFormat/API/Selection.swift index 2e7d00109..bb1313ca3 100644 --- a/Sources/SwiftFormat/API/Selection.swift +++ b/Sources/SwiftFormat/API/Selection.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2024 Apple Inc. and the Swift project authors +// Copyright (c) 2024 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,10 +11,10 @@ //===----------------------------------------------------------------------===// import Foundation -import SwiftSyntax +public import SwiftSyntax /// The selection as given on the command line - an array of offets and lengths -public enum Selection { +public enum Selection: Sendable { case infinite case ranges([Range]) diff --git a/Sources/SwiftFormat/API/SwiftFormatError.swift b/Sources/SwiftFormat/API/SwiftFormatError.swift index 5dd2a6e69..6791dd5d5 100644 --- a/Sources/SwiftFormat/API/SwiftFormatError.swift +++ b/Sources/SwiftFormat/API/SwiftFormatError.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import Foundation +public import Foundation import SwiftSyntax /// Errors that can be thrown by the `SwiftFormatter` and `SwiftLinter` APIs. diff --git a/Sources/SwiftFormat/API/SwiftFormatter.swift b/Sources/SwiftFormat/API/SwiftFormatter.swift index 6e06015cf..ab73ad891 100644 --- a/Sources/SwiftFormat/API/SwiftFormatter.swift +++ b/Sources/SwiftFormat/API/SwiftFormatter.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,10 +10,10 @@ // //===----------------------------------------------------------------------===// -import Foundation -import SwiftDiagnostics -import SwiftOperators -import SwiftSyntax +public import Foundation +public import SwiftDiagnostics +public import SwiftOperators +public import SwiftSyntax /// Formats Swift source code or syntax trees according to the Swift style guidelines. public final class SwiftFormatter { diff --git a/Sources/SwiftFormat/API/SwiftLinter.swift b/Sources/SwiftFormat/API/SwiftLinter.swift index d70f30673..b4263f2ec 100644 --- a/Sources/SwiftFormat/API/SwiftLinter.swift +++ b/Sources/SwiftFormat/API/SwiftLinter.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,10 +10,10 @@ // //===----------------------------------------------------------------------===// -import Foundation -import SwiftDiagnostics -import SwiftOperators -import SwiftSyntax +public import Foundation +public import SwiftDiagnostics +public import SwiftOperators +public import SwiftSyntax /// Diagnoses and reports problems in Swift source code or syntax trees according to the Swift style /// guidelines. diff --git a/Sources/SwiftFormat/Core/Context.swift b/Sources/SwiftFormat/Core/Context.swift index e00e38b20..5783281c9 100644 --- a/Sources/SwiftFormat/Core/Context.swift +++ b/Sources/SwiftFormat/Core/Context.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,10 +10,10 @@ // //===----------------------------------------------------------------------===// -import Foundation -import SwiftOperators +public import Foundation +public import SwiftOperators import SwiftParser -import SwiftSyntax +public import SwiftSyntax /// Context contains the bits that each formatter and linter will need access to. /// diff --git a/Sources/SwiftFormat/Core/DocumentationComment.swift b/Sources/SwiftFormat/Core/DocumentationComment.swift index d89b4c1c6..d47c0607d 100644 --- a/Sources/SwiftFormat/Core/DocumentationComment.swift +++ b/Sources/SwiftFormat/Core/DocumentationComment.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,8 +10,9 @@ // //===----------------------------------------------------------------------===// -import Markdown -import SwiftSyntax +import Foundation +public import Markdown +public import SwiftSyntax /// A structured representation of information extracted from a documentation comment. /// @@ -55,7 +56,7 @@ public struct DocumentationComment { /// /// If a brief summary paragraph was extracted from the comment, it will not be present in this /// collection. - public var bodyNodes: [Markup] = [] + public var bodyNodes: [any Markup] = [] /// The structural layout of the parameter descriptions in the comment. public var parameterLayout: ParameterLayout? = nil @@ -94,7 +95,7 @@ public struct DocumentationComment { } /// Creates a new `DocumentationComment` from the given `Markup` node. - private init(markup: Markup) { + private init(markup: any Markup) { // Extract the first paragraph as the brief summary. It will *not* be included in the body // nodes. let remainingChildren: DropFirstSequence @@ -143,7 +144,7 @@ public struct DocumentationComment { /// If parameters were successfully extracted, the provided list is mutated to remove them as a /// side effect of this function. private mutating func extractParameterOutline(from list: inout UnorderedList) { - var unprocessedChildren: [Markup] = [] + var unprocessedChildren: [any Markup] = [] for child in list.children { guard @@ -182,7 +183,7 @@ public struct DocumentationComment { /// If parameters were successfully extracted, the provided list is mutated to remove them as a /// side effect of this function. private mutating func extractSeparatedParameters(from list: inout UnorderedList) { - var unprocessedChildren: [Markup] = [] + var unprocessedChildren: [any Markup] = [] for child in list.children { guard @@ -231,7 +232,7 @@ public struct DocumentationComment { /// /// If fields were successfully extracted, the provided list is mutated to remove them. private mutating func extractSimpleFields(from list: inout UnorderedList) { - var unprocessedChildren: [Markup] = [] + var unprocessedChildren: [any Markup] = [] for child in list.children { guard @@ -271,19 +272,19 @@ private struct ParameterOutlineMarkupRewriter: MarkupRewriter { /// Populated if the list item to which this is applied represents a valid parameter field. private(set) var parameterName: String? = nil - mutating func visitListItem(_ listItem: ListItem) -> Markup? { + mutating func visitListItem(_ listItem: ListItem) -> (any Markup)? { // Only recurse into the exact list item we're applying this to; otherwise, return it unchanged. guard listItem.isIdentical(to: origin) else { return listItem } return defaultVisit(listItem) } - mutating func visitParagraph(_ paragraph: Paragraph) -> Markup? { + mutating func visitParagraph(_ paragraph: Paragraph) -> (any Markup)? { // Only recurse into the first paragraph in the list item. guard paragraph.indexInParent == 0 else { return paragraph } return defaultVisit(paragraph) } - mutating func visitText(_ text: Text) -> Markup? { + mutating func visitText(_ text: Text) -> (any Markup)? { // Only manipulate the first text node (of the first paragraph). guard text.indexInParent == 0 else { return text } @@ -315,13 +316,13 @@ private struct SimpleFieldMarkupRewriter: MarkupRewriter { /// Populated if the list item to which this is applied represents a valid simple field. private(set) var paragraph: Paragraph? = nil - mutating func visitListItem(_ listItem: ListItem) -> Markup? { + mutating func visitListItem(_ listItem: ListItem) -> (any Markup)? { // Only recurse into the exact list item we're applying this to; otherwise, return it unchanged. guard listItem.isIdentical(to: origin) else { return listItem } return defaultVisit(listItem) } - mutating func visitParagraph(_ paragraph: Paragraph) -> Markup? { + mutating func visitParagraph(_ paragraph: Paragraph) -> (any Markup)? { // Only recurse into the first paragraph in the list item. guard paragraph.indexInParent == 0 else { return paragraph } guard let newNode = defaultVisit(paragraph) else { return nil } @@ -330,7 +331,7 @@ private struct SimpleFieldMarkupRewriter: MarkupRewriter { return newParagraph } - mutating func visitText(_ text: Text) -> Markup? { + mutating func visitText(_ text: Text) -> (any Markup)? { // Only manipulate the first text node (of the first paragraph). guard text.indexInParent == 0 else { return text } diff --git a/Sources/SwiftFormat/Core/DocumentationCommentText.swift b/Sources/SwiftFormat/Core/DocumentationCommentText.swift index 8fbf61873..01a83badc 100644 --- a/Sources/SwiftFormat/Core/DocumentationCommentText.swift +++ b/Sources/SwiftFormat/Core/DocumentationCommentText.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// The text contents of a documentation comment extracted from trivia. /// diff --git a/Sources/SwiftFormat/Core/FindingEmitter.swift b/Sources/SwiftFormat/Core/FindingEmitter.swift index 71dd8f83d..f85c54695 100644 --- a/Sources/SwiftFormat/Core/FindingEmitter.swift +++ b/Sources/SwiftFormat/Core/FindingEmitter.swift @@ -42,7 +42,7 @@ final class FindingEmitter { /// related locations in the source file. public func emit( _ message: Finding.Message, - category: FindingCategorizing, + category: any FindingCategorizing, location: Finding.Location? = nil, notes: [Finding.Note] = [] ) { diff --git a/Sources/SwiftFormat/Core/ImportsXCTestVisitor.swift b/Sources/SwiftFormat/Core/ImportsXCTestVisitor.swift index ed9e9750f..7718f631c 100644 --- a/Sources/SwiftFormat/Core/ImportsXCTestVisitor.swift +++ b/Sources/SwiftFormat/Core/ImportsXCTestVisitor.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// A visitor that determines if the target source file imports `XCTest`. private class ImportsXCTestVisitor: SyntaxVisitor { diff --git a/Sources/SwiftFormat/Core/Pipelines+Generated.swift b/Sources/SwiftFormat/Core/Pipelines+Generated.swift index 54f843549..7f41a1e31 100644 --- a/Sources/SwiftFormat/Core/Pipelines+Generated.swift +++ b/Sources/SwiftFormat/Core/Pipelines+Generated.swift @@ -24,11 +24,11 @@ class LintPipeline: SyntaxVisitor { /// Stores lint and format rule instances, indexed by the `ObjectIdentifier` of a rule's /// class type. - var ruleCache = [ObjectIdentifier: Rule]() + var ruleCache = [ObjectIdentifier: any Rule]() /// Rules present in this dictionary skip visiting children until they leave the /// syntax node stored as their value - var shouldSkipChildren = [ObjectIdentifier: SyntaxProtocol]() + var shouldSkipChildren = [ObjectIdentifier: any SyntaxProtocol]() /// Creates a new lint pipeline. init(context: Context) { diff --git a/Sources/SwiftFormat/Core/Rule.swift b/Sources/SwiftFormat/Core/Rule.swift index 764aa45e3..bfe2ff877 100644 --- a/Sources/SwiftFormat/Core/Rule.swift +++ b/Sources/SwiftFormat/Core/Rule.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// import Foundation -import SwiftSyntax +public import SwiftSyntax /// A Rule is a linting or formatting pass that executes in a given context. @_spi(Rules) diff --git a/Sources/SwiftFormat/Core/RuleBasedFindingCategory.swift b/Sources/SwiftFormat/Core/RuleBasedFindingCategory.swift index 03a2f4541..52f7ad206 100644 --- a/Sources/SwiftFormat/Core/RuleBasedFindingCategory.swift +++ b/Sources/SwiftFormat/Core/RuleBasedFindingCategory.swift @@ -18,12 +18,12 @@ /// defaults to the rule's type name). struct RuleBasedFindingCategory: FindingCategorizing { /// The type of the rule associated with this category. - private let ruleType: Rule.Type + private let ruleType: any Rule.Type var description: String { ruleType.ruleName } /// Creates a finding category that wraps the given rule type. - init(ruleType: Rule.Type) { + init(ruleType: any Rule.Type) { self.ruleType = ruleType } } diff --git a/Sources/SwiftFormat/Core/RuleMask.swift b/Sources/SwiftFormat/Core/RuleMask.swift index 976d8ee62..62b47bfef 100644 --- a/Sources/SwiftFormat/Core/RuleMask.swift +++ b/Sources/SwiftFormat/Core/RuleMask.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// import Foundation -import SwiftSyntax +public import SwiftSyntax /// This class takes the raw source text and scans through it searching for comments that instruct /// the formatter to change the status of rules for the following node. The comments may include no @@ -124,6 +124,9 @@ enum IgnoreDirective: CustomStringConvertible { } } +// This regex is thread-safe. +extension IgnoreDirective.RegexExpression: @unchecked @retroactive Sendable {} + /// A syntax visitor that finds `SourceRange`s of nodes that have rule status modifying comment /// directives. The changes requested in each comment is parsed and collected into a map to support /// status lookup per rule name. diff --git a/Sources/SwiftFormat/Core/SyntaxFormatRule.swift b/Sources/SwiftFormat/Core/SyntaxFormatRule.swift index 92fc7c835..bbcac0c76 100644 --- a/Sources/SwiftFormat/Core/SyntaxFormatRule.swift +++ b/Sources/SwiftFormat/Core/SyntaxFormatRule.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// A rule that both formats and lints a given file. @_spi(Rules) diff --git a/Sources/SwiftFormat/Core/SyntaxLintRule.swift b/Sources/SwiftFormat/Core/SyntaxLintRule.swift index 696cfcb8a..f5e357e0f 100644 --- a/Sources/SwiftFormat/Core/SyntaxLintRule.swift +++ b/Sources/SwiftFormat/Core/SyntaxLintRule.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// import Foundation -import SwiftSyntax +public import SwiftSyntax /// A rule that lints a given file. @_spi(Rules) diff --git a/Sources/SwiftFormat/Core/SyntaxTraits.swift b/Sources/SwiftFormat/Core/SyntaxTraits.swift index 7c64cca52..6b4801474 100644 --- a/Sources/SwiftFormat/Core/SyntaxTraits.swift +++ b/Sources/SwiftFormat/Core/SyntaxTraits.swift @@ -21,20 +21,20 @@ extension FunctionCallExprSyntax: CallingExprSyntaxProtocol {} extension SubscriptCallExprSyntax: CallingExprSyntaxProtocol {} extension Syntax { - func asProtocol(_: CallingExprSyntaxProtocol.Protocol) -> CallingExprSyntaxProtocol? { - return self.asProtocol(SyntaxProtocol.self) as? CallingExprSyntaxProtocol + func asProtocol(_: (any CallingExprSyntaxProtocol).Protocol) -> (any CallingExprSyntaxProtocol)? { + return self.asProtocol((any SyntaxProtocol).self) as? (any CallingExprSyntaxProtocol) } - func isProtocol(_: CallingExprSyntaxProtocol.Protocol) -> Bool { - return self.asProtocol(CallingExprSyntaxProtocol.self) != nil + func isProtocol(_: (any CallingExprSyntaxProtocol).Protocol) -> Bool { + return self.asProtocol((any CallingExprSyntaxProtocol).self) != nil } } extension ExprSyntax { - func asProtocol(_: CallingExprSyntaxProtocol.Protocol) -> CallingExprSyntaxProtocol? { - return Syntax(self).asProtocol(SyntaxProtocol.self) as? CallingExprSyntaxProtocol + func asProtocol(_: (any CallingExprSyntaxProtocol).Protocol) -> (any CallingExprSyntaxProtocol)? { + return Syntax(self).asProtocol((any SyntaxProtocol).self) as? (any CallingExprSyntaxProtocol) } - func isProtocol(_: CallingExprSyntaxProtocol.Protocol) -> Bool { - return self.asProtocol(CallingExprSyntaxProtocol.self) != nil + func isProtocol(_: (any CallingExprSyntaxProtocol).Protocol) -> Bool { + return self.asProtocol((any CallingExprSyntaxProtocol).self) != nil } } @@ -49,20 +49,20 @@ extension TryExprSyntax: KeywordModifiedExprSyntaxProtocol {} extension UnsafeExprSyntax: KeywordModifiedExprSyntaxProtocol {} extension Syntax { - func asProtocol(_: KeywordModifiedExprSyntaxProtocol.Protocol) -> KeywordModifiedExprSyntaxProtocol? { - return self.asProtocol(SyntaxProtocol.self) as? KeywordModifiedExprSyntaxProtocol + func asProtocol(_: (any KeywordModifiedExprSyntaxProtocol).Protocol) -> (any KeywordModifiedExprSyntaxProtocol)? { + return self.asProtocol((any SyntaxProtocol).self) as? (any KeywordModifiedExprSyntaxProtocol) } - func isProtocol(_: KeywordModifiedExprSyntaxProtocol.Protocol) -> Bool { - return self.asProtocol(KeywordModifiedExprSyntaxProtocol.self) != nil + func isProtocol(_: (any KeywordModifiedExprSyntaxProtocol).Protocol) -> Bool { + return self.asProtocol((any KeywordModifiedExprSyntaxProtocol).self) != nil } } extension ExprSyntax { - func asProtocol(_: KeywordModifiedExprSyntaxProtocol.Protocol) -> KeywordModifiedExprSyntaxProtocol? { - return Syntax(self).asProtocol(SyntaxProtocol.self) as? KeywordModifiedExprSyntaxProtocol + func asProtocol(_: (any KeywordModifiedExprSyntaxProtocol).Protocol) -> (any KeywordModifiedExprSyntaxProtocol)? { + return Syntax(self).asProtocol((any SyntaxProtocol).self) as? (any KeywordModifiedExprSyntaxProtocol) } - func isProtocol(_: KeywordModifiedExprSyntaxProtocol.Protocol) -> Bool { - return self.asProtocol(KeywordModifiedExprSyntaxProtocol.self) != nil + func isProtocol(_: (any KeywordModifiedExprSyntaxProtocol).Protocol) -> Bool { + return self.asProtocol((any KeywordModifiedExprSyntaxProtocol).self) != nil } } @@ -70,20 +70,20 @@ extension ExprSyntax { /// support a `trailingComma`. protocol CommaSeparatedListSyntaxProtocol: SyntaxCollection where Element: WithTrailingCommaSyntax & Equatable { /// The node used for trailing comma handling; inserted immediately after this node. - var lastNodeForTrailingComma: SyntaxProtocol? { get } + var lastNodeForTrailingComma: (any SyntaxProtocol)? { get } } extension ArrayElementListSyntax: CommaSeparatedListSyntaxProtocol { - var lastNodeForTrailingComma: SyntaxProtocol? { last?.expression } + var lastNodeForTrailingComma: (any SyntaxProtocol)? { last?.expression } } extension DictionaryElementListSyntax: CommaSeparatedListSyntaxProtocol { - var lastNodeForTrailingComma: SyntaxProtocol? { last } + var lastNodeForTrailingComma: (any SyntaxProtocol)? { last } } extension LabeledExprListSyntax: CommaSeparatedListSyntaxProtocol { - var lastNodeForTrailingComma: SyntaxProtocol? { last?.expression } + var lastNodeForTrailingComma: (any SyntaxProtocol)? { last?.expression } } extension ClosureCaptureListSyntax: CommaSeparatedListSyntaxProtocol { - var lastNodeForTrailingComma: SyntaxProtocol? { + var lastNodeForTrailingComma: (any SyntaxProtocol)? { if let initializer = last?.initializer { return initializer } else { @@ -92,7 +92,7 @@ extension ClosureCaptureListSyntax: CommaSeparatedListSyntaxProtocol { } } extension EnumCaseParameterListSyntax: CommaSeparatedListSyntaxProtocol { - var lastNodeForTrailingComma: SyntaxProtocol? { + var lastNodeForTrailingComma: (any SyntaxProtocol)? { if let defaultValue = last?.defaultValue { return defaultValue } else { @@ -101,7 +101,7 @@ extension EnumCaseParameterListSyntax: CommaSeparatedListSyntaxProtocol { } } extension FunctionParameterListSyntax: CommaSeparatedListSyntaxProtocol { - var lastNodeForTrailingComma: SyntaxProtocol? { + var lastNodeForTrailingComma: (any SyntaxProtocol)? { if let defaultValue = last?.defaultValue { return defaultValue } else if let ellipsis = last?.ellipsis { @@ -112,7 +112,7 @@ extension FunctionParameterListSyntax: CommaSeparatedListSyntaxProtocol { } } extension GenericParameterListSyntax: CommaSeparatedListSyntaxProtocol { - var lastNodeForTrailingComma: SyntaxProtocol? { + var lastNodeForTrailingComma: (any SyntaxProtocol)? { if let inheritedType = last?.inheritedType { return inheritedType } else { @@ -121,12 +121,12 @@ extension GenericParameterListSyntax: CommaSeparatedListSyntaxProtocol { } } extension TuplePatternElementListSyntax: CommaSeparatedListSyntaxProtocol { - var lastNodeForTrailingComma: SyntaxProtocol? { last?.pattern } + var lastNodeForTrailingComma: (any SyntaxProtocol)? { last?.pattern } } extension SyntaxProtocol { func asProtocol(_: (any CommaSeparatedListSyntaxProtocol).Protocol) -> (any CommaSeparatedListSyntaxProtocol)? { - return Syntax(self).asProtocol(SyntaxProtocol.self) as? (any CommaSeparatedListSyntaxProtocol) + return Syntax(self).asProtocol((any SyntaxProtocol).self) as? (any CommaSeparatedListSyntaxProtocol) } func isProtocol(_: (any CommaSeparatedListSyntaxProtocol).Protocol) -> Bool { return self.asProtocol((any CommaSeparatedListSyntaxProtocol).self) != nil diff --git a/Sources/SwiftFormat/Core/WithSemicolonSyntax.swift b/Sources/SwiftFormat/Core/WithSemicolonSyntax.swift index 42ac7ce42..3cf7c90b8 100644 --- a/Sources/SwiftFormat/Core/WithSemicolonSyntax.swift +++ b/Sources/SwiftFormat/Core/WithSemicolonSyntax.swift @@ -21,11 +21,11 @@ extension MemberBlockItemSyntax: WithSemicolonSyntax {} extension CodeBlockItemSyntax: WithSemicolonSyntax {} extension SyntaxProtocol { - func asProtocol(_: WithSemicolonSyntax.Protocol) -> WithSemicolonSyntax? { - return Syntax(self).asProtocol(SyntaxProtocol.self) as? WithSemicolonSyntax + func asProtocol(_: (any WithSemicolonSyntax).Protocol) -> (any WithSemicolonSyntax)? { + return Syntax(self).asProtocol((any SyntaxProtocol).self) as? (any WithSemicolonSyntax) } - func isProtocol(_: WithSemicolonSyntax.Protocol) -> Bool { - return self.asProtocol(WithSemicolonSyntax.self) != nil + func isProtocol(_: (any WithSemicolonSyntax).Protocol) -> Bool { + return self.asProtocol((any WithSemicolonSyntax).self) != nil } } diff --git a/Sources/SwiftFormat/PrettyPrint/PrettyPrint.swift b/Sources/SwiftFormat/PrettyPrint/PrettyPrint.swift index 69329f3b0..bf5c53b73 100644 --- a/Sources/SwiftFormat/PrettyPrint/PrettyPrint.swift +++ b/Sources/SwiftFormat/PrettyPrint/PrettyPrint.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// import Foundation -import SwiftSyntax +public import SwiftSyntax /// PrettyPrinter takes a Syntax node and outputs a well-formatted, re-indented reproduction of the /// code as a String. diff --git a/Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift b/Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift index f56f50e6d..5d17d24ab 100644 --- a/Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift +++ b/Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift @@ -1048,7 +1048,7 @@ private final class TokenStreamCreator: SyntaxVisitor { // when visiting that wrapping expression is sufficient. Adding another group here in that // case can result in unnecessarily breaking after the modifier keyword. if !(base.firstToken(viewMode: .sourceAccurate)?.previousToken(viewMode: .all)?.parent?.isProtocol( - KeywordModifiedExprSyntaxProtocol.self + (any KeywordModifiedExprSyntaxProtocol).self ) ?? false) { before(base.firstToken(viewMode: .sourceAccurate), tokens: .open) after(calledMemberAccessExpr.declName.baseName.lastToken(viewMode: .sourceAccurate), tokens: .close) @@ -1789,7 +1789,7 @@ private final class TokenStreamCreator: SyntaxVisitor { // Check for an anchor token inside of the expression to end a group starting with the `try` // keyword. - if !(node.parent?.isProtocol(KeywordModifiedExprSyntaxProtocol.self) ?? false), + if !(node.parent?.isProtocol((any KeywordModifiedExprSyntaxProtocol).self) ?? false), let anchorToken = connectingTokenForKeywordModifiedExpr(inSubExpr: node.expression) { before(node.tryKeyword, tokens: .open) @@ -1807,7 +1807,7 @@ private final class TokenStreamCreator: SyntaxVisitor { // Check for an anchor token inside of the expression to end a group starting with the `await` // keyword. - if !(node.parent?.isProtocol(KeywordModifiedExprSyntaxProtocol.self) ?? false), + if !(node.parent?.isProtocol((any KeywordModifiedExprSyntaxProtocol).self) ?? false), let anchorToken = connectingTokenForKeywordModifiedExpr(inSubExpr: node.expression) { before(node.awaitKeyword, tokens: .open) @@ -1824,7 +1824,7 @@ private final class TokenStreamCreator: SyntaxVisitor { // Check for an anchor token inside of the expression to end a group starting with the `unsafe` // keyword. - if !(node.parent?.isProtocol(KeywordModifiedExprSyntaxProtocol.self) ?? false), + if !(node.parent?.isProtocol((any KeywordModifiedExprSyntaxProtocol).self) ?? false), let anchorToken = connectingTokenForKeywordModifiedExpr(inSubExpr: node.expression) { before(node.unsafeKeyword, tokens: .open) @@ -1841,12 +1841,12 @@ private final class TokenStreamCreator: SyntaxVisitor { /// - Returns: The token that should end the group that is started by the modifier keyword, or /// nil if there should be no group. func connectingTokenForKeywordModifiedExpr(inSubExpr expr: ExprSyntax) -> TokenSyntax? { - if let modifiedExpr = expr.asProtocol(KeywordModifiedExprSyntaxProtocol.self) { + if let modifiedExpr = expr.asProtocol((any KeywordModifiedExprSyntaxProtocol).self) { // If we were called from a keyword-modified expression like `try`, `await`, or `unsafe`, // recursively drill into the child expression. return connectingTokenForKeywordModifiedExpr(inSubExpr: modifiedExpr.expression) } - if let callingExpr = expr.asProtocol(CallingExprSyntaxProtocol.self) { + if let callingExpr = expr.asProtocol((any CallingExprSyntaxProtocol).self) { return connectingTokenForKeywordModifiedExpr(inSubExpr: callingExpr.calledExpression) } if let memberAccessExpr = expr.as(MemberAccessExprSyntax.self), let base = memberAccessExpr.base { @@ -3903,7 +3903,7 @@ private final class TokenStreamCreator: SyntaxVisitor { /// that are known to wrap an expression, e.g. try expressions, are handled by checking the /// expression that they contain. private func isCompoundExpression(_ expr: ExprSyntax) -> Bool { - if let modifiedExpr = expr.asProtocol(KeywordModifiedExprSyntaxProtocol.self) { + if let modifiedExpr = expr.asProtocol((any KeywordModifiedExprSyntaxProtocol).self) { return isCompoundExpression(modifiedExpr.expression) } switch Syntax(expr).as(SyntaxEnum.self) { @@ -4262,7 +4262,7 @@ private final class TokenStreamCreator: SyntaxVisitor { // When the member access is part of a calling expression, the break before the dot is // inserted when visiting the parent node instead so that the break is inserted before any // scoping tokens (e.g. `contextualBreakingStart`, `open`). - if memberAccessExpr.base != nil && expr.parent?.isProtocol(CallingExprSyntaxProtocol.self) != true { + if memberAccessExpr.base != nil && expr.parent?.isProtocol((any CallingExprSyntaxProtocol).self) != true { before(memberAccessExpr.period, tokens: .break(.contextual, size: 0)) } var hasCompoundExpression = false @@ -4292,7 +4292,7 @@ private final class TokenStreamCreator: SyntaxVisitor { after(postfixIfExpr.config.poundEndif, tokens: .break(.same, size: 0)) return insertContextualBreaks(base, isTopLevel: false) - } else if let callingExpr = expr.asProtocol(CallingExprSyntaxProtocol.self) { + } else if let callingExpr = expr.asProtocol((any CallingExprSyntaxProtocol).self) { let calledExpression = callingExpr.calledExpression let (hasCompoundExpression, hasMemberAccess) = insertContextualBreaks(calledExpression, isTopLevel: false) diff --git a/Sources/SwiftFormat/Rules/AllPublicDeclarationsHaveDocumentation.swift b/Sources/SwiftFormat/Rules/AllPublicDeclarationsHaveDocumentation.swift index feaa3a550..2cd0c7b4c 100644 --- a/Sources/SwiftFormat/Rules/AllPublicDeclarationsHaveDocumentation.swift +++ b/Sources/SwiftFormat/Rules/AllPublicDeclarationsHaveDocumentation.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// All public or open declarations must have a top-level documentation comment. /// diff --git a/Sources/SwiftFormat/Rules/AlwaysUseLiteralForEmptyCollectionInit.swift b/Sources/SwiftFormat/Rules/AlwaysUseLiteralForEmptyCollectionInit.swift index 124ad63f7..4b18540cf 100644 --- a/Sources/SwiftFormat/Rules/AlwaysUseLiteralForEmptyCollectionInit.swift +++ b/Sources/SwiftFormat/Rules/AlwaysUseLiteralForEmptyCollectionInit.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ import Foundation import SwiftParser -import SwiftSyntax +public import SwiftSyntax /// Never use `[]()` syntax. In call sites that should be replaced with `[]`, /// for initializations use explicit type combined with empty array literal `let _: [] = []` diff --git a/Sources/SwiftFormat/Rules/AlwaysUseLowerCamelCase.swift b/Sources/SwiftFormat/Rules/AlwaysUseLowerCamelCase.swift index bbd47d74d..c203b7985 100644 --- a/Sources/SwiftFormat/Rules/AlwaysUseLowerCamelCase.swift +++ b/Sources/SwiftFormat/Rules/AlwaysUseLowerCamelCase.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// All values should be written in lower camel-case (`lowerCamelCase`). /// Underscores (except at the beginning of an identifier) are disallowed. diff --git a/Sources/SwiftFormat/Rules/AmbiguousTrailingClosureOverload.swift b/Sources/SwiftFormat/Rules/AmbiguousTrailingClosureOverload.swift index 72eb28cc3..186515659 100644 --- a/Sources/SwiftFormat/Rules/AmbiguousTrailingClosureOverload.swift +++ b/Sources/SwiftFormat/Rules/AmbiguousTrailingClosureOverload.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Overloads with only a closure argument should not be disambiguated by parameter labels. /// diff --git a/Sources/SwiftFormat/Rules/AvoidRetroactiveConformances.swift b/Sources/SwiftFormat/Rules/AvoidRetroactiveConformances.swift index 1573d3de2..dd82299d9 100644 --- a/Sources/SwiftFormat/Rules/AvoidRetroactiveConformances.swift +++ b/Sources/SwiftFormat/Rules/AvoidRetroactiveConformances.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// `@retroactive` conformances are forbidden. /// diff --git a/Sources/SwiftFormat/Rules/BeginDocumentationCommentWithOneLineSummary.swift b/Sources/SwiftFormat/Rules/BeginDocumentationCommentWithOneLineSummary.swift index 09fdb92ad..888c64715 100644 --- a/Sources/SwiftFormat/Rules/BeginDocumentationCommentWithOneLineSummary.swift +++ b/Sources/SwiftFormat/Rules/BeginDocumentationCommentWithOneLineSummary.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ import Foundation import Markdown -import SwiftSyntax +public import SwiftSyntax #if os(macOS) import NaturalLanguage @@ -29,7 +29,7 @@ public final class BeginDocumentationCommentWithOneLineSummary: SyntaxLintRule { /// even on platforms that support the latter (currently only Apple OSes). /// /// This allows test runs on those platforms to test both implementations. - public static var _forcesFallbackModeForTesting = false + nonisolated(unsafe) package static var _forcesFallbackModeForTesting = false /// Identifies this rule as being opt-in. Well written docs on declarations are important, but /// this rule isn't linguistically advanced enough on all platforms to be applied universally. @@ -240,7 +240,7 @@ extension Finding.Message { } struct InlineCodeRemover: MarkupRewriter { - mutating func visitInlineCode(_ inlineCode: InlineCode) -> Markup? { + mutating func visitInlineCode(_ inlineCode: InlineCode) -> (any Markup)? { nil } } diff --git a/Sources/SwiftFormat/Rules/DoNotUseSemicolons.swift b/Sources/SwiftFormat/Rules/DoNotUseSemicolons.swift index 7559d72ed..693cd5a30 100644 --- a/Sources/SwiftFormat/Rules/DoNotUseSemicolons.swift +++ b/Sources/SwiftFormat/Rules/DoNotUseSemicolons.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Semicolons should not be present in Swift code. /// @@ -109,7 +109,7 @@ public final class DoNotUseSemicolons: SyntaxFormatRule { /// given type. private func isCodeBlockItem( _ node: some SyntaxProtocol, - containingStmtType stmtType: StmtSyntaxProtocol.Type + containingStmtType stmtType: any StmtSyntaxProtocol.Type ) -> Bool { if let codeBlockItem = node.as(CodeBlockItemSyntax.self), case .stmt(let stmt) = codeBlockItem.item, diff --git a/Sources/SwiftFormat/Rules/DontRepeatTypeInStaticProperties.swift b/Sources/SwiftFormat/Rules/DontRepeatTypeInStaticProperties.swift index b56192cba..0e0f3fe7b 100644 --- a/Sources/SwiftFormat/Rules/DontRepeatTypeInStaticProperties.swift +++ b/Sources/SwiftFormat/Rules/DontRepeatTypeInStaticProperties.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,8 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +import Foundation +public import SwiftSyntax /// Static properties of a type that return that type should not include a reference to their type. /// diff --git a/Sources/SwiftFormat/Rules/FileScopedDeclarationPrivacy.swift b/Sources/SwiftFormat/Rules/FileScopedDeclarationPrivacy.swift index e0f9af4c5..79bd92e3c 100644 --- a/Sources/SwiftFormat/Rules/FileScopedDeclarationPrivacy.swift +++ b/Sources/SwiftFormat/Rules/FileScopedDeclarationPrivacy.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Declarations at file scope with effective private access should be consistently declared as /// either `fileprivate` or `private`, determined by configuration. diff --git a/Sources/SwiftFormat/Rules/FullyIndirectEnum.swift b/Sources/SwiftFormat/Rules/FullyIndirectEnum.swift index 53273f676..a0117d7af 100644 --- a/Sources/SwiftFormat/Rules/FullyIndirectEnum.swift +++ b/Sources/SwiftFormat/Rules/FullyIndirectEnum.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// If all cases of an enum are `indirect`, the entire enum should be marked `indirect`. /// diff --git a/Sources/SwiftFormat/Rules/GroupNumericLiterals.swift b/Sources/SwiftFormat/Rules/GroupNumericLiterals.swift index b29089efb..b713b20d3 100644 --- a/Sources/SwiftFormat/Rules/GroupNumericLiterals.swift +++ b/Sources/SwiftFormat/Rules/GroupNumericLiterals.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Numeric literals should be grouped with `_`s to delimit common separators. /// diff --git a/Sources/SwiftFormat/Rules/IdentifiersMustBeASCII.swift b/Sources/SwiftFormat/Rules/IdentifiersMustBeASCII.swift index 913dc2a06..6c09909c3 100644 --- a/Sources/SwiftFormat/Rules/IdentifiersMustBeASCII.swift +++ b/Sources/SwiftFormat/Rules/IdentifiersMustBeASCII.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// All identifiers must be ASCII. /// diff --git a/Sources/SwiftFormat/Rules/NeverForceUnwrap.swift b/Sources/SwiftFormat/Rules/NeverForceUnwrap.swift index f81c9953d..4655b69d9 100644 --- a/Sources/SwiftFormat/Rules/NeverForceUnwrap.swift +++ b/Sources/SwiftFormat/Rules/NeverForceUnwrap.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Force-unwraps are strongly discouraged and must be documented. /// diff --git a/Sources/SwiftFormat/Rules/NeverUseForceTry.swift b/Sources/SwiftFormat/Rules/NeverUseForceTry.swift index 2eada1a78..24a2bbbdb 100644 --- a/Sources/SwiftFormat/Rules/NeverUseForceTry.swift +++ b/Sources/SwiftFormat/Rules/NeverUseForceTry.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Force-try (`try!`) is forbidden. /// diff --git a/Sources/SwiftFormat/Rules/NeverUseImplicitlyUnwrappedOptionals.swift b/Sources/SwiftFormat/Rules/NeverUseImplicitlyUnwrappedOptionals.swift index 009969ddc..d33b33859 100644 --- a/Sources/SwiftFormat/Rules/NeverUseImplicitlyUnwrappedOptionals.swift +++ b/Sources/SwiftFormat/Rules/NeverUseImplicitlyUnwrappedOptionals.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Implicitly unwrapped optionals (e.g. `var s: String!`) are forbidden. /// diff --git a/Sources/SwiftFormat/Rules/NoAccessLevelOnExtensionDeclaration.swift b/Sources/SwiftFormat/Rules/NoAccessLevelOnExtensionDeclaration.swift index 2e9d0631c..5e4491aa6 100644 --- a/Sources/SwiftFormat/Rules/NoAccessLevelOnExtensionDeclaration.swift +++ b/Sources/SwiftFormat/Rules/NoAccessLevelOnExtensionDeclaration.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Specifying an access level for an extension declaration is forbidden. /// @@ -144,7 +144,7 @@ public final class NoAccessLevelOnExtensionDeclaration: SyntaxFormatRule { // allows modifiers but doesn't already have an access level modifier. guard case .insideExtension(let accessKeyword) = state, - let modifiers = decl.asProtocol(WithModifiersSyntax.self)?.modifiers, + let modifiers = decl.asProtocol((any WithModifiersSyntax).self)?.modifiers, modifiers.accessLevelModifier == nil else { return DeclSyntax(decl) diff --git a/Sources/SwiftFormat/Rules/NoAssignmentInExpressions.swift b/Sources/SwiftFormat/Rules/NoAssignmentInExpressions.swift index 194ed43cb..ba63ea12d 100644 --- a/Sources/SwiftFormat/Rules/NoAssignmentInExpressions.swift +++ b/Sources/SwiftFormat/Rules/NoAssignmentInExpressions.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,8 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +import SwiftOperators +public import SwiftSyntax /// Assignment expressions must be their own statements. /// diff --git a/Sources/SwiftFormat/Rules/NoBlockComments.swift b/Sources/SwiftFormat/Rules/NoBlockComments.swift index 1f5f0647c..b4cdfbbfe 100644 --- a/Sources/SwiftFormat/Rules/NoBlockComments.swift +++ b/Sources/SwiftFormat/Rules/NoBlockComments.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Block comments should be avoided in favor of line comments. /// diff --git a/Sources/SwiftFormat/Rules/NoCasesWithOnlyFallthrough.swift b/Sources/SwiftFormat/Rules/NoCasesWithOnlyFallthrough.swift index 486071251..e77bc743c 100644 --- a/Sources/SwiftFormat/Rules/NoCasesWithOnlyFallthrough.swift +++ b/Sources/SwiftFormat/Rules/NoCasesWithOnlyFallthrough.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Cases that contain only the `fallthrough` statement are forbidden. /// diff --git a/Sources/SwiftFormat/Rules/NoEmptyLineOpeningClosingBraces.swift b/Sources/SwiftFormat/Rules/NoEmptyLineOpeningClosingBraces.swift index 3251a92b1..45a03da50 100644 --- a/Sources/SwiftFormat/Rules/NoEmptyLineOpeningClosingBraces.swift +++ b/Sources/SwiftFormat/Rules/NoEmptyLineOpeningClosingBraces.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Empty lines are forbidden after opening braces and before closing braces. /// diff --git a/Sources/SwiftFormat/Rules/NoEmptyTrailingClosureParentheses.swift b/Sources/SwiftFormat/Rules/NoEmptyTrailingClosureParentheses.swift index 80dba8bcc..8cd645c3f 100644 --- a/Sources/SwiftFormat/Rules/NoEmptyTrailingClosureParentheses.swift +++ b/Sources/SwiftFormat/Rules/NoEmptyTrailingClosureParentheses.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Function calls with no arguments and a trailing closure should not have empty parentheses. /// diff --git a/Sources/SwiftFormat/Rules/NoLabelsInCasePatterns.swift b/Sources/SwiftFormat/Rules/NoLabelsInCasePatterns.swift index aba7cdf1f..1d83443c2 100644 --- a/Sources/SwiftFormat/Rules/NoLabelsInCasePatterns.swift +++ b/Sources/SwiftFormat/Rules/NoLabelsInCasePatterns.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// import Foundation -import SwiftSyntax +public import SwiftSyntax /// Redundant labels are forbidden in case patterns. /// diff --git a/Sources/SwiftFormat/Rules/NoLeadingUnderscores.swift b/Sources/SwiftFormat/Rules/NoLeadingUnderscores.swift index bc3a7fff5..fed7b2bff 100644 --- a/Sources/SwiftFormat/Rules/NoLeadingUnderscores.swift +++ b/Sources/SwiftFormat/Rules/NoLeadingUnderscores.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Identifiers in declarations and patterns should not have leading underscores. /// diff --git a/Sources/SwiftFormat/Rules/NoParensAroundConditions.swift b/Sources/SwiftFormat/Rules/NoParensAroundConditions.swift index 7c9f1dc9d..071eb4b75 100644 --- a/Sources/SwiftFormat/Rules/NoParensAroundConditions.swift +++ b/Sources/SwiftFormat/Rules/NoParensAroundConditions.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Enforces rules around parentheses in conditions or matched expressions. /// diff --git a/Sources/SwiftFormat/Rules/NoPlaygroundLiterals.swift b/Sources/SwiftFormat/Rules/NoPlaygroundLiterals.swift index e9d5d653a..24609d9b1 100644 --- a/Sources/SwiftFormat/Rules/NoPlaygroundLiterals.swift +++ b/Sources/SwiftFormat/Rules/NoPlaygroundLiterals.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// import Foundation -import SwiftSyntax +public import SwiftSyntax /// The playground literals (`#colorLiteral`, `#fileLiteral`, and `#imageLiteral`) are forbidden. /// diff --git a/Sources/SwiftFormat/Rules/NoVoidReturnOnFunctionSignature.swift b/Sources/SwiftFormat/Rules/NoVoidReturnOnFunctionSignature.swift index 3cacd29e0..ffa508393 100644 --- a/Sources/SwiftFormat/Rules/NoVoidReturnOnFunctionSignature.swift +++ b/Sources/SwiftFormat/Rules/NoVoidReturnOnFunctionSignature.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Functions that return `()` or `Void` should omit the return signature. /// diff --git a/Sources/SwiftFormat/Rules/OmitExplicitReturns.swift b/Sources/SwiftFormat/Rules/OmitExplicitReturns.swift index 032ef736d..238e48da8 100644 --- a/Sources/SwiftFormat/Rules/OmitExplicitReturns.swift +++ b/Sources/SwiftFormat/Rules/OmitExplicitReturns.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Single-expression functions, closures, subscripts can omit `return` statement. /// diff --git a/Sources/SwiftFormat/Rules/OneCasePerLine.swift b/Sources/SwiftFormat/Rules/OneCasePerLine.swift index 08f50e703..3c31e0586 100644 --- a/Sources/SwiftFormat/Rules/OneCasePerLine.swift +++ b/Sources/SwiftFormat/Rules/OneCasePerLine.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Each enum case with associated values or a raw value should appear in its own case declaration. /// diff --git a/Sources/SwiftFormat/Rules/OneVariableDeclarationPerLine.swift b/Sources/SwiftFormat/Rules/OneVariableDeclarationPerLine.swift index 0387942fa..253d2f9c8 100644 --- a/Sources/SwiftFormat/Rules/OneVariableDeclarationPerLine.swift +++ b/Sources/SwiftFormat/Rules/OneVariableDeclarationPerLine.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Each variable declaration, with the exception of tuple destructuring, should /// declare 1 variable. diff --git a/Sources/SwiftFormat/Rules/OnlyOneTrailingClosureArgument.swift b/Sources/SwiftFormat/Rules/OnlyOneTrailingClosureArgument.swift index ea62a06ff..4ee960891 100644 --- a/Sources/SwiftFormat/Rules/OnlyOneTrailingClosureArgument.swift +++ b/Sources/SwiftFormat/Rules/OnlyOneTrailingClosureArgument.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Function calls should never mix normal closure arguments and trailing closures. /// diff --git a/Sources/SwiftFormat/Rules/OrderedImports.swift b/Sources/SwiftFormat/Rules/OrderedImports.swift index bc82bfa8d..3dfe722ad 100644 --- a/Sources/SwiftFormat/Rules/OrderedImports.swift +++ b/Sources/SwiftFormat/Rules/OrderedImports.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,8 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +import Foundation +public import SwiftSyntax /// Imports must be lexicographically ordered and logically grouped at the top of each source file. /// The order of the import groups is 1) regular imports, 2) declaration imports, 3) @_implementationOnly diff --git a/Sources/SwiftFormat/Rules/ReplaceForEachWithForLoop.swift b/Sources/SwiftFormat/Rules/ReplaceForEachWithForLoop.swift index 14e6dcbff..7fa6d6dfa 100644 --- a/Sources/SwiftFormat/Rules/ReplaceForEachWithForLoop.swift +++ b/Sources/SwiftFormat/Rules/ReplaceForEachWithForLoop.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Replace `forEach` with `for-in` loop unless its argument is a function reference. /// diff --git a/Sources/SwiftFormat/Rules/ReturnVoidInsteadOfEmptyTuple.swift b/Sources/SwiftFormat/Rules/ReturnVoidInsteadOfEmptyTuple.swift index 977c9bfe0..300478a54 100644 --- a/Sources/SwiftFormat/Rules/ReturnVoidInsteadOfEmptyTuple.swift +++ b/Sources/SwiftFormat/Rules/ReturnVoidInsteadOfEmptyTuple.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Return `Void`, not `()`, in signatures. /// diff --git a/Sources/SwiftFormat/Rules/TypeNamesShouldBeCapitalized.swift b/Sources/SwiftFormat/Rules/TypeNamesShouldBeCapitalized.swift index 8a610ed0c..b80d91d39 100644 --- a/Sources/SwiftFormat/Rules/TypeNamesShouldBeCapitalized.swift +++ b/Sources/SwiftFormat/Rules/TypeNamesShouldBeCapitalized.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// `struct`, `class`, `enum` and `protocol` declarations should have a capitalized name. /// diff --git a/Sources/SwiftFormat/Rules/UseEarlyExits.swift b/Sources/SwiftFormat/Rules/UseEarlyExits.swift index 3f1e53912..f4faf9994 100644 --- a/Sources/SwiftFormat/Rules/UseEarlyExits.swift +++ b/Sources/SwiftFormat/Rules/UseEarlyExits.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Early exits should be used whenever possible. /// diff --git a/Sources/SwiftFormat/Rules/UseExplicitNilCheckInConditions.swift b/Sources/SwiftFormat/Rules/UseExplicitNilCheckInConditions.swift index 5c2f6bdae..2b5830a11 100644 --- a/Sources/SwiftFormat/Rules/UseExplicitNilCheckInConditions.swift +++ b/Sources/SwiftFormat/Rules/UseExplicitNilCheckInConditions.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax import SwiftSyntaxBuilder /// When checking an optional value for `nil`-ness, prefer writing an explicit `nil` check rather diff --git a/Sources/SwiftFormat/Rules/UseLetInEveryBoundCaseVariable.swift b/Sources/SwiftFormat/Rules/UseLetInEveryBoundCaseVariable.swift index 4d7b41636..54f951123 100644 --- a/Sources/SwiftFormat/Rules/UseLetInEveryBoundCaseVariable.swift +++ b/Sources/SwiftFormat/Rules/UseLetInEveryBoundCaseVariable.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Every variable bound in a `case` pattern must have its own `let/var`. /// diff --git a/Sources/SwiftFormat/Rules/UseShorthandTypeNames.swift b/Sources/SwiftFormat/Rules/UseShorthandTypeNames.swift index 28d048fac..edfdd8288 100644 --- a/Sources/SwiftFormat/Rules/UseShorthandTypeNames.swift +++ b/Sources/SwiftFormat/Rules/UseShorthandTypeNames.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Shorthand type forms must be used wherever possible. /// diff --git a/Sources/SwiftFormat/Rules/UseSingleLinePropertyGetter.swift b/Sources/SwiftFormat/Rules/UseSingleLinePropertyGetter.swift index 81d4c0a61..e5b889540 100644 --- a/Sources/SwiftFormat/Rules/UseSingleLinePropertyGetter.swift +++ b/Sources/SwiftFormat/Rules/UseSingleLinePropertyGetter.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// Read-only computed properties must use implicit `get` blocks. /// diff --git a/Sources/SwiftFormat/Rules/UseSynthesizedInitializer.swift b/Sources/SwiftFormat/Rules/UseSynthesizedInitializer.swift index e0081059e..cb4a5f333 100644 --- a/Sources/SwiftFormat/Rules/UseSynthesizedInitializer.swift +++ b/Sources/SwiftFormat/Rules/UseSynthesizedInitializer.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// import Foundation -import SwiftSyntax +public import SwiftSyntax /// When possible, the synthesized `struct` initializer should be used. /// diff --git a/Sources/SwiftFormat/Rules/UseTripleSlashForDocumentationComments.swift b/Sources/SwiftFormat/Rules/UseTripleSlashForDocumentationComments.swift index 319c478eb..fe20eb057 100644 --- a/Sources/SwiftFormat/Rules/UseTripleSlashForDocumentationComments.swift +++ b/Sources/SwiftFormat/Rules/UseTripleSlashForDocumentationComments.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// import Foundation -import SwiftSyntax +public import SwiftSyntax /// Documentation comments must use the `///` form. /// diff --git a/Sources/SwiftFormat/Rules/UseWhereClausesInForLoops.swift b/Sources/SwiftFormat/Rules/UseWhereClausesInForLoops.swift index 12e6c3ea9..c7af37ed3 100644 --- a/Sources/SwiftFormat/Rules/UseWhereClausesInForLoops.swift +++ b/Sources/SwiftFormat/Rules/UseWhereClausesInForLoops.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax /// `for` loops that consist of a single `if` statement must use `where` clauses instead. /// diff --git a/Sources/SwiftFormat/Rules/ValidateDocumentationComments.swift b/Sources/SwiftFormat/Rules/ValidateDocumentationComments.swift index 05495d207..e606b7e1e 100644 --- a/Sources/SwiftFormat/Rules/ValidateDocumentationComments.swift +++ b/Sources/SwiftFormat/Rules/ValidateDocumentationComments.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -12,7 +12,7 @@ import Foundation import Markdown -import SwiftSyntax +public import SwiftSyntax /// Documentation comments must be complete and valid. /// diff --git a/Sources/SwiftFormat/Utilities/FileIterator.swift b/Sources/SwiftFormat/Utilities/FileIterator.swift index f6d05776c..b99b5231d 100644 --- a/Sources/SwiftFormat/Utilities/FileIterator.swift +++ b/Sources/SwiftFormat/Utilities/FileIterator.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import Foundation +public import Foundation #if os(Windows) import WinSDK diff --git a/Sources/SwiftFormat/Utilities/URL+isRoot.swift b/Sources/SwiftFormat/Utilities/URL+isRoot.swift index 6a8522889..6ef990634 100644 --- a/Sources/SwiftFormat/Utilities/URL+isRoot.swift +++ b/Sources/SwiftFormat/Utilities/URL+isRoot.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import Foundation +public import Foundation #if os(Windows) import WinSDK diff --git a/Sources/_GenerateSwiftFormat/FileGenerator.swift b/Sources/_GenerateSwiftFormat/FileGenerator.swift index 77c82c962..5c6d17cd3 100644 --- a/Sources/_GenerateSwiftFormat/FileGenerator.swift +++ b/Sources/_GenerateSwiftFormat/FileGenerator.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import Foundation +public import Foundation /// Common behavior used to generate source files. @_spi(Internal) public protocol FileGenerator { diff --git a/Sources/_GenerateSwiftFormat/GenerateSwiftFormatPaths.swift b/Sources/_GenerateSwiftFormat/GenerateSwiftFormatPaths.swift index c36308568..7f6e45bdd 100644 --- a/Sources/_GenerateSwiftFormat/GenerateSwiftFormatPaths.swift +++ b/Sources/_GenerateSwiftFormat/GenerateSwiftFormatPaths.swift @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import Foundation +public import Foundation /// A namespace that provides paths for files generated by the `generate-swift-format` tool. @_spi(Internal) public enum GenerateSwiftFormatPaths { diff --git a/Sources/_GenerateSwiftFormat/RuleCollector.swift b/Sources/_GenerateSwiftFormat/RuleCollector.swift index 60646d37b..f68f9a37d 100644 --- a/Sources/_GenerateSwiftFormat/RuleCollector.swift +++ b/Sources/_GenerateSwiftFormat/RuleCollector.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import Foundation +public import Foundation @_spi(Rules) import SwiftFormat import SwiftParser import SwiftSyntax @@ -142,7 +142,7 @@ import SwiftSyntax /// Ignore it if it doesn't have any; there's no point in putting no-op rules in the pipeline. /// Otherwise, return it (we don't need to look at the rest of the inheritances). guard !visitedNodes.isEmpty else { return nil } - guard let ruleType = _typeByName("SwiftFormat.\(typeName)") as? Rule.Type else { + guard let ruleType = _typeByName("SwiftFormat.\(typeName)") as? any Rule.Type else { preconditionFailure("Failed to find type for rule named \(typeName)") } return DetectedRule( diff --git a/Sources/_GenerateSwiftFormat/Syntax+Convenience.swift b/Sources/_GenerateSwiftFormat/Syntax+Convenience.swift index 91023b2da..e21f009fd 100644 --- a/Sources/_GenerateSwiftFormat/Syntax+Convenience.swift +++ b/Sources/_GenerateSwiftFormat/Syntax+Convenience.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +public import SwiftSyntax extension SyntaxCollection { /// The first element in the syntax collection if it is the *only* element, or nil otherwise. diff --git a/Sources/_SwiftFormatTestSupport/Configuration+Testing.swift b/Sources/_SwiftFormatTestSupport/Configuration+Testing.swift index 0c8974609..06e3b22ea 100644 --- a/Sources/_SwiftFormatTestSupport/Configuration+Testing.swift +++ b/Sources/_SwiftFormatTestSupport/Configuration+Testing.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftFormat +package import SwiftFormat extension Configuration { /// The default configuration to be used during unit tests. @@ -22,7 +22,7 @@ extension Configuration { /// delegate to another initializer first, which defeats the purpose). So, users adding new /// configuration settings should be sure to supply a default here for testing, otherwise they /// will be implicitly relying on the real default. - public static var forTesting: Configuration { + package static var forTesting: Configuration { var config = Configuration() config.rules = Configuration.defaultRuleEnablements config.maximumBlankLines = 1 @@ -45,7 +45,7 @@ extension Configuration { return config } - public static func forTesting(enabledRule: String) -> Configuration { + package static func forTesting(enabledRule: String) -> Configuration { var config = Configuration.forTesting config.rules = config.rules.mapValues({ _ in false }) config.rules[enabledRule] = true diff --git a/Sources/_SwiftFormatTestSupport/DiagnosingTestCase.swift b/Sources/_SwiftFormatTestSupport/DiagnosingTestCase.swift index b72f7ef95..a1858441a 100644 --- a/Sources/_SwiftFormatTestSupport/DiagnosingTestCase.swift +++ b/Sources/_SwiftFormatTestSupport/DiagnosingTestCase.swift @@ -10,10 +10,10 @@ // //===----------------------------------------------------------------------===// -import SwiftFormat -@_spi(Rules) @_spi(Testing) import SwiftFormat -import SwiftSyntax -import XCTest +@_spi(Rules) @_spi(Testing) public import SwiftFormat +import SwiftOperators +public import SwiftSyntax +public import XCTest /// DiagnosingTestCase is an XCTestCase subclass meant to inject diagnostic-specific testing /// routines into specific formatting test cases. @@ -48,7 +48,7 @@ open class DiagnosingTestCase: XCTestCase { markerLocations: [String: Int], emittedFindings: [Finding], context: Context, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { var emittedFindings = emittedFindings @@ -86,7 +86,7 @@ open class DiagnosingTestCase: XCTestCase { markerLocations: [String: Int], emittedFindings: inout [Finding], context: Context, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { guard let utf8Offset = markerLocations[findingSpec.marker] else { @@ -164,7 +164,7 @@ open class DiagnosingTestCase: XCTestCase { markerLocations: [String: Int], emittedNotes: inout [Finding.Note], context: Context, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { guard let utf8Offset = markerLocations[noteSpec.marker] else { @@ -218,11 +218,11 @@ open class DiagnosingTestCase: XCTestCase { /// which this function was called. /// - line: The line number on which failure occurred. Defaults to the line number on which this /// function was called. - public final func assertStringsEqualWithDiff( + package final func assertStringsEqualWithDiff( _ actual: String, _ expected: String, _ message: String = "", - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { let actualLines = actual.components(separatedBy: .newlines) diff --git a/Sources/_SwiftFormatTestSupport/FindingSpec.swift b/Sources/_SwiftFormatTestSupport/FindingSpec.swift index e9751ede4..da6af117b 100644 --- a/Sources/_SwiftFormatTestSupport/FindingSpec.swift +++ b/Sources/_SwiftFormatTestSupport/FindingSpec.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -13,16 +13,16 @@ /// A description of a `Finding` that can be asserted during tests. public struct FindingSpec { /// The marker that identifies the finding. - public var marker: String + package var marker: String /// The message text associated with the finding. - public var message: String + package var message: String /// A description of a `Note` that should be associated with this finding. - public var notes: [NoteSpec] + package var notes: [NoteSpec] /// Creates a new `FindingSpec` with the given values. - public init(_ marker: String = "1️⃣", message: String, notes: [NoteSpec] = []) { + package init(_ marker: String = "1️⃣", message: String, notes: [NoteSpec] = []) { self.marker = marker self.message = message self.notes = notes @@ -30,15 +30,15 @@ public struct FindingSpec { } /// A description of a `Note` that can be asserted during tests. -public struct NoteSpec { +package struct NoteSpec { /// The marker that identifies the note. - public var marker: String + package var marker: String /// The message text associated with the note. - public var message: String + package var message: String /// Creates a new `NoteSpec` with the given values. - public init(_ marker: String, message: String) { + package init(_ marker: String, message: String) { self.marker = marker self.message = message } diff --git a/Sources/_SwiftFormatTestSupport/MarkedText.swift b/Sources/_SwiftFormatTestSupport/MarkedText.swift index 9d63a4812..d2ef34633 100644 --- a/Sources/_SwiftFormatTestSupport/MarkedText.swift +++ b/Sources/_SwiftFormatTestSupport/MarkedText.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,22 +10,22 @@ // //===----------------------------------------------------------------------===// -import SwiftFormat +package import SwiftFormat import SwiftSyntax /// Encapsulates the locations of emoji markers extracted from source text. -public struct MarkedText { +package struct MarkedText { /// A mapping from marker names to the UTF-8 offset where the marker was found in the string. - public let markers: [String: Int] + package let markers: [String: Int] /// The text with all markers removed. - public let textWithoutMarkers: String + package let textWithoutMarkers: String /// If the marked text contains "⏩" and "⏪", they're used to create a selection - public var selection: Selection + package var selection: Selection /// Creates a new `MarkedText` value by extracting emoji markers from the given text. - public init(textWithMarkers markedText: String) { + package init(textWithMarkers markedText: String) { var text = "" var markers = [String: Int]() var lastIndex = markedText.startIndex diff --git a/Sources/_SwiftFormatTestSupport/Parsing.swift b/Sources/_SwiftFormatTestSupport/Parsing.swift index 71f1a64d4..56b9c3e08 100644 --- a/Sources/_SwiftFormatTestSupport/Parsing.swift +++ b/Sources/_SwiftFormatTestSupport/Parsing.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// -@_spi(ExperimentalLanguageFeatures) import SwiftParser -import SwiftSyntax +@_spi(ExperimentalLanguageFeatures) public import SwiftParser +public import SwiftSyntax import XCTest extension Parser { diff --git a/Sources/swift-format/Frontend/ConfigurationLoader.swift b/Sources/swift-format/Frontend/ConfigurationLoader.swift index 57d9bb63b..98b54e53c 100644 --- a/Sources/swift-format/Frontend/ConfigurationLoader.swift +++ b/Sources/swift-format/Frontend/ConfigurationLoader.swift @@ -15,7 +15,7 @@ import SwiftFormat /// Loads formatter configurations, caching them in memory so that multiple operations in the same /// directory do not repeatedly hit the file system. -struct ConfigurationLoader { +struct ConfigurationLoader: ~Copyable { /// The cache of previously loaded configurations. private var cache = [String: Configuration]() diff --git a/Sources/swift-format/Frontend/ConfigurationProvider.swift b/Sources/swift-format/Frontend/ConfigurationProvider.swift new file mode 100644 index 000000000..da9744c27 --- /dev/null +++ b/Sources/swift-format/Frontend/ConfigurationProvider.swift @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import Foundation +@_spi(Internal) import SwiftFormat + +// FIXME: This needn't be MainActor because we never actually access it concurrently. +// It can be made nonisolated if decoupled from the Sendable Frontend. +/// Provides formatter configurations for given `.swift` source files, configuration files or configuration strings. +@MainActor +final class ConfigurationProvider { + /// Loads formatter configuration files and caches them in memory. + private var configurationLoader: ConfigurationLoader + + /// The diagnostic engine to which warnings and errors will be emitted. + private let diagnosticsEngine: DiagnosticsEngine + + /// Creates a new instance with the given options. + /// + /// - Parameter diagnosticsEngine: The diagnostic engine to which warnings and errors will be emitted. + nonisolated init(diagnosticsEngine: DiagnosticsEngine) { + self.diagnosticsEngine = diagnosticsEngine + self.configurationLoader = ConfigurationLoader() + } + + /// Checks if all the rules in the given configuration are supported by the registry. + /// + /// If there are any rules that are not supported, they are emitted as a warning. + private func checkForUnrecognizedRules(in configuration: Configuration) { + // If any rules in the decoded configuration are not supported by the registry, + // emit them into the diagnosticsEngine as warnings. + // That way they will be printed out, but we'll continue execution on the valid rules. + + for (key, _) in configuration.rules { + if RuleRegistry.rules.keys.contains(key) { + continue + } + diagnosticsEngine.emitWarning("Configuration contains an unrecognized rule: \(key)", location: nil) + } + } + + /// Returns the configuration that applies to the given `.swift` source file, when an explicit + /// configuration path is also perhaps provided. + /// + /// This method also checks for unrecognized rules within the configuration. + /// + /// - Parameters: + /// - pathOrString: A string containing either the path to a configuration file that will be + /// loaded, JSON configuration data directly, or `nil` to try to infer it from + /// `swiftFileURL`. + /// - swiftFileURL: The path to a `.swift` file, which will be used to infer the path to the + /// configuration file if `configurationFilePath` is nil. + /// + /// - Returns: If successful, the returned configuration is the one loaded from `pathOrString` if + /// it was provided, or by searching in paths inferred by `swiftFileURL` if one exists, or the + /// default configuration otherwise. If an error occurred when reading the configuration, a + /// diagnostic is emitted and `nil` is returned. If neither `pathOrString` nor `swiftFileURL` + /// were provided, a default `Configuration()` will be returned. + func provide( + forConfigPathOrString pathOrString: String?, + orForSwiftFileAt swiftFileURL: URL? + ) -> Configuration? { + if let pathOrString = pathOrString { + // If an explicit configuration file path was given, try to load it and fail if it cannot be + // loaded. (Do not try to fall back to a path inferred from the source file path.) + let configurationFileURL = URL(fileURLWithPath: pathOrString) + do { + let configuration = try configurationLoader.configuration(at: configurationFileURL) + self.checkForUnrecognizedRules(in: configuration) + return configuration + } catch { + // If we failed to load this from the path, try interpreting the string as configuration + // data itself because the user might have written something like `--configuration '{...}'`, + let data = pathOrString.data(using: .utf8)! + if let configuration = try? Configuration(data: data) { + return configuration + } + + // Fail if the configuration flag was neither a valid file path nor valid configuration + // data. + diagnosticsEngine.emitError("Unable to read configuration: \(error.localizedDescription)") + return nil + } + } + + // If no explicit configuration file path was given but a `.swift` source file path was given, + // then try to load the configuration by inferring it based on the source file path. + if let swiftFileURL = swiftFileURL { + do { + if let configuration = try configurationLoader.configuration(forPath: swiftFileURL) { + self.checkForUnrecognizedRules(in: configuration) + return configuration + } + // Fall through to the default return at the end of the function. + } catch { + diagnosticsEngine.emitError( + "Unable to read configuration for \(swiftFileURL.relativePath): \(error.localizedDescription)" + ) + return nil + } + } else { + // If reading from stdin and no explicit configuration file was given, + // walk up the file tree from the cwd to find a config. + + let cwd = URL(fileURLWithPath: FileManager.default.currentDirectoryPath) + // Definitely a Swift file. Definitely not a directory. Shhhhhh. + do { + if let configuration = try configurationLoader.configuration(forPath: cwd) { + self.checkForUnrecognizedRules(in: configuration) + return configuration + } + } catch { + diagnosticsEngine.emitError( + "Unable to read configuration for \(cwd.relativePath): \(error.localizedDescription)" + ) + return nil + } + } + + // An explicit configuration has not been given, and one cannot be found. + // Return the default configuration. + return Configuration() + } +} diff --git a/Sources/swift-format/Frontend/FileToProcess.swift b/Sources/swift-format/Frontend/FileToProcess.swift new file mode 100644 index 000000000..ea21daa2f --- /dev/null +++ b/Sources/swift-format/Frontend/FileToProcess.swift @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import Foundation +import SwiftFormat + +/// Represents a file to be processed by the frontend and any file-specific options associated +/// with it. +struct FileToProcess: ~Copyable { + /// An open file handle to the source code of the file. + private let fileHandle: FileHandle + + /// A file URL representing the path to the source file being processed. + /// + /// It is the responsibility of the specific frontend to make guarantees about the validity of + /// this path. For example, the formatting frontend ensures that it is a path to an existing + /// file only when doing in-place formatting (so that the file can be replaced). In other + /// situations, it may correspond to a different file than the underlying file handle (if + /// standard input is used with the `--assume-filename` flag), or it may not be a valid path at + /// all (the string `""`). + let url: URL + + /// The configuration that should applied for this file. + let configuration: Configuration + + /// the selected ranges to process + let selection: Selection + + /// Returns the string contents of the file. + /// + /// The contents of the file are assumed to be UTF-8 encoded. If there is an error decoding the + /// contents, `nil` will be returned. + func readString() -> String? { + let sourceData = fileHandle.readDataToEndOfFile() + defer { fileHandle.closeFile() } + return String(data: sourceData, encoding: .utf8) + } + + init( + fileHandle: FileHandle, + url: URL, + configuration: Configuration, + selection: Selection = .infinite + ) { + self.fileHandle = fileHandle + self.url = url + self.configuration = configuration + self.selection = selection + } +} diff --git a/Sources/swift-format/Frontend/FormatFrontend.swift b/Sources/swift-format/Frontend/FormatFrontend.swift index 0e8fca9d2..b6a0aa406 100644 --- a/Sources/swift-format/Frontend/FormatFrontend.swift +++ b/Sources/swift-format/Frontend/FormatFrontend.swift @@ -16,16 +16,39 @@ import SwiftFormat import SwiftSyntax /// The frontend for formatting operations. -class FormatFrontend: Frontend { +struct FormatFrontend: Frontend { + /// The diagnostic engine to which warnings and errors will be emitted. + let diagnosticsEngine: DiagnosticsEngine + + /// Options that control the tool's configuration. + let configurationOptions: ConfigurationOptions + + /// Options that apply during formatting. + let lintFormatOptions: LintFormatOptions + + /// The provider for formatter configurations. + let configurationProvider: ConfigurationProvider + /// Whether or not to format the Swift file in-place. private let inPlace: Bool - init(configurationOptions: ConfigurationOptions, lintFormatOptions: LintFormatOptions, inPlace: Bool) { + /// Creates a new frontend with the given options. + /// + /// - Parameter lintFormatOptions: Options that apply during formatting. + init( + diagnosticEngine: DiagnosticsEngine, + configurationOptions: ConfigurationOptions, + lintFormatOptions: LintFormatOptions, + inPlace: Bool + ) { + self.diagnosticsEngine = diagnosticEngine + self.configurationOptions = configurationOptions + self.lintFormatOptions = lintFormatOptions self.inPlace = inPlace - super.init(configurationOptions: configurationOptions, lintFormatOptions: lintFormatOptions) + self.configurationProvider = ConfigurationProvider(diagnosticsEngine: self.diagnosticsEngine) } - override func processFile(_ fileToProcess: FileToProcess) { + nonisolated func processFile(_ fileToProcess: borrowing FileToProcess) { // In format mode, the diagnostics engine is reserved for fatal messages. Pass nil as the // finding consumer to ignore findings emitted while the syntax tree is processed because they // will be fixed automatically if they can be, or ignored otherwise. @@ -33,7 +56,7 @@ class FormatFrontend: Frontend { formatter.debugOptions = debugOptions let url = fileToProcess.url - guard let source = fileToProcess.sourceText else { + guard let source = fileToProcess.readString() else { diagnosticsEngine.emitError( "Unable to format \(url.relativePath): file is not readable or does not exist." ) diff --git a/Sources/swift-format/Frontend/Frontend.swift b/Sources/swift-format/Frontend/Frontend.swift index aaa24ad01..a6ff97851 100644 --- a/Sources/swift-format/Frontend/Frontend.swift +++ b/Sources/swift-format/Frontend/Frontend.swift @@ -12,216 +12,43 @@ import Foundation @_spi(Internal) import SwiftFormat -import SwiftParser -import SwiftSyntax - -class Frontend { - /// Provides formatter configurations for given `.swift` source files, configuration files or configuration strings. - struct ConfigurationProvider { - /// Loads formatter configuration files and chaches them in memory. - private var configurationLoader: ConfigurationLoader = ConfigurationLoader() - - /// The diagnostic engine to which warnings and errors will be emitted. - private let diagnosticsEngine: DiagnosticsEngine - - /// Creates a new instance with the given options. - /// - /// - Parameter diagnosticsEngine: The diagnostic engine to which warnings and errors will be emitted. - init(diagnosticsEngine: DiagnosticsEngine) { - self.diagnosticsEngine = diagnosticsEngine - } - - /// Checks if all the rules in the given configuration are supported by the registry. - /// - /// If there are any rules that are not supported, they are emitted as a warning. - private func checkForUnrecognizedRules(in configuration: Configuration) { - // If any rules in the decoded configuration are not supported by the registry, - // emit them into the diagnosticsEngine as warnings. - // That way they will be printed out, but we'll continue execution on the valid rules. - let invalidRules = configuration.rules.filter { !RuleRegistry.rules.keys.contains($0.key) } - for rule in invalidRules { - diagnosticsEngine.emitWarning("Configuration contains an unrecognized rule: \(rule.key)", location: nil) - } - } - - /// Returns the configuration that applies to the given `.swift` source file, when an explicit - /// configuration path is also perhaps provided. - /// - /// This method also checks for unrecognized rules within the configuration. - /// - /// - Parameters: - /// - pathOrString: A string containing either the path to a configuration file that will be - /// loaded, JSON configuration data directly, or `nil` to try to infer it from - /// `swiftFileURL`. - /// - swiftFileURL: The path to a `.swift` file, which will be used to infer the path to the - /// configuration file if `configurationFilePath` is nil. - /// - /// - Returns: If successful, the returned configuration is the one loaded from `pathOrString` if - /// it was provided, or by searching in paths inferred by `swiftFileURL` if one exists, or the - /// default configuration otherwise. If an error occurred when reading the configuration, a - /// diagnostic is emitted and `nil` is returned. If neither `pathOrString` nor `swiftFileURL` - /// were provided, a default `Configuration()` will be returned. - mutating func provide( - forConfigPathOrString pathOrString: String?, - orForSwiftFileAt swiftFileURL: URL? - ) -> Configuration? { - if let pathOrString = pathOrString { - // If an explicit configuration file path was given, try to load it and fail if it cannot be - // loaded. (Do not try to fall back to a path inferred from the source file path.) - let configurationFileURL = URL(fileURLWithPath: pathOrString) - do { - let configuration = try configurationLoader.configuration(at: configurationFileURL) - self.checkForUnrecognizedRules(in: configuration) - return configuration - } catch { - // If we failed to load this from the path, try interpreting the string as configuration - // data itself because the user might have written something like `--configuration '{...}'`, - let data = pathOrString.data(using: .utf8)! - if let configuration = try? Configuration(data: data) { - return configuration - } - - // Fail if the configuration flag was neither a valid file path nor valid configuration - // data. - diagnosticsEngine.emitError("Unable to read configuration: \(error.localizedDescription)") - return nil - } - } - - // If no explicit configuration file path was given but a `.swift` source file path was given, - // then try to load the configuration by inferring it based on the source file path. - if let swiftFileURL = swiftFileURL { - do { - if let configuration = try configurationLoader.configuration(forPath: swiftFileURL) { - self.checkForUnrecognizedRules(in: configuration) - return configuration - } - // Fall through to the default return at the end of the function. - } catch { - diagnosticsEngine.emitError( - "Unable to read configuration for \(swiftFileURL.relativePath): \(error.localizedDescription)" - ) - return nil - } - } else { - // If reading from stdin and no explicit configuration file was given, - // walk up the file tree from the cwd to find a config. - - let cwd = URL(fileURLWithPath: FileManager.default.currentDirectoryPath) - // Definitely a Swift file. Definitely not a directory. Shhhhhh. - do { - if let configuration = try configurationLoader.configuration(forPath: cwd) { - self.checkForUnrecognizedRules(in: configuration) - return configuration - } - } catch { - diagnosticsEngine.emitError( - "Unable to read configuration for \(cwd.relativePath): \(error.localizedDescription)" - ) - return nil - } - } - - // An explicit configuration has not been given, and one cannot be found. - // Return the default configuration. - return Configuration() - } - } - - /// Represents a file to be processed by the frontend and any file-specific options associated - /// with it. - final class FileToProcess { - /// An open file handle to the source code of the file. - private let fileHandle: FileHandle - - /// A file URL representing the path to the source file being processed. - /// - /// It is the responsibility of the specific frontend to make guarantees about the validity of - /// this path. For example, the formatting frontend ensures that it is a path to an existing - /// file only when doing in-place formatting (so that the file can be replaced). In other - /// situations, it may correspond to a different file than the underlying file handle (if - /// standard input is used with the `--assume-filename` flag), or it may not be a valid path at - /// all (the string `""`). - let url: URL - - /// The configuration that should applied for this file. - let configuration: Configuration - - /// the selected ranges to process - let selection: Selection - - /// Returns the string contents of the file. - /// - /// The contents of the file are assumed to be UTF-8 encoded. If there is an error decoding the - /// contents, `nil` will be returned. - lazy var sourceText: String? = { - let sourceData = fileHandle.readDataToEndOfFile() - defer { fileHandle.closeFile() } - return String(data: sourceData, encoding: .utf8) - }() - - init( - fileHandle: FileHandle, - url: URL, - configuration: Configuration, - selection: Selection = .infinite - ) { - self.fileHandle = fileHandle - self.url = url - self.configuration = configuration - self.selection = selection - } - } - - /// Prints diagnostics to standard error, optionally with color. - final let diagnosticPrinter: StderrDiagnosticPrinter +protocol Frontend: Sendable { /// The diagnostic engine to which warnings and errors will be emitted. - final let diagnosticsEngine: DiagnosticsEngine + var diagnosticsEngine: DiagnosticsEngine { get } /// Options that control the tool's configuration. - final let configurationOptions: ConfigurationOptions + var configurationOptions: ConfigurationOptions { get } /// Options that apply during formatting or linting. - final let lintFormatOptions: LintFormatOptions + var lintFormatOptions: LintFormatOptions { get } /// The provider for formatter configurations. - final var configurationProvider: ConfigurationProvider + var configurationProvider: ConfigurationProvider { get } + /// Called by the frontend to process a single file. + /// + /// Subclasses must override this method to provide the actual linting or formatting logic. + /// + /// - Parameter fileToProcess: A `FileToProcess` that contains information about the file to be + /// processed. + func processFile(_ fileToProcess: borrowing FileToProcess) +} + +extension Frontend { /// Advanced options that are useful for developing/debugging but otherwise not meant for general /// use. - final var debugOptions: DebugOptions { + var debugOptions: DebugOptions { [ lintFormatOptions.debugDisablePrettyPrint ? .disablePrettyPrint : [], lintFormatOptions.debugDumpTokenStream ? .dumpTokenStream : [], ] } - /// Creates a new frontend with the given options. - /// - /// - Parameter lintFormatOptions: Options that apply during formatting or linting. - init( - configurationOptions: ConfigurationOptions, - lintFormatOptions: LintFormatOptions, - treatWarningsAsErrors: Bool = false - ) { - self.configurationOptions = configurationOptions - self.lintFormatOptions = lintFormatOptions - - self.diagnosticPrinter = StderrDiagnosticPrinter( - colorMode: lintFormatOptions.colorDiagnostics.map { $0 ? .on : .off } ?? .auto - ) - self.diagnosticsEngine = DiagnosticsEngine( - diagnosticsHandlers: [diagnosticPrinter.printDiagnostic], - treatWarningsAsErrors: treatWarningsAsErrors - ) - self.configurationProvider = ConfigurationProvider(diagnosticsEngine: self.diagnosticsEngine) - } - /// Runs the linter or formatter over the inputs. - final func run() { + func run() async { if lintFormatOptions.paths == ["-"] { - processStandardInput() + await processStandardInput() } else if lintFormatOptions.paths.isEmpty { diagnosticsEngine.emitWarning( """ @@ -237,26 +64,17 @@ class Frontend { For more information, use the `--help` option. """ ) - processStandardInput() + await processStandardInput() } else { - processURLs( + await processURLs( lintFormatOptions.paths.map(URL.init(fileURLWithPath:)), parallel: lintFormatOptions.parallel ) } } - /// Called by the frontend to process a single file. - /// - /// Subclasses must override this method to provide the actual linting or formatting logic. - /// - /// - Parameter fileToProcess: A `FileToProcess` that contains information about the file to be - /// processed. - func processFile(_ fileToProcess: FileToProcess) { - fatalError("Must be overridden by subclasses.") - } - /// Processes source content from standard input. + @MainActor private func processStandardInput() { let assumedUrl = lintFormatOptions.assumeFilename.map(URL.init(fileURLWithPath:)) @@ -280,29 +98,37 @@ class Frontend { } /// Processes source content from a list of files and/or directories provided as file URLs. - private func processURLs(_ urls: [URL], parallel: Bool) { + @MainActor + private func processURLs(_ urls: [URL], parallel: Bool) async { precondition( !urls.isEmpty, "processURLs(_:) should only be called when 'urls' is non-empty." ) + let filesToProcess = FileIterator(urls: urls, followSymlinks: lintFormatOptions.followSymlinks) + if parallel { - let filesToProcess = - FileIterator(urls: urls, followSymlinks: lintFormatOptions.followSymlinks) - .compactMap(openAndPrepareFile) - DispatchQueue.concurrentPerform(iterations: filesToProcess.count) { index in - processFile(filesToProcess[index]) + await withTaskGroup(of: Void.self) { group in + for url in filesToProcess { + if let file = self.openAndPrepareFile(at: url) { + group.addTask { + self.processFile(file) + } + } + } } } else { - FileIterator(urls: urls, followSymlinks: lintFormatOptions.followSymlinks) - .lazy - .compactMap(openAndPrepareFile) - .forEach(processFile) + for url in filesToProcess { + if let file = self.openAndPrepareFile(at: url) { + self.processFile(file) + } + } } } /// Read and prepare the file at the given path for processing, optionally synchronizing /// diagnostic output. + @MainActor private func openAndPrepareFile(at url: URL) -> FileToProcess? { guard let sourceFile = try? FileHandle(forReadingFrom: url) else { diagnosticsEngine.emitError( @@ -328,5 +154,4 @@ class Frontend { selection: Selection(offsetRanges: lintFormatOptions.offsets) ) } - } diff --git a/Sources/swift-format/Frontend/LintFrontend.swift b/Sources/swift-format/Frontend/LintFrontend.swift index c231266a7..ddd59db4b 100644 --- a/Sources/swift-format/Frontend/LintFrontend.swift +++ b/Sources/swift-format/Frontend/LintFrontend.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -11,13 +11,38 @@ //===----------------------------------------------------------------------===// import Foundation -import SwiftDiagnostics import SwiftFormat import SwiftSyntax /// The frontend for linting operations. -class LintFrontend: Frontend { - override func processFile(_ fileToProcess: FileToProcess) { +struct LintFrontend: Frontend { + /// The diagnostic engine to which warnings and errors will be emitted. + let diagnosticsEngine: DiagnosticsEngine + + /// Options that control the tool's configuration. + let configurationOptions: ConfigurationOptions + + /// Options that apply during linting. + let lintFormatOptions: LintFormatOptions + + /// The provider for formatter configurations. + let configurationProvider: ConfigurationProvider + + /// Creates a new frontend with the given options. + /// + /// - Parameter lintFormatOptions: Options that apply during linting. + init( + diagnosticEngine: DiagnosticsEngine, + configurationOptions: ConfigurationOptions, + lintFormatOptions: LintFormatOptions + ) { + self.diagnosticsEngine = diagnosticEngine + self.configurationOptions = configurationOptions + self.lintFormatOptions = lintFormatOptions + self.configurationProvider = ConfigurationProvider(diagnosticsEngine: self.diagnosticsEngine) + } + + nonisolated func processFile(_ fileToProcess: borrowing FileToProcess) { let linter = SwiftLinter( configuration: fileToProcess.configuration, findingConsumer: diagnosticsEngine.consumeFinding @@ -25,7 +50,7 @@ class LintFrontend: Frontend { linter.debugOptions = debugOptions let url = fileToProcess.url - guard let source = fileToProcess.sourceText else { + guard let source = fileToProcess.readString() else { diagnosticsEngine.emitError( "Unable to lint \(url.relativePath): file is not readable or does not exist." ) diff --git a/Sources/swift-format/Subcommands/DumpConfiguration.swift b/Sources/swift-format/Subcommands/DumpConfiguration.swift index 3104ed588..c24aef3e9 100644 --- a/Sources/swift-format/Subcommands/DumpConfiguration.swift +++ b/Sources/swift-format/Subcommands/DumpConfiguration.swift @@ -16,8 +16,8 @@ import SwiftFormat extension SwiftFormatCommand { /// Dumps the tool's configuration in JSON format to standard output. - struct DumpConfiguration: ParsableCommand { - static var configuration = CommandConfiguration( + struct DumpConfiguration: AsyncParsableCommand { + static let configuration = CommandConfiguration( abstract: "Dump the configuration in JSON format to standard output", discussion: """ Without any options, dumps the default configuration. When '--effective' is set, dumps the configuration that \ @@ -39,16 +39,16 @@ extension SwiftFormatCommand { } } - func run() throws { + func run() async throws { let diagnosticPrinter = StderrDiagnosticPrinter(colorMode: .auto) let diagnosticsEngine = DiagnosticsEngine(diagnosticsHandlers: [diagnosticPrinter.printDiagnostic]) let configuration: Configuration if effective { - var configurationProvider = Frontend.ConfigurationProvider(diagnosticsEngine: diagnosticsEngine) + let configurationProvider = ConfigurationProvider(diagnosticsEngine: diagnosticsEngine) guard - let effectiveConfiguration = configurationProvider.provide( + let effectiveConfiguration = await configurationProvider.provide( forConfigPathOrString: configurationOptions.configuration, orForSwiftFileAt: nil ) diff --git a/Sources/swift-format/Subcommands/Format.swift b/Sources/swift-format/Subcommands/Format.swift index 0aab74d58..cc9702493 100644 --- a/Sources/swift-format/Subcommands/Format.swift +++ b/Sources/swift-format/Subcommands/Format.swift @@ -14,8 +14,8 @@ import ArgumentParser extension SwiftFormatCommand { /// Formats one or more files containing Swift code. - struct Format: ParsableCommand { - static var configuration = CommandConfiguration( + struct Format: AsyncParsableCommand { + static let configuration = CommandConfiguration( abstract: "Format Swift source code", discussion: "When no files are specified, it expects the source from standard input." ) @@ -44,15 +44,25 @@ extension SwiftFormatCommand { } } - func run() throws { - try performanceMeasurementOptions.printingInstructionCountIfRequested { + func run() async throws { + try await self.performanceMeasurementOptions.printingInstructionCountIfRequested { + let diagnosticPrinter = StderrDiagnosticPrinter( + colorMode: self.formatOptions.diagnosticsColorMode + ) + + let diagnosticsEngine = DiagnosticsEngine( + diagnosticsHandlers: [diagnosticPrinter.printDiagnostic], + treatWarningsAsErrors: false + ) + let frontend = FormatFrontend( + diagnosticEngine: diagnosticsEngine, configurationOptions: configurationOptions, lintFormatOptions: formatOptions, inPlace: inPlace ) - frontend.run() - if frontend.diagnosticsEngine.hasErrors { throw ExitCode.failure } + await frontend.run() + if diagnosticsEngine.hasErrors { throw ExitCode.failure } } } } diff --git a/Sources/swift-format/Subcommands/Lint.swift b/Sources/swift-format/Subcommands/Lint.swift index 99d088a39..dbfa72560 100644 --- a/Sources/swift-format/Subcommands/Lint.swift +++ b/Sources/swift-format/Subcommands/Lint.swift @@ -14,8 +14,8 @@ import ArgumentParser extension SwiftFormatCommand { /// Emits style diagnostics for one or more files containing Swift code. - struct Lint: ParsableCommand { - static var configuration = CommandConfiguration( + struct Lint: AsyncParsableCommand { + static let configuration = CommandConfiguration( abstract: "Diagnose style issues in Swift source code", discussion: "When no files are specified, it expects the source from standard input." ) @@ -35,16 +35,25 @@ extension SwiftFormatCommand { @OptionGroup(visibility: .hidden) var performanceMeasurementOptions: PerformanceMeasurementsOptions - func run() throws { - try performanceMeasurementOptions.printingInstructionCountIfRequested { + func run() async throws { + try await self.performanceMeasurementOptions.printingInstructionCountIfRequested { + let diagnosticPrinter = StderrDiagnosticPrinter( + colorMode: self.lintOptions.diagnosticsColorMode + ) + + let diagnosticsEngine = DiagnosticsEngine( + diagnosticsHandlers: [diagnosticPrinter.printDiagnostic], + treatWarningsAsErrors: self.strict + ) + let frontend = LintFrontend( + diagnosticEngine: diagnosticsEngine, configurationOptions: configurationOptions, - lintFormatOptions: lintOptions, - treatWarningsAsErrors: strict + lintFormatOptions: lintOptions ) - frontend.run() + await frontend.run() - if frontend.diagnosticsEngine.hasErrors { + if diagnosticsEngine.hasErrors { throw ExitCode.failure } } diff --git a/Sources/swift-format/Subcommands/LintFormatOptions.swift b/Sources/swift-format/Subcommands/LintFormatOptions.swift index 25fdcaf68..c626308f0 100644 --- a/Sources/swift-format/Subcommands/LintFormatOptions.swift +++ b/Sources/swift-format/Subcommands/LintFormatOptions.swift @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import ArgumentParser +public import ArgumentParser import Foundation /// Common arguments used by the `lint` and `format` subcommands. @@ -75,7 +75,15 @@ struct LintFormatOptions: ParsableArguments { to not use colors otherwise. """ ) - var colorDiagnostics: Bool? + private var colorDiagnostics: Bool? + + var diagnosticsColorMode: StderrDiagnosticPrinter.ColorMode { + switch colorDiagnostics { + case .none: .auto + case .some(true): .on + case .some(false): .off + } + } /// Whether symlinks should be followed. @Flag( diff --git a/Sources/swift-format/Subcommands/PerformanceMeasurement.swift b/Sources/swift-format/Subcommands/PerformanceMeasurement.swift index a230aa052..53edde37a 100644 --- a/Sources/swift-format/Subcommands/PerformanceMeasurement.swift +++ b/Sources/swift-format/Subcommands/PerformanceMeasurement.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -19,15 +19,17 @@ struct PerformanceMeasurementsOptions: ParsableArguments { /// If `measureInstructions` is set, execute `body` and print the number of instructions /// executed by it. Otherwise, just execute `body` - func printingInstructionCountIfRequested(_ body: () throws -> T) rethrows -> T { + func printingInstructionCountIfRequested( + _ body: () async throws -> T + ) async rethrows -> T { if !measureInstructions { - return try body() + return try await body() } else { let startInstructions = getInstructionsExecuted() defer { print("Instructions executed: \(getInstructionsExecuted() - startInstructions)") } - return try body() + return try await body() } } } diff --git a/Sources/swift-format/SwiftFormatCommand.swift b/Sources/swift-format/SwiftFormatCommand.swift index 5b814a159..1442ab319 100644 --- a/Sources/swift-format/SwiftFormatCommand.swift +++ b/Sources/swift-format/SwiftFormatCommand.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -15,8 +15,8 @@ import ArgumentParser /// Collects the command line options that were passed to `swift-format` and dispatches to the /// appropriate subcommand. @main -struct SwiftFormatCommand: ParsableCommand { - static var configuration = CommandConfiguration( +struct SwiftFormatCommand: AsyncParsableCommand { + static let configuration = CommandConfiguration( commandName: "swift-format", abstract: "Format or lint Swift source code", subcommands: [ diff --git a/Sources/swift-format/Utilities/DiagnosticsEngine.swift b/Sources/swift-format/Utilities/DiagnosticsEngine.swift index 5d51bef71..b1d38a652 100644 --- a/Sources/swift-format/Utilities/DiagnosticsEngine.swift +++ b/Sources/swift-format/Utilities/DiagnosticsEngine.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -16,15 +16,21 @@ import SwiftSyntax /// Unifies the handling of findings from the linter, parsing errors from the syntax parser, and /// generic errors from the frontend so that they are emitted in a uniform fashion. -final class DiagnosticsEngine { +final class DiagnosticsEngine: Sendable { /// The handler functions that will be called to process diagnostics that are emitted. - private let handlers: [(Diagnostic) -> Void] + private let handlers: [@Sendable (Diagnostic) -> Void] /// A Boolean value indicating whether any errors were emitted by the diagnostics engine. - private(set) var hasErrors: Bool + var hasErrors: Bool { + self._hasErrors.value + } + private let _hasErrors = ThreadSafeBox(false) /// A Boolean value indicating whether any warnings were emitted by the diagnostics engine. - private(set) var hasWarnings: Bool + var hasWarnings: Bool { + self._hasWarnings.value + } + private let _hasWarnings = ThreadSafeBox(false) /// Whether to upgrade all warnings to errors. private let treatWarningsAsErrors: Bool @@ -34,23 +40,23 @@ final class DiagnosticsEngine { /// - Parameter diagnosticsHandlers: An array of functions, each of which takes a `Diagnostic` as /// its sole argument and returns `Void`. The functions are called whenever a diagnostic is /// received by the engine. - init(diagnosticsHandlers: [(Diagnostic) -> Void], treatWarningsAsErrors: Bool = false) { + init( + diagnosticsHandlers: [@Sendable (Diagnostic) -> Void], + treatWarningsAsErrors: Bool = false + ) { self.handlers = diagnosticsHandlers - self.hasErrors = false - self.hasWarnings = false self.treatWarningsAsErrors = treatWarningsAsErrors } /// Emits the diagnostic by passing it to the registered handlers, and tracks whether it was an /// error or warning diagnostic. - private func emit(_ diagnostic: Diagnostic) { - var diagnostic = diagnostic + private func emit(_ diagnostic: consuming Diagnostic) { if treatWarningsAsErrors, diagnostic.severity == .warning { diagnostic.severity = .error } switch diagnostic.severity { - case .error: self.hasErrors = true - case .warning: self.hasWarnings = true + case .error: self._hasErrors.value = true + case .warning: self._hasWarnings.value = true default: break } @@ -95,7 +101,7 @@ final class DiagnosticsEngine { /// /// - Parameter finding: The finding that should be emitted. func consumeFinding(_ finding: Finding) { - emit(diagnosticMessage(for: finding)) + emit(DiagnosticsEngine.diagnosticMessage(for: finding)) for note in finding.notes { emit( @@ -115,13 +121,13 @@ final class DiagnosticsEngine { _ diagnostic: SwiftDiagnostics.Diagnostic, _ location: SourceLocation ) { - emit(diagnosticMessage(for: diagnostic.diagMessage, at: location)) + emit(DiagnosticsEngine.diagnosticMessage(for: diagnostic.diagMessage, at: location)) } /// Converts a diagnostic message from the syntax parser into a diagnostic message that can be /// used by the `TSCBasic` diagnostics engine and returns it. - private func diagnosticMessage( - for message: SwiftDiagnostics.DiagnosticMessage, + private static func diagnosticMessage( + for message: any SwiftDiagnostics.DiagnosticMessage, at location: SourceLocation ) -> Diagnostic { let severity: Diagnostic.Severity @@ -141,7 +147,7 @@ final class DiagnosticsEngine { /// Converts a lint finding into a diagnostic message that can be used by the `TSCBasic` /// diagnostics engine and returns it. - private func diagnosticMessage(for finding: Finding) -> Diagnostic { + private static func diagnosticMessage(for finding: Finding) -> Diagnostic { return Diagnostic( severity: .warning, location: finding.location.map(Diagnostic.Location.init), diff --git a/Sources/swift-format/Utilities/StderrDiagnosticPrinter.swift b/Sources/swift-format/Utilities/StderrDiagnosticPrinter.swift index eb4f79c87..31f70da9f 100644 --- a/Sources/swift-format/Utilities/StderrDiagnosticPrinter.swift +++ b/Sources/swift-format/Utilities/StderrDiagnosticPrinter.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -14,7 +14,7 @@ import Dispatch import Foundation /// Manages printing of diagnostics to standard error. -final class StderrDiagnosticPrinter { +struct StderrDiagnosticPrinter { /// Determines how colors are used in printed diagnostics. enum ColorMode { /// Colors are used if stderr is detected to be connected to a TTY; otherwise, colors will not @@ -57,6 +57,7 @@ final class StderrDiagnosticPrinter { } /// Prints a diagnostic to standard error. + @Sendable func printDiagnostic(_ diagnostic: Diagnostic) { printQueue.sync { let stderr = FileHandleTextOutputStream(FileHandle.standardError) diff --git a/Sources/swift-format/Utilities/ThreadSafeBox.swift b/Sources/swift-format/Utilities/ThreadSafeBox.swift new file mode 100644 index 000000000..401248d68 --- /dev/null +++ b/Sources/swift-format/Utilities/ThreadSafeBox.swift @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import class Foundation.NSLock + +/// A thread safe container that contains a mutable value of type `T`. +/// +/// - Note: Unchecked sendable conformance because value is guarded by a lock. +// TODO: This can be replaced with Synchronization.Mutex once deployment target >= macOS 15.0 +class ThreadSafeBox: @unchecked Sendable { + /// Lock guarding `_value`. + private let lock = NSLock() + + private var _value: Value + + init(_ value: Value) { + _value = value + } + + var value: Value { + _read { + lock.lock() + defer { lock.unlock() } + yield _value + } + _modify { + lock.lock() + defer { lock.unlock() } + yield &_value + } + } + + func withLock(_ body: (inout Value) throws -> Result) rethrows -> Result { + try self.lock.withLock { + try body(&self.value) + } + } +} diff --git a/Tests/SwiftFormatTests/PrettyPrint/AssignmentExprTests.swift b/Tests/SwiftFormatTests/PrettyPrint/AssignmentExprTests.swift index f6a8604ac..507f19242 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/AssignmentExprTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/AssignmentExprTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class AssignmentExprTests: PrettyPrintTestCase { func testBasicAssignmentExprs() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/AttributeTests.swift b/Tests/SwiftFormatTests/PrettyPrint/AttributeTests.swift index 430656d4e..db979eb30 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/AttributeTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/AttributeTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class AttributeTests: PrettyPrintTestCase { func testAttributeParamSpacing() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/BinaryOperatorExprTests.swift b/Tests/SwiftFormatTests/PrettyPrint/BinaryOperatorExprTests.swift index 9fac440ba..4f42f40c9 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/BinaryOperatorExprTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/BinaryOperatorExprTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class BinaryOperatorExprTests: PrettyPrintTestCase { func testNonRangeFormationOperatorsAreSurroundedByBreaks() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/ClassDeclTests.swift b/Tests/SwiftFormatTests/PrettyPrint/ClassDeclTests.swift index deac2b9e2..55fc8345e 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/ClassDeclTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/ClassDeclTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class ClassDeclTests: PrettyPrintTestCase { func testBasicClassDeclarations() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/ClosureExprTests.swift b/Tests/SwiftFormatTests/PrettyPrint/ClosureExprTests.swift index 76a453c31..e4a30c84f 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/ClosureExprTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/ClosureExprTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class ClosureExprTests: PrettyPrintTestCase { func testBasicFunctionClosures_noPackArguments() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/CommaTests.swift b/Tests/SwiftFormatTests/PrettyPrint/CommaTests.swift index d8dc75da5..cdbac6c4c 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/CommaTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/CommaTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class CommaTests: PrettyPrintTestCase { func testArrayCommasAbsentEnabled() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/DeclNameArgumentTests.swift b/Tests/SwiftFormatTests/PrettyPrint/DeclNameArgumentTests.swift index 37d005e8b..ba9763cd1 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/DeclNameArgumentTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/DeclNameArgumentTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class DeclNameArgumentTests: PrettyPrintTestCase { func testSelectors_noPackArguments() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/DoStmtTests.swift b/Tests/SwiftFormatTests/PrettyPrint/DoStmtTests.swift index 9d013c559..3631db7a0 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/DoStmtTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/DoStmtTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class DoStmtTests: PrettyPrintTestCase { func testBasicDoStmt() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/EnumDeclTests.swift b/Tests/SwiftFormatTests/PrettyPrint/EnumDeclTests.swift index 81e764626..e4dadb05d 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/EnumDeclTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/EnumDeclTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class EnumDeclTests: PrettyPrintTestCase { func testBasicEnumDeclarations() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/ExtensionDeclTests.swift b/Tests/SwiftFormatTests/PrettyPrint/ExtensionDeclTests.swift index 1f27a4a82..284fd5661 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/ExtensionDeclTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/ExtensionDeclTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class ExtensionDeclTests: PrettyPrintTestCase { func testBasicExtensionDeclarations() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/FunctionCallTests.swift b/Tests/SwiftFormatTests/PrettyPrint/FunctionCallTests.swift index 837031317..9329e59da 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/FunctionCallTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/FunctionCallTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class FunctionCallTests: PrettyPrintTestCase { func testBasicFunctionCalls_noPackArguments() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/FunctionDeclTests.swift b/Tests/SwiftFormatTests/PrettyPrint/FunctionDeclTests.swift index 1bfa566f1..cb9757845 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/FunctionDeclTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/FunctionDeclTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class FunctionDeclTests: PrettyPrintTestCase { func testBasicFunctionDeclarations_noPackArguments() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/IfConfigTests.swift b/Tests/SwiftFormatTests/PrettyPrint/IfConfigTests.swift index 1524297bb..2d2d38fbf 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/IfConfigTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/IfConfigTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class IfConfigTests: PrettyPrintTestCase { func testBasicIfConfig() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/IfStmtTests.swift b/Tests/SwiftFormatTests/PrettyPrint/IfStmtTests.swift index 4d2685d0b..6ab85c288 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/IfStmtTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/IfStmtTests.swift @@ -12,6 +12,7 @@ import SwiftFormat import XCTest +import _SwiftFormatTestSupport final class IfStmtTests: PrettyPrintTestCase { func testIfStatement() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/IndentBlankLinesTests.swift b/Tests/SwiftFormatTests/PrettyPrint/IndentBlankLinesTests.swift index 0819c2613..5fa8e3689 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/IndentBlankLinesTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/IndentBlankLinesTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class IndentBlankLinesTests: PrettyPrintTestCase { func testIndentBlankLinesEnabled() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/InitializerDeclTests.swift b/Tests/SwiftFormatTests/PrettyPrint/InitializerDeclTests.swift index 4f0edcf91..1e4257f36 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/InitializerDeclTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/InitializerDeclTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class InitializerDeclTests: PrettyPrintTestCase { func testBasicInitializerDeclarations_noPackArguments() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/MacroDeclTests.swift b/Tests/SwiftFormatTests/PrettyPrint/MacroDeclTests.swift index 918e337e5..52a093ce4 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/MacroDeclTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/MacroDeclTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class MacroDeclTests: PrettyPrintTestCase { func testBasicMacroDeclarations_noPackArguments() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/MemberAccessExprTests.swift b/Tests/SwiftFormatTests/PrettyPrint/MemberAccessExprTests.swift index a8f31746f..32fcf1738 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/MemberAccessExprTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/MemberAccessExprTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class MemberAccessExprTests: PrettyPrintTestCase { func testMemberAccess() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/ObjectLiteralExprTests.swift b/Tests/SwiftFormatTests/PrettyPrint/ObjectLiteralExprTests.swift index 499a79d21..e38240171 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/ObjectLiteralExprTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/ObjectLiteralExprTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class ObjectLiteralExprTests: PrettyPrintTestCase { func testColorLiteral_noPackArguments() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/PrettyPrintTestCase.swift b/Tests/SwiftFormatTests/PrettyPrint/PrettyPrintTestCase.swift index eda24f531..2a1837534 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/PrettyPrintTestCase.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/PrettyPrintTestCase.swift @@ -44,7 +44,7 @@ class PrettyPrintTestCase: DiagnosingTestCase { whitespaceOnly: Bool = false, findings: [FindingSpec] = [], experimentalFeatures: Parser.ExperimentalFeatures = [], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { var configuration = configuration diff --git a/Tests/SwiftFormatTests/PrettyPrint/ProtocolDeclTests.swift b/Tests/SwiftFormatTests/PrettyPrint/ProtocolDeclTests.swift index 9be89469c..1e88cb112 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/ProtocolDeclTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/ProtocolDeclTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class ProtocolDeclTests: PrettyPrintTestCase { func testBasicProtocolDeclarations() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/RepeatStmtTests.swift b/Tests/SwiftFormatTests/PrettyPrint/RepeatStmtTests.swift index 944eb6410..bb5f54f00 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/RepeatStmtTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/RepeatStmtTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class RepeatStmtTests: PrettyPrintTestCase { func testBasicRepeatTests_noBreakBeforeWhile() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/RespectsExistingLineBreaksTests.swift b/Tests/SwiftFormatTests/PrettyPrint/RespectsExistingLineBreaksTests.swift index 09260a679..3c3ba2ffc 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/RespectsExistingLineBreaksTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/RespectsExistingLineBreaksTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport /// Basic checks and regression tests for the `respectsExistingLineBreaks` configuration setting /// in both true and false states. diff --git a/Tests/SwiftFormatTests/PrettyPrint/StringTests.swift b/Tests/SwiftFormatTests/PrettyPrint/StringTests.swift index 5b5172a28..d6439b93d 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/StringTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/StringTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// @_spi(Rules) @_spi(Testing) import SwiftFormat +import _SwiftFormatTestSupport final class StringTests: PrettyPrintTestCase { func testStrings() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/StructDeclTests.swift b/Tests/SwiftFormatTests/PrettyPrint/StructDeclTests.swift index 7d3526226..c7e5a020d 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/StructDeclTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/StructDeclTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class StructDeclTests: PrettyPrintTestCase { func testBasicStructDeclarations() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/SubscriptDeclTests.swift b/Tests/SwiftFormatTests/PrettyPrint/SubscriptDeclTests.swift index 2f3d75a60..fe69bc73c 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/SubscriptDeclTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/SubscriptDeclTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class SubscriptDeclTests: PrettyPrintTestCase { func testBasicSubscriptDeclarations() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/SwitchCaseIndentConfigTests.swift b/Tests/SwiftFormatTests/PrettyPrint/SwitchCaseIndentConfigTests.swift index 02b52d008..f3f8f149a 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/SwitchCaseIndentConfigTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/SwitchCaseIndentConfigTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport /// Tests the `indentSwitchCaseLabels` config option final class SwitchCaseIndentConfigTests: PrettyPrintTestCase { diff --git a/Tests/SwiftFormatTests/PrettyPrint/SwitchStmtTests.swift b/Tests/SwiftFormatTests/PrettyPrint/SwitchStmtTests.swift index 0aa25e122..f58ef1d00 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/SwitchStmtTests.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/SwitchStmtTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import SwiftFormat +import _SwiftFormatTestSupport final class SwitchStmtTests: PrettyPrintTestCase { func testBasicSwitch() { diff --git a/Tests/SwiftFormatTests/PrettyPrint/WhitespaceTestCase.swift b/Tests/SwiftFormatTests/PrettyPrint/WhitespaceTestCase.swift index a638bb7e0..d2189fdef 100644 --- a/Tests/SwiftFormatTests/PrettyPrint/WhitespaceTestCase.swift +++ b/Tests/SwiftFormatTests/PrettyPrint/WhitespaceTestCase.swift @@ -34,7 +34,7 @@ class WhitespaceTestCase: DiagnosingTestCase { expected: String, linelength: Int? = nil, findings: [FindingSpec], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { let markedText = MarkedText(textWithMarkers: input) diff --git a/Tests/SwiftFormatTests/Rules/BeginDocumentationCommentWithOneLineSummaryTests.swift b/Tests/SwiftFormatTests/Rules/BeginDocumentationCommentWithOneLineSummaryTests.swift index 1cf33f303..c55c7fee7 100644 --- a/Tests/SwiftFormatTests/Rules/BeginDocumentationCommentWithOneLineSummaryTests.swift +++ b/Tests/SwiftFormatTests/Rules/BeginDocumentationCommentWithOneLineSummaryTests.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// @_spi(Rules) import SwiftFormat +import XCTest import _SwiftFormatTestSupport // FIXME: We should place the diagnostic somewhere in the comment, not on the declaration. diff --git a/Tests/SwiftFormatTests/Rules/FileScopedDeclarationPrivacyTests.swift b/Tests/SwiftFormatTests/Rules/FileScopedDeclarationPrivacyTests.swift index c0a317f52..460f3d666 100644 --- a/Tests/SwiftFormatTests/Rules/FileScopedDeclarationPrivacyTests.swift +++ b/Tests/SwiftFormatTests/Rules/FileScopedDeclarationPrivacyTests.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +import Foundation import SwiftFormat @_spi(Rules) import SwiftFormat import SwiftSyntax @@ -174,7 +175,7 @@ final class FileScopedDeclarationPrivacyTests: LintOrFormatRuleTestCase { private func runWithMultipleConfigurations( source: String, testConfigurations: [TestConfiguration], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line, findingsProvider: (String, String) -> [FindingSpec] ) { diff --git a/Tests/SwiftFormatTests/Rules/ImportsXCTestVisitorTests.swift b/Tests/SwiftFormatTests/Rules/ImportsXCTestVisitorTests.swift index 0c4999019..c47f7b658 100644 --- a/Tests/SwiftFormatTests/Rules/ImportsXCTestVisitorTests.swift +++ b/Tests/SwiftFormatTests/Rules/ImportsXCTestVisitorTests.swift @@ -12,6 +12,7 @@ import SwiftFormat @_spi(Rules) @_spi(Testing) import SwiftFormat +import SwiftOperators import SwiftParser import XCTest diff --git a/Tests/SwiftFormatTests/Rules/LintOrFormatRuleTestCase.swift b/Tests/SwiftFormatTests/Rules/LintOrFormatRuleTestCase.swift index 938d956d8..807b4d571 100644 --- a/Tests/SwiftFormatTests/Rules/LintOrFormatRuleTestCase.swift +++ b/Tests/SwiftFormatTests/Rules/LintOrFormatRuleTestCase.swift @@ -37,7 +37,7 @@ class LintOrFormatRuleTestCase: DiagnosingTestCase { _ markedSource: String, findings: [FindingSpec] = [], experimentalFeatures: Parser.ExperimentalFeatures = [], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { let markedText = MarkedText(textWithMarkers: markedSource) @@ -103,7 +103,7 @@ class LintOrFormatRuleTestCase: DiagnosingTestCase { findings: [FindingSpec] = [], configuration: Configuration? = nil, experimentalFeatures: Parser.ExperimentalFeatures = [], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { let markedInput = MarkedText(textWithMarkers: input)