Compare commits
13 Commits
main
...
0.46.5-mul
Author | SHA1 | Date |
---|---|---|
![]() |
af93485bbe | |
![]() |
925ff8738f | |
![]() |
e176a9648f | |
![]() |
b0afb75714 | |
![]() |
8ecb7c435e | |
![]() |
e8ef21fef6 | |
![]() |
169542a3e2 | |
![]() |
2eca7783b3 | |
![]() |
e8dc313d8b | |
![]() |
9445e676d2 | |
![]() |
8023f36485 | |
![]() |
052708b82c | |
![]() |
17026c12b1 |
|
@ -3,44 +3,38 @@ name: docker
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- '*'
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Extract DOCKER_TAG using tag name
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
run: |
|
|
||||||
echo "DOCKER_TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Use default DOCKER_TAG
|
|
||||||
if: startsWith(github.ref, 'refs/tags/') != true
|
|
||||||
run: |
|
|
||||||
echo "DOCKER_TAG=latest" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set lowercase repository name
|
- name: Set lowercase repository name
|
||||||
run: |
|
run: |
|
||||||
echo "REPOSITORY_LC=${REPOSITORY,,}" >>${GITHUB_ENV}
|
echo "REPOSITORY_LC=${REPOSITORY,,}" >>${GITHUB_ENV}
|
||||||
env:
|
env:
|
||||||
REPOSITORY: '${{ github.repository }}'
|
REPOSITORY: '${{ github.repository }}'
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v1
|
||||||
|
|
||||||
- name: Login to Github registry
|
- name: Log in to Github registry
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
|
|
||||||
- uses: docker/build-push-action@v2
|
- uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
|
platforms: linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: ghcr.io/${{ env.REPOSITORY_LC }}:${{ env.DOCKER_TAG }}
|
tags: ghcr.io/${{ env.REPOSITORY_LC }}:multiarch
|
||||||
|
|
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -1,4 +1,4 @@
|
||||||
## Master
|
## 0.46.5: Laundry Studio
|
||||||
|
|
||||||
#### Breaking
|
#### Breaking
|
||||||
|
|
||||||
|
@ -14,7 +14,25 @@
|
||||||
|
|
||||||
#### Bug Fixes
|
#### Bug Fixes
|
||||||
|
|
||||||
* None.
|
* Fix `empty_parentheses_with_trailing_closure` rule when using Swift 5.6.
|
||||||
|
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||||
|
[#3846](https://github.com/realm/SwiftLint/issues/3846)
|
||||||
|
|
||||||
|
* Fix false negatives in `closure_parameter_position` rule with Swift 5.6.
|
||||||
|
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||||
|
[#3845](https://github.com/realm/SwiftLint/issues/3845)
|
||||||
|
|
||||||
|
* Fix regression in `last_where` rule when using Swift 5.6.
|
||||||
|
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||||
|
[#3847](https://github.com/realm/SwiftLint/issues/3847)
|
||||||
|
|
||||||
|
* Fix regression in `unused_import` rule when using Swift 5.6.
|
||||||
|
[JP Simard](https://github.com/jpsim)
|
||||||
|
[#3849](https://github.com/realm/SwiftLint/issues/3849)
|
||||||
|
|
||||||
|
* Fix regression in `trailing_closure` rule when using Swift 5.6.
|
||||||
|
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||||
|
[#3848](https://github.com/realm/SwiftLint/issues/3848)
|
||||||
|
|
||||||
## 0.46.4: Detergent Tray
|
## 0.46.4: Detergent Tray
|
||||||
|
|
||||||
|
|
11
Dockerfile
11
Dockerfile
|
@ -1,5 +1,5 @@
|
||||||
# Explicitly specify `focal` because `swift:latest` does not use `ubuntu:latest`.
|
# Explicitly specify `focal` because `swift:latest` does not use `ubuntu:latest`.
|
||||||
ARG BUILDER_IMAGE=swift:focal
|
ARG BUILDER_IMAGE=swiftlang/swift:nightly-5.6-focal
|
||||||
ARG RUNTIME_IMAGE=ubuntu:focal
|
ARG RUNTIME_IMAGE=ubuntu:focal
|
||||||
|
|
||||||
# builder image
|
# builder image
|
||||||
|
@ -13,12 +13,10 @@ COPY Source Source/
|
||||||
COPY Tests Tests/
|
COPY Tests Tests/
|
||||||
COPY Package.* ./
|
COPY Package.* ./
|
||||||
|
|
||||||
ARG SWIFT_FLAGS="-c release -Xswiftc -static-stdlib -Xlinker -lCFURLSessionInterface -Xlinker -lCFXMLInterface -Xlinker -lcurl -Xlinker -lxml2"
|
ARG SWIFT_FLAGS="-c release"
|
||||||
RUN swift build $SWIFT_FLAGS
|
RUN swift build $SWIFT_FLAGS
|
||||||
RUN mkdir -p /executables
|
RUN mkdir -p /executables
|
||||||
RUN for executable in $(swift package completion-tool list-executables); do \
|
RUN mv $(swift build $SWIFT_FLAGS --show-bin-path)/swiftlint /executables
|
||||||
install -v `swift build $SWIFT_FLAGS --show-bin-path`/$executable /executables; \
|
|
||||||
done
|
|
||||||
|
|
||||||
# runtime image
|
# runtime image
|
||||||
FROM ${RUNTIME_IMAGE}
|
FROM ${RUNTIME_IMAGE}
|
||||||
|
@ -28,8 +26,7 @@ RUN apt-get update && apt-get install -y \
|
||||||
libxml2 \
|
libxml2 \
|
||||||
&& rm -r /var/lib/apt/lists/*
|
&& rm -r /var/lib/apt/lists/*
|
||||||
COPY --from=builder /usr/lib/libsourcekitdInProc.so /usr/lib
|
COPY --from=builder /usr/lib/libsourcekitdInProc.so /usr/lib
|
||||||
COPY --from=builder /usr/lib/swift/linux/libBlocksRuntime.so /usr/lib
|
COPY --from=builder /usr/lib/swift/linux/* /usr/lib
|
||||||
COPY --from=builder /usr/lib/swift/linux/libdispatch.so /usr/lib
|
|
||||||
COPY --from=builder /executables/* /usr/bin
|
COPY --from=builder /executables/* /usr/bin
|
||||||
|
|
||||||
RUN swiftlint version
|
RUN swiftlint version
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -158,7 +158,7 @@ endif
|
||||||
@sed 's/__VERSION__/$(NEW_VERSION)/g' script/Version.swift.template > Source/SwiftLintFramework/Models/Version.swift
|
@sed 's/__VERSION__/$(NEW_VERSION)/g' script/Version.swift.template > Source/SwiftLintFramework/Models/Version.swift
|
||||||
git commit -a -m "release $(NEW_VERSION)"
|
git commit -a -m "release $(NEW_VERSION)"
|
||||||
git tag -a $(NEW_VERSION) -m "$(NEW_VERSION_AND_NAME)"
|
git tag -a $(NEW_VERSION) -m "$(NEW_VERSION_AND_NAME)"
|
||||||
git push origin master
|
git push origin HEAD
|
||||||
git push origin $(NEW_VERSION)
|
git push origin $(NEW_VERSION)
|
||||||
|
|
||||||
%:
|
%:
|
||||||
|
|
|
@ -4,5 +4,5 @@ public struct Version {
|
||||||
public let value: String
|
public let value: String
|
||||||
|
|
||||||
/// The current SwiftLint version.
|
/// The current SwiftLint version.
|
||||||
public static let current = Version(value: "0.46.4")
|
public static let current = Version(value: "0.46.5")
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,10 @@ private extension SwiftLintFile {
|
||||||
// Always disallow 'Swift' and 'SwiftShims' because they're always available without importing.
|
// Always disallow 'Swift' and 'SwiftShims' because they're always available without importing.
|
||||||
usrFragments.remove("Swift")
|
usrFragments.remove("Swift")
|
||||||
usrFragments.remove("SwiftShims")
|
usrFragments.remove("SwiftShims")
|
||||||
|
if SwiftVersion.current >= .fiveDotSix {
|
||||||
|
usrFragments.remove("main")
|
||||||
|
}
|
||||||
|
|
||||||
var unusedImports = imports.subtracting(usrFragments).subtracting(configuration.alwaysKeepImports)
|
var unusedImports = imports.subtracting(usrFragments).subtracting(configuration.alwaysKeepImports)
|
||||||
// Certain Swift attributes requires importing Foundation.
|
// Certain Swift attributes requires importing Foundation.
|
||||||
if unusedImports.contains("Foundation") && containsAttributesRequiringFoundation() {
|
if unusedImports.contains("Foundation") && containsAttributesRequiringFoundation() {
|
||||||
|
|
|
@ -35,7 +35,19 @@ public struct LastWhereRule: CallPairRule, OptInRule, ConfigurationProviderRule,
|
||||||
patternSyntaxKinds: [.identifier],
|
patternSyntaxKinds: [.identifier],
|
||||||
callNameSuffix: ".filter",
|
callNameSuffix: ".filter",
|
||||||
severity: configuration.severity) { dictionary in
|
severity: configuration.severity) { dictionary in
|
||||||
if dictionary.substructure.isNotEmpty {
|
let substructure: [SourceKittenDictionary] = {
|
||||||
|
if SwiftVersion.current >= .fiveDotSix {
|
||||||
|
return dictionary.substructure.flatMap { dict -> [SourceKittenDictionary] in
|
||||||
|
if dict.expressionKind == .argument {
|
||||||
|
return dict.substructure
|
||||||
|
}
|
||||||
|
return [dict]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dictionary.substructure
|
||||||
|
}()
|
||||||
|
if substructure.isNotEmpty {
|
||||||
return true // has a substructure, like a closure
|
return true // has a substructure, like a closure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,16 +112,23 @@ public struct ClosureParameterPositionRule: ASTRule, ConfigurationProviderRule,
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let nameOffset = dictionary.nameOffset,
|
guard let bodyLength = dictionary.bodyLength,
|
||||||
let nameLength = dictionary.nameLength,
|
|
||||||
let bodyLength = dictionary.bodyLength,
|
|
||||||
bodyLength > 0
|
bodyLength > 0
|
||||||
else {
|
else {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
let parameters = dictionary.enclosedVarParameters +
|
let nameOffset = dictionary.nameOffset ?? 0
|
||||||
dictionary.substructure.filter { $0.declarationKind == .varLocal } // capture lists
|
let nameLength = dictionary.nameLength ?? 0
|
||||||
|
|
||||||
|
let captureLists = dictionary.substructure.flatMap { dict -> [SourceKittenDictionary] in
|
||||||
|
if SwiftVersion.current >= .fiveDotSix, dict.expressionKind == .argument {
|
||||||
|
return dict.substructure.filter { $0.declarationKind == .varLocal }
|
||||||
|
}
|
||||||
|
|
||||||
|
return dict.declarationKind == .varLocal ? [dict] : []
|
||||||
|
}
|
||||||
|
let parameters = dictionary.enclosedVarParameters + captureLists
|
||||||
let rangeStart = nameOffset + nameLength
|
let rangeStart = nameOffset + nameLength
|
||||||
let regex = Self.openBraceRegex
|
let regex = Self.openBraceRegex
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ public struct EmptyParenthesesWithTrailingClosureRule: SubstitutionCorrectableAS
|
||||||
|
|
||||||
// avoid the more expensive regex match if there's no trailing closure in the substructure
|
// avoid the more expensive regex match if there's no trailing closure in the substructure
|
||||||
if SwiftVersion.current >= .fourDotTwo,
|
if SwiftVersion.current >= .fourDotTwo,
|
||||||
dictionary.substructure.last?.expressionKind != .closure {
|
!dictionary.hasTrailingClosure {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,3 +99,17 @@ public struct EmptyParenthesesWithTrailingClosureRule: SubstitutionCorrectableAS
|
||||||
return [match]
|
return [match]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private extension SourceKittenDictionary {
|
||||||
|
var hasTrailingClosure: Bool {
|
||||||
|
guard let lastStructure = substructure.last else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if SwiftVersion.current >= .fiveDotSix, lastStructure.expressionKind == .argument {
|
||||||
|
return lastStructure.substructure.last?.expressionKind == .closure
|
||||||
|
} else {
|
||||||
|
return lastStructure.expressionKind == .closure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,16 +10,8 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule,
|
||||||
nonTriggeringExamples: [
|
nonTriggeringExamples: [
|
||||||
Example("""
|
Example("""
|
||||||
class C {
|
class C {
|
||||||
static private(set) var i = 0, j = C.i
|
static let primes = [2, 3, 5, 7]
|
||||||
let h = C.i
|
func isPrime(i: Int) -> Bool { Self.primes.contains(i) }
|
||||||
@GreaterThan(C.j) var k: Int
|
|
||||||
}
|
|
||||||
"""),
|
|
||||||
Example("""
|
|
||||||
class `Self` {
|
|
||||||
static let i = 0
|
|
||||||
func f() -> Int { Self.i }
|
|
||||||
}
|
|
||||||
"""),
|
"""),
|
||||||
Example("""
|
Example("""
|
||||||
struct T {
|
struct T {
|
||||||
|
@ -29,9 +21,24 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule,
|
||||||
static let i = 0
|
static let i = 0
|
||||||
}
|
}
|
||||||
extension T {
|
extension T {
|
||||||
static let j = S.i + Self.i
|
static let j = S.i + T.i
|
||||||
|
static let k = { T.j }()
|
||||||
}
|
}
|
||||||
"""),
|
"""),
|
||||||
|
Example("""
|
||||||
|
class `Self` {
|
||||||
|
static let i = 0
|
||||||
|
func f() -> Int { Self.i }
|
||||||
|
}
|
||||||
|
"""),
|
||||||
|
Example("""
|
||||||
|
class C {
|
||||||
|
static private(set) var i = 0, j = C.i
|
||||||
|
static let k = { C.i }()
|
||||||
|
let h = C.i
|
||||||
|
@GreaterThan(C.j) var k: Int
|
||||||
|
}
|
||||||
|
""", excludeFromDocumentation: true),
|
||||||
Example("""
|
Example("""
|
||||||
struct S {
|
struct S {
|
||||||
struct T {
|
struct T {
|
||||||
|
@ -45,7 +52,7 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule,
|
||||||
static let j = Self.T.R.i + Self.R.j
|
static let j = Self.T.R.i + Self.R.j
|
||||||
let h = Self.T.R.i + Self.R.j
|
let h = Self.T.R.i + Self.R.j
|
||||||
}
|
}
|
||||||
"""),
|
""", excludeFromDocumentation: true),
|
||||||
Example("""
|
Example("""
|
||||||
class C {
|
class C {
|
||||||
static let s = 2
|
static let s = 2
|
||||||
|
@ -55,31 +62,9 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule,
|
||||||
}
|
}
|
||||||
func g() -> Any { C.self }
|
func g() -> Any { C.self }
|
||||||
}
|
}
|
||||||
"""),
|
""", excludeFromDocumentation: true)
|
||||||
Example("""
|
|
||||||
struct S {
|
|
||||||
static let i = 1
|
|
||||||
static let j = { Self.i }()
|
|
||||||
}
|
|
||||||
extension S {
|
|
||||||
static let k = { S.j }()
|
|
||||||
}
|
|
||||||
""")
|
|
||||||
],
|
],
|
||||||
triggeringExamples: [
|
triggeringExamples: [
|
||||||
Example("""
|
|
||||||
struct C {
|
|
||||||
static let i = 0
|
|
||||||
static let j = ↓C.i
|
|
||||||
}
|
|
||||||
"""),
|
|
||||||
Example("""
|
|
||||||
struct S {
|
|
||||||
static let i = 0
|
|
||||||
func f() -> Int { ↓S.i }
|
|
||||||
func g() -> Any { ↓S.self }
|
|
||||||
}
|
|
||||||
"""),
|
|
||||||
Example("""
|
Example("""
|
||||||
class C {
|
class C {
|
||||||
struct S {
|
struct S {
|
||||||
|
@ -88,8 +73,16 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule,
|
||||||
}
|
}
|
||||||
static let i = 1
|
static let i = 1
|
||||||
let h = C.i
|
let h = C.i
|
||||||
|
func f() -> Int { ↓C.i + h }
|
||||||
}
|
}
|
||||||
"""),
|
"""),
|
||||||
|
Example("""
|
||||||
|
struct S {
|
||||||
|
static let i = 1
|
||||||
|
static func f() -> Int { ↓S.i }
|
||||||
|
func g() -> Any { ↓S.self }
|
||||||
|
}
|
||||||
|
"""),
|
||||||
Example("""
|
Example("""
|
||||||
struct S {
|
struct S {
|
||||||
struct T {
|
struct T {
|
||||||
|
@ -105,28 +98,19 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule,
|
||||||
corrections: [
|
corrections: [
|
||||||
Example("""
|
Example("""
|
||||||
struct S {
|
struct S {
|
||||||
struct T {
|
static let i = 1
|
||||||
static let i = 3
|
static let j = ↓S.i
|
||||||
}
|
let k = ↓S.j
|
||||||
static let h = ↓S.T.i
|
static func f(_ l: Int = ↓S.i) -> Int { l*↓S.j }
|
||||||
|
func g() { ↓S.i + ↓S.f() + k }
|
||||||
}
|
}
|
||||||
"""): Example("""
|
"""): Example("""
|
||||||
struct S {
|
struct S {
|
||||||
struct T {
|
static let i = 1
|
||||||
static let i = 3
|
static let j = Self.i
|
||||||
}
|
let k = Self.j
|
||||||
static let h = Self.T.i
|
static func f(_ l: Int = Self.i) -> Int { l*Self.j }
|
||||||
}
|
func g() { Self.i + Self.f() + k }
|
||||||
"""),
|
|
||||||
Example("""
|
|
||||||
class S {
|
|
||||||
static func f() { ↓S.g(↓S.f) }
|
|
||||||
static func g(f: () -> Void) { f() }
|
|
||||||
}
|
|
||||||
"""): Example("""
|
|
||||||
class S {
|
|
||||||
static func f() { Self.g(Self.f) }
|
|
||||||
static func g(f: () -> Void) { f() }
|
|
||||||
}
|
}
|
||||||
""")
|
""")
|
||||||
]
|
]
|
||||||
|
|
|
@ -82,8 +82,16 @@ public struct TrailingClosureRule: OptInRule, ConfigurationProviderRule {
|
||||||
return shouldTrigger()
|
return shouldTrigger()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let argumentsCountIsExpected: Bool = {
|
||||||
|
if SwiftVersion.current >= .fiveDotSix, arguments.count == 1,
|
||||||
|
arguments[0].expressionKind == .argument {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return arguments.isEmpty
|
||||||
|
}()
|
||||||
// check if there's only one unnamed parameter that is a closure
|
// check if there's only one unnamed parameter that is a closure
|
||||||
if arguments.isEmpty,
|
if argumentsCountIsExpected,
|
||||||
let offset = dictionary.offset,
|
let offset = dictionary.offset,
|
||||||
let totalLength = dictionary.length,
|
let totalLength = dictionary.length,
|
||||||
let nameOffset = dictionary.nameOffset,
|
let nameOffset = dictionary.nameOffset,
|
||||||
|
|
Loading…
Reference in New Issue