prefer_key_path autofix produces uncompilable code for closures nested inside a #require/#expect call
### New Issue Checklist
- [x] Updated SwiftLint to the latest version (0.63.2)
- [x] Searched for existing issues — closest is #5744 / #5765 (see below), which this does not fully cover
### Bug Description
`prefer_key_path`'s autofix rewrites a property-access closure into a key path even when the call is nested inside a `#require`/`#expect` macro argument. The rewritten key-path form **fails to compile** inside those macros, so `swiftlint --fix` produces a non-building project.
`#5765` ("Silence `prefer_key_path` rule on macro expansion expressions", fixing `#5744`) already handles closures that are a **direct** macro argument, e.g. `#Predicate { $0.isCompleted }`. But the silencing check only inspects the closure's **immediate parent** — in `PreferKeyPathRule.swift`, `isInvalid(...)` guards on `![.macroExpansionExpr, …].contains(parent.kind)`. A closure nested deeper — inside a function-call argument that is itself the macro's argument — has a `FunctionCallExprSyntax` parent, not the `MacroExpansionExprSyntax`, so it is still flagged and still auto-corrected.
### Reproduction
```swift
import Testing
struct Item { let flag: Bool }
@Test func repro() throws {
let items = [Item(flag: true)]
let found = try #require(items.first(where: { $0.flag })) // flagged — but must not be rewritten
#expect(found.flag)
}
```
```
$ swiftlint lint --only-rule prefer_key_path
…:7:49: warning: Prefer Key Path Violation: Use a key path argument instead of a closure with property access (prefer_key_path)
```
`swiftlint --fix` rewrites it to `items.first(where: \.flag)`, after which `swift build` fails:
```
macro expansion #require:2:3: error: call can throw, but it is not marked with 'try' and the error is not handled
note: call is to 'rethrows' function, but argument function can throw
```
(The key-path form is otherwise valid Swift — it compiles fine outside the macro. `#require`/`#expect` decompose the call via `__checkFunctionCall`, which passes the key path as an opaque closure parameter and loses its non-throwing guarantee. Reported separately at swiftlang/swift-testing#1723. Regardless of the swift-testing fix, `prefer_key_path` should not rewrite closures inside a macro expansion — same rationale as #5744.)
### Expected behavior
`prefer_key_path` should not flag (or `--fix` rewrite) a closure that lies anywhere inside a macro-expansion argument — not only when the closure is the direct macro argument. The check could walk ancestors for a `MacroExpansionExprSyntax` / `MacroExpansionDeclSyntax` rather than inspecting only `parent.kind`.
### Environment
* SwiftLint version: 0.63.2
* Xcode version: 26.4
* Swift: 6.2.4
* Installation method: installer
* Configuration:
```yml
only_rules:
- prefer_key_path
```
1 条评论