Skip to content

Commit

Permalink
New rule: LongLineRule
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryuichi Saito committed Jun 21, 2017
1 parent 8cee34b commit fa2808a
Show file tree
Hide file tree
Showing 10 changed files with 260 additions and 3 deletions.
1 change: 1 addition & 0 deletions .yanagiba
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
lint:
rule-configurations:
- NESTED_CODE_BLOCK_DEPTH: 6
- LONG_LINE: 120
severity-thresholds:
- critical: 0
- major: 0
Expand Down
32 changes: 32 additions & 0 deletions Documentation/Rules/Readability.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,35 @@ func example(
##### References:

Fowler, Martin (1999). *Refactoring: Improving the design of existing code.* Addison Wesley.


## Long Line

<dl>
<dt>Identifier</dt>
<dd>long_line</dd>
<dt>File name</dt>
<dd>LongLineRule.swift</dd>
<dt>Severity</dt>
<dd>Minor</dd>
<dt>Category</dt>
<dd>Readability</dd>
</dl>

When a line of code is very long, it largely harms the readability.
Break long lines of code into multiple lines.

##### Thresholds:

<dl>
<dt>LONG_LINE</dt>
<dd>The long line reporting threshold, default value is 100.</dd>
</dl>

##### Examples:

###### Example 1

```
let a012345678901234567890123456789...1234567890123456789012345678901234567890123456789
```
32 changes: 32 additions & 0 deletions Documentation/Rules/Readability_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,35 @@ func example(
##### References:

Fowler, Martin (1999). *Refactoring: Improving the design of existing code.* Addison Wesley.


## Long Line

<dl>
<dt>标识名</dt>
<dd>long_line</dd>
<dt>文件名</dt>
<dd>LongLineRule.swift</dd>
<dt>严重级别</dt>
<dd>Minor</dd>
<dt>分类</dt>
<dd>Readability</dd>
</dl>

When a line of code is very long, it largely harms the readability.
Break long lines of code into multiple lines.

##### Thresholds:

<dl>
<dt>LONG_LINE</dt>
<dd>The long line reporting threshold, default value is 100.</dd>
</dl>

##### Examples:

###### Example 1

```
let a012345678901234567890123456789...1234567890123456789012345678901234567890123456789
```
32 changes: 32 additions & 0 deletions Documentation/Rules/Readability_JP.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,35 @@ func example(
##### References:

Fowler, Martin (1999). *Refactoring: Improving the design of existing code.* Addison Wesley.


## Long Line

<dl>
<dt>識別子</dt>
<dd>long_line</dd>
<dt>ファイル名</dt>
<dd>LongLineRule.swift</dd>
<dt>激しさ</dt>
<dd>Minor</dd>
<dt>分類</dt>
<dd>Readability</dd>
</dl>

When a line of code is very long, it largely harms the readability.
Break long lines of code into multiple lines.

##### Thresholds:

<dl>
<dt>LONG_LINE</dt>
<dd>The long line reporting threshold, default value is 100.</dd>
</dl>

##### Examples:

###### Example 1

```
let a012345678901234567890123456789...1234567890123456789012345678901234567890123456789
```
61 changes: 61 additions & 0 deletions Sources/Lint/Rule/LongLineRule.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
Copyright 2017 Ryuichi Saito, LLC and the Yanagiba project contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import Foundation

class LongLineRule : RuleBase, SourceCodeRule {
static let ThresholdKey = "LONG_LINE"
static let DefaultThreshold = 100

let name = "Long Line"
var description: String? {
return """
When a line of code is very long, it largely harms the readability.
Break long lines of code into multiple lines.
"""
}
var examples: [String]? {
return [
"let a012345678901234567890123456789...1234567890123456789012345678901234567890123456789",
]
}
var thresholds: [String: String]? {
return [
LongLineRule.ThresholdKey:
"The long line reporting threshold, default value is \(LongLineRule.DefaultThreshold)."
]
}
let severity = Issue.Severity.minor
let category = Issue.Category.readability

private func getThreshold(of lineNumber: Int) -> Int {
return getConfiguration(
forKey: LongLineRule.ThresholdKey,
atLineNumber: lineNumber,
orDefault: LongLineRule.DefaultThreshold)
}

func inspect(line: String, lineNumber: Int) {
let threshold = getThreshold(of: lineNumber)
let lineCount = line.count
guard lineCount > threshold else {
return
}
emitIssue(
lineNumber,
description: "Line with \(lineCount) characters exceeds limit of \(threshold)")
}
}
1 change: 1 addition & 0 deletions Sources/Lint/RuleSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public struct RuleSet {
RedundantVariableDeclarationKeywordRule(),
RedundantEnumCaseStringValueRule(),
TooManyParametersRule(),
LongLineRule(),
]

public static var ruleIdentifiers: [String] {
Expand Down
31 changes: 28 additions & 3 deletions Sources/Lint/SourceCodeRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,40 @@ protocol SourceCodeRule : Rule {
}

extension SourceCodeRule where Self : RuleBase {
private var lines: [String] {
guard let astContext = astContext else {
return []
}

return astContext.sourceFile.content.components(separatedBy: .newlines)
}

func inspect(_ astContext: ASTContext, configurations: [String: Any]? = nil) {
self.astContext = astContext
self.configurations = configurations

let sourceContent = astContext.sourceFile.content

let lines = sourceContent.components(separatedBy: .newlines)
for (lineNumber, line) in lines.enumerated() {
inspect(line: line, lineNumber: lineNumber + 1)
}
}

func emitIssue(
_ lineNumber: Int,
description: String,
correction: Correction? = nil
) {
guard lineNumber > 0 && lineNumber <= lines.count,
let path = astContext?.sourceFile.path
else {
return
}

let lineIndex = lineNumber - 1
let line = lines[lineIndex]
let sourceRange = SourceRange(
start: SourceLocation(path: path, line: lineNumber, column: 1),
end: SourceLocation(path: path, line: lineNumber, column: line.count)
)
emitIssue(sourceRange, description: description, correction: correction)
}
}
72 changes: 72 additions & 0 deletions Tests/RuleTests/LongLineRuleTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
Copyright 2017 Ryuichi Saito, LLC and the Yanagiba project contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import XCTest

@testable import Lint

class LongLineRuleTests : XCTestCase {
func testShortText() {
XCTAssertTrue(getIssues(from: """
let a
b
""").isEmpty)
}

func testLongText() {
let issues = getIssues(from: """
let a = b
foo() {}
""")
XCTAssertEqual(issues.count, 2)
let issue0 = issues[0]
XCTAssertEqual(issue0.ruleIdentifier, "long_line")
XCTAssertEqual(issue0.description, "Line with 9 characters exceeds limit of 5")
XCTAssertEqual(issue0.category, .readability)
XCTAssertEqual(issue0.severity, .minor)
let range0 = issue0.location
XCTAssertEqual(range0.start.path, "test/test")
XCTAssertEqual(range0.start.line, 1)
XCTAssertEqual(range0.start.column, 1)
XCTAssertEqual(range0.end.path, "test/test")
XCTAssertEqual(range0.end.line, 1)
XCTAssertEqual(range0.end.column, 9)
let issue1 = issues[1]
XCTAssertEqual(issue1.ruleIdentifier, "long_line")
XCTAssertEqual(issue1.description, "Line with 8 characters exceeds limit of 5")
XCTAssertEqual(issue1.category, .readability)
XCTAssertEqual(issue1.severity, .minor)
let range1 = issue1.location
XCTAssertEqual(range1.start.path, "test/test")
XCTAssertEqual(range1.start.line, 2)
XCTAssertEqual(range1.start.column, 1)
XCTAssertEqual(range1.end.path, "test/test")
XCTAssertEqual(range1.end.line, 2)
XCTAssertEqual(range1.end.column, 8)
}

private func getIssues(from content: String) -> [Issue] {
return content.inspect(
withRule: LongLineRule(),
configurations: [LongLineRule.ThresholdKey: 5]
)
}

static var allTests = [
("testShortText", testShortText),
("testLongText", testLongText),
]
}
1 change: 1 addition & 0 deletions Tests/RuleTests/XCTestManifests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public func allTests() -> [XCTestCaseEntry] {
testCase(RedundantVariableDeclarationKeywordRuleTests.allTests),
testCase(RedundantEnumCaseStringValueRuleTests.allTests),
testCase(TooManyParametersRuleTests.allTests),
testCase(LongLineRuleTests.allTests),
]
}
#endif

0 comments on commit fa2808a

Please sign in to comment.