Skip to content

Commit 983872b

Browse files
committed
[ASTGen] Simplify diagnostics framework
This simplifies both the diagnostic declarations and usages. To create a new diangnostic message, create a static method: extension ASTGenDiagnostic { static func invalidToken(_ token: TokenSyntax) -> Self { return Self( node: token, message: "invalid token: '\(token.trimmed)'" ) } } To use it In ASTGenVisitor: self.diagnose(.invalidToken(token))
1 parent 919ec93 commit 983872b

File tree

5 files changed

+106
-113
lines changed

5 files changed

+106
-113
lines changed

lib/ASTGen/Sources/ASTGen/ASTGen.swift

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class Boxed<Value> {
6969
}
7070

7171
struct ASTGenVisitor {
72-
fileprivate let diagnosticEngine: BridgedDiagnosticEngine
72+
let diagnosticEngine: BridgedDiagnosticEngine
7373

7474
let base: UnsafeBufferPointer<UInt8>
7575

@@ -273,24 +273,6 @@ extension ASTGenVisitor {
273273
}
274274
}
275275

276-
extension ASTGenVisitor {
277-
/// Emits the given diagnostic via the C++ diagnostic engine.
278-
@inline(__always)
279-
func diagnose(_ diagnostic: Diagnostic) {
280-
emitDiagnostic(
281-
diagnosticEngine: self.diagnosticEngine,
282-
sourceFileBuffer: self.base,
283-
diagnostic: diagnostic,
284-
diagnosticSeverity: diagnostic.diagMessage.severity
285-
)
286-
}
287-
288-
/// Emits the given diagnostics via the C++ diagnostic engine.
289-
func diagnoseAll(_ diagnostics: [Diagnostic]) {
290-
diagnostics.forEach(diagnose)
291-
}
292-
}
293-
294276
// Forwarding overloads that take optional syntax nodes. These are defined on demand to achieve a consistent
295277
// 'self.generate(foo: FooSyntax)' recursion pattern between optional and non-optional inputs.
296278
extension ASTGenVisitor {

lib/ASTGen/Sources/ASTGen/Decls.swift

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ extension ASTGenVisitor {
340340
case .`init`:
341341
return .`init`
342342
default:
343-
self.diagnose(Diagnostic(node: specifier, message: UnknownAccessorSpecifierError(specifier)))
343+
self.diagnose(.unknownAccessorSpecifier(specifier))
344344
return nil
345345
}
346346
}
@@ -448,7 +448,7 @@ extension ASTGenVisitor {
448448
let storage = primaryVar.asAbstractStorageDecl
449449
storage.setAccessors(generate(accessorBlock: accessors, for: storage))
450450
} else {
451-
self.diagnose(Diagnostic(node: binding.pattern, message: NonTrivialPatternForAccessorError()))
451+
self.diagnose(.nonTrivialPatternForAccessor(binding.pattern))
452452
}
453453
}
454454
return BridgedPatternBindingEntry(
@@ -667,9 +667,7 @@ extension ASTGenVisitor {
667667
fixity = value
668668
} else {
669669
fixity = .infix
670-
self.diagnose(
671-
Diagnostic(node: node.fixitySpecifier, message: UnexpectedTokenKindError(token: node.fixitySpecifier))
672-
)
670+
self.diagnose(.unexpectedTokenKind(token: node.fixitySpecifier))
673671
}
674672

675673
return .createParsed(
@@ -712,9 +710,7 @@ extension ASTGenVisitor {
712710
}
713711

714712
func diagnoseDuplicateSyntax(_ duplicate: some SyntaxProtocol, original: some SyntaxProtocol) {
715-
self.diagnose(
716-
Diagnostic(node: duplicate, message: DuplicateSyntaxError(duplicate: duplicate, original: original))
717-
)
713+
self.diagnose(.duplicateSyntax(duplicate: duplicate, original: original))
718714
}
719715

720716
let body = node.groupAttributes.reduce(into: PrecedenceGroupBody()) { body, element in
@@ -735,7 +731,7 @@ extension ASTGenVisitor {
735731
body.lowerThanRelation = relation
736732
}
737733
default:
738-
return self.diagnose(Diagnostic(node: keyword, message: UnexpectedTokenKindError(token: keyword)))
734+
return self.diagnose(.unexpectedTokenKind(token: keyword))
739735
}
740736
case .precedenceGroupAssignment(let assignment):
741737
if let current = body.assignment {
@@ -757,7 +753,7 @@ extension ASTGenVisitor {
757753
if let value = BridgedAssociativity(from: token.keywordKind) {
758754
associativityValue = value
759755
} else {
760-
self.diagnose(Diagnostic(node: token, message: UnexpectedTokenKindError(token: token)))
756+
self.diagnose(.unexpectedTokenKind(token: token))
761757
associativityValue = .none
762758
}
763759
} else {
@@ -769,7 +765,7 @@ extension ASTGenVisitor {
769765
if token.keywordKind == .true {
770766
assignmentValue = true
771767
} else {
772-
self.diagnose(Diagnostic(node: token, message: UnexpectedTokenKindError(token: token)))
768+
self.diagnose(.unexpectedTokenKind(token: token))
773769
assignmentValue = false
774770
}
775771
} else {
@@ -824,7 +820,7 @@ extension ASTGenVisitor {
824820
if let value = BridgedImportKind(from: specifier.keywordKind) {
825821
importKind = value
826822
} else {
827-
self.diagnose(Diagnostic(node: specifier, message: UnexpectedTokenKindError(token: specifier)))
823+
self.diagnose(.unexpectedTokenKind(token: specifier))
828824
importKind = .module
829825
}
830826
} else {

lib/ASTGen/Sources/ASTGen/Diagnostics.swift

Lines changed: 94 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -13,65 +13,98 @@
1313
import SwiftDiagnostics
1414
import SwiftSyntax
1515

16-
protocol ASTGenError: DiagnosticMessage {}
16+
extension ASTGenVisitor {
17+
/// Emits the given ASTGen diagnostic via the C++ diagnostic engine.
18+
func diagnose(_ message: ASTGenDiagnostic, highlights: [Syntax]? = nil, notes: [Note] = [], fixIts: [FixIt] = []) {
19+
self.diagnose(Diagnostic(
20+
node: message.node,
21+
message: message,
22+
highlights: highlights,
23+
notes: notes,
24+
fixIts: fixIts
25+
))
26+
}
1727

18-
extension ASTGenError {
19-
var diagnosticID: MessageID {
20-
MessageID(domain: "ASTGen", id: "\(Self.self)")
28+
/// Emits the given diagnostic via the C++ diagnostic engine.
29+
func diagnose(_ diagnostic: Diagnostic) {
30+
emitDiagnostic(
31+
diagnosticEngine: self.diagnosticEngine,
32+
sourceFileBuffer: self.base,
33+
diagnostic: diagnostic,
34+
diagnosticSeverity: diagnostic.diagMessage.severity
35+
)
2136
}
2237

23-
var severity: DiagnosticSeverity { .error }
38+
/// Emits the given diagnostics via the C++ diagnostic engine.
39+
func diagnoseAll(_ diagnostics: [Diagnostic]) {
40+
diagnostics.forEach(diagnose)
41+
}
2442
}
2543

26-
/// An error emitted when a token is of an unexpected kind.
27-
struct UnexpectedTokenKindError: ASTGenError {
28-
let token: TokenSyntax
29-
private let parent: Syntax
44+
// Extract messageID from a string, particularly a function name.
45+
private func baseName(_ name: String) -> String {
46+
if let idx = name.firstIndex(of: "(") {
47+
return String(name[..<idx])
48+
}
49+
return name
50+
}
3051

31-
init(token: TokenSyntax) {
32-
guard let parent = token.parent else {
33-
preconditionFailure("Expected a child (not a root) token")
34-
}
52+
struct ASTGenDiagnostic: DiagnosticMessage {
53+
var node: Syntax
54+
var message: String
55+
var severity: DiagnosticSeverity
56+
var messageID: String
3557

36-
self.token = token
37-
self.parent = parent
58+
var diagnosticID: MessageID {
59+
MessageID(domain: "ASTGen", id: messageID)
3860
}
3961

40-
var message: String {
41-
return """
42-
unexpected token kind for token:
43-
\(self.token.debugDescription)
44-
in parent:
45-
\(self.parent.debugDescription(indentString: " "))
46-
"""
62+
init(node: some SyntaxProtocol, message: String, severity: DiagnosticSeverity = .error, messageID: String) {
63+
self.node = Syntax(node)
64+
self.message = message
65+
self.severity = severity
66+
self.messageID = messageID
67+
}
68+
69+
fileprivate init(node: some SyntaxProtocol, message: String, severity: DiagnosticSeverity = .error, function: String = #function) {
70+
// Extract messageID from the function name.
71+
let messageID: String = String(function.prefix(while: { $0 != "(" }))
72+
self.init(node: node, message: message, severity: severity, messageID: messageID)
4773
}
4874
}
4975

50-
/// An error emitted when an optional child token is unexpectedly nil.
51-
struct MissingChildTokenError: ASTGenError {
52-
let parent: Syntax
53-
let kindOfTokenMissing: TokenKind
76+
extension ASTGenDiagnostic {
77+
/// An error emitted when a token is of an unexpected kind.
78+
static func unexpectedTokenKind(token: TokenSyntax) -> Self {
79+
guard let parent = token.parent else {
80+
preconditionFailure("Expected a child (not a root) token")
81+
}
5482

55-
init(parent: some SyntaxProtocol, kindOfTokenMissing: TokenKind) {
56-
self.parent = Syntax(parent)
57-
self.kindOfTokenMissing = kindOfTokenMissing
83+
return Self(
84+
node: token,
85+
message: """
86+
unexpected token kind for token:
87+
\(token.debugDescription)
88+
in parent:
89+
\(parent.debugDescription(indentString: " "))
90+
"""
91+
)
5892
}
5993

60-
var message: String {
61-
"""
62-
missing child token of kind '\(self.kindOfTokenMissing)' in:
63-
\(parent.debugDescription(indentString: " "))
64-
"""
94+
/// An error emitted when an optional child token is unexpectedly nil.
95+
static func missingChildToken(parent: some SyntaxProtocol, kindOfTokenMissing: TokenKind) -> Self {
96+
Self(
97+
node: parent,
98+
message: """
99+
missing child token of kind '\(kindOfTokenMissing)' in:
100+
\(parent.debugDescription(indentString: " "))
101+
"""
102+
)
65103
}
66-
}
67104

68-
/// An error emitted when a syntax collection entry is encountered that is considered a duplicate of a previous entry
69-
/// per the language grammar.
70-
struct DuplicateSyntaxError: ASTGenError {
71-
let duplicate: Syntax
72-
let original: Syntax
73-
74-
init(duplicate: some SyntaxProtocol, original: some SyntaxProtocol) {
105+
/// An error emitted when a syntax collection entry is encountered that is
106+
/// considered a duplicate of a previous entry per the language grammar.
107+
static func duplicateSyntax(duplicate: some SyntaxProtocol, original: some SyntaxProtocol) -> Self {
75108
precondition(duplicate.kind == original.kind, "Expected duplicate and original to be of same kind")
76109

77110
guard let duplicateParent = duplicate.parent, let originalParent = original.parent,
@@ -80,42 +113,28 @@ struct DuplicateSyntaxError: ASTGenError {
80113
preconditionFailure("Expected a shared syntax collection parent")
81114
}
82115

83-
self.duplicate = Syntax(duplicate)
84-
self.original = Syntax(original)
85-
}
86-
87-
var message: String {
88-
"""
89-
unexpected duplicate syntax in list:
90-
\(duplicate.debugDescription(indentString: " "))
91-
previous syntax:
92-
\(original.debugDescription(indentString: " "))
93-
"""
94-
}
95-
}
96-
97-
struct NonTrivialPatternForAccessorError: ASTGenError {
98-
var message: String {
99-
"getter/setter can only be defined for a single variable"
116+
return Self(
117+
node: duplicate,
118+
message: """
119+
unexpected duplicate syntax in list:
120+
\(duplicate.debugDescription(indentString: " "))
121+
previous syntax:
122+
\(original.debugDescription(indentString: " "))
123+
"""
124+
)
100125
}
101-
}
102126

103-
struct UnknownAccessorSpecifierError: ASTGenError {
104-
var specifier: TokenSyntax
105-
init(_ specifier: TokenSyntax) {
106-
self.specifier = specifier
127+
static func nonTrivialPatternForAccessor(_ pattern: some SyntaxProtocol) -> Self {
128+
Self(
129+
node: pattern,
130+
message: "getter/setter can only be defined for a single variable"
131+
)
107132
}
108133

109-
var message: String {
110-
"unknown accessor specifier '\(specifier.text)'"
134+
static func unknownAccessorSpecifier(_ specifier: TokenSyntax) -> Self {
135+
Self(
136+
node: specifier,
137+
message: "unknown accessor specifier '\(specifier.text)'"
138+
)
111139
}
112140
}
113-
114-
struct RegexParserError: ASTGenError {
115-
var message: String
116-
init(_ message: String) {
117-
self.message = message
118-
}
119-
120-
var severity: DiagnosticSeverity { .error }
121-
}

lib/ASTGen/Sources/ASTGen/Exprs.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -406,14 +406,10 @@ extension ASTGenVisitor {
406406
func generate(functionCallExpr node: FunctionCallExprSyntax, postfixIfConfigBaseExpr: BridgedExpr? = nil) -> BridgedCallExpr {
407407
if !node.arguments.isEmpty || node.trailingClosure == nil {
408408
if node.leftParen == nil {
409-
self.diagnose(
410-
Diagnostic(node: node, message: MissingChildTokenError(parent: node, kindOfTokenMissing: .leftParen))
411-
)
409+
self.diagnose(.missingChildToken(parent: node, kindOfTokenMissing: .leftParen))
412410
}
413411
if node.rightParen == nil {
414-
self.diagnose(
415-
Diagnostic(node: node, message: MissingChildTokenError(parent: node, kindOfTokenMissing: .rightParen))
416-
)
412+
self.diagnose(.missingChildToken(parent: node, kindOfTokenMissing: .rightParen))
417413
}
418414
}
419415

lib/ASTGen/Sources/ASTGen/Types.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ extension ASTGenVisitor {
367367
specifierLoc: self.generateSourceLoc(specifier)
368368
).asTypeRepr
369369
} else {
370-
self.diagnose(Diagnostic(node: specifier, message: UnexpectedTokenKindError(token: specifier)))
370+
self.diagnose(.unexpectedTokenKind(token: specifier))
371371
}
372372
}
373373

0 commit comments

Comments
 (0)