1
+
1
2
import Core
2
3
import Foundation
3
4
import SwiftSyntax
@@ -12,5 +13,97 @@ import SwiftSyntax
12
13
///
13
14
/// - SeeAlso: https://google.github.io/swift#enum-cases
14
15
public final class FullyIndirectEnum : SyntaxFormatRule {
16
+ public override func visit( _ node: EnumDeclSyntax ) -> DeclSyntax {
17
+
18
+ let enumMembers = node. members. members
19
+ guard allAreIndirectCases ( members: enumMembers) else { return node }
20
+ diagnose ( . reassignIndirectKeyword( name: node. identifier. text) , on: node. identifier)
21
+
22
+ // Removes 'indirect' keyword from cases, reformats
23
+ var newMembers : [ MemberDeclListItemSyntax ] = [ ]
24
+ for member in enumMembers {
25
+ if let caseMember = member. decl as? EnumCaseDeclSyntax {
26
+ guard let caseModifiers = caseMember. modifiers else { continue }
27
+ guard let firstModifier = caseModifiers. first else { continue }
28
+ let newCase = caseMember. withModifiers ( removeIndirectModifier ( curModifiers: caseModifiers) )
29
+ let formattedCase = formatCase ( unformattedCase: newCase,
30
+ leadingTrivia: firstModifier. leadingTrivia)
31
+ let newMember = SyntaxFactory . makeMemberDeclListItem ( decl: formattedCase, semicolon: nil )
32
+ newMembers. append ( newMember)
33
+ } else {
34
+ newMembers. append ( member)
35
+ }
36
+ }
37
+
38
+ let members = SyntaxFactory . makeMemberDeclList ( newMembers)
39
+ let newMemberBlock = SyntaxFactory . makeMemberDeclBlock ( leftBrace: node. members. leftBrace,
40
+ members: members,
41
+ rightBrace: node. members. rightBrace)
42
+
43
+ // Format indirect keyword and following token, if necessary
44
+ guard let firstTok = node. firstToken else { return node }
45
+ var leadingTrivia : Trivia = [ ]
46
+ var newDecl = node
47
+ if firstTok. tokenKind == . enumKeyword {
48
+ leadingTrivia = firstTok. leadingTrivia
49
+ newDecl = replaceTrivia ( on: node,
50
+ token: node. firstToken,
51
+ leadingTrivia: [ ] ) as! EnumDeclSyntax
52
+ }
53
+
54
+ let newModifier = SyntaxFactory . makeDeclModifier (
55
+ name: SyntaxFactory . makeIdentifier ( " indirect " ,
56
+ leadingTrivia: leadingTrivia,
57
+ trailingTrivia: . spaces( 1 ) ) ,
58
+ detailLeftParen: nil , detail: nil , detailRightParen: nil )
59
+
60
+ return newDecl. addModifier ( newModifier) . withMembers ( newMemberBlock)
61
+ }
62
+
63
+ // Determines if all given cases are indirect
64
+ func allAreIndirectCases( members: MemberDeclListSyntax ) -> Bool {
65
+ for member in members {
66
+ if let caseMember = member. decl as? EnumCaseDeclSyntax {
67
+ guard let caseModifiers = caseMember. modifiers else { return false }
68
+ if isIndirectCase ( modifiers: caseModifiers) { continue }
69
+ else { return false }
70
+ }
71
+ }
72
+ return true
73
+ }
74
+
75
+ func isIndirectCase( modifiers: ModifierListSyntax ) -> Bool {
76
+ for modifier in modifiers {
77
+ if modifier. name. tokenKind == . identifier( " indirect " ) { return true }
78
+ }
79
+ return false
80
+ }
81
+
82
+ func removeIndirectModifier( curModifiers: ModifierListSyntax ) -> ModifierListSyntax {
83
+ var newMods : [ DeclModifierSyntax ] = [ ]
84
+ for modifier in curModifiers {
85
+ if modifier. name. tokenKind != . identifier( " indirect " ) { newMods. append ( modifier) }
86
+ }
87
+ return SyntaxFactory . makeModifierList ( newMods)
88
+ }
89
+
90
+ // Transfers given leading trivia to the first token in the case declaration
91
+ func formatCase( unformattedCase: EnumCaseDeclSyntax ,
92
+ leadingTrivia: Trivia ? ) -> EnumCaseDeclSyntax {
93
+ if let modifiers = unformattedCase. modifiers, let first = modifiers. first {
94
+ return replaceTrivia ( on: unformattedCase,
95
+ token: first. firstToken,
96
+ leadingTrivia: leadingTrivia) as! EnumCaseDeclSyntax
97
+ } else {
98
+ return replaceTrivia ( on: unformattedCase,
99
+ token: unformattedCase. caseKeyword,
100
+ leadingTrivia: leadingTrivia) as! EnumCaseDeclSyntax
101
+ }
102
+ }
103
+ }
15
104
105
+ extension Diagnostic . Message {
106
+ static func reassignIndirectKeyword( name: String ) -> Diagnostic . Message {
107
+ return . init( . warning, " move 'indirect' to \( name) enum declaration " )
108
+ }
16
109
}
0 commit comments