From d7750b35cd4e4ca8904aa79e40f0ad5fae455886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20G=C3=BCnd=C3=BCz?= Date: Wed, 28 Nov 2018 19:30:36 +0100 Subject: [PATCH] Multiline Brackets (#2302) * Add new multiline_literal_brackets rule with examples * Implement rule * Add changelog entry * Fix CHANGELOG and rule name * Fix tests + Update stuff after rebasing * Add more examples & fix whitespace issue * Address feedback from @ornithocoder * Add multiline rules for arguments and parameters * Fix false positives in rule multiline_parameters_brackets * Fix false positive for trailing closures in multiline_arguments_brackets * Add nested examples to rule multiline_arguments_brackets * Fix more false positives in multiline_arguments_brackets rule * Use guard where appropriate instead of if * Update generated artifacts after rebase * Add CHANGELOG entry for all three new rules * Move changelog entries to new version * Fix changelog entries position * Move new rules to correct subfolder * Update Rules.md file contents * Fixup changelog * Refactor rules --- CHANGELOG.md | 15 + Rules.md | 307 ++++++++++++++++++ .../Models/MasterRuleList.swift | 3 + .../MultilineArgumentsBracketsRule.swift | 115 +++++++ .../Style/MultilineLiteralBracketsRule.swift | 137 ++++++++ .../MultilineParametersBracketsRule.swift | 185 +++++++++++ SwiftLint.xcodeproj/project.pbxproj | 12 + Tests/LinuxMain.swift | 21 ++ .../AutomaticRuleTests.generated.swift | 18 + 9 files changed, 813 insertions(+) create mode 100644 Source/SwiftLintFramework/Rules/Style/MultilineArgumentsBracketsRule.swift create mode 100644 Source/SwiftLintFramework/Rules/Style/MultilineLiteralBracketsRule.swift create mode 100644 Source/SwiftLintFramework/Rules/Style/MultilineParametersBracketsRule.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 43990e825c2..7f3a98e23f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,21 @@ [Cihat Gündüz](https://github.com/Dschee) [#1517](https://github.com/realm/SwiftLint/issues/1517) +* Add `multiline_arguments_brackets` opt-in rule to warn against multiline + function call arguments with surrounding brackets without newline. + [Cihat Gündüz](https://github.com/Dschee) + [#2306](https://github.com/realm/SwiftLint/issues/2306) + +* Add `multiline_literal_brackets` opt-in rule to warn against multiline + literal arrays & dictionaries with surrounding brackets without newline. + [Cihat Gündüz](https://github.com/Dschee) + [#2306](https://github.com/realm/SwiftLint/issues/2306) + +* Add `multiline_parameters_brackets` opt-in rule to warn against multiline + function definition parameters with surrounding brackets without newline. + [Cihat Gündüz](https://github.com/Dschee) + [#2306](https://github.com/realm/SwiftLint/issues/2306) + #### Bug Fixes * Fix false positive in `nimble_operator` rule. diff --git a/Rules.md b/Rules.md index 108d78c71e7..df2d3b70d01 100644 --- a/Rules.md +++ b/Rules.md @@ -77,8 +77,11 @@ * [Missing Docs](#missing-docs) * [Modifier Order](#modifier-order) * [Multiline Arguments](#multiline-arguments) +* [Multiline Arguments Brackets](#multiline-arguments-brackets) * [Multiline Function Chains](#multiline-function-chains) +* [Multiline Literal Brackets](#multiline-literal-brackets) * [Multiline Parameters](#multiline-parameters) +* [Multiline Parameters Brackets](#multiline-parameters-brackets) * [Multiple Closures with Trailing Closure](#multiple-closures-with-trailing-closure) * [Nesting](#nesting) * [Nimble Operator](#nimble-operator) @@ -11091,6 +11094,95 @@ foo( +## Multiline Arguments Brackets + +Identifier | Enabled by default | Supports autocorrection | Kind | Analyzer | Minimum Swift Compiler Version +--- | --- | --- | --- | --- | --- +`multiline_arguments_brackets` | Disabled | No | style | No | 3.0.0 + +Multiline arguments should have their surrounding brackets in a new line. + +### Examples + +
+Non Triggering Examples + +```swift +foo(param1: "Param1", param2: "Param2", param3: "Param3") +``` + +```swift +foo( + param1: "Param1", param2: "Param2", param3: "Param3" +) +``` + +```swift +func foo( + param1: "Param1", + param2: "Param2", + param3: "Param3" +) +``` + +```swift +foo { param1, param2 in + print("hello world") +} +``` + +```swift +foo( + bar( + x: 5, + y: 7 + ) +) +``` + +```swift +AlertViewModel.AlertAction(title: "some title", style: .default) { + AlertManager.shared.presentNextDebugAlert() +} +``` + +
+
+Triggering Examples + +```swift +foo(↓param1: "Param1", param2: "Param2", + param3: "Param3" +) +``` + +```swift +foo( + param1: "Param1", + param2: "Param2", + param3: "Param3"↓) +``` + +```swift +foo(↓bar( + x: 5, + y: 7 +) +) +``` + +```swift +foo( + bar( + x: 5, + y: 7 +)↓) +``` + +
+ + + ## Multiline Function Chains Identifier | Enabled by default | Supports autocorrection | Kind | Analyzer | Minimum Swift Compiler Version @@ -11207,6 +11299,118 @@ a.b { +## Multiline Literal Brackets + +Identifier | Enabled by default | Supports autocorrection | Kind | Analyzer | Minimum Swift Compiler Version +--- | --- | --- | --- | --- | --- +`multiline_literal_brackets` | Disabled | No | style | No | 3.0.0 + +Multiline literals should have their surrounding brackets in a new line. + +### Examples + +
+Non Triggering Examples + +```swift +let trio = ["harry", "ronald", "hermione"] +let houseCup = ["gryffinder": 460, "hufflepuff": 370, "ravenclaw": 410, "slytherin": 450] +``` + +```swift +let trio = [ + "harry", + "ronald", + "hermione" +] +let houseCup = [ + "gryffinder": 460, + "hufflepuff": 370, + "ravenclaw": 410, + "slytherin": 450 +] +``` + +```swift +let trio = [ + "harry", "ronald", "hermione" +] +let houseCup = [ + "gryffinder": 460, "hufflepuff": 370, + "ravenclaw": 410, "slytherin": 450 +] +``` + +```swift + _ = [ + 1, + 2, + 3, + 4, + 5, 6, + 7, 8, 9 + ] +``` + +
+
+Triggering Examples + +```swift +let trio = [↓"harry", + "ronald", + "hermione" +] +``` + +```swift +let houseCup = [↓"gryffinder": 460, "hufflepuff": 370, + "ravenclaw": 410, "slytherin": 450 +] +``` + +```swift +let trio = [ + "harry", + "ronald", + "hermione"↓] +``` + +```swift +let houseCup = [ + "gryffinder": 460, "hufflepuff": 370, + "ravenclaw": 410, "slytherin": 450↓] +``` + +```swift +class Hogwarts { + let houseCup = [ + "gryffinder": 460, "hufflepuff": 370, + "ravenclaw": 410, "slytherin": 450↓] +} +``` + +```swift + _ = [ + 1, + 2, + 3, + 4, + 5, 6, + 7, 8, 9↓] +``` + +```swift + _ = [↓1, 2, 3, + 4, 5, 6, + 7, 8, 9 + ] +``` + +
+ + + ## Multiline Parameters Identifier | Enabled by default | Supports autocorrection | Kind | Analyzer | Minimum Swift Compiler Version @@ -11687,6 +11891,109 @@ class Foo { +## Multiline Parameters Brackets + +Identifier | Enabled by default | Supports autocorrection | Kind | Analyzer | Minimum Swift Compiler Version +--- | --- | --- | --- | --- | --- +`multiline_parameters_brackets` | Disabled | No | style | No | 3.0.0 + +Multiline parameters should have their surrounding brackets in a new line. + +### Examples + +
+Non Triggering Examples + +```swift +func foo(param1: String, param2: String, param3: String) +``` + +```swift +func foo( + param1: String, param2: String, param3: String +) +``` + +```swift +func foo( + param1: String, + param2: String, + param3: String +) +``` + +```swift +class SomeType { + func foo(param1: String, param2: String, param3: String) +} +``` + +```swift +class SomeType { + func foo( + param1: String, param2: String, param3: String + ) +} +``` + +```swift +class SomeType { + func foo( + param1: String, + param2: String, + param3: String + ) +} +``` + +```swift +func foo(param1: T, param2: String, param3: String) -> T { /* some code */ } +``` + +
+
+Triggering Examples + +```swift +func foo(↓param1: String, param2: String, + param3: String +) +``` + +```swift +func foo( + param1: String, + param2: String, + param3: String↓) +``` + +```swift +class SomeType { + func foo(↓param1: String, param2: String, + param3: String + ) +} +``` + +```swift +class SomeType { + func foo( + param1: String, + param2: String, + param3: String↓) +} +``` + +```swift +func foo(↓param1: T, param2: String, + param3: String +) -> T +``` + +
+ + + ## Multiple Closures with Trailing Closure Identifier | Enabled by default | Supports autocorrection | Kind | Analyzer | Minimum Swift Compiler Version diff --git a/Source/SwiftLintFramework/Models/MasterRuleList.swift b/Source/SwiftLintFramework/Models/MasterRuleList.swift index f004d0083cf..2162fcb7a44 100644 --- a/Source/SwiftLintFramework/Models/MasterRuleList.swift +++ b/Source/SwiftLintFramework/Models/MasterRuleList.swift @@ -77,8 +77,11 @@ public let masterRuleList = RuleList(rules: [ MarkRule.self, MissingDocsRule.self, ModifierOrderRule.self, + MultilineArgumentsBracketsRule.self, MultilineArgumentsRule.self, MultilineFunctionChainsRule.self, + MultilineLiteralBracketsRule.self, + MultilineParametersBracketsRule.self, MultilineParametersRule.self, MultipleClosuresWithTrailingClosureRule.self, NestingRule.self, diff --git a/Source/SwiftLintFramework/Rules/Style/MultilineArgumentsBracketsRule.swift b/Source/SwiftLintFramework/Rules/Style/MultilineArgumentsBracketsRule.swift new file mode 100644 index 00000000000..d04bfe5ef92 --- /dev/null +++ b/Source/SwiftLintFramework/Rules/Style/MultilineArgumentsBracketsRule.swift @@ -0,0 +1,115 @@ +import Foundation +import SourceKittenFramework + +public struct MultilineArgumentsBracketsRule: ASTRule, OptInRule, ConfigurationProviderRule, AutomaticTestableRule { + public var configuration = SeverityConfiguration(.warning) + + public init() {} + + public static let description = RuleDescription( + identifier: "multiline_arguments_brackets", + name: "Multiline Arguments Brackets", + description: "Multiline arguments should have their surrounding brackets in a new line.", + kind: .style, + nonTriggeringExamples: [ + """ + foo(param1: "Param1", param2: "Param2", param3: "Param3") + """, + """ + foo( + param1: "Param1", param2: "Param2", param3: "Param3" + ) + """, + """ + func foo( + param1: "Param1", + param2: "Param2", + param3: "Param3" + ) + """, + """ + foo { param1, param2 in + print("hello world") + } + """, + """ + foo( + bar( + x: 5, + y: 7 + ) + ) + """, + """ + AlertViewModel.AlertAction(title: "some title", style: .default) { + AlertManager.shared.presentNextDebugAlert() + } + """ + ], + triggeringExamples: [ + """ + foo(↓param1: "Param1", param2: "Param2", + param3: "Param3" + ) + """, + """ + foo( + param1: "Param1", + param2: "Param2", + param3: "Param3"↓) + """, + """ + foo(↓bar( + x: 5, + y: 7 + ) + ) + """, + """ + foo( + bar( + x: 5, + y: 7 + )↓) + """ + ] + ) + + public func validate(file: File, + kind: SwiftExpressionKind, + dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] { + guard + kind == .call, + let bodyOffset = dictionary.bodyOffset, + let bodyLength = dictionary.bodyLength, + let range = file.contents.bridge().byteRangeToNSRange(start: bodyOffset, length: bodyLength) + else { + return [] + } + + let body = file.contents.substring(from: range.location, length: range.length) + let isMultiline = body.contains("\n") + guard isMultiline else { + return [] + } + + let expectedBodyBeginRegex = regex("\\A(?:[ \\t]*\\n|[^\\n]*(?:in|\\{)\\n)") + let expectedBodyEndRegex = regex("\\n[ \\t]*\\z") + + var violatingByteOffsets = [Int]() + if expectedBodyBeginRegex.firstMatch(in: body, options: [], range: body.fullNSRange) == nil { + violatingByteOffsets.append(bodyOffset) + } + + if expectedBodyEndRegex.firstMatch(in: body, options: [], range: body.fullNSRange) == nil { + violatingByteOffsets.append(bodyOffset + bodyLength) + } + + return violatingByteOffsets.map { byteOffset in + StyleViolation( + ruleDescription: type(of: self).description, severity: configuration.severity, + location: Location(file: file, byteOffset: byteOffset) + ) + } + } +} diff --git a/Source/SwiftLintFramework/Rules/Style/MultilineLiteralBracketsRule.swift b/Source/SwiftLintFramework/Rules/Style/MultilineLiteralBracketsRule.swift new file mode 100644 index 00000000000..61141e3f9b4 --- /dev/null +++ b/Source/SwiftLintFramework/Rules/Style/MultilineLiteralBracketsRule.swift @@ -0,0 +1,137 @@ +import Foundation +import SourceKittenFramework + +public struct MultilineLiteralBracketsRule: ASTRule, OptInRule, ConfigurationProviderRule, AutomaticTestableRule { + public var configuration = SeverityConfiguration(.warning) + + public init() {} + + public static let description = RuleDescription( + identifier: "multiline_literal_brackets", + name: "Multiline Literal Brackets", + description: "Multiline literals should have their surrounding brackets in a new line.", + kind: .style, + nonTriggeringExamples: [ + """ + let trio = ["harry", "ronald", "hermione"] + let houseCup = ["gryffinder": 460, "hufflepuff": 370, "ravenclaw": 410, "slytherin": 450] + """, + """ + let trio = [ + "harry", + "ronald", + "hermione" + ] + let houseCup = [ + "gryffinder": 460, + "hufflepuff": 370, + "ravenclaw": 410, + "slytherin": 450 + ] + """, + """ + let trio = [ + "harry", "ronald", "hermione" + ] + let houseCup = [ + "gryffinder": 460, "hufflepuff": 370, + "ravenclaw": 410, "slytherin": 450 + ] + """, + """ + _ = [ + 1, + 2, + 3, + 4, + 5, 6, + 7, 8, 9 + ] + """ + ], + triggeringExamples: [ + """ + let trio = [↓"harry", + "ronald", + "hermione" + ] + """, + """ + let houseCup = [↓"gryffinder": 460, "hufflepuff": 370, + "ravenclaw": 410, "slytherin": 450 + ] + """, + """ + let trio = [ + "harry", + "ronald", + "hermione"↓] + """, + """ + let houseCup = [ + "gryffinder": 460, "hufflepuff": 370, + "ravenclaw": 410, "slytherin": 450↓] + """, + """ + class Hogwarts { + let houseCup = [ + "gryffinder": 460, "hufflepuff": 370, + "ravenclaw": 410, "slytherin": 450↓] + } + """, + """ + _ = [ + 1, + 2, + 3, + 4, + 5, 6, + 7, 8, 9↓] + """, + """ + _ = [↓1, 2, 3, + 4, 5, 6, + 7, 8, 9 + ] + """ + ] + ) + + public func validate(file: File, + kind: SwiftExpressionKind, + dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] { + guard + [.array, .dictionary].contains(kind), + let bodyOffset = dictionary.bodyOffset, + let bodyLength = dictionary.bodyLength, + let range = file.contents.bridge().byteRangeToNSRange(start: bodyOffset, length: bodyLength) + else { + return [] + } + + let body = file.contents.substring(from: range.location, length: range.length) + let isMultiline = body.contains("\n") + guard isMultiline else { + return [] + } + + let expectedBodyBeginRegex = regex("\\A[ \\t]*\\n") + let expectedBodyEndRegex = regex("\\n[ \\t]*\\z") + + var violatingByteOffsets = [Int]() + if expectedBodyBeginRegex.firstMatch(in: body, options: [], range: body.fullNSRange) == nil { + violatingByteOffsets.append(bodyOffset) + } + + if expectedBodyEndRegex.firstMatch(in: body, options: [], range: body.fullNSRange) == nil { + violatingByteOffsets.append(bodyOffset + bodyLength) + } + + return violatingByteOffsets.map { byteOffset in + StyleViolation( + ruleDescription: type(of: self).description, severity: configuration.severity, + location: Location(file: file, byteOffset: byteOffset) + ) + } + } +} diff --git a/Source/SwiftLintFramework/Rules/Style/MultilineParametersBracketsRule.swift b/Source/SwiftLintFramework/Rules/Style/MultilineParametersBracketsRule.swift new file mode 100644 index 00000000000..e545dc80ef3 --- /dev/null +++ b/Source/SwiftLintFramework/Rules/Style/MultilineParametersBracketsRule.swift @@ -0,0 +1,185 @@ +import Foundation +import SourceKittenFramework + +public struct MultilineParametersBracketsRule: OptInRule, ConfigurationProviderRule, AutomaticTestableRule { + public var configuration = SeverityConfiguration(.warning) + + public init() {} + + public static let description = RuleDescription( + identifier: "multiline_parameters_brackets", + name: "Multiline Parameters Brackets", + description: "Multiline parameters should have their surrounding brackets in a new line.", + kind: .style, + nonTriggeringExamples: [ + """ + func foo(param1: String, param2: String, param3: String) + """, + """ + func foo( + param1: String, param2: String, param3: String + ) + """, + """ + func foo( + param1: String, + param2: String, + param3: String + ) + """, + """ + class SomeType { + func foo(param1: String, param2: String, param3: String) + } + """, + """ + class SomeType { + func foo( + param1: String, param2: String, param3: String + ) + } + """, + """ + class SomeType { + func foo( + param1: String, + param2: String, + param3: String + ) + } + """, + """ + func foo(param1: T, param2: String, param3: String) -> T { /* some code */ } + """ + ], + triggeringExamples: [ + """ + func foo(↓param1: String, param2: String, + param3: String + ) + """, + """ + func foo( + param1: String, + param2: String, + param3: String↓) + """, + """ + class SomeType { + func foo(↓param1: String, param2: String, + param3: String + ) + } + """, + """ + class SomeType { + func foo( + param1: String, + param2: String, + param3: String↓) + } + """, + """ + func foo(↓param1: T, param2: String, + param3: String + ) -> T + """ + ] + ) + + public func validate(file: File) -> [StyleViolation] { + return violations(in: file.structure.dictionary, file: file) + } + + private func violations(in substructure: [String: SourceKitRepresentable], file: File) -> [StyleViolation] { + var violations = [StyleViolation]() + + // find violations at current level + if let kindString = substructure.kind, let kind = SwiftDeclarationKind(rawValue: kindString), + SwiftDeclarationKind.functionKinds.contains(kind) { + + guard + let nameOffset = substructure.nameOffset, + let nameLength = substructure.nameLength, + let functionName = file.contents.bridge().substringWithByteRange(start: nameOffset, length: nameLength) + else { + return [] + } + + let isMultiline = functionName.contains("\n") + + let parameters = substructure.substructure.filter { $0.kind == SwiftDeclarationKind.varParameter.rawValue } + if isMultiline && !parameters.isEmpty { + if let openingBracketViolation = openingBracketViolation(parameters: parameters, file: file) { + violations.append(openingBracketViolation) + } + + if let closingBracketViolation = closingBracketViolation(parameters: parameters, file: file) { + violations.append(closingBracketViolation) + } + } + } + + // find violations at deeper levels + for substructure in substructure.substructure { + violations += self.violations(in: substructure, file: file) + } + + return violations + } + + private func openingBracketViolation(parameters: [[String: SourceKitRepresentable]], + file: File) -> StyleViolation? { + guard + let firstParamByteOffset = parameters.first?.offset, + let firstParamByteLength = parameters.first?.length, + let firstParamRange = file.contents.bridge().byteRangeToNSRange( + start: firstParamByteOffset, + length: firstParamByteLength + ) + else { + return nil + } + + let prefix = file.contents.bridge().substring(to: firstParamRange.lowerBound) + let invalidRegex = regex("\\([ \\t]*\\z") + + guard let invalidMatch = invalidRegex.firstMatch(in: prefix, options: [], range: prefix.fullNSRange) else { + return nil + } + + return StyleViolation( + ruleDescription: type(of: self).description, + severity: configuration.severity, + location: Location(file: file, characterOffset: invalidMatch.range.location + 1) + ) + } + + private func closingBracketViolation(parameters: [[String: SourceKitRepresentable]], + file: File) -> StyleViolation? { + guard + let lastParamByteOffset = parameters.last?.offset, + let lastParamByteLength = parameters.last?.length, + let lastParamRange = file.contents.bridge().byteRangeToNSRange( + start: lastParamByteOffset, + length: lastParamByteLength + ) + else { + return nil + } + + let suffix = file.contents.bridge().substring(from: lastParamRange.upperBound) + let invalidRegex = regex("\\A[ \\t]*\\)") + + guard let invalidMatch = invalidRegex.firstMatch(in: suffix, options: [], range: suffix.fullNSRange) else { + return nil + } + + let characterOffset = lastParamRange.upperBound + invalidMatch.range.upperBound - 1 + return StyleViolation( + ruleDescription: type(of: self).description, + severity: configuration.severity, + location: Location(file: file, characterOffset: characterOffset) + ) + } +} diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj index 8b6afcea87a..44bf72b8eff 100644 --- a/SwiftLint.xcodeproj/project.pbxproj +++ b/SwiftLint.xcodeproj/project.pbxproj @@ -139,10 +139,13 @@ 7C0C2E7A1D2866CB0076435A /* ExplicitInitRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C0C2E791D2866CB0076435A /* ExplicitInitRule.swift */; }; 820F451E21073D7200AA056A /* ConditionalReturnsOnNewlineRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 820F451D21073D7200AA056A /* ConditionalReturnsOnNewlineRuleTests.swift */; }; 824AB64D2105C39F004B5A8F /* ConditionalReturnsOnNewlineConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824AB64C2105C39F004B5A8F /* ConditionalReturnsOnNewlineConfiguration.swift */; }; + 823EDC6221020D850070B7CD /* MultilineLiteralBracketsRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823EDC6121020D850070B7CD /* MultilineLiteralBracketsRule.swift */; }; 82144ACC20F640F200B06695 /* VerticalWhitespaceBetweenCasesRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82144ACB20F640F200B06695 /* VerticalWhitespaceBetweenCasesRule.swift */; }; 825F19D11EEFF19700969EF1 /* ObjectLiteralRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825F19D01EEFF19700969EF1 /* ObjectLiteralRuleTests.swift */; }; 827169B31F488181003FB9AF /* ExplicitEnumRawValueRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827169B21F488181003FB9AF /* ExplicitEnumRawValueRule.swift */; }; 827169B51F48D712003FB9AF /* NoGroupingExtensionRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827169B41F48D712003FB9AF /* NoGroupingExtensionRule.swift */; }; + 82F614F22106014500D23904 /* MultilineParametersBracketsRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F614F12106014500D23904 /* MultilineParametersBracketsRule.swift */; }; + 82F614F42106015100D23904 /* MultilineArgumentsBracketsRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F614F32106015100D23904 /* MultilineArgumentsBracketsRule.swift */; }; 83894F221B0C928A006214E1 /* RulesCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83894F211B0C928A006214E1 /* RulesCommand.swift */; }; 83D71E281B131ECE000395DE /* RuleDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83D71E261B131EB5000395DE /* RuleDescription.swift */; }; 85DA81321D6B471000951BC4 /* MarkRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 856651A61D6B395F005E6B29 /* MarkRule.swift */; }; @@ -561,10 +564,13 @@ 7C0C2E791D2866CB0076435A /* ExplicitInitRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExplicitInitRule.swift; sourceTree = ""; }; 820F451D21073D7200AA056A /* ConditionalReturnsOnNewlineRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConditionalReturnsOnNewlineRuleTests.swift; sourceTree = ""; }; 824AB64C2105C39F004B5A8F /* ConditionalReturnsOnNewlineConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConditionalReturnsOnNewlineConfiguration.swift; sourceTree = ""; }; + 823EDC6121020D850070B7CD /* MultilineLiteralBracketsRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultilineLiteralBracketsRule.swift; sourceTree = ""; }; 82144ACB20F640F200B06695 /* VerticalWhitespaceBetweenCasesRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerticalWhitespaceBetweenCasesRule.swift; sourceTree = ""; }; 825F19D01EEFF19700969EF1 /* ObjectLiteralRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectLiteralRuleTests.swift; sourceTree = ""; }; 827169B21F488181003FB9AF /* ExplicitEnumRawValueRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExplicitEnumRawValueRule.swift; sourceTree = ""; }; 827169B41F48D712003FB9AF /* NoGroupingExtensionRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoGroupingExtensionRule.swift; sourceTree = ""; }; + 82F614F12106014500D23904 /* MultilineParametersBracketsRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultilineParametersBracketsRule.swift; sourceTree = ""; }; + 82F614F32106015100D23904 /* MultilineArgumentsBracketsRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultilineArgumentsBracketsRule.swift; sourceTree = ""; }; 83894F211B0C928A006214E1 /* RulesCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RulesCommand.swift; sourceTree = ""; }; 83D71E261B131EB5000395DE /* RuleDescription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RuleDescription.swift; sourceTree = ""; }; 856651A61D6B395F005E6B29 /* MarkRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkRule.swift; sourceTree = ""; }; @@ -1050,9 +1056,12 @@ C946FEC91EAE5E20007DD778 /* LetVarWhitespaceRule.swift */, D4EA77C91F81FACC00C315FB /* LiteralExpressionEndIdentationRule.swift */, 188B3FF1207D61040073C2D6 /* ModifierOrderRule.swift */, + 82F614F32106015100D23904 /* MultilineArgumentsBracketsRule.swift */, B25DCD071F7E9B5F0028A199 /* MultilineArgumentsRule.swift */, B25DCD091F7E9BB50028A199 /* MultilineArgumentsRuleExamples.swift */, 3ABE19CD20B7CDE0009C2EC2 /* MultilineFunctionChainsRule.swift */, + 823EDC6121020D850070B7CD /* MultilineLiteralBracketsRule.swift */, + 82F614F12106014500D23904 /* MultilineParametersBracketsRule.swift */, 6238AE411ED4D734006C3601 /* MultilineParametersRule.swift */, 621061BE1ED57E640082D51E /* MultilineParametersRuleExamples.swift */, BB00B4E71F5216070079869F /* MultipleClosuresWithTrailingClosureRule.swift */, @@ -1787,6 +1796,7 @@ D44AD2761C0AA5350048F7B0 /* LegacyConstructorRule.swift in Sources */, D286EC021E02DF6F0003CF72 /* SortedImportsRule.swift in Sources */, D40E041C1F46E3B30043BC4E /* SuperfluousDisableCommandRule.swift in Sources */, + 82F614F42106015100D23904 /* MultilineArgumentsBracketsRule.swift in Sources */, E86623671F1D377900AAA3A2 /* Configuration+Parsing.swift in Sources */, 3BCC04CD1C4F5694006073C3 /* ConfigurationError.swift in Sources */, D4C4A34E1DEA877200E0E04C /* FileHeaderRule.swift in Sources */, @@ -1839,6 +1849,7 @@ D4B022A41E105636007E5297 /* GenericTypeNameRule.swift in Sources */, E86396CB1BADB519002C9E88 /* CSVReporter.swift in Sources */, 37B3FA8B1DFD45A700AD30D2 /* Dictionary+SwiftLint.swift in Sources */, + 823EDC6221020D850070B7CD /* MultilineLiteralBracketsRule.swift in Sources */, D47EF4801F69E3100012C4CA /* ColonRule+FunctionCall.swift in Sources */, E88198561BEA94D800333A11 /* FileLengthRule.swift in Sources */, D47079A91DFDBED000027086 /* ClosureParameterPositionRule.swift in Sources */, @@ -1904,6 +1915,7 @@ E86396C51BADAC15002C9E88 /* XcodeReporter.swift in Sources */, E889D8C51F1D11A200058332 /* Configuration+LintableFiles.swift in Sources */, 094385011D5D2894009168CF /* WeakDelegateRule.swift in Sources */, + 82F614F22106014500D23904 /* MultilineParametersBracketsRule.swift in Sources */, 3B1DF0121C5148140011BCED /* CustomRules.swift in Sources */, 2E5761AA1C573B83003271AF /* FunctionParameterCountRule.swift in Sources */, E86396C91BADB2B9002C9E88 /* JSONReporter.swift in Sources */, diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 43bbab27f14..426e0ace9a8 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -714,6 +714,12 @@ extension ModifierOrderTests { ] } +extension MultilineArgumentsBracketsRuleTests { + static var allTests: [(String, (MultilineArgumentsBracketsRuleTests) -> () throws -> Void)] = [ + ("testWithDefaultConfiguration", testWithDefaultConfiguration) + ] +} + extension MultilineArgumentsRuleTests { static var allTests: [(String, (MultilineArgumentsRuleTests) -> () throws -> Void)] = [ ("testMultilineArgumentsWithDefaultConfiguration", testMultilineArgumentsWithDefaultConfiguration), @@ -729,6 +735,18 @@ extension MultilineFunctionChainsRuleTests { ] } +extension MultilineLiteralBracketsRuleTests { + static var allTests: [(String, (MultilineLiteralBracketsRuleTests) -> () throws -> Void)] = [ + ("testWithDefaultConfiguration", testWithDefaultConfiguration) + ] +} + +extension MultilineParametersBracketsRuleTests { + static var allTests: [(String, (MultilineParametersBracketsRuleTests) -> () throws -> Void)] = [ + ("testWithDefaultConfiguration", testWithDefaultConfiguration) + ] +} + extension MultilineParametersRuleTests { static var allTests: [(String, (MultilineParametersRuleTests) -> () throws -> Void)] = [ ("testWithDefaultConfiguration", testWithDefaultConfiguration) @@ -1400,8 +1418,11 @@ XCTMain([ testCase(MissingDocsRuleConfigurationTests.allTests), testCase(MissingDocsRuleTests.allTests), testCase(ModifierOrderTests.allTests), + testCase(MultilineArgumentsBracketsRuleTests.allTests), testCase(MultilineArgumentsRuleTests.allTests), testCase(MultilineFunctionChainsRuleTests.allTests), + testCase(MultilineLiteralBracketsRuleTests.allTests), + testCase(MultilineParametersBracketsRuleTests.allTests), testCase(MultilineParametersRuleTests.allTests), testCase(MultipleClosuresWithTrailingClosureRuleTests.allTests), testCase(NestingRuleTests.allTests), diff --git a/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift b/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift index 06810873347..1941262c1cb 100644 --- a/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift +++ b/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift @@ -330,12 +330,30 @@ class MissingDocsRuleTests: XCTestCase { } } +class MultilineArgumentsBracketsRuleTests: XCTestCase { + func testWithDefaultConfiguration() { + verifyRule(MultilineArgumentsBracketsRule.description) + } +} + class MultilineFunctionChainsRuleTests: XCTestCase { func testWithDefaultConfiguration() { verifyRule(MultilineFunctionChainsRule.description) } } +class MultilineLiteralBracketsRuleTests: XCTestCase { + func testWithDefaultConfiguration() { + verifyRule(MultilineLiteralBracketsRule.description) + } +} + +class MultilineParametersBracketsRuleTests: XCTestCase { + func testWithDefaultConfiguration() { + verifyRule(MultilineParametersBracketsRule.description) + } +} + class MultilineParametersRuleTests: XCTestCase { func testWithDefaultConfiguration() { verifyRule(MultilineParametersRule.description)