diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fbff96b2f..2671da56a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,14 @@ ##### Breaking -* None. +* Remove support for Swift 2. + [Marcelo Fabri](https://github.com/marcelofabri) + [#1387](https://github.com/realm/SwiftLint/issues/1453) + +* Remove `missing_docs` and `valid_docs` rules since + they were already disabled. + [Marcelo Fabri](https://github.com/marcelofabri) + [#1387](https://github.com/realm/SwiftLint/issues/1453) ##### Enhancements diff --git a/Makefile b/Makefile index c8088aaab6..5c0e5aa0a1 100644 --- a/Makefile +++ b/Makefile @@ -7,11 +7,6 @@ XCODEFLAGS=-workspace 'SwiftLint.xcworkspace' \ DSTROOT=$(TEMPORARY_FOLDER) \ OTHER_LDFLAGS=-Wl,-headerpad_max_install_names -SWIFT_2_XCODEFLAGS=-workspace 'SwiftLint.xcworkspace' \ - -scheme 'swiftlint with Swift 2.3' \ - DSTROOT=$(TEMPORARY_FOLDER) \ - OTHER_LDFLAGS=-Wl,-headerpad_max_install_names - BUILT_BUNDLE=$(TEMPORARY_FOLDER)/Applications/swiftlint.app SWIFTLINTFRAMEWORK_BUNDLE=$(BUILT_BUNDLE)/Contents/Frameworks/SwiftLintFramework.framework SWIFTLINT_EXECUTABLE=$(BUILT_BUNDLE)/Contents/MacOS/swiftlint @@ -42,7 +37,6 @@ bootstrap: script/bootstrap test: clean bootstrap - $(BUILD_TOOL) $(SWIFT_2_XCODEFLAGS) test $(BUILD_TOOL) $(XCODEFLAGS) test clean: @@ -51,9 +45,6 @@ clean: $(BUILD_TOOL) $(XCODEFLAGS) -configuration Debug clean $(BUILD_TOOL) $(XCODEFLAGS) -configuration Release clean $(BUILD_TOOL) $(XCODEFLAGS) -configuration Test clean - $(BUILD_TOOL) $(SWIFT_2_XCODEFLAGS) -configuration Debug clean - $(BUILD_TOOL) $(SWIFT_2_XCODEFLAGS) -configuration Release clean - $(BUILD_TOOL) $(SWIFT_2_XCODEFLAGS) -configuration Test clean install: uninstall package sudo installer -pkg SwiftLint.pkg -target / diff --git a/README.md b/README.md index 534e53ca65..94ec9ddf7e 100644 --- a/README.md +++ b/README.md @@ -144,8 +144,7 @@ You should always run SwiftLint with the same toolchain you use to compile your code. You may want to override SwiftLint's default Swift toolchain if you have -multiple toolchains or Xcodes installed, or if you're using legacy Swift -versions (e.g. Swift 2.3 with Xcode 8). +multiple toolchains or Xcodes installed. Here's the order in which SwiftLint determines which Swift toolchain to use: @@ -188,7 +187,7 @@ Guidelines on when to implement a rule as opt-in: * A rule that can have many false positives (e.g. `empty_count`) * A rule that is too slow * A rule that is not general consensus or is only useful in some cases - (e.g. `force_unwrapping`, `missing_docs`) + (e.g. `force_unwrapping`) ### Disable rules in code @@ -249,7 +248,6 @@ disabled_rules: # rule identifiers to exclude from running - control_statement opt_in_rules: # some rules are only opt-in - empty_count - - missing_docs # Find all the available rules by running: # swiftlint rules included: # paths to include during linting. `--path` is ignored if present. diff --git a/Source/SwiftLintFramework/Extensions/AccessControlLevel.swift b/Source/SwiftLintFramework/Extensions/AccessControlLevel.swift new file mode 100644 index 0000000000..1bfe50c145 --- /dev/null +++ b/Source/SwiftLintFramework/Extensions/AccessControlLevel.swift @@ -0,0 +1,48 @@ +// +// AccessControlLevel.swift +// SwiftLint +// +// Created by Marcelo Fabri on 23/04/17. +// Copyright © 2017 Realm. All rights reserved. +// + +import Foundation + +public enum AccessControlLevel: String, CustomStringConvertible { + case `private` = "source.lang.swift.accessibility.private" + case `fileprivate` = "source.lang.swift.accessibility.fileprivate" + case `internal` = "source.lang.swift.accessibility.internal" + case `public` = "source.lang.swift.accessibility.public" + case `open` = "source.lang.swift.accessibility.open" + + internal init?(description value: String) { + switch value { + case "private": self = .private + case "fileprivate": self = .fileprivate + case "internal": self = .internal + case "public": self = .public + case "open": self = .open + default: return nil + } + } + + init?(identifier value: String) { + self.init(rawValue: value) + } + + public var description: String { + switch self { + case .private: return "private" + case .fileprivate: return "fileprivate" + case .internal: return "internal" + case .public: return "public" + case .open: return "open" + } + } + + // Returns true if is `private` or `fileprivate` + var isPrivate: Bool { + return self == .private || self == .fileprivate + } + +} diff --git a/Source/SwiftLintFramework/Extensions/Dictionary+SwiftLint.swift b/Source/SwiftLintFramework/Extensions/Dictionary+SwiftLint.swift index 298a3ed502..597dd45742 100644 --- a/Source/SwiftLintFramework/Extensions/Dictionary+SwiftLint.swift +++ b/Source/SwiftLintFramework/Extensions/Dictionary+SwiftLint.swift @@ -94,16 +94,7 @@ extension Dictionary where Key: ExpressibleByStringLiteral { } if SwiftDeclarationKind(rawValue: kindString) == .varParameter { - switch SwiftVersion.current { - case .two, .twoPointThree: - // with Swift 2.3, a closure parameter is inside another .varParameter and not inside an .argument - let parameters = subDict.enclosedVarParameters + [subDict] - return parameters.filter { - $0.typeName != nil - } - case .three: - return [subDict] - } + return [subDict] } else if SwiftExpressionKind(rawValue: kindString) == .argument { return subDict.enclosedVarParameters } @@ -114,19 +105,9 @@ extension Dictionary where Key: ExpressibleByStringLiteral { var enclosedArguments: [[String: SourceKitRepresentable]] { return substructure.flatMap { subDict -> [[String: SourceKitRepresentable]] in - guard let kindString = subDict.kind else { - return [] - } - - switch SwiftVersion.current { - case .two, .twoPointThree: - guard SwiftDeclarationKind(rawValue: kindString) == .varParameter else { - return [] - } - case .three: - guard SwiftExpressionKind(rawValue: kindString) == .argument else { + guard let kindString = subDict.kind, + SwiftExpressionKind(rawValue: kindString) == .argument else { return [] - } } return [subDict] diff --git a/Source/SwiftLintFramework/Models/MasterRuleList.swift b/Source/SwiftLintFramework/Models/MasterRuleList.swift index 882d0fb0df..ef3c082cac 100644 --- a/Source/SwiftLintFramework/Models/MasterRuleList.swift +++ b/Source/SwiftLintFramework/Models/MasterRuleList.swift @@ -116,7 +116,6 @@ public let masterRuleList = RuleList(rules: LegacyNSGeometryFunctionsRule.self, LineLengthRule.self, MarkRule.self, - MissingDocsRule.self, NestingRule.self, NimbleOperatorRule.self, NotificationCenterDetachmentRule.self, @@ -150,7 +149,6 @@ public let masterRuleList = RuleList(rules: UnusedClosureParameterRule.self, UnusedEnumeratedRule.self, UnusedOptionalBindingRule.self, - ValidDocsRule.self, ValidIBInspectableRule.self, VerticalParameterAlignmentRule.self, VerticalWhitespaceRule.self, diff --git a/Source/SwiftLintFramework/Models/SwiftVersion.swift b/Source/SwiftLintFramework/Models/SwiftVersion.swift index 443297933a..24bda60f2c 100644 --- a/Source/SwiftLintFramework/Models/SwiftVersion.swift +++ b/Source/SwiftLintFramework/Models/SwiftVersion.swift @@ -7,34 +7,18 @@ // import Foundation -import SourceKittenFramework enum SwiftVersion { - case two - case twoPointThree case three static let current: SwiftVersion = { // Allow forcing the Swift version, useful in cases where SourceKit isn't available if let envVersion = ProcessInfo.processInfo.environment["SWIFTLINT_SWIFT_VERSION"] { switch envVersion { - case "2": return .two - case "2.3": return .twoPointThree default: return .three } } - let file = File(contents: "#sourceLocation()") - let kinds = file.syntaxMap.tokens.flatMap { SyntaxKind(rawValue: $0.type) } - if kinds == [.identifier] { - let docStructureDescription = File(contents: "/// A\nclass A {}").structure.description - if docStructureDescription.contains("source.decl.attribute.__raw_doc_comment") { - return .two - } - return .twoPointThree - } else if kinds == [.keyword] { - return .three - } - fatalError("Unexpected Swift version") + return .three }() } diff --git a/Source/SwiftLintFramework/Rules/AttributesRule.swift b/Source/SwiftLintFramework/Rules/AttributesRule.swift index 818c6de896..1613643d2e 100644 --- a/Source/SwiftLintFramework/Rules/AttributesRule.swift +++ b/Source/SwiftLintFramework/Rules/AttributesRule.swift @@ -27,8 +27,8 @@ public struct AttributesRule: ASTRule, OptInRule, ConfigurationProviderRule { name: "Attributes", description: "Attributes should be on their own lines in functions and types, " + "but on the same line as variables and imports.", - nonTriggeringExamples: AttributesRuleExamples.swift3NonTriggeringExamples, - triggeringExamples: AttributesRuleExamples.swift3TriggeringExamples + nonTriggeringExamples: AttributesRuleExamples.nonTriggeringExamples, + triggeringExamples: AttributesRuleExamples.triggeringExamples ) public func validate(file: File) -> [StyleViolation] { diff --git a/Source/SwiftLintFramework/Rules/AttributesRulesExamples.swift b/Source/SwiftLintFramework/Rules/AttributesRulesExamples.swift index 2fba66aba4..f7f4f19932 100644 --- a/Source/SwiftLintFramework/Rules/AttributesRulesExamples.swift +++ b/Source/SwiftLintFramework/Rules/AttributesRulesExamples.swift @@ -8,7 +8,7 @@ internal struct AttributesRuleExamples { - private static let commonNonTriggeringExamples = [ + static let nonTriggeringExamples = [ "@objc var x: String", "@objc private var x: String", "@nonobjc var x: String", @@ -39,10 +39,7 @@ internal struct AttributesRuleExamples { // attribute with allowed empty new line above "extension Property {\n\n @available(*, unavailable, renamed: \"isOptional\")\n" + - "public var optional: Bool { fatalError() }\n}" - ] - - static let swift3NonTriggeringExamples = commonNonTriggeringExamples + [ + "public var optional: Bool { fatalError() }\n}", "@GKInspectable var maxSpeed: Float", "@discardableResult\n func a() -> Int", "@objc\n @discardableResult\n func a() -> Int", @@ -50,16 +47,7 @@ internal struct AttributesRuleExamples { "func foo(completionHandler: @escaping () -> Void)" ] - static let swift2NonTriggeringExamples = commonNonTriggeringExamples + [ - "@warn_unused_result\n func a() -> Int", - "@objc\n @warn_unused_result\n func a() -> Int", - "func increase(@autoclosure f: () -> Int ) -> Int", - "func foo(@noescape x: Int -> Int)", - "@noreturn\n func exit(_: Int)", - "func exit(_: Int) -> @noreturn Int" - ] - - static let commonTriggeringExamples = [ + static let triggeringExamples = [ "@objc\n ↓var x: String", "@objc\n\n ↓var x: String", "@objc\n private ↓var x: String", @@ -87,21 +75,10 @@ internal struct AttributesRuleExamples { "@available(iOS 9.0, *) @objc(abc_stackView)\n ↓let stackView: UIStackView", "@objc(abc_addSomeObject:) @NSManaged\n ↓func addSomeObject(book: SomeObject)", "@objc(abc_addSomeObject:)\n @NSManaged\n ↓func addSomeObject(book: SomeObject)", - "@available(iOS 9.0, *)\n @objc(ABCThing) ↓class Thing" - ] - - static let swift3TriggeringExamples = commonTriggeringExamples + [ + "@available(iOS 9.0, *)\n @objc(ABCThing) ↓class Thing", "@GKInspectable\n ↓var maxSpeed: Float", "@discardableResult ↓func a() -> Int", "@objc\n @discardableResult ↓func a() -> Int", "@objc\n\n @discardableResult\n ↓func a() -> Int" ] - - static let swift2TriggeringExamples = commonTriggeringExamples + [ - "@warn_unused_result ↓func a() -> Int", - "@warn_unused_result(message=\"You should use this\") ↓func a() -> Int", - "@objc\n @warn_unused_result ↓func a() -> Int", - "@objc\n\n @warn_unused_result\n ↓func a() -> Int", - "@noreturn ↓func exit(_: Int)" - ] } diff --git a/Source/SwiftLintFramework/Rules/ExplicitTypeInterfaceRule.swift b/Source/SwiftLintFramework/Rules/ExplicitTypeInterfaceRule.swift index 9393810909..b880d01afe 100644 --- a/Source/SwiftLintFramework/Rules/ExplicitTypeInterfaceRule.swift +++ b/Source/SwiftLintFramework/Rules/ExplicitTypeInterfaceRule.swift @@ -52,16 +52,6 @@ public struct ExplicitTypeInterfaceRule: ASTRule, OptInRule, ConfigurationProvid } private func containsType(dictionary: [String: SourceKitRepresentable]) -> Bool { - if let typeName = dictionary.typeName { - switch SwiftVersion.current { - // on Swift 2.x, `key.typename` returns the `key.name` if there's no explicit type - case .two, .twoPointThree: - return typeName != dictionary.name - case .three: - return true - } - } - - return false + return dictionary.typeName != nil } } diff --git a/Source/SwiftLintFramework/Rules/IdentifierNameRule.swift b/Source/SwiftLintFramework/Rules/IdentifierNameRule.swift index 65c86e207c..cde0c0dab5 100644 --- a/Source/SwiftLintFramework/Rules/IdentifierNameRule.swift +++ b/Source/SwiftLintFramework/Rules/IdentifierNameRule.swift @@ -26,8 +26,8 @@ public struct IdentifierNameRule: ASTRule, ConfigurationProviderRule { "In an exception to the above, variable names may start with a capital letter " + "when they are declared static and immutable. Variable names should not be too " + "long or too short.", - nonTriggeringExamples: IdentifierNameRuleExamples.swift3NonTriggeringExamples, - triggeringExamples: IdentifierNameRuleExamples.swift3TriggeringExamples, + nonTriggeringExamples: IdentifierNameRuleExamples.nonTriggeringExamples, + triggeringExamples: IdentifierNameRuleExamples.triggeringExamples, deprecatedAliases: ["variable_name"] ) @@ -88,7 +88,7 @@ public struct IdentifierNameRule: ASTRule, ConfigurationProviderRule { kind: SwiftDeclarationKind) -> (name: String, offset: Int)? { guard let name = dictionary.name, let offset = dictionary.offset, - kinds(for: .current).contains(kind), + kinds.contains(kind), !name.hasPrefix("$") else { return nil } @@ -96,15 +96,9 @@ public struct IdentifierNameRule: ASTRule, ConfigurationProviderRule { return (name.nameStrippingLeadingUnderscoreIfPrivate(dictionary), offset) } - private func kinds(for version: SwiftVersion) -> [SwiftDeclarationKind] { - let common = SwiftDeclarationKind.variableKinds() + SwiftDeclarationKind.functionKinds() - switch version { - case .two, .twoPointThree: - return common - case .three: - return common + [.enumelement] - } - } + private let kinds: [SwiftDeclarationKind] = { + return SwiftDeclarationKind.variableKinds() + SwiftDeclarationKind.functionKinds() + [.enumelement] + }() private func type(for kind: SwiftDeclarationKind) -> String { if SwiftDeclarationKind.functionKinds().contains(kind) { diff --git a/Source/SwiftLintFramework/Rules/IdentifierNameRuleExamples.swift b/Source/SwiftLintFramework/Rules/IdentifierNameRuleExamples.swift index 1e31479cb7..5ec0c32183 100644 --- a/Source/SwiftLintFramework/Rules/IdentifierNameRuleExamples.swift +++ b/Source/SwiftLintFramework/Rules/IdentifierNameRuleExamples.swift @@ -9,7 +9,7 @@ import Foundation internal struct IdentifierNameRuleExamples { - private static let commonNonTriggeringExamples = [ + static let nonTriggeringExamples = [ "let myLet = 0", "var myVar = 0", "private let _myLet = 0", @@ -24,13 +24,7 @@ internal struct IdentifierNameRuleExamples { "override func IsOperator(name: String) -> Bool" ] - static let swift2NonTriggeringExamples = commonNonTriggeringExamples + [ - "enum Foo { case MyEnum }" - ] - - static let swift3NonTriggeringExamples = commonNonTriggeringExamples - - private static let commonTriggeringExamples = [ + static let triggeringExamples = [ "↓let MyLet = 0", "↓let _myLet = 0", "private ↓let myLet_ = 0", @@ -40,12 +34,7 @@ internal struct IdentifierNameRuleExamples { "↓let i = 0", "↓var id = 0", "private ↓let _i = 0", - "↓func IsOperator(name: String) -> Bool" - ] - - static let swift2TriggeringExamples = commonTriggeringExamples - - static let swift3TriggeringExamples = commonTriggeringExamples + [ + "↓func IsOperator(name: String) -> Bool", "enum Foo { case ↓MyEnum }" ] } diff --git a/Source/SwiftLintFramework/Rules/LegacyConstantRule.swift b/Source/SwiftLintFramework/Rules/LegacyConstantRule.swift index 5a88538841..f78146afb2 100644 --- a/Source/SwiftLintFramework/Rules/LegacyConstantRule.swift +++ b/Source/SwiftLintFramework/Rules/LegacyConstantRule.swift @@ -15,43 +15,20 @@ public struct LegacyConstantRule: CorrectableRule, ConfigurationProviderRule { public init() {} - public static let description: RuleDescription = { - let nonTriggeringExamples: [String] - let triggeringExampes: [String] - let corrections: [String: String] - switch SwiftVersion.current { - case .two, .twoPointThree: - nonTriggeringExamples = LegacyConstantRuleExamples.swift2NonTriggeringExamples - triggeringExampes = LegacyConstantRuleExamples.swift2TriggeringExamples - corrections = LegacyConstantRuleExamples.swift2Corrections - case .three: - nonTriggeringExamples = LegacyConstantRuleExamples.swift3NonTriggeringExamples - triggeringExampes = LegacyConstantRuleExamples.swift3TriggeringExamples - corrections = LegacyConstantRuleExamples.swift3Corrections - } - - return RuleDescription( - identifier: "legacy_constant", - name: "Legacy Constant", - description: "Struct-scoped constants are preferred over legacy global constants.", - nonTriggeringExamples: nonTriggeringExamples, - triggeringExamples: triggeringExampes, - corrections: corrections - ) - }() + public static let description = RuleDescription( + identifier: "legacy_constant", + name: "Legacy Constant", + description: "Struct-scoped constants are preferred over legacy global constants.", + nonTriggeringExamples: LegacyConstantRuleExamples.nonTriggeringExamples, + triggeringExamples: LegacyConstantRuleExamples.triggeringExamples, + corrections: LegacyConstantRuleExamples.corrections + ) private static let legacyConstants: [String] = { return Array(LegacyConstantRule.legacyPatterns.keys) }() - private static let legacyPatterns: [String: String] = { - switch SwiftVersion.current { - case .two, .twoPointThree: - return LegacyConstantRuleExamples.swift2Patterns - case .three: - return LegacyConstantRuleExamples.swift3Patterns - } - }() + private static let legacyPatterns = LegacyConstantRuleExamples.patterns public func validate(file: File) -> [StyleViolation] { let pattern = "\\b" + LegacyConstantRule.legacyConstants.joined(separator: "|") diff --git a/Source/SwiftLintFramework/Rules/LegacyConstantRuleExamples.swift b/Source/SwiftLintFramework/Rules/LegacyConstantRuleExamples.swift index bf10511521..6a4f8118ee 100644 --- a/Source/SwiftLintFramework/Rules/LegacyConstantRuleExamples.swift +++ b/Source/SwiftLintFramework/Rules/LegacyConstantRuleExamples.swift @@ -10,38 +10,7 @@ import Foundation internal struct LegacyConstantRuleExamples { - static let swift2NonTriggeringExamples = commonNonTriggeringExamples - - static let swift3NonTriggeringExamples = commonNonTriggeringExamples + ["CGFloat.pi", "Float.pi"] - - static let swift2TriggeringExamples = commonTriggeringExamples - - static let swift3TriggeringExamples = commonTriggeringExamples + ["↓CGFloat(M_PI)", "↓Float(M_PI)"] - - static let swift2Corrections = commonCorrections - - static let swift3Corrections: [String: String] = { - var corrections = commonCorrections - ["↓CGFloat(M_PI)": "CGFloat.pi", - "↓Float(M_PI)": "Float.pi", - "↓CGFloat(M_PI)\n↓Float(M_PI)\n": "CGFloat.pi\nFloat.pi\n"].forEach { key, value in - corrections[key] = value - } - return corrections - }() - - static let swift2Patterns = commonPatterns - - static let swift3Patterns: [String: String] = { - var patterns = commonPatterns - ["CGFloat\\(M_PI\\)": "CGFloat.pi", - "Float\\(M_PI\\)": "Float.pi"].forEach { key, value in - patterns[key] = value - } - return patterns - }() - - private static let commonNonTriggeringExamples = [ + static let nonTriggeringExamples = [ "CGRect.infinite", "CGPoint.zero", "CGRect.zero", @@ -49,10 +18,12 @@ internal struct LegacyConstantRuleExamples { "NSPoint.zero", "NSRect.zero", "NSSize.zero", - "CGRect.null" + "CGRect.null", + "CGFloat.pi", + "Float.pi" ] - private static let commonTriggeringExamples = [ + static let triggeringExamples = [ "↓CGRectInfinite", "↓CGPointZero", "↓CGRectZero", @@ -60,10 +31,12 @@ internal struct LegacyConstantRuleExamples { "↓NSZeroPoint", "↓NSZeroRect", "↓NSZeroSize", - "↓CGRectNull" + "↓CGRectNull", + "↓CGFloat(M_PI)", + "↓Float(M_PI)" ] - private static let commonCorrections = [ + static let corrections = [ "↓CGRectInfinite": "CGRect.infinite", "↓CGPointZero": "CGPoint.zero", "↓CGRectZero": "CGRect.zero", @@ -72,10 +45,13 @@ internal struct LegacyConstantRuleExamples { "↓NSZeroRect": "NSRect.zero", "↓NSZeroSize": "NSSize.zero", "↓CGRectNull": "CGRect.null", - "↓CGRectInfinite\n↓CGRectNull\n": "CGRect.infinite\nCGRect.null\n" + "↓CGRectInfinite\n↓CGRectNull\n": "CGRect.infinite\nCGRect.null\n", + "↓CGFloat(M_PI)": "CGFloat.pi", + "↓Float(M_PI)": "Float.pi", + "↓CGFloat(M_PI)\n↓Float(M_PI)\n": "CGFloat.pi\nFloat.pi\n" ] - private static let commonPatterns = [ + static let patterns = [ "CGRectInfinite": "CGRect.infinite", "CGPointZero": "CGPoint.zero", "CGRectZero": "CGRect.zero", @@ -83,7 +59,8 @@ internal struct LegacyConstantRuleExamples { "NSZeroPoint": "NSPoint.zero", "NSZeroRect": "NSRect.zero", "NSZeroSize": "NSSize.zero", - "CGRectNull": "CGRect.null" + "CGRectNull": "CGRect.null", + "CGFloat\\(M_PI\\)": "CGFloat.pi", + "Float\\(M_PI\\)": "Float.pi" ] - } diff --git a/Source/SwiftLintFramework/Rules/MissingDocsRule.swift b/Source/SwiftLintFramework/Rules/MissingDocsRule.swift deleted file mode 100644 index ce96c46296..0000000000 --- a/Source/SwiftLintFramework/Rules/MissingDocsRule.swift +++ /dev/null @@ -1,179 +0,0 @@ -// -// MissingDocsRule.swift -// SwiftLint -// -// Created by JP Simard on 11/15/15. -// Copyright © 2015 Realm. All rights reserved. -// - -import SourceKittenFramework - -private func mappedDictValues(fromDictionary dictionary: [String: SourceKitRepresentable], key: String, - subKey: String) -> [String] { - return (dictionary[key] as? [SourceKitRepresentable])?.flatMap({ - ($0 as? [String: SourceKitRepresentable]) as? [String: String] - }).flatMap({ $0[subKey] }) ?? [] -} - -private func declarationOverrides(in dictionary: [String: SourceKitRepresentable]) -> Bool { - return dictionary.enclosedSwiftAttributes.contains("source.decl.attribute.override") -} - -private func inheritedMembers(for dictionary: [String: SourceKitRepresentable]) -> [String] { - return mappedDictValues(fromDictionary: dictionary, key: "key.inheritedtypes", subKey: "key.name").flatMap { - File.allDeclarationsByType[$0] ?? [] - } -} - -extension File { - fileprivate func missingDocOffsets(in dictionary: [String: SourceKitRepresentable], - acl: [AccessControlLevel], skipping: [String] = []) -> [Int] { - if declarationOverrides(in: dictionary) { - return [] - } - if let name = dictionary.name, skipping.contains(name) { - return [] - } - let inherited = inheritedMembers(for: dictionary) - let substructureOffsets = dictionary.substructure.flatMap { - missingDocOffsets(in: $0, acl: acl, skipping: inherited) - } - guard (dictionary.kind).flatMap(SwiftDeclarationKind.init) != nil, - let offset = dictionary.offset, - let accessibility = dictionary.accessibility, - acl.map({ $0.rawValue }).contains(accessibility) else { - return substructureOffsets - } - if parseDocumentationCommentBody(dictionary, syntaxMap: syntaxMap) != nil { - return substructureOffsets - } - return substructureOffsets + [offset] - } -} - -public enum AccessControlLevel: String, CustomStringConvertible { - case `private` = "source.lang.swift.accessibility.private" - case `fileprivate` = "source.lang.swift.accessibility.fileprivate" - case `internal` = "source.lang.swift.accessibility.internal" - case `public` = "source.lang.swift.accessibility.public" - case `open` = "source.lang.swift.accessibility.open" - - internal init?(description value: String) { - switch value { - case "private": self = .private - case "fileprivate": self = .fileprivate - case "internal": self = .internal - case "public": self = .public - case "open": self = .open - default: return nil - } - } - - init?(identifier value: String) { - self.init(rawValue: value) - } - - public var description: String { - switch self { - case .private: return "private" - case .fileprivate: return "fileprivate" - case .internal: return "internal" - case .public: return "public" - case .open: return "open" - } - } - - // Returns true if is `private` or `fileprivate` - var isPrivate: Bool { - return self == .private || self == .fileprivate - } - -} - -public struct MissingDocsRule: OptInRule { - public init(configuration: Any) throws { - guard let array = [String].array(of: configuration) else { - throw ConfigurationError.unknownConfiguration - } - let acl = array.flatMap(AccessControlLevel.init(description:)) - parameters = zip([.warning, .error], acl).map(RuleParameter.init) - } - - public var configurationDescription: String { - return parameters.map({ - "\($0.severity.rawValue): \($0.value.rawValue)" - }).joined(separator: ", ") - } - - public init() { - parameters = [RuleParameter(severity: .warning, value: .public), - RuleParameter(severity: .warning, value: .open)] - } - - public let parameters: [RuleParameter] - - public static let description = RuleDescription( - identifier: "missing_docs", - name: "Missing Docs", - description: "Public declarations should be documented.", - nonTriggeringExamples: [ - // public, documented using /// docs - "/// docs\npublic func a() {}\n", - // public, documented using /** docs */ - "/** docs */\npublic func a() {}\n", - // internal (implicit), undocumented - "func a() {}\n", - // internal (explicit), undocumented - "internal func a() {}\n", - // private, undocumented - "private func a() {}\n", - // internal (implicit), undocumented - "// regular comment\nfunc a() {}\n", - // internal (implicit), undocumented - "/* regular comment */\nfunc a() {}\n", - // protocol member is documented, but inherited member is not - "/// docs\npublic protocol A {\n/// docs\nvar b: Int { get } }\n" + - "/// docs\npublic struct C: A {\npublic let b: Int\n}", - // locally-defined superclass member is documented, but subclass member is not - "/// docs\npublic class A {\n/// docs\npublic func b() {}\n}\n" + - "/// docs\npublic class B: A { override public func b() {} }\n", - // externally-defined superclass member is documented, but subclass member is not - "import Foundation\n/// docs\npublic class B: NSObject {\n" + - "// no docs\noverride public var description: String { fatalError() } }\n" - ], - triggeringExamples: [ - // public, undocumented - "public func a() {}\n", - // public, undocumented - "// regular comment\npublic func a() {}\n", - // public, undocumented - "/* regular comment */\npublic func a() {}\n", - // protocol member and inherited member are both undocumented - "/// docs\npublic protocol A {\n// no docs\nvar b: Int { get } }\n" + - "/// docs\npublic struct C: A {\n\npublic let b: Int\n}" - ] - ) - - public func validate(file: File) -> [StyleViolation] { - guard SwiftVersion.current == .two else { - warnMissingDocsRuleDisabledOnce - return [] - } - let acl = parameters.map { $0.value } - return file.missingDocOffsets(in: file.structure.dictionary, acl: acl).map { - StyleViolation(ruleDescription: type(of: self).description, - location: Location(file: file, byteOffset: $0)) - } - } - - public func isEqualTo(_ rule: Rule) -> Bool { - if let rule = rule as? MissingDocsRule { - return rule.parameters == parameters - } - return false - } -} - -private let warnMissingDocsRuleDisabledOnce: Void = { - queuedPrintError("Missing Docs rule is disabled in Swift 2.3 and later as it is non functional.") -}() diff --git a/Source/SwiftLintFramework/Rules/NotificationCenterDetachmentRule.swift b/Source/SwiftLintFramework/Rules/NotificationCenterDetachmentRule.swift index 5e02c0a702..fc94a48f0b 100644 --- a/Source/SwiftLintFramework/Rules/NotificationCenterDetachmentRule.swift +++ b/Source/SwiftLintFramework/Rules/NotificationCenterDetachmentRule.swift @@ -18,8 +18,8 @@ public struct NotificationCenterDetachmentRule: ASTRule, ConfigurationProviderRu identifier: "notification_center_detachment", name: "Notification Center Detachment", description: "An object should only remove itself as an observer in `deinit`.", - nonTriggeringExamples: NotificationCenterDetachmentRuleExamples.swift3NonTriggeringExamples, - triggeringExamples: NotificationCenterDetachmentRuleExamples.swift3TriggeringExamples + nonTriggeringExamples: NotificationCenterDetachmentRuleExamples.nonTriggeringExamples, + triggeringExamples: NotificationCenterDetachmentRuleExamples.triggeringExamples ) public func validate(file: File, kind: SwiftDeclarationKind, @@ -59,14 +59,7 @@ public struct NotificationCenterDetachmentRule: ASTRule, ConfigurationProviderRu } } - private var methodName: String = { - switch SwiftVersion.current { - case .two, .twoPointThree: - return "NSNotificationCenter.defaultCenter.removeObserver" - case .three: - return "NotificationCenter.default.removeObserver" - } - }() + private var methodName = "NotificationCenter.default.removeObserver" private func parameterIsSelf(dictionary: [String: SourceKitRepresentable], file: File) -> Bool { guard let bodyOffset = dictionary.bodyOffset, diff --git a/Source/SwiftLintFramework/Rules/NotificationCenterDetachmentRuleExamples.swift b/Source/SwiftLintFramework/Rules/NotificationCenterDetachmentRuleExamples.swift index 9b8500c941..300a0d0dde 100644 --- a/Source/SwiftLintFramework/Rules/NotificationCenterDetachmentRuleExamples.swift +++ b/Source/SwiftLintFramework/Rules/NotificationCenterDetachmentRuleExamples.swift @@ -8,7 +8,7 @@ internal struct NotificationCenterDetachmentRuleExamples { - static let swift3NonTriggeringExamples = [ + static let nonTriggeringExamples = [ "class Foo { \n" + " deinit {\n" + " NotificationCenter.default.removeObserver(self)\n" + @@ -22,34 +22,11 @@ internal struct NotificationCenterDetachmentRuleExamples { "}\n" ] - static let swift2NonTriggeringExamples = [ - "class Foo { \n" + - " deinit {\n" + - " NSNotificationCenter.defaultCenter.removeObserver(self)\n" + - " }\n" + - "}\n", - - "class Foo { \n" + - " func bar() {\n" + - " NSNotificationCenter.defaultCenter.removeObserver(otherObject)\n" + - " }\n" + - "}\n" - ] - - static let swift3TriggeringExamples = [ + static let triggeringExamples = [ "class Foo { \n" + " func bar() {\n" + " ↓NotificationCenter.default.removeObserver(self)\n" + " }\n" + "}\n" ] - - static let swift2TriggeringExamples = [ - "class Foo { \n" + - " func bar() {\n" + - " ↓NSNotificationCenter.defaultCenter.removeObserver(self)\n" + - " }\n" + - "}\n" - ] - } diff --git a/Source/SwiftLintFramework/Rules/NumberSeparatorRule.swift b/Source/SwiftLintFramework/Rules/NumberSeparatorRule.swift index 185bdb829a..78530f17c3 100644 --- a/Source/SwiftLintFramework/Rules/NumberSeparatorRule.swift +++ b/Source/SwiftLintFramework/Rules/NumberSeparatorRule.swift @@ -19,8 +19,8 @@ public struct NumberSeparatorRule: OptInRule, CorrectableRule, ConfigurationProv name: "Number Separator", description: "Underscores should be used as thousand separator in large decimal numbers.", nonTriggeringExamples: NumberSeparatorRuleExamples.nonTriggeringExamples, - triggeringExamples: NumberSeparatorRuleExamples.swift3TriggeringExamples, - corrections: NumberSeparatorRuleExamples.swift3Corrections + triggeringExamples: NumberSeparatorRuleExamples.triggeringExamples, + corrections: NumberSeparatorRuleExamples.corrections ) public func validate(file: File) -> [StyleViolation] { diff --git a/Source/SwiftLintFramework/Rules/NumberSeparatorRuleExamples.swift b/Source/SwiftLintFramework/Rules/NumberSeparatorRuleExamples.swift index e528c6b495..b69df83437 100644 --- a/Source/SwiftLintFramework/Rules/NumberSeparatorRuleExamples.swift +++ b/Source/SwiftLintFramework/Rules/NumberSeparatorRuleExamples.swift @@ -29,15 +29,11 @@ internal struct NumberSeparatorRuleExamples { } }() - static let swift3TriggeringExamples = triggeringExamples(signs: ["↓-", "+↓", "↓"]) + static let triggeringExamples = makeTriggeringExamples(signs: ["↓-", "+↓", "↓"]) - static let swift2TriggeringExamples = triggeringExamples(signs: ["-↓", "+↓", "↓"]) + static let corrections = makeCorrections(signs: [("↓-", "-"), ("+↓", "+"), ("↓", "")]) - static let swift3Corrections = corrections(signs: [("↓-", "-"), ("+↓", "+"), ("↓", "")]) - - static let swift2Corrections = corrections(signs: [("-↓", "-"), ("+↓", "+"), ("↓", "")]) - - private static func triggeringExamples(signs: [String]) -> [String] { + private static func makeTriggeringExamples(signs: [String]) -> [String] { return signs.flatMap { (sign: String) -> [String] in [ "let foo = \(sign)10_0", @@ -52,7 +48,7 @@ internal struct NumberSeparatorRuleExamples { } } - private static func corrections(signs: [(String, String)]) -> [String: String] { + private static func makeCorrections(signs: [(String, String)]) -> [String: String] { var result = [String: String]() for (violation, sign) in signs { diff --git a/Source/SwiftLintFramework/Rules/TypeNameRule.swift b/Source/SwiftLintFramework/Rules/TypeNameRule.swift index 00864377c0..1de8d8b322 100644 --- a/Source/SwiftLintFramework/Rules/TypeNameRule.swift +++ b/Source/SwiftLintFramework/Rules/TypeNameRule.swift @@ -23,19 +23,11 @@ public struct TypeNameRule: ASTRule, ConfigurationProviderRule { name: "Type Name", description: "Type name should only contain alphanumeric characters, start with an " + "uppercase character and span between 3 and 40 characters in length.", - nonTriggeringExamples: TypeNameRuleExamples.swift3NonTriggeringExamples, - triggeringExamples: TypeNameRuleExamples.swift3TriggeringExamples + nonTriggeringExamples: TypeNameRuleExamples.nonTriggeringExamples, + triggeringExamples: TypeNameRuleExamples.triggeringExamples ) - private let typeKinds: [SwiftDeclarationKind] = { - let common = SwiftDeclarationKind.typeKinds() - switch SwiftVersion.current { - case .two, .twoPointThree: - return common + [.enumelement] - case .three: - return common - } - }() + private let typeKinds = SwiftDeclarationKind.typeKinds() public func validate(file: File) -> [StyleViolation] { return validateTypeAliasesAndAssociatedTypes(in: file) + diff --git a/Source/SwiftLintFramework/Rules/TypeNameRuleExamples.swift b/Source/SwiftLintFramework/Rules/TypeNameRuleExamples.swift index dd41a72294..c1086f27a7 100644 --- a/Source/SwiftLintFramework/Rules/TypeNameRuleExamples.swift +++ b/Source/SwiftLintFramework/Rules/TypeNameRuleExamples.swift @@ -10,17 +10,9 @@ import Foundation internal struct TypeNameRuleExamples { - static let swift2NonTriggeringExamples = commonNonTriggeringExamples + ["enum MyType {\ncase Value\n}"] - - static let swift3NonTriggeringExamples = commonNonTriggeringExamples + ["enum MyType {\ncase value\n}"] - - static let swift2TriggeringExamples = commonTriggeringExamples + ["enum MyType {\ncase ↓value\n}"] - - static let swift3TriggeringExamples = commonTriggeringExamples - private static let types = ["class", "struct", "enum"] - private static let commonNonTriggeringExamples: [String] = { + static let nonTriggeringExamples: [String] = { let typeExamples: [String] = types.flatMap { (type: String) -> [String] in [ "\(type) MyType {}", @@ -35,10 +27,10 @@ internal struct TypeNameRuleExamples { "protocol Foo {\n associatedtype Bar: Equatable\n }" ] - return typeExamples + typeAliasAndAssociatedTypeExamples + return typeExamples + typeAliasAndAssociatedTypeExamples + ["enum MyType {\ncase value\n}"] }() - private static let commonTriggeringExamples: [String] = { + static let triggeringExamples: [String] = { let typeExamples: [String] = types.flatMap { (type: String) -> [String] in [ "↓\(type) myType {}", diff --git a/Source/SwiftLintFramework/Rules/ValidDocsRule.swift b/Source/SwiftLintFramework/Rules/ValidDocsRule.swift deleted file mode 100644 index 08824a0c0a..0000000000 --- a/Source/SwiftLintFramework/Rules/ValidDocsRule.swift +++ /dev/null @@ -1,244 +0,0 @@ -// -// ValidDocsRule.swift -// SwiftLint -// -// Created by JP Simard on 11/21/15. -// Copyright © 2015 Realm. All rights reserved. -// - -import Foundation -import SourceKittenFramework - -extension File { - fileprivate func invalidDocOffsets(in dictionary: [String: SourceKitRepresentable]) -> [Int] { - let substructure = dictionary.substructure - let substructureOffsets = substructure.flatMap(invalidDocOffsets) - guard let kind = (dictionary.kind).flatMap(SwiftDeclarationKind.init), - kind != .varParameter, - let offset = dictionary.offset, - let bodyOffset = dictionary.bodyOffset, - let comment = parseDocumentationCommentBody(dictionary, syntaxMap: syntaxMap), - !comment.contains(":nodoc:") else { - return substructureOffsets - } - let declaration = contents.bridge() - .substringWithByteRange(start: offset, length: bodyOffset - offset)! - let hasViolation = missingReturnDocumentation(declaration, comment: comment) || - superfluousReturnDocumentation(declaration, comment: comment, kind: kind) || - superfluousOrMissingThrowsDocumentation(declaration, comment: comment) || - superfluousOrMissingParameterDocumentation(declaration, substructure: substructure, - offset: offset, bodyOffset: bodyOffset, - comment: comment) - - return substructureOffsets + (hasViolation ? [offset] : []) - } -} - -func superfluousOrMissingThrowsDocumentation(_ declaration: String, comment: String) -> Bool { - guard let outsideBracesMatch = matchOutsideBraces(declaration) else { - return false == !comment.lowercased().contains("- throws:") - } - return outsideBracesMatch.contains(" throws ") == - !comment.lowercased().contains("- throws:") -} - -func declarationReturns(_ declaration: String, kind: SwiftDeclarationKind? = nil) -> Bool { - if let kind = kind, SwiftDeclarationKind.variableKinds().contains(kind) { - return true - } - - guard let outsideBracesMatch = matchOutsideBraces(declaration) else { - return false - } - return outsideBracesMatch.contains("->") -} - -func matchOutsideBraces(_ declaration: String) -> NSString? { - guard let outsideBracesMatch = - regex("(?:\\)(\\s*\\w*\\s*)*((\\s*->\\s*)(\\(.*\\))*(?!.*->)[^()]*(\\(.*\\))*)?\\s*\\{)") - .matches(in: declaration, options: [], - range: NSRange(location: 0, length: declaration.bridge().length)).first else { - return nil - } - - return declaration.bridge().substring(with: outsideBracesMatch.range).bridge() -} - -func declarationIsInitializer(_ declaration: String) -> Bool { - let range = NSRange(location: 0, length: declaration.bridge().length) - return !regex("^((.+)?\\s+)?init\\?*\\(.*\\)") - .matches(in: declaration, options: [], range: range).isEmpty -} - -func commentHasBatchedParameters(_ comment: String) -> Bool { - return comment.lowercased().contains("- parameters:") -} - -func commentReturns(_ comment: String) -> Bool { - return comment.lowercased().contains("- returns:") || - comment.range(of: "Returns")?.lowerBound == comment.startIndex -} - -func missingReturnDocumentation(_ declaration: String, comment: String) -> Bool { - guard !declarationIsInitializer(declaration) else { - return false - } - return declarationReturns(declaration) && !commentReturns(comment) -} - -func superfluousReturnDocumentation(_ declaration: String, comment: String, - kind: SwiftDeclarationKind) -> Bool { - guard !declarationIsInitializer(declaration) else { - return false - } - return !declarationReturns(declaration, kind: kind) && commentReturns(comment) -} - -func superfluousOrMissingParameterDocumentation(_ declaration: String, - substructure: [[String: SourceKitRepresentable]], - offset: Int, bodyOffset: Int, - comment: String) -> Bool { - // This function doesn't handle batched parameters, so skip those. - if commentHasBatchedParameters(comment) { return false } - let parameterNames = substructure.filter { - ($0.kind).flatMap(SwiftDeclarationKind.init) == .varParameter - }.filter { subDict in - return subDict.offset.map({ $0 < bodyOffset }) ?? false - }.flatMap { - $0.name - } - let labelsAndParams = parameterNames.map { parameter -> (label: String, parameter: String) in - let fullRange = NSRange(location: 0, length: declaration.utf16.count) - let firstMatch = regex("([^,\\s(]+)\\s+\(parameter)\\s*:") - .firstMatch(in: declaration, options: [], range: fullRange) - if let match = firstMatch { - let label = declaration.bridge().substring(with: match.rangeAt(1)) - return (label, parameter) - } - return (parameter, parameter) - } - let optionallyDocumentedParameterCount = labelsAndParams.filter({ $0.0 == "_" }).count - let commentRange = NSRange(location: 0, length: comment.utf16.count) - let commentParameterMatches = regex("- [p|P]arameter ([^:]+)") - .matches(in: comment, options: [], range: commentRange) - let commentParameters = commentParameterMatches.map { match in - return comment.bridge().substring(with: match.rangeAt(1)) - } - if commentParameters.count > labelsAndParams.count || - labelsAndParams.count - commentParameters.count > optionallyDocumentedParameterCount { - return true - } - return !zip(commentParameters, labelsAndParams).filter { - ![$1.label, $1.parameter].contains($0) - }.isEmpty -} - -public struct ValidDocsRule: ConfigurationProviderRule, OptInRule { - - public var configuration = SeverityConfiguration(.warning) - - public init() {} - - public static let description = RuleDescription( - identifier: "valid_docs", - name: "Valid Docs", - description: "Documented declarations should be valid.", - nonTriggeringExamples: [ - "/// docs\npublic func a() {}\n", - "/// docs\n/// - parameter param: this is void\npublic func a(param: Void) {}\n", - "/// docs\n/// - parameter label: this is void\npublic func a(label param: Void) {}", - "/// docs\n/// - parameter param: this is void\npublic func a(label param: Void) {}", - "/// docs\n/// - Parameter param: this is void\npublic func a(label param: Void) {}", - "/// docs\n/// - returns: false\npublic func no() -> Bool { return false }", - "/// docs\n/// - Returns: false\npublic func no() -> Bool { return false }", - "/// Returns false\npublic func no() -> Bool { return false }", - "/// Returns false\nvar no: Bool { return false }", - "/// docs\nvar no: Bool { return false }", - "/// docs\n/// - throws: NSError\nfunc a() throws {}", - "/// docs\n/// - Throws: NSError\nfunc a() throws {}", - "/// docs\n/// - parameter param: this is void\n/// - returns: false" + - "\npublic func no(param: (Void -> Void)?) -> Bool { return false }", - "/// docs\n/// - parameter param: this is void" + - "\n///- parameter param2: this is void too\n/// - returns: false", - "\npublic func no(param: (Void -> Void)?, param2: String->Void) -> Bool " + - "{return false}", - "/// docs\n/// - parameter param: this is void" + - "\npublic func no(param: (Void -> Void)?) {}", - "/// docs\n/// - parameter param: this is void" + - "\n///- parameter param2: this is void too" + - "\npublic func no(param: (Void -> Void)?, param2: String->Void) {}", - "/// docs👨‍👩‍👧‍👧\n/// - returns: false\npublic func no() -> Bool { return false }", - "/// docs\n/// - returns: tuple\npublic func no() -> (Int, Int) {return (1, 2)}", - "/// docs\n/// - returns: closure\npublic func no() -> (Void->Void) {}", - "/// docs\n/// - parameter param: this is void" + - "\n/// - parameter param2: this is void too" + - "\nfunc no(param: (Void) -> Void, onError param2: ((NSError) -> Void)? = nil) {}", - "/// docs\n/// - parameter param: this is a void closure" + - "\n/// - parameter param2: this is a void closure too" + - "\n/// - parameter param3: this is a void closure too" + - "\nfunc a(param: () -> Void, param2: (parameter: Int) -> Void, " + - "param3: (parameter: Int) -> Void) {}", - "/// docs\n/// - parameter param: this is a void closure" + - "\n/// - Parameter param2: this is a void closure too" + - "\n/// - Parameter param3: this is a void closure too" + - "\nfunc a(param: () -> Void, param2: (parameter: Int) -> Void, " + - "param3: (parameter: Int) -> Void) {}", - "/// docs\n/// - parameter param: this is a void closure" + - "\n/// - returns: Foo" + - "\nfunc a(param: () -> Void) -> Foo {return Foo}", - "/// docs\n/// - parameter param: this is a void closure" + - "\n/// - returns: Foo" + - "\nfunc a(param: () -> Void) -> Foo<[Int]> {return Foo<[Int]>}", - "/// docs\n/// - throws: NSError\n/// - returns: false" + - "\nfunc a() throws -> Bool { return true }", - "/// docs\n/// - parameter param: this is a closure\n/// - returns: Bool" + - "\nfunc a(param: (Void throws -> Bool)) -> Bool { return true }" - ], - triggeringExamples: [ - "/// docs\npublic ↓func a(param: Void) {}\n", - "/// docs\n/// - parameter invalid: this is void\npublic ↓func a(param: Void) {}", - "/// docs\n/// - parameter invalid: this is void\npublic ↓func a(label param: Void) {}", - "/// docs\n/// - parameter invalid: this is void\npublic ↓func a() {}", - "/// docs\npublic ↓func no() -> Bool { return false }", - "/// Returns false\npublic ↓func a() {}", - "/// docs\n/// - throws: NSError\n↓func a() {}", - "/// docs\n↓func a() throws {}", - "/// docs\n/// - parameter param: this is void" + - "\npublic ↓func no(param: (Void -> Void)?) -> Bool { return false }", - "/// docs\n/// - parameter param: this is void" + - "\n///- parameter param2: this is void too" + - "\npublic ↓func no(param: (Void -> Void)?, param2: String->Void) -> " + - "Bool {return false}", - "/// docs\n/// - parameter param: this is void\n/// - returns: false" + - "\npublic ↓func no(param: (Void -> Void)?) {}", - "/// docs\n/// - parameter param: this is void" + - "\n///- parameter param2: this is void too\n/// - returns: false" + - "\npublic ↓func no(param: (Void -> Void)?, param2: String->Void) {}", - "/// docs\npublic func no() -> (Int, Int) {return (1, 2)}", - "/// docs\n/// - parameter param: this is void" + - "\n///- parameter param2: this is void too\n///- returns: closure" + - "\nfunc no(param: (Void) -> Void, onError param2: ((NSError) -> Void)? = nil) {}", - "/// docs\n/// - parameter param: this is a void closure" + - "\nfunc a(param: () -> Void) -> Foo {return Foo}", - "/// docs\n/// - parameter param: this is a void closure" + - "\nfunc a(param: () -> Void) -> Foo<[Int]> {return Foo<[Int]>}", - "/// docs\nfunc a() throws -> Bool { return true }" - ] - ) - - public func validate(file: File) -> [StyleViolation] { - guard SwiftVersion.current == .two else { - warnValidDocsRuleDisabledOnce - return [] - } - return file.invalidDocOffsets(in: file.structure.dictionary).map { - StyleViolation(ruleDescription: type(of: self).description, - severity: configuration.severity, - location: Location(file: file, byteOffset: $0)) - } - } -} - -private let warnValidDocsRuleDisabledOnce: Void = { - queuedPrintError("Valid Docs rule is disabled in Swift 2.3 and later as it is non functional.") -}() diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj index db9c222706..b507d1e018 100644 --- a/SwiftLint.xcodeproj/project.pbxproj +++ b/SwiftLint.xcodeproj/project.pbxproj @@ -116,7 +116,6 @@ D44254271DB9C15C00492EA4 /* SyntacticSugarRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44254251DB9C12300492EA4 /* SyntacticSugarRule.swift */; }; D44AD2761C0AA5350048F7B0 /* LegacyConstructorRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44AD2741C0AA3730048F7B0 /* LegacyConstructorRule.swift */; }; D462021F1E15F52D0027AAD1 /* NumberSeparatorRuleExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = D462021E1E15F52D0027AAD1 /* NumberSeparatorRuleExamples.swift */; }; - D46202211E16002A0027AAD1 /* Swift2RulesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46202201E16002A0027AAD1 /* Swift2RulesTests.swift */; }; D46252541DF63FB200BE2CA1 /* NumberSeparatorRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46252531DF63FB200BE2CA1 /* NumberSeparatorRule.swift */; }; D46E041D1DE3712C00728374 /* TrailingCommaRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46E041C1DE3712C00728374 /* TrailingCommaRule.swift */; }; D47079A71DFCEB2D00027086 /* EmptyParenthesesWithTrailingClosureRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47079A61DFCEB2D00027086 /* EmptyParenthesesWithTrailingClosureRule.swift */; }; @@ -145,6 +144,7 @@ D4C4A3521DEFBBB700E0E04C /* FileHeaderConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C4A3511DEFBBB700E0E04C /* FileHeaderConfiguration.swift */; }; D4C889711E385B7B00BAE88D /* RedundantDiscardableLetRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C889701E385B7B00BAE88D /* RedundantDiscardableLetRule.swift */; }; D4CA758F1E2DEEA500A40E8A /* NumberSeparatorRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4CA758E1E2DEEA500A40E8A /* NumberSeparatorRuleTests.swift */; }; + D4D1B9BB1EAC2C910028BE6A /* AccessControlLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D1B9B91EAC2C870028BE6A /* AccessControlLevel.swift */; }; D4D5A5FF1E1F3A1C00D15E0C /* ShorthandOperatorRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D5A5FE1E1F3A1C00D15E0C /* ShorthandOperatorRule.swift */; }; D4DA1DF41E17511D0037413D /* CompilerProtocolInitRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4DA1DF31E17511D0037413D /* CompilerProtocolInitRule.swift */; }; D4DA1DF81E175E8A0037413D /* LinterCache+CommandLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4DA1DF71E175E8A0037413D /* LinterCache+CommandLine.swift */; }; @@ -171,13 +171,11 @@ E816194C1BFBF35D00946723 /* SwiftDeclarationKind+SwiftLint.swift in Sources */ = {isa = PBXBuildFile; fileRef = E816194B1BFBF35D00946723 /* SwiftDeclarationKind+SwiftLint.swift */; }; E816194E1BFBFEAB00946723 /* ForceTryRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E816194D1BFBFEAB00946723 /* ForceTryRule.swift */; }; E81619531BFC162C00946723 /* QueuedPrint.swift in Sources */ = {isa = PBXBuildFile; fileRef = E81619521BFC162C00946723 /* QueuedPrint.swift */; }; - E81CDE711C00FEAA00B430F6 /* ValidDocsRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E81CDE701C00FEAA00B430F6 /* ValidDocsRule.swift */; }; E81FB3E41C6D507B00DC988F /* CommonOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E81FB3E31C6D507B00DC988F /* CommonOptions.swift */; }; E832F10B1B17E2F5003F265F /* NSFileManager+SwiftLint.swift in Sources */ = {isa = PBXBuildFile; fileRef = E832F10A1B17E2F5003F265F /* NSFileManager+SwiftLint.swift */; }; E832F10D1B17E725003F265F /* IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E832F10C1B17E725003F265F /* IntegrationTests.swift */; }; E83A0B351A5D382B0041A60A /* VersionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = E83A0B341A5D382B0041A60A /* VersionCommand.swift */; }; E847F0A91BFBBABD00EA9363 /* EmptyCountRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E847F0A81BFBBABD00EA9363 /* EmptyCountRule.swift */; }; - E849FF281BF9481A009AE999 /* MissingDocsRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E849FF271BF9481A009AE999 /* MissingDocsRule.swift */; }; E84E07471C13F95300F11122 /* AutoCorrectCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = E84E07461C13F95300F11122 /* AutoCorrectCommand.swift */; }; E861519B1B0573B900C54AC0 /* LintCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = E861519A1B0573B900C54AC0 /* LintCommand.swift */; }; E86396C21BADAAE5002C9E88 /* Reporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86396C11BADAAE5002C9E88 /* Reporter.swift */; }; @@ -399,7 +397,6 @@ D44254251DB9C12300492EA4 /* SyntacticSugarRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyntacticSugarRule.swift; sourceTree = ""; }; D44AD2741C0AA3730048F7B0 /* LegacyConstructorRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyConstructorRule.swift; sourceTree = ""; }; D462021E1E15F52D0027AAD1 /* NumberSeparatorRuleExamples.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberSeparatorRuleExamples.swift; sourceTree = ""; }; - D46202201E16002A0027AAD1 /* Swift2RulesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Swift2RulesTests.swift; sourceTree = ""; }; D46252531DF63FB200BE2CA1 /* NumberSeparatorRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberSeparatorRule.swift; sourceTree = ""; }; D46E041C1DE3712C00728374 /* TrailingCommaRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrailingCommaRule.swift; sourceTree = ""; }; D47079A61DFCEB2D00027086 /* EmptyParenthesesWithTrailingClosureRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyParenthesesWithTrailingClosureRule.swift; sourceTree = ""; }; @@ -428,6 +425,7 @@ D4C4A3511DEFBBB700E0E04C /* FileHeaderConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileHeaderConfiguration.swift; sourceTree = ""; }; D4C889701E385B7B00BAE88D /* RedundantDiscardableLetRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedundantDiscardableLetRule.swift; sourceTree = ""; }; D4CA758E1E2DEEA500A40E8A /* NumberSeparatorRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberSeparatorRuleTests.swift; sourceTree = ""; }; + D4D1B9B91EAC2C870028BE6A /* AccessControlLevel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessControlLevel.swift; sourceTree = ""; }; D4D5A5FE1E1F3A1C00D15E0C /* ShorthandOperatorRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShorthandOperatorRule.swift; sourceTree = ""; }; D4DA1DF31E17511D0037413D /* CompilerProtocolInitRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompilerProtocolInitRule.swift; sourceTree = ""; }; D4DA1DF71E175E8A0037413D /* LinterCache+CommandLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LinterCache+CommandLine.swift"; sourceTree = ""; }; @@ -455,13 +453,11 @@ E816194B1BFBF35D00946723 /* SwiftDeclarationKind+SwiftLint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SwiftDeclarationKind+SwiftLint.swift"; sourceTree = ""; }; E816194D1BFBFEAB00946723 /* ForceTryRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForceTryRule.swift; sourceTree = ""; }; E81619521BFC162C00946723 /* QueuedPrint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueuedPrint.swift; sourceTree = ""; }; - E81CDE701C00FEAA00B430F6 /* ValidDocsRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidDocsRule.swift; sourceTree = ""; }; E81FB3E31C6D507B00DC988F /* CommonOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonOptions.swift; sourceTree = ""; }; E832F10A1B17E2F5003F265F /* NSFileManager+SwiftLint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSFileManager+SwiftLint.swift"; sourceTree = ""; }; E832F10C1B17E725003F265F /* IntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntegrationTests.swift; sourceTree = ""; }; E83A0B341A5D382B0041A60A /* VersionCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionCommand.swift; sourceTree = ""; }; E847F0A81BFBBABD00EA9363 /* EmptyCountRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyCountRule.swift; sourceTree = ""; }; - E849FF271BF9481A009AE999 /* MissingDocsRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MissingDocsRule.swift; sourceTree = ""; }; E84E07461C13F95300F11122 /* AutoCorrectCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoCorrectCommand.swift; sourceTree = ""; }; E861519A1B0573B900C54AC0 /* LintCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LintCommand.swift; sourceTree = ""; }; E86396C11BADAAE5002C9E88 /* Reporter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reporter.swift; sourceTree = ""; }; @@ -764,7 +760,6 @@ 3B30C4A01C3785B300E04027 /* YamlParserTests.swift */, 3BCC04D31C502BAB006073C3 /* RuleConfigurationTests.swift */, 6C7045431C6ADA450003F15A /* SourceKitCrashTests.swift */, - D46202201E16002A0027AAD1 /* Swift2RulesTests.swift */, C9802F2E1E0C8AEE008AB27F /* TrailingCommaRuleTests.swift */, 006204DD1E1E4E0A00FFFBE1 /* VerticalWhitespaceRuleTests.swift */, 67EB4DFB1E4CD7F5004E9ACD /* CyclomaticComplexityRuleTests.swift */, @@ -866,7 +861,6 @@ F22314AE1D4F7C77009AD165 /* LegacyNSGeometryFunctionsRule.swift */, E88DEA7B1B098D7D00A66CB0 /* LineLengthRule.swift */, 856651A61D6B395F005E6B29 /* MarkRule.swift */, - E849FF271BF9481A009AE999 /* MissingDocsRule.swift */, E88DEA951B099CF200A66CB0 /* NestingRule.swift */, D4DAE8BB1DE14E8F00B0AE7A /* NimbleOperatorRule.swift */, D4DABFD61E2C23B1009617B6 /* NotificationCenterDetachmentRule.swift */, @@ -904,7 +898,6 @@ D40AD0891E032F9700F48C30 /* UnusedClosureParameterRule.swift */, D43B04631E0620AB004016AF /* UnusedEnumeratedRule.swift */, 92CCB2D61E1EEFA300C8E5A3 /* UnusedOptionalBindingRule.swift */, - E81CDE701C00FEAA00B430F6 /* ValidDocsRule.swift */, D442541E1DB87C3D00492EA4 /* ValidIBInspectableRule.swift */, D4B0226E1E0C75F9007E5297 /* VerticalParameterAlignmentRule.swift */, 1EC163511D5992D900DD2928 /* VerticalWhitespaceRule.swift */, @@ -967,6 +960,7 @@ D47079AA1DFDCF7A00027086 /* SwiftExpressionKind.swift */, E87E4A081BFB9CAE00FCFE46 /* SyntaxKind+SwiftLint.swift */, 6CC4259A1C77046200AEA885 /* SyntaxMap+SwiftLint.swift */, + D4D1B9B91EAC2C870028BE6A /* AccessControlLevel.swift */, ); path = Extensions; sourceTree = ""; @@ -1192,7 +1186,6 @@ E881985E1BEA982100333A11 /* TypeBodyLengthRule.swift in Sources */, 69F88BF71BDA38A6005E7CAE /* OpeningBraceRule.swift in Sources */, 78F032461D7C877E00BE709A /* OverriddenSuperCallRule.swift in Sources */, - E849FF281BF9481A009AE999 /* MissingDocsRule.swift in Sources */, E80E018D1B92C0F60078EB70 /* Command.swift in Sources */, E88198571BEA953300333A11 /* ForceCastRule.swift in Sources */, D44AD2761C0AA5350048F7B0 /* LegacyConstructorRule.swift in Sources */, @@ -1208,7 +1201,6 @@ 3B12C9C51C322032000B423F /* MasterRuleList.swift in Sources */, E812249C1B04FADC001783D2 /* Linter.swift in Sources */, 1F11B3CF1C252F23002E8FA8 /* ClosingBraceRule.swift in Sources */, - E81CDE711C00FEAA00B430F6 /* ValidDocsRule.swift in Sources */, DAD3BE4A1D6ECD9500660239 /* PrivateOutletRuleConfiguration.swift in Sources */, D4B022961E0EF80C007E5297 /* RedundantOptionalInitializationRule.swift in Sources */, 2E02005F1C54BF680024D09D /* CyclomaticComplexityRule.swift in Sources */, @@ -1314,6 +1306,7 @@ E88DEA6B1B0983FE00A66CB0 /* StyleViolation.swift in Sources */, 3BB47D831C514E8100AE6A10 /* RegexConfiguration.swift in Sources */, D4C889711E385B7B00BAE88D /* RedundantDiscardableLetRule.swift in Sources */, + D4D1B9BB1EAC2C910028BE6A /* AccessControlLevel.swift in Sources */, 4A9A3A3A1DC1D75F00DF5183 /* HTMLReporter.swift in Sources */, D40F83881DE9179200524C62 /* TrailingCommaConfiguration.swift in Sources */, 3B5B9FE11C444DA20009AD27 /* Array+SwiftLint.swift in Sources */, @@ -1365,7 +1358,6 @@ D4998DE71DF191380006E05D /* AttributesRuleTests.swift in Sources */, E88198631BEA9A5400333A11 /* RulesTests.swift in Sources */, 47ACC89A1E7DCCAD0088EEB2 /* ImplicitlyUnwrappedOptionalConfigurationTests.swift in Sources */, - D46202211E16002A0027AAD1 /* Swift2RulesTests.swift in Sources */, 67932E2D1E54AF4B00CB0629 /* CyclomaticComplexityConfigurationTests.swift in Sources */, C9802F2F1E0C8AEE008AB27F /* TrailingCommaRuleTests.swift in Sources */, 3B63D46F1E1F09DF0057BE35 /* LineLengthRuleTests.swift in Sources */, diff --git a/SwiftLint.xcodeproj/xcshareddata/xcschemes/swiftlint with Swift 2.3.xcscheme b/SwiftLint.xcodeproj/xcshareddata/xcschemes/swiftlint with Swift 2.3.xcscheme deleted file mode 100644 index fbc511e683..0000000000 --- a/SwiftLint.xcodeproj/xcshareddata/xcschemes/swiftlint with Swift 2.3.xcscheme +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SwiftLint.xcodeproj/xcshareddata/xcschemes/swiftlint.xcscheme b/SwiftLint.xcodeproj/xcshareddata/xcschemes/swiftlint.xcscheme index ed573dbd03..22d3441f47 100644 --- a/SwiftLint.xcodeproj/xcshareddata/xcschemes/swiftlint.xcscheme +++ b/SwiftLint.xcodeproj/xcshareddata/xcschemes/swiftlint.xcscheme @@ -39,9 +39,6 @@ ReferencedContainer = "container:SwiftLint.xcodeproj"> - - diff --git a/Tests/SwiftLintFrameworkTests/Swift2RulesTests.swift b/Tests/SwiftLintFrameworkTests/Swift2RulesTests.swift deleted file mode 100644 index 288b610b1c..0000000000 --- a/Tests/SwiftLintFrameworkTests/Swift2RulesTests.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// Swift2RulesTests.swift -// SwiftLint -// -// Created by Marcelo Fabri on 12/30/16. -// Copyright © 2016 Realm. All rights reserved. -// - -@testable import SwiftLintFramework -import XCTest - -#if !SWIFT_PACKAGE -class Swift2RulesTests: XCTestCase { - - func testAttributes() { - let description = RuleDescription( - identifier: AttributesRule.description.identifier, - name: AttributesRule.description.name, - description: AttributesRule.description.description, - nonTriggeringExamples: AttributesRuleExamples.swift2NonTriggeringExamples, - triggeringExamples: AttributesRuleExamples.swift2TriggeringExamples - ) - - verifyRule(description) - } - - func testIdentifierName() { - let description = RuleDescription( - identifier: IdentifierNameRule.description.identifier, - name: IdentifierNameRule.description.name, - description: IdentifierNameRule.description.description, - nonTriggeringExamples: IdentifierNameRuleExamples.swift2NonTriggeringExamples, - triggeringExamples: IdentifierNameRuleExamples.swift2TriggeringExamples - ) - - verifyRule(description) - } - - func testNotificationCenterDetachment() { - let description = RuleDescription( - identifier: NotificationCenterDetachmentRule.description.identifier, - name: NotificationCenterDetachmentRule.description.name, - description: NotificationCenterDetachmentRule.description.description, - nonTriggeringExamples: NotificationCenterDetachmentRuleExamples.swift2NonTriggeringExamples, - triggeringExamples: NotificationCenterDetachmentRuleExamples.swift2TriggeringExamples - ) - - verifyRule(description) - } - - func testNumberSeparator() { - let description = RuleDescription( - identifier: NumberSeparatorRule.description.identifier, - name: NumberSeparatorRule.description.name, - description: NumberSeparatorRule.description.description, - nonTriggeringExamples: NumberSeparatorRuleExamples.nonTriggeringExamples, - triggeringExamples: NumberSeparatorRuleExamples.swift2TriggeringExamples, - corrections: NumberSeparatorRuleExamples.swift2Corrections - ) - - verifyRule(description) - } - - func testTypeName() { - let description = RuleDescription( - identifier: TypeNameRule.description.identifier, - name: TypeNameRule.description.name, - description: TypeNameRule.description.description, - nonTriggeringExamples: TypeNameRuleExamples.swift2NonTriggeringExamples, - triggeringExamples: TypeNameRuleExamples.swift2TriggeringExamples - ) - - verifyRule(description) - } -} -#endif