diff --git a/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift b/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift index bad1bed9251..3bb177c3227 100644 --- a/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift @@ -1278,6 +1278,18 @@ public let DECL_NODES: [Node] = [ "FreestandingMacroExpansion" ], children: [ + Child( + name: "Attributes", + kind: .collection(kind: "AttributeList", collectionElementName: "Attribute"), + nameForDiagnostics: "attributes", + isOptional: true + ), + Child( + name: "Modifiers", + kind: .collection(kind: "ModifierList", collectionElementName: "Modifier"), + nameForDiagnostics: "modifiers", + isOptional: true + ), Child( name: "PoundToken", kind: .token(choices: [.token(tokenKind: "PoundToken")]), diff --git a/Sources/SwiftParser/Declarations.swift b/Sources/SwiftParser/Declarations.swift index d510243e5d8..4749f94d66e 100644 --- a/Sources/SwiftParser/Declarations.swift +++ b/Sources/SwiftParser/Declarations.swift @@ -29,18 +29,25 @@ extension DeclarationModifier { } extension TokenConsumer { + mutating func atStartOfFreestandingMacroExpansion() -> Bool { + if !self.at(.pound) { + return false + } + if self.peek().rawTokenKind != .identifier && !self.peek().isLexerClassifiedKeyword { + return false + } + if self.currentToken.trailingTriviaByteLength != 0 || self.peek().leadingTriviaByteLength != 0 { + return false + } + return true + } + mutating func atStartOfDeclaration( isAtTopLevel: Bool = false, allowInitDecl: Bool = true, allowRecovery: Bool = false ) -> Bool { if self.at(anyIn: PoundDeclarationStart.self) != nil { - // Don't treat freestanding macro expansions as declarations. They'll be - // parsed as expressions. - if self.at(.pound) { - return false - } - return true } @@ -53,12 +60,14 @@ extension TokenConsumer { _ = subparser.consumeAttributeList() } + var hasModifier = false if subparser.currentToken.isLexerClassifiedKeyword || subparser.currentToken.rawTokenKind == .identifier { var modifierProgress = LoopProgressCondition() while let (modifierKind, handle) = subparser.at(anyIn: DeclarationModifier.self), modifierKind != .class, modifierProgress.evaluate(subparser.currentToken) { + hasModifier = true subparser.eat(handle) if modifierKind != .open && subparser.at(.leftParen) && modifierKind.canHaveParenthesizedArgument { // When determining whether we are at a declaration, don't consume anything in parentheses after 'open' @@ -113,6 +122,16 @@ extension TokenConsumer { case .macroKeyword: // macro Foo ... return subparser.peek().rawTokenKind == .identifier + case .pound: + // Force parsing '#' after attributes as a macro expansion decl. + if hasAttribute || hasModifier { + return true + } + + // Otherwise, parse it as a expression. + // FIXME: C++ parser returns true if this is a top-level non-"script" files. + // But we don't have "is library" flag. + return false case .some(_): // All other decl start keywords unconditonally start a decl. return true @@ -203,10 +222,6 @@ extension Parser { return .decls(RawMemberDeclListSyntax(elements: elements, arena: parser.arena)) } return RawDeclSyntax(directive) - case (.pound, _)?: - // FIXME: If we can have attributes for macro expansions, handle this - // via DeclarationStart. - return RawDeclSyntax(self.parseMacroExpansionDeclaration()) case nil: break } @@ -258,6 +273,8 @@ extension Parser { return RawDeclSyntax(self.parseNominalTypeDeclaration(for: RawActorDeclSyntax.self, attrs: attrs, introucerHandle: handle)) case (.macroKeyword, let handle)?: return RawDeclSyntax(self.parseMacroDeclaration(attrs: attrs, introducerHandle: handle)) + case (.pound, let handle)?: + return RawDeclSyntax(self.parseMacroExpansionDeclaration(attrs, handle)) case nil: if inMemberDeclList { let isProbablyVarDecl = self.at(.identifier, .wildcard) && self.peek().rawTokenKind.is(.colon, .equal, .comma) @@ -2023,9 +2040,30 @@ extension Parser { /// ======= /// /// macro-expansion-declaration → '#' identifier expr-call-suffix? - mutating func parseMacroExpansionDeclaration() -> RawMacroExpansionDeclSyntax { - let poundKeyword = self.consumeAnyToken() - let (unexpectedBeforeMacro, macro) = self.expectIdentifier() + mutating func parseMacroExpansionDeclaration( + _ attrs: DeclAttributes, + _ handle: RecoveryConsumptionHandle + ) -> RawMacroExpansionDeclSyntax { + + let (unexpectedBeforePound, poundKeyword) = self.eat(handle) + // Don't allow space between '#' and the macro name. + if poundKeyword.trailingTriviaByteLength != 0 || self.currentToken.leadingTriviaByteLength != 0 { + return RawMacroExpansionDeclSyntax( + attributes: attrs.attributes, + modifiers: attrs.modifiers, + unexpectedBeforePound, + poundToken: poundKeyword, + macro: self.missingToken(.identifier), + genericArguments: nil, + leftParen: nil, + argumentList: .init(elements: [], arena: self.arena), + rightParen: nil, + trailingClosure: nil, + additionalTrailingClosures: nil, + arena: self.arena + ) + } + let (unexpectedBeforeMacro, macro) = self.expectIdentifier(keywordRecovery: true) // Parse the optional generic argument list. let generics: RawGenericArgumentClauseSyntax? @@ -2063,6 +2101,9 @@ extension Parser { } return RawMacroExpansionDeclSyntax( + attributes: attrs.attributes, + modifiers: attrs.modifiers, + unexpectedBeforePound, poundToken: poundKeyword, unexpectedBeforeMacro, macro: macro, diff --git a/Sources/SwiftParser/Expressions.swift b/Sources/SwiftParser/Expressions.swift index e9332141879..62ae35b6084 100644 --- a/Sources/SwiftParser/Expressions.swift +++ b/Sources/SwiftParser/Expressions.swift @@ -1394,8 +1394,21 @@ extension Parser { pattern: PatternContext, flavor: ExprFlavor ) -> RawMacroExpansionExprSyntax { + if !atStartOfFreestandingMacroExpansion() { + return RawMacroExpansionExprSyntax( + poundToken: self.consumeAnyToken(), + macro: self.missingToken(.identifier), + genericArguments: nil, + leftParen: nil, + argumentList: .init(elements: [], arena: self.arena), + rightParen: nil, + trailingClosure: nil, + additionalTrailingClosures: nil, + arena: self.arena + ) + } let poundKeyword = self.consumeAnyToken() - let (unexpectedBeforeMacro, macro) = self.expectIdentifier() + let (unexpectedBeforeMacro, macro) = self.expectIdentifier(keywordRecovery: true) // Parse the optional generic argument list. let generics: RawGenericArgumentClauseSyntax? diff --git a/Sources/SwiftParser/TokenSpecSet.swift b/Sources/SwiftParser/TokenSpecSet.swift index a8e0bcfe337..82460f6ea16 100644 --- a/Sources/SwiftParser/TokenSpecSet.swift +++ b/Sources/SwiftParser/TokenSpecSet.swift @@ -272,6 +272,7 @@ enum DeclarationStart: TokenSpecSet { case typealiasKeyword case varKeyword case inoutKeyword + case pound init?(lexeme: Lexer.Lexeme) { switch PrepareForKeywordMatch(lexeme) { @@ -295,6 +296,7 @@ enum DeclarationStart: TokenSpecSet { case TokenSpec(.typealias): self = .typealiasKeyword case TokenSpec(.var): self = .varKeyword case TokenSpec(.inout): self = .inoutKeyword + case TokenSpec(.pound): self = .pound default: return nil } } @@ -321,6 +323,7 @@ enum DeclarationStart: TokenSpecSet { case .typealiasKeyword: return .keyword(.typealias) case .varKeyword: return .keyword(.var) case .inoutKeyword: return TokenSpec(.inout, recoveryPrecedence: .declKeyword) + case .pound: return TokenSpec(.pound, recoveryPrecedence: .openingPoundIf) } } } @@ -396,12 +399,10 @@ enum OperatorLike: TokenSpecSet { enum PoundDeclarationStart: TokenSpecSet { case poundIfKeyword - case pound init?(lexeme: Lexer.Lexeme) { switch lexeme.rawTokenKind { case .poundIfKeyword: self = .poundIfKeyword - case .pound: self = .pound default: return nil } } @@ -409,7 +410,6 @@ enum PoundDeclarationStart: TokenSpecSet { var spec: TokenSpec { switch self { case .poundIfKeyword: return .poundIfKeyword - case .pound: return .pound } } } diff --git a/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift b/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift index 22e1b869d09..69f3c4c8e67 100644 --- a/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift +++ b/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift @@ -236,6 +236,10 @@ private func childNameForDiagnostics(_ keyPath: AnyKeyPath) -> String? { return "macro definition" case \MacroDeclSyntax.genericWhereClause: return "generic where clause" + case \MacroExpansionDeclSyntax.attributes: + return "attributes" + case \MacroExpansionDeclSyntax.modifiers: + return "modifiers" case \MemberAccessExprSyntax.base: return "base" case \MemberAccessExprSyntax.name: diff --git a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift index 787711dab4b..f6b3c528944 100644 --- a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift +++ b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift @@ -1995,8 +1995,16 @@ public func childName(_ keyPath: AnyKeyPath) -> String? { return "genericWhereClause" case \MacroDeclSyntax.unexpectedAfterGenericWhereClause: return "unexpectedAfterGenericWhereClause" - case \MacroExpansionDeclSyntax.unexpectedBeforePoundToken: - return "unexpectedBeforePoundToken" + case \MacroExpansionDeclSyntax.unexpectedBeforeAttributes: + return "unexpectedBeforeAttributes" + case \MacroExpansionDeclSyntax.attributes: + return "attributes" + case \MacroExpansionDeclSyntax.unexpectedBetweenAttributesAndModifiers: + return "unexpectedBetweenAttributesAndModifiers" + case \MacroExpansionDeclSyntax.modifiers: + return "modifiers" + case \MacroExpansionDeclSyntax.unexpectedBetweenModifiersAndPoundToken: + return "unexpectedBetweenModifiersAndPoundToken" case \MacroExpansionDeclSyntax.poundToken: return "poundToken" case \MacroExpansionDeclSyntax.unexpectedBetweenPoundTokenAndMacro: diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift index 0beae502cf2..3b78eb77261 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift @@ -13322,7 +13322,11 @@ public struct RawMacroExpansionDeclSyntax: RawDeclSyntaxNodeProtocol { } public init( - _ unexpectedBeforePoundToken: RawUnexpectedNodesSyntax? = nil, + _ unexpectedBeforeAttributes: RawUnexpectedNodesSyntax? = nil, + attributes: RawAttributeListSyntax?, + _ unexpectedBetweenAttributesAndModifiers: RawUnexpectedNodesSyntax? = nil, + modifiers: RawModifierListSyntax?, + _ unexpectedBetweenModifiersAndPoundToken: RawUnexpectedNodesSyntax? = nil, poundToken: RawTokenSyntax, _ unexpectedBetweenPoundTokenAndMacro: RawUnexpectedNodesSyntax? = nil, macro: RawTokenSyntax, @@ -13342,95 +13346,115 @@ public struct RawMacroExpansionDeclSyntax: RawDeclSyntaxNodeProtocol { arena: __shared SyntaxArena ) { let raw = RawSyntax.makeLayout( - kind: .macroExpansionDecl, uninitializedCount: 17, arena: arena) { layout in + kind: .macroExpansionDecl, uninitializedCount: 21, arena: arena) { layout in layout.initialize(repeating: nil) - layout[0] = unexpectedBeforePoundToken?.raw - layout[1] = poundToken.raw - layout[2] = unexpectedBetweenPoundTokenAndMacro?.raw - layout[3] = macro.raw - layout[4] = unexpectedBetweenMacroAndGenericArguments?.raw - layout[5] = genericArguments?.raw - layout[6] = unexpectedBetweenGenericArgumentsAndLeftParen?.raw - layout[7] = leftParen?.raw - layout[8] = unexpectedBetweenLeftParenAndArgumentList?.raw - layout[9] = argumentList.raw - layout[10] = unexpectedBetweenArgumentListAndRightParen?.raw - layout[11] = rightParen?.raw - layout[12] = unexpectedBetweenRightParenAndTrailingClosure?.raw - layout[13] = trailingClosure?.raw - layout[14] = unexpectedBetweenTrailingClosureAndAdditionalTrailingClosures?.raw - layout[15] = additionalTrailingClosures?.raw - layout[16] = unexpectedAfterAdditionalTrailingClosures?.raw + layout[0] = unexpectedBeforeAttributes?.raw + layout[1] = attributes?.raw + layout[2] = unexpectedBetweenAttributesAndModifiers?.raw + layout[3] = modifiers?.raw + layout[4] = unexpectedBetweenModifiersAndPoundToken?.raw + layout[5] = poundToken.raw + layout[6] = unexpectedBetweenPoundTokenAndMacro?.raw + layout[7] = macro.raw + layout[8] = unexpectedBetweenMacroAndGenericArguments?.raw + layout[9] = genericArguments?.raw + layout[10] = unexpectedBetweenGenericArgumentsAndLeftParen?.raw + layout[11] = leftParen?.raw + layout[12] = unexpectedBetweenLeftParenAndArgumentList?.raw + layout[13] = argumentList.raw + layout[14] = unexpectedBetweenArgumentListAndRightParen?.raw + layout[15] = rightParen?.raw + layout[16] = unexpectedBetweenRightParenAndTrailingClosure?.raw + layout[17] = trailingClosure?.raw + layout[18] = unexpectedBetweenTrailingClosureAndAdditionalTrailingClosures?.raw + layout[19] = additionalTrailingClosures?.raw + layout[20] = unexpectedAfterAdditionalTrailingClosures?.raw } self.init(unchecked: raw) } - public var unexpectedBeforePoundToken: RawUnexpectedNodesSyntax? { + public var unexpectedBeforeAttributes: RawUnexpectedNodesSyntax? { layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) } + public var attributes: RawAttributeListSyntax? { + layoutView.children[1].map(RawAttributeListSyntax.init(raw:)) + } + + public var unexpectedBetweenAttributesAndModifiers: RawUnexpectedNodesSyntax? { + layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var modifiers: RawModifierListSyntax? { + layoutView.children[3].map(RawModifierListSyntax.init(raw:)) + } + + public var unexpectedBetweenModifiersAndPoundToken: RawUnexpectedNodesSyntax? { + layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:)) + } + public var poundToken: RawTokenSyntax { - layoutView.children[1].map(RawTokenSyntax.init(raw:))! + layoutView.children[5].map(RawTokenSyntax.init(raw:))! } public var unexpectedBetweenPoundTokenAndMacro: RawUnexpectedNodesSyntax? { - layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) + layoutView.children[6].map(RawUnexpectedNodesSyntax.init(raw:)) } public var macro: RawTokenSyntax { - layoutView.children[3].map(RawTokenSyntax.init(raw:))! + layoutView.children[7].map(RawTokenSyntax.init(raw:))! } public var unexpectedBetweenMacroAndGenericArguments: RawUnexpectedNodesSyntax? { - layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:)) + layoutView.children[8].map(RawUnexpectedNodesSyntax.init(raw:)) } public var genericArguments: RawGenericArgumentClauseSyntax? { - layoutView.children[5].map(RawGenericArgumentClauseSyntax.init(raw:)) + layoutView.children[9].map(RawGenericArgumentClauseSyntax.init(raw:)) } public var unexpectedBetweenGenericArgumentsAndLeftParen: RawUnexpectedNodesSyntax? { - layoutView.children[6].map(RawUnexpectedNodesSyntax.init(raw:)) + layoutView.children[10].map(RawUnexpectedNodesSyntax.init(raw:)) } public var leftParen: RawTokenSyntax? { - layoutView.children[7].map(RawTokenSyntax.init(raw:)) + layoutView.children[11].map(RawTokenSyntax.init(raw:)) } public var unexpectedBetweenLeftParenAndArgumentList: RawUnexpectedNodesSyntax? { - layoutView.children[8].map(RawUnexpectedNodesSyntax.init(raw:)) + layoutView.children[12].map(RawUnexpectedNodesSyntax.init(raw:)) } public var argumentList: RawTupleExprElementListSyntax { - layoutView.children[9].map(RawTupleExprElementListSyntax.init(raw:))! + layoutView.children[13].map(RawTupleExprElementListSyntax.init(raw:))! } public var unexpectedBetweenArgumentListAndRightParen: RawUnexpectedNodesSyntax? { - layoutView.children[10].map(RawUnexpectedNodesSyntax.init(raw:)) + layoutView.children[14].map(RawUnexpectedNodesSyntax.init(raw:)) } public var rightParen: RawTokenSyntax? { - layoutView.children[11].map(RawTokenSyntax.init(raw:)) + layoutView.children[15].map(RawTokenSyntax.init(raw:)) } public var unexpectedBetweenRightParenAndTrailingClosure: RawUnexpectedNodesSyntax? { - layoutView.children[12].map(RawUnexpectedNodesSyntax.init(raw:)) + layoutView.children[16].map(RawUnexpectedNodesSyntax.init(raw:)) } public var trailingClosure: RawClosureExprSyntax? { - layoutView.children[13].map(RawClosureExprSyntax.init(raw:)) + layoutView.children[17].map(RawClosureExprSyntax.init(raw:)) } public var unexpectedBetweenTrailingClosureAndAdditionalTrailingClosures: RawUnexpectedNodesSyntax? { - layoutView.children[14].map(RawUnexpectedNodesSyntax.init(raw:)) + layoutView.children[18].map(RawUnexpectedNodesSyntax.init(raw:)) } public var additionalTrailingClosures: RawMultipleTrailingClosureElementListSyntax? { - layoutView.children[15].map(RawMultipleTrailingClosureElementListSyntax.init(raw:)) + layoutView.children[19].map(RawMultipleTrailingClosureElementListSyntax.init(raw:)) } public var unexpectedAfterAdditionalTrailingClosures: RawUnexpectedNodesSyntax? { - layoutView.children[16].map(RawUnexpectedNodesSyntax.init(raw:)) + layoutView.children[20].map(RawUnexpectedNodesSyntax.init(raw:)) } } diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift index b59b1e9b827..6ba7ae1ff09 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift @@ -1701,24 +1701,28 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { assertNoError(kind, 15, verify(layout[15], as: RawGenericWhereClauseSyntax?.self)) assertNoError(kind, 16, verify(layout[16], as: RawUnexpectedNodesSyntax?.self)) case .macroExpansionDecl: - assert(layout.count == 17) + assert(layout.count == 21) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.pound)])) + 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: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier)])) + 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: RawGenericArgumentClauseSyntax?.self)) + assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.pound)])) assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 7, verify(layout[7], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.leftParen)])) + assertNoError(kind, 7, verify(layout[7], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier)])) assertNoError(kind, 8, verify(layout[8], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 9, verify(layout[9], as: RawTupleExprElementListSyntax.self)) + assertNoError(kind, 9, verify(layout[9], as: RawGenericArgumentClauseSyntax?.self)) assertNoError(kind, 10, verify(layout[10], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 11, verify(layout[11], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.rightParen)])) + assertNoError(kind, 11, verify(layout[11], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.leftParen)])) assertNoError(kind, 12, verify(layout[12], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 13, verify(layout[13], as: RawClosureExprSyntax?.self)) + assertNoError(kind, 13, verify(layout[13], as: RawTupleExprElementListSyntax.self)) assertNoError(kind, 14, verify(layout[14], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 15, verify(layout[15], as: RawMultipleTrailingClosureElementListSyntax?.self)) + assertNoError(kind, 15, verify(layout[15], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.rightParen)])) assertNoError(kind, 16, verify(layout[16], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 17, verify(layout[17], as: RawClosureExprSyntax?.self)) + assertNoError(kind, 18, verify(layout[18], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 19, verify(layout[19], as: RawMultipleTrailingClosureElementListSyntax?.self)) + assertNoError(kind, 20, verify(layout[20], as: RawUnexpectedNodesSyntax?.self)) case .macroExpansionExpr: assert(layout.count == 17) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxDeclNodes.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxDeclNodes.swift index 465a07192f3..41980622245 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxDeclNodes.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxDeclNodes.swift @@ -3699,7 +3699,11 @@ public struct MacroExpansionDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { public init( leadingTrivia: Trivia? = nil, - _ unexpectedBeforePoundToken: UnexpectedNodesSyntax? = nil, + _ unexpectedBeforeAttributes: UnexpectedNodesSyntax? = nil, + attributes: AttributeListSyntax? = nil, + _ unexpectedBetweenAttributesAndModifiers: UnexpectedNodesSyntax? = nil, + modifiers: ModifierListSyntax? = nil, + _ unexpectedBetweenModifiersAndPoundToken: UnexpectedNodesSyntax? = nil, poundToken: TokenSyntax = .poundToken(), _ unexpectedBetweenPoundTokenAndMacro: UnexpectedNodesSyntax? = nil, macro: TokenSyntax, @@ -3722,7 +3726,11 @@ public struct MacroExpansionDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { // 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(), ( - unexpectedBeforePoundToken, + unexpectedBeforeAttributes, + attributes, + unexpectedBetweenAttributesAndModifiers, + modifiers, + unexpectedBetweenModifiersAndPoundToken, poundToken, unexpectedBetweenPoundTokenAndMacro, macro, @@ -3741,7 +3749,11 @@ public struct MacroExpansionDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { unexpectedAfterAdditionalTrailingClosures ))) {(arena, _) in let layout: [RawSyntax?] = [ - unexpectedBeforePoundToken?.raw, + unexpectedBeforeAttributes?.raw, + attributes?.raw, + unexpectedBetweenAttributesAndModifiers?.raw, + modifiers?.raw, + unexpectedBetweenModifiersAndPoundToken?.raw, poundToken.raw, unexpectedBetweenPoundTokenAndMacro?.raw, macro.raw, @@ -3772,7 +3784,7 @@ public struct MacroExpansionDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { self.init(data) } - public var unexpectedBeforePoundToken: UnexpectedNodesSyntax? { + public var unexpectedBeforeAttributes: UnexpectedNodesSyntax? { get { return data.child(at: 0, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } @@ -3781,85 +3793,159 @@ public struct MacroExpansionDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { } } + public var attributes: AttributeListSyntax? { + get { + return data.child(at: 1, parent: Syntax(self)).map(AttributeListSyntax.init) + } + set(value) { + self = MacroExpansionDeclSyntax(data.replacingChild(at: 1, with: value?.raw, arena: SyntaxArena())) + } + } + + /// Adds the provided `Attribute` to the node's `attributes` + /// collection. + /// - param element: The new `Attribute` to add to the node's + /// `attributes` collection. + /// - returns: A copy of the receiver with the provided `Attribute` + /// appended to its `attributes` collection. + public func addAttribute(_ element: Syntax) -> MacroExpansionDeclSyntax { + var collection: RawSyntax + let arena = SyntaxArena() + if let col = raw.layoutView!.children[1] { + collection = col.layoutView!.appending(element.raw, arena: arena) + } else { + collection = RawSyntax.makeLayout(kind: SyntaxKind.attributeList, + from: [element.raw], arena: arena) + } + let newData = data.replacingChild(at: 1, with: collection, arena: arena) + return MacroExpansionDeclSyntax(newData) + } + + public var unexpectedBetweenAttributesAndModifiers: UnexpectedNodesSyntax? { + get { + return data.child(at: 2, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = MacroExpansionDeclSyntax(data.replacingChild(at: 2, with: value?.raw, arena: SyntaxArena())) + } + } + + public var modifiers: ModifierListSyntax? { + get { + return data.child(at: 3, parent: Syntax(self)).map(ModifierListSyntax.init) + } + set(value) { + self = MacroExpansionDeclSyntax(data.replacingChild(at: 3, with: value?.raw, arena: SyntaxArena())) + } + } + + /// Adds the provided `Modifier` to the node's `modifiers` + /// collection. + /// - param element: The new `Modifier` to add to the node's + /// `modifiers` collection. + /// - returns: A copy of the receiver with the provided `Modifier` + /// appended to its `modifiers` collection. + public func addModifier(_ element: DeclModifierSyntax) -> MacroExpansionDeclSyntax { + var collection: RawSyntax + let arena = SyntaxArena() + if let col = raw.layoutView!.children[3] { + collection = col.layoutView!.appending(element.raw, arena: arena) + } else { + collection = RawSyntax.makeLayout(kind: SyntaxKind.modifierList, + from: [element.raw], arena: arena) + } + let newData = data.replacingChild(at: 3, with: collection, arena: arena) + return MacroExpansionDeclSyntax(newData) + } + + public var unexpectedBetweenModifiersAndPoundToken: UnexpectedNodesSyntax? { + get { + return data.child(at: 4, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = MacroExpansionDeclSyntax(data.replacingChild(at: 4, with: value?.raw, arena: SyntaxArena())) + } + } + /// The `#` sign. public var poundToken: TokenSyntax { get { - return TokenSyntax(data.child(at: 1, parent: Syntax(self))!) + return TokenSyntax(data.child(at: 5, parent: Syntax(self))!) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 1, with: value.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 5, with: value.raw, arena: SyntaxArena())) } } public var unexpectedBetweenPoundTokenAndMacro: UnexpectedNodesSyntax? { get { - return data.child(at: 2, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + return data.child(at: 6, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 2, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 6, with: value?.raw, arena: SyntaxArena())) } } public var macro: TokenSyntax { get { - return TokenSyntax(data.child(at: 3, parent: Syntax(self))!) + return TokenSyntax(data.child(at: 7, parent: Syntax(self))!) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 3, with: value.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 7, with: value.raw, arena: SyntaxArena())) } } public var unexpectedBetweenMacroAndGenericArguments: UnexpectedNodesSyntax? { get { - return data.child(at: 4, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + return data.child(at: 8, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 4, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 8, with: value?.raw, arena: SyntaxArena())) } } public var genericArguments: GenericArgumentClauseSyntax? { get { - return data.child(at: 5, parent: Syntax(self)).map(GenericArgumentClauseSyntax.init) + return data.child(at: 9, parent: Syntax(self)).map(GenericArgumentClauseSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 5, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 9, with: value?.raw, arena: SyntaxArena())) } } public var unexpectedBetweenGenericArgumentsAndLeftParen: UnexpectedNodesSyntax? { get { - return data.child(at: 6, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + return data.child(at: 10, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 6, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 10, with: value?.raw, arena: SyntaxArena())) } } public var leftParen: TokenSyntax? { get { - return data.child(at: 7, parent: Syntax(self)).map(TokenSyntax.init) + return data.child(at: 11, parent: Syntax(self)).map(TokenSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 7, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 11, with: value?.raw, arena: SyntaxArena())) } } public var unexpectedBetweenLeftParenAndArgumentList: UnexpectedNodesSyntax? { get { - return data.child(at: 8, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + return data.child(at: 12, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 8, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 12, with: value?.raw, arena: SyntaxArena())) } } public var argumentList: TupleExprElementListSyntax { get { - return TupleExprElementListSyntax(data.child(at: 9, parent: Syntax(self))!) + return TupleExprElementListSyntax(data.child(at: 13, parent: Syntax(self))!) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 9, with: value.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 13, with: value.raw, arena: SyntaxArena())) } } @@ -3872,67 +3958,67 @@ public struct MacroExpansionDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { public func addArgument(_ element: TupleExprElementSyntax) -> MacroExpansionDeclSyntax { var collection: RawSyntax let arena = SyntaxArena() - if let col = raw.layoutView!.children[9] { + if let col = raw.layoutView!.children[13] { collection = col.layoutView!.appending(element.raw, arena: arena) } else { collection = RawSyntax.makeLayout(kind: SyntaxKind.tupleExprElementList, from: [element.raw], arena: arena) } - let newData = data.replacingChild(at: 9, with: collection, arena: arena) + let newData = data.replacingChild(at: 13, with: collection, arena: arena) return MacroExpansionDeclSyntax(newData) } public var unexpectedBetweenArgumentListAndRightParen: UnexpectedNodesSyntax? { get { - return data.child(at: 10, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + return data.child(at: 14, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 10, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 14, with: value?.raw, arena: SyntaxArena())) } } public var rightParen: TokenSyntax? { get { - return data.child(at: 11, parent: Syntax(self)).map(TokenSyntax.init) + return data.child(at: 15, parent: Syntax(self)).map(TokenSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 11, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 15, with: value?.raw, arena: SyntaxArena())) } } public var unexpectedBetweenRightParenAndTrailingClosure: UnexpectedNodesSyntax? { get { - return data.child(at: 12, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + return data.child(at: 16, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 12, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 16, with: value?.raw, arena: SyntaxArena())) } } public var trailingClosure: ClosureExprSyntax? { get { - return data.child(at: 13, parent: Syntax(self)).map(ClosureExprSyntax.init) + return data.child(at: 17, parent: Syntax(self)).map(ClosureExprSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 13, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 17, with: value?.raw, arena: SyntaxArena())) } } public var unexpectedBetweenTrailingClosureAndAdditionalTrailingClosures: UnexpectedNodesSyntax? { get { - return data.child(at: 14, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + return data.child(at: 18, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 14, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 18, with: value?.raw, arena: SyntaxArena())) } } public var additionalTrailingClosures: MultipleTrailingClosureElementListSyntax? { get { - return data.child(at: 15, parent: Syntax(self)).map(MultipleTrailingClosureElementListSyntax.init) + return data.child(at: 19, parent: Syntax(self)).map(MultipleTrailingClosureElementListSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 15, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 19, with: value?.raw, arena: SyntaxArena())) } } @@ -3945,28 +4031,32 @@ public struct MacroExpansionDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { public func addAdditionalTrailingClosure(_ element: MultipleTrailingClosureElementSyntax) -> MacroExpansionDeclSyntax { var collection: RawSyntax let arena = SyntaxArena() - if let col = raw.layoutView!.children[15] { + if let col = raw.layoutView!.children[19] { collection = col.layoutView!.appending(element.raw, arena: arena) } else { collection = RawSyntax.makeLayout(kind: SyntaxKind.multipleTrailingClosureElementList, from: [element.raw], arena: arena) } - let newData = data.replacingChild(at: 15, with: collection, arena: arena) + let newData = data.replacingChild(at: 19, with: collection, arena: arena) return MacroExpansionDeclSyntax(newData) } public var unexpectedAfterAdditionalTrailingClosures: UnexpectedNodesSyntax? { get { - return data.child(at: 16, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + return data.child(at: 20, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } set(value) { - self = MacroExpansionDeclSyntax(data.replacingChild(at: 16, with: value?.raw, arena: SyntaxArena())) + self = MacroExpansionDeclSyntax(data.replacingChild(at: 20, with: value?.raw, arena: SyntaxArena())) } } public static var structure: SyntaxNodeStructure { return .layout([ - \Self.unexpectedBeforePoundToken, + \Self.unexpectedBeforeAttributes, + \Self.attributes, + \Self.unexpectedBetweenAttributesAndModifiers, + \Self.modifiers, + \Self.unexpectedBetweenModifiersAndPoundToken, \Self.poundToken, \Self.unexpectedBetweenPoundTokenAndMacro, \Self.macro, diff --git a/Sources/SwiftSyntaxBuilder/generated/BuildableNodes.swift b/Sources/SwiftSyntaxBuilder/generated/BuildableNodes.swift index 71df4f2b7df..e59d1352dda 100644 --- a/Sources/SwiftSyntaxBuilder/generated/BuildableNodes.swift +++ b/Sources/SwiftSyntaxBuilder/generated/BuildableNodes.swift @@ -897,7 +897,11 @@ extension MacroExpansionDeclSyntax { /// A convenience initializer that allows initializing syntax collections using result builders public init( leadingTrivia: Trivia? = nil, - unexpectedBeforePoundToken: UnexpectedNodesSyntax? = nil, + unexpectedBeforeAttributes: UnexpectedNodesSyntax? = nil, + attributes: AttributeListSyntax? = nil, + unexpectedBetweenAttributesAndModifiers: UnexpectedNodesSyntax? = nil, + modifiers: ModifierListSyntax? = nil, + unexpectedBetweenModifiersAndPoundToken: UnexpectedNodesSyntax? = nil, poundToken: TokenSyntax = .poundToken(), unexpectedBetweenPoundTokenAndMacro: UnexpectedNodesSyntax? = nil, macro: TokenSyntax, @@ -918,7 +922,11 @@ extension MacroExpansionDeclSyntax { ) rethrows { try self.init( leadingTrivia: leadingTrivia, - unexpectedBeforePoundToken, + unexpectedBeforeAttributes, + attributes: attributes, + unexpectedBetweenAttributesAndModifiers, + modifiers: modifiers, + unexpectedBetweenModifiersAndPoundToken, poundToken: poundToken, unexpectedBetweenPoundTokenAndMacro, macro: macro, diff --git a/Tests/SwiftParserTest/DeclarationTests.swift b/Tests/SwiftParserTest/DeclarationTests.swift index 36f4ae707f3..aed2d7c1932 100644 --- a/Tests/SwiftParserTest/DeclarationTests.swift +++ b/Tests/SwiftParserTest/DeclarationTests.swift @@ -1427,6 +1427,208 @@ final class DeclarationTests: XCTestCase { ) } + func testAttributedMacroExpansionDeclaration() { + assertParse( + """ + @attribute #topLevelWithAttr + public #topLevelWithModifier + #topLevelBare + """, + substructure: Syntax( + CodeBlockItemListSyntax([ + CodeBlockItemSyntax( + item: .decl( + DeclSyntax( + MacroExpansionDeclSyntax( + attributes: [.attribute(AttributeSyntax(attributeName: TypeSyntax("attribute")))], + macro: "topLevelWithAttr", + argumentList: [] + ) + ) + ) + ), + CodeBlockItemSyntax( + item: .decl( + DeclSyntax( + MacroExpansionDeclSyntax( + modifiers: [DeclModifierSyntax(name: .keyword(.public))], + macro: "topLevelWithModifier", + argumentList: [] + ) + ) + ) + ), + CodeBlockItemSyntax( + item: .expr( + ExprSyntax( + MacroExpansionExprSyntax( + macro: "topLevelBare", + argumentList: [] + ) + ) + ) + ), + ]) + ) + ) + + assertParse( + """ + struct S { + @attribute #memberWithAttr + public #memberWithModifier + #memberBare + } + """, + substructure: Syntax( + MemberDeclListSyntax([ + MemberDeclListItemSyntax( + decl: MacroExpansionDeclSyntax( + attributes: [.attribute(AttributeSyntax(attributeName: TypeSyntax("attribute")))], + macro: "memberWithAttr", + argumentList: [] + ) + ), + MemberDeclListItemSyntax( + decl: MacroExpansionDeclSyntax( + modifiers: [DeclModifierSyntax(name: .keyword(.public))], + macro: "memberWithModifier", + argumentList: [] + ) + ), + MemberDeclListItemSyntax( + decl: MacroExpansionDeclSyntax( + macro: "memberBare", + argumentList: [] + ) + ), + ]) + ) + ) + + assertParse( + """ + func test() { + @attribute #bodyWithAttr + public #bodyWithModifier + #bodyBare + } + """, + substructure: Syntax( + FunctionDeclSyntax( + identifier: .identifier("test"), + signature: FunctionSignatureSyntax( + input: ParameterClauseSyntax(parameterList: []) + ) + ) { + DeclSyntax( + MacroExpansionDeclSyntax( + attributes: [.attribute(AttributeSyntax(attributeName: TypeSyntax("attribute")))], + macro: "bodyWithAttr", + argumentList: [] + ) + ) + DeclSyntax( + MacroExpansionDeclSyntax( + modifiers: [DeclModifierSyntax(name: .keyword(.public))], + macro: "bodyWithModifier", + argumentList: [] + ) + ) + ExprSyntax( + MacroExpansionExprSyntax( + macro: "bodyBare", + argumentList: [] + ) + ) + } + ) + ) + + assertParse( + """ + func test() { + @attrib1 + @attrib2 + public + #declMacro + } + """, + substructure: Syntax( + FunctionDeclSyntax( + identifier: .identifier("test"), + signature: FunctionSignatureSyntax( + input: ParameterClauseSyntax(parameterList: []) + ) + ) { + DeclSyntax( + MacroExpansionDeclSyntax( + attributes: [ + .attribute(AttributeSyntax(attributeName: TypeSyntax("attrib1"))), + .attribute(AttributeSyntax(attributeName: TypeSyntax("attrib2"))), + ], + modifiers: [DeclModifierSyntax(name: .keyword(.public))], + macro: "declMacro", + argumentList: [] + ) + ) + } + ) + ) + + assertParse( + """ + struct S { + @attrib #1️⃣class + #2️⃣struct + } + """, + substructure: Syntax( + MemberDeclListSyntax([ + MemberDeclListItemSyntax( + decl: MacroExpansionDeclSyntax( + attributes: [.attribute(AttributeSyntax(attributeName: TypeSyntax("attrib")))], + poundToken: .poundToken(), + /*unexpectedBetweenPoundTokenAndMacro:*/ [ + TokenSyntax.keyword(.class) + ], + macro: .identifier("", presence: .missing), + argumentList: [] + ) + ), + MemberDeclListItemSyntax( + decl: MacroExpansionDeclSyntax( + poundToken: .poundToken(), + /*unexpectedBetweenPoundTokenAndMacro:*/ [ + TokenSyntax.keyword(.struct) + ], + macro: .identifier("", presence: .missing), + argumentList: [] + ) + ), + ]) + ), + diagnostics: [ + DiagnosticSpec( + locationMarker: "1️⃣", + message: "keyword 'class' cannot be used as an identifier here", + fixIts: ["if this name is unavoidable, use backticks to escape it"] + ), + DiagnosticSpec( + locationMarker: "2️⃣", + message: "keyword 'struct' cannot be used as an identifier here", + fixIts: ["if this name is unavoidable, use backticks to escape it"] + ), + ], + fixedSource: """ + struct S { + @attrib #`class` + #`struct` + } + """ + ) + } + func testVariableDeclWithGetSetButNoBrace() { assertParse( """ diff --git a/Tests/SwiftParserTest/translated/IfconfigExprTests.swift b/Tests/SwiftParserTest/translated/IfconfigExprTests.swift index 673d0cbd214..3a1a01d58db 100644 --- a/Tests/SwiftParserTest/translated/IfconfigExprTests.swift +++ b/Tests/SwiftParserTest/translated/IfconfigExprTests.swift @@ -500,26 +500,49 @@ final class IfconfigExprTests: XCTestCase { ) } - // FIXME: Parsing should generate diagnostics - https://github.com/apple/swift-syntax/issues/1395 + // FIXME: Diagnostics could be better. func testIfConfigExpr34() { assertParse( """ #if MY_FLAG - # + #1️⃣ elif #endif - """ + """, + diagnostics: [ + DiagnosticSpec( + message: "expected identifier in macro expansion", + fixIts: ["insert identifier"] + ) + ], + fixedSource: """ + #if MY_FLAG + #<#identifier#> + elif + #endif + """ ) } - // FIXME: Parsing should generate diagnostics - https://github.com/apple/swift-syntax/issues/1395 + // FIXME: Diagnostics could be better. func testIfConfigExpr35() { assertParse( """ #if MY_FLAG - # elif + # 1️⃣elif #endif - """ + """, + diagnostics: [ + DiagnosticSpec( + message: "expected identifier in macro expansion", + fixIts: ["insert identifier"] + ) + ], + fixedSource: """ + #if MY_FLAG + #<#identifier#>elif + #endif + """ ) }