diff --git a/CHANGELOG.md b/CHANGELOG.md index 0353b4e1a..04a11add3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,14 @@ macOS < 12. positional paths that can be added last to both commands. [SimplyDanny](https://github.com/SimplyDanny) +* SwiftLint now requires Swift 5.6 or higher to build, and macOS 12 + or higher to run. + [JP Simard](https://github.com/jpsim) + +* Code Climate reports now use SHA256 strings as the issue fingerprint + values. + [JP Simard](https://github.com/jpsim) + #### Experimental * None. diff --git a/Package.resolved b/Package.resolved index ff3752f7f..b38b75fb3 100644 --- a/Package.resolved +++ b/Package.resolved @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/apple/swift-argument-parser.git", "state": { "branch": null, - "revision": "e394bf350e38cb100b6bc4172834770ede1b7232", - "version": "1.0.3" + "revision": "df9ee6676cd5b3bf5b330ec7568a5644f547201b", + "version": "1.1.3" } }, { diff --git a/Package.swift b/Package.swift index 97bdc8344..dc980f30c 100644 --- a/Package.swift +++ b/Package.swift @@ -9,36 +9,29 @@ private let addCryptoSwift = true private let staticSwiftSyntax = false #endif -#if os(Linux) && compiler(<5.6) -private let swiftSyntaxFiveDotSix = false -#else -private let swiftSyntaxFiveDotSix = true -#endif - let frameworkDependencies: [Target.Dependency] = [ .product(name: "SourceKittenFramework", package: "SourceKitten"), .product(name: "SwiftSyntax", package: "SwiftSyntax"), + .product(name: "SwiftSyntaxParser", package: "SwiftSyntax"), "Yams", ] + (addCryptoSwift ? ["CryptoSwift"] : []) + (staticSwiftSyntax ? ["lib_InternalSwiftSyntaxParser"] : []) -+ (swiftSyntaxFiveDotSix ? [.product(name: "SwiftSyntaxParser", package: "SwiftSyntax")] : []) let package = Package( name: "SwiftLint", - platforms: [.macOS(.v10_12)], + platforms: [.macOS(.v12)], products: [ .executable(name: "swiftlint", targets: ["swiftlint"]), .library(name: "SwiftLintFramework", targets: ["SwiftLintFramework"]) ], dependencies: [ - .package(name: "swift-argument-parser", url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.0.3")), - .package(name: "SwiftSyntax", url: "https://github.com/apple/swift-syntax.git", - .exact(swiftSyntaxFiveDotSix ? "0.50600.1" : "0.50500.0")), + .package(name: "swift-argument-parser", url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.1.3")), + .package(name: "SwiftSyntax", url: "https://github.com/apple/swift-syntax.git", .exact("0.50600.1")), .package(url: "https://github.com/jpsim/SourceKitten.git", from: "0.32.0"), .package(url: "https://github.com/jpsim/Yams.git", from: "4.0.2"), .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"), - ] + (addCryptoSwift ? [.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.4.3"))] : []), + ] + (addCryptoSwift ? [.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.5.1"))] : []), targets: [ .executableTarget( name: "swiftlint", @@ -51,7 +44,6 @@ let package = Package( .target( name: "SwiftLintFramework", dependencies: frameworkDependencies, - swiftSettings: swiftSyntaxFiveDotSix ? [.define("SWIFT_SYNTAX_FIVE_DOT_SIX")] : [], // Pass `-dead_strip_dylibs` to ignore the dynamic version of `lib_InternalSwiftSyntaxParser` // that ships with SwiftSyntax because we want the static version from // `StaticInternalSwiftSyntaxParser`. diff --git a/README.md b/README.md index 0fb44f87e..0f59f0eac 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ running it. ### Installing from source: You can also build and install from source by cloning this project and running -`make install` (Xcode 13 or later). +`make install` (Xcode 13.3 or later). ## Usage diff --git a/Source/SwiftLintFramework/Extensions/Configuration+Cache.swift b/Source/SwiftLintFramework/Extensions/Configuration+Cache.swift index 2e6a964f5..5acd514d1 100644 --- a/Source/SwiftLintFramework/Extensions/Configuration+Cache.swift +++ b/Source/SwiftLintFramework/Extensions/Configuration+Cache.swift @@ -65,7 +65,7 @@ extension Configuration { let jsonObject: [Any] = [rootDirectory, cacheRulesDescriptions] if let jsonData = try? JSONSerialization.data(withJSONObject: jsonObject), let jsonString = String(data: jsonData, encoding: .utf8) { - return jsonString.md5() + return jsonString.sha256() } queuedFatalError("Could not serialize configuration for cache") } diff --git a/Source/SwiftLintFramework/Extensions/String+md5.swift b/Source/SwiftLintFramework/Extensions/String+md5.swift deleted file mode 100644 index f120d348a..000000000 --- a/Source/SwiftLintFramework/Extensions/String+md5.swift +++ /dev/null @@ -1,15 +0,0 @@ -#if canImport(CommonCrypto) -import CommonCrypto - -extension String { - internal func md5() -> String { - let context = UnsafeMutablePointer.allocate(capacity: 1) - var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH)) - CC_MD5_Init(context) - CC_MD5_Update(context, self, CC_LONG(lengthOfBytes(using: .utf8))) - CC_MD5_Final(&digest, context) - context.deallocate() - return digest.reduce(into: "") { $0.append(String(format: "%02x", $1)) } - } -} -#endif diff --git a/Source/SwiftLintFramework/Extensions/String+sha256.swift b/Source/SwiftLintFramework/Extensions/String+sha256.swift new file mode 100644 index 000000000..f9e1d675e --- /dev/null +++ b/Source/SwiftLintFramework/Extensions/String+sha256.swift @@ -0,0 +1,14 @@ +#if canImport(CommonCrypto) +import CommonCrypto + +extension String { + internal func sha256() -> String { + let theData = data(using: .utf8)! + return theData.withUnsafeBytes { bytes in + var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) + _ = CC_SHA256(bytes.baseAddress, CC_LONG(theData.count), &hash) + return hash.reduce(into: "") { $0.append(String(format: "%02x", $1)) } + } + } +} +#endif diff --git a/Source/SwiftLintFramework/Models/Command.swift b/Source/SwiftLintFramework/Models/Command.swift index b76325e32..c87ed98bf 100644 --- a/Source/SwiftLintFramework/Models/Command.swift +++ b/Source/SwiftLintFramework/Models/Command.swift @@ -1,33 +1,4 @@ import Foundation -import SourceKittenFramework - -#if os(Linux) -private extension Scanner { - func scanString(string: String) -> String? { - return scanString(string) - } -} -#else -private extension Scanner { - func scanUpToString(_ string: String) -> String? { - var result: NSString? - let success = scanUpTo(string, into: &result) - if success { - return result?.bridge() - } - return nil - } - - func scanString(string: String) -> String? { - var result: NSString? - let success = scanString(string, into: &result) - if success { - return result?.bridge() - } - return nil - } -} -#endif /// A SwiftLint-interpretable command to modify SwiftLint's behavior embedded as comments in source code. public struct Command: Equatable { @@ -100,7 +71,7 @@ public struct Command: Equatable { /// defined. public init?(actionString: String, line: Int, character: Int) { let scanner = Scanner(string: actionString) - _ = scanner.scanString(string: "swiftlint:") + _ = scanner.scanString("swiftlint:") // (enable|disable)(:previous|:this|:next) guard let actionAndModifierString = scanner.scanUpToString(" ") else { return nil @@ -120,9 +91,12 @@ public struct Command: Equatable { trailingComment = nil } else { // Store any text after the comment delimiter as the trailingComment. - // The addition to scanLocation is to move past the delimiter - let startOfCommentPastDelimiter = scanner.scanLocation + Self.commentDelimiter.count - trailingComment = scanner.string.bridge().substring(from: startOfCommentPastDelimiter) + // The addition to currentIndex is to move past the delimiter + trailingComment = String( + scanner + .string[scanner.currentIndex...] + .dropFirst(Self.commentDelimiter.count) + ) } let ruleTexts = rawRuleTexts.components(separatedBy: .whitespacesAndNewlines).filter { let component = $0.trimmingCharacters(in: .whitespaces) @@ -132,11 +106,13 @@ public struct Command: Equatable { ruleIdentifiers = Set(ruleTexts.map(RuleIdentifier.init(_:))) // Modifier - let hasModifier = actionAndModifierScanner.scanString(string: ":") != nil + let hasModifier = actionAndModifierScanner.scanString(":") != nil if hasModifier { - let modifierString = actionAndModifierScanner.string.bridge() - .substring(from: actionAndModifierScanner.scanLocation) - modifier = Modifier(rawValue: modifierString) + modifier = Modifier( + rawValue: String( + actionAndModifierScanner.string[actionAndModifierScanner.currentIndex...] + ) + ) } else { modifier = nil } diff --git a/Source/SwiftLintFramework/Reporters/CodeClimateReporter.swift b/Source/SwiftLintFramework/Reporters/CodeClimateReporter.swift index e110b6f7b..0b79d78d9 100644 --- a/Source/SwiftLintFramework/Reporters/CodeClimateReporter.swift +++ b/Source/SwiftLintFramework/Reporters/CodeClimateReporter.swift @@ -50,6 +50,6 @@ public struct CodeClimateReporter: Reporter { return [ "\(fingerprintLocation)", "\(violation.ruleIdentifier)" - ].joined().md5() + ].joined().sha256() } } diff --git a/Source/SwiftLintFramework/Rules/Idiomatic/UnavailableConditionRule.swift b/Source/SwiftLintFramework/Rules/Idiomatic/UnavailableConditionRule.swift index 5acb4ef91..14b6056f1 100644 --- a/Source/SwiftLintFramework/Rules/Idiomatic/UnavailableConditionRule.swift +++ b/Source/SwiftLintFramework/Rules/Idiomatic/UnavailableConditionRule.swift @@ -90,10 +90,8 @@ public struct UnavailableConditionRule: ConfigurationProviderRule, AutomaticTest switch check { case is AvailabilityConditionSyntax: return "Use #unavailable instead of #available with an empty body." - #if SWIFT_SYNTAX_FIVE_DOT_SIX case is UnavailabilityConditionSyntax: return "Use #available instead of #unavailable with an empty body." - #endif default: queuedFatalError("Unknown availability check type.") } @@ -123,12 +121,8 @@ private final class UnavailableConditionRuleVisitor: SyntaxVisitor { } private func asAvailabilityCondition(_ condition: Syntax) -> SyntaxProtocol? { - let availability = condition.as(AvailabilityConditionSyntax.self) - #if SWIFT_SYNTAX_FIVE_DOT_SIX - return availability ?? condition.as(UnavailabilityConditionSyntax.self) - #else - return availability - #endif + condition.as(AvailabilityConditionSyntax.self) ?? + condition.as(UnavailabilityConditionSyntax.self) } private func otherAvailabilityCheckInvolved(ifStmt: IfStmtSyntax) -> Bool { diff --git a/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift b/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift index c1266cfeb..dac90f2f5 100644 --- a/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift +++ b/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift @@ -1,5 +1,4 @@ import Foundation -import SourceKittenFramework struct CompilerArgumentsExtractor { static func allCompilerInvocations(compilerLogs: String) -> [[String]] { @@ -18,28 +17,6 @@ struct CompilerArgumentsExtractor { // MARK: - Private -#if !os(Linux) -private extension Scanner { - func scanUpToString(_ string: String) -> String? { - var result: NSString? - let success = scanUpTo(string, into: &result) - if success { - return result?.bridge() - } - return nil - } - - func scanString(_ string: String) -> String? { - var result: NSString? - let success = scanString(string, into: &result) - if success { - return result?.bridge() - } - return nil - } -} -#endif - private func parseCLIArguments(_ string: String) -> [String] { let escapedSpacePlaceholder = "\u{0}" let scanner = Scanner(string: string) diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift index 8cd946067..c1055788c 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift @@ -47,7 +47,7 @@ struct LintOrAnalyzeArguments: ParsableArguments { // `LintOrAnalyzeArguments`. func pathOptionDescription(for mode: LintOrAnalyzeMode) -> ArgumentHelp { - ArgumentHelp(shouldDisplay: false) + ArgumentHelp(visibility: .hidden) } func pathsArgumentDescription(for mode: LintOrAnalyzeMode) -> ArgumentHelp { diff --git a/Tests/SwiftLintFrameworkTests/ReporterTests.swift b/Tests/SwiftLintFrameworkTests/ReporterTests.swift index 5e87fdd00..028f6805e 100644 --- a/Tests/SwiftLintFrameworkTests/ReporterTests.swift +++ b/Tests/SwiftLintFrameworkTests/ReporterTests.swift @@ -42,7 +42,7 @@ class ReporterTests: XCTestCase { severity: .error, location: location, reason: "Shorthand syntactic sugar should be used" + - ", i.e. [Int] instead of Array."), + ", i.e. [Int] instead of Array."), StyleViolation(ruleDescription: ColonRule.description, severity: .error, location: Location(file: nil), @@ -118,9 +118,9 @@ class ReporterTests: XCTestCase { func testHTMLReporter() { let expectedOutput = stringFromFile("CannedHTMLReporterOutput.html") let result = HTMLReporter.generateReport( - generateViolations(), - swiftlintVersion: "1.2.3", - dateString: "13/12/2016" + generateViolations(), + swiftlintVersion: "1.2.3", + dateString: "13/12/2016" ) XCTAssertEqual(result, expectedOutput) } diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedCodeClimateReporterOutput.json b/Tests/SwiftLintFrameworkTests/Resources/CannedCodeClimateReporterOutput.json index 64f31d6e8..c8d56f3b5 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedCodeClimateReporterOutput.json +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedCodeClimateReporterOutput.json @@ -3,7 +3,7 @@ "check_name" : "Line Length", "description" : "Violation Reason.", "engine_name" : "SwiftLint", - "fingerprint" : "091a80392f7aebde05dab908162c3629", + "fingerprint" : "917a85854a9500cfd28520fa4875a3ecbba171e522f13452c7adec71fc14497a", "location" : { "lines" : { "begin" : 1, @@ -18,7 +18,7 @@ "check_name" : "Line Length", "description" : "Violation Reason.", "engine_name" : "SwiftLint", - "fingerprint" : "091a80392f7aebde05dab908162c3629", + "fingerprint" : "917a85854a9500cfd28520fa4875a3ecbba171e522f13452c7adec71fc14497a", "location" : { "lines" : { "begin" : 1, @@ -33,7 +33,7 @@ "check_name" : "Syntactic Sugar", "description" : "Shorthand syntactic sugar should be used, i.e. [Int] instead of Array.", "engine_name" : "SwiftLint", - "fingerprint" : "624a4e77e797c9e6a42c82b6428e9c45", + "fingerprint" : "6477f518963149b01807a31e7067be97dc39a30b93673e1e246f812e9ea5ef21", "location" : { "lines" : { "begin" : 1, @@ -48,7 +48,7 @@ "check_name" : "Colon Spacing", "description" : "Colons should be next to the identifier when specifying a type and next to the key in dictionary literals.", "engine_name" : "SwiftLint", - "fingerprint" : "1f9389145aa6d7e89a582fce5ae54659", + "fingerprint" : "9b1ddedc847d23a54124cb02a56452fc01c23df8f3babc07a6a68cf2449b14a6", "location" : { "lines" : { "begin" : null, diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c65c856bd..b0032a383 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,8 +8,6 @@ jobs: strategy: maxParallel: 10 matrix: - swift55: - containerImage: swift:5.5 swift56: containerImage: swift:5.6 container: $[ variables['containerImage'] ] @@ -23,8 +21,6 @@ jobs: strategy: maxParallel: 10 matrix: - xcode1321: - DEVELOPER_DIR: /Applications/Xcode_13.2.1.app xcode1331: DEVELOPER_DIR: /Applications/Xcode_13.3.1.app steps: @@ -41,8 +37,6 @@ jobs: strategy: maxParallel: 10 matrix: - xcode1321: - DEVELOPER_DIR: /Applications/Xcode_13.2.1.app xcode1331: DEVELOPER_DIR: /Applications/Xcode_13.3.1.app steps: