Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjustments for refactoring of representation of Accessors in SwiftSyntax #576

Merged
merged 1 commit into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 39 additions & 20 deletions Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ import SwiftFormatCore
import SwiftOperators
import SwiftSyntax

fileprivate extension AccessorBlockSyntax {
/// Assuming that the accessor only contains an implicit getter (i.e. no
/// `get` or `set`), return the code block items in that getter.
var getterCodeBlockItems: CodeBlockItemListSyntax {
guard case .getter(let codeBlockItemList) = self.accessors else {
preconditionFailure("AccessorBlock has an accessor list and not just a getter")
}
return codeBlockItemList
}
}

/// Visits the nodes of a syntax tree and constructs a linear stream of formatting tokens that
/// tell the pretty printer how the source text should be laid out.
fileprivate final class TokenStreamCreator: SyntaxVisitor {
Expand Down Expand Up @@ -442,12 +453,16 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {

before(node.returnClause.firstToken(viewMode: .sourceAccurate), tokens: .break)

if let accessorOrCodeBlock = node.accessors {
switch accessorOrCodeBlock {
case .accessors(let accessorBlock):
arrangeBracesAndContents(of: accessorBlock)
case .getter(let codeBlock):
arrangeBracesAndContents(of: codeBlock, contentsKeyPath: \.statements)
if let accessorBlock = node.accessorBlock {
switch accessorBlock.accessors {
case .accessors(let accessors):
arrangeBracesAndContents(
leftBrace: accessorBlock.leftBrace,
accessors: accessors,
rightBrace: accessorBlock.rightBrace
)
case .getter:
arrangeBracesAndContents(of: accessorBlock, contentsKeyPath: \.getterCodeBlockItems)
}
}

Expand Down Expand Up @@ -2160,12 +2175,16 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
}
}

if let accessorOrCodeBlock = node.accessors {
switch accessorOrCodeBlock {
case .accessors(let accessorBlock):
arrangeBracesAndContents(of: accessorBlock)
case .getter(let codeBlock):
arrangeBracesAndContents(of: codeBlock, contentsKeyPath: \.statements)
if let accessorBlock = node.accessorBlock {
switch accessorBlock.accessors {
case .accessors(let accessors):
arrangeBracesAndContents(
leftBrace: accessorBlock.leftBrace,
accessors: accessors,
rightBrace: accessorBlock.rightBrace
)
case .getter:
arrangeBracesAndContents(of: accessorBlock, contentsKeyPath: \.getterCodeBlockItems)
}
} else if let trailingComma = node.trailingComma {
// If this is one of multiple comma-delimited bindings, move any pending close breaks to
Expand Down Expand Up @@ -2960,24 +2979,24 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
/// Applies consistent formatting to the braces and contents of the given node.
///
/// - Parameter node: An `AccessorBlockSyntax` node.
private func arrangeBracesAndContents(of node: AccessorBlockSyntax) {
private func arrangeBracesAndContents(leftBrace: TokenSyntax, accessors: AccessorDeclListSyntax, rightBrace: TokenSyntax) {
// If the collection is empty, then any comments that might be present in the block must be
// leading trivia of the right brace.
let commentPrecedesRightBrace = node.rightBrace.leadingTrivia.numberOfComments > 0
let commentPrecedesRightBrace = rightBrace.leadingTrivia.numberOfComments > 0
// We can't use `count` here because it also includes missing children. Instead, we get an
// iterator and check if it returns `nil` immediately.
var accessorsIterator = node.accessors.makeIterator()
var accessorsIterator = accessors.makeIterator()
let areAccessorsEmpty = accessorsIterator.next() == nil
let bracesAreCompletelyEmpty = areAccessorsEmpty && !commentPrecedesRightBrace

before(node.leftBrace, tokens: .break(.reset, size: 1))
before(leftBrace, tokens: .break(.reset, size: 1))

if !bracesAreCompletelyEmpty {
after(node.leftBrace, tokens: .break(.open, size: 1), .open)
before(node.rightBrace, tokens: .break(.close, size: 1), .close)
after(leftBrace, tokens: .break(.open, size: 1), .open)
before(rightBrace, tokens: .break(.close, size: 1), .close)
} else {
after(node.leftBrace, tokens: .break(.open, size: 0))
before(node.rightBrace, tokens: .break(.close, size: 0))
after(leftBrace, tokens: .break(.open, size: 0))
before(rightBrace, tokens: .break(.close, size: 0))
}
}

Expand Down
7 changes: 3 additions & 4 deletions Sources/SwiftFormatRules/UseShorthandTypeNames.swift
Original file line number Diff line number Diff line change
Expand Up @@ -499,19 +499,18 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
/// Returns true if the given pattern binding represents a stored property/variable (as opposed to
/// a computed property/variable).
private func isStoredProperty(_ node: PatternBindingSyntax) -> Bool {
guard let accessor = node.accessors else {
guard let accessor = node.accessorBlock else {
// If it has no accessors at all, it is definitely a stored property.
return true
}

guard let accessorBlock = accessor.as(AccessorBlockSyntax.self) else {
guard case .accessors(let accessors) = accessor.accessors else {
// If the accessor isn't an `AccessorBlockSyntax`, then it is a `CodeBlockSyntax`; i.e., the
// accessor an implicit `get`. So, it is definitely not a stored property.
assert(accessor.is(CodeBlockSyntax.self))
return false
}

for accessorDecl in accessorBlock.accessors {
for accessorDecl in accessors {
// Look for accessors that indicate that this is a computed property. If none are found, then
// it is a stored property (e.g., having only observers like `willSet/didSet`).
switch accessorDecl.accessorSpecifier.tokenKind {
Expand Down
14 changes: 7 additions & 7 deletions Sources/SwiftFormatRules/UseSingleLinePropertyGetter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ public final class UseSingleLinePropertyGetter: SyntaxFormatRule {

public override func visit(_ node: PatternBindingSyntax) -> PatternBindingSyntax {
guard
let accessorBlock = node.accessors?.as(AccessorBlockSyntax.self),
let acc = accessorBlock.accessors.first,
let accessorBlock = node.accessorBlock,
case .accessors(let accessors) = accessorBlock.accessors,
let acc = accessors.first,
let body = acc.body,
accessorBlock.accessors.count == 1,
accessors.count == 1,
acc.accessorSpecifier.tokenKind == .keyword(.get),
acc.attributes == nil,
acc.modifier == nil,
Expand All @@ -34,10 +35,9 @@ public final class UseSingleLinePropertyGetter: SyntaxFormatRule {

diagnose(.removeExtraneousGetBlock, on: acc)

let newBlock = CodeBlockSyntax(
leftBrace: accessorBlock.leftBrace, statements: body.statements,
rightBrace: accessorBlock.rightBrace)
return node.with(\.accessors, .getter(newBlock))
var result = node
result.accessorBlock?.accessors = .getter(body.statements)
return result
}
}

Expand Down