From 4e0e1371f9dab7e4307f947289a8e89d39ca1382 Mon Sep 17 00:00:00 2001 From: oxyu8 Date: Sat, 4 Nov 2023 00:07:52 +0900 Subject: [PATCH 01/28] wip --- .../Models/BuiltInRules.swift | 1 + .../Lint/FunctionArgumentsSpacingRule.swift | 36 +++++++++++++++++++ .../CyclomaticComplexityRuleTests.swift | 1 - .../FunctionArgumentsSpacingRuleTests.swift | 18 ++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift create mode 100644 Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index 59b7908a1a..4b9ce7db26 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -78,6 +78,7 @@ public let builtInRules: [any Rule.Type] = [ ForceCastRule.self, ForceTryRule.self, ForceUnwrappingRule.self, + FunctionArgumentsSpacingRule.self, FunctionBodyLengthRule.self, FunctionDefaultParameterAtEndRule.self, FunctionParameterCountRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift new file mode 100644 index 0000000000..f726e48725 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -0,0 +1,36 @@ +import SwiftSyntax + + +@SwiftSyntaxRule +struct FunctionArgumentsSpacingRule: Rule { + var configuration = SeverityConfiguration(.warning) + + static let description = RuleDescription( + identifier: "functions_arguments_spacing", + name: "Function Arguments Spacing", + description: "Remove spaces before the function argument and after the function argument", + kind: .lint + ) +} + +private extension FunctionArgumentsSpacingRule { + final class Visitor: ViolationsSyntaxVisitor { + override func visitPost(_ node: FunctionCallExprSyntax) { + let argsCount = node.arguments.count + guard argsCount != 0 else { + return + } + // before + print("=============================================") + print(node.arguments.first?.expression.description) + print(node.arguments.first?.expression.leadingTrivia.isEmpty) + print("aaaaaaaaaaaaaaaaaaaaaa") + print(node.arguments.first!.expression.positionAfterSkippingLeadingTrivia) + if (!node.arguments.first!.expression.leadingTrivia.isEmpty) { + print("----------------------------") + violations.append(node.arguments.first!.expression.positionAfterSkippingLeadingTrivia) + } + + } + } +} diff --git a/Tests/SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift b/Tests/SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift index be4233ccab..53d07a126a 100644 --- a/Tests/SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift @@ -63,7 +63,6 @@ class CyclomaticComplexityRuleTests: SwiftLintTestCase { let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples) .with(triggeringExamples: triggeringExamples) - verifyRule(description, ruleConfiguration: ["ignores_case_statements": false], commentDoesntViolate: true, stringDoesntViolate: true) } diff --git a/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift b/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift new file mode 100644 index 0000000000..983326cc0e --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift @@ -0,0 +1,18 @@ +@testable import SwiftLintBuiltInRules + +class FunctionArgumentsSpacingRuleTests: SwiftLintTestCase { + func test() { + + let nonTriggeringExamples = [ + Example("makeGenerator(style)") + ] + let triggeringExamples = [ + Example("makeGenerator( ↓style)") + ] + let description = FunctionArgumentsSpacingRule.description.with(nonTriggeringExamples: nonTriggeringExamples) + .with(triggeringExamples: triggeringExamples) + + verifyRule(description) + + } +} From 9cb3de34df0bff1de4ba0bb884c5d109c64db064 Mon Sep 17 00:00:00 2001 From: uabyss Date: Wed, 8 Nov 2023 12:36:53 +0900 Subject: [PATCH 02/28] implement rule --- .../Lint/FunctionArgumentsSpacingRule.swift | 20 +++++++++---------- .../FunctionArgumentsSpacingRuleTests.swift | 13 ++++++++---- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index f726e48725..484a13f311 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -8,7 +8,7 @@ struct FunctionArgumentsSpacingRule: Rule { static let description = RuleDescription( identifier: "functions_arguments_spacing", name: "Function Arguments Spacing", - description: "Remove spaces before the function argument and after the function argument", + description: "", kind: .lint ) } @@ -20,17 +20,17 @@ private extension FunctionArgumentsSpacingRule { guard argsCount != 0 else { return } - // before - print("=============================================") - print(node.arguments.first?.expression.description) - print(node.arguments.first?.expression.leadingTrivia.isEmpty) - print("aaaaaaaaaaaaaaaaaaaaaa") - print(node.arguments.first!.expression.positionAfterSkippingLeadingTrivia) - if (!node.arguments.first!.expression.leadingTrivia.isEmpty) { - print("----------------------------") - violations.append(node.arguments.first!.expression.positionAfterSkippingLeadingTrivia) + let left = node.leftParen?.trailingTrivia + + let arg = node.arguments.last + if left == Trivia.space { + violations.append(node.leftParen!.endPositionBeforeTrailingTrivia) } + if arg?.trailingTrivia == Trivia.space { + violations.append(node.rightParen!.positionAfterSkippingLeadingTrivia) + } + return } } } diff --git a/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift b/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift index 983326cc0e..8a5b847404 100644 --- a/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift @@ -2,17 +2,22 @@ class FunctionArgumentsSpacingRuleTests: SwiftLintTestCase { func test() { - let nonTriggeringExamples = [ - Example("makeGenerator(style)") + Example("makeGenerator()"), + Example("makeGenerator(style)"), + Example("makeGenerator(true, false)"), ] let triggeringExamples = [ - Example("makeGenerator( ↓style)") + Example("makeGenerator(↓ style)"), + Example("makeGenerator(style ↓)"), + Example("makeGenerator(↓ style ↓)"), + Example("makeGenerator(↓ offset: 0, limit: 0)"), + Example("makeGenerator(offset: 0, limit: 0 ↓)"), + Example("makeGenerator(↓ 1, 2, 3 ↓)") ] let description = FunctionArgumentsSpacingRule.description.with(nonTriggeringExamples: nonTriggeringExamples) .with(triggeringExamples: triggeringExamples) verifyRule(description) - } } From a4f2e8148575679f2eff3773a11e65c1c60ced86 Mon Sep 17 00:00:00 2001 From: uabyss Date: Wed, 8 Nov 2023 13:13:09 +0900 Subject: [PATCH 03/28] add: description and lil refactoring --- .../Lint/FunctionArgumentsSpacingRule.swift | 22 ++++++++++--------- .../OperatorUsageWhitespaceRuleExamples.swift | 2 +- .../FunctionArgumentsSpacingRuleTests.swift | 5 ++--- Tests/SwiftLintTestHelpers/TestHelpers.swift | 2 +- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 484a13f311..11fd127927 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -1,14 +1,13 @@ import SwiftSyntax - @SwiftSyntaxRule -struct FunctionArgumentsSpacingRule: Rule { +struct FunctionArgumentsSpacingRule: OptInRule { var configuration = SeverityConfiguration(.warning) - + static let description = RuleDescription( identifier: "functions_arguments_spacing", name: "Function Arguments Spacing", - description: "", + description: "Remove the space before the first function argument and after the last argument", kind: .lint ) } @@ -20,14 +19,17 @@ private extension FunctionArgumentsSpacingRule { guard argsCount != 0 else { return } - let left = node.leftParen?.trailingTrivia - - let arg = node.arguments.last - if left == Trivia.space { + + let leftParanTrailingTrivia = node.leftParen?.trailingTrivia + if leftParanTrailingTrivia == Trivia.space { violations.append(node.leftParen!.endPositionBeforeTrailingTrivia) } - - if arg?.trailingTrivia == Trivia.space { + + let lastArgument = node.arguments.last + guard lastArgument != nil else { + return + } + if lastArgument!.trailingTrivia == Trivia.space { violations.append(node.rightParen!.positionAfterSkippingLeadingTrivia) } return diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRuleExamples.swift index 432748d683..48cca20459 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRuleExamples.swift @@ -29,7 +29,7 @@ internal enum OperatorUsageWhitespaceRuleExamples { Example(""" let something = Something() - """ ), + """), Example(""" return path.flatMap { path in return compileCommands[path] ?? diff --git a/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift b/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift index 8a5b847404..098b1e28c0 100644 --- a/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift @@ -1,11 +1,11 @@ @testable import SwiftLintBuiltInRules class FunctionArgumentsSpacingRuleTests: SwiftLintTestCase { - func test() { + func testFunctionArgumentsSpacingRule() { let nonTriggeringExamples = [ Example("makeGenerator()"), Example("makeGenerator(style)"), - Example("makeGenerator(true, false)"), + Example("makeGenerator(true, false)") ] let triggeringExamples = [ Example("makeGenerator(↓ style)"), @@ -17,7 +17,6 @@ class FunctionArgumentsSpacingRuleTests: SwiftLintTestCase { ] let description = FunctionArgumentsSpacingRule.description.with(nonTriggeringExamples: nonTriggeringExamples) .with(triggeringExamples: triggeringExamples) - verifyRule(description) } } diff --git a/Tests/SwiftLintTestHelpers/TestHelpers.swift b/Tests/SwiftLintTestHelpers/TestHelpers.swift index df18ff6fed..dc896157e8 100644 --- a/Tests/SwiftLintTestHelpers/TestHelpers.swift +++ b/Tests/SwiftLintTestHelpers/TestHelpers.swift @@ -191,7 +191,7 @@ private func render(violations: [StyleViolation], in contents: String) -> String private func render(locations: [Location], in contents: String) -> String { var contents = StringView(contents).lines.map { $0.content } - for location in locations.sorted(by: > ) { + for location in locations.sorted(by: >) { guard let line = location.line, let character = location.character else { continue } let content = NSMutableString(string: contents[line - 1]) content.insert("↓", at: character - 1) From c39187cba2e8cce8ba789b59b458e2c6dc5574a5 Mon Sep 17 00:00:00 2001 From: uabyss Date: Wed, 8 Nov 2023 13:28:42 +0900 Subject: [PATCH 04/28] change: confirm Rule --- .../Rules/Lint/FunctionArgumentsSpacingRule.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 11fd127927..c7dcc893d3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -1,7 +1,7 @@ import SwiftSyntax @SwiftSyntaxRule -struct FunctionArgumentsSpacingRule: OptInRule { +struct FunctionArgumentsSpacingRule: Rule { var configuration = SeverityConfiguration(.warning) static let description = RuleDescription( From 98ae8b7b389928c4c2ab6b4fc50e7d66d28ab3c0 Mon Sep 17 00:00:00 2001 From: uabyss Date: Wed, 8 Nov 2023 20:08:21 +0900 Subject: [PATCH 05/28] add: FunctionArgumentsSpacingRuleGeneratedTests --- Tests/GeneratedTests/GeneratedTests.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index 5d9f5acaa3..a183d813e9 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -458,6 +458,12 @@ class ForceUnwrappingRuleGeneratedTests: SwiftLintTestCase { } } +class FunctionArgumentsSpacingRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(FunctionArgumentsSpacingRule.description) + } +} + class FunctionBodyLengthRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FunctionBodyLengthRule.description) From 281e73de9e5d6fd8c5d4215dfdd066f99f68e0e3 Mon Sep 17 00:00:00 2001 From: uabyss Date: Mon, 27 Nov 2023 22:00:09 +0900 Subject: [PATCH 06/28] change: move test examples into rule description --- .../Lint/FunctionArgumentsSpacingRule.swift | 15 ++++++++++++++- .../FunctionArgumentsSpacingRuleTests.swift | 16 +--------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index c7dcc893d3..40edd6a488 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -8,7 +8,20 @@ struct FunctionArgumentsSpacingRule: Rule { identifier: "functions_arguments_spacing", name: "Function Arguments Spacing", description: "Remove the space before the first function argument and after the last argument", - kind: .lint + kind: .lint, + nonTriggeringExamples: [ + Example("makeGenerator()"), + Example("makeGenerator(style)"), + Example("makeGenerator(true, false)") + ], + triggeringExamples: [ + Example("makeGenerator(↓ style)"), + Example("makeGenerator(style ↓)"), + Example("makeGenerator(↓ style ↓)"), + Example("makeGenerator(↓ offset: 0, limit: 0)"), + Example("makeGenerator(offset: 0, limit: 0 ↓)"), + Example("makeGenerator(↓ 1, 2, 3 ↓)") + ] ) } diff --git a/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift b/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift index 098b1e28c0..45fb57e6a0 100644 --- a/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift @@ -2,21 +2,7 @@ class FunctionArgumentsSpacingRuleTests: SwiftLintTestCase { func testFunctionArgumentsSpacingRule() { - let nonTriggeringExamples = [ - Example("makeGenerator()"), - Example("makeGenerator(style)"), - Example("makeGenerator(true, false)") - ] - let triggeringExamples = [ - Example("makeGenerator(↓ style)"), - Example("makeGenerator(style ↓)"), - Example("makeGenerator(↓ style ↓)"), - Example("makeGenerator(↓ offset: 0, limit: 0)"), - Example("makeGenerator(offset: 0, limit: 0 ↓)"), - Example("makeGenerator(↓ 1, 2, 3 ↓)") - ] - let description = FunctionArgumentsSpacingRule.description.with(nonTriggeringExamples: nonTriggeringExamples) - .with(triggeringExamples: triggeringExamples) + let description = FunctionArgumentsSpacingRule.description verifyRule(description) } } From f1e35a713d3eb6d5f3a15ee72d32164e45baeaeb Mon Sep 17 00:00:00 2001 From: uabyss Date: Mon, 27 Nov 2023 22:04:23 +0900 Subject: [PATCH 07/28] change: consider for function with no parameters --- .../Rules/Lint/FunctionArgumentsSpacingRule.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 40edd6a488..f7d6161112 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -15,6 +15,7 @@ struct FunctionArgumentsSpacingRule: Rule { Example("makeGenerator(true, false)") ], triggeringExamples: [ + Example("makeGenerator(↓ )"), Example("makeGenerator(↓ style)"), Example("makeGenerator(style ↓)"), Example("makeGenerator(↓ style ↓)"), @@ -28,11 +29,6 @@ struct FunctionArgumentsSpacingRule: Rule { private extension FunctionArgumentsSpacingRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: FunctionCallExprSyntax) { - let argsCount = node.arguments.count - guard argsCount != 0 else { - return - } - let leftParanTrailingTrivia = node.leftParen?.trailingTrivia if leftParanTrailingTrivia == Trivia.space { violations.append(node.leftParen!.endPositionBeforeTrailingTrivia) From 485c60646c444984ba757204cfc57993f5b1e127 Mon Sep 17 00:00:00 2001 From: uabyss Date: Mon, 27 Nov 2023 22:07:42 +0900 Subject: [PATCH 08/28] restore the newline --- .../SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift b/Tests/SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift index 53d07a126a..be4233ccab 100644 --- a/Tests/SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift @@ -63,6 +63,7 @@ class CyclomaticComplexityRuleTests: SwiftLintTestCase { let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples) .with(triggeringExamples: triggeringExamples) + verifyRule(description, ruleConfiguration: ["ignores_case_statements": false], commentDoesntViolate: true, stringDoesntViolate: true) } From c744b9d34ca5acfb29f9b6088c3b234e92e54fcc Mon Sep 17 00:00:00 2001 From: uabyss Date: Mon, 27 Nov 2023 22:27:07 +0900 Subject: [PATCH 09/28] add: triggering the rule with multiple spaces --- .../Lint/FunctionArgumentsSpacingRule.swift | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index f7d6161112..dd4bb5cf65 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -17,29 +17,48 @@ struct FunctionArgumentsSpacingRule: Rule { triggeringExamples: [ Example("makeGenerator(↓ )"), Example("makeGenerator(↓ style)"), + Example("makeGenerator(↓ style)"), + Example("makeGenerator(style ↓)"), + Example("makeGenerator(↓ style ↓)"), Example("makeGenerator(style ↓)"), Example("makeGenerator(↓ style ↓)"), Example("makeGenerator(↓ offset: 0, limit: 0)"), Example("makeGenerator(offset: 0, limit: 0 ↓)"), - Example("makeGenerator(↓ 1, 2, 3 ↓)") + Example("makeGenerator(↓ 1, 2, 3 ↓)"), +// Example("makeGenerator(↓ /* comment */ a /* other comment */)"), +// Example("makeGenerator(/* comment */ a /* other comment */ ↓)"), +// Example("makeGenerator(↓ /* comment */ a /* other comment */ ↓)") ] ) } +private extension TriviaPiece { + var isSpaces: Bool { + if case .spaces = self { + return true + } else { + return false + } + } +} + + private extension FunctionArgumentsSpacingRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: FunctionCallExprSyntax) { let leftParanTrailingTrivia = node.leftParen?.trailingTrivia - if leftParanTrailingTrivia == Trivia.space { - violations.append(node.leftParen!.endPositionBeforeTrailingTrivia) + let hasLeftSpaces = leftParanTrailingTrivia?.filter({$0.isSpaces}).count ?? 0 > 0 + if hasLeftSpaces, let leftParen = node.leftParen { + violations.append(leftParen.endPositionBeforeTrailingTrivia) } let lastArgument = node.arguments.last guard lastArgument != nil else { return } - if lastArgument!.trailingTrivia == Trivia.space { - violations.append(node.rightParen!.positionAfterSkippingLeadingTrivia) + let hasRightSpaces = lastArgument?.trailingTrivia.filter({$0.isSpaces}).count ?? 0 > 0 + if hasRightSpaces, let rightParen = node.rightParen { + violations.append(rightParen.positionAfterSkippingLeadingTrivia) } return } From 8c9e54b172c57c2e8e6564a73703546ee8034e00 Mon Sep 17 00:00:00 2001 From: uabyss Date: Sun, 3 Dec 2023 11:50:03 +0900 Subject: [PATCH 10/28] fix: linter is triggered when a comment is included --- .../Lint/FunctionArgumentsSpacingRule.swift | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index dd4bb5cf65..937d3db9d1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -25,9 +25,12 @@ struct FunctionArgumentsSpacingRule: Rule { Example("makeGenerator(↓ offset: 0, limit: 0)"), Example("makeGenerator(offset: 0, limit: 0 ↓)"), Example("makeGenerator(↓ 1, 2, 3 ↓)"), -// Example("makeGenerator(↓ /* comment */ a /* other comment */)"), -// Example("makeGenerator(/* comment */ a /* other comment */ ↓)"), -// Example("makeGenerator(↓ /* comment */ a /* other comment */ ↓)") + Example("makeGenerator(↓ /* comment */ a)"), + Example("makeGenerator(a /* other comment */ ↓)"), + Example("makeGenerator(↓ /* comment */ a /* other comment */)"), + Example("makeGenerator(/* comment */ a /* other comment */ ↓)"), + Example("makeGenerator(↓ /* comment */ a /* other comment */ ↓)"), + Example("makeGenerator(↓ /* comment */ a /* other comment */ ↓)") ] ) } @@ -42,23 +45,25 @@ private extension TriviaPiece { } } - private extension FunctionArgumentsSpacingRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: FunctionCallExprSyntax) { - let leftParanTrailingTrivia = node.leftParen?.trailingTrivia - let hasLeftSpaces = leftParanTrailingTrivia?.filter({$0.isSpaces}).count ?? 0 > 0 - if hasLeftSpaces, let leftParen = node.leftParen { - violations.append(leftParen.endPositionBeforeTrailingTrivia) + if let leftParan = node.leftParen { + if let firstArgument = leftParan.trailingTrivia.first { + if firstArgument.isSpaces, let leftParen = node.leftParen { + violations.append(leftParen.endPositionBeforeTrailingTrivia) + } + } } - let lastArgument = node.arguments.last - guard lastArgument != nil else { + guard lastArgument != nil || node.rightParen != nil else { return } - let hasRightSpaces = lastArgument?.trailingTrivia.filter({$0.isSpaces}).count ?? 0 > 0 - if hasRightSpaces, let rightParen = node.rightParen { - violations.append(rightParen.positionAfterSkippingLeadingTrivia) + let _lastArgument = lastArgument?.trailingTrivia.reversed().first + if let lastArg = _lastArgument { + if lastArg.isSpaces { + violations.append(node.rightParen!.positionAfterSkippingLeadingTrivia) + } } return } From 57154902887563890ee4f9ce00a12c3066bb05ba Mon Sep 17 00:00:00 2001 From: uabyss Date: Sun, 3 Dec 2023 12:30:11 +0900 Subject: [PATCH 11/28] update: checks the trivia at each of the variables and at the paren and add comment --- .../Lint/FunctionArgumentsSpacingRule.swift | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 937d3db9d1..484a153eda 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -47,22 +47,43 @@ private extension TriviaPiece { private extension FunctionArgumentsSpacingRule { final class Visitor: ViolationsSyntaxVisitor { + /* + Because it is not sure at which node SwiftSyntax will put a space, + it checks the trivia at each of the variables and at the paren. + */ override func visitPost(_ node: FunctionCallExprSyntax) { - if let leftParan = node.leftParen { - if let firstArgument = leftParan.trailingTrivia.first { - if firstArgument.isSpaces, let leftParen = node.leftParen { + if let leftParen = node.leftParen { + let firstArgument = node.arguments.first + // Check that the trivia immediately following the leftParen is spaces(_:), + // as it may contain trivia that is not space like blockComment(_:) + if let firstArgumentLeadingTrivia = firstArgument?.leadingTrivia { + if let firstElementTrivia = firstArgumentLeadingTrivia.reversed().first { + if firstElementTrivia.isSpaces { + violations.append(leftParen.positionAfterSkippingLeadingTrivia) + } + } + } + + if let trailingTrivia = leftParen.trailingTrivia.first { + if trailingTrivia.isSpaces { violations.append(leftParen.endPositionBeforeTrailingTrivia) } } } - let lastArgument = node.arguments.last - guard lastArgument != nil || node.rightParen != nil else { - return - } - let _lastArgument = lastArgument?.trailingTrivia.reversed().first - if let lastArg = _lastArgument { - if lastArg.isSpaces { - violations.append(node.rightParen!.positionAfterSkippingLeadingTrivia) + + if let rightParen = node.rightParen { + let lastArgument = node.arguments.last + // Check that the trivia immediately preceding the rightParen is spaces(_:), + // as it may contain trivia that is not space like blockComment(_:) + if let lastElementTrivia = lastArgument?.trailingTrivia.reversed().first { + if lastElementTrivia.isSpaces { + violations.append(rightParen.positionAfterSkippingLeadingTrivia) + } + } + if let firstArgument = rightParen.trailingTrivia.first { + if firstArgument.isSpaces, let rightParan = node.rightParen { + violations.append(rightParan.endPositionBeforeTrailingTrivia) + } } } return From f88686db22d091c61773a625db0e954344a39ba3 Mon Sep 17 00:00:00 2001 From: uabyss Date: Sun, 3 Dec 2023 12:42:29 +0900 Subject: [PATCH 12/28] add: CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07e746454f..7fd6e5c7f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,6 +121,10 @@ * Make `empty_count` auto-correctable. [KS1019](https://github.com/KS1019/) +* Add new `functions_arguments_spacing` rule to remove the space before the first function argument + and after the last argument. + [u-abyss](https://github.com/u-abyss) + [#5259](https://github.com/realm/SwiftLint/issues/5224) #### Bug Fixes From ff605ad819e40101a60edfe0c6f4577398d369a3 Mon Sep 17 00:00:00 2001 From: uabyss Date: Sun, 3 Dec 2023 13:11:15 +0900 Subject: [PATCH 13/28] fix: change trailingTrivia to leadingTrivia --- .../Rules/Lint/FunctionArgumentsSpacingRule.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 484a153eda..68892da558 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -80,7 +80,7 @@ private extension FunctionArgumentsSpacingRule { violations.append(rightParen.positionAfterSkippingLeadingTrivia) } } - if let firstArgument = rightParen.trailingTrivia.first { + if let firstArgument = rightParen.leadingTrivia.first { if firstArgument.isSpaces, let rightParan = node.rightParen { violations.append(rightParan.endPositionBeforeTrailingTrivia) } From 5d5c868630a65b8adfd9ec97fe96cfe01c87895f Mon Sep 17 00:00:00 2001 From: uabyss Date: Wed, 13 Dec 2023 23:51:06 +0900 Subject: [PATCH 14/28] handle newline --- .../Lint/FunctionArgumentsSpacingRule.swift | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 68892da558..1f0e288e80 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -12,7 +12,13 @@ struct FunctionArgumentsSpacingRule: Rule { nonTriggeringExamples: [ Example("makeGenerator()"), Example("makeGenerator(style)"), - Example("makeGenerator(true, false)") + Example("makeGenerator(true, false)"), + Example(""" + makeGenerator( + a: true, + b: false + ) + """), ], triggeringExamples: [ Example("makeGenerator(↓ )"), @@ -57,9 +63,11 @@ private extension FunctionArgumentsSpacingRule { // Check that the trivia immediately following the leftParen is spaces(_:), // as it may contain trivia that is not space like blockComment(_:) if let firstArgumentLeadingTrivia = firstArgument?.leadingTrivia { - if let firstElementTrivia = firstArgumentLeadingTrivia.reversed().first { - if firstElementTrivia.isSpaces { - violations.append(leftParen.positionAfterSkippingLeadingTrivia) + if !firstArgumentLeadingTrivia.containsNewlines() { + if let firstElementTrivia = firstArgumentLeadingTrivia.reversed().first { + if firstElementTrivia.isSpaces { + violations.append(leftParen.positionAfterSkippingLeadingTrivia) + } } } } From 64938509d05c211e7ae84697581fc69a00e6e789 Mon Sep 17 00:00:00 2001 From: uabyss Date: Thu, 14 Dec 2023 00:59:46 +0900 Subject: [PATCH 15/28] fix: pass all tests --- .../Lint/FunctionArgumentsSpacingRule.swift | 55 ++++++++----------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 1f0e288e80..1ee6214e8b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -18,7 +18,7 @@ struct FunctionArgumentsSpacingRule: Rule { a: true, b: false ) - """), + """) ], triggeringExamples: [ Example("makeGenerator(↓ )"), @@ -58,43 +58,36 @@ private extension FunctionArgumentsSpacingRule { it checks the trivia at each of the variables and at the paren. */ override func visitPost(_ node: FunctionCallExprSyntax) { - if let leftParen = node.leftParen { - let firstArgument = node.arguments.first - // Check that the trivia immediately following the leftParen is spaces(_:), - // as it may contain trivia that is not space like blockComment(_:) - if let firstArgumentLeadingTrivia = firstArgument?.leadingTrivia { - if !firstArgumentLeadingTrivia.containsNewlines() { - if let firstElementTrivia = firstArgumentLeadingTrivia.reversed().first { - if firstElementTrivia.isSpaces { - violations.append(leftParen.positionAfterSkippingLeadingTrivia) - } + guard let leftParen = node.leftParen, let rightParen = node.rightParen else { return } + let firstArgument = node.arguments.first + // Check that the trivia immediately following the leftParen is spaces(_:), + // as it may contain trivia that is not space like blockComment(_:) + if let firstArgumentLeadingTrivia = firstArgument?.leadingTrivia, + !firstArgumentLeadingTrivia.containsNewlines() { + if let firstElementTrivia = firstArgumentLeadingTrivia.reversed().first { + if firstElementTrivia.isSpaces { + violations.append(leftParen.positionAfterSkippingLeadingTrivia) } } - } - - if let trailingTrivia = leftParen.trailingTrivia.first { - if trailingTrivia.isSpaces { - violations.append(leftParen.endPositionBeforeTrailingTrivia) - } + } + if let trailingTrivia = leftParen.trailingTrivia.first { + if trailingTrivia.isSpaces { + violations.append(leftParen.endPositionBeforeTrailingTrivia) } } - - if let rightParen = node.rightParen { - let lastArgument = node.arguments.last - // Check that the trivia immediately preceding the rightParen is spaces(_:), - // as it may contain trivia that is not space like blockComment(_:) - if let lastElementTrivia = lastArgument?.trailingTrivia.reversed().first { - if lastElementTrivia.isSpaces { - violations.append(rightParen.positionAfterSkippingLeadingTrivia) - } + let lastArgument = node.arguments.last + // Check that the trivia immediately preceding the rightParen is spaces(_:), + // as it may contain trivia that is not space like blockComment(_:) + if let lastElementTrivia = lastArgument?.trailingTrivia.reversed().first { + if lastElementTrivia.isSpaces { + violations.append(rightParen.positionAfterSkippingLeadingTrivia) } - if let firstArgument = rightParen.leadingTrivia.first { - if firstArgument.isSpaces, let rightParan = node.rightParen { - violations.append(rightParan.endPositionBeforeTrailingTrivia) - } + } + if let firstArgument = rightParen.leadingTrivia.first { + if firstArgument.isSpaces, let rightParan = node.rightParen { + violations.append(rightParan.endPositionBeforeTrailingTrivia) } } - return } } } From c2e50d18cc0d040d06d3579a18c232a12742516d Mon Sep 17 00:00:00 2001 From: uabyss Date: Thu, 14 Dec 2023 01:51:43 +0900 Subject: [PATCH 16/28] rerun From c319bd21c87f66a5359c06931bb03248eb28f16d Mon Sep 17 00:00:00 2001 From: uabyss <47887646+u-abyss@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:23:55 +0900 Subject: [PATCH 17/28] Update Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danny Mösch --- .../Rules/Lint/FunctionArgumentsSpacingRule.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 1ee6214e8b..b344c573e5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -64,7 +64,7 @@ private extension FunctionArgumentsSpacingRule { // as it may contain trivia that is not space like blockComment(_:) if let firstArgumentLeadingTrivia = firstArgument?.leadingTrivia, !firstArgumentLeadingTrivia.containsNewlines() { - if let firstElementTrivia = firstArgumentLeadingTrivia.reversed().first { + if let firstElementTrivia = firstArgumentLeadingTrivia.pieces.last { if firstElementTrivia.isSpaces { violations.append(leftParen.positionAfterSkippingLeadingTrivia) } From 32bbf0d3c061851aa0a574469e1282f1ae399aea Mon Sep 17 00:00:00 2001 From: uabyss Date: Tue, 16 Jan 2024 20:25:39 +0900 Subject: [PATCH 18/28] change: function name --- .../Lint/FunctionArgumentsSpacingRule.swift | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index b344c573e5..3f850c5fb4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -10,9 +10,9 @@ struct FunctionArgumentsSpacingRule: Rule { description: "Remove the space before the first function argument and after the last argument", kind: .lint, nonTriggeringExamples: [ - Example("makeGenerator()"), - Example("makeGenerator(style)"), - Example("makeGenerator(true, false)"), + Example("testFunc()"), + Example("testFunc(style)"), + Example("testFunc(true, false)"), Example(""" makeGenerator( a: true, @@ -21,22 +21,22 @@ struct FunctionArgumentsSpacingRule: Rule { """) ], triggeringExamples: [ - Example("makeGenerator(↓ )"), - Example("makeGenerator(↓ style)"), - Example("makeGenerator(↓ style)"), - Example("makeGenerator(style ↓)"), - Example("makeGenerator(↓ style ↓)"), - Example("makeGenerator(style ↓)"), - Example("makeGenerator(↓ style ↓)"), - Example("makeGenerator(↓ offset: 0, limit: 0)"), - Example("makeGenerator(offset: 0, limit: 0 ↓)"), - Example("makeGenerator(↓ 1, 2, 3 ↓)"), - Example("makeGenerator(↓ /* comment */ a)"), - Example("makeGenerator(a /* other comment */ ↓)"), - Example("makeGenerator(↓ /* comment */ a /* other comment */)"), - Example("makeGenerator(/* comment */ a /* other comment */ ↓)"), - Example("makeGenerator(↓ /* comment */ a /* other comment */ ↓)"), - Example("makeGenerator(↓ /* comment */ a /* other comment */ ↓)") + Example("testFunc(↓ )"), + Example("testFunc(↓ style)"), + Example("testFunc(↓ style)"), + Example("testFunc(style ↓)"), + Example("testFunc(↓ style ↓)"), + Example("testFunc(style ↓)"), + Example("testFunc(↓ style ↓)"), + Example("testFunc(↓ offset: 0, limit: 0)"), + Example("testFunc(offset: 0, limit: 0 ↓)"), + Example("testFunc(↓ 1, 2, 3 ↓)"), + Example("testFunc(↓ /* comment */ a)"), + Example("testFunc(a /* other comment */ ↓)"), + Example("testFunc(↓ /* comment */ a /* other comment */)"), + Example("testFunc(/* comment */ a /* other comment */ ↓)"), + Example("testFunc(↓ /* comment */ a /* other comment */ ↓)"), + Example("testFunc(↓ /* comment */ a /* other comment */ ↓)") ] ) } From 99c421b01fc9731afbdc09dedc34a4e6683bf8bc Mon Sep 17 00:00:00 2001 From: uabyss Date: Sat, 3 Feb 2024 20:01:07 +0900 Subject: [PATCH 19/28] update: passed all current tests --- .../Lint/FunctionArgumentsSpacingRule.swift | 123 +++++++++++++----- 1 file changed, 88 insertions(+), 35 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 3f850c5fb4..3e97dd05df 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -14,7 +14,7 @@ struct FunctionArgumentsSpacingRule: Rule { Example("testFunc(style)"), Example("testFunc(true, false)"), Example(""" - makeGenerator( + testFunc( a: true, b: false ) @@ -22,26 +22,35 @@ struct FunctionArgumentsSpacingRule: Rule { ], triggeringExamples: [ Example("testFunc(↓ )"), + Example("testFunc(↓ )"), Example("testFunc(↓ style)"), Example("testFunc(↓ style)"), - Example("testFunc(style ↓)"), - Example("testFunc(↓ style ↓)"), Example("testFunc(style ↓)"), + Example("testFunc(↓ style ↓)"), Example("testFunc(↓ style ↓)"), Example("testFunc(↓ offset: 0, limit: 0)"), Example("testFunc(offset: 0, limit: 0 ↓)"), Example("testFunc(↓ 1, 2, 3 ↓)"), + Example("testFunc(↓ 1, ↓2, 3 ↓)"), + Example("testFunc(↓ 1, ↓2, ↓3 ↓)"), Example("testFunc(↓ /* comment */ a)"), Example("testFunc(a /* other comment */ ↓)"), Example("testFunc(↓ /* comment */ a /* other comment */)"), Example("testFunc(/* comment */ a /* other comment */ ↓)"), Example("testFunc(↓ /* comment */ a /* other comment */ ↓)"), - Example("testFunc(↓ /* comment */ a /* other comment */ ↓)") + Example("testFunc(↓ /* comment */ a /* other comment */ ↓)"), ] ) } private extension TriviaPiece { + var isSingleSpace: Bool { + if case .spaces(1) = self { + return true + } else { + return false + } + } var isSpaces: Bool { if case .spaces = self { return true @@ -49,45 +58,89 @@ private extension TriviaPiece { return false } } + var isTabs: Bool { + if case .tabs = self { + return true + } else { + return false + } + } + var isBlockComment: Bool { + if case .blockComment = self { + return true + } else { + return false + } + } } private extension FunctionArgumentsSpacingRule { - final class Visitor: ViolationsSyntaxVisitor { - /* - Because it is not sure at which node SwiftSyntax will put a space, - it checks the trivia at each of the variables and at the paren. - */ - override func visitPost(_ node: FunctionCallExprSyntax) { - guard let leftParen = node.leftParen, let rightParen = node.rightParen else { return } - let firstArgument = node.arguments.first - // Check that the trivia immediately following the leftParen is spaces(_:), - // as it may contain trivia that is not space like blockComment(_:) - if let firstArgumentLeadingTrivia = firstArgument?.leadingTrivia, - !firstArgumentLeadingTrivia.containsNewlines() { - if let firstElementTrivia = firstArgumentLeadingTrivia.pieces.last { - if firstElementTrivia.isSpaces { - violations.append(leftParen.positionAfterSkippingLeadingTrivia) - } - } + final class Visitor: ViolationsSyntaxVisitor { + override func visitPost(_ node: FunctionCallExprSyntax) { + guard let leftParen = node.leftParen, let rightParen = node.rightParen else { return } + let arguments = node.arguments + if arguments.isEmpty { + if let triviaAfterLeftParen = leftParen.trailingTrivia.pieces.first { + if triviaAfterLeftParen.isSpaces { + violations.append(leftParen.endPositionBeforeTrailingTrivia) + } + } + } + if arguments.count == 1 { + if let firstArg = node.arguments.first { + if let triviaAfterLeftParen = leftParen.trailingTrivia.pieces.first { + if triviaAfterLeftParen.isSpaces && !firstArg.leadingTrivia.containsNewlines() { + violations.append(leftParen.endPositionBeforeTrailingTrivia) } - if let trailingTrivia = leftParen.trailingTrivia.first { - if trailingTrivia.isSpaces { - violations.append(leftParen.endPositionBeforeTrailingTrivia) - } + } + if firstArg.trailingTrivia.pieces.isNotEmpty { + if firstArg.trailingTrivia.pieces.count == 1 && firstArg.trailingTrivia.pieces.first!.isSpaces { + violations.append(firstArg.endPosition) } - let lastArgument = node.arguments.last - // Check that the trivia immediately preceding the rightParen is spaces(_:), - // as it may contain trivia that is not space like blockComment(_:) - if let lastElementTrivia = lastArgument?.trailingTrivia.reversed().first { - if lastElementTrivia.isSpaces { - violations.append(rightParen.positionAfterSkippingLeadingTrivia) - } + if firstArg.trailingTrivia.pieces.first!.isSpaces && firstArg.trailingTrivia.pieces.count >= 2 && !firstArg.trailingTrivia.pieces.last!.isBlockComment { + violations.append(firstArg.endPosition) } - if let firstArgument = rightParen.leadingTrivia.first { - if firstArgument.isSpaces, let rightParan = node.rightParen { - violations.append(rightParan.endPositionBeforeTrailingTrivia) + } + } + } + if arguments.count >= 2 { + arguments.enumerated().forEach { index, arg in + if index == 0 { + if let triviaAfterLeftParen = leftParen.trailingTrivia.pieces.first { + if triviaAfterLeftParen.isSpaces && !arg.leadingTrivia.containsNewlines() { + violations.append(leftParen.endPositionBeforeTrailingTrivia) + } + } + let trailingComma = arg.trailingComma + guard let _trailingComma = trailingComma else { return } + guard let trailingTrivia = _trailingComma.trailingTrivia.pieces.first else { return } + if !(trailingTrivia.isSingleSpace) { + violations.append(_trailingComma.endPosition) + } + } else if index == arguments.count - 1 { + if let lastArgument = arguments.last { + if let triviaAfterLastArgument = lastArgument.trailingTrivia.pieces.first { + if triviaAfterLastArgument.isSpaces { + violations.append(lastArgument.endPosition) } + } + } + let trailingComma = arg.trailingComma + guard let _trailingComma = trailingComma else { return } + guard let trailingTrivia = _trailingComma.trailingTrivia.pieces.first else { return } + if !(trailingTrivia.isSingleSpace) { + violations.append(_trailingComma.endPosition) + } + } else { + let trailingComma = arg.trailingComma + guard let _trailingComma = trailingComma else { return } + guard let trailingTrivia = _trailingComma.trailingTrivia.pieces.first else { return } + if !(trailingTrivia.isSingleSpace) { + violations.append(_trailingComma.endPosition) } + } } + } } + } } From bb4267d6a2d32e1725343bf4748e6fca0dac119a Mon Sep 17 00:00:00 2001 From: uabyss Date: Sun, 4 Feb 2024 20:17:34 +0900 Subject: [PATCH 20/28] update: trigger comment and tab --- .../Rules/Lint/FunctionArgumentsSpacingRule.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 3e97dd05df..6c3a018527 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -39,6 +39,7 @@ struct FunctionArgumentsSpacingRule: Rule { Example("testFunc(/* comment */ a /* other comment */ ↓)"), Example("testFunc(↓ /* comment */ a /* other comment */ ↓)"), Example("testFunc(↓ /* comment */ a /* other comment */ ↓)"), + Example("testFunc(↓ /* comment */ ↓a↓ /* other comment */ ↓)"), ] ) } @@ -93,13 +94,23 @@ private extension FunctionArgumentsSpacingRule { violations.append(leftParen.endPositionBeforeTrailingTrivia) } } + if let lastTriviaAfterLeftParan = leftParen.trailingTrivia.pieces.last { + if !lastTriviaAfterLeftParan.isSingleSpace && leftParen.trailingTrivia.pieces.count >= 2 { + violations.append(leftParen.endPosition) + } + } if firstArg.trailingTrivia.pieces.isNotEmpty { if firstArg.trailingTrivia.pieces.count == 1 && firstArg.trailingTrivia.pieces.first!.isSpaces { violations.append(firstArg.endPosition) } + if firstArg.trailingTrivia.pieces.first!.isSpaces && firstArg.trailingTrivia.pieces.count >= 2 && !firstArg.trailingTrivia.pieces.last!.isBlockComment { violations.append(firstArg.endPosition) } + + if firstArg.trailingTrivia.pieces.count >= 2 && !firstArg.trailingTrivia.pieces.first!.isSingleSpace { + violations.append(firstArg.endPositionBeforeTrailingTrivia) + } } } } From df301a7507f165a94e2785804b110cb850c6f512 Mon Sep 17 00:00:00 2001 From: uabyss Date: Tue, 6 Feb 2024 10:23:45 +0900 Subject: [PATCH 21/28] change: logic --- .../Lint/FunctionArgumentsSpacingRule.swift | 155 ++++++++---------- 1 file changed, 66 insertions(+), 89 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 6c3a018527..1a94e3db20 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -10,36 +10,29 @@ struct FunctionArgumentsSpacingRule: Rule { description: "Remove the space before the first function argument and after the last argument", kind: .lint, nonTriggeringExamples: [ - Example("testFunc()"), - Example("testFunc(style)"), - Example("testFunc(true, false)"), + Example("f()"), + Example("f(true)"), + Example("f(true, false)"), + Example("f(true, false, true)"), + Example("f(/* comment */true/* other comment */)"), + Example("f(/* comment */true/* other comment */, false)"), + Example("f(/* comment */true/* other comment */, /* comment */false/* other comment */, false)"), Example(""" - testFunc( + f( a: true, - b: false + b: true, ) """) ], triggeringExamples: [ - Example("testFunc(↓ )"), - Example("testFunc(↓ )"), - Example("testFunc(↓ style)"), - Example("testFunc(↓ style)"), - Example("testFunc(style ↓)"), - Example("testFunc(↓ style ↓)"), - Example("testFunc(↓ style ↓)"), - Example("testFunc(↓ offset: 0, limit: 0)"), - Example("testFunc(offset: 0, limit: 0 ↓)"), - Example("testFunc(↓ 1, 2, 3 ↓)"), - Example("testFunc(↓ 1, ↓2, 3 ↓)"), - Example("testFunc(↓ 1, ↓2, ↓3 ↓)"), - Example("testFunc(↓ /* comment */ a)"), - Example("testFunc(a /* other comment */ ↓)"), - Example("testFunc(↓ /* comment */ a /* other comment */)"), - Example("testFunc(/* comment */ a /* other comment */ ↓)"), - Example("testFunc(↓ /* comment */ a /* other comment */ ↓)"), - Example("testFunc(↓ /* comment */ a /* other comment */ ↓)"), - Example("testFunc(↓ /* comment */ ↓a↓ /* other comment */ ↓)"), + Example("f(↓ )"), + Example("f(↓ )"), + Example("f(↓\t)"), + Example("f(↓ true↓ )"), + Example("f(↓ /* comment */ ↓true↓ /* other comment */ ↓)"), + Example("f(↓ x: 0, y: 0↓ )"), + Example("f(↓ true,↓ false, true↓ )"), + Example("f(↓ true,↓ false,↓ /* other comment */ ↓true↓ )") ] ) } @@ -78,78 +71,62 @@ private extension TriviaPiece { private extension FunctionArgumentsSpacingRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: FunctionCallExprSyntax) { - guard let leftParen = node.leftParen, let rightParen = node.rightParen else { return } + guard let leftParen = node.leftParen else { return } let arguments = node.arguments - if arguments.isEmpty { - if let triviaAfterLeftParen = leftParen.trailingTrivia.pieces.first { - if triviaAfterLeftParen.isSpaces { + let argumentsCounts = arguments.count + switch argumentsCounts { + case 0: + guard let triviaAfterLeftParen = leftParen.trailingTrivia.pieces.first else { return } + if triviaAfterLeftParen.isSpaces || triviaAfterLeftParen.isTabs { violations.append(leftParen.endPositionBeforeTrailingTrivia) } + case 1: + guard let argument = node.arguments.first else { return } + // check whether there are whitespaces before a variable + checkLeftParenTrailingTrivia(leftParen: leftParen) + // check whether there are whitespaces after a variable + checkArgumentTrailingTrivia(argument: argument) + default: + arguments.enumerated().forEach { index, arg in + switch index { + case 0: + checkLeftParenTrailingTrivia(leftParen: leftParen) + guard let trailingComma = arg.trailingComma else {return } + checkTrailingComma(trailingComma: trailingComma) + case arguments.count - 1: + guard let lastArgument = arguments.last else { return} + checkArgumentTrailingTrivia(argument: lastArgument) + default: + guard let trailingComma = arg.trailingComma else {return} + checkTrailingComma(trailingComma: trailingComma) + } } } - if arguments.count == 1 { - if let firstArg = node.arguments.first { - if let triviaAfterLeftParen = leftParen.trailingTrivia.pieces.first { - if triviaAfterLeftParen.isSpaces && !firstArg.leadingTrivia.containsNewlines() { - violations.append(leftParen.endPositionBeforeTrailingTrivia) - } - } - if let lastTriviaAfterLeftParan = leftParen.trailingTrivia.pieces.last { - if !lastTriviaAfterLeftParan.isSingleSpace && leftParen.trailingTrivia.pieces.count >= 2 { - violations.append(leftParen.endPosition) - } - } - if firstArg.trailingTrivia.pieces.isNotEmpty { - if firstArg.trailingTrivia.pieces.count == 1 && firstArg.trailingTrivia.pieces.first!.isSpaces { - violations.append(firstArg.endPosition) - } - - if firstArg.trailingTrivia.pieces.first!.isSpaces && firstArg.trailingTrivia.pieces.count >= 2 && !firstArg.trailingTrivia.pieces.last!.isBlockComment { - violations.append(firstArg.endPosition) - } - - if firstArg.trailingTrivia.pieces.count >= 2 && !firstArg.trailingTrivia.pieces.first!.isSingleSpace { - violations.append(firstArg.endPositionBeforeTrailingTrivia) - } - } + } + private func checkLeftParenTrailingTrivia(leftParen: TokenSyntax) { + leftParen.trailingTrivia.pieces.enumerated().forEach { index, trivia in + if (trivia.isSpaces || trivia.isTabs) && (index == 0 || leftParen.trailingTrivia.count == 1) { + violations.append(leftParen.endPositionBeforeTrailingTrivia) + } else if trivia.isSpaces || trivia.isTabs { + violations.append(leftParen.endPosition) } } - if arguments.count >= 2 { - arguments.enumerated().forEach { index, arg in - if index == 0 { - if let triviaAfterLeftParen = leftParen.trailingTrivia.pieces.first { - if triviaAfterLeftParen.isSpaces && !arg.leadingTrivia.containsNewlines() { - violations.append(leftParen.endPositionBeforeTrailingTrivia) - } - } - let trailingComma = arg.trailingComma - guard let _trailingComma = trailingComma else { return } - guard let trailingTrivia = _trailingComma.trailingTrivia.pieces.first else { return } - if !(trailingTrivia.isSingleSpace) { - violations.append(_trailingComma.endPosition) - } - } else if index == arguments.count - 1 { - if let lastArgument = arguments.last { - if let triviaAfterLastArgument = lastArgument.trailingTrivia.pieces.first { - if triviaAfterLastArgument.isSpaces { - violations.append(lastArgument.endPosition) - } - } - } - let trailingComma = arg.trailingComma - guard let _trailingComma = trailingComma else { return } - guard let trailingTrivia = _trailingComma.trailingTrivia.pieces.first else { return } - if !(trailingTrivia.isSingleSpace) { - violations.append(_trailingComma.endPosition) - } - } else { - let trailingComma = arg.trailingComma - guard let _trailingComma = trailingComma else { return } - guard let trailingTrivia = _trailingComma.trailingTrivia.pieces.first else { return } - if !(trailingTrivia.isSingleSpace) { - violations.append(_trailingComma.endPosition) - } - } + } + private func checkArgumentTrailingTrivia(argument: LabeledExprListSyntax.Element) { + argument.trailingTrivia.pieces.enumerated().forEach { index, trivia in + if (trivia.isSpaces || trivia.isTabs) && (index == 0 || argument.trailingTrivia.count == 1) { + violations.append(argument.endPositionBeforeTrailingTrivia) + } else if trivia.isSpaces || trivia.isTabs { + violations.append(argument.endPosition) + } + } + } + private func checkTrailingComma(trailingComma: TokenSyntax) { + trailingComma.trailingTrivia.pieces.enumerated().forEach { index, trivia in + if !trivia.isSingleSpace && (index == 0 || trailingComma.trailingTrivia.count == 1) { + violations.append(trailingComma.endPositionBeforeTrailingTrivia) + } else if !trivia.isSingleSpace && !trivia.isBlockComment { + violations.append(trailingComma.endPosition) } } } From e355ba6febe0987784da2653deb783f77d3dd973 Mon Sep 17 00:00:00 2001 From: uabyss Date: Thu, 8 Feb 2024 17:58:57 +0900 Subject: [PATCH 22/28] wip --- .../Lint/FunctionArgumentsSpacingRule.swift | 50 ++++++++++++------- .../Rules/Style/VerticalWhitespaceRule.swift | 2 +- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 1a94e3db20..27ca6c2308 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -14,11 +14,13 @@ struct FunctionArgumentsSpacingRule: Rule { Example("f(true)"), Example("f(true, false)"), Example("f(true, false, true)"), + Example("f(a /* comment */)"), Example("f(/* comment */true/* other comment */)"), Example("f(/* comment */true/* other comment */, false)"), Example("f(/* comment */true/* other comment */, /* comment */false/* other comment */, false)"), Example(""" f( + /* comment */ a: true, b: true, ) @@ -29,10 +31,11 @@ struct FunctionArgumentsSpacingRule: Rule { Example("f(↓ )"), Example("f(↓\t)"), Example("f(↓ true↓ )"), - Example("f(↓ /* comment */ ↓true↓ /* other comment */ ↓)"), - Example("f(↓ x: 0, y: 0↓ )"), - Example("f(↓ true,↓ false, true↓ )"), - Example("f(↓ true,↓ false,↓ /* other comment */ ↓true↓ )") +// Example("f(/* comment */ ↓a)"), +// Example("f(↓ /* comment */ ↓true /* other comment */ ↓)"), +// Example("f(↓ x: 0, y: 0↓ )"), +// Example("f(↓ true,↓ false, true↓ )"), +// Example("f(↓ true,↓ false,↓ /* other comment */ ↓true↓ )") ] ) } @@ -87,19 +90,23 @@ private extension FunctionArgumentsSpacingRule { // check whether there are whitespaces after a variable checkArgumentTrailingTrivia(argument: argument) default: - arguments.enumerated().forEach { index, arg in - switch index { - case 0: - checkLeftParenTrailingTrivia(leftParen: leftParen) - guard let trailingComma = arg.trailingComma else {return } - checkTrailingComma(trailingComma: trailingComma) - case arguments.count - 1: - guard let lastArgument = arguments.last else { return} - checkArgumentTrailingTrivia(argument: lastArgument) - default: - guard let trailingComma = arg.trailingComma else {return} - checkTrailingComma(trailingComma: trailingComma) - } + test(arguments: arguments, leftParen: leftParen) + } + } + + func test(arguments: LabeledExprListSyntax, leftParen: TokenSyntax) { + arguments.enumerated().forEach { index, arg in + switch index { + case 0: + checkLeftParenTrailingTrivia(leftParen: leftParen) + guard let trailingComma = arg.trailingComma else { return } + checkTrailingComma(trailingComma: trailingComma) + case arguments.count - 1: + guard let lastArgument = arguments.last else { return } + checkArgumentTrailingTrivia(argument: lastArgument) + default: + guard let trailingComma = arg.trailingComma else { return } + checkTrailingComma(trailingComma: trailingComma) } } } @@ -112,9 +119,14 @@ private extension FunctionArgumentsSpacingRule { } } } + private func checkArgumentTrailingTrivia(argument: LabeledExprListSyntax.Element) { - argument.trailingTrivia.pieces.enumerated().forEach { index, trivia in - if (trivia.isSpaces || trivia.isTabs) && (index == 0 || argument.trailingTrivia.count == 1) { + if argument.trailingTrivia.pieces.count == 0 { return } + for i in 0 ..< argument.trailingTrivia.pieces.count - 1 { + let trivia = argument.trailingTrivia.pieces[i] + let next = argument.trailingTrivia.pieces[i + 1] + if trivia.isSingleSpace && next.isBlockComment { return } + if (trivia.isSpaces || trivia.isTabs) && (i == 0 || argument.trailingTrivia.count == 1) { violations.append(argument.endPositionBeforeTrailingTrivia) } else if trivia.isSpaces || trivia.isTabs { violations.append(argument.endPosition) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift index 70751ab2a9..c7c509d728 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift @@ -26,7 +26,7 @@ struct VerticalWhitespaceRule: CorrectableRule { Example("let b = 0\n\n\nclass AAA {}\n"): Example("let b = 0\n\nclass AAA {}\n"), Example("let c = 0\n\n\nlet num = 1\n"): Example("let c = 0\n\nlet num = 1\n"), Example("// bca \n\n\n"): Example("// bca \n\n") - ] // End of line autocorrections are handled by Trailing Newline Rule. + ]// End of line autocorrections are handled by Trailing Newline Rule. ) private var configuredDescriptionReason: String { From e68a3c638d95b36b34896c85ba02ab15f35f54b2 Mon Sep 17 00:00:00 2001 From: uabyss Date: Sun, 11 Feb 2024 16:32:51 +0900 Subject: [PATCH 23/28] update: not triggering when argument with linecomment --- .../Lint/FunctionArgumentsSpacingRule.swift | 110 +++++++++++------- 1 file changed, 68 insertions(+), 42 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 27ca6c2308..de8c63f5fc 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -15,6 +15,7 @@ struct FunctionArgumentsSpacingRule: Rule { Example("f(true, false)"), Example("f(true, false, true)"), Example("f(a /* comment */)"), + Example("f(true, /* comment */, false)"), Example("f(/* comment */true/* other comment */)"), Example("f(/* comment */true/* other comment */, false)"), Example("f(/* comment */true/* other comment */, /* comment */false/* other comment */, false)"), @@ -24,6 +25,12 @@ struct FunctionArgumentsSpacingRule: Rule { a: true, b: true, ) + """), + Example(""" + f( + a: true, // line comment + b: true, // line comment + ) """) ], triggeringExamples: [ @@ -31,11 +38,11 @@ struct FunctionArgumentsSpacingRule: Rule { Example("f(↓ )"), Example("f(↓\t)"), Example("f(↓ true↓ )"), -// Example("f(/* comment */ ↓a)"), -// Example("f(↓ /* comment */ ↓true /* other comment */ ↓)"), -// Example("f(↓ x: 0, y: 0↓ )"), -// Example("f(↓ true,↓ false, true↓ )"), -// Example("f(↓ true,↓ false,↓ /* other comment */ ↓true↓ )") + Example("f(/* comment */ ↓a)"), + Example("f(↓ /* comment */ ↓true /* other comment */ ↓)"), + Example("f(↓ x: 0, y: 0↓ )"), + Example("f(↓ true,↓ false, true↓ )"), + Example("f(↓ true,↓ false,↓ /* other comment */ ↓true↓ )") ] ) } @@ -48,27 +55,34 @@ private extension TriviaPiece { return false } } - var isSpaces: Bool { - if case .spaces = self { - return true - } else { - return false - } - } - var isTabs: Bool { - if case .tabs = self { - return true - } else { - return false - } - } - var isBlockComment: Bool { - if case .blockComment = self { - return true - } else { - return false - } + var isLineComment: Bool { + if case .lineComment = self { + return true + } else { + return false } + } + var isSpaces: Bool { + if case .spaces = self { + return true + } else { + return false + } + } + var isTabs: Bool { + if case .tabs = self { + return true + } else { + return false + } + } + var isBlockComment: Bool { + if case .blockComment = self { + return true + } else { + return false + } + } } private extension FunctionArgumentsSpacingRule { @@ -119,27 +133,39 @@ private extension FunctionArgumentsSpacingRule { } } } - private func checkArgumentTrailingTrivia(argument: LabeledExprListSyntax.Element) { - if argument.trailingTrivia.pieces.count == 0 { return } - for i in 0 ..< argument.trailingTrivia.pieces.count - 1 { - let trivia = argument.trailingTrivia.pieces[i] - let next = argument.trailingTrivia.pieces[i + 1] - if trivia.isSingleSpace && next.isBlockComment { return } - if (trivia.isSpaces || trivia.isTabs) && (i == 0 || argument.trailingTrivia.count == 1) { - violations.append(argument.endPositionBeforeTrailingTrivia) - } else if trivia.isSpaces || trivia.isTabs { - violations.append(argument.endPosition) + guard !argument.trailingTrivia.pieces.isEmpty else { return } + + for index in 0 ..< argument.trailingTrivia.pieces.count { + let trivia = argument.trailingTrivia.pieces[index] + + if index < argument.trailingTrivia.pieces.count - 1 { + let next = argument.trailingTrivia.pieces[index + 1] + if trivia.isSingleSpace && next.isBlockComment { continue } + } + let isInitialOrSinglePiece = index == 0 || argument.trailingTrivia.pieces.count == 1 + + if (trivia.isSpaces || trivia.isTabs) && isInitialOrSinglePiece { + violations.append(argument.endPositionBeforeTrailingTrivia) + } else if trivia.isSpaces || trivia.isTabs { + violations.append(argument.endPosition) + } } - } } private func checkTrailingComma(trailingComma: TokenSyntax) { - trailingComma.trailingTrivia.pieces.enumerated().forEach { index, trivia in - if !trivia.isSingleSpace && (index == 0 || trailingComma.trailingTrivia.count == 1) { - violations.append(trailingComma.endPositionBeforeTrailingTrivia) - } else if !trivia.isSingleSpace && !trivia.isBlockComment { - violations.append(trailingComma.endPosition) - } + for index in 0 ..< trailingComma.trailingTrivia.pieces.count { + let trivia = trailingComma.trailingTrivia.pieces[index] + + if index < trailingComma.trailingTrivia.pieces.count - 1 { + let next = trailingComma.trailingTrivia.pieces[index + 1] + if trivia.isSingleSpace && (next.isBlockComment || next.isLineComment) { continue } + } + + if !trivia.isSingleSpace && (index == 0 || trailingComma.trailingTrivia.count == 1) { + violations.append(trailingComma.endPositionBeforeTrailingTrivia) + } else if !trivia.isSingleSpace && !trivia.isBlockComment && !trivia.isLineComment { + violations.append(trailingComma.endPosition) + } } } } From 4035a8857ffb43460bd1c4f4845638bffc3d22ad Mon Sep 17 00:00:00 2001 From: uabyss Date: Sun, 11 Feb 2024 17:16:43 +0900 Subject: [PATCH 24/28] wip --- .../Lint/FunctionArgumentsSpacingRule.swift | 43 ++++++++----------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index de8c63f5fc..9c47d46638 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -12,13 +12,13 @@ struct FunctionArgumentsSpacingRule: Rule { nonTriggeringExamples: [ Example("f()"), Example("f(true)"), - Example("f(true, false)"), Example("f(true, false, true)"), - Example("f(a /* comment */)"), + Example("f(a // line comment)"), + Example("f(a /* block comment */)"), Example("f(true, /* comment */, false)"), - Example("f(/* comment */true/* other comment */)"), - Example("f(/* comment */true/* other comment */, false)"), - Example("f(/* comment */true/* other comment */, /* comment */false/* other comment */, false)"), + Example("f(/* comment */ true /* other comment */)"), + Example("f(/* comment */ true /* other comment */, false)"), + Example("f(/* comment */ true /* other comment */, /* comment */ false /* other comment */, false // line comment)"), Example(""" f( /* comment */ @@ -38,8 +38,7 @@ struct FunctionArgumentsSpacingRule: Rule { Example("f(↓ )"), Example("f(↓\t)"), Example("f(↓ true↓ )"), - Example("f(/* comment */ ↓a)"), - Example("f(↓ /* comment */ ↓true /* other comment */ ↓)"), + Example("f(↓ /* comment */ true /* other comment */ ↓)"), Example("f(↓ x: 0, y: 0↓ )"), Example("f(↓ true,↓ false, true↓ )"), Example("f(↓ true,↓ false,↓ /* other comment */ ↓true↓ )") @@ -63,11 +62,11 @@ private extension TriviaPiece { } } var isSpaces: Bool { - if case .spaces = self { - return true - } else { - return false - } + if case .spaces = self { + return true + } else { + return false + } } var isTabs: Bool { if case .tabs = self { @@ -90,19 +89,12 @@ private extension FunctionArgumentsSpacingRule { override func visitPost(_ node: FunctionCallExprSyntax) { guard let leftParen = node.leftParen else { return } let arguments = node.arguments - let argumentsCounts = arguments.count - switch argumentsCounts { - case 0: - guard let triviaAfterLeftParen = leftParen.trailingTrivia.pieces.first else { return } - if triviaAfterLeftParen.isSpaces || triviaAfterLeftParen.isTabs { - violations.append(leftParen.endPositionBeforeTrailingTrivia) - } - case 1: - guard let argument = node.arguments.first else { return } + switch arguments.count { + case 0, 1: // check whether there are whitespaces before a variable checkLeftParenTrailingTrivia(leftParen: leftParen) // check whether there are whitespaces after a variable - checkArgumentTrailingTrivia(argument: argument) + checkArgumentTrailingTrivia(argument: node.arguments.first) default: test(arguments: arguments, leftParen: leftParen) } @@ -128,12 +120,15 @@ private extension FunctionArgumentsSpacingRule { leftParen.trailingTrivia.pieces.enumerated().forEach { index, trivia in if (trivia.isSpaces || trivia.isTabs) && (index == 0 || leftParen.trailingTrivia.count == 1) { violations.append(leftParen.endPositionBeforeTrailingTrivia) + } else if trivia.isSingleSpace && leftParen.trailingTrivia.count - 1 == index { + return } else if trivia.isSpaces || trivia.isTabs { violations.append(leftParen.endPosition) } } } - private func checkArgumentTrailingTrivia(argument: LabeledExprListSyntax.Element) { + private func checkArgumentTrailingTrivia(argument: LabeledExprListSyntax.Element?) { + guard let argument = argument else { return } guard !argument.trailingTrivia.pieces.isEmpty else { return } for index in 0 ..< argument.trailingTrivia.pieces.count { @@ -141,7 +136,7 @@ private extension FunctionArgumentsSpacingRule { if index < argument.trailingTrivia.pieces.count - 1 { let next = argument.trailingTrivia.pieces[index + 1] - if trivia.isSingleSpace && next.isBlockComment { continue } + if trivia.isSingleSpace && (next.isBlockComment || next.isLineComment) { continue } } let isInitialOrSinglePiece = index == 0 || argument.trailingTrivia.pieces.count == 1 From 89f32aefb74a617c15ab74d4d7dafe5dc3d5cb53 Mon Sep 17 00:00:00 2001 From: uabyss Date: Sun, 11 Feb 2024 22:05:35 +0900 Subject: [PATCH 25/28] refactoring --- .../Lint/FunctionArgumentsSpacingRule.swift | 61 +++++++------------ 1 file changed, 23 insertions(+), 38 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 9c47d46638..a38e2a605e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -18,7 +18,7 @@ struct FunctionArgumentsSpacingRule: Rule { Example("f(true, /* comment */, false)"), Example("f(/* comment */ true /* other comment */)"), Example("f(/* comment */ true /* other comment */, false)"), - Example("f(/* comment */ true /* other comment */, /* comment */ false /* other comment */, false // line comment)"), + Example("f(true /* other comment */, /* comment */ false /* other comment */, false // line comment)"), Example(""" f( /* comment */ @@ -88,31 +88,18 @@ private extension FunctionArgumentsSpacingRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: FunctionCallExprSyntax) { guard let leftParen = node.leftParen else { return } - let arguments = node.arguments - switch arguments.count { - case 0, 1: - // check whether there are whitespaces before a variable - checkLeftParenTrailingTrivia(leftParen: leftParen) - // check whether there are whitespaces after a variable - checkArgumentTrailingTrivia(argument: node.arguments.first) - default: - test(arguments: arguments, leftParen: leftParen) - } + checkSpaces(arguments: node.arguments, leftParen: leftParen) } - - func test(arguments: LabeledExprListSyntax, leftParen: TokenSyntax) { - arguments.enumerated().forEach { index, arg in - switch index { - case 0: - checkLeftParenTrailingTrivia(leftParen: leftParen) + func checkSpaces(arguments: LabeledExprListSyntax?, leftParen: TokenSyntax) { + checkLeftParenTrailingTrivia(leftParen: leftParen) + if let arguments { + arguments.enumerated().forEach { index, arg in + // check argument if index is last + if index == arguments.count - 1 { + checkArgumentTrailingTrivia(argument: arguments.last) + } guard let trailingComma = arg.trailingComma else { return } checkTrailingComma(trailingComma: trailingComma) - case arguments.count - 1: - guard let lastArgument = arguments.last else { return } - checkArgumentTrailingTrivia(argument: lastArgument) - default: - guard let trailingComma = arg.trailingComma else { return } - checkTrailingComma(trailingComma: trailingComma) } } } @@ -128,24 +115,22 @@ private extension FunctionArgumentsSpacingRule { } } private func checkArgumentTrailingTrivia(argument: LabeledExprListSyntax.Element?) { - guard let argument = argument else { return } + if let argument { guard !argument.trailingTrivia.pieces.isEmpty else { return } - for index in 0 ..< argument.trailingTrivia.pieces.count { - let trivia = argument.trailingTrivia.pieces[index] - - if index < argument.trailingTrivia.pieces.count - 1 { - let next = argument.trailingTrivia.pieces[index + 1] - if trivia.isSingleSpace && (next.isBlockComment || next.isLineComment) { continue } - } - let isInitialOrSinglePiece = index == 0 || argument.trailingTrivia.pieces.count == 1 - - if (trivia.isSpaces || trivia.isTabs) && isInitialOrSinglePiece { - violations.append(argument.endPositionBeforeTrailingTrivia) - } else if trivia.isSpaces || trivia.isTabs { - violations.append(argument.endPosition) - } + let trivia = argument.trailingTrivia.pieces[index] + if index < argument.trailingTrivia.pieces.count - 1 { + let next = argument.trailingTrivia.pieces[index + 1] + if trivia.isSingleSpace && (next.isBlockComment || next.isLineComment) { continue } + } + let isInitialOrSinglePiece = index == 0 || argument.trailingTrivia.pieces.count == 1 + if (trivia.isSpaces || trivia.isTabs) && isInitialOrSinglePiece { + violations.append(argument.endPositionBeforeTrailingTrivia) + } else if trivia.isSpaces || trivia.isTabs { + violations.append(argument.endPosition) + } } + } } private func checkTrailingComma(trailingComma: TokenSyntax) { for index in 0 ..< trailingComma.trailingTrivia.pieces.count { From 85943973878bec77fa200bea54785d4452caaa75 Mon Sep 17 00:00:00 2001 From: uabyss Date: Sun, 11 Feb 2024 22:13:11 +0900 Subject: [PATCH 26/28] add: test case --- .../Lint/FunctionArgumentsSpacingRule.swift | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index a38e2a605e..290f7f948b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -15,9 +15,8 @@ struct FunctionArgumentsSpacingRule: Rule { Example("f(true, false, true)"), Example("f(a // line comment)"), Example("f(a /* block comment */)"), - Example("f(true, /* comment */, false)"), + Example("f(true, /* comment */, false // line comment)"), Example("f(/* comment */ true /* other comment */)"), - Example("f(/* comment */ true /* other comment */, false)"), Example("f(true /* other comment */, /* comment */ false /* other comment */, false // line comment)"), Example(""" f( @@ -41,7 +40,13 @@ struct FunctionArgumentsSpacingRule: Rule { Example("f(↓ /* comment */ true /* other comment */ ↓)"), Example("f(↓ x: 0, y: 0↓ )"), Example("f(↓ true,↓ false, true↓ )"), - Example("f(↓ true,↓ false,↓ /* other comment */ ↓true↓ )") + Example("f(↓ true,↓ false,↓ /* other comment */ ↓true↓ )"), + Example(""" + f( + a: true,↓ // line comment + b: true,↓ // line comment + ) + """) ] ) } @@ -134,18 +139,18 @@ private extension FunctionArgumentsSpacingRule { } private func checkTrailingComma(trailingComma: TokenSyntax) { for index in 0 ..< trailingComma.trailingTrivia.pieces.count { - let trivia = trailingComma.trailingTrivia.pieces[index] + let trivia = trailingComma.trailingTrivia.pieces[index] - if index < trailingComma.trailingTrivia.pieces.count - 1 { - let next = trailingComma.trailingTrivia.pieces[index + 1] - if trivia.isSingleSpace && (next.isBlockComment || next.isLineComment) { continue } - } + if index < trailingComma.trailingTrivia.pieces.count - 1 { + let next = trailingComma.trailingTrivia.pieces[index + 1] + if trivia.isSingleSpace && (next.isBlockComment || next.isLineComment) { continue } + } - if !trivia.isSingleSpace && (index == 0 || trailingComma.trailingTrivia.count == 1) { - violations.append(trailingComma.endPositionBeforeTrailingTrivia) - } else if !trivia.isSingleSpace && !trivia.isBlockComment && !trivia.isLineComment { - violations.append(trailingComma.endPosition) - } + if !trivia.isSingleSpace && (index == 0 || trailingComma.trailingTrivia.count == 1) { + violations.append(trailingComma.endPositionBeforeTrailingTrivia) + } else if !trivia.isSingleSpace && !trivia.isBlockComment && !trivia.isLineComment { + violations.append(trailingComma.endPosition) + } } } } From 2f86326d452441ecbab3d5aa47e07602f4f237d0 Mon Sep 17 00:00:00 2001 From: uabyss Date: Sun, 11 Feb 2024 22:43:57 +0900 Subject: [PATCH 27/28] refactoring --- .../Lint/FunctionArgumentsSpacingRule.swift | 57 ++++++++----------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift index 290f7f948b..54b686d14c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift @@ -52,13 +52,6 @@ struct FunctionArgumentsSpacingRule: Rule { } private extension TriviaPiece { - var isSingleSpace: Bool { - if case .spaces(1) = self { - return true - } else { - return false - } - } var isLineComment: Bool { if case .lineComment = self { return true @@ -66,26 +59,19 @@ private extension TriviaPiece { return false } } - var isSpaces: Bool { - if case .spaces = self { + var isBlockComment: Bool { + if case .blockComment = self { return true } else { return false } } - var isTabs: Bool { - if case .tabs = self { - return true - } else { - return false - } - } - var isBlockComment: Bool { - if case .blockComment = self { - return true - } else { - return false - } + var isSingleSpace: Bool { + if case .spaces(1) = self { + return true + } else { + return false + } } } @@ -99,45 +85,52 @@ private extension FunctionArgumentsSpacingRule { checkLeftParenTrailingTrivia(leftParen: leftParen) if let arguments { arguments.enumerated().forEach { index, arg in - // check argument if index is last + // By trailing trivia in the last argument, the space in front of the right bracket is checked. if index == arguments.count - 1 { checkArgumentTrailingTrivia(argument: arguments.last) } guard let trailingComma = arg.trailingComma else { return } - checkTrailingComma(trailingComma: trailingComma) + checkCommaTrailingTrivia(trailingComma: trailingComma) } } } + private func checkLeftParenTrailingTrivia(leftParen: TokenSyntax) { leftParen.trailingTrivia.pieces.enumerated().forEach { index, trivia in - if (trivia.isSpaces || trivia.isTabs) && (index == 0 || leftParen.trailingTrivia.count == 1) { + if trivia.isSpaceOrTab && (index == 0 || leftParen.trailingTrivia.count == 1) { violations.append(leftParen.endPositionBeforeTrailingTrivia) } else if trivia.isSingleSpace && leftParen.trailingTrivia.count - 1 == index { return - } else if trivia.isSpaces || trivia.isTabs { + } else if trivia.isSpaceOrTab { violations.append(leftParen.endPosition) } } } + private func checkArgumentTrailingTrivia(argument: LabeledExprListSyntax.Element?) { if let argument { guard !argument.trailingTrivia.pieces.isEmpty else { return } + for index in 0 ..< argument.trailingTrivia.pieces.count { let trivia = argument.trailingTrivia.pieces[index] + if index < argument.trailingTrivia.pieces.count - 1 { let next = argument.trailingTrivia.pieces[index + 1] if trivia.isSingleSpace && (next.isBlockComment || next.isLineComment) { continue } } - let isInitialOrSinglePiece = index == 0 || argument.trailingTrivia.pieces.count == 1 - if (trivia.isSpaces || trivia.isTabs) && isInitialOrSinglePiece { - violations.append(argument.endPositionBeforeTrailingTrivia) - } else if trivia.isSpaces || trivia.isTabs { - violations.append(argument.endPosition) + + if trivia.isSpaceOrTab { + if index == 0 || argument.trailingTrivia.pieces.count == 1 { + violations.append(argument.endPositionBeforeTrailingTrivia) + } else { + violations.append(argument.endPosition) + } } } } } - private func checkTrailingComma(trailingComma: TokenSyntax) { + + private func checkCommaTrailingTrivia(trailingComma: TokenSyntax) { for index in 0 ..< trailingComma.trailingTrivia.pieces.count { let trivia = trailingComma.trailingTrivia.pieces[index] From dfbec83534f2d3d4c75639a653926b86a3b8faf1 Mon Sep 17 00:00:00 2001 From: uabyss Date: Mon, 12 Feb 2024 00:03:58 +0900 Subject: [PATCH 28/28] change: name and description --- CHANGELOG.md | 3 +-- .../SwiftLintBuiltInRules/Models/BuiltInRules.swift | 2 +- ...acingRule.swift => NoUnnecessarySpacesRule.swift} | 10 +++++----- .../Rules/Style/VerticalWhitespaceRule.swift | 2 +- Tests/GeneratedTests/GeneratedTests.swift | 12 ++++++------ .../FunctionArgumentsSpacingRuleTests.swift | 8 -------- .../NoUnnecessarySpacesRuleTests.swift | 8 ++++++++ 7 files changed, 22 insertions(+), 23 deletions(-) rename Source/SwiftLintBuiltInRules/Rules/Lint/{FunctionArgumentsSpacingRule.swift => NoUnnecessarySpacesRule.swift} (94%) delete mode 100644 Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift create mode 100644 Tests/SwiftLintFrameworkTests/NoUnnecessarySpacesRuleTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fd6e5c7f1..6c08ac4af3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,8 +121,7 @@ * Make `empty_count` auto-correctable. [KS1019](https://github.com/KS1019/) -* Add new `functions_arguments_spacing` rule to remove the space before the first function argument - and after the last argument. +* Add new `no_unnecessary_spaces` rule that No space before the first and after the last argument and exactly one space after every comma. [u-abyss](https://github.com/u-abyss) [#5259](https://github.com/realm/SwiftLint/issues/5224) diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index 4b9ce7db26..38e60a5364 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -78,7 +78,6 @@ public let builtInRules: [any Rule.Type] = [ ForceCastRule.self, ForceTryRule.self, ForceUnwrappingRule.self, - FunctionArgumentsSpacingRule.self, FunctionBodyLengthRule.self, FunctionDefaultParameterAtEndRule.self, FunctionParameterCountRule.self, @@ -135,6 +134,7 @@ public let builtInRules: [any Rule.Type] = [ NonOptionalStringDataConversionRule.self, NonOverridableClassDeclarationRule.self, NotificationCenterDetachmentRule.self, + NoUnnecessarySpacesRule.self, NumberSeparatorRule.self, ObjectLiteralRule.self, OneDelarationPerFileRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/NoUnnecessarySpacesRule.swift similarity index 94% rename from Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift rename to Source/SwiftLintBuiltInRules/Rules/Lint/NoUnnecessarySpacesRule.swift index 54b686d14c..bca94525d0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/FunctionArgumentsSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/NoUnnecessarySpacesRule.swift @@ -1,13 +1,13 @@ import SwiftSyntax @SwiftSyntaxRule -struct FunctionArgumentsSpacingRule: Rule { +struct NoUnnecessarySpacesRule: Rule { var configuration = SeverityConfiguration(.warning) static let description = RuleDescription( - identifier: "functions_arguments_spacing", - name: "Function Arguments Spacing", - description: "Remove the space before the first function argument and after the last argument", + identifier: "no_unnecessary_spaces", + name: "no Unnecessary Spaces", + description: "No space before the first and after the last argument and exactly one space after every comma", kind: .lint, nonTriggeringExamples: [ Example("f()"), @@ -75,7 +75,7 @@ private extension TriviaPiece { } } -private extension FunctionArgumentsSpacingRule { +private extension NoUnnecessarySpacesRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: FunctionCallExprSyntax) { guard let leftParen = node.leftParen else { return } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift index c7c509d728..70751ab2a9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift @@ -26,7 +26,7 @@ struct VerticalWhitespaceRule: CorrectableRule { Example("let b = 0\n\n\nclass AAA {}\n"): Example("let b = 0\n\nclass AAA {}\n"), Example("let c = 0\n\n\nlet num = 1\n"): Example("let c = 0\n\nlet num = 1\n"), Example("// bca \n\n\n"): Example("// bca \n\n") - ]// End of line autocorrections are handled by Trailing Newline Rule. + ] // End of line autocorrections are handled by Trailing Newline Rule. ) private var configuredDescriptionReason: String { diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index a183d813e9..d12375506b 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -458,12 +458,6 @@ class ForceUnwrappingRuleGeneratedTests: SwiftLintTestCase { } } -class FunctionArgumentsSpacingRuleGeneratedTests: SwiftLintTestCase { - func testWithDefaultConfiguration() { - verifyRule(FunctionArgumentsSpacingRule.description) - } -} - class FunctionBodyLengthRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FunctionBodyLengthRule.description) @@ -800,6 +794,12 @@ class NotificationCenterDetachmentRuleGeneratedTests: SwiftLintTestCase { } } +class NoUnnecessarySpacesRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(NoUnnecessarySpacesRule.description) + } +} + class NumberSeparatorRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NumberSeparatorRule.description) diff --git a/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift b/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift deleted file mode 100644 index 45fb57e6a0..0000000000 --- a/Tests/SwiftLintFrameworkTests/FunctionArgumentsSpacingRuleTests.swift +++ /dev/null @@ -1,8 +0,0 @@ -@testable import SwiftLintBuiltInRules - -class FunctionArgumentsSpacingRuleTests: SwiftLintTestCase { - func testFunctionArgumentsSpacingRule() { - let description = FunctionArgumentsSpacingRule.description - verifyRule(description) - } -} diff --git a/Tests/SwiftLintFrameworkTests/NoUnnecessarySpacesRuleTests.swift b/Tests/SwiftLintFrameworkTests/NoUnnecessarySpacesRuleTests.swift new file mode 100644 index 0000000000..78044eb593 --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/NoUnnecessarySpacesRuleTests.swift @@ -0,0 +1,8 @@ +@testable import SwiftLintBuiltInRules + +class NoUnnecessarySpacesRuleTests: SwiftLintTestCase { + func testNoUnnecessarySpacesRule() { + let description = NoUnnecessarySpacesRule.description + verifyRule(description) + } +}