-
-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathGroupedVariableDeclaration.swift
More file actions
102 lines (97 loc) · 4.05 KB
/
GroupedVariableDeclaration.swift
File metadata and controls
102 lines (97 loc) · 4.05 KB
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
99
100
101
102
@_implementationOnly import SwiftDiagnostics
@_implementationOnly import SwiftSyntax
@_implementationOnly import SwiftSyntaxMacros
/// A diagnostic producer type that can validate passed syntax is not a grouped
/// variable declaration.
///
/// This producer can be used for macro-attributes that must be attached to
/// single variable declarations.
///
/// - Note: This producer also validates passed syntax is of variable
/// declaration type. No need to pass additional diagnostic producer
/// to validate this.
struct GroupedVariableDeclaration<Attr: PropertyAttribute>: DiagnosticProducer {
/// The attribute for which
/// validation performed.
///
/// Uses this attribute name
/// in generated diagnostic
/// messages.
let attr: Attr
/// The attribute is attatch to multiple bindings variable.
let isAttach: Bool
/// Underlying producer that validates passed syntax is variable
/// declaration.
///
/// This diagnostic producer is used first to check if passed declaration is
/// variable declaration. If validation failed, then further validation by
/// this type is terminated.
let base: InvalidDeclaration<Attr>
/// Creates a grouped variable declaration validation instance
/// with provided attribute.
///
/// Underlying variable declaration validation instance is created
/// and used first. Post the success of base validation this type
/// performs validation.
///
/// - Parameter attr: The attribute for which
/// validation performed.
/// - Parameter isAttach: can attach to multiple bindings.
/// - Returns: Newly created diagnostic producer.
init(_ attr: Attr, isAttach: Bool) {
self.attr = attr
self.isAttach = isAttach
self.base = .init(attr, expect: [VariableDeclSyntax.self])
}
/// Validates and produces diagnostics for the passed syntax
/// in the macro expansion context provided.
///
/// Checks whether provided syntax is a single variable declaration,
/// for grouped variable and non-variable declarations error diagnostics
/// is generated.
///
/// - Parameters:
/// - syntax: The syntax to validate and produce diagnostics for.
/// - context: The macro expansion context diagnostics produced in.
///
/// - Returns: True if syntax fails validation, false otherwise.
@discardableResult
func produce(
for syntax: some SyntaxProtocol,
in context: some MacroExpansionContext
) -> Bool {
guard !base.produce(for: syntax, in: context) else { return true }
guard (!isAttach && syntax.as(VariableDeclSyntax.self)!.bindings.count > 1) || (isAttach && syntax.as(VariableDeclSyntax.self)!.bindings.count == 1)
else { return false }
let message = attr.diagnostic(
message:
isAttach ? "@\(attr.name) can't be used with single variables declaration" : "@\(attr.name) can't be used with grouped variables declaration",
id: attr.misuseMessageID,
severity: .error
)
attr.diagnose(message: message, in: context)
return true
}
}
extension PropertyAttribute {
/// Indicates attribute must be attached to single variable declaration.
///
/// The created diagnostic producer produces error diagnostic,
/// if attribute is attached to grouped variable and non-variable
/// declarations.
///
/// - Returns: Grouped variable declaration validation diagnostic producer.
func attachedToUngroupedVariable() -> GroupedVariableDeclaration<Self> {
return .init(self, isAttach: false)
}
/// Indicates attribute must be attached to multiple bindings variable declaration.
///
/// The created diagnostic producer produces error diagnostic,
/// if attribute is attached to grouped variable and non-variable
/// declarations.
///
/// - Returns: Grouped variable declaration validation diagnostic producer.
func attachedToGroupedVariable() -> GroupedVariableDeclaration<Self> {
return .init(self, isAttach: true)
}
}