Correctly handle init accessor

This commit is contained in:
Nick Lockwood
2024-06-09 18:47:04 +01:00
parent eeb37b50ac
commit e51ce8a47e
5 changed files with 88 additions and 8 deletions
+20 -5
View File
@@ -2870,7 +2870,7 @@ extension Formatter {
["static", "class"].contains(string)
})
if let name = name, classOrStatic || !staticSelf {
processAccessors(["get", "set", "willSet", "didSet"], for: name,
processAccessors(["get", "set", "willSet", "didSet", "init"], for: name,
at: &index, localNames: localNames, members: members,
typeStack: &typeStack, closureStack: &closureStack,
membersByType: &membersByType,
@@ -3160,8 +3160,15 @@ extension Formatter {
assert(tokens[index] == .startOfScope("{"))
var foundAccessors = false
var localNames = localNames
while let nextIndex = self.index(of: .nonSpaceOrCommentOrLinebreak, after: index, if: {
if case let .identifier(name) = $0, names.contains(name) { return true } else { return false }
while var nextIndex = self.index(of: .nonSpaceOrCommentOrLinebreak, after: index, if: {
switch $0 {
case .keyword where $0.isAttribute:
return true
case let .identifier(name), let .keyword(name):
return names.contains(name)
default:
return false
}
}), let startIndex = self.index(of: .startOfScope("{"), after: nextIndex) {
foundAccessors = true
index = startIndex + 1
@@ -3170,10 +3177,18 @@ extension Formatter {
}), let varToken = next(.identifier, after: parenStart) {
localNames.insert(varToken.unescaped())
} else {
switch tokens[nextIndex].string {
var token = tokens[nextIndex]
while token.isAttribute,
let endIndex = endOfAttribute(at: nextIndex),
let index = self.index(of: .nonSpaceOrCommentOrLinebreak, after: endIndex)
{
nextIndex = index
token = tokens[nextIndex]
}
switch token.string {
case "get":
localNames.insert(name)
case "set":
case "set", "init":
localNames.insert(name)
localNames.insert("newValue")
case "willSet":
+1 -1
View File
@@ -994,7 +994,7 @@ private struct Inference {
prevIndex -= 1
}
if let name = name {
processAccessors(["get", "set", "willSet", "didSet"], for: name,
processAccessors(["get", "set", "willSet", "didSet", "init"], for: name,
at: &index, localNames: localNames, members: members,
typeStack: &typeStack, membersByType: &membersByType,
classMembersByType: &classMembersByType,
+2 -2
View File
@@ -668,7 +668,7 @@ extension Formatter {
func isAccessorKeyword(at i: Int, checkKeyword: Bool = true) -> Bool {
guard !checkKeyword ||
["get", "set", "willSet", "didSet"].contains(token(at: i)?.string ?? ""),
["get", "set", "willSet", "didSet", "init"].contains(token(at: i)?.string ?? ""),
var prevIndex = index(of: .nonSpaceOrCommentOrLinebreak, before: i)
else {
return false
@@ -1120,7 +1120,7 @@ extension Formatter {
return true
}
return false
case "get", "set", "willSet", "didSet":
case "get", "set", "willSet", "didSet", "init":
return isAccessorKeyword(at: i, checkKeyword: false)
case "actor":
if last(.nonSpaceOrCommentOrLinebreak, before: i)?.isOperator(ofType: .infix) == true {
+21
View File
@@ -625,6 +625,18 @@ class ParsingHelpersTests: XCTestCase {
XCTAssert(formatter.isAccessorKeyword(at: 34))
}
func testInit() {
let formatter = Formatter(tokenize("""
var foo: Int {
init {}
get {}
set {}
}
"""))
XCTAssert(formatter.isAccessorKeyword(at: 10))
XCTAssert(formatter.isAccessorKeyword(at: 16))
}
func testNotGetter() {
let formatter = Formatter(tokenize("""
func foo() {
@@ -644,6 +656,15 @@ class ParsingHelpersTests: XCTestCase {
XCTAssert(formatter.isAccessorKeyword(at: 10, checkKeyword: false))
}
func testNotSetterInit() {
let formatter = Formatter(tokenize("""
class Foo {
init() { print("") }
}
"""))
XCTAssertFalse(formatter.isAccessorKeyword(at: 7))
}
// MARK: isEnumCase
func testIsEnumCase() {
+44
View File
@@ -6230,6 +6230,50 @@ class RedundancyTests: RulesTests {
testFormatting(for: input, rule: FormatRules.redundantSelf, options: options)
}
func testPropertyInitNotInterpretedAsTypeInit() {
let input = """
struct MyStruct {
private var __myVar: String
var myVar: String {
@storageRestrictions(initializes: __myVar)
init(initialValue) {
__myVar = initialValue
}
set {
__myVar = newValue
}
get {
__myVar
}
}
}
"""
let options = FormatOptions(explicitSelf: .initOnly)
testFormatting(for: input, rule: FormatRules.redundantSelf, options: options)
}
func testPropertyInitNotInterpretedAsTypeInit2() {
let input = """
struct MyStruct {
private var __myVar: String
var myVar: String {
@storageRestrictions(initializes: __myVar)
init {
__myVar = newValue
}
set {
__myVar = newValue
}
get {
__myVar
}
}
}
"""
let options = FormatOptions(explicitSelf: .initOnly)
testFormatting(for: input, rule: FormatRules.redundantSelf, options: options)
}
// parsing bugs
func testSelfRemovalParsingBug() {