|
| 1 | +@_implementationOnly import SwiftDiagnostics |
| 2 | +@_implementationOnly import SwiftSyntax |
| 3 | +@_implementationOnly import SwiftSyntaxMacros |
| 4 | + |
| 5 | +/// A diagnostic producer type that can validate passed syntax is not a static |
| 6 | +/// variable declaration. |
| 7 | +/// |
| 8 | +/// This producer can be used for macro-attributes that must be attached to |
| 9 | +/// non static variable declarations. |
| 10 | +struct StaticVariableDeclaration<Attr: PropertyAttribute>: DiagnosticProducer { |
| 11 | + /// The attribute for which |
| 12 | + /// validation performed. |
| 13 | + /// |
| 14 | + /// Uses this attribute name |
| 15 | + /// in generated diagnostic |
| 16 | + /// messages. |
| 17 | + let attr: Attr |
| 18 | + |
| 19 | + /// Creates a static variable declaration validation instance |
| 20 | + /// with provided attribute. |
| 21 | + /// |
| 22 | + /// - Parameter attr: The attribute for which |
| 23 | + /// validation performed. |
| 24 | + /// - Returns: Newly created diagnostic producer. |
| 25 | + init(_ attr: Attr) { |
| 26 | + self.attr = attr |
| 27 | + } |
| 28 | + |
| 29 | + /// Validates and produces diagnostics for the passed syntax |
| 30 | + /// in the macro expansion context provided. |
| 31 | + /// |
| 32 | + /// Checks whether provided syntax is a non static variable declaration, |
| 33 | + /// for static variable declarations error diagnostics |
| 34 | + /// are generated. |
| 35 | + /// |
| 36 | + /// - Parameters: |
| 37 | + /// - syntax: The syntax to validate and produce diagnostics for. |
| 38 | + /// - context: The macro expansion context diagnostics produced in. |
| 39 | + /// |
| 40 | + /// - Returns: True if syntax fails validation, false otherwise. |
| 41 | + @discardableResult |
| 42 | + func produce( |
| 43 | + for syntax: some SyntaxProtocol, |
| 44 | + in context: some MacroExpansionContext |
| 45 | + ) -> Bool { |
| 46 | + // The Macro fails to compile if the .modifiers.contains |
| 47 | + // is directly used in the guard statement. |
| 48 | + let isStatic = syntax.as(VariableDeclSyntax.self)? |
| 49 | + .modifiers.contains { $0.name.tokenKind == .keyword(.static) } |
| 50 | + guard isStatic ?? false else { return false } |
| 51 | + let message = attr.node.diagnostic( |
| 52 | + message: |
| 53 | + "@\(attr.name) can't be used with static variables declarations", |
| 54 | + id: attr.misuseMessageID, |
| 55 | + severity: .error |
| 56 | + ) |
| 57 | + context.diagnose(attr: attr, message: message) |
| 58 | + return true |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +extension PropertyAttribute { |
| 63 | + /// Indicates attribute must be attached to non static variable declaration. |
| 64 | + /// |
| 65 | + /// The created diagnostic producer produces error diagnostic, |
| 66 | + /// if attribute is attached to static variable declarations. |
| 67 | + /// |
| 68 | + /// - Returns: Static variable declaration validation diagnostic producer. |
| 69 | + func attachedToNonStaticVariable() -> StaticVariableDeclaration<Self> { |
| 70 | + return .init(self) |
| 71 | + } |
| 72 | +} |
0 commit comments