Add optional return_value_from_void_function rule using SwiftSyntax (#3054)
* Add optional return_value_from_void_function rule using SwiftSyntax * Use Script/bootstrap in CI * Make SwiftSyntax optional * Make SwiftSyntax optional in SPM * Fix Package.swift * Try again * Add minSwiftVersion * Fix thread sanitizer issue * Take 2 * Fix false positive on nested computed variables * Remove support for Xcode 10.x * Fix rule description * Enable opt-in rule in configuration file * Extract code into `SyntaxRule` protocol * nit: make property private * Missing docs * Fix MasterRuleList.swift * Update CHANGELOG * Remove unused imports * Use Example type * Change rule kind to .idiomatic * Update CHANGELOG * Bump deployment target to macOS 10.12 * Simplify SyntaxRule.validate(file:visitor) * Make TSan happy * Use script/bootstrap in the README
This commit is contained in:
parent
0991ede1ed
commit
8d9c501cb8
|
@ -16,3 +16,6 @@
|
|||
[submodule "Carthage/Checkouts/Yams"]
|
||||
path = Carthage/Checkouts/Yams
|
||||
url = https://github.com/jpsim/Yams.git
|
||||
[submodule "SwiftSyntax"]
|
||||
path = SwiftSyntax
|
||||
url = https://github.com/apple/swift-syntax.git
|
||||
|
|
|
@ -54,6 +54,7 @@ opt_in_rules:
|
|||
- reduce_into
|
||||
- redundant_nil_coalescing
|
||||
- redundant_type_annotation
|
||||
- return_value_from_void_function
|
||||
- single_test_class
|
||||
- sorted_first_last
|
||||
- sorted_imports
|
||||
|
|
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -9,6 +9,10 @@
|
|||
[Paul Taykalo](https://github.com/PaulTaykalo)
|
||||
[JP Simard](https://github.com/jpsim)
|
||||
|
||||
* SwiftLint now imports [SwiftSyntax](https://github.com/apple/swift-syntax)
|
||||
and requires Xcode 11.0 to build.
|
||||
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||
|
||||
#### Experimental
|
||||
|
||||
* None.
|
||||
|
@ -26,6 +30,14 @@
|
|||
[ZevEisenberg](https://github.com/ZevEisenberg)
|
||||
[#3040](https://github.com/realm/SwiftLint/pull/3040)
|
||||
|
||||
* Introduce a new `SyntaxRule` that enables writing rules using
|
||||
[SwiftSyntax](https://github.com/apple/swift-syntax).
|
||||
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||
|
||||
* Add `return_value_from_void_function` opt-in rule to warn against using
|
||||
`return <expression>` in a function that is `Void`.
|
||||
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Fix `discarded_notification_center_observer` false positives when
|
||||
|
|
|
@ -55,6 +55,15 @@
|
|||
"version": "0.29.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftSyntax",
|
||||
"repositoryURL": "https://github.com/apple/swift-syntax.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "3e3eb191fcdbecc6031522660c4ed6ce25282c25",
|
||||
"version": "0.50100.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftyTextTable",
|
||||
"repositoryURL": "https://github.com/scottrhoyt/SwiftyTextTable.git",
|
||||
|
|
|
@ -7,8 +7,17 @@ private let addCryptoSwift = false
|
|||
private let addCryptoSwift = true
|
||||
#endif
|
||||
|
||||
#if compiler(>=5.1.0)
|
||||
private let addSwiftSyntax = true
|
||||
#else
|
||||
private let addSwiftSyntax = false
|
||||
#endif
|
||||
|
||||
let package = Package(
|
||||
name: "SwiftLint",
|
||||
platforms: [
|
||||
.macOS(.v10_12)
|
||||
],
|
||||
products: [
|
||||
.executable(name: "swiftlint", targets: ["swiftlint"]),
|
||||
.library(name: "SwiftLintFramework", targets: ["SwiftLintFramework"])
|
||||
|
@ -18,7 +27,8 @@ let package = Package(
|
|||
.package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.29.0")),
|
||||
.package(url: "https://github.com/jpsim/Yams.git", from: "2.0.0"),
|
||||
.package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"),
|
||||
] + (addCryptoSwift ? [.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.0.0"))] : []),
|
||||
] + (addCryptoSwift ? [.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.0.0"))] : []) +
|
||||
(addSwiftSyntax ? [.package(url: "https://github.com/apple/swift-syntax.git", .exact("0.50100.0"))] : []),
|
||||
targets: [
|
||||
.target(
|
||||
name: "swiftlint",
|
||||
|
@ -33,7 +43,8 @@ let package = Package(
|
|||
dependencies: [
|
||||
"SourceKittenFramework",
|
||||
"Yams",
|
||||
] + (addCryptoSwift ? ["CryptoSwift"] : [])
|
||||
] + (addCryptoSwift ? ["CryptoSwift"] : []) +
|
||||
(addSwiftSyntax ? ["SwiftSyntax"] : [])
|
||||
),
|
||||
.testTarget(
|
||||
name: "SwiftLintFrameworkTests",
|
||||
|
|
|
@ -61,7 +61,7 @@ running it.
|
|||
### Compiling from source:
|
||||
|
||||
You can also build from source by cloning this project and running
|
||||
`git submodule update --init --recursive; make install` (Xcode 10.2 or later).
|
||||
`script/bootstrap; make install` (Xcode 11.0 or later).
|
||||
|
||||
### Known Installation Issues On MacOS Before 10.14.4
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import Foundation
|
||||
import SourceKittenFramework
|
||||
#if canImport(SwiftSyntax)
|
||||
import SwiftSyntax
|
||||
#endif
|
||||
|
||||
private typealias FileCacheKey = Int
|
||||
private var responseCache = Cache({ file -> [String: SourceKitRepresentable]? in
|
||||
|
@ -30,6 +33,20 @@ private var syntaxMapCache = Cache({ file in
|
|||
private var syntaxKindsByLinesCache = Cache({ file in file.syntaxKindsByLine() })
|
||||
private var syntaxTokensByLinesCache = Cache({ file in file.syntaxTokensByLine() })
|
||||
|
||||
#if canImport(SwiftSyntax)
|
||||
private var syntaxCache = Cache({ file -> SourceFileSyntax? in
|
||||
do {
|
||||
if let path = file.path {
|
||||
return try SyntaxParser.parse(URL(fileURLWithPath: path))
|
||||
}
|
||||
|
||||
return try SyntaxParser.parse(source: file.contents)
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
#endif
|
||||
|
||||
internal typealias AssertHandler = () -> Void
|
||||
|
||||
private var assertHandlers = [FileCacheKey: AssertHandler]()
|
||||
|
@ -158,6 +175,19 @@ extension SwiftLintFile {
|
|||
return syntaxMap
|
||||
}
|
||||
|
||||
#if canImport(SwiftSyntax)
|
||||
internal var syntax: SourceFileSyntax {
|
||||
guard let syntax = syntaxCache.get(self) else {
|
||||
if let handler = assertHandler {
|
||||
handler()
|
||||
return SourceFileSyntax({ _ in })
|
||||
}
|
||||
queuedFatalError("Never call this for file that sourcekitd fails.")
|
||||
}
|
||||
return syntax
|
||||
}
|
||||
#endif
|
||||
|
||||
internal var syntaxTokensByLines: [[SwiftLintSyntaxToken]] {
|
||||
guard let syntaxTokensByLines = syntaxTokensByLinesCache.get(self) else {
|
||||
if let handler = assertHandler {
|
||||
|
@ -189,6 +219,9 @@ extension SwiftLintFile {
|
|||
syntaxMapCache.invalidate(self)
|
||||
syntaxTokensByLinesCache.invalidate(self)
|
||||
syntaxKindsByLinesCache.invalidate(self)
|
||||
#if canImport(SwiftSyntax)
|
||||
syntaxCache.invalidate(self)
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static func clearCaches() {
|
||||
|
@ -200,5 +233,8 @@ extension SwiftLintFile {
|
|||
syntaxMapCache.clear()
|
||||
syntaxTokensByLinesCache.clear()
|
||||
syntaxKindsByLinesCache.clear()
|
||||
#if canImport(SwiftSyntax)
|
||||
syntaxCache.clear()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,6 +147,7 @@ public let masterRuleList = RuleList(rules: [
|
|||
RequiredDeinitRule.self,
|
||||
RequiredEnumCaseRule.self,
|
||||
ReturnArrowWhitespaceRule.self,
|
||||
ReturnValueFromVoidFunctionRule.self,
|
||||
ShorthandOperatorRule.self,
|
||||
SingleTestClassRule.self,
|
||||
SortedFirstLastRule.self,
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import Foundation
|
||||
#if canImport(SwiftSyntax)
|
||||
import SwiftSyntax
|
||||
#endif
|
||||
|
||||
/// A rule that leverages the SwiftSyntax library.
|
||||
public protocol SyntaxRule: Rule {}
|
||||
|
||||
#if canImport(SwiftSyntax)
|
||||
/// A SwiftSyntax visitor that collects data to provide violations for a specific rule.
|
||||
public protocol SyntaxRuleVisitor: SyntaxVisitor {
|
||||
/// The rule that uses this visitor.
|
||||
associatedtype Rule: SyntaxRule
|
||||
|
||||
/// Returns the violations that should be calculated based on data that was accumulated during the `visit` methods.
|
||||
func violations(for rule: Rule, in file: SwiftLintFile) -> [StyleViolation]
|
||||
}
|
||||
|
||||
public extension SyntaxRule {
|
||||
/// Wraps computation of violations based on a visitor.
|
||||
func validate<Visitor: SyntaxRuleVisitor>(file: SwiftLintFile,
|
||||
visitor: Visitor) -> [StyleViolation] where Visitor.Rule == Self {
|
||||
let lock = NSLock()
|
||||
var visitor = visitor
|
||||
|
||||
// https://bugs.swift.org/browse/SR-11170
|
||||
let work = DispatchWorkItem {
|
||||
lock.lock()
|
||||
file.syntax.walk(&visitor)
|
||||
lock.unlock()
|
||||
}
|
||||
let thread = Thread {
|
||||
work.perform()
|
||||
}
|
||||
thread.stackSize = 8 << 20 // 8 MB.
|
||||
thread.start()
|
||||
work.wait()
|
||||
|
||||
lock.lock()
|
||||
defer { lock.unlock() }
|
||||
return visitor.violations(for: self, in: file)
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,76 @@
|
|||
import SourceKittenFramework
|
||||
#if canImport(SwiftSyntax)
|
||||
import SwiftSyntax
|
||||
#endif
|
||||
|
||||
public struct ReturnValueFromVoidFunctionRule: ConfigurationProviderRule, SyntaxRule, OptInRule,
|
||||
AutomaticTestableRule {
|
||||
public var configuration = SeverityConfiguration(.warning)
|
||||
|
||||
public init() {}
|
||||
|
||||
public static let description = RuleDescription(
|
||||
identifier: "return_value_from_void_function",
|
||||
name: "Return Value from Void Function",
|
||||
description: "Returning values from Void functions should be avoided.",
|
||||
kind: .idiomatic,
|
||||
minSwiftVersion: .fiveDotOne,
|
||||
nonTriggeringExamples: ReturnValueFromVoidFunctionRuleExamples.nonTriggeringExamples,
|
||||
triggeringExamples: ReturnValueFromVoidFunctionRuleExamples.triggeringExamples
|
||||
)
|
||||
|
||||
public func validate(file: SwiftLintFile) -> [StyleViolation] {
|
||||
#if canImport(SwiftSyntax)
|
||||
return validate(file: file, visitor: ReturnVisitor())
|
||||
#else
|
||||
return []
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if canImport(SwiftSyntax)
|
||||
private class ReturnVisitor: SyntaxRuleVisitor {
|
||||
private var positions = [AbsolutePosition]()
|
||||
|
||||
func visit(_ node: ReturnStmtSyntax) -> SyntaxVisitorContinueKind {
|
||||
if node.expression != nil,
|
||||
let functionNode = node.enclosingFunction(),
|
||||
functionNode.returnsVoid {
|
||||
positions.append(node.positionAfterSkippingLeadingTrivia)
|
||||
}
|
||||
return .visitChildren
|
||||
}
|
||||
|
||||
func violations(for rule: ReturnValueFromVoidFunctionRule, in file: SwiftLintFile) -> [StyleViolation] {
|
||||
return positions.map { position in
|
||||
StyleViolation(ruleDescription: type(of: rule).description,
|
||||
severity: rule.configuration.severity,
|
||||
location: Location(file: file, byteOffset: ByteCount(position.utf8Offset)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension Syntax {
|
||||
func enclosingFunction() -> FunctionDeclSyntax? {
|
||||
if let node = self as? FunctionDeclSyntax {
|
||||
return node
|
||||
}
|
||||
|
||||
if self is ClosureExprSyntax || self is VariableDeclSyntax {
|
||||
return nil
|
||||
}
|
||||
|
||||
return parent?.enclosingFunction()
|
||||
}
|
||||
}
|
||||
|
||||
private extension FunctionDeclSyntax {
|
||||
var returnsVoid: Bool {
|
||||
if let type = signature.output?.returnType as? SimpleTypeIdentifierSyntax {
|
||||
return type.name.text == "Void"
|
||||
}
|
||||
|
||||
return signature.output?.returnType == nil
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,234 @@
|
|||
// swiftlint:disable:next type_body_length
|
||||
internal struct ReturnValueFromVoidFunctionRuleExamples {
|
||||
static let nonTriggeringExamples = [
|
||||
Example("""
|
||||
func foo() {
|
||||
return
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func foo() {
|
||||
return /* a comment */
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func foo() -> Int {
|
||||
return 1
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func foo() -> Void {
|
||||
if condition {
|
||||
return
|
||||
}
|
||||
bar()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func foo() {
|
||||
return;
|
||||
bar()
|
||||
}
|
||||
"""),
|
||||
Example("func test() {}"),
|
||||
Example("""
|
||||
init?() {
|
||||
guard condition else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
init?(arg: String?) {
|
||||
guard arg != nil else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() {
|
||||
guard condition else {
|
||||
return
|
||||
}
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() -> Result<String, Error> {
|
||||
func other() {}
|
||||
func otherVoid() -> Void {}
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() -> Int? {
|
||||
return nil
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() {
|
||||
if bar {
|
||||
print("")
|
||||
return
|
||||
}
|
||||
let foo = [1, 2, 3].filter { return true }
|
||||
return
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() {
|
||||
guard foo else {
|
||||
bar()
|
||||
return
|
||||
}
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func spec() {
|
||||
var foo: Int {
|
||||
return 0
|
||||
}
|
||||
""")
|
||||
]
|
||||
|
||||
static let triggeringExamples = [
|
||||
Example("""
|
||||
func foo() {
|
||||
↓return bar()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func foo() {
|
||||
↓return self.bar()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func foo() -> Void {
|
||||
↓return bar()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func foo() -> Void {
|
||||
↓return /* comment */ bar()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func foo() {
|
||||
↓return
|
||||
self.bar()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func foo() {
|
||||
variable += 1
|
||||
↓return
|
||||
variable += 1
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func initThing() {
|
||||
guard foo else {
|
||||
↓return print("")
|
||||
}
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
// Leading comment
|
||||
func test() {
|
||||
guard condition else {
|
||||
↓return assertionfailure("")
|
||||
}
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() -> Result<String, Error> {
|
||||
func other() {
|
||||
guard false else {
|
||||
↓return assertionfailure("")
|
||||
}
|
||||
}
|
||||
func otherVoid() -> Void {}
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() {
|
||||
guard conditionIsTrue else {
|
||||
sideEffects()
|
||||
return // comment
|
||||
}
|
||||
guard otherCondition else {
|
||||
↓return assertionfailure("")
|
||||
}
|
||||
differentSideEffect()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() {
|
||||
guard otherCondition else {
|
||||
↓return assertionfailure(""); // comment
|
||||
}
|
||||
differentSideEffect()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() {
|
||||
if x {
|
||||
↓return foo()
|
||||
}
|
||||
bar()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() {
|
||||
switch x {
|
||||
case .a:
|
||||
↓return foo() // return to skip baz()
|
||||
case .b:
|
||||
bar()
|
||||
}
|
||||
baz()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() {
|
||||
if check {
|
||||
if otherCheck {
|
||||
↓return foo()
|
||||
}
|
||||
}
|
||||
bar()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() {
|
||||
↓return foo()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() {
|
||||
↓return foo({
|
||||
return bar()
|
||||
})
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() {
|
||||
guard x else {
|
||||
↓return foo()
|
||||
}
|
||||
bar()
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
func test() {
|
||||
let closure: () -> () = {
|
||||
return assert()
|
||||
}
|
||||
if check {
|
||||
if otherCheck {
|
||||
return // comments are fine
|
||||
}
|
||||
}
|
||||
↓return foo()
|
||||
}
|
||||
""")
|
||||
]
|
||||
}
|
|
@ -295,6 +295,8 @@
|
|||
D4470D591EB6B4D1008A1B2E /* EmptyEnumArgumentsRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4470D581EB6B4D1008A1B2E /* EmptyEnumArgumentsRule.swift */; };
|
||||
D4470D5B1EB76F44008A1B2E /* UnusedOptionalBindingRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4470D5A1EB76F44008A1B2E /* UnusedOptionalBindingRuleTests.swift */; };
|
||||
D4470D5D1EB8004B008A1B2E /* VerticalParameterAlignmentOnCallRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4470D5C1EB8004B008A1B2E /* VerticalParameterAlignmentOnCallRule.swift */; };
|
||||
D4492B9323DD499A004EC27B /* _CSwiftSyntax.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4492B9123DD499A004EC27B /* _CSwiftSyntax.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
D4492B9523DD499A004EC27B /* SwiftSyntax.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4492B9223DD499A004EC27B /* SwiftSyntax.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
D44AD2761C0AA5350048F7B0 /* LegacyConstructorRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44AD2741C0AA3730048F7B0 /* LegacyConstructorRule.swift */; };
|
||||
D450D1D121EC4A6900E60010 /* StrongIBOutletRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D450D1D021EC4A6900E60010 /* StrongIBOutletRule.swift */; };
|
||||
D450D1DD21F199F700E60010 /* TrailingClosureConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D450D1DA21F1992E00E60010 /* TrailingClosureConfiguration.swift */; };
|
||||
|
@ -366,11 +368,14 @@
|
|||
D4DE9133207B4750000FFAA8 /* UnavailableFunctionRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4DE9131207B4731000FFAA8 /* UnavailableFunctionRule.swift */; };
|
||||
D4E2BA851F6CD77B00E8E184 /* ArrayInitRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4E2BA841F6CD77B00E8E184 /* ArrayInitRule.swift */; };
|
||||
D4E4FB5223E7A1A300746FCD /* LineEndingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4E4FB5123E7A1A300746FCD /* LineEndingTests.swift */; };
|
||||
D4E4FB5523E7A6CF00746FCD /* ReturnValueFromVoidFunctionRuleExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4E4FB5323E7A6CF00746FCD /* ReturnValueFromVoidFunctionRuleExamples.swift */; };
|
||||
D4E4FB5623E7A6CF00746FCD /* ReturnValueFromVoidFunctionRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4E4FB5423E7A6CF00746FCD /* ReturnValueFromVoidFunctionRule.swift */; };
|
||||
D4E92D1F2137B4C9002EDD48 /* IdenticalOperandsRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4E92D1E2137B4C9002EDD48 /* IdenticalOperandsRule.swift */; };
|
||||
D4EA77C81F817FD200C315FB /* UnneededBreakInSwitchRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4EA77C71F817FD200C315FB /* UnneededBreakInSwitchRule.swift */; };
|
||||
D4EA77CA1F81FACC00C315FB /* LiteralExpressionEndIdentationRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4EA77C91F81FACC00C315FB /* LiteralExpressionEndIdentationRule.swift */; };
|
||||
D4EAB3A420E9948E0051C09A /* AutomaticRuleTests.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4EAB3A320E9948D0051C09A /* AutomaticRuleTests.generated.swift */; };
|
||||
D4EABD0C22CE6F5B00635667 /* VerticalParameterAlignmentRuleExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4EABD0B22CE6F5B00635667 /* VerticalParameterAlignmentRuleExamples.swift */; };
|
||||
D4EF8EA223E695EA0038C26E /* SyntaxRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4EF8EA123E695EA0038C26E /* SyntaxRule.swift */; };
|
||||
D4F10614229A2F5E00FDE319 /* NoFallthroughOnlyRuleExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4F10613229A2F5E00FDE319 /* NoFallthroughOnlyRuleExamples.swift */; };
|
||||
D4F10616229A331200FDE319 /* LegacyMultipleRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4F10615229A331200FDE319 /* LegacyMultipleRule.swift */; };
|
||||
D4F5851520E99A8A0085C6D8 /* TrailingWhitespaceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4F5851320E99A720085C6D8 /* TrailingWhitespaceTests.swift */; };
|
||||
|
@ -820,6 +825,8 @@
|
|||
D4470D581EB6B4D1008A1B2E /* EmptyEnumArgumentsRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyEnumArgumentsRule.swift; sourceTree = "<group>"; };
|
||||
D4470D5A1EB76F44008A1B2E /* UnusedOptionalBindingRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnusedOptionalBindingRuleTests.swift; sourceTree = "<group>"; };
|
||||
D4470D5C1EB8004B008A1B2E /* VerticalParameterAlignmentOnCallRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerticalParameterAlignmentOnCallRule.swift; sourceTree = "<group>"; };
|
||||
D4492B9123DD499A004EC27B /* _CSwiftSyntax.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = _CSwiftSyntax.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D4492B9223DD499A004EC27B /* SwiftSyntax.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SwiftSyntax.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D44AD2741C0AA3730048F7B0 /* LegacyConstructorRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyConstructorRule.swift; sourceTree = "<group>"; };
|
||||
D450D1D021EC4A6900E60010 /* StrongIBOutletRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StrongIBOutletRule.swift; sourceTree = "<group>"; };
|
||||
D450D1DA21F1992E00E60010 /* TrailingClosureConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrailingClosureConfiguration.swift; sourceTree = "<group>"; };
|
||||
|
@ -892,11 +899,14 @@
|
|||
D4DE9131207B4731000FFAA8 /* UnavailableFunctionRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnavailableFunctionRule.swift; sourceTree = "<group>"; };
|
||||
D4E2BA841F6CD77B00E8E184 /* ArrayInitRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayInitRule.swift; sourceTree = "<group>"; };
|
||||
D4E4FB5123E7A1A300746FCD /* LineEndingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineEndingTests.swift; sourceTree = "<group>"; };
|
||||
D4E4FB5323E7A6CF00746FCD /* ReturnValueFromVoidFunctionRuleExamples.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReturnValueFromVoidFunctionRuleExamples.swift; sourceTree = "<group>"; };
|
||||
D4E4FB5423E7A6CF00746FCD /* ReturnValueFromVoidFunctionRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReturnValueFromVoidFunctionRule.swift; sourceTree = "<group>"; };
|
||||
D4E92D1E2137B4C9002EDD48 /* IdenticalOperandsRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdenticalOperandsRule.swift; sourceTree = "<group>"; };
|
||||
D4EA77C71F817FD200C315FB /* UnneededBreakInSwitchRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnneededBreakInSwitchRule.swift; sourceTree = "<group>"; };
|
||||
D4EA77C91F81FACC00C315FB /* LiteralExpressionEndIdentationRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiteralExpressionEndIdentationRule.swift; sourceTree = "<group>"; };
|
||||
D4EAB3A320E9948D0051C09A /* AutomaticRuleTests.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutomaticRuleTests.generated.swift; sourceTree = "<group>"; };
|
||||
D4EABD0B22CE6F5B00635667 /* VerticalParameterAlignmentRuleExamples.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerticalParameterAlignmentRuleExamples.swift; sourceTree = "<group>"; };
|
||||
D4EF8EA123E695EA0038C26E /* SyntaxRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyntaxRule.swift; sourceTree = "<group>"; };
|
||||
D4F10613229A2F5E00FDE319 /* NoFallthroughOnlyRuleExamples.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoFallthroughOnlyRuleExamples.swift; sourceTree = "<group>"; };
|
||||
D4F10615229A331200FDE319 /* LegacyMultipleRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyMultipleRule.swift; sourceTree = "<group>"; };
|
||||
D4F5851320E99A720085C6D8 /* TrailingWhitespaceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrailingWhitespaceTests.swift; sourceTree = "<group>"; };
|
||||
|
@ -998,8 +1008,10 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E876BFBE1B07828500114ED5 /* SourceKittenFramework.framework in Frameworks */,
|
||||
D4492B9323DD499A004EC27B /* _CSwiftSyntax.framework in Frameworks */,
|
||||
E8C0DFCD1AD349DB007EE3D4 /* SWXMLHash.framework in Frameworks */,
|
||||
3BBF2F9D1C640A0F006CD775 /* SwiftyTextTable.framework in Frameworks */,
|
||||
D4492B9523DD499A004EC27B /* SwiftSyntax.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1356,6 +1368,8 @@
|
|||
D41E7E0A1DF9DABB0065259A /* RedundantStringEnumValueRule.swift */,
|
||||
6208ED4E20C297AC004E78D1 /* RedundantTypeAnnotationRule.swift */,
|
||||
D4B022B11E10B613007E5297 /* RedundantVoidReturnRule.swift */,
|
||||
D4E4FB5423E7A6CF00746FCD /* ReturnValueFromVoidFunctionRule.swift */,
|
||||
D4E4FB5323E7A6CF00746FCD /* ReturnValueFromVoidFunctionRuleExamples.swift */,
|
||||
D4D383842145F550000235BD /* StaticOperatorRule.swift */,
|
||||
D42B45D81F0AF5E30086B683 /* StrictFilePrivateRule.swift */,
|
||||
D44254251DB9C12300492EA4 /* SyntacticSugarRule.swift */,
|
||||
|
@ -1391,6 +1405,7 @@
|
|||
D0D1211A19E87861005E4BAA /* swiftlint */,
|
||||
D0D1216E19E87B05005E4BAA /* SwiftLintFramework */,
|
||||
D0D1217B19E87B05005E4BAA /* SwiftLintFrameworkTests */,
|
||||
D4492B9023DD499A004EC27B /* Frameworks */,
|
||||
);
|
||||
indentWidth = 4;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1615,6 +1630,15 @@
|
|||
path = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D4492B9023DD499A004EC27B /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D4492B9123DD499A004EC27B /* _CSwiftSyntax.framework */,
|
||||
D4492B9223DD499A004EC27B /* SwiftSyntax.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E802ECFE1C56A54600A35AE1 /* Helpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1674,6 +1698,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
E88DEA8B1B0999A000A66CB0 /* ASTRule.swift */,
|
||||
D4EF8EA123E695EA0038C26E /* SyntaxRule.swift */,
|
||||
E80746F51ECB722F00548D31 /* CacheDescriptionProvider.swift */,
|
||||
A73469401FB12149009B57C7 /* CallPairRule.swift */,
|
||||
E86396C11BADAAE5002C9E88 /* Reporter.swift */,
|
||||
|
@ -2062,6 +2087,7 @@
|
|||
62A3E95D209E084000547A86 /* EmptyXCTestMethodRule.swift in Sources */,
|
||||
D4C4A34C1DEA4FF000E0E04C /* AttributesConfiguration.swift in Sources */,
|
||||
29FC197A21382C07006D208C /* DuplicateImportsRuleExamples.swift in Sources */,
|
||||
D4E4FB5623E7A6CF00746FCD /* ReturnValueFromVoidFunctionRule.swift in Sources */,
|
||||
83D71E281B131ECE000395DE /* RuleDescription.swift in Sources */,
|
||||
D4470D571EB69225008A1B2E /* ImplicitReturnRule.swift in Sources */,
|
||||
8FE3CCBC22DBF8D000B8EA87 /* UnusedDeclarationConfiguration.swift in Sources */,
|
||||
|
@ -2077,6 +2103,7 @@
|
|||
D4C4A3521DEFBBB700E0E04C /* FileHeaderConfiguration.swift in Sources */,
|
||||
623675B01F960C5C009BE6F3 /* QuickDiscouragedPendingTestRule.swift in Sources */,
|
||||
287F8B642230843000BDC504 /* NSLocalizedStringRequireBundleRule.swift in Sources */,
|
||||
D4EF8EA223E695EA0038C26E /* SyntaxRule.swift in Sources */,
|
||||
D47079AD1DFE2FA700027086 /* EmptyParametersRule.swift in Sources */,
|
||||
E87E4A091BFB9CAE00FCFE46 /* SyntaxKind+SwiftLint.swift in Sources */,
|
||||
3B0B14541C505D6300BE82F7 /* SeverityConfiguration.swift in Sources */,
|
||||
|
@ -2322,6 +2349,7 @@
|
|||
C946FECB1EAE67EE007DD778 /* LetVarWhitespaceRule.swift in Sources */,
|
||||
E881985D1BEA97EB00333A11 /* TrailingWhitespaceRule.swift in Sources */,
|
||||
E832F10B1B17E2F5003F265F /* FileManager+SwiftLint.swift in Sources */,
|
||||
D4E4FB5523E7A6CF00746FCD /* ReturnValueFromVoidFunctionRuleExamples.swift in Sources */,
|
||||
E816194C1BFBF35D00946723 /* SwiftDeclarationKind+SwiftLint.swift in Sources */,
|
||||
D4DABFD71E2C23B1009617B6 /* NotificationCenterDetachmentRule.swift in Sources */,
|
||||
3BA79C9B1C4767910057E705 /* NSRange+SwiftLint.swift in Sources */,
|
||||
|
@ -2480,7 +2508,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D0D1212619E878CC005E4BAA /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
|
@ -2489,7 +2517,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D0D1212819E878CC005E4BAA /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Release;
|
||||
|
@ -2566,7 +2594,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D0D1212719E878CC005E4BAA /* Profile.xcconfig */;
|
||||
buildSettings = {
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Profile;
|
||||
|
@ -2609,7 +2637,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D0D1212919E878CC005E4BAA /* Test.xcconfig */;
|
||||
buildSettings = {
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Test;
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
<FileRef
|
||||
location = "group:Carthage/Checkouts/SwiftyTextTable/SwiftyTextTable.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:SwiftSyntax/SwiftSyntax.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Carthage/Checkouts/Yams/Yams.xcodeproj">
|
||||
</FileRef>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 3e3eb191fcdbecc6031522660c4ed6ce25282c25
|
|
@ -1260,6 +1260,12 @@ extension ReturnArrowWhitespaceRuleTests {
|
|||
]
|
||||
}
|
||||
|
||||
extension ReturnValueFromVoidFunctionRuleTests {
|
||||
static var allTests: [(String, (ReturnValueFromVoidFunctionRuleTests) -> () throws -> Void)] = [
|
||||
("testWithDefaultConfiguration", testWithDefaultConfiguration)
|
||||
]
|
||||
}
|
||||
|
||||
extension RuleConfigurationTests {
|
||||
static var allTests: [(String, (RuleConfigurationTests) -> () throws -> Void)] = [
|
||||
("testNameConfigurationSetsCorrectly", testNameConfigurationSetsCorrectly),
|
||||
|
@ -1816,6 +1822,7 @@ XCTMain([
|
|||
testCase(RequiredDeinitRuleTests.allTests),
|
||||
testCase(RequiredEnumCaseRuleTestCase.allTests),
|
||||
testCase(ReturnArrowWhitespaceRuleTests.allTests),
|
||||
testCase(ReturnValueFromVoidFunctionRuleTests.allTests),
|
||||
testCase(RuleConfigurationTests.allTests),
|
||||
testCase(RuleTests.allTests),
|
||||
testCase(RulesTests.allTests),
|
||||
|
|
|
@ -648,6 +648,12 @@ class ReturnArrowWhitespaceRuleTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
class ReturnValueFromVoidFunctionRuleTests: XCTestCase {
|
||||
func testWithDefaultConfiguration() {
|
||||
verifyRule(ReturnValueFromVoidFunctionRule.description)
|
||||
}
|
||||
}
|
||||
|
||||
class ShorthandOperatorRuleTests: XCTestCase {
|
||||
func testWithDefaultConfiguration() {
|
||||
verifyRule(ShorthandOperatorRule.description)
|
||||
|
|
|
@ -88,7 +88,8 @@ extension ConfigurationTests {
|
|||
let mergedConfiguration = projectMockConfig0CustomRules.merge(with: projectMockConfig2CustomRules)
|
||||
guard let mergedCustomRules = mergedConfiguration.rules.first(where: { $0 is CustomRules }) as? CustomRules
|
||||
else {
|
||||
return XCTFail("Custom rule are expected to be present")
|
||||
XCTFail("Custom rule are expected to be present")
|
||||
return
|
||||
}
|
||||
XCTAssertTrue(
|
||||
mergedCustomRules.configuration.customRuleConfigurations.contains(where: { $0.identifier == "no_abc" })
|
||||
|
@ -102,7 +103,8 @@ extension ConfigurationTests {
|
|||
let mergedConfiguration = projectMockConfig0CustomRules.merge(with: projectMockConfig2CustomRulesDisabled)
|
||||
guard let mergedCustomRules = mergedConfiguration.rules.first(where: { $0 is CustomRules }) as? CustomRules
|
||||
else {
|
||||
return XCTFail("Custom rule are expected to be present")
|
||||
XCTFail("Custom rule are expected to be present")
|
||||
return
|
||||
}
|
||||
XCTAssertFalse(
|
||||
mergedCustomRules.configuration.customRuleConfigurations.contains(where: { $0.identifier == "no_abc" })
|
||||
|
|
|
@ -23,15 +23,11 @@ jobs:
|
|||
strategy:
|
||||
maxParallel: 10
|
||||
matrix:
|
||||
xcode102:
|
||||
DEVELOPER_DIR: /Applications/Xcode_10.2.app
|
||||
xcode103:
|
||||
DEVELOPER_DIR: /Applications/Xcode_10.3.app
|
||||
xcode111:
|
||||
DEVELOPER_DIR: /Applications/Xcode_11.1.app
|
||||
steps:
|
||||
- script: git submodule update --init --recursive
|
||||
displayName: Update git submodules
|
||||
- script: Script/bootstrap
|
||||
displayName: Bootstrap
|
||||
- script: |
|
||||
sw_vers
|
||||
xcodebuild -version
|
||||
|
|
|
@ -21,6 +21,8 @@ main ()
|
|||
echo "*** Updating submodules..."
|
||||
update_submodules
|
||||
fi
|
||||
|
||||
cd "SwiftSyntax" && swift package generate-xcodeproj
|
||||
}
|
||||
|
||||
bootstrap_submodule ()
|
||||
|
|
Loading…
Reference in New Issue