mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
Merge master into trailing-comma-rule-reason-string
This commit is contained in:
+18
-1
@@ -2,7 +2,24 @@
|
||||
|
||||
##### Breaking
|
||||
|
||||
* `file_length` rule now has a default value of `120` for warnings.
|
||||
* None.
|
||||
|
||||
##### Enhancements
|
||||
|
||||
* Add `vertical_parameter_alignment` rule that checks if parameters are
|
||||
vertically aligned for multi-line function declarations.
|
||||
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||
[#1033](https://github.com/realm/SwiftLint/issues/1033)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* None.
|
||||
|
||||
## 0.15.0: Hand Washable Holiday Linens 🎄
|
||||
|
||||
##### Breaking
|
||||
|
||||
* `line_length` rule now has a default value of `120` for warnings.
|
||||
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||
[#1008](https://github.com/realm/SwiftLint/issues/1008)
|
||||
|
||||
|
||||
@@ -102,6 +102,7 @@ public let masterRuleList = RuleList(rules:
|
||||
ValidDocsRule.self,
|
||||
ValidIBInspectableRule.self,
|
||||
VariableNameRule.self,
|
||||
VerticalParameterAlignmentRule.self,
|
||||
VerticalWhitespaceRule.self,
|
||||
VoidReturnRule.self,
|
||||
WeakDelegateRule.self
|
||||
|
||||
@@ -21,7 +21,7 @@ public struct JSONReporter: Reporter {
|
||||
return toJSON(violations.map(dictionaryForViolation))
|
||||
}
|
||||
|
||||
fileprivate static func dictionaryForViolation(_ violation: StyleViolation) -> NSDictionary {
|
||||
fileprivate static func dictionaryForViolation(_ violation: StyleViolation) -> [String: Any] {
|
||||
return [
|
||||
"file": violation.location.file ?? NSNull() as Any,
|
||||
"line": violation.location.line ?? NSNull() as Any,
|
||||
|
||||
@@ -66,7 +66,7 @@ public struct LineLengthRule: ConfigurationProviderRule, SourceKitFreeRule {
|
||||
///
|
||||
/// - returns: sourceString with the given literals replaced by `#`
|
||||
private func stripLiterals(fromSourceString sourceString: String,
|
||||
withDelimiter delimiter: String) -> String {
|
||||
withDelimiter delimiter: String) -> String {
|
||||
var modifiedString = sourceString
|
||||
|
||||
// While copy of content contains literal, replace with a single character
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// VerticalParameterAlignmentRule.swift
|
||||
// SwiftLint
|
||||
//
|
||||
// Created by Marcelo Fabri on 12/22/16.
|
||||
// Copyright © 2016 Realm. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SourceKittenFramework
|
||||
|
||||
public struct VerticalParameterAlignmentRule: ASTRule, ConfigurationProviderRule {
|
||||
public var configuration = SeverityConfiguration(.warning)
|
||||
|
||||
public init() {}
|
||||
|
||||
public static let description = RuleDescription(
|
||||
identifier: "vertical_parameter_alignment",
|
||||
name: "Vertical Parameter Alignment",
|
||||
description: "Function parameters should be aligned vertically if they're in multiple lines in a declaration.",
|
||||
nonTriggeringExamples: [
|
||||
"func validateFunction(_ file: File, kind: SwiftDeclarationKind,\n" +
|
||||
" dictionary: [String: SourceKitRepresentable]) { }\n",
|
||||
"func validateFunction(_ file: File, kind: SwiftDeclarationKind,\n" +
|
||||
" dictionary: [String: SourceKitRepresentable]) -> [StyleViolation]\n",
|
||||
"func foo(bar: Int)\n",
|
||||
"func foo(bar: Int) -> String \n",
|
||||
"func validateFunction(_ file: File, kind: SwiftDeclarationKind,\n" +
|
||||
" dictionary: [String: SourceKitRepresentable])\n" +
|
||||
" -> [StyleViolation]\n",
|
||||
"func validateFunction(\n" +
|
||||
" _ file: File, kind: SwiftDeclarationKind,\n" +
|
||||
" dictionary: [String: SourceKitRepresentable]) -> [StyleViolation]\n"
|
||||
],
|
||||
triggeringExamples: [
|
||||
"func validateFunction(_ file: File, kind: SwiftDeclarationKind,\n" +
|
||||
" ↓dictionary: [String: SourceKitRepresentable]) { }\n",
|
||||
"func validateFunction(_ file: File, kind: SwiftDeclarationKind,\n" +
|
||||
" ↓dictionary: [String: SourceKitRepresentable]) { }\n",
|
||||
"func validateFunction(_ file: File,\n" +
|
||||
" ↓kind: SwiftDeclarationKind,\n" +
|
||||
" ↓dictionary: [String: SourceKitRepresentable]) { }\n"
|
||||
]
|
||||
)
|
||||
|
||||
public func validateFile(_ file: File,
|
||||
kind: SwiftDeclarationKind,
|
||||
dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
|
||||
guard SwiftDeclarationKind.functionKinds().contains(kind) else {
|
||||
return []
|
||||
}
|
||||
|
||||
let contents = file.contents.bridge()
|
||||
let pattern = "\\(\\s*(\\S)"
|
||||
|
||||
guard let nameOffset = (dictionary["key.nameoffset"] as? Int64).flatMap({ Int($0) }),
|
||||
let nameLength = (dictionary["key.namelength"] as? Int64).flatMap({ Int($0) }),
|
||||
let nameRange = contents.byteRangeToNSRange(start: nameOffset, length: nameLength),
|
||||
let paramStart = regex(pattern).firstMatch(in: file.contents,
|
||||
options: [], range: nameRange)?.rangeAt(1).location,
|
||||
let (startLine, startCharacter) = contents.lineAndCharacter(forCharacterOffset: paramStart),
|
||||
let (endLine, _) = contents.lineAndCharacter(forByteOffset: nameOffset + nameLength - 1),
|
||||
endLine > startLine else {
|
||||
return []
|
||||
}
|
||||
|
||||
let linesRange = (startLine + 1)...endLine
|
||||
let violationLocations = linesRange.flatMap { lineIndex -> Int? in
|
||||
let line = file.lines[lineIndex - 1]
|
||||
guard let paramLocation = regex("\\S").firstMatch(in: file.contents, options: [],
|
||||
range: line.range)?.range.location,
|
||||
let (_, paramCharacter) = contents.lineAndCharacter(forCharacterOffset: paramLocation),
|
||||
paramCharacter != startCharacter else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return paramLocation
|
||||
}
|
||||
|
||||
return violationLocations.map {
|
||||
StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: configuration.severity,
|
||||
location: Location(file: file, characterOffset: $0))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.14.0</string>
|
||||
<string>0.15.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.14.0</string>
|
||||
<string>0.15.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@@ -90,9 +90,9 @@
|
||||
D42D2B381E09CC0D00CD7A2E /* FirstWhereRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D42D2B371E09CC0D00CD7A2E /* FirstWhereRule.swift */; };
|
||||
D4348EEA1C46122C007707FB /* FunctionBodyLengthRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4348EE91C46122C007707FB /* FunctionBodyLengthRuleTests.swift */; };
|
||||
D43B04641E0620AB004016AF /* UnusedEnumeratedRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43B04631E0620AB004016AF /* UnusedEnumeratedRule.swift */; };
|
||||
D43B046B1E075905004016AF /* ClosureEndIndentationRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43B046A1E075905004016AF /* ClosureEndIndentationRule.swift */; };
|
||||
D43B04661E071ED3004016AF /* ColonRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43B04651E071ED3004016AF /* ColonRuleTests.swift */; };
|
||||
D43B04691E072291004016AF /* ColonConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43B04671E07228D004016AF /* ColonConfiguration.swift */; };
|
||||
D43B046B1E075905004016AF /* ClosureEndIndentationRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43B046A1E075905004016AF /* ClosureEndIndentationRule.swift */; };
|
||||
D43DB1081DC573DA00281215 /* ImplicitGetterRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43DB1071DC573DA00281215 /* ImplicitGetterRule.swift */; };
|
||||
D44254201DB87CA200492EA4 /* ValidIBInspectableRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D442541E1DB87C3D00492EA4 /* ValidIBInspectableRule.swift */; };
|
||||
D44254271DB9C15C00492EA4 /* SyntacticSugarRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44254251DB9C12300492EA4 /* SyntacticSugarRule.swift */; };
|
||||
@@ -109,6 +109,7 @@
|
||||
D48AE2CC1DFB58C5001C6A4A /* AttributesRulesExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = D48AE2CB1DFB58C5001C6A4A /* AttributesRulesExamples.swift */; };
|
||||
D4998DE71DF191380006E05D /* AttributesRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4998DE61DF191380006E05D /* AttributesRuleTests.swift */; };
|
||||
D4998DE91DF194F20006E05D /* FileHeaderRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4998DE81DF194F20006E05D /* FileHeaderRuleTests.swift */; };
|
||||
D4B0226F1E0C75F9007E5297 /* VerticalParameterAlignmentRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4B0226E1E0C75F9007E5297 /* VerticalParameterAlignmentRule.swift */; };
|
||||
D4C4A34C1DEA4FF000E0E04C /* AttributesConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C4A34A1DEA4FD700E0E04C /* AttributesConfiguration.swift */; };
|
||||
D4C4A34E1DEA877200E0E04C /* FileHeaderRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C4A34D1DEA877200E0E04C /* FileHeaderRule.swift */; };
|
||||
D4C4A3521DEFBBB700E0E04C /* FileHeaderConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C4A3511DEFBBB700E0E04C /* FileHeaderConfiguration.swift */; };
|
||||
@@ -329,9 +330,9 @@
|
||||
D42D2B371E09CC0D00CD7A2E /* FirstWhereRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirstWhereRule.swift; sourceTree = "<group>"; };
|
||||
D4348EE91C46122C007707FB /* FunctionBodyLengthRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FunctionBodyLengthRuleTests.swift; sourceTree = "<group>"; };
|
||||
D43B04631E0620AB004016AF /* UnusedEnumeratedRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnusedEnumeratedRule.swift; sourceTree = "<group>"; };
|
||||
D43B046A1E075905004016AF /* ClosureEndIndentationRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosureEndIndentationRule.swift; sourceTree = "<group>"; };
|
||||
D43B04651E071ED3004016AF /* ColonRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColonRuleTests.swift; sourceTree = "<group>"; };
|
||||
D43B04671E07228D004016AF /* ColonConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColonConfiguration.swift; sourceTree = "<group>"; };
|
||||
D43B046A1E075905004016AF /* ClosureEndIndentationRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosureEndIndentationRule.swift; sourceTree = "<group>"; };
|
||||
D43DB1071DC573DA00281215 /* ImplicitGetterRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImplicitGetterRule.swift; sourceTree = "<group>"; };
|
||||
D442541E1DB87C3D00492EA4 /* ValidIBInspectableRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidIBInspectableRule.swift; sourceTree = "<group>"; };
|
||||
D44254251DB9C12300492EA4 /* SyntacticSugarRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyntacticSugarRule.swift; sourceTree = "<group>"; };
|
||||
@@ -348,6 +349,7 @@
|
||||
D48AE2CB1DFB58C5001C6A4A /* AttributesRulesExamples.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttributesRulesExamples.swift; sourceTree = "<group>"; };
|
||||
D4998DE61DF191380006E05D /* AttributesRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttributesRuleTests.swift; sourceTree = "<group>"; };
|
||||
D4998DE81DF194F20006E05D /* FileHeaderRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileHeaderRuleTests.swift; sourceTree = "<group>"; };
|
||||
D4B0226E1E0C75F9007E5297 /* VerticalParameterAlignmentRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerticalParameterAlignmentRule.swift; sourceTree = "<group>"; };
|
||||
D4C4A34A1DEA4FD700E0E04C /* AttributesConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttributesConfiguration.swift; sourceTree = "<group>"; };
|
||||
D4C4A34D1DEA877200E0E04C /* FileHeaderRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileHeaderRule.swift; sourceTree = "<group>"; };
|
||||
D4C4A3511DEFBBB700E0E04C /* FileHeaderConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileHeaderConfiguration.swift; sourceTree = "<group>"; };
|
||||
@@ -778,6 +780,7 @@
|
||||
E81CDE701C00FEAA00B430F6 /* ValidDocsRule.swift */,
|
||||
D442541E1DB87C3D00492EA4 /* ValidIBInspectableRule.swift */,
|
||||
E88DEA931B099C0900A66CB0 /* VariableNameRule.swift */,
|
||||
D4B0226E1E0C75F9007E5297 /* VerticalParameterAlignmentRule.swift */,
|
||||
1EC163511D5992D900DD2928 /* VerticalWhitespaceRule.swift */,
|
||||
D47079AE1DFE520000027086 /* VoidReturnRule.swift */,
|
||||
094384FF1D5D2382009168CF /* WeakDelegateRule.swift */,
|
||||
@@ -1094,6 +1097,7 @@
|
||||
D46252541DF63FB200BE2CA1 /* NumberSeparatorRule.swift in Sources */,
|
||||
E315B83C1DFA4BC500621B44 /* DynamicInlineRule.swift in Sources */,
|
||||
D42D2B381E09CC0D00CD7A2E /* FirstWhereRule.swift in Sources */,
|
||||
D4B0226F1E0C75F9007E5297 /* VerticalParameterAlignmentRule.swift in Sources */,
|
||||
D44254271DB9C15C00492EA4 /* SyntacticSugarRule.swift in Sources */,
|
||||
E88198441BEA93D200333A11 /* ColonRule.swift in Sources */,
|
||||
E809EDA11B8A71DF00399043 /* Configuration.swift in Sources */,
|
||||
|
||||
@@ -69,7 +69,18 @@ class ReporterTests: XCTestCase {
|
||||
func testJSONReporter() {
|
||||
let expectedOutput = stringFromFile("CannedJSONReporterOutput.json")
|
||||
let result = JSONReporter.generateReport(generateViolations())
|
||||
XCTAssertEqual(result, expectedOutput)
|
||||
func jsonValue(_ jsonString: String) -> NSObject {
|
||||
let data = jsonString.data(using: .utf8)!
|
||||
// swiftlint:disable:next force_try
|
||||
let result = try! JSONSerialization.jsonObject(with: data, options: [])
|
||||
if let dict = (result as? [String: Any])?.bridge() {
|
||||
return dict
|
||||
} else if let array = (result as? [Any])?.bridge() {
|
||||
return array
|
||||
}
|
||||
fatalError()
|
||||
}
|
||||
XCTAssertEqual(jsonValue(result), jsonValue(expectedOutput))
|
||||
}
|
||||
|
||||
func testCSVReporter() {
|
||||
@@ -107,8 +118,7 @@ extension ReporterTests {
|
||||
("testReporterFromString", testReporterFromString),
|
||||
("testXcodeReporter", testXcodeReporter),
|
||||
("testEmojiReporter", testEmojiReporter),
|
||||
// Fails on Linux
|
||||
// ("testJSONReporter", testJSONReporter),
|
||||
("testJSONReporter", testJSONReporter),
|
||||
("testCSVReporter", testCSVReporter),
|
||||
("testCheckstyleReporter", testCheckstyleReporter),
|
||||
("testJunitReporter", testJunitReporter),
|
||||
|
||||
@@ -292,6 +292,10 @@ class RulesTests: XCTestCase {
|
||||
verifyRule(VariableNameRule.description)
|
||||
}
|
||||
|
||||
func testVerticalParameterAlignment() {
|
||||
verifyRule(VerticalParameterAlignmentRule.description)
|
||||
}
|
||||
|
||||
func testVoidReturn() {
|
||||
verifyRule(VoidReturnRule.description)
|
||||
}
|
||||
@@ -345,7 +349,7 @@ extension RulesTests {
|
||||
("testOperatorFunctionWhitespace", testOperatorFunctionWhitespace),
|
||||
("testOperatorUsageWhitespace", testOperatorUsageWhitespace),
|
||||
("testPrivateOutlet", testPrivateOutlet),
|
||||
// ("testPrivateUnitTest", testPrivateUnitTest),
|
||||
("testPrivateUnitTest", testPrivateUnitTest),
|
||||
("testProhibitedSuper", testProhibitedSuper),
|
||||
("testRedundantNilCoalescing", testRedundantNilCoalescing),
|
||||
("testRedundantStringEnumValue", testRedundantStringEnumValue),
|
||||
@@ -364,6 +368,7 @@ extension RulesTests {
|
||||
("testUnusedEnumerated", testUnusedEnumerated),
|
||||
("testValidIBInspectable", testValidIBInspectable),
|
||||
// ("testVariableName", testVariableName),
|
||||
("VerticalParameterAlignmentRule", testVerticalParameterAlignment),
|
||||
("testVoidReturn", testVoidReturn),
|
||||
("testSuperCall", testSuperCall),
|
||||
("testWeakDelegate", testWeakDelegate)
|
||||
|
||||
Reference in New Issue
Block a user