mirror of
https://github.com/nicklockwood/SwiftFormat.git
synced 2026-05-17 10:30:35 +00:00
107 lines
3.6 KiB
Swift
107 lines
3.6 KiB
Swift
//
|
|
// RedundantNilInit.swift
|
|
// SwiftFormat
|
|
//
|
|
// Created by Nick Lockwood on 12/5/16.
|
|
// Copyright © 2024 Nick Lockwood. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public extension FormatRule {
|
|
/// Remove or insert redundant `= nil` initialization for Optional properties
|
|
static let redundantNilInit = FormatRule(
|
|
help: "Remove/insert redundant `nil` default value (Optional vars are nil by default).",
|
|
options: ["nil-init"]
|
|
) { formatter in
|
|
let declarations = formatter.parseDeclarations()
|
|
declarations.forEachRecursiveDeclaration { declaration in
|
|
// Only process var declarations
|
|
guard declaration.keyword == "var" else { return }
|
|
|
|
let varIndex = declaration.keywordIndex
|
|
|
|
// Check modifiers don't include `lazy` or property wrappers
|
|
if declaration.modifiers.contains(where: {
|
|
$0 == "lazy" || ($0 != "@objc" && $0.isAttribute)
|
|
}) {
|
|
return
|
|
}
|
|
|
|
// Preserve as-is in result builders
|
|
if formatter.isInResultBuilder(at: varIndex) {
|
|
return
|
|
}
|
|
|
|
if let parentType = declaration.parentType {
|
|
// Check if this is in a Codable type
|
|
if parentType.conformances.contains(where: {
|
|
["Codable", "Decodable"].contains($0.conformance.string)
|
|
}) {
|
|
return
|
|
}
|
|
|
|
// Preserve the value if the struct has a synthesized memberwise init
|
|
// before Swift 5.2
|
|
if parentType.keyword == "struct",
|
|
formatter.index(of: .keyword("init"), after: parentType.openBraceIndex) == nil,
|
|
formatter.options.swiftVersion < "5.2"
|
|
{
|
|
return
|
|
}
|
|
}
|
|
|
|
guard let propertyDeclaration = formatter.parsePropertyDeclaration(atIntroducerIndex: varIndex),
|
|
let type = propertyDeclaration.type,
|
|
type.isOptionalType
|
|
else { return }
|
|
|
|
switch formatter.options.nilInit {
|
|
case .remove:
|
|
// Remove `= nil` if it exists
|
|
if let valueInfo = propertyDeclaration.value,
|
|
formatter.tokens[valueInfo.expressionRange] == [.identifier("nil")]
|
|
{
|
|
// Remove from the space before = to the end of the value
|
|
let startIndex = formatter.index(of: .nonSpaceOrCommentOrLinebreak, before: valueInfo.assignmentIndex, if: { !$0.isSpaceOrCommentOrLinebreak }) ?? valueInfo.assignmentIndex - 1
|
|
formatter.removeTokens(in: startIndex + 1 ... valueInfo.expressionRange.upperBound)
|
|
}
|
|
|
|
case .insert:
|
|
// Insert `= nil` if it doesn't exist and this is a stored property
|
|
if propertyDeclaration.value == nil, declaration.isStoredProperty {
|
|
let tokens: [Token] = [.space(" "), .operator("=", .infix), .space(" "), .identifier("nil")]
|
|
formatter.insert(tokens, at: type.range.upperBound + 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
} examples: {
|
|
"""
|
|
`--nil-init remove`
|
|
|
|
```diff
|
|
- var foo: Int? = nil
|
|
+ var foo: Int?
|
|
```
|
|
|
|
```diff
|
|
// doesn't apply to `let` properties
|
|
let foo: Int? = nil
|
|
```
|
|
|
|
```diff
|
|
// doesn't affect non-nil initialization
|
|
var foo: Int? = 0
|
|
```
|
|
|
|
`--nil-init insert`
|
|
|
|
```diff
|
|
- var foo: Int?
|
|
+ var foo: Int? = nil
|
|
```
|
|
"""
|
|
}
|
|
}
|