Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
fix: avoid recursive isImplicitReturn call to prevent thread-safety i…
…ssues

Replace recursive call to isImplicitReturn inside isIfExprOrSwitchExprImplicitReturn
with a new non-recursive isImplicitReturnExcludingIfSwitchExpr property. This avoids
potential data races when multiple rules traverse the same syntax tree concurrently
during parallel rule execution in SwiftLint's linter.
  • Loading branch information
WZBbiao committed Mar 2, 2026
commit 93d1c918cf1a131111483bd40883331b3c233318
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,15 @@ private extension CodeBlockItemSyntax {
isAccessorImplicitReturn || isIfExprOrSwitchExprImplicitReturn
}

/// Like `isImplicitReturn` but without checking `isIfExprOrSwitchExprImplicitReturn`.
/// Used inside `isIfExprOrSwitchExprImplicitReturn` to avoid recursive calls that can
/// trigger thread-safety issues when multiple rules traverse the syntax tree concurrently.
var isImplicitReturnExcludingIfSwitchExpr: Bool {
isClosureImplicitReturn || isFunctionImplicitReturn ||
isVariableImplicitReturn || isSubscriptImplicitReturn ||
isAccessorImplicitReturn
}

var isClosureImplicitReturn: Bool {
guard let parent = parent?.as(CodeBlockItemListSyntax.self),
let grandparent = parent.parent else {
Expand Down Expand Up @@ -265,15 +274,19 @@ private extension CodeBlockItemSyntax {
// Note: IfExprSyntax used as a statement is wrapped in ExpressionStmtSyntax inside the CodeBlockItemSyntax.
if let ifExpr = parent.parent?.parent?.as(IfExprSyntax.self),
let ifCodeBlockItem = ifExpr.parent?.as(ExpressionStmtSyntax.self)?.parent?.as(CodeBlockItemSyntax.self) {
return ifCodeBlockItem.isImplicitReturn
// Use isImplicitReturnExcludingIfSwitchExpr instead of isImplicitReturn to avoid
// recursive calls that traverse shared syntax nodes concurrently during parallel rule execution.
return ifCodeBlockItem.isImplicitReturnExcludingIfSwitchExpr
}

// Check if inside a switch expression case body.
// Chain: CodeBlockItemListSyntax -> SwitchCaseSyntax -> SwitchCaseListSyntax -> SwitchExprSyntax
// Note: SwitchExprSyntax used as a statement is wrapped in ExpressionStmtSyntax inside the CodeBlockItemSyntax.
if let switchExpr = parent.parent?.parent?.parent?.as(SwitchExprSyntax.self),
let switchCodeBlockItem = switchExpr.parent?.as(ExpressionStmtSyntax.self)?.parent?.as(CodeBlockItemSyntax.self) {
return switchCodeBlockItem.isImplicitReturn
// Use isImplicitReturnExcludingIfSwitchExpr instead of isImplicitReturn to avoid
// recursive calls that traverse shared syntax nodes concurrently during parallel rule execution.
return switchCodeBlockItem.isImplicitReturnExcludingIfSwitchExpr
}

return false
Expand Down