diff --git a/CHANGELOG.md b/CHANGELOG.md index 06509950b..593719e3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,9 @@ [woodhamgh](https://github.com/woodhamgh) [696](https://github.com/realm/SwiftLint/issues/696) +* Adds 'ConditionalReturnsOnNewLineRule' rule. + [Rohan Dhaimade](https://github.com/HaloZero) + ##### Bug Fixes * Fixed CustomRule Regex. diff --git a/Source/SwiftLintFramework/Models/MasterRuleList.swift b/Source/SwiftLintFramework/Models/MasterRuleList.swift index ab5de8cef..333269500 100644 --- a/Source/SwiftLintFramework/Models/MasterRuleList.swift +++ b/Source/SwiftLintFramework/Models/MasterRuleList.swift @@ -44,6 +44,7 @@ public let masterRuleList = RuleList(rules: ClosingBraceRule.self, ColonRule.self, CommaRule.self, + ConditionalReturnsOnNewline.self, ControlStatementRule.self, CustomRules.self, CyclomaticComplexityRule.self, diff --git a/Source/SwiftLintFramework/Rules/ConditionalReturnsOnNewline.swift b/Source/SwiftLintFramework/Rules/ConditionalReturnsOnNewline.swift new file mode 100644 index 000000000..15a8644bf --- /dev/null +++ b/Source/SwiftLintFramework/Rules/ConditionalReturnsOnNewline.swift @@ -0,0 +1,43 @@ +// +// ConditionalReturnsOnNewline.swift +// SwiftLint +// +// Created by Rohan Dhaimade on 12/08/2016. +// Copyright © 2016 Realm. All rights reserved. +// + +import Foundation +import SourceKittenFramework + +public struct ConditionalReturnsOnNewline: ConfigurationProviderRule, Rule, OptInRule { + public let configurationDescription = "N/A" + public var configuration = SeverityConfiguration(.Warning) + + public init() { } + + public static let description = RuleDescription( + identifier: "conditional_returns_on_newline", + name: "Conditional Returns on Newline", + description: "Conditional statements should always return on the next line", + nonTriggeringExamples: [ + "guard true else {\n return true\n}", + "guard true,\n let x = true else {\n return true\n}", + "if true else {\n return true\n}", + "if true,\n let x = true else {\n return true\n}" + ], + triggeringExamples: [ + "guard true else { return }", + "if true { return }", + "if true { break } else { return }", + ] + ) + + public func validateFile(file: File) -> [StyleViolation] { + let pattern = "(guard|if)[^\n]*return[^\n]\n*" + let excludingKinds = SyntaxKind.commentAndStringKinds() + return file.matchPattern(pattern, excludingSyntaxKinds: excludingKinds).map { + StyleViolation(ruleDescription: self.dynamicType.description, + location: Location(file: file, byteOffset: $0.location)) + } + } +} diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj index 7b3c2315f..fa992d8c5 100644 --- a/SwiftLint.xcodeproj/project.pbxproj +++ b/SwiftLint.xcodeproj/project.pbxproj @@ -53,6 +53,7 @@ 7250948A1D0859260039B353 /* StatementPositionConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 725094881D0855760039B353 /* StatementPositionConfiguration.swift */; }; 83894F221B0C928A006214E1 /* RulesCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83894F211B0C928A006214E1 /* RulesCommand.swift */; }; 83D71E281B131ECE000395DE /* RuleDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83D71E261B131EB5000395DE /* RuleDescription.swift */; }; + 93E0C3CE1D67BD7F007FA25D /* ConditionalReturnsOnNewline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93E0C3CD1D67BD7F007FA25D /* ConditionalReturnsOnNewline.swift */; }; B58AEED61C492C7B00E901FD /* ForceUnwrappingRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58AEED51C492C7B00E901FD /* ForceUnwrappingRule.swift */; }; BFF028AE1CBCF8A500B38A9D /* TrailingWhitespaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF48D2D61CBCCA5F0080BDAE /* TrailingWhitespaceConfiguration.swift */; }; D0AAAB5019FB0960007B24B3 /* SwiftLintFramework.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D0D1216D19E87B05005E4BAA /* SwiftLintFramework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -215,6 +216,7 @@ 725094881D0855760039B353 /* StatementPositionConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatementPositionConfiguration.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 = ""; }; + 93E0C3CD1D67BD7F007FA25D /* ConditionalReturnsOnNewline.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConditionalReturnsOnNewline.swift; sourceTree = ""; }; B58AEED51C492C7B00E901FD /* ForceUnwrappingRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForceUnwrappingRule.swift; sourceTree = ""; }; BF48D2D61CBCCA5F0080BDAE /* TrailingWhitespaceConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrailingWhitespaceConfiguration.swift; sourceTree = ""; }; D0D1211B19E87861005E4BAA /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; usesTabs = 0; }; @@ -583,6 +585,7 @@ 1F11B3CE1C252F23002E8FA8 /* ClosingBraceRule.swift */, E88DEA831B0990F500A66CB0 /* ColonRule.swift */, 695BE9CE1BDFD92B0071E985 /* CommaRule.swift */, + 93E0C3CD1D67BD7F007FA25D /* ConditionalReturnsOnNewline.swift */, 65454F451B14D73800319A6C /* ControlStatementRule.swift */, 3B1DF0111C5148140011BCED /* CustomRules.swift */, 2E02005E1C54BF680024D09D /* CyclomaticComplexityRule.swift */, @@ -920,6 +923,7 @@ E881985A1BEA96EA00333A11 /* OperatorFunctionWhitespaceRule.swift in Sources */, 3BCC04D21C4F56D3006073C3 /* NameConfiguration.swift in Sources */, E88DEA6F1B09843F00A66CB0 /* Location.swift in Sources */, + 93E0C3CE1D67BD7F007FA25D /* ConditionalReturnsOnNewline.swift in Sources */, E88DEA771B098D0C00A66CB0 /* Rule.swift in Sources */, 7250948A1D0859260039B353 /* StatementPositionConfiguration.swift in Sources */, E81619531BFC162C00946723 /* QueuedPrint.swift in Sources */, diff --git a/Tests/SwiftLintFramework/RulesTests.swift b/Tests/SwiftLintFramework/RulesTests.swift index fe26d103d..ab09ba40d 100644 --- a/Tests/SwiftLintFramework/RulesTests.swift +++ b/Tests/SwiftLintFramework/RulesTests.swift @@ -93,6 +93,10 @@ class RulesTests: XCTestCase { verifyRule(CommaRule.description) } + func testConditionalReturnsOnNewline() { + verifyRule(ConditionalReturnsOnNewline.description) + } + func testControlStatement() { verifyRule(ControlStatementRule.description) }