mirror of
https://github.com/realm/SwiftLint.git
synced 2026-05-07 20:12:49 +00:00
Ignore override declarations in async_without_await rule (#6417)
Co-authored-by: Danny Mösch <danny.moesch@icloud.com>
This commit is contained in:
@@ -16,6 +16,10 @@
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Ignore `override` functions in `async_without_await` rule.
|
||||
[SimplyDanny](https://github.com/SimplyDanny)
|
||||
[#6416](https://github.com/realm/SwiftLint/issues/6416)
|
||||
|
||||
* Fix false positive in `unneeded_escaping` rule when an escaping closure is used in
|
||||
a nested closure preceded by another closure.
|
||||
[SimplyDanny](https://github.com/SimplyDanny)
|
||||
|
||||
@@ -26,15 +26,10 @@ private extension AsyncWithoutAwaitRule {
|
||||
private var pendingAsync: TokenSyntax?
|
||||
|
||||
override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind {
|
||||
guard node.body != nil else {
|
||||
return .visitChildren
|
||||
if node.body != nil {
|
||||
let asyncToken = node.needsToKeepAsync ? nil : node.signature.effectSpecifiers?.asyncSpecifier
|
||||
functionScopes.push(.init(asyncToken: asyncToken))
|
||||
}
|
||||
|
||||
// @concurrent functions require the async keyword even without await calls
|
||||
let asyncToken = node.attributes.contains(attributeNamed: "concurrent")
|
||||
? nil : node.signature.effectSpecifiers?.asyncSpecifier
|
||||
functionScopes.push(.init(asyncToken: asyncToken))
|
||||
|
||||
return .visitChildren
|
||||
}
|
||||
|
||||
@@ -45,7 +40,7 @@ private extension AsyncWithoutAwaitRule {
|
||||
}
|
||||
|
||||
override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind {
|
||||
// @concurrent closures require the async keyword even without await calls
|
||||
// @concurrent closures require the async keyword even without await calls,
|
||||
let asyncToken = (node.signature?.attributes.contains(attributeNamed: "concurrent") ?? false)
|
||||
? nil : pendingAsync
|
||||
functionScopes.push(.init(asyncToken: asyncToken))
|
||||
@@ -62,13 +57,10 @@ private extension AsyncWithoutAwaitRule {
|
||||
}
|
||||
|
||||
override func visit(_ node: AccessorDeclSyntax) -> SyntaxVisitorContinueKind {
|
||||
guard node.body != nil else {
|
||||
return .visitChildren
|
||||
if node.body != nil {
|
||||
let asyncToken = node.needsToKeepAsync ? nil : node.effectSpecifiers?.asyncSpecifier
|
||||
functionScopes.push(.init(asyncToken: asyncToken))
|
||||
}
|
||||
|
||||
let asyncToken = node.effectSpecifiers?.asyncSpecifier
|
||||
functionScopes.push(.init(asyncToken: asyncToken))
|
||||
|
||||
return .visitChildren
|
||||
}
|
||||
|
||||
@@ -79,15 +71,10 @@ private extension AsyncWithoutAwaitRule {
|
||||
}
|
||||
|
||||
override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind {
|
||||
guard node.body != nil else {
|
||||
return .visitChildren
|
||||
if node.body != nil {
|
||||
let asyncToken = node.needsToKeepAsync ? nil : node.signature.effectSpecifiers?.asyncSpecifier
|
||||
functionScopes.push(.init(asyncToken: asyncToken))
|
||||
}
|
||||
|
||||
// @concurrent can be applied to initializers
|
||||
let asyncToken = node.attributes.contains(attributeNamed: "concurrent")
|
||||
? nil : node.signature.effectSpecifiers?.asyncSpecifier
|
||||
functionScopes.push(.init(asyncToken: asyncToken))
|
||||
|
||||
return .visitChildren
|
||||
}
|
||||
|
||||
@@ -163,3 +150,21 @@ private extension TypeSyntax {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private extension WithModifiersSyntax where Self: WithAttributesSyntax {
|
||||
var needsToKeepAsync: Bool {
|
||||
attributes.contains(attributeNamed: "concurrent") || modifiers.contains(keyword: .override)
|
||||
}
|
||||
}
|
||||
|
||||
private extension SyntaxProtocol {
|
||||
var needsToKeepAsync: Bool {
|
||||
if let variableDecl = `as`(VariableDeclSyntax.self) {
|
||||
return variableDecl.needsToKeepAsync
|
||||
}
|
||||
if let subscriptDecl = `as`(SubscriptDeclSyntax.self) {
|
||||
return subscriptDecl.needsToKeepAsync
|
||||
}
|
||||
return parent?.needsToKeepAsync ?? false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,6 +188,34 @@ internal struct AsyncWithoutAwaitRuleExamples {
|
||||
let c: () async -> Int = { @concurrent in 1 }
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
class Parent {
|
||||
func test() async { await foo() }
|
||||
}
|
||||
class Child: Parent {
|
||||
override func test() async { print("Child") }
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
class Parent {
|
||||
var prop: Int {
|
||||
get async { await fetchValue() }
|
||||
}
|
||||
}
|
||||
class Child: Parent {
|
||||
override var prop: Int {
|
||||
get async { return 2 }
|
||||
}
|
||||
}
|
||||
"""),
|
||||
Example("""
|
||||
class Base {
|
||||
init() async { await setup() }
|
||||
}
|
||||
class Derived: Base {
|
||||
override init() async { print("Derived") }
|
||||
}
|
||||
"""),
|
||||
]
|
||||
|
||||
static let triggeringExamples = [
|
||||
|
||||
Reference in New Issue
Block a user