1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import SwiftDiagnostics
import SwiftOperators
import SwiftSyntax
import SwiftSyntaxMacros
/// Implementation of the `addBlocker` macro, which demonstrates how to
/// produce detailed diagnostics from a macro implementation for an utterly
/// silly task: warning about every "add" (binary +) in the argument, with a
/// Fix-It that changes it to a "-".
public struct AddBlocker: ExpressionMacro {
class AddVisitor: SyntaxRewriter {
var diagnostics: [Diagnostic] = []
override func visit(
_ node: InfixOperatorExprSyntax
) -> ExprSyntax {
// Identify any infix operator + in the tree.
if var binOp = node.operator.as(BinaryOperatorExprSyntax.self) {
if binOp.operator.text == "+" {
// Form the warning
let messageID = MessageID(domain: "silly", id: "addblock")
diagnostics.append(
Diagnostic(
// Where the warning should go (on the "+").
node: Syntax(node.operator),
// The warning message and severity.
message: SimpleDiagnosticMessage(
message: "blocked an add; did you mean to subtract?",
diagnosticID: messageID,
severity: .warning
),
// Highlight the left and right sides of the `+`.
highlights: [
Syntax(node.leftOperand),
Syntax(node.rightOperand),
],
fixIts: [
// Fix-It to replace the '+' with a '-'.
FixIt(
message: SimpleDiagnosticMessage(
message: "use '-'",
diagnosticID: messageID,
severity: .error
),
changes: [
FixIt.Change.replace(
oldNode: Syntax(binOp.operator),
newNode: Syntax(
TokenSyntax(
.binaryOperator("-"),
leadingTrivia: binOp.operator.leadingTrivia,
trailingTrivia: binOp.operator.trailingTrivia,
presence: .present
)
)
)
]
)
]
)
)
binOp.operator.tokenKind = .binaryOperator("-")
return ExprSyntax(node.with(\.operator, ExprSyntax(binOp)))
}
}
return ExprSyntax(node)
}
}
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> ExprSyntax {
let visitor = AddVisitor()
let result = visitor.rewrite(Syntax(node))
for diag in visitor.diagnostics {
context.diagnose(diag)
}
return result.asProtocol(FreestandingMacroExpansionSyntax.self)!.arguments.first!.expression
}
}
|