Skip to content

Commit 1c960a9

Browse files
committed
Consolidate some fairly specialized helpers.
These were only used in one place and have implementations that are pretty specific to just the calling rule, so move them side-by-side with that rule and make them file-private.
1 parent c3d4e7e commit 1c960a9

5 files changed

+109
-270
lines changed

Sources/SwiftFormat/Core/AddModifierRewriter.swift

-183
This file was deleted.

Sources/SwiftFormat/Core/ModifierListSyntax+Convenience.swift

-27
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ extension DeclModifierListSyntax {
4646
}
4747
}
4848

49-
5049
/// Returns a copy of the modifier list with any of the modifiers in the given set removed.
5150
func removing(anyOf keywords: Set<Keyword>) -> DeclModifierListSyntax {
5251
return filter {
@@ -56,30 +55,4 @@ extension DeclModifierListSyntax {
5655
}
5756
}
5857
}
59-
60-
/// Inserts the given modifier into the list at a specific index.
61-
///
62-
/// If the modifier is being inserted at the front of the list, the current front element's
63-
/// leading trivia will be moved to the new element to preserve any leading comments and newlines.
64-
mutating func triviaPreservingInsert(
65-
_ modifier: DeclModifierSyntax, at index: SyntaxChildrenIndex
66-
) {
67-
var modifier = modifier
68-
modifier.trailingTrivia = [.spaces(1)]
69-
70-
guard index == self.startIndex else {
71-
self.insert(modifier, at: index)
72-
return
73-
}
74-
guard var firstMod = first, let firstTok = firstMod.firstToken(viewMode: .sourceAccurate) else {
75-
self.insert(modifier, at: index)
76-
return
77-
}
78-
79-
modifier.leadingTrivia = firstTok.leadingTrivia
80-
firstMod.leadingTrivia = []
81-
firstMod.trailingTrivia = [.spaces(1)]
82-
self[self.startIndex] = firstMod
83-
self.insert(modifier, at: self.startIndex)
84-
}
8558
}

Sources/SwiftFormat/Core/VarDeclSyntax+Convenience.swift

-41
This file was deleted.

Sources/SwiftFormat/Rules/NoAccessLevelOnExtensionDeclaration.swift

+80-19
Original file line numberDiff line numberDiff line change
@@ -71,40 +71,35 @@ public final class NoAccessLevelOnExtensionDeclaration: SyntaxFormatRule {
7171

7272
// Adds given keyword to all members in declaration block
7373
private func addMemberAccessKeyword(
74-
_ keyword: DeclModifierSyntax,
74+
_ modifier: DeclModifierSyntax,
7575
toMembersIn memberBlock: MemberBlockSyntax
7676
) -> (MemberBlockItemListSyntax, [Finding.Note]) {
7777
var newMembers: [MemberBlockItemSyntax] = []
7878
var notes: [Finding.Note] = []
7979

80-
var formattedKeyword = keyword
81-
formattedKeyword.leadingTrivia = []
82-
8380
for memberItem in memberBlock.members {
84-
let member = memberItem.decl
81+
let decl = memberItem.decl
8582
guard
86-
let modifiers = member.asProtocol(WithModifiersSyntax.self)?.modifiers,
87-
// addModifier relocates trivia for any token(s) displaced by the new modifier.
88-
let newDecl = addModifier(declaration: member, modifierKeyword: formattedKeyword)
89-
.as(DeclSyntax.self)
83+
let modifiers = decl.asProtocol(WithModifiersSyntax.self)?.modifiers,
84+
modifiers.accessLevelModifier == nil
9085
else {
9186
newMembers.append(memberItem)
9287
continue
9388
}
9489

90+
// Create a note associated with each declaration that needs to have an access level modifier
91+
// added to it.
92+
notes.append(Finding.Note(
93+
message: .addModifierToExtensionMember(keyword: modifier.name.text),
94+
location:
95+
Finding.Location(decl.startLocation(converter: context.sourceLocationConverter))
96+
))
97+
9598
var newItem = memberItem
96-
newItem.decl = newDecl
99+
newItem.decl = applyingAccessModifierIfNone(modifier, to: decl)
97100
newMembers.append(newItem)
98-
99-
// If it already had an explicit access modifier, don't leave a note.
100-
if modifiers.accessLevelModifier == nil {
101-
notes.append(Finding.Note(
102-
message: .addModifierToExtensionMember(keyword: formattedKeyword.name.text),
103-
location:
104-
Finding.Location(member.startLocation(converter: context.sourceLocationConverter))
105-
))
106-
}
107101
}
102+
108103
return (MemberBlockItemListSyntax(newMembers), notes)
109104
}
110105
}
@@ -129,3 +124,69 @@ extension Finding.Message {
129124
"add '\(keyword)' access modifier to this declaration"
130125
}
131126
}
127+
128+
/// Adds `modifier` to `decl` if it doesn't already have an explicit access level modifier and
129+
/// returns the new declaration.
130+
///
131+
/// If `decl` already has an access level modifier, it is returned unchanged.
132+
private func applyingAccessModifierIfNone(
133+
_ modifier: DeclModifierSyntax,
134+
to decl: DeclSyntax
135+
) -> DeclSyntax {
136+
switch Syntax(decl).as(SyntaxEnum.self) {
137+
case .actorDecl(let actorDecl):
138+
return applyingAccessModifierIfNone(modifier, to: actorDecl, declKeywordKeyPath: \.actorKeyword)
139+
case .classDecl(let classDecl):
140+
return applyingAccessModifierIfNone(modifier, to: classDecl, declKeywordKeyPath: \.classKeyword)
141+
case .enumDecl(let enumDecl):
142+
return applyingAccessModifierIfNone(modifier, to: enumDecl, declKeywordKeyPath: \.enumKeyword)
143+
case .initializerDecl(let initDecl):
144+
return applyingAccessModifierIfNone(modifier, to: initDecl, declKeywordKeyPath: \.initKeyword)
145+
case .functionDecl(let funcDecl):
146+
return applyingAccessModifierIfNone(modifier, to: funcDecl, declKeywordKeyPath: \.funcKeyword)
147+
case .structDecl(let structDecl):
148+
return applyingAccessModifierIfNone(
149+
modifier, to: structDecl, declKeywordKeyPath: \.structKeyword)
150+
case .subscriptDecl(let subscriptDecl):
151+
return applyingAccessModifierIfNone(
152+
modifier, to: subscriptDecl, declKeywordKeyPath: \.subscriptKeyword)
153+
case .typeAliasDecl(let typeAliasDecl):
154+
return applyingAccessModifierIfNone(
155+
modifier, to: typeAliasDecl, declKeywordKeyPath: \.typealiasKeyword)
156+
case .variableDecl(let varDecl):
157+
return applyingAccessModifierIfNone(
158+
modifier, to: varDecl, declKeywordKeyPath: \.bindingSpecifier)
159+
default:
160+
return decl
161+
}
162+
}
163+
164+
private func applyingAccessModifierIfNone<Decl: DeclSyntaxProtocol & WithModifiersSyntax>(
165+
_ modifier: DeclModifierSyntax,
166+
to decl: Decl,
167+
declKeywordKeyPath: WritableKeyPath<Decl, TokenSyntax>
168+
) -> DeclSyntax {
169+
// If there's already an access modifier among the modifier list, bail out.
170+
guard decl.modifiers.accessLevelModifier == nil else { return DeclSyntax(decl) }
171+
172+
var result = decl
173+
var modifier = modifier
174+
modifier.trailingTrivia = [.spaces(1)]
175+
176+
guard var firstModifier = decl.modifiers.first else {
177+
// If there are no modifiers at all, add the one being requested, moving the leading trivia
178+
// from the decl keyword to that modifier (to preserve leading comments, newlines, etc.).
179+
modifier.leadingTrivia = decl[keyPath: declKeywordKeyPath].leadingTrivia
180+
result[keyPath: declKeywordKeyPath].leadingTrivia = []
181+
result.modifiers = .init([modifier])
182+
return DeclSyntax(result)
183+
}
184+
185+
// Otherwise, insert the modifier at the front of the modifier list, moving the (original) first
186+
// modifier's leading trivia to the new one (to preserve leading comments, newlines, etc.).
187+
modifier.leadingTrivia = firstModifier.leadingTrivia
188+
firstModifier.leadingTrivia = []
189+
result.modifiers[result.modifiers.startIndex] = firstModifier
190+
result.modifiers.insert(modifier, at: result.modifiers.startIndex)
191+
return DeclSyntax(result)
192+
}

0 commit comments

Comments
 (0)