mirror of
https://github.com/nicklockwood/SwiftFormat.git
synced 2026-06-16 10:34:34 +00:00
108 lines
3.8 KiB
Swift
108 lines
3.8 KiB
Swift
//
|
|
// RedundantObjc.swift
|
|
// SwiftFormat
|
|
//
|
|
// Created by Nick Lockwood on 1/30/19.
|
|
// Copyright © 2024 Nick Lockwood. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public extension FormatRule {
|
|
/// Remove redundant @objc annotation
|
|
static let redundantObjc = FormatRule(
|
|
help: "Remove redundant `@objc` annotations."
|
|
) { formatter in
|
|
let objcAttributes = [
|
|
"@IBOutlet", "@IBAction", "@IBSegueAction",
|
|
"@IBDesignable", "@IBInspectable", "@GKInspectable",
|
|
"@NSManaged",
|
|
]
|
|
|
|
formatter.forEach(.keyword("@objc")) { i, _ in
|
|
guard formatter.next(.nonSpaceOrCommentOrLinebreak, after: i) != .startOfScope("(") else {
|
|
return
|
|
}
|
|
var index = i
|
|
loop: while var nextIndex = formatter.index(of: .nonSpaceOrCommentOrLinebreak, after: index) {
|
|
switch formatter.tokens[nextIndex] {
|
|
case .keyword("class"), .keyword("actor"), .keyword("enum"),
|
|
// Not actually allowed currently, but: future-proofing!
|
|
.keyword("protocol"), .keyword("struct"):
|
|
return
|
|
case .keyword("private"), .keyword("fileprivate"):
|
|
if formatter.next(.nonSpaceOrComment, after: nextIndex) == .startOfScope("(") {
|
|
break
|
|
}
|
|
// Can't safely remove objc from private members
|
|
return
|
|
case let token where token.isAttribute:
|
|
if let startIndex = formatter.index(of: .startOfScope("("), after: nextIndex),
|
|
let endIndex = formatter.index(of: .endOfScope(")"), after: startIndex)
|
|
{
|
|
nextIndex = endIndex
|
|
}
|
|
case let token:
|
|
guard formatter.isModifier(at: nextIndex) else {
|
|
break loop
|
|
}
|
|
}
|
|
index = nextIndex
|
|
}
|
|
if formatter.last(.nonSpaceOrCommentOrLinebreak, before: i, if: {
|
|
$0.isAttribute && objcAttributes.contains($0.string)
|
|
}) != nil || formatter.next(.nonSpaceOrCommentOrLinebreak, after: i, if: {
|
|
$0.isAttribute && objcAttributes.contains($0.string)
|
|
}) != nil {
|
|
formatter.removeAttribute(at: i)
|
|
return
|
|
}
|
|
guard let scopeStart = formatter.index(of: .startOfScope("{"), before: i),
|
|
let keywordIndex = formatter.index(of: .keyword, before: scopeStart)
|
|
else {
|
|
return
|
|
}
|
|
switch formatter.tokens[keywordIndex] {
|
|
case .keyword("class"), .keyword("actor"):
|
|
if formatter.modifiersForDeclaration(at: keywordIndex, contains: "@objcMembers") {
|
|
formatter.removeAttribute(at: i)
|
|
}
|
|
case .keyword("extension"):
|
|
if formatter.modifiersForDeclaration(at: keywordIndex, contains: "@objc") {
|
|
formatter.removeAttribute(at: i)
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
} examples: {
|
|
"""
|
|
```diff
|
|
- @objc @IBOutlet var label: UILabel!
|
|
+ @IBOutlet var label: UILabel!
|
|
```
|
|
|
|
```diff
|
|
- @IBAction @objc func goBack() {}
|
|
+ @IBAction func goBack() {}
|
|
```
|
|
|
|
```diff
|
|
- @objc @NSManaged private var foo: String?
|
|
+ @NSManaged private var foo: String?
|
|
```
|
|
"""
|
|
}
|
|
}
|
|
|
|
extension Formatter {
|
|
func removeAttribute(at i: Int) {
|
|
removeToken(at: i)
|
|
if token(at: i)?.isSpace == true {
|
|
removeToken(at: i)
|
|
} else if token(at: i - 1)?.isSpace == true {
|
|
removeToken(at: i - 1)
|
|
}
|
|
}
|
|
}
|