diff --git a/CodeGeneration/Sources/SyntaxSupport/CommonNodes.swift b/CodeGeneration/Sources/SyntaxSupport/CommonNodes.swift index f9e245d877c..5d7fbaa35bb 100644 --- a/CodeGeneration/Sources/SyntaxSupport/CommonNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/CommonNodes.swift @@ -144,6 +144,7 @@ public let COMMON_NODES: [Node] = [ Node( name: "MissingDecl", nameForDiagnostics: "declaration", + description: "In case the source code is missing a declaration, this node stands in place of the missing declaration.", kind: "Decl", traits: [ "Attributed" @@ -152,44 +153,108 @@ public let COMMON_NODES: [Node] = [ Child( name: "Attributes", kind: .collection(kind: "AttributeList", collectionElementName: "Attribute"), + description: "If there were standalone attributes without a declaration to attach them to, the `MissingDeclSyntax` will contain these.", isOptional: true ), Child( name: "Modifiers", kind: .collection(kind: "ModifierList", collectionElementName: "Modifier"), + description: "If there were standalone modifiers without a declaration to attach them to, the `MissingDeclSyntax` will contain these.", isOptional: true ), + Child( + name: "Placeholder", + kind: .token(choices: [.token(tokenKind: "IdentifierToken")], requiresLeadingSpace: false, requiresTrailingSpace: false), + description: """ + A placeholder, i.e. `<#decl#>` that can be inserted into the source code to represent the missing declaration. + This token should always have `presence = .missing`. + """ + ), ] ), Node( name: "MissingExpr", nameForDiagnostics: "expression", - kind: "Expr" + description: "In case the source code is missing a expression, this node stands in place of the missing expression.", + kind: "Expr", + children: [ + Child( + name: "Placeholder", + kind: .token(choices: [.token(tokenKind: "IdentifierToken")], requiresLeadingSpace: false, requiresTrailingSpace: false), + description: """ + A placeholder, i.e. `<#expression#>` that can be inserted into the source code to represent the missing expression. + This token should always have `presence = .missing`. + """ + ) + ] ), Node( name: "MissingPattern", nameForDiagnostics: "pattern", - kind: "Pattern" + description: "In case the source code is missing a pattern, this node stands in place of the missing pattern.", + kind: "Pattern", + children: [ + Child( + name: "Placeholder", + kind: .token(choices: [.token(tokenKind: "IdentifierToken")], requiresLeadingSpace: false, requiresTrailingSpace: false), + description: """ + A placeholder, i.e. `<#pattern#>` that can be inserted into the source code to represent the missing pattern. + This token should always have `presence = .missing`. + """ + ) + ] ), Node( name: "MissingStmt", nameForDiagnostics: "statement", - kind: "Stmt" + description: "In case the source code is missing a statement, this node stands in place of the missing statement.", + kind: "Stmt", + children: [ + Child( + name: "Placeholder", + kind: .token(choices: [.token(tokenKind: "IdentifierToken")], requiresLeadingSpace: false, requiresTrailingSpace: false), + description: """ + A placeholder, i.e. `<#statement#>` that can be inserted into the source code to represent the missing pattern. + This token should always have `presence = .missing`. + """ + ) + ] ), Node( name: "Missing", nameForDiagnostics: nil, - kind: "Syntax" + description: "In case the source code is missing a syntax node, this node stands in place of the missing node.", + kind: "Syntax", + children: [ + Child( + name: "Placeholder", + kind: .token(choices: [.token(tokenKind: "IdentifierToken")], requiresLeadingSpace: false, requiresTrailingSpace: false), + description: """ + A placeholder, i.e. `<#syntax#>` that can be inserted into the source code to represent the missing pattern. + This token should always have `presence = .missing` + """ + ) + ] ), Node( name: "MissingType", nameForDiagnostics: "type", - kind: "Type" + description: "In case the source code is missing a type, this node stands in place of the missing type.", + kind: "Type", + children: [ + Child( + name: "Placeholder", + kind: .token(choices: [.token(tokenKind: "IdentifierToken")], requiresLeadingSpace: false, requiresTrailingSpace: false), + description: """ + A placeholder, i.e. `<#type#>` that can be inserted into the source code to represent the missing type. This token should always have `presence = .missing`. + """ + ) + ] ), Node( diff --git a/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxNodesFile.swift b/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxNodesFile.swift index 283b06615ce..60a3c4734d4 100644 --- a/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxNodesFile.swift +++ b/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxNodesFile.swift @@ -15,6 +15,18 @@ import SwiftSyntaxBuilder import SyntaxSupport import Utils +extension Child { + public var docComment: SwiftSyntax.Trivia { + guard let description = description else { + return [] + } + let dedented = dedented(string: description) + let lines = dedented.split(separator: "\n", omittingEmptySubsequences: false) + let pieces = lines.map { SwiftSyntax.TriviaPiece.docLineComment("/// \($0)") } + return Trivia(pieces: pieces) + } +} + /// This file generates the syntax nodes for SwiftSyntax. To keep the generated /// files at a managable file size, it is to be invoked multiple times with the /// variable `emitKind` set to a base kind listed in @@ -33,7 +45,7 @@ func syntaxNode(emitKind: String) -> SourceFileSyntax { """ ) { for child in node.children { - if let childChoiceDecl = try generateSyntaxChildChoices(for: child) { + if let childChoiceDecl = try! generateSyntaxChildChoices(for: child) { childChoiceDecl } } @@ -140,7 +152,7 @@ func syntaxNode(emitKind: String) -> SourceFileSyntax { if node.hasOptionalBaseTypeChild { // TODO: Remove when we no longer support compiling in Swift 5.6. Change the // above constructor to use `Optional.none` instead. - try InitializerDeclSyntax( + try! InitializerDeclSyntax( """ /// This initializer exists solely because Swift 5.6 does not support /// `Optional.none` as a default value of a generic parameter. @@ -191,11 +203,10 @@ func syntaxNode(emitKind: String) -> SourceFileSyntax { let childType: String = child.kind.isNodeChoicesEmpty ? child.typeName : child.name let type = child.isOptional ? TypeSyntax("\(raw: childType)?") : TypeSyntax("\(raw: childType)") - let childDoc = child.description.map { dedented(string: $0) }.map { Trivia.docLineComment("/// \($0)") } - try VariableDeclSyntax( + try! VariableDeclSyntax( """ - \(raw: childDoc ?? []) + \(raw: child.docComment) public var \(raw: child.swiftName): \(type) """ ) { @@ -274,7 +285,7 @@ private func generateSyntaxChildChoices(for child: Child) throws -> EnumDeclSynt return nil } - return try EnumDeclSyntax("public enum \(raw: child.name): SyntaxChildChoices") { + return try! EnumDeclSyntax("public enum \(raw: child.name): SyntaxChildChoices") { for choice in choices { DeclSyntax("case `\(raw: choice.swiftName)`(\(raw: choice.typeName))") } diff --git a/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxRewriterFile.swift b/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxRewriterFile.swift index 2f03b156e69..2b9b79d089f 100644 --- a/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxRewriterFile.swift +++ b/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxRewriterFile.swift @@ -335,5 +335,17 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) { } """ ) + + DeclSyntax( + """ + /// Rewrite `node` and anchor, making sure that the rewritten node also has + /// a parent if `node` had one. + public func rewrite(_ node: Syntax) -> Syntax { + let rewritten = self.visit(node) + let arena = SyntaxArena() + return Syntax(node.data.replacingSelf(rewritten.raw, arena: arena)) + } + """ + ) } } diff --git a/Sources/SwiftBasicFormat/generated/BasicFormat+Extensions.swift b/Sources/SwiftBasicFormat/generated/BasicFormat+Extensions.swift index 446ac7644f7..ac2a48fcfd0 100644 --- a/Sources/SwiftBasicFormat/generated/BasicFormat+Extensions.swift +++ b/Sources/SwiftBasicFormat/generated/BasicFormat+Extensions.swift @@ -245,6 +245,18 @@ fileprivate extension AnyKeyPath { return false case \FunctionParameterSyntax.secondName: return true + case \MissingDeclSyntax.placeholder: + return false + case \MissingExprSyntax.placeholder: + return false + case \MissingPatternSyntax.placeholder: + return false + case \MissingStmtSyntax.placeholder: + return false + case \MissingSyntax.placeholder: + return false + case \MissingTypeSyntax.placeholder: + return false default: return nil } @@ -262,6 +274,18 @@ fileprivate extension AnyKeyPath { return false case \DynamicReplacementArgumentsSyntax.forLabel: return false + case \MissingDeclSyntax.placeholder: + return false + case \MissingExprSyntax.placeholder: + return false + case \MissingPatternSyntax.placeholder: + return false + case \MissingStmtSyntax.placeholder: + return false + case \MissingSyntax.placeholder: + return false + case \MissingTypeSyntax.placeholder: + return false case \SwitchCaseLabelSyntax.colon: return false case \SwitchDefaultLabelSyntax.colon: diff --git a/Sources/SwiftParserDiagnostics/MissingNodesError.swift b/Sources/SwiftParserDiagnostics/MissingNodesError.swift index d47d52d3b05..f4d8e55d2a5 100644 --- a/Sources/SwiftParserDiagnostics/MissingNodesError.swift +++ b/Sources/SwiftParserDiagnostics/MissingNodesError.swift @@ -335,17 +335,18 @@ extension ParseDiagnosticsGenerator { /// Ancestors that don't contain any tokens are not very interesting to merge diagnostics (because there can't be any missing tokens we can merge them with). /// Find the first ancestor that contains any tokens. - var ancestorWithTokens = node.parent + var ancestorWithMoreTokens = node.parent var index = node.index - while let unwrappedParent = ancestorWithTokens, !unwrappedParent.hasTokens { - ancestorWithTokens = unwrappedParent.parent + let nodeTokens = Array(node.tokens(viewMode: .all)) + while let unwrappedParent = ancestorWithMoreTokens, Array(unwrappedParent.tokens(viewMode: .all)) == nodeTokens { + ancestorWithMoreTokens = unwrappedParent.parent index = unwrappedParent.index } // Walk all upcoming sibling to see if they are also missing to handle them in this diagnostic. // If this is the case, handle all of them in this diagnostic. var missingNodes = [Syntax(node)] - if let parentWithTokens = ancestorWithTokens { + if let parentWithTokens = ancestorWithMoreTokens { let siblings = parentWithTokens.children(viewMode: .all) let siblingsAfter = siblings[siblings.index(after: index)...] for sibling in siblingsAfter { diff --git a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift index 5a682200f8e..a73e8b1cee2 100644 --- a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift +++ b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift @@ -953,27 +953,27 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor { } public override func visit(_ node: MissingDeclSyntax) -> SyntaxVisitorContinueKind { - return handleMissingSyntax(node) + return handleMissingSyntax(node, additionalHandledNodes: [node.placeholder.id]) } public override func visit(_ node: MissingExprSyntax) -> SyntaxVisitorContinueKind { - return handleMissingSyntax(node) + return handleMissingSyntax(node, additionalHandledNodes: [node.placeholder.id]) } public override func visit(_ node: MissingPatternSyntax) -> SyntaxVisitorContinueKind { - return handleMissingSyntax(node) + return handleMissingSyntax(node, additionalHandledNodes: [node.placeholder.id]) } public override func visit(_ node: MissingStmtSyntax) -> SyntaxVisitorContinueKind { - return handleMissingSyntax(node) + return handleMissingSyntax(node, additionalHandledNodes: [node.placeholder.id]) } public override func visit(_ node: MissingSyntax) -> SyntaxVisitorContinueKind { - return handleMissingSyntax(node) + return handleMissingSyntax(node, additionalHandledNodes: [node.placeholder.id]) } public override func visit(_ node: MissingTypeSyntax) -> SyntaxVisitorContinueKind { - return handleMissingSyntax(node) + return handleMissingSyntax(node, additionalHandledNodes: [node.placeholder.id]) } public override func visit(_ node: OperatorDeclSyntax) -> SyntaxVisitorContinueKind { diff --git a/Sources/SwiftParserDiagnostics/PresenceUtils.swift b/Sources/SwiftParserDiagnostics/PresenceUtils.swift index fdc4a711990..654ca8d0973 100644 --- a/Sources/SwiftParserDiagnostics/PresenceUtils.swift +++ b/Sources/SwiftParserDiagnostics/PresenceUtils.swift @@ -60,62 +60,6 @@ class PresentMaker: SyntaxRewriter { return token } } - - override func visit(_ node: MissingDeclSyntax) -> DeclSyntax { - let leadingTriviaBeforePlaceholder: Trivia - if node.isMissingAllTokens { - leadingTriviaBeforePlaceholder = [] - } else if node.modifiers != nil { - leadingTriviaBeforePlaceholder = .space - } else { - leadingTriviaBeforePlaceholder = .newline - } - return DeclSyntax( - StructDeclSyntax( - node.unexpectedBeforeAttributes, - attributes: node.attributes, - node.unexpectedBetweenAttributesAndModifiers, - modifiers: node.modifiers, - structKeyword: .keyword(.struct, presence: .missing), - identifier: .identifier("<#declaration#>", leadingTrivia: leadingTriviaBeforePlaceholder), - memberBlock: MemberDeclBlockSyntax( - leftBrace: .leftBraceToken(presence: .missing), - members: MemberDeclListSyntax([]), - rightBrace: .rightBraceToken(presence: .missing) - ) - ) - ) - } - - override func visit(_ node: MissingExprSyntax) -> ExprSyntax { - return ExprSyntax(IdentifierExprSyntax(identifier: .identifier("<#expression#>"))) - } - - override func visit(_ node: MissingPatternSyntax) -> PatternSyntax { - return PatternSyntax(IdentifierPatternSyntax(identifier: .identifier("<#pattern#>"))) - } - - override func visit(_ node: MissingStmtSyntax) -> StmtSyntax { - return StmtSyntax( - DoStmtSyntax( - doKeyword: .keyword(.do, presence: .missing), - UnexpectedNodesSyntax([Syntax(TokenSyntax.identifier("<#statement#>"))]), - body: CodeBlockSyntax( - leftBrace: .leftBraceToken(presence: .missing), - statements: CodeBlockItemListSyntax([]), - rightBrace: .rightBraceToken(presence: .missing) - ) - ) - ) - } - - override func visit(_ node: MissingTypeSyntax) -> TypeSyntax { - return TypeSyntax(SimpleTypeIdentifierSyntax(name: .identifier("<#type#>"))) - } - - override func visit(_ node: MissingSyntax) -> Syntax { - return Syntax(IdentifierExprSyntax(identifier: .identifier("<#syntax#>"))) - } } class MissingMaker: SyntaxRewriter { diff --git a/Sources/SwiftSyntax/CMakeLists.txt b/Sources/SwiftSyntax/CMakeLists.txt index 2c914bf601e..117fd67368e 100644 --- a/Sources/SwiftSyntax/CMakeLists.txt +++ b/Sources/SwiftSyntax/CMakeLists.txt @@ -12,6 +12,8 @@ add_swift_host_library(SwiftSyntax BumpPtrAllocator.swift CommonAncestor.swift IncrementalParseTransition.swift + MemoryLayout.swift + MissingNodeInitializers.swift Trivia.swift SourceLength.swift SourceLocation.swift diff --git a/Sources/SwiftSyntax/MissingNodeInitializers.swift b/Sources/SwiftSyntax/MissingNodeInitializers.swift new file mode 100644 index 00000000000..9e71c05fc89 --- /dev/null +++ b/Sources/SwiftSyntax/MissingNodeInitializers.swift @@ -0,0 +1,127 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +public extension MissingDeclSyntax { + init( + attributes: AttributeListSyntax?, + modifiers: ModifierListSyntax?, + arena: __shared SyntaxArena + ) { + self.init( + attributes: attributes, + modifiers: modifiers, + placeholder: TokenSyntax.identifier("<#declaration#>") + ) + } +} + +public extension MissingExprSyntax { + init() { + self.init( + placeholder: TokenSyntax.identifier("<#expression#>") + ) + } +} + +public extension MissingPatternSyntax { + init() { + self.init( + placeholder: TokenSyntax.identifier("<#pattern#>") + ) + } +} + +public extension MissingStmtSyntax { + init() { + self.init( + placeholder: TokenSyntax.identifier("<#statement#>") + ) + } +} + +public extension MissingTypeSyntax { + init() { + self.init( + placeholder: TokenSyntax.identifier("<#type#>") + ) + } +} + +public extension MissingSyntax { + init() { + self.init( + placeholder: TokenSyntax.identifier("<#syntax#>") + ) + } +} + +// MARK: - Raw + +public extension RawMissingDeclSyntax { + init( + attributes: RawAttributeListSyntax?, + modifiers: RawModifierListSyntax?, + arena: __shared SyntaxArena + ) { + self.init( + attributes: attributes, + modifiers: modifiers, + placeholder: RawTokenSyntax(missing: .identifier, text: "<#declaration#>", arena: arena), + arena: arena + ) + } +} + +public extension RawMissingExprSyntax { + init(arena: __shared SyntaxArena) { + self.init( + placeholder: RawTokenSyntax(missing: .identifier, text: "<#expression#>", arena: arena), + arena: arena + ) + } +} + +public extension RawMissingPatternSyntax { + init(arena: __shared SyntaxArena) { + self.init( + placeholder: RawTokenSyntax(missing: .identifier, text: "<#pattern#>", arena: arena), + arena: arena + ) + } +} + +public extension RawMissingStmtSyntax { + init(arena: __shared SyntaxArena) { + self.init( + placeholder: RawTokenSyntax(missing: .identifier, text: "<#statement#>", arena: arena), + arena: arena + ) + } +} + +public extension RawMissingTypeSyntax { + init(arena: __shared SyntaxArena) { + self.init( + placeholder: RawTokenSyntax(missing: .identifier, text: "<#type#>", arena: arena), + arena: arena + ) + } +} + +public extension RawMissingSyntax { + init(arena: __shared SyntaxArena) { + self.init( + placeholder: RawTokenSyntax(missing: .identifier, text: "<#syntax#>", arena: arena), + arena: arena + ) + } +} diff --git a/Sources/SwiftSyntax/Raw/RawSyntaxTokenView.swift b/Sources/SwiftSyntax/Raw/RawSyntaxTokenView.swift index 8168bfbfaa7..d1ad19f9a01 100644 --- a/Sources/SwiftSyntax/Raw/RawSyntaxTokenView.swift +++ b/Sources/SwiftSyntax/Raw/RawSyntaxTokenView.swift @@ -174,6 +174,7 @@ public struct RawSyntaxTokenView { /// kind changed to `newValue`. @_spi(RawSyntax) public func withKind(_ newValue: TokenKind, arena: SyntaxArena) -> RawSyntax { + arena.addChild(self.raw.arenaReference) switch raw.rawData.payload { case .parsedToken(_): // The wholeText can't be continuous anymore. Make a materialized token. @@ -200,6 +201,7 @@ public struct RawSyntaxTokenView { /// Returns a `RawSyntax` node with the presence changed to `newValue`. @_spi(RawSyntax) public func withPresence(_ newValue: SourcePresence, arena: SyntaxArena) -> RawSyntax { + arena.addChild(self.raw.arenaReference) switch raw.rawData.payload { case .parsedToken(var payload): payload.presence = newValue @@ -269,6 +271,7 @@ public struct RawSyntaxTokenView { @_spi(RawSyntax) public func withTokenDiagnostic(tokenDiagnostic: TokenDiagnostic?, arena: SyntaxArena) -> RawSyntax { + arena.addChild(self.raw.arenaReference) switch raw.rawData.payload { case .parsedToken(var dat): dat.tokenDiagnostic = tokenDiagnostic diff --git a/Sources/SwiftSyntax/Syntax.swift b/Sources/SwiftSyntax/Syntax.swift index 4cb0e2be99e..b9af71fe0b8 100644 --- a/Sources/SwiftSyntax/Syntax.swift +++ b/Sources/SwiftSyntax/Syntax.swift @@ -660,21 +660,22 @@ public protocol SyntaxChildChoices: SyntaxProtocol {} public struct TokenSequence: Sequence { public struct Iterator: IteratorProtocol { var nextToken: TokenSyntax? - let endPosition: AbsolutePosition + /// The last token to iterate (inclusive). + let endToken: TokenSyntax? let viewMode: SyntaxTreeViewMode - init(_ token: TokenSyntax?, endPosition: AbsolutePosition, viewMode: SyntaxTreeViewMode) { + init(_ token: TokenSyntax?, endToken: TokenSyntax?, viewMode: SyntaxTreeViewMode) { self.nextToken = token - self.endPosition = endPosition + self.endToken = endToken self.viewMode = viewMode } public mutating func next() -> TokenSyntax? { guard let token = self.nextToken else { return nil } - self.nextToken = token.nextToken(viewMode: viewMode) - // Make sure we stop once we reach the end of the containing node. - if let nextTok = self.nextToken, nextTok.position >= self.endPosition { + if nextToken == endToken { self.nextToken = nil + } else { + self.nextToken = token.nextToken(viewMode: viewMode) } return token } @@ -689,7 +690,7 @@ public struct TokenSequence: Sequence { } public func makeIterator() -> Iterator { - return Iterator(node.firstToken(viewMode: viewMode), endPosition: node.endPosition, viewMode: viewMode) + return Iterator(node.firstToken(viewMode: viewMode), endToken: node.lastToken(viewMode: viewMode), viewMode: viewMode) } public func reversed() -> ReversedTokenSequence { diff --git a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift index 449aad295b6..25c595d3ea7 100644 --- a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift +++ b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift @@ -2126,18 +2126,42 @@ internal func childName(_ keyPath: AnyKeyPath) -> String? { return "unexpectedBetweenAttributesAndModifiers" case \MissingDeclSyntax.modifiers: return "modifiers" - case \MissingDeclSyntax.unexpectedAfterModifiers: - return "unexpectedAfterModifiers" - case \MissingExprSyntax.unexpected: - return "unexpected" - case \MissingPatternSyntax.unexpected: - return "unexpected" - case \MissingStmtSyntax.unexpected: - return "unexpected" - case \MissingSyntax.unexpected: - return "unexpected" - case \MissingTypeSyntax.unexpected: - return "unexpected" + case \MissingDeclSyntax.unexpectedBetweenModifiersAndPlaceholder: + return "unexpectedBetweenModifiersAndPlaceholder" + case \MissingDeclSyntax.placeholder: + return "placeholder" + case \MissingDeclSyntax.unexpectedAfterPlaceholder: + return "unexpectedAfterPlaceholder" + case \MissingExprSyntax.unexpectedBeforePlaceholder: + return "unexpectedBeforePlaceholder" + case \MissingExprSyntax.placeholder: + return "placeholder" + case \MissingExprSyntax.unexpectedAfterPlaceholder: + return "unexpectedAfterPlaceholder" + case \MissingPatternSyntax.unexpectedBeforePlaceholder: + return "unexpectedBeforePlaceholder" + case \MissingPatternSyntax.placeholder: + return "placeholder" + case \MissingPatternSyntax.unexpectedAfterPlaceholder: + return "unexpectedAfterPlaceholder" + case \MissingStmtSyntax.unexpectedBeforePlaceholder: + return "unexpectedBeforePlaceholder" + case \MissingStmtSyntax.placeholder: + return "placeholder" + case \MissingStmtSyntax.unexpectedAfterPlaceholder: + return "unexpectedAfterPlaceholder" + case \MissingSyntax.unexpectedBeforePlaceholder: + return "unexpectedBeforePlaceholder" + case \MissingSyntax.placeholder: + return "placeholder" + case \MissingSyntax.unexpectedAfterPlaceholder: + return "unexpectedAfterPlaceholder" + case \MissingTypeSyntax.unexpectedBeforePlaceholder: + return "unexpectedBeforePlaceholder" + case \MissingTypeSyntax.placeholder: + return "placeholder" + case \MissingTypeSyntax.unexpectedAfterPlaceholder: + return "unexpectedAfterPlaceholder" case \MoveExprSyntax.unexpectedBeforeMoveKeyword: return "unexpectedBeforeMoveKeyword" case \MoveExprSyntax.moveKeyword: diff --git a/Sources/SwiftSyntax/generated/SyntaxRewriter.swift b/Sources/SwiftSyntax/generated/SyntaxRewriter.swift index 8c68ef93b2b..3fdb902fd64 100644 --- a/Sources/SwiftSyntax/generated/SyntaxRewriter.swift +++ b/Sources/SwiftSyntax/generated/SyntaxRewriter.swift @@ -6941,4 +6941,12 @@ open class SyntaxRewriter { return node } } + + /// Rewrite `node` and anchor, making sure that the rewritten node also has + /// a parent if `node` had one. + public func rewrite(_ node: Syntax) -> Syntax { + let rewritten = self.visit(node) + let arena = SyntaxArena() + return Syntax(node.data.replacingSelf(rewritten.raw, arena: arena)) + } } diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift index 552f6f7f0e8..9119faec524 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift @@ -13988,17 +13988,21 @@ public struct RawMissingDeclSyntax: RawDeclSyntaxNodeProtocol { attributes: RawAttributeListSyntax?, _ unexpectedBetweenAttributesAndModifiers: RawUnexpectedNodesSyntax? = nil, modifiers: RawModifierListSyntax?, - _ unexpectedAfterModifiers: RawUnexpectedNodesSyntax? = nil, + _ unexpectedBetweenModifiersAndPlaceholder: RawUnexpectedNodesSyntax? = nil, + placeholder: RawTokenSyntax, + _ unexpectedAfterPlaceholder: RawUnexpectedNodesSyntax? = nil, arena: __shared SyntaxArena ) { let raw = RawSyntax.makeLayout( - kind: .missingDecl, uninitializedCount: 5, arena: arena) { layout in + kind: .missingDecl, uninitializedCount: 7, arena: arena) { layout in layout.initialize(repeating: nil) layout[0] = unexpectedBeforeAttributes?.raw layout[1] = attributes?.raw layout[2] = unexpectedBetweenAttributesAndModifiers?.raw layout[3] = modifiers?.raw - layout[4] = unexpectedAfterModifiers?.raw + layout[4] = unexpectedBetweenModifiersAndPlaceholder?.raw + layout[5] = placeholder.raw + layout[6] = unexpectedAfterPlaceholder?.raw } self.init(unchecked: raw) } @@ -14019,9 +14023,17 @@ public struct RawMissingDeclSyntax: RawDeclSyntaxNodeProtocol { layoutView.children[3].map(RawModifierListSyntax.init(raw:)) } - public var unexpectedAfterModifiers: RawUnexpectedNodesSyntax? { + public var unexpectedBetweenModifiersAndPlaceholder: RawUnexpectedNodesSyntax? { layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:)) } + + public var placeholder: RawTokenSyntax { + layoutView.children[5].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedAfterPlaceholder: RawUnexpectedNodesSyntax? { + layoutView.children[6].map(RawUnexpectedNodesSyntax.init(raw:)) + } } @_spi(RawSyntax) @@ -14053,18 +14065,33 @@ public struct RawMissingExprSyntax: RawExprSyntaxNodeProtocol { self.init(unchecked: other.raw) } - public init(_ unexpected: RawUnexpectedNodesSyntax? = nil, arena: __shared SyntaxArena) { + public init( + _ unexpectedBeforePlaceholder: RawUnexpectedNodesSyntax? = nil, + placeholder: RawTokenSyntax, + _ unexpectedAfterPlaceholder: RawUnexpectedNodesSyntax? = nil, + arena: __shared SyntaxArena + ) { let raw = RawSyntax.makeLayout( - kind: .missingExpr, uninitializedCount: 1, arena: arena) { layout in + kind: .missingExpr, uninitializedCount: 3, arena: arena) { layout in layout.initialize(repeating: nil) - layout[0] = unexpected?.raw + layout[0] = unexpectedBeforePlaceholder?.raw + layout[1] = placeholder.raw + layout[2] = unexpectedAfterPlaceholder?.raw } self.init(unchecked: raw) } - public var unexpected: RawUnexpectedNodesSyntax? { + public var unexpectedBeforePlaceholder: RawUnexpectedNodesSyntax? { layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) } + + public var placeholder: RawTokenSyntax { + layoutView.children[1].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedAfterPlaceholder: RawUnexpectedNodesSyntax? { + layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) + } } @_spi(RawSyntax) @@ -14096,18 +14123,33 @@ public struct RawMissingPatternSyntax: RawPatternSyntaxNodeProtocol { self.init(unchecked: other.raw) } - public init(_ unexpected: RawUnexpectedNodesSyntax? = nil, arena: __shared SyntaxArena) { + public init( + _ unexpectedBeforePlaceholder: RawUnexpectedNodesSyntax? = nil, + placeholder: RawTokenSyntax, + _ unexpectedAfterPlaceholder: RawUnexpectedNodesSyntax? = nil, + arena: __shared SyntaxArena + ) { let raw = RawSyntax.makeLayout( - kind: .missingPattern, uninitializedCount: 1, arena: arena) { layout in + kind: .missingPattern, uninitializedCount: 3, arena: arena) { layout in layout.initialize(repeating: nil) - layout[0] = unexpected?.raw + layout[0] = unexpectedBeforePlaceholder?.raw + layout[1] = placeholder.raw + layout[2] = unexpectedAfterPlaceholder?.raw } self.init(unchecked: raw) } - public var unexpected: RawUnexpectedNodesSyntax? { + public var unexpectedBeforePlaceholder: RawUnexpectedNodesSyntax? { layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) } + + public var placeholder: RawTokenSyntax { + layoutView.children[1].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedAfterPlaceholder: RawUnexpectedNodesSyntax? { + layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) + } } @_spi(RawSyntax) @@ -14139,18 +14181,33 @@ public struct RawMissingStmtSyntax: RawStmtSyntaxNodeProtocol { self.init(unchecked: other.raw) } - public init(_ unexpected: RawUnexpectedNodesSyntax? = nil, arena: __shared SyntaxArena) { + public init( + _ unexpectedBeforePlaceholder: RawUnexpectedNodesSyntax? = nil, + placeholder: RawTokenSyntax, + _ unexpectedAfterPlaceholder: RawUnexpectedNodesSyntax? = nil, + arena: __shared SyntaxArena + ) { let raw = RawSyntax.makeLayout( - kind: .missingStmt, uninitializedCount: 1, arena: arena) { layout in + kind: .missingStmt, uninitializedCount: 3, arena: arena) { layout in layout.initialize(repeating: nil) - layout[0] = unexpected?.raw + layout[0] = unexpectedBeforePlaceholder?.raw + layout[1] = placeholder.raw + layout[2] = unexpectedAfterPlaceholder?.raw } self.init(unchecked: raw) } - public var unexpected: RawUnexpectedNodesSyntax? { + public var unexpectedBeforePlaceholder: RawUnexpectedNodesSyntax? { layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) } + + public var placeholder: RawTokenSyntax { + layoutView.children[1].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedAfterPlaceholder: RawUnexpectedNodesSyntax? { + layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) + } } @_spi(RawSyntax) @@ -14182,18 +14239,33 @@ public struct RawMissingSyntax: RawSyntaxNodeProtocol { self.init(unchecked: other.raw) } - public init(_ unexpected: RawUnexpectedNodesSyntax? = nil, arena: __shared SyntaxArena) { + public init( + _ unexpectedBeforePlaceholder: RawUnexpectedNodesSyntax? = nil, + placeholder: RawTokenSyntax, + _ unexpectedAfterPlaceholder: RawUnexpectedNodesSyntax? = nil, + arena: __shared SyntaxArena + ) { let raw = RawSyntax.makeLayout( - kind: .missing, uninitializedCount: 1, arena: arena) { layout in + kind: .missing, uninitializedCount: 3, arena: arena) { layout in layout.initialize(repeating: nil) - layout[0] = unexpected?.raw + layout[0] = unexpectedBeforePlaceholder?.raw + layout[1] = placeholder.raw + layout[2] = unexpectedAfterPlaceholder?.raw } self.init(unchecked: raw) } - public var unexpected: RawUnexpectedNodesSyntax? { + public var unexpectedBeforePlaceholder: RawUnexpectedNodesSyntax? { layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) } + + public var placeholder: RawTokenSyntax { + layoutView.children[1].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedAfterPlaceholder: RawUnexpectedNodesSyntax? { + layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) + } } @_spi(RawSyntax) @@ -14225,18 +14297,33 @@ public struct RawMissingTypeSyntax: RawTypeSyntaxNodeProtocol { self.init(unchecked: other.raw) } - public init(_ unexpected: RawUnexpectedNodesSyntax? = nil, arena: __shared SyntaxArena) { + public init( + _ unexpectedBeforePlaceholder: RawUnexpectedNodesSyntax? = nil, + placeholder: RawTokenSyntax, + _ unexpectedAfterPlaceholder: RawUnexpectedNodesSyntax? = nil, + arena: __shared SyntaxArena + ) { let raw = RawSyntax.makeLayout( - kind: .missingType, uninitializedCount: 1, arena: arena) { layout in + kind: .missingType, uninitializedCount: 3, arena: arena) { layout in layout.initialize(repeating: nil) - layout[0] = unexpected?.raw + layout[0] = unexpectedBeforePlaceholder?.raw + layout[1] = placeholder.raw + layout[2] = unexpectedAfterPlaceholder?.raw } self.init(unchecked: raw) } - public var unexpected: RawUnexpectedNodesSyntax? { + public var unexpectedBeforePlaceholder: RawUnexpectedNodesSyntax? { layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) } + + public var placeholder: RawTokenSyntax { + layoutView.children[1].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedAfterPlaceholder: RawUnexpectedNodesSyntax? { + layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) + } } @_spi(RawSyntax) diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift index a13929585df..0a04d3fc683 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift @@ -1775,27 +1775,39 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.keyword("Type"), .keyword("Protocol")])) assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) case .missingDecl: - assert(layout.count == 5) + assert(layout.count == 7) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 1, verify(layout[1], as: RawAttributeListSyntax?.self)) assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 3, verify(layout[3], as: RawModifierListSyntax?.self)) assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier)])) + assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) case .missingExpr: - assert(layout.count == 1) + assert(layout.count == 3) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier)])) + assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) case .missingPattern: - assert(layout.count == 1) + assert(layout.count == 3) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier)])) + assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) case .missingStmt: - assert(layout.count == 1) + assert(layout.count == 3) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier)])) + assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) case .missing: - assert(layout.count == 1) + assert(layout.count == 3) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier)])) + assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) case .missingType: - assert(layout.count == 1) + assert(layout.count == 3) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier)])) + assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) case .modifierList: for (index, element) in layout.enumerated() { assertNoError(kind, index, verify(element, as: RawDeclModifierSyntax.self)) diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxDeclNodes.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxDeclNodes.swift index 465f850fa9a..7c222d03f1a 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxDeclNodes.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxDeclNodes.swift @@ -3914,7 +3914,7 @@ public struct MacroExpansionDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { // MARK: - MissingDeclSyntax - +/// In case the source code is missing a declaration, this node stands in place of the missing declaration. public struct MissingDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { public let _syntaxNode: Syntax @@ -3939,7 +3939,9 @@ public struct MissingDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { attributes: AttributeListSyntax? = nil, _ unexpectedBetweenAttributesAndModifiers: UnexpectedNodesSyntax? = nil, modifiers: ModifierListSyntax? = nil, - _ unexpectedAfterModifiers: UnexpectedNodesSyntax? = nil, + _ unexpectedBetweenModifiersAndPlaceholder: UnexpectedNodesSyntax? = nil, + placeholder: TokenSyntax, + _ unexpectedAfterPlaceholder: UnexpectedNodesSyntax? = nil, trailingTrivia: Trivia? = nil ) { @@ -3950,14 +3952,18 @@ public struct MissingDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { attributes, unexpectedBetweenAttributesAndModifiers, modifiers, - unexpectedAfterModifiers + unexpectedBetweenModifiersAndPlaceholder, + placeholder, + unexpectedAfterPlaceholder ))) {(arena, _) in let layout: [RawSyntax?] = [ unexpectedBeforeAttributes?.raw, attributes?.raw, unexpectedBetweenAttributesAndModifiers?.raw, modifiers?.raw, - unexpectedAfterModifiers?.raw + unexpectedBetweenModifiersAndPlaceholder?.raw, + placeholder.raw, + unexpectedAfterPlaceholder?.raw ] let raw = RawSyntax.makeLayout( kind: SyntaxKind.missingDecl, @@ -3981,6 +3987,7 @@ public struct MissingDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { } } + /// If there were standalone attributes without a declaration to attach them to, the `MissingDeclSyntax` will contain these. public var attributes: AttributeListSyntax? { get { return data.child(at: 1, parent: Syntax(self)).map(AttributeListSyntax.init) @@ -4018,6 +4025,7 @@ public struct MissingDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { } } + /// If there were standalone modifiers without a declaration to attach them to, the `MissingDeclSyntax` will contain these. public var modifiers: ModifierListSyntax? { get { return data.child(at: 3, parent: Syntax(self)).map(ModifierListSyntax.init) @@ -4046,7 +4054,7 @@ public struct MissingDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { return MissingDeclSyntax(newData) } - public var unexpectedAfterModifiers: UnexpectedNodesSyntax? { + public var unexpectedBetweenModifiersAndPlaceholder: UnexpectedNodesSyntax? { get { return data.child(at: 4, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } @@ -4055,13 +4063,34 @@ public struct MissingDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { } } + /// A placeholder, i.e. `<#decl#>` that can be inserted into the source code to represent the missing declaration./// This token should always have `presence = .missing`. + public var placeholder: TokenSyntax { + get { + return TokenSyntax(data.child(at: 5, parent: Syntax(self))!) + } + set(value) { + self = MissingDeclSyntax(data.replacingChild(at: 5, with: value.raw, arena: SyntaxArena())) + } + } + + public var unexpectedAfterPlaceholder: UnexpectedNodesSyntax? { + get { + return data.child(at: 6, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = MissingDeclSyntax(data.replacingChild(at: 6, with: value?.raw, arena: SyntaxArena())) + } + } + public static var structure: SyntaxNodeStructure { return .layout([ \Self.unexpectedBeforeAttributes, \Self.attributes, \Self.unexpectedBetweenAttributesAndModifiers, \Self.modifiers, - \Self.unexpectedAfterModifiers + \Self.unexpectedBetweenModifiersAndPlaceholder, + \Self.placeholder, + \Self.unexpectedAfterPlaceholder ]) } } diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxExprNodes.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxExprNodes.swift index fc1a0dc5e6d..98dd79a1c38 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxExprNodes.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxExprNodes.swift @@ -3467,7 +3467,7 @@ public struct MemberAccessExprSyntax: ExprSyntaxProtocol, SyntaxHashable { // MARK: - MissingExprSyntax - +/// In case the source code is missing a expression, this node stands in place of the missing expression. public struct MissingExprSyntax: ExprSyntaxProtocol, SyntaxHashable { public let _syntaxNode: Syntax @@ -3487,14 +3487,17 @@ public struct MissingExprSyntax: ExprSyntaxProtocol, SyntaxHashable { } public init( - leadingTrivia: Trivia? = nil, - _ unexpected: UnexpectedNodesSyntax? = nil, - trailingTrivia: Trivia? = nil + leadingTrivia: Trivia? = nil, + _ unexpectedBeforePlaceholder: UnexpectedNodesSyntax? = nil, + placeholder: TokenSyntax, + _ unexpectedAfterPlaceholder: UnexpectedNodesSyntax? = nil, + trailingTrivia: Trivia? = nil + ) { // Extend the lifetime of all parameters so their arenas don't get destroyed // before they can be added as children of the new arena. - let data: SyntaxData = withExtendedLifetime((SyntaxArena(), (unexpected))) {(arena, _) in - let layout: [RawSyntax?] = [unexpected?.raw] + let data: SyntaxData = withExtendedLifetime((SyntaxArena(), (unexpectedBeforePlaceholder, placeholder, unexpectedAfterPlaceholder))) {(arena, _) in + let layout: [RawSyntax?] = [unexpectedBeforePlaceholder?.raw, placeholder.raw, unexpectedAfterPlaceholder?.raw] let raw = RawSyntax.makeLayout( kind: SyntaxKind.missingExpr, from: layout, @@ -3508,7 +3511,7 @@ public struct MissingExprSyntax: ExprSyntaxProtocol, SyntaxHashable { self.init(data) } - public var unexpected: UnexpectedNodesSyntax? { + public var unexpectedBeforePlaceholder: UnexpectedNodesSyntax? { get { return data.child(at: 0, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } @@ -3517,8 +3520,27 @@ public struct MissingExprSyntax: ExprSyntaxProtocol, SyntaxHashable { } } + /// A placeholder, i.e. `<#expression#>` that can be inserted into the source code to represent the missing expression./// This token should always have `presence = .missing`. + public var placeholder: TokenSyntax { + get { + return TokenSyntax(data.child(at: 1, parent: Syntax(self))!) + } + set(value) { + self = MissingExprSyntax(data.replacingChild(at: 1, with: value.raw, arena: SyntaxArena())) + } + } + + public var unexpectedAfterPlaceholder: UnexpectedNodesSyntax? { + get { + return data.child(at: 2, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = MissingExprSyntax(data.replacingChild(at: 2, with: value?.raw, arena: SyntaxArena())) + } + } + public static var structure: SyntaxNodeStructure { - return .layout([\Self.unexpected]) + return .layout([\Self.unexpectedBeforePlaceholder, \Self.placeholder, \Self.unexpectedAfterPlaceholder]) } } diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodes.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodes.swift index f9abd9a30de..ff4acd30865 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodes.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodes.swift @@ -12242,7 +12242,7 @@ public struct MemberDeclListItemSyntax: SyntaxProtocol, SyntaxHashable { // MARK: - MissingSyntax - +/// In case the source code is missing a syntax node, this node stands in place of the missing node. public struct MissingSyntax: SyntaxProtocol, SyntaxHashable { public let _syntaxNode: Syntax @@ -12262,14 +12262,17 @@ public struct MissingSyntax: SyntaxProtocol, SyntaxHashable { } public init( - leadingTrivia: Trivia? = nil, - _ unexpected: UnexpectedNodesSyntax? = nil, - trailingTrivia: Trivia? = nil + leadingTrivia: Trivia? = nil, + _ unexpectedBeforePlaceholder: UnexpectedNodesSyntax? = nil, + placeholder: TokenSyntax, + _ unexpectedAfterPlaceholder: UnexpectedNodesSyntax? = nil, + trailingTrivia: Trivia? = nil + ) { // Extend the lifetime of all parameters so their arenas don't get destroyed // before they can be added as children of the new arena. - let data: SyntaxData = withExtendedLifetime((SyntaxArena(), (unexpected))) {(arena, _) in - let layout: [RawSyntax?] = [unexpected?.raw] + let data: SyntaxData = withExtendedLifetime((SyntaxArena(), (unexpectedBeforePlaceholder, placeholder, unexpectedAfterPlaceholder))) {(arena, _) in + let layout: [RawSyntax?] = [unexpectedBeforePlaceholder?.raw, placeholder.raw, unexpectedAfterPlaceholder?.raw] let raw = RawSyntax.makeLayout( kind: SyntaxKind.missing, from: layout, @@ -12283,7 +12286,7 @@ public struct MissingSyntax: SyntaxProtocol, SyntaxHashable { self.init(data) } - public var unexpected: UnexpectedNodesSyntax? { + public var unexpectedBeforePlaceholder: UnexpectedNodesSyntax? { get { return data.child(at: 0, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } @@ -12292,8 +12295,27 @@ public struct MissingSyntax: SyntaxProtocol, SyntaxHashable { } } + /// A placeholder, i.e. `<#syntax#>` that can be inserted into the source code to represent the missing pattern./// This token should always have `presence = .missing` + public var placeholder: TokenSyntax { + get { + return TokenSyntax(data.child(at: 1, parent: Syntax(self))!) + } + set(value) { + self = MissingSyntax(data.replacingChild(at: 1, with: value.raw, arena: SyntaxArena())) + } + } + + public var unexpectedAfterPlaceholder: UnexpectedNodesSyntax? { + get { + return data.child(at: 2, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = MissingSyntax(data.replacingChild(at: 2, with: value?.raw, arena: SyntaxArena())) + } + } + public static var structure: SyntaxNodeStructure { - return .layout([\Self.unexpected]) + return .layout([\Self.unexpectedBeforePlaceholder, \Self.placeholder, \Self.unexpectedAfterPlaceholder]) } } diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxPatternNodes.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxPatternNodes.swift index 74817e3e838..3c57a873352 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxPatternNodes.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxPatternNodes.swift @@ -286,7 +286,7 @@ public struct IsTypePatternSyntax: PatternSyntaxProtocol, SyntaxHashable { // MARK: - MissingPatternSyntax - +/// In case the source code is missing a pattern, this node stands in place of the missing pattern. public struct MissingPatternSyntax: PatternSyntaxProtocol, SyntaxHashable { public let _syntaxNode: Syntax @@ -306,14 +306,17 @@ public struct MissingPatternSyntax: PatternSyntaxProtocol, SyntaxHashable { } public init( - leadingTrivia: Trivia? = nil, - _ unexpected: UnexpectedNodesSyntax? = nil, - trailingTrivia: Trivia? = nil + leadingTrivia: Trivia? = nil, + _ unexpectedBeforePlaceholder: UnexpectedNodesSyntax? = nil, + placeholder: TokenSyntax, + _ unexpectedAfterPlaceholder: UnexpectedNodesSyntax? = nil, + trailingTrivia: Trivia? = nil + ) { // Extend the lifetime of all parameters so their arenas don't get destroyed // before they can be added as children of the new arena. - let data: SyntaxData = withExtendedLifetime((SyntaxArena(), (unexpected))) {(arena, _) in - let layout: [RawSyntax?] = [unexpected?.raw] + let data: SyntaxData = withExtendedLifetime((SyntaxArena(), (unexpectedBeforePlaceholder, placeholder, unexpectedAfterPlaceholder))) {(arena, _) in + let layout: [RawSyntax?] = [unexpectedBeforePlaceholder?.raw, placeholder.raw, unexpectedAfterPlaceholder?.raw] let raw = RawSyntax.makeLayout( kind: SyntaxKind.missingPattern, from: layout, @@ -327,7 +330,7 @@ public struct MissingPatternSyntax: PatternSyntaxProtocol, SyntaxHashable { self.init(data) } - public var unexpected: UnexpectedNodesSyntax? { + public var unexpectedBeforePlaceholder: UnexpectedNodesSyntax? { get { return data.child(at: 0, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } @@ -336,8 +339,27 @@ public struct MissingPatternSyntax: PatternSyntaxProtocol, SyntaxHashable { } } + /// A placeholder, i.e. `<#pattern#>` that can be inserted into the source code to represent the missing pattern./// This token should always have `presence = .missing`. + public var placeholder: TokenSyntax { + get { + return TokenSyntax(data.child(at: 1, parent: Syntax(self))!) + } + set(value) { + self = MissingPatternSyntax(data.replacingChild(at: 1, with: value.raw, arena: SyntaxArena())) + } + } + + public var unexpectedAfterPlaceholder: UnexpectedNodesSyntax? { + get { + return data.child(at: 2, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = MissingPatternSyntax(data.replacingChild(at: 2, with: value?.raw, arena: SyntaxArena())) + } + } + public static var structure: SyntaxNodeStructure { - return .layout([\Self.unexpected]) + return .layout([\Self.unexpectedBeforePlaceholder, \Self.placeholder, \Self.unexpectedAfterPlaceholder]) } } diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxStmtNodes.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxStmtNodes.swift index 6e7b528890e..1370f48b786 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxStmtNodes.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxStmtNodes.swift @@ -1448,7 +1448,7 @@ public struct LabeledStmtSyntax: StmtSyntaxProtocol, SyntaxHashable { // MARK: - MissingStmtSyntax - +/// In case the source code is missing a statement, this node stands in place of the missing statement. public struct MissingStmtSyntax: StmtSyntaxProtocol, SyntaxHashable { public let _syntaxNode: Syntax @@ -1468,14 +1468,17 @@ public struct MissingStmtSyntax: StmtSyntaxProtocol, SyntaxHashable { } public init( - leadingTrivia: Trivia? = nil, - _ unexpected: UnexpectedNodesSyntax? = nil, - trailingTrivia: Trivia? = nil + leadingTrivia: Trivia? = nil, + _ unexpectedBeforePlaceholder: UnexpectedNodesSyntax? = nil, + placeholder: TokenSyntax, + _ unexpectedAfterPlaceholder: UnexpectedNodesSyntax? = nil, + trailingTrivia: Trivia? = nil + ) { // Extend the lifetime of all parameters so their arenas don't get destroyed // before they can be added as children of the new arena. - let data: SyntaxData = withExtendedLifetime((SyntaxArena(), (unexpected))) {(arena, _) in - let layout: [RawSyntax?] = [unexpected?.raw] + let data: SyntaxData = withExtendedLifetime((SyntaxArena(), (unexpectedBeforePlaceholder, placeholder, unexpectedAfterPlaceholder))) {(arena, _) in + let layout: [RawSyntax?] = [unexpectedBeforePlaceholder?.raw, placeholder.raw, unexpectedAfterPlaceholder?.raw] let raw = RawSyntax.makeLayout( kind: SyntaxKind.missingStmt, from: layout, @@ -1489,7 +1492,7 @@ public struct MissingStmtSyntax: StmtSyntaxProtocol, SyntaxHashable { self.init(data) } - public var unexpected: UnexpectedNodesSyntax? { + public var unexpectedBeforePlaceholder: UnexpectedNodesSyntax? { get { return data.child(at: 0, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } @@ -1498,8 +1501,27 @@ public struct MissingStmtSyntax: StmtSyntaxProtocol, SyntaxHashable { } } + /// A placeholder, i.e. `<#statement#>` that can be inserted into the source code to represent the missing pattern./// This token should always have `presence = .missing`. + public var placeholder: TokenSyntax { + get { + return TokenSyntax(data.child(at: 1, parent: Syntax(self))!) + } + set(value) { + self = MissingStmtSyntax(data.replacingChild(at: 1, with: value.raw, arena: SyntaxArena())) + } + } + + public var unexpectedAfterPlaceholder: UnexpectedNodesSyntax? { + get { + return data.child(at: 2, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = MissingStmtSyntax(data.replacingChild(at: 2, with: value?.raw, arena: SyntaxArena())) + } + } + public static var structure: SyntaxNodeStructure { - return .layout([\Self.unexpected]) + return .layout([\Self.unexpectedBeforePlaceholder, \Self.placeholder, \Self.unexpectedAfterPlaceholder]) } } diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxTypeNodes.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxTypeNodes.swift index e61414649cf..b3c42bda968 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxTypeNodes.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxTypeNodes.swift @@ -1441,7 +1441,7 @@ public struct MetatypeTypeSyntax: TypeSyntaxProtocol, SyntaxHashable { // MARK: - MissingTypeSyntax - +/// In case the source code is missing a type, this node stands in place of the missing type. public struct MissingTypeSyntax: TypeSyntaxProtocol, SyntaxHashable { public let _syntaxNode: Syntax @@ -1461,14 +1461,17 @@ public struct MissingTypeSyntax: TypeSyntaxProtocol, SyntaxHashable { } public init( - leadingTrivia: Trivia? = nil, - _ unexpected: UnexpectedNodesSyntax? = nil, - trailingTrivia: Trivia? = nil + leadingTrivia: Trivia? = nil, + _ unexpectedBeforePlaceholder: UnexpectedNodesSyntax? = nil, + placeholder: TokenSyntax, + _ unexpectedAfterPlaceholder: UnexpectedNodesSyntax? = nil, + trailingTrivia: Trivia? = nil + ) { // Extend the lifetime of all parameters so their arenas don't get destroyed // before they can be added as children of the new arena. - let data: SyntaxData = withExtendedLifetime((SyntaxArena(), (unexpected))) {(arena, _) in - let layout: [RawSyntax?] = [unexpected?.raw] + let data: SyntaxData = withExtendedLifetime((SyntaxArena(), (unexpectedBeforePlaceholder, placeholder, unexpectedAfterPlaceholder))) {(arena, _) in + let layout: [RawSyntax?] = [unexpectedBeforePlaceholder?.raw, placeholder.raw, unexpectedAfterPlaceholder?.raw] let raw = RawSyntax.makeLayout( kind: SyntaxKind.missingType, from: layout, @@ -1482,7 +1485,7 @@ public struct MissingTypeSyntax: TypeSyntaxProtocol, SyntaxHashable { self.init(data) } - public var unexpected: UnexpectedNodesSyntax? { + public var unexpectedBeforePlaceholder: UnexpectedNodesSyntax? { get { return data.child(at: 0, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } @@ -1491,8 +1494,27 @@ public struct MissingTypeSyntax: TypeSyntaxProtocol, SyntaxHashable { } } + /// A placeholder, i.e. `<#type#>` that can be inserted into the source code to represent the missing type. This token should always have `presence = .missing`. + public var placeholder: TokenSyntax { + get { + return TokenSyntax(data.child(at: 1, parent: Syntax(self))!) + } + set(value) { + self = MissingTypeSyntax(data.replacingChild(at: 1, with: value.raw, arena: SyntaxArena())) + } + } + + public var unexpectedAfterPlaceholder: UnexpectedNodesSyntax? { + get { + return data.child(at: 2, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = MissingTypeSyntax(data.replacingChild(at: 2, with: value?.raw, arena: SyntaxArena())) + } + } + public static var structure: SyntaxNodeStructure { - return .layout([\Self.unexpected]) + return .layout([\Self.unexpectedBeforePlaceholder, \Self.placeholder, \Self.unexpectedAfterPlaceholder]) } } diff --git a/Tests/SwiftIDEUtilsTest/ClassificationTests.swift b/Tests/SwiftIDEUtilsTest/ClassificationTests.swift index 7d18d05b999..8982cbd7f2e 100644 --- a/Tests/SwiftIDEUtilsTest/ClassificationTests.swift +++ b/Tests/SwiftIDEUtilsTest/ClassificationTests.swift @@ -117,8 +117,8 @@ public class ClassificationTests: XCTestCase { let tree = Parser.parse(source: source) do { let tokens = Array(tree.tokens(viewMode: .sourceAccurate)) - XCTAssertEqual(tokens.count, 4) - guard tokens.count == 4 else { + XCTAssertEqual(tokens.count, 5) + guard tokens.count == 5 else { return } let classif = tokens.map { $0.tokenClassification } @@ -130,6 +130,8 @@ public class ClassificationTests: XCTestCase { XCTAssertEqual(classif[2].range, ByteSourceRange(offset: 5, length: 1)) XCTAssertEqual(classif[3].kind, .typeIdentifier) XCTAssertEqual(classif[3].range, ByteSourceRange(offset: 7, length: 3)) + XCTAssertEqual(classif[4].kind, .none) + XCTAssertEqual(classif[4].range, ByteSourceRange(offset: 10, length: 0)) } do { let tok = tree.lastToken(viewMode: .sourceAccurate)!.previousToken(viewMode: .sourceAccurate)! @@ -145,8 +147,8 @@ public class ClassificationTests: XCTestCase { let tree = Parser.parse(source: source) let tokens = Array(tree.tokens(viewMode: .sourceAccurate)) - XCTAssertEqual(tokens.count, 10) - guard tokens.count == 10 else { + XCTAssertEqual(tokens.count, 11) + guard tokens.count == 11 else { return } let classif = tokens.map { $0.tokenClassification } @@ -170,6 +172,8 @@ public class ClassificationTests: XCTestCase { XCTAssertEqual(classif[8].range, ByteSourceRange(offset: 19, length: 1)) XCTAssertEqual(classif[9].kind, .integerLiteral) XCTAssertEqual(classif[9].range, ByteSourceRange(offset: 21, length: 1)) + XCTAssertEqual(classif[10].kind, .none) + XCTAssertEqual(classif[10].range, ByteSourceRange(offset: 22, length: 0)) } do { @@ -177,8 +181,8 @@ public class ClassificationTests: XCTestCase { let tree = Parser.parse(source: source) let tokens = Array(tree.tokens(viewMode: .sourceAccurate)) - XCTAssertEqual(tokens.count, 3) - guard tokens.count == 3 else { + XCTAssertEqual(tokens.count, 4) + guard tokens.count == 4 else { return } let classif = tokens.map { $0.tokenClassification } @@ -188,6 +192,8 @@ public class ClassificationTests: XCTestCase { XCTAssertEqual(classif[1].range, ByteSourceRange(offset: 6, length: 8)) XCTAssertEqual(classif[2].kind, .operatorIdentifier) XCTAssertEqual(classif[2].range, ByteSourceRange(offset: 15, length: 4)) + XCTAssertEqual(classif[3].kind, .none) + XCTAssertEqual(classif[3].range, ByteSourceRange(offset: 19, length: 0)) } } } diff --git a/Tests/SwiftParserTest/AttributeTests.swift b/Tests/SwiftParserTest/AttributeTests.swift index 19c859b1f21..ddea7673132 100644 --- a/Tests/SwiftParserTest/AttributeTests.swift +++ b/Tests/SwiftParserTest/AttributeTests.swift @@ -311,8 +311,7 @@ final class AttributeTests: XCTestCase { "@resultBuilder1️⃣", diagnostics: [DiagnosticSpec(message: "expected declaration after attribute", fixIts: ["insert declaration"])], fixedSource: """ - @resultBuilder - <#declaration#> + @resultBuilder<#declaration#> """ ) } diff --git a/Tests/SwiftParserTest/DeclarationTests.swift b/Tests/SwiftParserTest/DeclarationTests.swift index 886c7d91ce1..6e49712a253 100644 --- a/Tests/SwiftParserTest/DeclarationTests.swift +++ b/Tests/SwiftParserTest/DeclarationTests.swift @@ -1384,8 +1384,7 @@ final class DeclarationTests: XCTestCase { "protocol1️⃣<2️⃣:3️⃣", diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in protocol", fixIts: ["insert identifier"]), - DiagnosticSpec(locationMarker: "2️⃣", message: "expected name in primary associated type clause", fixIts: ["insert name"]), - DiagnosticSpec(locationMarker: "2️⃣", message: "expected '>' to end primary associated type clause", fixIts: ["insert '>'"]), + DiagnosticSpec(locationMarker: "2️⃣", message: "expected name and '>' to end primary associated type clause", fixIts: ["insert name and '>'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected type in inherited type", fixIts: ["insert type"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected member block in protocol", fixIts: ["insert member block"]), ] diff --git a/Tests/SwiftParserTest/translated/AvailabilityQueryTests.swift b/Tests/SwiftParserTest/translated/AvailabilityQueryTests.swift index 207886d40aa..d14eac569c5 100644 --- a/Tests/SwiftParserTest/translated/AvailabilityQueryTests.swift +++ b/Tests/SwiftParserTest/translated/AvailabilityQueryTests.swift @@ -125,8 +125,7 @@ final class AvailabilityQueryTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "expected version restriction in availability argument", fixIts: ["insert version restriction"]), - DiagnosticSpec(message: "expected ')' to end availability condition", fixIts: ["insert ')'"]), + DiagnosticSpec(message: "expected platform and ')' to end availability condition", fixIts: ["insert platform and ')'"]) ] ) } diff --git a/Tests/SwiftParserTest/translated/AvailabilityQueryUnavailabilityTests.swift b/Tests/SwiftParserTest/translated/AvailabilityQueryUnavailabilityTests.swift index 6b4974cb51c..e698196fbe0 100644 --- a/Tests/SwiftParserTest/translated/AvailabilityQueryUnavailabilityTests.swift +++ b/Tests/SwiftParserTest/translated/AvailabilityQueryUnavailabilityTests.swift @@ -106,8 +106,7 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "expected version restriction in availability argument", fixIts: ["insert version restriction"]), - DiagnosticSpec(message: "expected ')' to end availability condition", fixIts: ["insert ')'"]), + DiagnosticSpec(message: "expected platform and ')' to end availability condition", fixIts: ["insert platform and ')'"]) ], fixedSource: """ if #unavailable(<#identifier#> ){ diff --git a/Tests/SwiftSyntaxTest/SyntaxChildrenTests.swift b/Tests/SwiftSyntaxTest/SyntaxChildrenTests.swift index 09caf2e8f8c..15976c45172 100644 --- a/Tests/SwiftSyntaxTest/SyntaxChildrenTests.swift +++ b/Tests/SwiftSyntaxTest/SyntaxChildrenTests.swift @@ -71,4 +71,14 @@ public class SyntaxChildrenTests: XCTestCase { try XCTAssertNext(&fixedUpIt) { $0.is(TokenSyntax.self) } try XCTAssertNext(&fixedUpIt) { $0.is(MissingExprSyntax.self) } } + + public func testTokenSequencesWithMissingChild() { + let codeBlock = CodeBlockSyntax( + leftBrace: .leftBraceToken(presence: .missing), + statements: [], + rightBrace: .rightBraceToken(presence: .missing) + ) + + XCTAssertEqual(Array(codeBlock.tokens(viewMode: .all)).count, 2) + } } diff --git a/utils/group.json b/utils/group.json index 8873f1dec56..ba6bb56be3b 100644 --- a/utils/group.json +++ b/utils/group.json @@ -36,6 +36,7 @@ ], "Utils": [ "CommonAncestor.swift", + "MissingNodeInitializers.swift", "SyntaxAnyVisitor.swift", "SyntaxBuilders.swift", "SyntaxClassifier.swift",