Skip to content

Commit

Permalink
Refactor syntax node manipulation to use variable setters
Browse files Browse the repository at this point in the history
This commit replaces the use of 'with' method for syntax node manipulation in SwiftSyntax examples with direct variable setters for better clarity and readability.
  • Loading branch information
Matejkob committed Oct 12, 2023
1 parent fc58fc8 commit 144b9ff
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ private class AddOneToIntegerLiterals: SyntaxRewriter {
let int = Int(integerText)!

// Create a new integer literal token with `int + 1` as its text.
let newIntegerLiteralToken = token.with(\.tokenKind, .integerLiteral("\(int + 1)"))
var newIntegerLiteralToken = token
newIntegerLiteralToken.tokenKind = .integerLiteral("\(int + 1)")

// Return the new integer literal.
return newIntegerLiteralToken
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ extension DictionaryStorageMacro: MemberMacro {
providingMembersOf declaration: some DeclGroupSyntax,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
let storage: DeclSyntax = "var _storage: [String: Any] = [:]"
return [
storage.with(\.leadingTrivia, [.newlines(1), .spaces(2)])
]
var storage: DeclSyntax = "var _storage: [String: Any] = [:]"
storage.leadingTrivia = [.newlines(1), .spaces(2)]
return [storage]
}
}

Expand All @@ -41,14 +40,14 @@ extension DictionaryStorageMacro: MemberAttributeMacro {
return []
}

return [
AttributeSyntax(
attributeName: IdentifierTypeSyntax(
name: .identifier("DictionaryStorageProperty")
)
var attribute = AttributeSyntax(
attributeName: IdentifierTypeSyntax(
name: .identifier("DictionaryStorageProperty")
)
.with(\.leadingTrivia, [.newlines(1), .spaces(2)])
]
)
attribute.leadingTrivia = [.newlines(1), .spaces(2)]

return [attribute]
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public struct AddBlocker: ExpressionMacro {
_ node: InfixOperatorExprSyntax
) -> ExprSyntax {
// Identify any infix operator + in the tree.
if let binOp = node.operator.as(BinaryOperatorExprSyntax.self) {
if var binOp = node.operator.as(BinaryOperatorExprSyntax.self) {
if binOp.operator.text == "+" {
// Form the warning
let messageID = MessageID(domain: "silly", id: "addblock")
Expand Down Expand Up @@ -72,17 +72,12 @@ public struct AddBlocker: ExpressionMacro {
)
)

return ExprSyntax(
node.with(
\.operator,
ExprSyntax(
binOp.with(
\.operator,
binOp.operator.with(\.tokenKind, .binaryOperator("-"))
)
)
)
)
binOp.operator.tokenKind = .binaryOperator("-")

var node = node
node.operator = ExprSyntax(binOp)

return ExprSyntax(node)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ private func replaceFirstLabel(
of tuple: LabeledExprListSyntax,
with newLabel: String
) -> LabeledExprListSyntax {
guard let firstElement = tuple.first else {
guard var firstElement = tuple.first else {
return tuple
}

firstElement.label = .identifier(newLabel)
firstElement.colon = .colonToken()

var tuple = tuple
tuple[tuple.startIndex] =
firstElement
.with(\.label, .identifier(newLabel))
.with(\.colon, .colonToken())
tuple[tuple.startIndex] = firstElement
return tuple
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,22 @@ public struct MetaEnumMacro {
let parentParamName: TokenSyntax

init(node: AttributeSyntax, declaration: some DeclGroupSyntax, context: some MacroExpansionContext) throws {
guard let enumDecl = declaration.as(EnumDeclSyntax.self) else {
guard var enumDecl = declaration.as(EnumDeclSyntax.self) else {
throw DiagnosticsError(diagnostics: [
CaseMacroDiagnostic.notAnEnum(declaration).diagnose(at: Syntax(node))
])
}

parentTypeName = enumDecl.name.with(\.trailingTrivia, [])
enumDecl.name.trailingTrivia = []

parentTypeName = enumDecl.name

access = enumDecl.modifiers.first(where: \.isNeededAccessLevelModifier)

childCases = enumDecl.caseElements.map { parentCase in
parentCase.with(\.parameterClause, nil)
var parentCase = parentCase
parentCase.parameterClause = nil
return parentCase
}

parentParamName = context.makeUniqueName("parent")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,13 @@ public struct WrapStoredPropertiesMacro: MemberAttributeMacro {
throw CustomError.message("macro requires a string literal containing the name of an attribute")
}

return [
AttributeSyntax(
attributeName: IdentifierTypeSyntax(
name: .identifier(wrapperName.content.text)
)
var attribute = AttributeSyntax(
attributeName: IdentifierTypeSyntax(
name: .identifier(wrapperName.content.text)
)
.with(\.leadingTrivia, [.newlines(1), .spaces(2)])
]
)
attribute.leadingTrivia = [.newlines(1), .spaces(2)]
return [attribute]
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public struct AddAsyncMacro: PeerMacro {
) throws -> [DeclSyntax] {

// Only on functions at the moment.
guard let funcDecl = declaration.as(FunctionDeclSyntax.self) else {
guard var funcDecl = declaration.as(FunctionDeclSyntax.self) else {
throw CustomError.message("@addAsync only works on functions")
}

Expand All @@ -42,7 +42,9 @@ public struct AddAsyncMacro: PeerMacro {
}

// This only makes sense void functions
if funcDecl.signature.returnClause?.type.with(\.leadingTrivia, []).with(\.trailingTrivia, []).description != "Void" {
guard let returnIdentifier = funcDecl.signature.returnClause?.type.as(IdentifierTypeSyntax.self),
returnIdentifier.name.text == "Void"
else {
throw CustomError.message(
"@addAsync requires an function that returns void"
)
Expand All @@ -58,7 +60,9 @@ public struct AddAsyncMacro: PeerMacro {
}

// Completion handler needs to return Void
if completionHandlerParameter.returnClause.type.with(\.leadingTrivia, []).with(\.trailingTrivia, []).description != "Void" {
guard let returnIdentifier = completionHandlerParameter.returnClause.type.as(IdentifierTypeSyntax.self),
returnIdentifier.name.text == "Void"
else {
throw CustomError.message(
"@addAsync requires an function that has a completion handler that returns Void"
)
Expand All @@ -72,9 +76,11 @@ public struct AddAsyncMacro: PeerMacro {
// Remove completionHandler and comma from the previous parameter
var newParameterList = funcDecl.signature.parameterClause.parameters
newParameterList.removeLast()
let newParameterListLastParameter = newParameterList.last!
var newParameterListLastParameter = newParameterList.last!
newParameterList.removeLast()
newParameterList.append(newParameterListLastParameter.with(\.trailingTrivia, []).with(\.trailingComma, nil))
newParameterListLastParameter.trailingTrivia = []
newParameterListLastParameter.trailingComma = nil
newParameterList.append(newParameterListLastParameter)

// Drop the @addAsync attribute from the new declaration.
let newAttributeList = funcDecl.attributes.filter {
Expand Down Expand Up @@ -121,42 +127,37 @@ public struct AddAsyncMacro: PeerMacro {
"""

let newFunc =
funcDecl
.with(
\.signature,
funcDecl.signature
.with(
\.effectSpecifiers,
FunctionEffectSpecifiersSyntax(
leadingTrivia: .space,
asyncSpecifier: .keyword(.async),
throwsSpecifier: isResultReturn ? .keyword(.throws) : nil
) // add async
)
.with(
\.returnClause,
successReturnType != nil ? ReturnClauseSyntax(leadingTrivia: .space, type: successReturnType!.with(\.leadingTrivia, .space)) : nil
) // add result type
.with(
\.parameterClause,
funcDecl.signature.parameterClause.with(\.parameters, newParameterList) // drop completion handler
.with(\.trailingTrivia, [])
)
)
.with(
\.body,
CodeBlockSyntax(
leftBrace: .leftBraceToken(leadingTrivia: .space),
statements: CodeBlockItemListSyntax(
[CodeBlockItemSyntax(item: .expr(newBody))]
),
rightBrace: .rightBraceToken(leadingTrivia: .newline)
)
)
.with(\.attributes, newAttributeList)
.with(\.leadingTrivia, .newlines(2))
// add async
funcDecl.signature.effectSpecifiers = FunctionEffectSpecifiersSyntax(
leadingTrivia: .space,
asyncSpecifier: .keyword(.async),
throwsSpecifier: isResultReturn ? .keyword(.throws) : nil
)

// add result type
if var successReturnType {
successReturnType.leadingTrivia = .space
funcDecl.signature.returnClause = ReturnClauseSyntax(leadingTrivia: .space, type: successReturnType)
} else {
funcDecl.signature.returnClause = nil
}

// drop completion handler
funcDecl.signature.parameterClause.parameters = newParameterList
funcDecl.signature.parameterClause.trailingTrivia = []

funcDecl.body = CodeBlockSyntax(
leftBrace: .leftBraceToken(leadingTrivia: .space),
statements: CodeBlockItemListSyntax(
[CodeBlockItemSyntax(item: .expr(newBody))]
),
rightBrace: .rightBraceToken(leadingTrivia: .newline)
)

funcDecl.attributes = newAttributeList

funcDecl.leadingTrivia = .newlines(2)

return [DeclSyntax(newFunc)]
return [DeclSyntax(funcDecl)]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,22 @@ public struct AddCompletionHandlerMacro: PeerMacro {
) throws -> [DeclSyntax] {
// Only on functions at the moment. We could handle initializers as well
// with a bit of work.
guard let funcDecl = declaration.as(FunctionDeclSyntax.self) else {
guard var funcDecl = declaration.as(FunctionDeclSyntax.self) else {
throw CustomError.message("@addCompletionHandler only works on functions")
}

// This only makes sense for async functions.
if funcDecl.signature.effectSpecifiers?.asyncSpecifier == nil {
let newEffects: FunctionEffectSpecifiersSyntax
if let existingEffects = funcDecl.signature.effectSpecifiers {
newEffects = existingEffects.with(\.asyncSpecifier, .keyword(.async))
if var existingEffects = funcDecl.signature.effectSpecifiers {
existingEffects.asyncSpecifier = .keyword(.async)
newEffects = existingEffects
} else {
newEffects = FunctionEffectSpecifiersSyntax(asyncSpecifier: .keyword(.async))
}

let newSignature = funcDecl.signature.with(\.effectSpecifiers, newEffects)
var newSignature = funcDecl.signature
newSignature.effectSpecifiers = newEffects
let messageID = MessageID(domain: "MacroExamples", id: "MissingAsync")

let diag = Diagnostic(
Expand Down Expand Up @@ -73,7 +75,9 @@ public struct AddCompletionHandlerMacro: PeerMacro {
}

// Form the completion handler parameter.
let resultType: TypeSyntax? = funcDecl.signature.returnClause?.type.with(\.leadingTrivia, []).with(\.trailingTrivia, [])
var resultType = funcDecl.signature.returnClause?.type
resultType?.leadingTrivia = []
resultType?.trailingTrivia = []

let completionHandlerParam =
FunctionParameterSyntax(
Expand All @@ -85,14 +89,12 @@ public struct AddCompletionHandlerMacro: PeerMacro {
// Add the completion handler parameter to the parameter list.
let parameterList = funcDecl.signature.parameterClause.parameters
var newParameterList = parameterList
if let lastParam = parameterList.last {
if var lastParam = parameterList.last {
// We need to add a trailing comma to the preceding list.
newParameterList.removeLast()
lastParam.trailingComma = .commaToken(trailingTrivia: .space)
newParameterList += [
lastParam.with(
\.trailingComma,
.commaToken(trailingTrivia: .space)
),
lastParam,
completionHandlerParam,
]
} else {
Expand Down Expand Up @@ -136,35 +138,28 @@ public struct AddCompletionHandlerMacro: PeerMacro {
return attributeType.name.text != nodeType.name.text
}

let newFunc =
funcDecl
.with(
\.signature,
funcDecl.signature
.with(
\.effectSpecifiers,
funcDecl.signature.effectSpecifiers?.with(\.asyncSpecifier, nil) // drop async
)
.with(\.returnClause, nil) // drop result type
.with(
\.parameterClause, // add completion handler parameter
funcDecl.signature.parameterClause.with(\.parameters, newParameterList)
.with(\.trailingTrivia, [])
)
)
.with(
\.body,
CodeBlockSyntax(
leftBrace: .leftBraceToken(leadingTrivia: .space),
statements: CodeBlockItemListSyntax(
[CodeBlockItemSyntax(item: .expr(newBody))]
),
rightBrace: .rightBraceToken(leadingTrivia: .newline)
)
)
.with(\.attributes, newAttributeList)
.with(\.leadingTrivia, .newlines(2))
// drop async
funcDecl.signature.effectSpecifiers?.asyncSpecifier = nil

// drop result type
funcDecl.signature.returnClause = nil

// add completion handler parameter
funcDecl.signature.parameterClause.parameters = newParameterList
funcDecl.signature.parameterClause.trailingTrivia = []

funcDecl.body = CodeBlockSyntax(
leftBrace: .leftBraceToken(leadingTrivia: .space),
statements: CodeBlockItemListSyntax(
[CodeBlockItemSyntax(item: .expr(newBody))]
),
rightBrace: .rightBraceToken(leadingTrivia: .newline)
)

funcDecl.attributes = newAttributeList

funcDecl.leadingTrivia = .newlines(2)

return [DeclSyntax(newFunc)]
return [DeclSyntax(funcDecl)]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func runPeerMacrosPlayground() {
var value = 0
}

let counter = Counter()
_ = Counter()

// print("Peer value with suffix name for \(Counter.self): \(String(describing: Counter_peer))")
}

0 comments on commit 144b9ff

Please sign in to comment.