mirror of
https://github.com/nicklockwood/SwiftFormat.git
synced 2026-05-17 10:30:35 +00:00
Fix issue where modifiersOrder rule confused async effect for async modifier (#2237)
This commit is contained in:
@@ -389,14 +389,14 @@ extension Formatter {
|
||||
|
||||
/// Returns true if the token at specified index is a modifier
|
||||
func isModifier(at index: Int) -> Bool {
|
||||
guard let token = token(at: index), token.isModifierKeyword else {
|
||||
guard let token = token(at: index), token._isModifierKeyword else {
|
||||
return false
|
||||
}
|
||||
|
||||
if token == .keyword("class"),
|
||||
let nextToken = next(.nonSpaceOrCommentOrLinebreak, after: index)
|
||||
{
|
||||
return nextToken.isDeclarationTypeKeyword || nextToken.isModifierKeyword
|
||||
return nextToken.isDeclarationTypeKeyword || nextToken._isModifierKeyword
|
||||
}
|
||||
|
||||
// Async is only a valid modifier on local let/var declarations.
|
||||
@@ -2536,7 +2536,7 @@ extension Formatter {
|
||||
if nextToken.isDeclarationTypeKeyword {
|
||||
return nextToken.string
|
||||
}
|
||||
guard nextToken.isModifierKeyword else {
|
||||
guard nextToken._isModifierKeyword else {
|
||||
break
|
||||
}
|
||||
nextIndex = i
|
||||
@@ -3648,7 +3648,11 @@ extension Token {
|
||||
.contains(keyword)
|
||||
}
|
||||
|
||||
var isModifierKeyword: Bool {
|
||||
/// Whether or not this token represents a potential modifier keyword.
|
||||
/// This doesn't necessarily mean that the keyword is a modifier: some modifiers
|
||||
/// like `class` and `async` are contextual.
|
||||
/// In rule implementations, prefer using the `Formatter.isModifier(at:)` helper.
|
||||
var _isModifierKeyword: Bool {
|
||||
switch self {
|
||||
case let .keyword(keyword), let .identifier(keyword):
|
||||
return _FormatRules.allModifiers.contains(keyword)
|
||||
|
||||
@@ -21,7 +21,7 @@ public extension FormatRule {
|
||||
return
|
||||
}
|
||||
var keyword: Token = formatter.tokens[nextIndex]
|
||||
while keyword == .startOfScope("#if") || keyword.isModifierKeyword || keyword.isAttribute,
|
||||
while keyword == .startOfScope("#if") || formatter.isModifier(at: nextIndex) || keyword.isAttribute,
|
||||
let index = formatter.index(of: .keyword, after: nextIndex)
|
||||
{
|
||||
nextIndex = index
|
||||
|
||||
@@ -163,7 +163,7 @@ extension Formatter {
|
||||
|
||||
// Check if this token defines a declaration that supports doc comments
|
||||
var declarationToken = tokens[nextDeclarationIndex]
|
||||
if declarationToken.isAttribute || declarationToken.isModifierKeyword,
|
||||
if declarationToken.isAttribute || isModifier(at: nextDeclarationIndex),
|
||||
let index = index(after: nextDeclarationIndex, where: { $0.isDeclarationTypeKeyword })
|
||||
{
|
||||
declarationToken = tokens[index]
|
||||
|
||||
@@ -19,11 +19,11 @@ public extension FormatRule {
|
||||
) { formatter in
|
||||
formatter.forEachToken(where: { [.keyword("class"), .keyword("struct")].contains($0) }) { i, token in
|
||||
if token == .keyword("class") {
|
||||
guard let next = formatter.next(.nonSpaceOrCommentOrLinebreak, after: i),
|
||||
guard let nextIndex = formatter.index(of: .nonSpaceOrCommentOrLinebreak, after: i),
|
||||
// exit if structs only
|
||||
formatter.options.enumNamespaces != .structsOnly,
|
||||
// exit if class is a type modifier
|
||||
!(next.isKeywordOrAttribute || next.isModifierKeyword),
|
||||
!(formatter.tokens[nextIndex].isKeywordOrAttribute || formatter.isModifier(at: nextIndex)),
|
||||
// exit for class as protocol conformance
|
||||
formatter.last(.nonSpaceOrCommentOrLinebreak, before: i) != .delimiter(":"),
|
||||
// exit if not closed for extension
|
||||
|
||||
@@ -15,13 +15,7 @@ public extension FormatRule {
|
||||
options: ["modifier-order"]
|
||||
) { formatter in
|
||||
formatter.forEach(.keyword) { i, token in
|
||||
switch token.string {
|
||||
case "let", "func", "var", "class", "actor", "extension", "init", "enum",
|
||||
"struct", "typealias", "subscript", "associatedtype", "protocol":
|
||||
break
|
||||
default:
|
||||
return
|
||||
}
|
||||
guard token.isDeclarationTypeKeyword else { return }
|
||||
var modifiers = [String: [Token]]()
|
||||
var lastModifier: (name: String, tokens: [Token])?
|
||||
func pushModifier() {
|
||||
@@ -36,7 +30,7 @@ public extension FormatRule {
|
||||
lastModifier = nil
|
||||
lastIndex = previousIndex
|
||||
break loop
|
||||
case let token where token.isModifierKeyword:
|
||||
case let token where formatter.isModifier(at: index):
|
||||
pushModifier()
|
||||
lastModifier = (token.string, [Token](formatter.tokens[index ..< lastIndex]))
|
||||
previousIndex = lastIndex
|
||||
@@ -45,7 +39,7 @@ public extension FormatRule {
|
||||
if case let .identifier(param)? = formatter.last(.nonSpaceOrCommentOrLinebreak, before: index),
|
||||
let openParenIndex = formatter.index(of: .startOfScope("("), before: index),
|
||||
let index = formatter.index(of: .nonSpaceOrCommentOrLinebreak, before: openParenIndex),
|
||||
let token = formatter.token(at: index), token.isModifierKeyword
|
||||
let token = formatter.token(at: index), formatter.isModifier(at: index)
|
||||
{
|
||||
pushModifier()
|
||||
let modifier = token.string + (param == "set" ? "(set)" : "")
|
||||
|
||||
@@ -43,7 +43,7 @@ public extension FormatRule {
|
||||
nextIndex = endIndex
|
||||
}
|
||||
case let token:
|
||||
guard token.isModifierKeyword else {
|
||||
guard formatter.isModifier(at: nextIndex) else {
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,8 @@ public extension FormatRule {
|
||||
formatter.forEach(.attribute) { i, _ in
|
||||
// Ignore sequential attributes
|
||||
guard let endIndex = formatter.endOfAttribute(at: i),
|
||||
var keywordIndex = formatter.index(
|
||||
of: .nonSpaceOrCommentOrLinebreak,
|
||||
after: endIndex, if: { $0.isKeyword || $0.isModifierKeyword }
|
||||
)
|
||||
var keywordIndex = formatter.index(of: .nonSpaceOrCommentOrLinebreak, after: endIndex),
|
||||
formatter.tokens[keywordIndex].isKeyword || formatter.isModifier(at: keywordIndex)
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -143,4 +143,15 @@ class ModifierOrderTests: XCTestCase {
|
||||
"""
|
||||
testFormatting(for: input, rule: .modifierOrder)
|
||||
}
|
||||
|
||||
func testAsyncFunctionBeforeNonisolatedVar() {
|
||||
let input = """
|
||||
protocol Test: Actor {
|
||||
func test() async
|
||||
nonisolated var test2: String
|
||||
}
|
||||
"""
|
||||
|
||||
testFormatting(for: input, rule: .modifierOrder)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user