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

Refactor syntax node manipulation to use variable setters #2278

Merged
merged 1 commit into from
Oct 19, 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
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,7 @@ 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)])
]
return ["\n var _storage: [String: Any] = [:]"]
}
}

Expand All @@ -43,11 +40,11 @@ extension DictionaryStorageMacro: MemberAttributeMacro {

return [
AttributeSyntax(
leadingTrivia: [.newlines(1), .spaces(2)],
attributeName: IdentifierTypeSyntax(
name: .identifier("DictionaryStorageProperty")
)
)
.with(\.leadingTrivia, [.newlines(1), .spaces(2)])
]
}
}
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,9 @@ public struct AddBlocker: ExpressionMacro {
)
)

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

return ExprSyntax(node.with(\.operator, ExprSyntax(binOp)))
}
}

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

var tuple = tuple
tuple[tuple.startIndex] =
firstElement
.with(\.label, .identifier(newLabel))
.with(\.colon, .colonToken())
tuple[tuple.startIndex].label = .identifier(newLabel)
tuple[tuple.startIndex].colon = .colonToken()
return tuple
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ public struct WrapStoredPropertiesMacro: MemberAttributeMacro {

return [
AttributeSyntax(
leadingTrivia: [.newlines(1), .spaces(2)],
attributeName: IdentifierTypeSyntax(
name: .identifier(wrapperName.content.text)
)
)
.with(\.leadingTrivia, [.newlines(1), .spaces(2)])
]
}
}
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,7 @@ public struct AddAsyncMacro: PeerMacro {
}

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

// Completion handler needs to return Void
if completionHandlerParameter.returnClause.type.with(\.leadingTrivia, []).with(\.trailingTrivia, []).description != "Void" {
if completionHandlerParameter.returnClause.type.as(IdentifierTypeSyntax.self)?.name.text != "Void" {
throw CustomError.message(
"@addAsync requires an function that has a completion handler that returns Void"
)
Expand All @@ -72,9 +72,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 +123,36 @@ 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 let successReturnType {
funcDecl.signature.returnClause = ReturnClauseSyntax(leadingTrivia: .space, type: successReturnType.with(\.leadingTrivia, .space))
} 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
var newEffects: FunctionEffectSpecifiersSyntax
if let existingEffects = funcDecl.signature.effectSpecifiers {
newEffects = existingEffects.with(\.asyncSpecifier, .keyword(.async))
newEffects = existingEffects
newEffects.asyncSpecifier = .keyword(.async)
} 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))")
}