diff --git a/lib/ASTGen/Sources/ASTGen/ASTGen.swift b/lib/ASTGen/Sources/ASTGen/ASTGen.swift index 208b7313a20ec..0ae0d5ae2f0b0 100644 --- a/lib/ASTGen/Sources/ASTGen/ASTGen.swift +++ b/lib/ASTGen/Sources/ASTGen/ASTGen.swift @@ -69,7 +69,7 @@ class Boxed { } struct ASTGenVisitor { - fileprivate let diagnosticEngine: BridgedDiagnosticEngine + let diagnosticEngine: BridgedDiagnosticEngine let base: UnsafeBufferPointer @@ -273,24 +273,6 @@ extension ASTGenVisitor { } } -extension ASTGenVisitor { - /// Emits the given diagnostic via the C++ diagnostic engine. - @inline(__always) - func diagnose(_ diagnostic: Diagnostic) { - emitDiagnostic( - diagnosticEngine: self.diagnosticEngine, - sourceFileBuffer: self.base, - diagnostic: diagnostic, - diagnosticSeverity: diagnostic.diagMessage.severity - ) - } - - /// Emits the given diagnostics via the C++ diagnostic engine. - func diagnoseAll(_ diagnostics: [Diagnostic]) { - diagnostics.forEach(diagnose) - } -} - // Forwarding overloads that take optional syntax nodes. These are defined on demand to achieve a consistent // 'self.generate(foo: FooSyntax)' recursion pattern between optional and non-optional inputs. extension ASTGenVisitor { diff --git a/lib/ASTGen/Sources/ASTGen/Decls.swift b/lib/ASTGen/Sources/ASTGen/Decls.swift index cd4b9da9bc5ee..a421b9bed2ce2 100644 --- a/lib/ASTGen/Sources/ASTGen/Decls.swift +++ b/lib/ASTGen/Sources/ASTGen/Decls.swift @@ -340,7 +340,7 @@ extension ASTGenVisitor { case .`init`: return .`init` default: - self.diagnose(Diagnostic(node: specifier, message: UnknownAccessorSpecifierError(specifier))) + self.diagnose(.unknownAccessorSpecifier(specifier)) return nil } } @@ -448,7 +448,7 @@ extension ASTGenVisitor { let storage = primaryVar.asAbstractStorageDecl storage.setAccessors(generate(accessorBlock: accessors, for: storage)) } else { - self.diagnose(Diagnostic(node: binding.pattern, message: NonTrivialPatternForAccessorError())) + self.diagnose(.nonTrivialPatternForAccessor(binding.pattern)) } } return BridgedPatternBindingEntry( @@ -667,9 +667,7 @@ extension ASTGenVisitor { fixity = value } else { fixity = .infix - self.diagnose( - Diagnostic(node: node.fixitySpecifier, message: UnexpectedTokenKindError(token: node.fixitySpecifier)) - ) + self.diagnose(.unexpectedTokenKind(token: node.fixitySpecifier)) } return .createParsed( @@ -712,9 +710,7 @@ extension ASTGenVisitor { } func diagnoseDuplicateSyntax(_ duplicate: some SyntaxProtocol, original: some SyntaxProtocol) { - self.diagnose( - Diagnostic(node: duplicate, message: DuplicateSyntaxError(duplicate: duplicate, original: original)) - ) + self.diagnose(.duplicateSyntax(duplicate: duplicate, original: original)) } let body = node.groupAttributes.reduce(into: PrecedenceGroupBody()) { body, element in @@ -735,7 +731,7 @@ extension ASTGenVisitor { body.lowerThanRelation = relation } default: - return self.diagnose(Diagnostic(node: keyword, message: UnexpectedTokenKindError(token: keyword))) + return self.diagnose(.unexpectedTokenKind(token: keyword)) } case .precedenceGroupAssignment(let assignment): if let current = body.assignment { @@ -757,7 +753,7 @@ extension ASTGenVisitor { if let value = BridgedAssociativity(from: token.keywordKind) { associativityValue = value } else { - self.diagnose(Diagnostic(node: token, message: UnexpectedTokenKindError(token: token))) + self.diagnose(.unexpectedTokenKind(token: token)) associativityValue = .none } } else { @@ -769,7 +765,7 @@ extension ASTGenVisitor { if token.keywordKind == .true { assignmentValue = true } else { - self.diagnose(Diagnostic(node: token, message: UnexpectedTokenKindError(token: token))) + self.diagnose(.unexpectedTokenKind(token: token)) assignmentValue = false } } else { @@ -824,7 +820,7 @@ extension ASTGenVisitor { if let value = BridgedImportKind(from: specifier.keywordKind) { importKind = value } else { - self.diagnose(Diagnostic(node: specifier, message: UnexpectedTokenKindError(token: specifier))) + self.diagnose(.unexpectedTokenKind(token: specifier)) importKind = .module } } else { diff --git a/lib/ASTGen/Sources/ASTGen/Diagnostics.swift b/lib/ASTGen/Sources/ASTGen/Diagnostics.swift index ae67e3e58a164..5b014acec65c3 100644 --- a/lib/ASTGen/Sources/ASTGen/Diagnostics.swift +++ b/lib/ASTGen/Sources/ASTGen/Diagnostics.swift @@ -13,65 +13,90 @@ import SwiftDiagnostics import SwiftSyntax -protocol ASTGenError: DiagnosticMessage {} +extension ASTGenVisitor { + /// Emits the given ASTGen diagnostic via the C++ diagnostic engine. + func diagnose(_ message: ASTGenDiagnostic, highlights: [Syntax]? = nil, notes: [Note] = [], fixIts: [FixIt] = []) { + self.diagnose(Diagnostic( + node: message.node, + message: message, + highlights: highlights, + notes: notes, + fixIts: fixIts + )) + } -extension ASTGenError { - var diagnosticID: MessageID { - MessageID(domain: "ASTGen", id: "\(Self.self)") + /// Emits the given diagnostic via the C++ diagnostic engine. + func diagnose(_ diagnostic: Diagnostic) { + emitDiagnostic( + diagnosticEngine: self.diagnosticEngine, + sourceFileBuffer: self.base, + diagnostic: diagnostic, + diagnosticSeverity: diagnostic.diagMessage.severity + ) } - var severity: DiagnosticSeverity { .error } + /// Emits the given diagnostics via the C++ diagnostic engine. + func diagnoseAll(_ diagnostics: [Diagnostic]) { + diagnostics.forEach(diagnose) + } } -/// An error emitted when a token is of an unexpected kind. -struct UnexpectedTokenKindError: ASTGenError { - let token: TokenSyntax - private let parent: Syntax +struct ASTGenDiagnostic: DiagnosticMessage { + var node: Syntax + var message: String + var severity: DiagnosticSeverity + var messageID: String - init(token: TokenSyntax) { - guard let parent = token.parent else { - preconditionFailure("Expected a child (not a root) token") - } + var diagnosticID: MessageID { + MessageID(domain: "ASTGen", id: messageID) + } - self.token = token - self.parent = parent + init(node: some SyntaxProtocol, message: String, severity: DiagnosticSeverity = .error, messageID: String) { + self.node = Syntax(node) + self.message = message + self.severity = severity + self.messageID = messageID } - var message: String { - return """ - unexpected token kind for token: - \(self.token.debugDescription) - in parent: - \(self.parent.debugDescription(indentString: " ")) - """ + fileprivate init(node: some SyntaxProtocol, message: String, severity: DiagnosticSeverity = .error, function: String = #function) { + // Extract messageID from the function name. + let messageID = String(function.prefix(while: { $0 != "(" })) + self.init(node: node, message: message, severity: severity, messageID: messageID) } } -/// An error emitted when an optional child token is unexpectedly nil. -struct MissingChildTokenError: ASTGenError { - let parent: Syntax - let kindOfTokenMissing: TokenKind +extension ASTGenDiagnostic { + /// An error emitted when a token is of an unexpected kind. + static func unexpectedTokenKind(token: TokenSyntax) -> Self { + guard let parent = token.parent else { + preconditionFailure("Expected a child (not a root) token") + } - init(parent: some SyntaxProtocol, kindOfTokenMissing: TokenKind) { - self.parent = Syntax(parent) - self.kindOfTokenMissing = kindOfTokenMissing + return Self( + node: token, + message: """ + unexpected token kind for token: + \(token.debugDescription) + in parent: + \(parent.debugDescription(indentString: " ")) + """ + ) } - var message: String { - """ - missing child token of kind '\(self.kindOfTokenMissing)' in: - \(parent.debugDescription(indentString: " ")) - """ + /// An error emitted when an optional child token is unexpectedly nil. + static func missingChildToken(parent: some SyntaxProtocol, kindOfTokenMissing: TokenKind) -> Self { + Self( + node: parent, + message: """ + missing child token of kind '\(kindOfTokenMissing)' in: + \(parent.debugDescription(indentString: " ")) + """ + ) } -} -/// An error emitted when a syntax collection entry is encountered that is considered a duplicate of a previous entry -/// per the language grammar. -struct DuplicateSyntaxError: ASTGenError { - let duplicate: Syntax - let original: Syntax - - init(duplicate: some SyntaxProtocol, original: some SyntaxProtocol) { + /// An error emitted when a syntax collection entry is encountered that is + /// considered a duplicate of a previous entry per the language grammar. + static func duplicateSyntax(duplicate: some SyntaxProtocol, original: some SyntaxProtocol) -> Self { precondition(duplicate.kind == original.kind, "Expected duplicate and original to be of same kind") guard let duplicateParent = duplicate.parent, let originalParent = original.parent, @@ -80,42 +105,28 @@ struct DuplicateSyntaxError: ASTGenError { preconditionFailure("Expected a shared syntax collection parent") } - self.duplicate = Syntax(duplicate) - self.original = Syntax(original) - } - - var message: String { - """ - unexpected duplicate syntax in list: - \(duplicate.debugDescription(indentString: " ")) - previous syntax: - \(original.debugDescription(indentString: " ")) - """ - } -} - -struct NonTrivialPatternForAccessorError: ASTGenError { - var message: String { - "getter/setter can only be defined for a single variable" - } -} - -struct UnknownAccessorSpecifierError: ASTGenError { - var specifier: TokenSyntax - init(_ specifier: TokenSyntax) { - self.specifier = specifier + return Self( + node: duplicate, + message: """ + unexpected duplicate syntax in list: + \(duplicate.debugDescription(indentString: " ")) + previous syntax: + \(original.debugDescription(indentString: " ")) + """ + ) } - var message: String { - "unknown accessor specifier '\(specifier.text)'" + static func nonTrivialPatternForAccessor(_ pattern: some SyntaxProtocol) -> Self { + Self( + node: pattern, + message: "getter/setter can only be defined for a single variable" + ) } -} -struct RegexParserError: ASTGenError { - var message: String - init(_ message: String) { - self.message = message + static func unknownAccessorSpecifier(_ specifier: TokenSyntax) -> Self { + Self( + node: specifier, + message: "unknown accessor specifier '\(specifier.text)'" + ) } - - var severity: DiagnosticSeverity { .error } } diff --git a/lib/ASTGen/Sources/ASTGen/Exprs.swift b/lib/ASTGen/Sources/ASTGen/Exprs.swift index 02f79bb395f9b..86e5f3b497f91 100644 --- a/lib/ASTGen/Sources/ASTGen/Exprs.swift +++ b/lib/ASTGen/Sources/ASTGen/Exprs.swift @@ -406,14 +406,10 @@ extension ASTGenVisitor { func generate(functionCallExpr node: FunctionCallExprSyntax, postfixIfConfigBaseExpr: BridgedExpr? = nil) -> BridgedCallExpr { if !node.arguments.isEmpty || node.trailingClosure == nil { if node.leftParen == nil { - self.diagnose( - Diagnostic(node: node, message: MissingChildTokenError(parent: node, kindOfTokenMissing: .leftParen)) - ) + self.diagnose(.missingChildToken(parent: node, kindOfTokenMissing: .leftParen)) } if node.rightParen == nil { - self.diagnose( - Diagnostic(node: node, message: MissingChildTokenError(parent: node, kindOfTokenMissing: .rightParen)) - ) + self.diagnose(.missingChildToken(parent: node, kindOfTokenMissing: .rightParen)) } } diff --git a/lib/ASTGen/Sources/ASTGen/Types.swift b/lib/ASTGen/Sources/ASTGen/Types.swift index 34ed2682fe449..45fd24f8caa6b 100644 --- a/lib/ASTGen/Sources/ASTGen/Types.swift +++ b/lib/ASTGen/Sources/ASTGen/Types.swift @@ -367,7 +367,7 @@ extension ASTGenVisitor { specifierLoc: self.generateSourceLoc(specifier) ).asTypeRepr } else { - self.diagnose(Diagnostic(node: specifier, message: UnexpectedTokenKindError(token: specifier))) + self.diagnose(.unexpectedTokenKind(token: specifier)) } }