diff --git a/.swiftlint.yml b/.swiftlint.yml index 8816be2c8e..c9c7c06ec9 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -108,3 +108,7 @@ custom_rules: message: Rule Test Function mustn't end with `rule` regex: func\s*test\w+(r|R)ule\(\) severity: error + +unused_import: + always_keep_imports: + - SwiftSyntaxBuilder # we can't detect uses of string interpolation of swift syntax nodes diff --git a/BUILD b/BUILD index fea8eb4549..c3c505ac4f 100644 --- a/BUILD +++ b/BUILD @@ -21,9 +21,9 @@ swift_library( visibility = ["//visibility:public"], deps = [ "@com_github_jpsim_sourcekitten//:SourceKittenFramework", - "@com_github_keith_swift_syntax//:SwiftSyntax", - "@com_github_keith_swift_syntax//:SwiftSyntaxBuilder", - "@com_github_keith_swift_syntax//:SwiftSyntaxParser", + "@com_github_apple_swift_syntax//:SwiftSyntax", + "@com_github_apple_swift_syntax//:SwiftSyntaxBuilder", + "@com_github_apple_swift_syntax//:SwiftParser", "@sourcekitten_com_github_jpsim_yams//:Yams", ] + select({ "@platforms//os:linux": ["@com_github_krzyzanowskim_cryptoswift//:CryptoSwift"], diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b9b58f6b2..0c652afde9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,18 @@ #### Enhancements +* SwiftSyntax libraries have been updated from the previous 5.6 release and now + use the new parser written in Swift. + Swift 5.7+ features should now be parsed more accurately. + We've also measured an improvement in lint times of up to 15%. + This should also fix some deployment issues where the exact version of the + internal SwiftSyntax parser needed to be available. + If you notice any unexpected changes to lint results, please file an issue on + the SwiftLint issue tracker. We can look into it and if it's a SwiftSyntax + parser regression we can re-file it upstream. + [JP Simard](https://github.com/jpims) + [#4031](https://github.com/realm/SwiftLint/issues/4031) + * Add new `excludes_trivial_init` configuration for `missing_docs` rule to exclude initializers without any parameters. [Marcelo Fabri](https://github.com/marcelofabri) @@ -78,10 +90,6 @@ [SimplyDanny](https://github.com/SimplyDanny) [#4202](https://github.com/realm/SwiftLint/issues/4202) -* SwiftSyntax libraries were updated to their 5.7 releases, improving how newer - Swift language features are handled. - [JP Simard](https://github.com/jpims) - #### Bug Fixes * Respect `validates_start_with_lowercase` option when linting function names. diff --git a/Package.resolved b/Package.resolved index 307b19ec97..e44f48a1bf 100644 --- a/Package.resolved +++ b/Package.resolved @@ -33,8 +33,8 @@ "repositoryURL": "https://github.com/apple/swift-syntax.git", "state": { "branch": null, - "revision": "04d4497be6b88e524a71778d828790e9589ae1c4", - "version": "0.50700.0" + "revision": "093e5ee151d206454e2c1950d81333c4d4a4472e", + "version": null } }, { diff --git a/Package.swift b/Package.swift index caf4ba0e35..63086a85cc 100644 --- a/Package.swift +++ b/Package.swift @@ -3,21 +3,18 @@ import PackageDescription #if os(macOS) private let addCryptoSwift = false -private let staticSwiftSyntax = true #else private let addCryptoSwift = true -private let staticSwiftSyntax = false #endif let frameworkDependencies: [Target.Dependency] = [ .product(name: "SourceKittenFramework", package: "SourceKitten"), .product(name: "SwiftSyntax", package: "SwiftSyntax"), .product(name: "SwiftSyntaxBuilder", package: "SwiftSyntax"), - .product(name: "SwiftSyntaxParser", package: "SwiftSyntax"), + .product(name: "SwiftParser", package: "SwiftSyntax"), "Yams", ] + (addCryptoSwift ? ["CryptoSwift"] : []) -+ (staticSwiftSyntax ? ["lib_InternalSwiftSyntaxParser"] : []) let package = Package( name: "SwiftLint", @@ -28,7 +25,7 @@ let package = Package( ], dependencies: [ .package(name: "swift-argument-parser", url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.1.3")), - .package(name: "SwiftSyntax", url: "https://github.com/apple/swift-syntax.git", .exact("0.50700.0")), + .package(name: "SwiftSyntax", url: "https://github.com/apple/swift-syntax.git", .revision("093e5ee151d206454e2c1950d81333c4d4a4472e")), .package(url: "https://github.com/jpsim/SourceKitten.git", from: "0.33.0"), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.1"), .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"), @@ -46,11 +43,7 @@ let package = Package( ), .target( name: "SwiftLintFramework", - dependencies: frameworkDependencies, - // Pass `-dead_strip_dylibs` to ignore the dynamic version of `lib_InternalSwiftSyntaxParser` - // that ships with SwiftSyntax because we want the static version from - // `StaticInternalSwiftSyntaxParser`. - linkerSettings: staticSwiftSyntax ? [.unsafeFlags(["-Xlinker", "-dead_strip_dylibs"])] : [] + dependencies: frameworkDependencies ), .testTarget( name: "SwiftLintFrameworkTests", @@ -61,9 +54,5 @@ let package = Package( "Resources", ] ), - ] + (staticSwiftSyntax ? [.binaryTarget( - name: "lib_InternalSwiftSyntaxParser", - url: "https://github.com/keith/StaticInternalSwiftSyntaxParser/releases/download/5.7/lib_InternalSwiftSyntaxParser.xcframework.zip", - checksum: "99803975d10b2664fc37cc223a39b4e37fe3c79d3d6a2c44432007206d49db15" - )] : []) + ] ) diff --git a/Source/SwiftLintFramework/Extensions/SourceFileSyntax+SwiftLint.swift b/Source/SwiftLintFramework/Extensions/SourceFileSyntax+SwiftLint.swift index 7ddf5e98c5..6bfab99bd9 100644 --- a/Source/SwiftLintFramework/Extensions/SourceFileSyntax+SwiftLint.swift +++ b/Source/SwiftLintFramework/Extensions/SourceFileSyntax+SwiftLint.swift @@ -2,7 +2,7 @@ import SwiftSyntax extension SourceFileSyntax { func windowsOfThreeTokens() -> [(TokenSyntax, TokenSyntax, TokenSyntax)] { - Array(tokens) + Array(tokens(viewMode: .sourceAccurate)) .windows(ofCount: 3) .map { tokens in let previous = tokens[tokens.startIndex] diff --git a/Source/SwiftLintFramework/Extensions/SwiftLintFile+Cache.swift b/Source/SwiftLintFramework/Extensions/SwiftLintFile+Cache.swift index 1b92288a12..a3e8644c4a 100644 --- a/Source/SwiftLintFramework/Extensions/SwiftLintFile+Cache.swift +++ b/Source/SwiftLintFramework/Extensions/SwiftLintFile+Cache.swift @@ -1,9 +1,7 @@ import Foundation import SourceKittenFramework +import SwiftParser import SwiftSyntax -#if canImport(SwiftSyntaxParser) -import SwiftSyntaxParser -#endif private let warnSyntaxParserFailureOnceImpl: Void = { queuedPrintError("Could not parse the syntax tree for at least one file. Results may be invalid.") @@ -38,7 +36,7 @@ private var structureDictionaryCache = Cache({ file in private var syntaxTreeCache = Cache({ file -> SourceFileSyntax? in do { - return try SyntaxParser.parse(source: file.contents) + return try Parser.parse(source: file.contents) } catch { warnSyntaxParserFailureOnce() return nil diff --git a/Source/SwiftLintFramework/Helpers/CommandVisitor.swift b/Source/SwiftLintFramework/Helpers/CommandVisitor.swift index 472abc2e9d..79fa571572 100644 --- a/Source/SwiftLintFramework/Helpers/CommandVisitor.swift +++ b/Source/SwiftLintFramework/Helpers/CommandVisitor.swift @@ -9,7 +9,7 @@ final class CommandVisitor: SyntaxVisitor { init(locationConverter: SourceLocationConverter) { self.locationConverter = locationConverter - super.init() + super.init(viewMode: .sourceAccurate) } override func visitPost(_ node: TokenSyntax) { diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/BlockBasedKVORule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/BlockBasedKVORule.swift index b549a98e05..f20a2207e4 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/BlockBasedKVORule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/BlockBasedKVORule.swift @@ -36,7 +36,7 @@ public struct BlockBasedKVORule: SwiftSyntaxRule, ConfigurationProviderRule { ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/DiscouragedObjectLiteralRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/DiscouragedObjectLiteralRule.swift index 3c2fd58213..8717c3816c 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/DiscouragedObjectLiteralRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/DiscouragedObjectLiteralRule.swift @@ -44,6 +44,7 @@ private extension DiscouragedObjectLiteralRule { init(configuration: ObjectLiteralConfiguration) { self.configuration = configuration + super.init(viewMode: .sourceAccurate) } override func visitPost(_ node: ObjectLiteralExprSyntax) { diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/DiscouragedOptionalBooleanRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/DiscouragedOptionalBooleanRule.swift index be41725f9e..203ab82d0b 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/DiscouragedOptionalBooleanRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/DiscouragedOptionalBooleanRule.swift @@ -15,7 +15,7 @@ public struct DiscouragedOptionalBooleanRule: OptInRule, ConfigurationProviderRu ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/FallthroughRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/FallthroughRule.swift index 6ab457de12..8fd81c72ba 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/FallthroughRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/FallthroughRule.swift @@ -31,7 +31,7 @@ public struct FallthroughRule: SwiftSyntaxRule, ConfigurationProviderRule, OptIn ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/ForceCastRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/ForceCastRule.swift index 9d1ee2c0b1..bf219d00a0 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/ForceCastRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/ForceCastRule.swift @@ -17,7 +17,7 @@ public struct ForceCastRule: ConfigurationProviderRule, SwiftSyntaxRule { ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - ForceCastRuleVisitor() + ForceCastRuleVisitor(viewMode: .sourceAccurate) } } @@ -29,4 +29,10 @@ private final class ForceCastRuleVisitor: SyntaxVisitor, ViolationsSyntaxVisitor violationPositions.append(node.asTok.positionAfterSkippingLeadingTrivia) } } + + override func visitPost(_ node: UnresolvedAsExprSyntax) { + if node.questionOrExclamationMark?.tokenKind == .exclamationMark { + violationPositions.append(node.asTok.positionAfterSkippingLeadingTrivia) + } + } } diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/ForceTryRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/ForceTryRule.swift index a8fd5e2189..6bcd49b08c 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/ForceTryRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/ForceTryRule.swift @@ -27,7 +27,7 @@ public struct ForceTryRule: ConfigurationProviderRule, SwiftSyntaxRule { ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/ForceUnwrappingRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/ForceUnwrappingRule.swift index 46c0681286..49fdfddbc9 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/ForceUnwrappingRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/ForceUnwrappingRule.swift @@ -68,7 +68,7 @@ public struct ForceUnwrappingRule: OptInRule, SwiftSyntaxRule, ConfigurationProv ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - ForceUnwrappingVisitor() + ForceUnwrappingVisitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/GenericTypeNameRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/GenericTypeNameRule.swift index 9baaa42f5d..23787e9ff2 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/GenericTypeNameRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/GenericTypeNameRule.swift @@ -69,6 +69,7 @@ private extension GenericTypeNameRule { init(configuration: NameConfiguration) { self.configuration = configuration + super.init(viewMode: .sourceAccurate) } override func visitPost(_ node: GenericParameterSyntax) { diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/IfLetShadowingRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/IfLetShadowingRule.swift index d1a66ccf27..8540bb2b66 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/IfLetShadowingRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/IfLetShadowingRule.swift @@ -81,7 +81,7 @@ public struct IfLetShadowingRule: OptInRule, SwiftSyntaxCorrectableRule, Configu public init() {} public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } public func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? { @@ -135,7 +135,7 @@ private class Rewriter: SyntaxRewriter, ViolationsSyntaxRewriter { private extension OptionalBindingConditionSyntax { var isShadowingOptionalBinding: Bool { if let id = pattern.as(IdentifierPatternSyntax.self), - let value = initializer.value.as(IdentifierExprSyntax.self), + let value = initializer?.value.as(IdentifierExprSyntax.self), id.identifier.text == value.identifier.text { return true } diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/RedundantNilCoalescingRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/RedundantNilCoalescingRule.swift index fd38362109..cf24d47a27 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/RedundantNilCoalescingRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/RedundantNilCoalescingRule.swift @@ -24,7 +24,7 @@ public struct RedundantNilCoalescingRule: OptInRule, SwiftSyntaxCorrectableRule, ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } public func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? { diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/ReturnValueFromVoidFunctionRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/ReturnValueFromVoidFunctionRule.swift index 781256a87e..18d325264a 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/ReturnValueFromVoidFunctionRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/ReturnValueFromVoidFunctionRule.swift @@ -16,7 +16,7 @@ public struct ReturnValueFromVoidFunctionRule: ConfigurationProviderRule, OptInR ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - ReturnValueFromVoidFunctionVisitor() + ReturnValueFromVoidFunctionVisitor(viewMode: .sourceAccurate) } } @@ -26,7 +26,7 @@ private final class ReturnValueFromVoidFunctionVisitor: SyntaxVisitor, Violation override func visitPost(_ node: ReturnStmtSyntax) { if node.expression != nil, let functionNode = Syntax(node).enclosingFunction(), - functionNode.returnsVoid { + functionNode.returnsVoid { violationPositions.append(node.positionAfterSkippingLeadingTrivia) } } diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/ReturnValueFromVoidFunctionRuleExamples.swift b/Source/SwiftLintFramework/Rules/Idiomatic/ReturnValueFromVoidFunctionRuleExamples.swift index d3adb651e5..fb37b6e978 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/ReturnValueFromVoidFunctionRuleExamples.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/ReturnValueFromVoidFunctionRuleExamples.swift @@ -86,7 +86,41 @@ internal struct ReturnValueFromVoidFunctionRuleExamples { var foo: Int { return 0 } - """) + """), + Example(#""" + final class SearchMessagesDataSource: ValueCellDataSource { + internal enum Section: Int { + case emptyState + case messageThreads + } + + internal func load(messageThreads: [MessageThread]) { + self.set( + values: messageThreads, + cellClass: MessageThreadCell.self, + inSection: Section.messageThreads.rawValue + ) + } + + internal func emptyState(isVisible: Bool) { + self.set( + cellIdentifiers: isVisible ? ["SearchMessagesEmptyState"] : [], + inSection: Section.emptyState.rawValue + ) + } + + internal override func configureCell(tableCell cell: UITableViewCell, withValue value: Any) { + switch (cell, value) { + case let (cell as MessageThreadCell, value as MessageThread): + cell.configureWith(value: value) + case (is StaticTableViewCell, is Void): + return + default: + assertionFailure("Unrecognized combo: \(cell), \(value).") + } + } + } + """#, excludeFromDocumentation: true) ] static let triggeringExamples = [ diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/SyntacticSugarRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/SyntacticSugarRule.swift index eb0e63cbc5..888096b3f6 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/SyntacticSugarRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/SyntacticSugarRule.swift @@ -18,7 +18,7 @@ public struct SyntacticSugarRule: CorrectableRule, ConfigurationProviderRule, So ) public func validate(file: SwiftLintFile) -> [StyleViolation] { - let visitor = SyntacticSugarRuleVisitor() + let visitor = SyntacticSugarRuleVisitor(viewMode: .sourceAccurate) return visitor.walk(file: file) { visitor in flattenViolations(visitor.violations) }.map { violation in @@ -34,7 +34,7 @@ public struct SyntacticSugarRule: CorrectableRule, ConfigurationProviderRule, So } public func correct(file: SwiftLintFile) -> [Correction] { - let visitor = SyntacticSugarRuleVisitor() + let visitor = SyntacticSugarRuleVisitor(viewMode: .sourceAccurate) return visitor.walk(file: file) { visitor in var context = CorrectingContext(rule: self, file: file, contents: file.contents) context.correctViolations(visitor.violations) @@ -137,13 +137,6 @@ private final class SyntacticSugarRuleVisitor: SyntaxVisitor { } } - override func visitPost(_ node: AsExprSyntax) { - // json["recommendations"] as? ↓Array<[String: Any]> - if let violation = violation(in: node.typeName) { - violations.append(violation) - } - } - override func visitPost(_ node: TypeInitializerClauseSyntax) { // typealias Document = ↓Dictionary if let violation = violation(in: node.value) { @@ -172,7 +165,7 @@ private final class SyntacticSugarRuleVisitor: SyntaxVisitor { // let x = ↓Array.array(of: object) // Skip checks for 'self' or \T Dictionary.self if let parent = node.parent?.as(MemberAccessExprSyntax.self), - let lastToken = Array(parent.tokens).last?.tokenKind, + let lastToken = Array(parent.tokens(viewMode: .sourceAccurate)).last?.tokenKind, [.selfKeyword, .identifier("Type"), .identifier("none"), .identifier("Index")].contains(lastToken) { return } @@ -194,6 +187,12 @@ private final class SyntacticSugarRuleVisitor: SyntaxVisitor { .map { violations.append($0) } } + override func visitPost(_ node: TypeExprSyntax) { + if let violation = violation(in: node.type) { + violations.append(violation) + } + } + private func violation(in typeSyntax: TypeSyntax?) -> SyntacticSugarRuleViolation? { if let optionalType = typeSyntax?.as(OptionalTypeSyntax.self) { return violation(in: optionalType.wrappedType) diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/SyntacticSugarRuleExamples.swift b/Source/SwiftLintFramework/Rules/Idiomatic/SyntacticSugarRuleExamples.swift index 3eaa9a6509..85f73eb2be 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/SyntacticSugarRuleExamples.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/SyntacticSugarRuleExamples.swift @@ -57,6 +57,11 @@ internal enum SyntacticSugarRuleExamples { Example(""" @_specialize(where S == ↓Array) public init(_ elements: S) + """), + + Example(""" + let dict: [String: Any] = [:] + _ = dict["key"] as? ↓Optional ?? Optional.none """) ] diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/ToggleBoolRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/ToggleBoolRule.swift index b410267a70..f16387725d 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/ToggleBoolRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/ToggleBoolRule.swift @@ -32,7 +32,7 @@ public struct ToggleBoolRule: SwiftSyntaxCorrectableRule, ConfigurationProviderR ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } public func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? { @@ -81,22 +81,8 @@ private extension ToggleBoolRule { correctionPositions.append(node.positionAfterSkippingLeadingTrivia) - let functionCall = FunctionCallExprSyntax { functionCall in - functionCall.useCalledExpression( - ExprSyntax( - MemberAccessExprSyntax { memberAccess in - memberAccess.useBase(node.first!.withoutTrivia()) - memberAccess.useDot(.period) - memberAccess.useName(.identifier("toggle")) - } - ) - ) - functionCall.useLeftParen(.leftParen) - functionCall.useRightParen(.rightParen) - } - let newNode = node - .replacing(childAt: 0, with: ExprSyntax(functionCall)) + .replacing(childAt: 0, with: "\(node.first!.withoutTrivia()).toggle()") .removingLast() .removingLast() .withLeadingTrivia(node.leadingTrivia ?? .zero) diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/UnavailableConditionRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/UnavailableConditionRule.swift index db445a1b8a..9f78f3a723 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/UnavailableConditionRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/UnavailableConditionRule.swift @@ -73,7 +73,7 @@ public struct UnavailableConditionRule: ConfigurationProviderRule, SourceKitFree ) public func validate(file: SwiftLintFile) -> [StyleViolation] { - let visitor = UnavailableConditionRuleVisitor() + let visitor = UnavailableConditionRuleVisitor(viewMode: .sourceAccurate) return visitor.walk(file: file, handler: \.availabilityChecks).map { check in StyleViolation( ruleDescription: Self.description, diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/UnneededBreakInSwitchRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/UnneededBreakInSwitchRule.swift index 7268c2bf6e..f01d643ab6 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/UnneededBreakInSwitchRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/UnneededBreakInSwitchRule.swift @@ -51,7 +51,7 @@ public struct UnneededBreakInSwitchRule: SwiftSyntaxRule, ConfigurationProviderR ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - UnneededBreakInSwitchRuleVisitor() + UnneededBreakInSwitchRuleVisitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/UntypedErrorInCatchRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/UntypedErrorInCatchRule.swift index d25039c9e0..45916d7b70 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/UntypedErrorInCatchRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/UntypedErrorInCatchRule.swift @@ -88,7 +88,7 @@ public struct UntypedErrorInCatchRule: OptInRule, ConfigurationProviderRule, Swi ]) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - UntypedErrorInCatchRuleVisitor() + UntypedErrorInCatchRuleVisitor(viewMode: .sourceAccurate) } public func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? { @@ -167,7 +167,7 @@ private final class UntypedErrorInCatchRuleRewriter: SyntaxRewriter, ViolationsS return super.visit( node .withCatchKeyword(node.catchKeyword.withTrailingTrivia(.spaces(1))) - .withCatchItems(SyntaxFactory.makeBlankCatchItemList()) + .withCatchItems(CatchItemListSyntax([])) ) } } diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift index 026825cb4c..701a3a5dc2 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift @@ -109,7 +109,7 @@ public struct VoidFunctionInTernaryConditionRule: ConfigurationProviderRule, Swi ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - VoidFunctionInTernaryConditionVisitor() + VoidFunctionInTernaryConditionVisitor(viewMode: .sourceAccurate) } } @@ -130,11 +130,26 @@ private class VoidFunctionInTernaryConditionVisitor: SyntaxVisitor, ViolationsSy violationPositions.append(node.questionMark.positionAfterSkippingLeadingTrivia) } + + override func visitPost(_ node: UnresolvedTernaryExprSyntax) { + guard node.firstChoice.is(FunctionCallExprSyntax.self), + let parent = node.parent?.as(ExprListSyntax.self), + parent.last?.is(FunctionCallExprSyntax.self) == true, + !parent.containsAssignment, + let grandparent = parent.parent, + grandparent.is(SequenceExprSyntax.self), + let blockItem = grandparent.parent?.as(CodeBlockItemSyntax.self), + !blockItem.isImplicitReturn else { + return + } + + violationPositions.append(node.questionMark.positionAfterSkippingLeadingTrivia) + } } private extension ExprListSyntax { var containsAssignment: Bool { - return children.contains(where: { $0.is(AssignmentExprSyntax.self) }) + return children(viewMode: .sourceAccurate).contains(where: { $0.is(AssignmentExprSyntax.self) }) } } @@ -151,7 +166,7 @@ private extension CodeBlockItemSyntax { return false } - return parent.children.count == 1 && grandparent.is(ClosureExprSyntax.self) + return parent.children(viewMode: .sourceAccurate).count == 1 && grandparent.is(ClosureExprSyntax.self) } var isFunctionImplicitReturn: Bool { @@ -160,7 +175,7 @@ private extension CodeBlockItemSyntax { return false } - return parent.children.count == 1 && functionDecl.signature.allowsImplicitReturns + return parent.children(viewMode: .sourceAccurate).count == 1 && functionDecl.signature.allowsImplicitReturns } var isVariableImplicitReturn: Bool { @@ -169,7 +184,7 @@ private extension CodeBlockItemSyntax { } let isVariableDecl = parent.parent?.parent?.as(PatternBindingSyntax.self) != nil - return parent.children.count == 1 && isVariableDecl + return parent.children(viewMode: .sourceAccurate).count == 1 && isVariableDecl } var isSubscriptImplicitReturn: Bool { @@ -178,7 +193,7 @@ private extension CodeBlockItemSyntax { return false } - return parent.children.count == 1 && subscriptDecl.allowsImplicitReturns + return parent.children(viewMode: .sourceAccurate).count == 1 && subscriptDecl.allowsImplicitReturns } var isAcessorImplicitReturn: Bool { @@ -187,7 +202,7 @@ private extension CodeBlockItemSyntax { return false } - return parent.children.count == 1 + return parent.children(viewMode: .sourceAccurate).count == 1 } } diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/XCTFailMessageRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/XCTFailMessageRule.swift index 96d9424817..2cf67666b0 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/XCTFailMessageRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/XCTFailMessageRule.swift @@ -37,7 +37,7 @@ public struct XCTFailMessageRule: SwiftSyntaxRule, ConfigurationProviderRule { ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Lint/AnyObjectProtocolRule.swift b/Source/SwiftLintFramework/Rules/Lint/AnyObjectProtocolRule.swift index d868eb9cd5..c2849a129b 100644 --- a/Source/SwiftLintFramework/Rules/Lint/AnyObjectProtocolRule.swift +++ b/Source/SwiftLintFramework/Rules/Lint/AnyObjectProtocolRule.swift @@ -1,5 +1,4 @@ import SwiftSyntax -import SwiftSyntaxBuilder private let warnDeprecatedOnceImpl: Void = { queuedPrintError(""" @@ -45,7 +44,7 @@ public struct AnyObjectProtocolRule: SwiftSyntaxCorrectableRule, OptInRule, Conf public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { warnDeprecatedOnce() - return Visitor() + return Visitor(viewMode: .sourceAccurate) } public func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? { @@ -95,7 +94,7 @@ private extension AnyObjectProtocolRule { return super.visit( node.withTypeName( TypeSyntax( - SimpleTypeIdentifierSyntax { $0.useName(.identifier("AnyObject")) } + SimpleTypeIdentifierSyntax(name: .identifier("AnyObject"), genericArgumentClause: nil) .withLeadingTrivia(typeName.leadingTrivia ?? .zero) .withTrailingTrivia(typeName.trailingTrivia ?? .zero) ) diff --git a/Source/SwiftLintFramework/Rules/Lint/ArrayInitRule.swift b/Source/SwiftLintFramework/Rules/Lint/ArrayInitRule.swift index f361f6ac6e..594bf57a3b 100644 --- a/Source/SwiftLintFramework/Rules/Lint/ArrayInitRule.swift +++ b/Source/SwiftLintFramework/Rules/Lint/ArrayInitRule.swift @@ -52,7 +52,7 @@ public struct ArrayInitRule: SwiftSyntaxRule, ConfigurationProviderRule, OptInRu ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Lint/ClassDelegateProtocolRule.swift b/Source/SwiftLintFramework/Rules/Lint/ClassDelegateProtocolRule.swift index f0ee87cb2b..71c5bbddba 100644 --- a/Source/SwiftLintFramework/Rules/Lint/ClassDelegateProtocolRule.swift +++ b/Source/SwiftLintFramework/Rules/Lint/ClassDelegateProtocolRule.swift @@ -32,7 +32,7 @@ public struct ClassDelegateProtocolRule: SwiftSyntaxRule, ConfigurationProviderR ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Lint/DynamicInlineRule.swift b/Source/SwiftLintFramework/Rules/Lint/DynamicInlineRule.swift index da186646c0..e0299aa214 100644 --- a/Source/SwiftLintFramework/Rules/Lint/DynamicInlineRule.swift +++ b/Source/SwiftLintFramework/Rules/Lint/DynamicInlineRule.swift @@ -25,7 +25,7 @@ public struct DynamicInlineRule: SwiftSyntaxRule, ConfigurationProviderRule { ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } @@ -50,7 +50,6 @@ private extension DynamicInlineRule { private extension AttributeSyntax { var isInlineAlways: Bool { attributeName.text == "inline" && - argument?.isToken == true && argument?.firstToken?.tokenKind == .identifier("__always") } } diff --git a/Source/SwiftLintFramework/Rules/Lint/EmptyXCTestMethodRule.swift b/Source/SwiftLintFramework/Rules/Lint/EmptyXCTestMethodRule.swift index 623fbf6776..7b4dcb6d06 100644 --- a/Source/SwiftLintFramework/Rules/Lint/EmptyXCTestMethodRule.swift +++ b/Source/SwiftLintFramework/Rules/Lint/EmptyXCTestMethodRule.swift @@ -15,7 +15,7 @@ public struct EmptyXCTestMethodRule: OptInRule, ConfigurationProviderRule, Swift ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - EmptyXCTestMethodRuleVisitor() + EmptyXCTestMethodRuleVisitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Lint/InertDeferRule.swift b/Source/SwiftLintFramework/Rules/Lint/InertDeferRule.swift index 816b9aba23..247eed751f 100644 --- a/Source/SwiftLintFramework/Rules/Lint/InertDeferRule.swift +++ b/Source/SwiftLintFramework/Rules/Lint/InertDeferRule.swift @@ -51,7 +51,7 @@ public struct InertDeferRule: ConfigurationProviderRule, SwiftSyntaxRule { ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Lint/UnownedVariableCaptureRule.swift b/Source/SwiftLintFramework/Rules/Lint/UnownedVariableCaptureRule.swift index 9c6fb130ed..43c5d70327 100644 --- a/Source/SwiftLintFramework/Rules/Lint/UnownedVariableCaptureRule.swift +++ b/Source/SwiftLintFramework/Rules/Lint/UnownedVariableCaptureRule.swift @@ -26,7 +26,7 @@ public struct UnownedVariableCaptureRule: SwiftSyntaxRule, OptInRule, Configurat ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - UnownedVariableCaptureRuleVisitor() + UnownedVariableCaptureRuleVisitor(viewMode: .sourceAccurate) } } @@ -38,6 +38,12 @@ private final class UnownedVariableCaptureRuleVisitor: SyntaxVisitor, Violations violationPositions.append(token.positionAfterSkippingLeadingTrivia) } } + + override func visitPost(_ node: TokenListSyntax) { + if case .contextualKeyword("unowned") = node.first?.tokenKind { + violationPositions.append(node.positionAfterSkippingLeadingTrivia) + } + } } private extension ClosureCaptureItemSyntax { diff --git a/Source/SwiftLintFramework/Rules/Lint/YodaConditionRule.swift b/Source/SwiftLintFramework/Rules/Lint/YodaConditionRule.swift index 50a6c612d3..89b41ca652 100644 --- a/Source/SwiftLintFramework/Rules/Lint/YodaConditionRule.swift +++ b/Source/SwiftLintFramework/Rules/Lint/YodaConditionRule.swift @@ -37,7 +37,7 @@ public struct YodaConditionRule: OptInRule, ConfigurationProviderRule, SwiftSynt ]) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - YodaConditionRuleVisitor() + YodaConditionRuleVisitor(viewMode: .sourceAccurate) } } @@ -65,7 +65,7 @@ private final class YodaConditionRuleVisitor: SyntaxVisitor, ViolationsSyntaxVis } private func visit(condition: ExprSyntax) { - guard let children = condition.as(SequenceExprSyntax.self)?.elements.children else { + guard let children = condition.as(SequenceExprSyntax.self)?.elements.children(viewMode: .sourceAccurate) else { return } let comparisonOperators = children diff --git a/Source/SwiftLintFramework/Rules/Metrics/LargeTupleRule.swift b/Source/SwiftLintFramework/Rules/Metrics/LargeTupleRule.swift index dc77a1abde..672ed227bd 100644 --- a/Source/SwiftLintFramework/Rules/Metrics/LargeTupleRule.swift +++ b/Source/SwiftLintFramework/Rules/Metrics/LargeTupleRule.swift @@ -15,7 +15,7 @@ public struct LargeTupleRule: SourceKitFreeRule, ConfigurationProviderRule { ) public func validate(file: SwiftLintFile) -> [StyleViolation] { - LargeTupleRuleVisitor() + LargeTupleRuleVisitor(viewMode: .sourceAccurate) .walk(file: file, handler: \.violationPositions) .sorted(by: { $0.position < $1.position }) .compactMap { position, size in diff --git a/Source/SwiftLintFramework/Rules/Performance/EmptyCollectionLiteralRule.swift b/Source/SwiftLintFramework/Rules/Performance/EmptyCollectionLiteralRule.swift index 22a2a3c454..dee3ef9d87 100644 --- a/Source/SwiftLintFramework/Rules/Performance/EmptyCollectionLiteralRule.swift +++ b/Source/SwiftLintFramework/Rules/Performance/EmptyCollectionLiteralRule.swift @@ -29,7 +29,7 @@ public struct EmptyCollectionLiteralRule: SwiftSyntaxRule, ConfigurationProvider ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Performance/EmptyStringRule.swift b/Source/SwiftLintFramework/Rules/Performance/EmptyStringRule.swift index d05844693f..ba7b621d06 100644 --- a/Source/SwiftLintFramework/Rules/Performance/EmptyStringRule.swift +++ b/Source/SwiftLintFramework/Rules/Performance/EmptyStringRule.swift @@ -25,7 +25,7 @@ public struct EmptyStringRule: ConfigurationProviderRule, OptInRule, SwiftSyntax ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Performance/FlatMapOverMapReduceRule.swift b/Source/SwiftLintFramework/Rules/Performance/FlatMapOverMapReduceRule.swift index 19e308a2bb..788c679857 100644 --- a/Source/SwiftLintFramework/Rules/Performance/FlatMapOverMapReduceRule.swift +++ b/Source/SwiftLintFramework/Rules/Performance/FlatMapOverMapReduceRule.swift @@ -20,7 +20,7 @@ public struct FlatMapOverMapReduceRule: SwiftSyntaxRule, OptInRule, Configuratio ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Style/ClosingBraceRule.swift b/Source/SwiftLintFramework/Rules/Style/ClosingBraceRule.swift index 23d4a032a8..3fb9ec0d9b 100644 --- a/Source/SwiftLintFramework/Rules/Style/ClosingBraceRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/ClosingBraceRule.swift @@ -24,7 +24,7 @@ public struct ClosingBraceRule: SwiftSyntaxCorrectableRule, ConfigurationProvide ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } public func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? { diff --git a/Source/SwiftLintFramework/Rules/Style/ClosureSpacingRule.swift b/Source/SwiftLintFramework/Rules/Style/ClosureSpacingRule.swift index 983bb6b018..bc82c227c9 100644 --- a/Source/SwiftLintFramework/Rules/Style/ClosureSpacingRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/ClosureSpacingRule.swift @@ -60,6 +60,7 @@ private final class ClosureSpacingRuleVisitor: SyntaxVisitor, ViolationsSyntaxVi init(locationConverter: SourceLocationConverter) { self.locationConverter = locationConverter + super.init(viewMode: .sourceAccurate) } override func visitPost(_ node: ClosureExprSyntax) { diff --git a/Source/SwiftLintFramework/Rules/Style/ColonRule.swift b/Source/SwiftLintFramework/Rules/Style/ColonRule.swift index c8d4a02ff8..3445ae7005 100644 --- a/Source/SwiftLintFramework/Rules/Style/ColonRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/ColonRule.swift @@ -32,7 +32,7 @@ public struct ColonRule: SubstitutionCorrectableRule, ConfigurationProviderRule, return [] } - let visitor = ColonRuleVisitor() + let visitor = ColonRuleVisitor(viewMode: .sourceAccurate) visitor.walk(syntaxTree) let positionsToSkip = visitor.positionsToSkip let dictionaryPositions = visitor.dictionaryPositions @@ -101,7 +101,7 @@ private final class ColonRuleVisitor: SyntaxVisitor { override func visitPost(_ node: DeclNameArgumentsSyntax) { positionsToSkip.append( - contentsOf: node.tokens + contentsOf: node.tokens(viewMode: .sourceAccurate) .filter { $0.tokenKind == .colon } .map(\.position) ) @@ -117,6 +117,10 @@ private final class ColonRuleVisitor: SyntaxVisitor { positionsToSkip.append(node.colon.position) } + override func visitPost(_ node: UnresolvedTernaryExprSyntax) { + positionsToSkip.append(node.colonMark.position) + } + override func visitPost(_ node: DictionaryElementSyntax) { dictionaryPositions.append(node.colon.position) } diff --git a/Source/SwiftLintFramework/Rules/Style/CommaInheritanceRule.swift b/Source/SwiftLintFramework/Rules/Style/CommaInheritanceRule.swift index cd767f567f..c6bc1015ca 100644 --- a/Source/SwiftLintFramework/Rules/Style/CommaInheritanceRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/CommaInheritanceRule.swift @@ -77,7 +77,7 @@ public struct CommaInheritanceRule: OptInRule, SubstitutionCorrectableRule, Conf } public func violationRanges(in file: SwiftLintFile) -> [NSRange] { - let visitor = CommaInheritanceRuleVisitor() + let visitor = CommaInheritanceRuleVisitor(viewMode: .sourceAccurate) return visitor.walk(file: file) { visitor -> [ByteRange] in visitor.violationRanges }.compactMap { @@ -90,7 +90,7 @@ private final class CommaInheritanceRuleVisitor: SyntaxVisitor { private(set) var violationRanges: [ByteRange] = [] override func visitPost(_ node: InheritedTypeSyntax) { - for type in node.children { + for type in node.children(viewMode: .sourceAccurate) { guard let composition = type.as(CompositionTypeSyntax.self) else { continue } diff --git a/Source/SwiftLintFramework/Rules/Style/ComputedAccessorsOrderRule.swift b/Source/SwiftLintFramework/Rules/Style/ComputedAccessorsOrderRule.swift index 751c2c15d6..394de8be90 100644 --- a/Source/SwiftLintFramework/Rules/Style/ComputedAccessorsOrderRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/ComputedAccessorsOrderRule.swift @@ -51,6 +51,7 @@ private final class ComputedAccessorsOrderRuleVisitor: SyntaxVisitor { init(expectedOrder: ComputedAccessorsOrderRuleConfiguration.Order) { self.expectedOrder = expectedOrder + super.init(viewMode: .sourceAccurate) } override func visitPost(_ node: AccessorBlockSyntax) { diff --git a/Source/SwiftLintFramework/Rules/Style/EmptyEnumArgumentsRule.swift b/Source/SwiftLintFramework/Rules/Style/EmptyEnumArgumentsRule.swift index b0acaccecf..88df6e5303 100644 --- a/Source/SwiftLintFramework/Rules/Style/EmptyEnumArgumentsRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/EmptyEnumArgumentsRule.swift @@ -108,7 +108,7 @@ public struct EmptyEnumArgumentsRule: SwiftSyntaxCorrectableRule, ConfigurationP ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } public func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? { diff --git a/Source/SwiftLintFramework/Rules/Style/EmptyParenthesesWithTrailingClosureRule.swift b/Source/SwiftLintFramework/Rules/Style/EmptyParenthesesWithTrailingClosureRule.swift index 02d033cc95..eaf4fcb26d 100644 --- a/Source/SwiftLintFramework/Rules/Style/EmptyParenthesesWithTrailingClosureRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/EmptyParenthesesWithTrailingClosureRule.swift @@ -47,7 +47,7 @@ public struct EmptyParenthesesWithTrailingClosureRule: SwiftSyntaxCorrectableRul ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } public func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? { diff --git a/Source/SwiftLintFramework/Rules/Style/ImplicitGetterRule.swift b/Source/SwiftLintFramework/Rules/Style/ImplicitGetterRule.swift index b30d088d1b..4ca3d4c971 100644 --- a/Source/SwiftLintFramework/Rules/Style/ImplicitGetterRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/ImplicitGetterRule.swift @@ -15,7 +15,7 @@ public struct ImplicitGetterRule: ConfigurationProviderRule, SourceKitFreeRule { ) public func validate(file: SwiftLintFile) -> [StyleViolation] { - ImplicitGetterRuleVisitor() + ImplicitGetterRuleVisitor(viewMode: .sourceAccurate) .walk(file: file, handler: \.violationPositions) .sorted { $0.position < $1.position } .map { violation in diff --git a/Source/SwiftLintFramework/Rules/Style/MultipleClosuresWithTrailingClosureRule.swift b/Source/SwiftLintFramework/Rules/Style/MultipleClosuresWithTrailingClosureRule.swift index 5b02cb6932..18343619f1 100644 --- a/Source/SwiftLintFramework/Rules/Style/MultipleClosuresWithTrailingClosureRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/MultipleClosuresWithTrailingClosureRule.swift @@ -38,7 +38,7 @@ public struct MultipleClosuresWithTrailingClosureRule: SwiftSyntaxRule, Configur ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } } diff --git a/Source/SwiftLintFramework/Rules/Style/NoSpaceInMethodCallRule.swift b/Source/SwiftLintFramework/Rules/Style/NoSpaceInMethodCallRule.swift index 8148b2ecee..d750371aa6 100644 --- a/Source/SwiftLintFramework/Rules/Style/NoSpaceInMethodCallRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/NoSpaceInMethodCallRule.swift @@ -46,7 +46,7 @@ public struct NoSpaceInMethodCallRule: SwiftSyntaxCorrectableRule, Configuration ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } public func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? { diff --git a/Source/SwiftLintFramework/Rules/Style/OperatorUsageWhitespaceRule.swift b/Source/SwiftLintFramework/Rules/Style/OperatorUsageWhitespaceRule.swift index 86220a0b4e..683310960c 100644 --- a/Source/SwiftLintFramework/Rules/Style/OperatorUsageWhitespaceRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/OperatorUsageWhitespaceRule.swift @@ -126,6 +126,7 @@ private class OperatorUsageWhitespaceVisitor: SyntaxVisitor { init(allowedNoSpaceOperators: [String]) { self.allowedNoSpaceOperators = Set(allowedNoSpaceOperators) + super.init(viewMode: .sourceAccurate) } override func visitPost(_ node: BinaryOperatorExprSyntax) { @@ -162,6 +163,16 @@ private class OperatorUsageWhitespaceVisitor: SyntaxVisitor { } } + override func visitPost(_ node: UnresolvedTernaryExprSyntax) { + if let violation = violation(operatorToken: node.colonMark) { + violationRanges.append(violation) + } + + if let violation = violation(operatorToken: node.questionMark) { + violationRanges.append(violation) + } + } + private func violation(operatorToken: TokenSyntax) -> (ByteRange, String)? { guard let previousToken = operatorToken.previousToken, let nextToken = operatorToken.nextToken else { @@ -216,8 +227,8 @@ private extension Trivia { switch element { case .blockComment, .docLineComment, .docBlockComment, .lineComment: return true - case .carriageReturnLineFeeds, .carriageReturns, .formfeeds, - .garbageText, .newlines, .spaces, .verticalTabs, .tabs: + case .carriageReturnLineFeeds, .carriageReturns, .formfeeds, .newlines, + .shebang, .spaces, .tabs, .unexpectedText, .verticalTabs: return false } } diff --git a/Source/SwiftLintFramework/Rules/Style/SelfBindingRule.swift b/Source/SwiftLintFramework/Rules/Style/SelfBindingRule.swift index 214ffa3566..44c499c9c5 100644 --- a/Source/SwiftLintFramework/Rules/Style/SelfBindingRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/SelfBindingRule.swift @@ -74,12 +74,13 @@ private final class SelfBindingRuleVisitor: SyntaxVisitor, ViolationsSyntaxVisit init(bindIdentifier: String) { self.bindIdentifier = bindIdentifier + super.init(viewMode: .sourceAccurate) } override func visitPost(_ node: OptionalBindingConditionSyntax) { if let identifierPattern = node.pattern.as(IdentifierPatternSyntax.self), identifierPattern.identifier.text != bindIdentifier, - let initializerIdentifier = node.initializer.value.as(IdentifierExprSyntax.self), + let initializerIdentifier = node.initializer?.value.as(IdentifierExprSyntax.self), initializerIdentifier.identifier.text == "self" { violationPositions.append(identifierPattern.positionAfterSkippingLeadingTrivia) } @@ -103,7 +104,7 @@ private final class SelfBindingRuleRewriter: SyntaxRewriter, ViolationsSyntaxRew override func visit(_ node: OptionalBindingConditionSyntax) -> Syntax { guard let identifierPattern = node.pattern.as(IdentifierPatternSyntax.self), identifierPattern.identifier.text != bindIdentifier, - let initializerIdentifier = node.initializer.value.as(IdentifierExprSyntax.self), + let initializerIdentifier = node.initializer?.value.as(IdentifierExprSyntax.self), initializerIdentifier.identifier.text == "self" else { return super.visit(node) } diff --git a/Source/SwiftLintFramework/Rules/Style/UnneededParenthesesInClosureArgumentRule.swift b/Source/SwiftLintFramework/Rules/Style/UnneededParenthesesInClosureArgumentRule.swift index 289c5d1a14..bb96aa8a23 100644 --- a/Source/SwiftLintFramework/Rules/Style/UnneededParenthesesInClosureArgumentRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/UnneededParenthesesInClosureArgumentRule.swift @@ -76,7 +76,7 @@ public struct UnneededParenthesesInClosureArgumentRule: ConfigurationProviderRul ) public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? { - Visitor() + Visitor(viewMode: .sourceAccurate) } public func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? { @@ -134,15 +134,15 @@ private final class Rewriter: SyntaxRewriter, ViolationsSyntaxRewriter { } let isLast = idx == clause.parameterList.count - 1 - return SyntaxFactory.makeClosureParam( + return ClosureParamSyntax( name: name, - trailingComma: isLast ? nil : SyntaxFactory.makeCommaToken(trailingTrivia: .spaces(1)) + trailingComma: isLast ? nil : .commaToken(trailingTrivia: Trivia(pieces: [.spaces(1)])) ) } correctionPositions.append(clause.positionAfterSkippingLeadingTrivia) - let paramList = SyntaxFactory.makeClosureParamList(items).withTrailingTrivia(.spaces(1)) + let paramList = ClosureParamListSyntax(items).withTrailingTrivia(.spaces(1)) return super.visit(node.withInput(Syntax(paramList))) } } diff --git a/bazel/SwiftSyntax.BUILD b/bazel/SwiftSyntax.BUILD new file mode 100644 index 0000000000..569b043a1e --- /dev/null +++ b/bazel/SwiftSyntax.BUILD @@ -0,0 +1,49 @@ +load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") + +cc_library( + name = "_CSwiftSyntax", + srcs = glob(["Sources/_CSwiftSyntax/src/*.c"]), + hdrs = glob(["Sources/_CSwiftSyntax/include/*.h"]), + linkstatic = True, + tags = ["swift_module"], +) + +swift_library( + name = "SwiftSyntax", + srcs = glob(["Sources/SwiftSyntax/**/*.swift"]), + module_name = "SwiftSyntax", + private_deps = ["_CSwiftSyntax"], + visibility = ["//visibility:public"], +) + +swift_library( + name = "SwiftBasicFormat", + srcs = glob(["Sources/SwiftBasicFormat/**/*.swift"]), + module_name = "SwiftBasicFormat", + visibility = ["//visibility:public"], + deps = [":SwiftSyntax"], +) + +swift_library( + name = "SwiftDiagnostics", + srcs = glob(["Sources/SwiftDiagnostics/**/*.swift"]), + module_name = "SwiftDiagnostics", + visibility = ["//visibility:public"], + deps = [":SwiftSyntax"], +) + +swift_library( + name = "SwiftParser", + srcs = glob(["Sources/SwiftParser/**/*.swift"]), + module_name = "SwiftParser", + visibility = ["//visibility:public"], + deps = [":SwiftSyntax", ":SwiftDiagnostics", ":SwiftBasicFormat"], +) + +swift_library( + name = "SwiftSyntaxBuilder", + srcs = glob(["Sources/SwiftSyntaxBuilder/**/*.swift"]), + module_name = "SwiftSyntaxBuilder", + visibility = ["//visibility:public"], + deps = [":SwiftSyntax", ":SwiftBasicFormat", ":SwiftParser"], +) diff --git a/bazel/deps.bzl b/bazel/deps.bzl index 894c40c27b..c1c3de88d6 100644 --- a/bazel/deps.bzl +++ b/bazel/deps.bzl @@ -1,5 +1,4 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -load("@com_github_keith_swift_syntax_bazel//:deps.bzl", "swift_syntax_deps") load("@com_github_jpsim_sourcekitten//bazel:repos.bzl", "sourcekitten_repos") def _default_extra_swift_sources_impl(ctx): @@ -27,5 +26,4 @@ def swiftlint_deps(): if not native.existing_rule("swiftlint_extra_rules"): _default_extra_swift_sources(name = "swiftlint_extra_rules") - swift_syntax_deps() sourcekitten_repos() diff --git a/bazel/repos.bzl b/bazel/repos.bzl index f5b52c49c5..fa09afaf62 100644 --- a/bazel/repos.bzl +++ b/bazel/repos.bzl @@ -18,10 +18,11 @@ def swiftlint_repos(): ) http_archive( - name = "com_github_keith_swift_syntax_bazel", - sha256 = "ca7f3a8099e4e7a454f45abea1ededabe209d9f6964df87566a142e3b281fe24", - strip_prefix = "swift-syntax-bazel-14.0.0.14A309", - url = "https://github.com/keith/swift-syntax-bazel/archive/refs/tags/14.0.0.14A309.tar.gz", + name = "com_github_apple_swift_syntax", + sha256 = "032a14f76285b2edc66f48ff968c3bf0bd1775e2afb8ad3eebb837e6e2519d6c", + build_file = "@SwiftLint//bazel:SwiftSyntax.BUILD", + strip_prefix = "swift-syntax-093e5ee151d206454e2c1950d81333c4d4a4472e", + url = "https://github.com/apple/swift-syntax/archive/093e5ee151d206454e2c1950d81333c4d4a4472e.tar.gz", ) http_archive(