mirror of
https://github.com/nicklockwood/SwiftFormat.git
synced 2026-05-17 10:30:35 +00:00
Update redundantSelf rule to support functions with no body (#2315)
This commit is contained in:
@@ -2924,6 +2924,7 @@ extension Formatter {
|
||||
usingDynamicLookup: Bool,
|
||||
classOrStatic: Bool)
|
||||
{
|
||||
let funcKeywordIndex = index
|
||||
let startToken = tokens[index]
|
||||
var localNames = localNames
|
||||
guard let startIndex = self.index(of: .startOfScope("("), after: index),
|
||||
@@ -2952,23 +2953,38 @@ extension Formatter {
|
||||
}
|
||||
index = self.index(of: .delimiter(","), after: index) ?? endIndex
|
||||
}
|
||||
guard let bodyStartIndex = self.index(after: endIndex, where: {
|
||||
switch $0 {
|
||||
case .startOfScope("{"): // What we're looking for
|
||||
return true
|
||||
case .keyword("throws"),
|
||||
.keyword("rethrows"),
|
||||
.keyword("where"),
|
||||
.keyword("is"),
|
||||
.keyword("repeat"):
|
||||
return false // Keep looking
|
||||
case .keyword where !$0.isAttribute:
|
||||
return true // Not valid between end of arguments and start of body
|
||||
default:
|
||||
return false // Keep looking
|
||||
|
||||
let bodyStartIndex: Int
|
||||
if let functionDeclaration = parseFunctionDeclaration(keywordIndex: funcKeywordIndex) {
|
||||
guard let validBodyStartIndex = functionDeclaration.bodyRange?.lowerBound else {
|
||||
// Ensure we move the `redundantSelf` work index to the end of the function declaration
|
||||
index = functionDeclaration.range.upperBound
|
||||
return
|
||||
}
|
||||
}), tokens[bodyStartIndex] == .startOfScope("{") else {
|
||||
return
|
||||
|
||||
bodyStartIndex = validBodyStartIndex
|
||||
} else {
|
||||
// If `parseFunctionDeclaration` fails due to some unsupported pattern, use a more permissive search.
|
||||
guard let validBodyStartIndex = self.index(after: endIndex, where: {
|
||||
switch $0 {
|
||||
case .startOfScope("{"): // What we're looking for
|
||||
return true
|
||||
case .keyword("throws"),
|
||||
.keyword("rethrows"),
|
||||
.keyword("where"),
|
||||
.keyword("is"),
|
||||
.keyword("repeat"):
|
||||
return false // Keep looking
|
||||
case .keyword where !$0.isAttribute:
|
||||
return true // Not valid between end of arguments and start of body
|
||||
default:
|
||||
return false // Keep looking
|
||||
}
|
||||
}), tokens[validBodyStartIndex] == .startOfScope("{") else {
|
||||
return
|
||||
}
|
||||
|
||||
bodyStartIndex = validBodyStartIndex
|
||||
}
|
||||
|
||||
// Functions defined inside closures with `[weak self]` captures can
|
||||
|
||||
@@ -3156,7 +3156,7 @@ extension Formatter {
|
||||
/// The range of the `where` clause if present
|
||||
let whereClauseRange: ClosedRange<Int>?
|
||||
/// The range of the function body (`{ ... }`) if present.
|
||||
/// A protocol method requirement doesn't have a body.
|
||||
/// A protocol method requirement, or a function with a `@_silgen` attribute, doesn't have a body.
|
||||
let bodyRange: ClosedRange<Int>?
|
||||
|
||||
/// The full range of this declaration
|
||||
|
||||
@@ -1180,6 +1180,9 @@ final class ParsingHelpersTests: XCTestCase {
|
||||
private(set)
|
||||
var instanceVar = "test" // trailing comment
|
||||
|
||||
@_silgen_name("__MARKER_functionWithNoBody")
|
||||
func functionWithNoBody(_ x: String) -> Int?
|
||||
|
||||
@objc
|
||||
private var computed: String {
|
||||
get {
|
||||
@@ -1304,6 +1307,9 @@ final class ParsingHelpersTests: XCTestCase {
|
||||
private(set)
|
||||
var instanceVar = "test" // trailing comment
|
||||
|
||||
@_silgen_name("__MARKER_functionWithNoBody")
|
||||
func functionWithNoBody(_ x: String) -> Int?
|
||||
|
||||
@objc
|
||||
private var computed: String {
|
||||
get {
|
||||
@@ -1363,6 +1369,16 @@ final class ParsingHelpersTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual(
|
||||
declarations[7].body?[2].tokens.string,
|
||||
"""
|
||||
@_silgen_name(\"__MARKER_functionWithNoBody\")
|
||||
func functionWithNoBody(_ x: String) -> Int?
|
||||
|
||||
|
||||
"""
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
declarations[7].body?[3].tokens.string,
|
||||
"""
|
||||
@objc
|
||||
private var computed: String {
|
||||
|
||||
@@ -2973,6 +2973,35 @@ final class RedundantSelfTests: XCTestCase {
|
||||
testFormatting(for: input, rule: .redundantSelf, options: options)
|
||||
}
|
||||
|
||||
func testFunctionWithNoBodyFollowedByStaticFunction() {
|
||||
let input = """
|
||||
struct Foo {
|
||||
let foo: String
|
||||
|
||||
@_silgen_name("__MARKER_doIt")
|
||||
func doIt(_ x: String) -> Int?
|
||||
|
||||
static func bar() {
|
||||
print(self.foo)
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
let output = """
|
||||
struct Foo {
|
||||
let foo: String
|
||||
|
||||
@_silgen_name("__MARKER_doIt")
|
||||
func doIt(_ x: String) -> Int?
|
||||
|
||||
static func bar() {
|
||||
print(foo)
|
||||
}
|
||||
}
|
||||
"""
|
||||
testFormatting(for: input, output, rule: .redundantSelf)
|
||||
}
|
||||
|
||||
func testNoInsertSelfBeforeSet() {
|
||||
let input = """
|
||||
class Foo {
|
||||
|
||||
Reference in New Issue
Block a user