From c7a6dec6f9c8360204acba08ca0d4a4745cf8422 Mon Sep 17 00:00:00 2001 From: Kim de Vos Date: Fri, 23 Jun 2023 08:12:27 +0200 Subject: [PATCH 1/2] Add diagnostic for label with string segment --- .../SyntaxSupport/AvailabilityNodes.swift | 2 +- .../Sources/SyntaxSupport/DeclNodes.swift | 2 +- .../Sources/SyntaxSupport/ExprNodes.swift | 32 +++ .../SyntaxSupport/SyntaxNodeKind.swift | 2 + Sources/SwiftBasicFormat/BasicFormat.swift | 1 + Sources/SwiftParser/Availability.swift | 3 +- Sources/SwiftParser/Directives.swift | 2 +- Sources/SwiftParser/StringLiterals.swift | 102 +++++++++- .../generated/Parser+TokenSpecSet.swift | 82 ++++++++ .../ParseDiagnosticsGenerator.swift | 50 +++++ .../ParserDiagnosticMessages.swift | 6 + .../SyntaxExtensions.swift | 9 + .../SyntaxKindNameForDiagnostics.swift | 2 + .../generated/SwiftSyntax.md | 3 + .../Raw/RawSyntaxNodeProtocol.swift | 4 + Sources/SwiftSyntax/SourceLocation.swift | 4 +- .../generated/ChildNameForKeyPath.swift | 14 ++ .../RenamedChildrenCompatibility.swift | 2 +- .../generated/SyntaxAnyVisitor.swift | 16 ++ .../generated/SyntaxBaseNodes.swift | 7 +- .../generated/SyntaxCollections.swift | 24 +++ .../SwiftSyntax/generated/SyntaxEnum.swift | 6 + .../SwiftSyntax/generated/SyntaxKind.swift | 8 + .../generated/SyntaxRewriter.swift | 50 +++++ .../generated/SyntaxTransform.swift | 28 +++ .../SwiftSyntax/generated/SyntaxVisitor.swift | 50 +++++ .../generated/raw/RawSyntaxNodes.swift | 146 +++++++++++++- .../generated/raw/RawSyntaxValidation.swift | 15 +- .../syntaxNodes/SyntaxExprNodes.swift | 189 +++++++++++++++++- .../generated/syntaxNodes/SyntaxNodes.swift | 19 +- .../generated/BuildableCollectionNodes.swift | 6 + .../generated/ResultBuilders.swift | 85 ++++++++ Tests/SwiftParserTest/Assertions.swift | 2 +- .../DiagnoseAvailabilityTests.swift | 59 ++++-- 34 files changed, 981 insertions(+), 51 deletions(-) diff --git a/CodeGeneration/Sources/SyntaxSupport/AvailabilityNodes.swift b/CodeGeneration/Sources/SyntaxSupport/AvailabilityNodes.swift index bf76105feb9..96df96c377a 100644 --- a/CodeGeneration/Sources/SyntaxSupport/AvailabilityNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/AvailabilityNodes.swift @@ -85,7 +85,7 @@ public let AVAILABILITY_NODES: [Node] = [ kind: .nodeChoices(choices: [ Child( name: "String", - kind: .node(kind: .stringLiteralExpr) + kind: .node(kind: .simpleStringLiteralExpr) ), Child( name: "Version", diff --git a/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift b/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift index c25854272fb..7b304ae9942 100644 --- a/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift @@ -1696,7 +1696,7 @@ public let DECL_NODES: [Node] = [ ), Child( name: "FileName", - kind: .node(kind: .stringLiteralExpr), + kind: .node(kind: .simpleStringLiteralExpr), nameForDiagnostics: "file name" ), Child( diff --git a/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift b/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift index 735e5e76c2b..56bdbb94516 100644 --- a/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift @@ -1501,6 +1501,38 @@ public let EXPR_NODES: [Node] = [ elementChoices: [.stringSegment, .expressionSegment] ), + Node( + kind: .simpleStringLiteralExpr, + base: .expr, + nameForDiagnostics: "simple string literal", + documentation: "A simple string that can’t contain string interpolation and cannot have raw string delimiters.", + children: [ + Child( + name: "OpeningQuote", + kind: .token(choices: [.token(.stringQuote), .token(.multilineStringQuote)]), + documentation: "Open quote for the string literal" + ), + Child( + name: "Segments", + kind: .collection(kind: .simpleStringLiteralSegmentList, collectionElementName: "Segment"), + documentation: "String content" + ), + Child( + name: "ClosingQuote", + kind: .token(choices: [.token(.stringQuote), .token(.multilineStringQuote)]), + documentation: "Close quote for the string literal" + ), + ] + ), + + Node( + kind: .simpleStringLiteralSegmentList, + base: .syntaxCollection, + nameForDiagnostics: nil, + documentation: "String literal segments that only can contain non string interpolated or extended escaped strings", + elementChoices: [.stringSegment] + ), + // string literal segment in a string interpolation expression. Node( kind: .stringSegment, diff --git a/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift b/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift index 7aeda5f1ee7..91c9a0225da 100644 --- a/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift +++ b/CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift @@ -250,6 +250,8 @@ public enum SyntaxNodeKind: String, CaseIterable { case specializeAvailabilityArgument case specializeTargetFunctionArgument case stmt + case simpleStringLiteralExpr + case simpleStringLiteralSegmentList case stringLiteralExpr case stringLiteralSegmentList case stringSegment diff --git a/Sources/SwiftBasicFormat/BasicFormat.swift b/Sources/SwiftBasicFormat/BasicFormat.swift index 5a663945c45..1d7f12fd5c2 100644 --- a/Sources/SwiftBasicFormat/BasicFormat.swift +++ b/Sources/SwiftBasicFormat/BasicFormat.swift @@ -347,6 +347,7 @@ open class BasicFormat: SyntaxRewriter { case \ExpressionSegmentSyntax.backslash, \ExpressionSegmentSyntax.rightParen, \DeclNameArgumentSyntax.colon, + \SimpleStringLiteralExprSyntax.openingQuote, \StringLiteralExprSyntax.openingQuote, \RegexLiteralExprSyntax.openingSlash: return false diff --git a/Sources/SwiftParser/Availability.swift b/Sources/SwiftParser/Availability.swift index 8101741d60a..4dc2696359c 100644 --- a/Sources/SwiftParser/Availability.swift +++ b/Sources/SwiftParser/Availability.swift @@ -102,8 +102,7 @@ extension Parser { (.renamed, let handle)?: let argumentLabel = self.eat(handle) let (unexpectedBeforeColon, colon) = self.expect(.colon) - // FIXME: Make sure this is a string literal with no interpolation. - let stringValue = self.parseStringLiteral() + let stringValue = self.parseSimpleString() entry = .availabilityLabeledArgument( RawAvailabilityLabeledArgumentSyntax( diff --git a/Sources/SwiftParser/Directives.swift b/Sources/SwiftParser/Directives.swift index 63ae86699c2..b3fd95f58cf 100644 --- a/Sources/SwiftParser/Directives.swift +++ b/Sources/SwiftParser/Directives.swift @@ -196,7 +196,7 @@ extension Parser { if !self.at(.rightParen) { let (unexpectedBeforeFile, file) = self.expect(.keyword(.file)) let (unexpectedBeforeFileColon, fileColon) = self.expect(.colon) - let fileName = self.parseStringLiteral() + let fileName = self.parseSimpleString() let (unexpectedBeforeComma, comma) = self.expect(.comma) let (unexpectedBeforeLine, line) = self.expect(.keyword(.line)) diff --git a/Sources/SwiftParser/StringLiterals.swift b/Sources/SwiftParser/StringLiterals.swift index 35edf913a7d..4224e5dd361 100644 --- a/Sources/SwiftParser/StringLiterals.swift +++ b/Sources/SwiftParser/StringLiterals.swift @@ -147,7 +147,7 @@ extension Parser { return RawTokenSyntax( kind: token.tokenKind, text: SyntaxText(rebasing: token.tokenText.dropFirst(reclassifyLeading.count).dropLast(reclassifyTrailing.count)), - leadingTriviaPieces: token.leadingTriviaPieces + TriviaParser.parseTrivia(reclassifyLeading, position: .trailing), + leadingTriviaPieces: token.leadingTriviaPieces + TriviaParser.parseTrivia(reclassifyLeading, position: .leading), trailingTriviaPieces: TriviaParser.parseTrivia(reclassifyTrailing, position: .trailing) + token.trailingTriviaPieces, presence: token.presence, tokenDiagnostic: token.tokenView.tokenDiagnostic ?? tokenDiagnostic, @@ -595,10 +595,110 @@ extension Parser { ) } } + + mutating func parseSimpleString() -> RawSimpleStringLiteralExprSyntax { + let openDelimiter = self.consume(if: .rawStringPoundDelimiter) + let (unexpectedBeforeOpenQuote, openQuote) = self.expect(anyIn: SimpleStringLiteralExprSyntax.OpeningQuoteOptions.self, default: .stringQuote) + + /// Parse segments. + var segments: [RawStringSegmentSyntax] = [] + var loopProgress = LoopProgressCondition() + while hasProgressed(&loopProgress) { + // If we encounter a token with leading trivia, we're no longer in the + // string literal. + guard currentToken.leadingTriviaText.isEmpty else { break } + + if let stringSegment = self.consume(if: .stringSegment, TokenSpec(.identifier, remapping: .stringSegment)) { + var unexpectedAfterContent: RawUnexpectedNodesSyntax? + + if let (backslash, leftParen) = self.consume(if: .backslash, followedBy: .leftParen) { + var unexpectedTokens: [RawSyntax] = [RawSyntax(backslash), RawSyntax(leftParen)] + + let (unexpectedBeforeRightParen, rightParen) = self.expect(TokenSpec(.rightParen, allowAtStartOfLine: false)) + unexpectedTokens += unexpectedBeforeRightParen?.elements ?? [] + unexpectedTokens.append(RawSyntax(rightParen)) + + unexpectedAfterContent = RawUnexpectedNodesSyntax( + unexpectedTokens, + arena: self.arena + ) + } + + segments.append(RawStringSegmentSyntax(content: stringSegment, unexpectedAfterContent, arena: self.arena)) + } else { + break + } + } + + let (unexpectedBetweenSegmentAndCloseQuote, closeQuote) = self.expect( + anyIn: SimpleStringLiteralExprSyntax.ClosingQuoteOptions.self, + default: openQuote.closeTokenKind + ) + let closeDelimiter = self.consume(if: .rawStringPoundDelimiter) + + if openQuote.tokenKind == .multilineStringQuote, !openQuote.isMissing, !closeQuote.isMissing { + let postProcessed = postProcessMultilineStringLiteral( + rawStringDelimitersToken: openDelimiter, + openQuote: openQuote, + segments: segments.compactMap { RawStringLiteralSegmentListSyntax.Element.stringSegment($0) }, + closeQuote: closeQuote + ) + + return RawSimpleStringLiteralExprSyntax( + RawUnexpectedNodesSyntax( + combining: openDelimiter, + unexpectedBeforeOpenQuote, + postProcessed.unexpectedBeforeOpeningQuote, + arena: self.arena + ), + openingQuote: postProcessed.openingQuote, + segments: RawSimpleStringLiteralSegmentListSyntax( + // `RawSimpleStringLiteralSegmentListSyntax` only accepts `RawStringSegmentSyntax`. + // So we can safely cast. + elements: postProcessed.segments.map { $0.cast(RawStringSegmentSyntax.self) }, + arena: self.arena + ), + RawUnexpectedNodesSyntax( + combining: unexpectedBetweenSegmentAndCloseQuote, + postProcessed.unexpectedBeforeClosingQuote, + arena: self.arena + ), + closingQuote: postProcessed.closingQuote, + RawUnexpectedNodesSyntax( + [closeDelimiter], + arena: self.arena + ), + arena: self.arena + ) + } else { + return RawSimpleStringLiteralExprSyntax( + RawUnexpectedNodesSyntax(combining: unexpectedBeforeOpenQuote, openDelimiter, arena: self.arena), + openingQuote: openQuote, + segments: RawSimpleStringLiteralSegmentListSyntax(elements: segments, arena: self.arena), + unexpectedBetweenSegmentAndCloseQuote, + closingQuote: closeQuote, + RawUnexpectedNodesSyntax([closeDelimiter], arena: self.arena), + arena: self.arena + ) + } + } } // MARK: - Utilities +fileprivate extension RawTokenSyntax { + var closeTokenKind: SimpleStringLiteralExprSyntax.ClosingQuoteOptions { + switch self { + case .multilineStringQuote: + return .multilineStringQuote + case .stringQuote: + return .stringQuote + default: + return .stringQuote + } + } +} + fileprivate extension SyntaxText { private func hasSuffix(_ other: String) -> Bool { var other = other diff --git a/Sources/SwiftParser/generated/Parser+TokenSpecSet.swift b/Sources/SwiftParser/generated/Parser+TokenSpecSet.swift index fde18c2bacb..7c0da11d953 100644 --- a/Sources/SwiftParser/generated/Parser+TokenSpecSet.swift +++ b/Sources/SwiftParser/generated/Parser+TokenSpecSet.swift @@ -2585,6 +2585,88 @@ extension SameTypeRequirementSyntax { } } +extension SimpleStringLiteralExprSyntax { + @_spi(Diagnostics) + public enum OpeningQuoteOptions: TokenSpecSet { + case stringQuote + case multilineStringQuote + + init?(lexeme: Lexer.Lexeme) { + switch PrepareForKeywordMatch(lexeme) { + case TokenSpec(.stringQuote): + self = .stringQuote + case TokenSpec(.multilineStringQuote): + self = .multilineStringQuote + default: + return nil + } + } + + var spec: TokenSpec { + switch self { + case .stringQuote: + return .stringQuote + case .multilineStringQuote: + return .multilineStringQuote + } + } + + /// Returns a token that satisfies the `TokenSpec` of this case. + /// + /// If the token kind of this spec has variable text, e.g. for an identifier, this returns a token with empty text. + @_spi(Diagnostics) + public var tokenSyntax: TokenSyntax { + switch self { + case .stringQuote: + return .stringQuoteToken() + case .multilineStringQuote: + return .multilineStringQuoteToken() + } + } + } +} + +extension SimpleStringLiteralExprSyntax { + @_spi(Diagnostics) + public enum ClosingQuoteOptions: TokenSpecSet { + case stringQuote + case multilineStringQuote + + init?(lexeme: Lexer.Lexeme) { + switch PrepareForKeywordMatch(lexeme) { + case TokenSpec(.stringQuote): + self = .stringQuote + case TokenSpec(.multilineStringQuote): + self = .multilineStringQuote + default: + return nil + } + } + + var spec: TokenSpec { + switch self { + case .stringQuote: + return .stringQuote + case .multilineStringQuote: + return .multilineStringQuote + } + } + + /// Returns a token that satisfies the `TokenSpec` of this case. + /// + /// If the token kind of this spec has variable text, e.g. for an identifier, this returns a token with empty text. + @_spi(Diagnostics) + public var tokenSyntax: TokenSyntax { + switch self { + case .stringQuote: + return .stringQuoteToken() + case .multilineStringQuote: + return .multilineStringQuoteToken() + } + } + } +} + extension SomeOrAnyTypeSyntax { @_spi(Diagnostics) public enum SomeOrAnySpecifierOptions: TokenSpecSet { diff --git a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift index 5057dc63419..e4b93764270 100644 --- a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift +++ b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift @@ -1506,6 +1506,56 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor { return .visitChildren } + public override func visit(_ node: SimpleStringLiteralExprSyntax) -> SyntaxVisitorContinueKind { + if shouldSkip(node) { + return .skipChildren + } + + var rawDelimiters: [TokenSyntax] = [] + + if let unexpectedBeforeOpenQuote = node.unexpectedBeforeOpeningQuote?.onlyPresentToken(where: { $0.tokenKind.isRawStringDelimiter }) { + rawDelimiters += [unexpectedBeforeOpenQuote] + } + + if let unexpectedAfterCloseQuote = node.unexpectedAfterClosingQuote?.onlyPresentToken(where: { $0.tokenKind.isRawStringDelimiter }) { + rawDelimiters += [unexpectedAfterCloseQuote] + } + + if !rawDelimiters.isEmpty { + addDiagnostic( + node, + .forbiddenExtendedEscapingString, + fixIts: [ + FixIt( + message: RemoveNodesFixIt(rawDelimiters), + changes: rawDelimiters.map { .makeMissing($0) } + ) + ], + handledNodes: rawDelimiters.map { $0.id } + ) + } + + return .visitChildren + } + + public override func visit(_ node: SimpleStringLiteralSegmentListSyntax) -> SyntaxVisitorContinueKind { + if shouldSkip(node) { + return .skipChildren + } + + for segment in node { + if let unexpectedAfterContent = segment.unexpectedAfterContent { + addDiagnostic( + node, + .forbiddenInterpolatedString, + handledNodes: [unexpectedAfterContent.id] + ) + } + } + + return .visitChildren + } + public override func visit(_ node: SourceFileSyntax) -> SyntaxVisitorContinueKind { if shouldSkip(node) { return .skipChildren diff --git a/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift b/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift index 401135b3bdb..a9b6e2276b2 100644 --- a/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift +++ b/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift @@ -165,6 +165,12 @@ extension DiagnosticMessage where Self == StaticParserError { public static var extraRightBracket: Self { .init("unexpected ']' in type; did you mean to write an array type?") } + public static var forbiddenExtendedEscapingString: Self { + .init("argument cannot be an extended escaping string literal") + } + public static var forbiddenInterpolatedString: Self { + return .init("argument cannot be an interpolated string literal") + } public static var initializerInPattern: Self { .init("unexpected initializer in pattern; did you mean to use '='?") } diff --git a/Sources/SwiftParserDiagnostics/SyntaxExtensions.swift b/Sources/SwiftParserDiagnostics/SyntaxExtensions.swift index bf3c0cd6cc0..47f251add25 100644 --- a/Sources/SwiftParserDiagnostics/SyntaxExtensions.swift +++ b/Sources/SwiftParserDiagnostics/SyntaxExtensions.swift @@ -163,6 +163,15 @@ extension TokenKind { return false } } + + var isRawStringDelimiter: Bool { + switch self { + case .rawStringPoundDelimiter: + return true + default: + return false + } + } } public extension TriviaPiece { diff --git a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift index 5c782a9b688..caf00deb6a2 100644 --- a/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift +++ b/Sources/SwiftParserDiagnostics/generated/SyntaxKindNameForDiagnostics.swift @@ -331,6 +331,8 @@ extension SyntaxKind { return "'return' statement" case .sameTypeRequirement: return "same type requirement" + case .simpleStringLiteralExpr: + return "simple string literal" case .someOrAnyType: return "type" case .sourceFile: diff --git a/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md b/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md index 19e07514242..9330148b2fa 100644 --- a/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md +++ b/Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md @@ -133,6 +133,7 @@ These articles are intended for developers wishing to contribute to SwiftSyntax - - - +- - - - @@ -282,6 +283,8 @@ These articles are intended for developers wishing to contribute to SwiftSyntax - - - +- +- - - - diff --git a/Sources/SwiftSyntax/Raw/RawSyntaxNodeProtocol.swift b/Sources/SwiftSyntax/Raw/RawSyntaxNodeProtocol.swift index d3ca583edaa..23779d414c5 100644 --- a/Sources/SwiftSyntax/Raw/RawSyntaxNodeProtocol.swift +++ b/Sources/SwiftSyntax/Raw/RawSyntaxNodeProtocol.swift @@ -35,6 +35,10 @@ public extension RawSyntaxNodeProtocol { Node.isKindOf(self.raw) } + func cast(_ syntaxType: S.Type) -> S { + return self.as(S.self)! + } + var description: String { raw.description } diff --git a/Sources/SwiftSyntax/SourceLocation.swift b/Sources/SwiftSyntax/SourceLocation.swift index a32d878ace0..647d225e2c0 100644 --- a/Sources/SwiftSyntax/SourceLocation.swift +++ b/Sources/SwiftSyntax/SourceLocation.swift @@ -122,7 +122,7 @@ fileprivate class SourceLocationCollector: SyntaxVisitor { fileprivate struct SourceLocationDirectiveArguments { enum Error: Swift.Error, CustomStringConvertible { case nonDecimalLineNumber(TokenSyntax) - case stringInterpolationInFileName(StringLiteralExprSyntax) + case stringInterpolationInFileName(SimpleStringLiteralExprSyntax) var description: String { switch self { @@ -142,7 +142,7 @@ fileprivate struct SourceLocationDirectiveArguments { init(_ args: PoundSourceLocationArgumentsSyntax) throws { guard args.fileName.segments.count == 1, - case .stringSegment(let segment) = args.fileName.segments.first! + let segment = args.fileName.segments.first else { throw Error.stringInterpolationInFileName(args.fileName) } diff --git a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift index 8e0c72c6c71..24b853b4dd5 100644 --- a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift +++ b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift @@ -2769,6 +2769,20 @@ public func childName(_ keyPath: AnyKeyPath) -> String? { return "elements" case \SequenceExprSyntax.unexpectedAfterElements: return "unexpectedAfterElements" + case \SimpleStringLiteralExprSyntax.unexpectedBeforeOpeningQuote: + return "unexpectedBeforeOpeningQuote" + case \SimpleStringLiteralExprSyntax.openingQuote: + return "openingQuote" + case \SimpleStringLiteralExprSyntax.unexpectedBetweenOpeningQuoteAndSegments: + return "unexpectedBetweenOpeningQuoteAndSegments" + case \SimpleStringLiteralExprSyntax.segments: + return "segments" + case \SimpleStringLiteralExprSyntax.unexpectedBetweenSegmentsAndClosingQuote: + return "unexpectedBetweenSegmentsAndClosingQuote" + case \SimpleStringLiteralExprSyntax.closingQuote: + return "closingQuote" + case \SimpleStringLiteralExprSyntax.unexpectedAfterClosingQuote: + return "unexpectedAfterClosingQuote" case \SomeOrAnyTypeSyntax.unexpectedBeforeSomeOrAnySpecifier: return "unexpectedBeforeSomeOrAnySpecifier" case \SomeOrAnyTypeSyntax.someOrAnySpecifier: diff --git a/Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift b/Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift index 0c9a58e155f..9c2360f2fec 100644 --- a/Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift +++ b/Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift @@ -5987,7 +5987,7 @@ extension PoundSourceLocationArgumentsSyntax { _ unexpectedBetweenFileArgLabelAndFileArgColon: UnexpectedNodesSyntax? = nil, fileArgColon: TokenSyntax = .colonToken(), _ unexpectedBetweenFileArgColonAndFileName: UnexpectedNodesSyntax? = nil, - fileName: StringLiteralExprSyntax, + fileName: SimpleStringLiteralExprSyntax, _ unexpectedBetweenFileNameAndComma: UnexpectedNodesSyntax? = nil, comma: TokenSyntax = .commaToken(), _ unexpectedBetweenCommaAndLineArgLabel: UnexpectedNodesSyntax? = nil, diff --git a/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift b/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift index bdfbad18dd7..6ee366f6e07 100644 --- a/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift +++ b/Sources/SwiftSyntax/generated/SyntaxAnyVisitor.swift @@ -1821,6 +1821,22 @@ open class SyntaxAnyVisitor: SyntaxVisitor { visitAnyPost(node._syntaxNode) } + override open func visit(_ node: SimpleStringLiteralExprSyntax) -> SyntaxVisitorContinueKind { + return visitAny(node._syntaxNode) + } + + override open func visitPost(_ node: SimpleStringLiteralExprSyntax) { + visitAnyPost(node._syntaxNode) + } + + override open func visit(_ node: SimpleStringLiteralSegmentListSyntax) -> SyntaxVisitorContinueKind { + return visitAny(node._syntaxNode) + } + + override open func visitPost(_ node: SimpleStringLiteralSegmentListSyntax) { + visitAnyPost(node._syntaxNode) + } + override open func visit(_ node: SomeOrAnyTypeSyntax) -> SyntaxVisitorContinueKind { return visitAny(node._syntaxNode) } diff --git a/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift b/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift index 338727e333f..39cffa35f63 100644 --- a/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift +++ b/Sources/SwiftSyntax/generated/SyntaxBaseNodes.swift @@ -206,7 +206,7 @@ public struct ExprSyntax: ExprSyntaxProtocol, SyntaxHashable { public init?(_ node: some SyntaxProtocol) { switch node.raw.kind { - case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, .canImportExpr, .canImportVersionInfo, .closureExpr, .consumeExpr, .copyExpr, .declReferenceExpr, .dictionaryExpr, .discardAssignmentExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forceUnwrapExpr, .functionCallExpr, .genericSpecializationExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .patternExpr, .postfixIfConfigExpr, .postfixOperatorExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .stringLiteralExpr, .subscriptCallExpr, .superExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedTernaryExpr: + case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, .canImportExpr, .canImportVersionInfo, .closureExpr, .consumeExpr, .copyExpr, .declReferenceExpr, .dictionaryExpr, .discardAssignmentExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forceUnwrapExpr, .functionCallExpr, .genericSpecializationExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .patternExpr, .postfixIfConfigExpr, .postfixOperatorExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .simpleStringLiteralExpr, .stringLiteralExpr, .subscriptCallExpr, .superExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedTernaryExpr: self._syntaxNode = node._syntaxNode default: return nil @@ -218,7 +218,7 @@ public struct ExprSyntax: ExprSyntaxProtocol, SyntaxHashable { /// is undefined. internal init(_ data: SyntaxData) { switch data.raw.kind { - case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, .canImportExpr, .canImportVersionInfo, .closureExpr, .consumeExpr, .copyExpr, .declReferenceExpr, .dictionaryExpr, .discardAssignmentExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forceUnwrapExpr, .functionCallExpr, .genericSpecializationExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .patternExpr, .postfixIfConfigExpr, .postfixOperatorExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .stringLiteralExpr, .subscriptCallExpr, .superExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedTernaryExpr: + case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, .canImportExpr, .canImportVersionInfo, .closureExpr, .consumeExpr, .copyExpr, .declReferenceExpr, .dictionaryExpr, .discardAssignmentExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forceUnwrapExpr, .functionCallExpr, .genericSpecializationExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .patternExpr, .postfixIfConfigExpr, .postfixOperatorExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .simpleStringLiteralExpr, .stringLiteralExpr, .subscriptCallExpr, .superExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedTernaryExpr: break default: preconditionFailure("Unable to create ExprSyntax from \(data.raw.kind)") @@ -294,6 +294,7 @@ public struct ExprSyntax: ExprSyntaxProtocol, SyntaxHashable { .node(PrefixOperatorExprSyntax.self), .node(RegexLiteralExprSyntax.self), .node(SequenceExprSyntax.self), + .node(SimpleStringLiteralExprSyntax.self), .node(StringLiteralExprSyntax.self), .node(SubscriptCallExprSyntax.self), .node(SuperExprSyntax.self), @@ -908,6 +909,8 @@ extension Syntax { .node(ReturnStmtSyntax.self), .node(SameTypeRequirementSyntax.self), .node(SequenceExprSyntax.self), + .node(SimpleStringLiteralExprSyntax.self), + .node(SimpleStringLiteralSegmentListSyntax.self), .node(SomeOrAnyTypeSyntax.self), .node(SourceFileSyntax.self), .node(SpecializeAttributeArgumentListSyntax.self), diff --git a/Sources/SwiftSyntax/generated/SyntaxCollections.swift b/Sources/SwiftSyntax/generated/SyntaxCollections.swift index 821cd2ce7f0..2e3bae9600a 100644 --- a/Sources/SwiftSyntax/generated/SyntaxCollections.swift +++ b/Sources/SwiftSyntax/generated/SyntaxCollections.swift @@ -1056,6 +1056,30 @@ public struct PrimaryAssociatedTypeListSyntax: SyntaxCollection, SyntaxHashable public static let syntaxKind = SyntaxKind.primaryAssociatedTypeList } +/// String literal segments that only can contain non string interpolated or extended escaped strings +/// +/// ### Children +/// +/// ``StringSegmentSyntax`` `*` +/// +/// ### Contained in +/// +/// - ``SimpleStringLiteralExprSyntax``.``SimpleStringLiteralExprSyntax/segments`` +public struct SimpleStringLiteralSegmentListSyntax: SyntaxCollection, SyntaxHashable { + public typealias Element = StringSegmentSyntax + + public let _syntaxNode: Syntax + + public init?(_ node: some SyntaxProtocol) { + guard node.raw.kind == .simpleStringLiteralSegmentList else { + return nil + } + self._syntaxNode = node._syntaxNode + } + + public static let syntaxKind = SyntaxKind.simpleStringLiteralSegmentList +} + /// A collection of arguments for the `@_specialize` attribute /// /// ### Children diff --git a/Sources/SwiftSyntax/generated/SyntaxEnum.swift b/Sources/SwiftSyntax/generated/SyntaxEnum.swift index f6911cf0d2a..0ca2ca95621 100644 --- a/Sources/SwiftSyntax/generated/SyntaxEnum.swift +++ b/Sources/SwiftSyntax/generated/SyntaxEnum.swift @@ -236,6 +236,8 @@ public enum SyntaxEnum { case returnStmt(ReturnStmtSyntax) case sameTypeRequirement(SameTypeRequirementSyntax) case sequenceExpr(SequenceExprSyntax) + case simpleStringLiteralExpr(SimpleStringLiteralExprSyntax) + case simpleStringLiteralSegmentList(SimpleStringLiteralSegmentListSyntax) case someOrAnyType(SomeOrAnyTypeSyntax) case sourceFile(SourceFileSyntax) case specializeAttributeArgumentList(SpecializeAttributeArgumentListSyntax) @@ -739,6 +741,10 @@ public extension Syntax { return .sameTypeRequirement(SameTypeRequirementSyntax(self)!) case .sequenceExpr: return .sequenceExpr(SequenceExprSyntax(self)!) + case .simpleStringLiteralExpr: + return .simpleStringLiteralExpr(SimpleStringLiteralExprSyntax(self)!) + case .simpleStringLiteralSegmentList: + return .simpleStringLiteralSegmentList(SimpleStringLiteralSegmentListSyntax(self)!) case .someOrAnyType: return .someOrAnyType(SomeOrAnyTypeSyntax(self)!) case .sourceFile: diff --git a/Sources/SwiftSyntax/generated/SyntaxKind.swift b/Sources/SwiftSyntax/generated/SyntaxKind.swift index 4f44d2b5405..18ef130b17c 100644 --- a/Sources/SwiftSyntax/generated/SyntaxKind.swift +++ b/Sources/SwiftSyntax/generated/SyntaxKind.swift @@ -236,6 +236,8 @@ public enum SyntaxKind: CaseIterable { case returnStmt case sameTypeRequirement case sequenceExpr + case simpleStringLiteralExpr + case simpleStringLiteralSegmentList case someOrAnyType case sourceFile case specializeAttributeArgumentList @@ -370,6 +372,8 @@ public enum SyntaxKind: CaseIterable { return true case .primaryAssociatedTypeList: return true + case .simpleStringLiteralSegmentList: + return true case .specializeAttributeArgumentList: return true case .stringLiteralSegmentList: @@ -858,6 +862,10 @@ public enum SyntaxKind: CaseIterable { return SameTypeRequirementSyntax.self case .sequenceExpr: return SequenceExprSyntax.self + case .simpleStringLiteralExpr: + return SimpleStringLiteralExprSyntax.self + case .simpleStringLiteralSegmentList: + return SimpleStringLiteralSegmentListSyntax.self case .someOrAnyType: return SomeOrAnyTypeSyntax.self case .sourceFile: diff --git a/Sources/SwiftSyntax/generated/SyntaxRewriter.swift b/Sources/SwiftSyntax/generated/SyntaxRewriter.swift index 5c52a74f98a..60c8ff8c1d7 100644 --- a/Sources/SwiftSyntax/generated/SyntaxRewriter.swift +++ b/Sources/SwiftSyntax/generated/SyntaxRewriter.swift @@ -1627,6 +1627,20 @@ open class SyntaxRewriter { return ExprSyntax(visitChildren(node)) } + /// Visit a ``SimpleStringLiteralExprSyntax``. + /// - Parameter node: the node that is being visited + /// - Returns: the rewritten node + open func visit(_ node: SimpleStringLiteralExprSyntax) -> ExprSyntax { + return ExprSyntax(visitChildren(node)) + } + + /// Visit a ``SimpleStringLiteralSegmentListSyntax``. + /// - Parameter node: the node that is being visited + /// - Returns: the rewritten node + open func visit(_ node: SimpleStringLiteralSegmentListSyntax) -> SimpleStringLiteralSegmentListSyntax { + return Syntax(visitChildren(node)).cast(SimpleStringLiteralSegmentListSyntax.self) + } + /// Visit a ``SomeOrAnyTypeSyntax``. /// - Parameter node: the node that is being visited /// - Returns: the rewritten node @@ -5127,6 +5141,34 @@ open class SyntaxRewriter { return Syntax(visit(node)) } + /// Implementation detail of visit(_:). Do not call directly. + private func visitImplSimpleStringLiteralExprSyntax(_ data: SyntaxData) -> Syntax { + let node = SimpleStringLiteralExprSyntax(data) + // Accessing _syntaxNode directly is faster than calling Syntax(node) + visitPre(node._syntaxNode) + defer { + visitPost(node._syntaxNode) + } + if let newNode = visitAny(node._syntaxNode) { + return newNode + } + return Syntax(visit(node)) + } + + /// Implementation detail of visit(_:). Do not call directly. + private func visitImplSimpleStringLiteralSegmentListSyntax(_ data: SyntaxData) -> Syntax { + let node = SimpleStringLiteralSegmentListSyntax(data) + // Accessing _syntaxNode directly is faster than calling Syntax(node) + visitPre(node._syntaxNode) + defer { + visitPost(node._syntaxNode) + } + if let newNode = visitAny(node._syntaxNode) { + return newNode + } + return Syntax(visit(node)) + } + /// Implementation detail of visit(_:). Do not call directly. private func visitImplSomeOrAnyTypeSyntax(_ data: SyntaxData) -> Syntax { let node = SomeOrAnyTypeSyntax(data) @@ -6353,6 +6395,10 @@ open class SyntaxRewriter { return visitImplSameTypeRequirementSyntax case .sequenceExpr: return visitImplSequenceExprSyntax + case .simpleStringLiteralExpr: + return visitImplSimpleStringLiteralExprSyntax + case .simpleStringLiteralSegmentList: + return visitImplSimpleStringLiteralSegmentListSyntax case .someOrAnyType: return visitImplSomeOrAnyTypeSyntax case .sourceFile: @@ -6911,6 +6957,10 @@ open class SyntaxRewriter { return visitImplSameTypeRequirementSyntax(data) case .sequenceExpr: return visitImplSequenceExprSyntax(data) + case .simpleStringLiteralExpr: + return visitImplSimpleStringLiteralExprSyntax(data) + case .simpleStringLiteralSegmentList: + return visitImplSimpleStringLiteralSegmentListSyntax(data) case .someOrAnyType: return visitImplSomeOrAnyTypeSyntax(data) case .sourceFile: diff --git a/Sources/SwiftSyntax/generated/SyntaxTransform.swift b/Sources/SwiftSyntax/generated/SyntaxTransform.swift index b47e319d491..2655fe4b83f 100644 --- a/Sources/SwiftSyntax/generated/SyntaxTransform.swift +++ b/Sources/SwiftSyntax/generated/SyntaxTransform.swift @@ -1124,6 +1124,16 @@ public protocol SyntaxTransformVisitor { /// - Returns: the sum of whatever the child visitors return. func visit(_ node: SequenceExprSyntax) -> ResultType + /// Visiting ``SimpleStringLiteralExprSyntax`` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: the sum of whatever the child visitors return. + func visit(_ node: SimpleStringLiteralExprSyntax) -> ResultType + + /// Visiting ``SimpleStringLiteralSegmentListSyntax`` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: the sum of whatever the child visitors return. + func visit(_ node: SimpleStringLiteralSegmentListSyntax) -> ResultType + /// Visiting ``SomeOrAnyTypeSyntax`` specifically. /// - Parameter node: the node we are visiting. /// - Returns: the sum of whatever the child visitors return. @@ -2942,6 +2952,20 @@ extension SyntaxTransformVisitor { visitAny(Syntax(node)) } + /// Visiting ``SimpleStringLiteralExprSyntax`` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: nil by default. + public func visit(_ node: SimpleStringLiteralExprSyntax) -> ResultType { + visitAny(Syntax(node)) + } + + /// Visiting ``SimpleStringLiteralSegmentListSyntax`` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: nil by default. + public func visit(_ node: SimpleStringLiteralSegmentListSyntax) -> ResultType { + visitAny(Syntax(node)) + } + /// Visiting ``SomeOrAnyTypeSyntax`` specifically. /// - Parameter node: the node we are visiting. /// - Returns: nil by default. @@ -3759,6 +3783,10 @@ extension SyntaxTransformVisitor { return visit(derived) case .sequenceExpr(let derived): return visit(derived) + case .simpleStringLiteralExpr(let derived): + return visit(derived) + case .simpleStringLiteralSegmentList(let derived): + return visit(derived) case .someOrAnyType(let derived): return visit(derived) case .sourceFile(let derived): diff --git a/Sources/SwiftSyntax/generated/SyntaxVisitor.swift b/Sources/SwiftSyntax/generated/SyntaxVisitor.swift index 30cd0f057c6..56a78a5387b 100644 --- a/Sources/SwiftSyntax/generated/SyntaxVisitor.swift +++ b/Sources/SwiftSyntax/generated/SyntaxVisitor.swift @@ -2686,6 +2686,30 @@ open class SyntaxVisitor { open func visitPost(_ node: SequenceExprSyntax) { } + /// Visiting ``SimpleStringLiteralExprSyntax`` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: how should we continue visiting. + open func visit(_ node: SimpleStringLiteralExprSyntax) -> SyntaxVisitorContinueKind { + return .visitChildren + } + + /// The function called after visiting ``SimpleStringLiteralExprSyntax`` and its descendants. + /// - node: the node we just finished visiting. + open func visitPost(_ node: SimpleStringLiteralExprSyntax) { + } + + /// Visiting ``SimpleStringLiteralSegmentListSyntax`` specifically. + /// - Parameter node: the node we are visiting. + /// - Returns: how should we continue visiting. + open func visit(_ node: SimpleStringLiteralSegmentListSyntax) -> SyntaxVisitorContinueKind { + return .visitChildren + } + + /// The function called after visiting ``SimpleStringLiteralSegmentListSyntax`` and its descendants. + /// - node: the node we just finished visiting. + open func visitPost(_ node: SimpleStringLiteralSegmentListSyntax) { + } + /// Visiting ``SomeOrAnyTypeSyntax`` specifically. /// - Parameter node: the node we are visiting. /// - Returns: how should we continue visiting. @@ -5765,6 +5789,28 @@ open class SyntaxVisitor { visitPost(node) } + /// Implementation detail of doVisit(_:_:). Do not call directly. + private func visitImplSimpleStringLiteralExprSyntax(_ data: SyntaxData) { + let node = SimpleStringLiteralExprSyntax(data) + let needsChildren = (visit(node) == .visitChildren) + // Avoid calling into visitChildren if possible. + if needsChildren && !node.raw.layoutView!.children.isEmpty { + visitChildren(node) + } + visitPost(node) + } + + /// Implementation detail of doVisit(_:_:). Do not call directly. + private func visitImplSimpleStringLiteralSegmentListSyntax(_ data: SyntaxData) { + let node = SimpleStringLiteralSegmentListSyntax(data) + let needsChildren = (visit(node) == .visitChildren) + // Avoid calling into visitChildren if possible. + if needsChildren && !node.raw.layoutView!.children.isEmpty { + visitChildren(node) + } + visitPost(node) + } + /// Implementation detail of doVisit(_:_:). Do not call directly. private func visitImplSomeOrAnyTypeSyntax(_ data: SyntaxData) { let node = SomeOrAnyTypeSyntax(data) @@ -6797,6 +6843,10 @@ open class SyntaxVisitor { visitImplSameTypeRequirementSyntax(data) case .sequenceExpr: visitImplSequenceExprSyntax(data) + case .simpleStringLiteralExpr: + visitImplSimpleStringLiteralExprSyntax(data) + case .simpleStringLiteralSegmentList: + visitImplSimpleStringLiteralSegmentListSyntax(data) case .someOrAnyType: visitImplSomeOrAnyTypeSyntax(data) case .sourceFile: diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift index 85fa79f4b60..5190988515e 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift @@ -1915,11 +1915,11 @@ public struct RawAvailabilityConditionSyntax: RawSyntaxNodeProtocol { @_spi(RawSyntax) public struct RawAvailabilityLabeledArgumentSyntax: RawSyntaxNodeProtocol { public enum Value: RawSyntaxNodeProtocol { - case `string`(RawStringLiteralExprSyntax) + case `string`(RawSimpleStringLiteralExprSyntax) case `version`(RawVersionTupleSyntax) public static func isKindOf(_ raw: RawSyntax) -> Bool { - return RawStringLiteralExprSyntax.isKindOf(raw) || RawVersionTupleSyntax.isKindOf(raw) + return RawSimpleStringLiteralExprSyntax.isKindOf(raw) || RawVersionTupleSyntax.isKindOf(raw) } public var raw: RawSyntax { @@ -1932,7 +1932,7 @@ public struct RawAvailabilityLabeledArgumentSyntax: RawSyntaxNodeProtocol { } public init?(_ other: some RawSyntaxNodeProtocol) { - if let node = RawStringLiteralExprSyntax(other) { + if let node = RawSimpleStringLiteralExprSyntax(other) { self = .string(node) return } @@ -8343,7 +8343,7 @@ public struct RawExprSyntax: RawExprSyntaxNodeProtocol { public static func isKindOf(_ raw: RawSyntax) -> Bool { switch raw.kind { - case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, .canImportExpr, .canImportVersionInfo, .closureExpr, .consumeExpr, .copyExpr, .declReferenceExpr, .dictionaryExpr, .discardAssignmentExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forceUnwrapExpr, .functionCallExpr, .genericSpecializationExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .patternExpr, .postfixIfConfigExpr, .postfixOperatorExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .stringLiteralExpr, .subscriptCallExpr, .superExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedTernaryExpr: + case .arrayExpr, .arrowExpr, .asExpr, .assignmentExpr, .awaitExpr, .binaryOperatorExpr, .booleanLiteralExpr, .borrowExpr, .canImportExpr, .canImportVersionInfo, .closureExpr, .consumeExpr, .copyExpr, .declReferenceExpr, .dictionaryExpr, .discardAssignmentExpr, .editorPlaceholderExpr, .floatLiteralExpr, .forceUnwrapExpr, .functionCallExpr, .genericSpecializationExpr, .ifExpr, .inOutExpr, .infixOperatorExpr, .integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .missingExpr, .nilLiteralExpr, .optionalChainingExpr, .packElementExpr, .packExpansionExpr, .patternExpr, .postfixIfConfigExpr, .postfixOperatorExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr, .simpleStringLiteralExpr, .stringLiteralExpr, .subscriptCallExpr, .superExpr, .switchExpr, .ternaryExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr, .unresolvedTernaryExpr: return true default: return false @@ -16558,7 +16558,7 @@ public struct RawPoundSourceLocationArgumentsSyntax: RawSyntaxNodeProtocol { _ unexpectedBetweenFileLabelAndFileColon: RawUnexpectedNodesSyntax? = nil, fileColon: RawTokenSyntax, _ unexpectedBetweenFileColonAndFileName: RawUnexpectedNodesSyntax? = nil, - fileName: RawStringLiteralExprSyntax, + fileName: RawSimpleStringLiteralExprSyntax, _ unexpectedBetweenFileNameAndComma: RawUnexpectedNodesSyntax? = nil, comma: RawTokenSyntax, _ unexpectedBetweenCommaAndLineLabel: RawUnexpectedNodesSyntax? = nil, @@ -16612,8 +16612,8 @@ public struct RawPoundSourceLocationArgumentsSyntax: RawSyntaxNodeProtocol { layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:)) } - public var fileName: RawStringLiteralExprSyntax { - layoutView.children[5].map(RawStringLiteralExprSyntax.init(raw:))! + public var fileName: RawSimpleStringLiteralExprSyntax { + layoutView.children[5].map(RawSimpleStringLiteralExprSyntax.init(raw:))! } public var unexpectedBetweenFileNameAndComma: RawUnexpectedNodesSyntax? { @@ -18306,6 +18306,138 @@ public struct RawSequenceExprSyntax: RawExprSyntaxNodeProtocol { } } +@_spi(RawSyntax) +public struct RawSimpleStringLiteralExprSyntax: RawExprSyntaxNodeProtocol { + @_spi(RawSyntax) + public var layoutView: RawSyntaxLayoutView { + return raw.layoutView! + } + + public static func isKindOf(_ raw: RawSyntax) -> Bool { + return raw.kind == .simpleStringLiteralExpr + } + + public var raw: RawSyntax + + init(raw: RawSyntax) { + precondition(Self.isKindOf(raw)) + self.raw = raw + } + + private init(unchecked raw: RawSyntax) { + self.raw = raw + } + + public init?(_ other: some RawSyntaxNodeProtocol) { + guard Self.isKindOf(other.raw) else { + return nil + } + self.init(unchecked: other.raw) + } + + public init( + _ unexpectedBeforeOpeningQuote: RawUnexpectedNodesSyntax? = nil, + openingQuote: RawTokenSyntax, + _ unexpectedBetweenOpeningQuoteAndSegments: RawUnexpectedNodesSyntax? = nil, + segments: RawSimpleStringLiteralSegmentListSyntax, + _ unexpectedBetweenSegmentsAndClosingQuote: RawUnexpectedNodesSyntax? = nil, + closingQuote: RawTokenSyntax, + _ unexpectedAfterClosingQuote: RawUnexpectedNodesSyntax? = nil, + arena: __shared SyntaxArena + ) { + let raw = RawSyntax.makeLayout( + kind: .simpleStringLiteralExpr, uninitializedCount: 7, arena: arena) { layout in + layout.initialize(repeating: nil) + layout[0] = unexpectedBeforeOpeningQuote?.raw + layout[1] = openingQuote.raw + layout[2] = unexpectedBetweenOpeningQuoteAndSegments?.raw + layout[3] = segments.raw + layout[4] = unexpectedBetweenSegmentsAndClosingQuote?.raw + layout[5] = closingQuote.raw + layout[6] = unexpectedAfterClosingQuote?.raw + } + self.init(unchecked: raw) + } + + public var unexpectedBeforeOpeningQuote: RawUnexpectedNodesSyntax? { + layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var openingQuote: RawTokenSyntax { + layoutView.children[1].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedBetweenOpeningQuoteAndSegments: RawUnexpectedNodesSyntax? { + layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var segments: RawSimpleStringLiteralSegmentListSyntax { + layoutView.children[3].map(RawSimpleStringLiteralSegmentListSyntax.init(raw:))! + } + + public var unexpectedBetweenSegmentsAndClosingQuote: RawUnexpectedNodesSyntax? { + layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:)) + } + + public var closingQuote: RawTokenSyntax { + layoutView.children[5].map(RawTokenSyntax.init(raw:))! + } + + public var unexpectedAfterClosingQuote: RawUnexpectedNodesSyntax? { + layoutView.children[6].map(RawUnexpectedNodesSyntax.init(raw:)) + } +} + +@_spi(RawSyntax) +public struct RawSimpleStringLiteralSegmentListSyntax: RawSyntaxNodeProtocol { + @_spi(RawSyntax) + public var layoutView: RawSyntaxLayoutView { + return raw.layoutView! + } + + public static func isKindOf(_ raw: RawSyntax) -> Bool { + return raw.kind == .simpleStringLiteralSegmentList + } + + public var raw: RawSyntax + + init(raw: RawSyntax) { + precondition(Self.isKindOf(raw)) + self.raw = raw + } + + private init(unchecked raw: RawSyntax) { + self.raw = raw + } + + public init?(_ other: some RawSyntaxNodeProtocol) { + guard Self.isKindOf(other.raw) else { + return nil + } + self.init(unchecked: other.raw) + } + + public init(elements: [RawStringSegmentSyntax], arena: __shared SyntaxArena) { + let raw = RawSyntax.makeLayout( + kind: .simpleStringLiteralSegmentList, uninitializedCount: elements.count, arena: arena) { layout in + guard var ptr = layout.baseAddress else { + return + } + for elem in elements { + ptr.initialize(to: elem.raw) + ptr += 1 + } + } + self.init(unchecked: raw) + } + + public var elements: [RawStringSegmentSyntax] { + layoutView.children.map { + RawStringSegmentSyntax(raw: $0!) + } + } +} + @_spi(RawSyntax) public struct RawSomeOrAnyTypeSyntax: RawTypeSyntaxNodeProtocol { @_spi(RawSyntax) diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift index d017a2a5822..a3b14137bfd 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift @@ -2044,7 +2044,7 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.colon)])) assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 5, verify(layout[5], as: RawStringLiteralExprSyntax.self)) + assertNoError(kind, 5, verify(layout[5], as: RawSimpleStringLiteralExprSyntax.self)) assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 7, verify(layout[7], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.comma)])) assertNoError(kind, 8, verify(layout[8], as: RawUnexpectedNodesSyntax?.self)) @@ -2234,6 +2234,19 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 1, verify(layout[1], as: RawExprListSyntax.self)) assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) + case .simpleStringLiteralExpr: + assert(layout.count == 7) + assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.stringQuote), .tokenKind(.multilineStringQuote)])) + assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 3, verify(layout[3], as: RawSimpleStringLiteralSegmentListSyntax.self)) + assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.stringQuote), .tokenKind(.multilineStringQuote)])) + assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) + case .simpleStringLiteralSegmentList: + for (index, element) in layout.enumerated() { + assertNoError(kind, index, verify(element, as: RawStringSegmentSyntax.self)) + } case .someOrAnyType: assert(layout.count == 5) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxExprNodes.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxExprNodes.swift index 8aca93c9231..63e04d53f5a 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxExprNodes.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxExprNodes.swift @@ -5656,6 +5656,193 @@ public struct SequenceExprSyntax: ExprSyntaxProtocol, SyntaxHashable { } } +// MARK: - SimpleStringLiteralExprSyntax + +/// A simple string that can’t contain string interpolation and cannot have raw string delimiters. +/// +/// ### Children +/// +/// - `openingQuote`: (`'"'` | `'"""'`) +/// - `segments`: ``SimpleStringLiteralSegmentListSyntax`` +/// - `closingQuote`: (`'"'` | `'"""'`) +/// +/// ### Contained in +/// +/// - ``AvailabilityLabeledArgumentSyntax``.``AvailabilityLabeledArgumentSyntax/value`` +/// - ``PoundSourceLocationArgumentsSyntax``.``PoundSourceLocationArgumentsSyntax/fileName`` +public struct SimpleStringLiteralExprSyntax: ExprSyntaxProtocol, SyntaxHashable { + public let _syntaxNode: Syntax + + public init?(_ node: some SyntaxProtocol) { + guard node.raw.kind == .simpleStringLiteralExpr else { + return nil + } + self._syntaxNode = node._syntaxNode + } + + /// Creates a ``SimpleStringLiteralExprSyntax`` node from the given ``SyntaxData``. This assumes + /// that the `SyntaxData` is of the correct kind. If it is not, the behaviour + /// is undefined. + internal init(_ data: SyntaxData) { + precondition(data.raw.kind == .simpleStringLiteralExpr) + self._syntaxNode = Syntax(data) + } + + /// - Parameters: + /// - leadingTrivia: Trivia to be prepended to the leading trivia of the node’s first token. If the node is empty, there is no token to attach the trivia to and the parameter is ignored. + /// - openingQuote: Open quote for the string literal + /// - segments: String content + /// - closingQuote: Close quote for the string literal + /// - trailingTrivia: Trivia to be appended to the trailing trivia of the node’s last token. If the node is empty, there is no token to attach the trivia to and the parameter is ignored. + public init( + leadingTrivia: Trivia? = nil, + _ unexpectedBeforeOpeningQuote: UnexpectedNodesSyntax? = nil, + openingQuote: TokenSyntax, + _ unexpectedBetweenOpeningQuoteAndSegments: UnexpectedNodesSyntax? = nil, + segments: SimpleStringLiteralSegmentListSyntax, + _ unexpectedBetweenSegmentsAndClosingQuote: UnexpectedNodesSyntax? = nil, + closingQuote: TokenSyntax, + _ unexpectedAfterClosingQuote: 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(), ( + unexpectedBeforeOpeningQuote, + openingQuote, + unexpectedBetweenOpeningQuoteAndSegments, + segments, + unexpectedBetweenSegmentsAndClosingQuote, + closingQuote, + unexpectedAfterClosingQuote + ))) { (arena, _) in + let layout: [RawSyntax?] = [ + unexpectedBeforeOpeningQuote?.raw, + openingQuote.raw, + unexpectedBetweenOpeningQuoteAndSegments?.raw, + segments.raw, + unexpectedBetweenSegmentsAndClosingQuote?.raw, + closingQuote.raw, + unexpectedAfterClosingQuote?.raw + ] + let raw = RawSyntax.makeLayout( + kind: SyntaxKind.simpleStringLiteralExpr, + from: layout, + arena: arena, + leadingTrivia: leadingTrivia, + trailingTrivia: trailingTrivia + + ) + return SyntaxData.forRoot(raw, rawNodeArena: arena) + } + self.init(data) + } + + public var unexpectedBeforeOpeningQuote: UnexpectedNodesSyntax? { + get { + return data.child(at: 0, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = SimpleStringLiteralExprSyntax(data.replacingChild(at: 0, with: value?.data, arena: SyntaxArena())) + } + } + + /// Open quote for the string literal + public var openingQuote: TokenSyntax { + get { + return TokenSyntax(data.child(at: 1, parent: Syntax(self))!) + } + set(value) { + self = SimpleStringLiteralExprSyntax(data.replacingChild(at: 1, with: value.data, arena: SyntaxArena())) + } + } + + public var unexpectedBetweenOpeningQuoteAndSegments: UnexpectedNodesSyntax? { + get { + return data.child(at: 2, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = SimpleStringLiteralExprSyntax(data.replacingChild(at: 2, with: value?.data, arena: SyntaxArena())) + } + } + + /// String content + public var segments: SimpleStringLiteralSegmentListSyntax { + get { + return SimpleStringLiteralSegmentListSyntax(data.child(at: 3, parent: Syntax(self))!) + } + set(value) { + self = SimpleStringLiteralExprSyntax(data.replacingChild(at: 3, with: value.data, arena: SyntaxArena())) + } + } + + /// Adds the provided `element` to the node's `segments` + /// collection. + /// - param element: The new `Segment` to add to the node's + /// `segments` collection. + /// - returns: A copy of the receiver with the provided `Segment` + /// appended to its `segments` collection. + @available(*, deprecated, message: "Use node.segments.append(newElement) instead") + public func addSegment(_ element: StringSegmentSyntax) -> SimpleStringLiteralExprSyntax { + 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.simpleStringLiteralSegmentList, + from: [element.raw], arena: arena) + } + let newData = data.replacingChild( + at: 3, + with: collection, + rawNodeArena: arena, + allocationArena: arena + ) + return SimpleStringLiteralExprSyntax(newData) + } + + public var unexpectedBetweenSegmentsAndClosingQuote: UnexpectedNodesSyntax? { + get { + return data.child(at: 4, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = SimpleStringLiteralExprSyntax(data.replacingChild(at: 4, with: value?.data, arena: SyntaxArena())) + } + } + + /// Close quote for the string literal + public var closingQuote: TokenSyntax { + get { + return TokenSyntax(data.child(at: 5, parent: Syntax(self))!) + } + set(value) { + self = SimpleStringLiteralExprSyntax(data.replacingChild(at: 5, with: value.data, arena: SyntaxArena())) + } + } + + public var unexpectedAfterClosingQuote: UnexpectedNodesSyntax? { + get { + return data.child(at: 6, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + } + set(value) { + self = SimpleStringLiteralExprSyntax(data.replacingChild(at: 6, with: value?.data, arena: SyntaxArena())) + } + } + + public static var structure: SyntaxNodeStructure { + return .layout([ + \Self.unexpectedBeforeOpeningQuote, + \Self.openingQuote, + \Self.unexpectedBetweenOpeningQuoteAndSegments, + \Self.segments, + \Self.unexpectedBetweenSegmentsAndClosingQuote, + \Self.closingQuote, + \Self.unexpectedAfterClosingQuote + ]) + } +} + // MARK: - StringLiteralExprSyntax /// ### Children @@ -5669,13 +5856,11 @@ public struct SequenceExprSyntax: ExprSyntaxProtocol, SyntaxHashable { /// ### Contained in /// /// - ``AttributeSyntax``.``AttributeSyntax/arguments`` -/// - ``AvailabilityLabeledArgumentSyntax``.``AvailabilityLabeledArgumentSyntax/value`` /// - ``ConventionAttributeArgumentsSyntax``.``ConventionAttributeArgumentsSyntax/cTypeString`` /// - ``DocumentationAttributeArgumentSyntax``.``DocumentationAttributeArgumentSyntax/value`` /// - ``ExposeAttributeArgumentsSyntax``.``ExposeAttributeArgumentsSyntax/cxxName`` /// - ``OpaqueReturnTypeOfAttributeArgumentsSyntax``.``OpaqueReturnTypeOfAttributeArgumentsSyntax/mangledName`` /// - ``OriginallyDefinedInAttributeArgumentsSyntax``.``OriginallyDefinedInAttributeArgumentsSyntax/moduleName`` -/// - ``PoundSourceLocationArgumentsSyntax``.``PoundSourceLocationArgumentsSyntax/fileName`` /// - ``UnavailableFromAsyncAttributeArgumentsSyntax``.``UnavailableFromAsyncAttributeArgumentsSyntax/message`` /// - ``UnderscorePrivateAttributeArgumentsSyntax``.``UnderscorePrivateAttributeArgumentsSyntax/filename`` public struct StringLiteralExprSyntax: ExprSyntaxProtocol, SyntaxHashable { diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodes.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodes.swift index b16604b987f..665fee1eb49 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodes.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodes.swift @@ -1495,14 +1495,14 @@ public struct AvailabilityConditionSyntax: SyntaxProtocol, SyntaxHashable { /// /// - `label`: (`'message'` | `'renamed'` | `'introduced'` | `'obsoleted'` | `'deprecated'`) /// - `colon`: `':'` -/// - `value`: (``StringLiteralExprSyntax`` | ``VersionTupleSyntax``) +/// - `value`: (``SimpleStringLiteralExprSyntax`` | ``VersionTupleSyntax``) /// /// ### Contained in /// /// - ``AvailabilityArgumentSyntax``.``AvailabilityArgumentSyntax/argument`` public struct AvailabilityLabeledArgumentSyntax: SyntaxProtocol, SyntaxHashable { public enum Value: SyntaxChildChoices, SyntaxHashable { - case `string`(StringLiteralExprSyntax) + case `string`(SimpleStringLiteralExprSyntax) case `version`(VersionTupleSyntax) public var _syntaxNode: Syntax { @@ -1518,7 +1518,7 @@ public struct AvailabilityLabeledArgumentSyntax: SyntaxProtocol, SyntaxHashable self.init(Syntax(data))! } - public init(_ node: StringLiteralExprSyntax) { + public init(_ node: SimpleStringLiteralExprSyntax) { self = .string(node) } @@ -1527,7 +1527,7 @@ public struct AvailabilityLabeledArgumentSyntax: SyntaxProtocol, SyntaxHashable } public init?(_ node: some SyntaxProtocol) { - if let node = node.as(StringLiteralExprSyntax.self) { + if let node = node.as(SimpleStringLiteralExprSyntax.self) { self = .string(node) return } @@ -1539,7 +1539,7 @@ public struct AvailabilityLabeledArgumentSyntax: SyntaxProtocol, SyntaxHashable } public static var structure: SyntaxNodeStructure { - return .choices([.node(StringLiteralExprSyntax.self), .node(VersionTupleSyntax.self)]) + return .choices([.node(SimpleStringLiteralExprSyntax.self), .node(VersionTupleSyntax.self)]) } } @@ -14615,7 +14615,7 @@ public struct PlatformVersionSyntax: SyntaxProtocol, SyntaxHashable { /// /// - `fileLabel`: `'file'` /// - `fileColon`: `':'` -/// - `fileName`: ``StringLiteralExprSyntax`` +/// - `fileName`: ``SimpleStringLiteralExprSyntax`` /// - `comma`: `','` /// - `lineLabel`: `'line'` /// - `lineColon`: `':'` @@ -14652,7 +14652,7 @@ public struct PoundSourceLocationArgumentsSyntax: SyntaxProtocol, SyntaxHashable _ unexpectedBetweenFileLabelAndFileColon: UnexpectedNodesSyntax? = nil, fileColon: TokenSyntax = .colonToken(), _ unexpectedBetweenFileColonAndFileName: UnexpectedNodesSyntax? = nil, - fileName: StringLiteralExprSyntax, + fileName: SimpleStringLiteralExprSyntax, _ unexpectedBetweenFileNameAndComma: UnexpectedNodesSyntax? = nil, comma: TokenSyntax = .commaToken(), _ unexpectedBetweenCommaAndLineLabel: UnexpectedNodesSyntax? = nil, @@ -14759,9 +14759,9 @@ public struct PoundSourceLocationArgumentsSyntax: SyntaxProtocol, SyntaxHashable } } - public var fileName: StringLiteralExprSyntax { + public var fileName: SimpleStringLiteralExprSyntax { get { - return StringLiteralExprSyntax(data.child(at: 5, parent: Syntax(self))!) + return SimpleStringLiteralExprSyntax(data.child(at: 5, parent: Syntax(self))!) } set(value) { self = PoundSourceLocationArgumentsSyntax(data.replacingChild(at: 5, with: value.data, arena: SyntaxArena())) @@ -16795,6 +16795,7 @@ public struct SpecializeTargetFunctionArgumentSyntax: SyntaxProtocol, SyntaxHash /// /// ### Contained in /// +/// - ``SimpleStringLiteralSegmentListSyntax`` /// - ``StringLiteralSegmentListSyntax`` public struct StringSegmentSyntax: SyntaxProtocol, SyntaxHashable { public let _syntaxNode: Syntax diff --git a/Sources/SwiftSyntaxBuilder/generated/BuildableCollectionNodes.swift b/Sources/SwiftSyntaxBuilder/generated/BuildableCollectionNodes.swift index e478de6e736..e419047fe38 100644 --- a/Sources/SwiftSyntaxBuilder/generated/BuildableCollectionNodes.swift +++ b/Sources/SwiftSyntaxBuilder/generated/BuildableCollectionNodes.swift @@ -254,6 +254,12 @@ extension PrimaryAssociatedTypeListSyntax: ExpressibleByArrayLiteral { } } +extension SimpleStringLiteralSegmentListSyntax: ExpressibleByArrayLiteral { + public init(arrayLiteral elements: Element...) { + self.init(elements) + } +} + extension SpecializeAttributeArgumentListSyntax: ExpressibleByArrayLiteral { public init(arrayLiteral elements: Element...) { self.init(elements) diff --git a/Sources/SwiftSyntaxBuilder/generated/ResultBuilders.swift b/Sources/SwiftSyntaxBuilder/generated/ResultBuilders.swift index ecc0799df7a..dfb706efbea 100644 --- a/Sources/SwiftSyntaxBuilder/generated/ResultBuilders.swift +++ b/Sources/SwiftSyntaxBuilder/generated/ResultBuilders.swift @@ -3425,6 +3425,91 @@ public extension PrimaryAssociatedTypeListSyntax { } } +@resultBuilder +public struct SimpleStringLiteralSegmentListBuilder { + /// The type of individual statement expressions in the transformed function, + /// which defaults to Component if buildExpression() is not provided. + public typealias Expression = StringSegmentSyntax + + /// The type of a partial result, which will be carried through all of the + /// build methods. + public typealias Component = [Expression] + + /// The type of the final returned result, which defaults to Component if + /// buildFinalResult() is not provided. + public typealias FinalResult = SimpleStringLiteralSegmentListSyntax + + /// Required by every result builder to build combined results from + /// statement blocks. + public static func buildBlock(_ components: Self.Component...) -> Self.Component { + return components.flatMap { + $0 + } + } + + /// If declared, provides contextual type information for statement + /// expressions to translate them into partial results. + public static func buildExpression(_ expression: Self.Expression) -> Self.Component { + return [expression] + } + + /// Add all the elements of `expression` to this result builder, effectively flattening them. + /// + /// - Note: This overload is disfavored to resolve an ambiguity when both the final result and + /// the elements are expressible by string interpolation. In that case we favor creating a + /// single element from the string literal. + @_disfavoredOverload + public static func buildExpression(_ expression: Self.FinalResult) -> Self.Component { + return expression.map { + $0 + } + } + + /// Enables support for `if` statements that do not have an `else`. + public static func buildOptional(_ component: Self.Component?) -> Self.Component { + return component ?? [] + } + + /// With buildEither(second:), enables support for 'if-else' and 'switch' + /// statements by folding conditional results into a single result. + public static func buildEither(first component: Self.Component) -> Self.Component { + return component + } + + /// With buildEither(first:), enables support for 'if-else' and 'switch' + /// statements by folding conditional results into a single result. + public static func buildEither(second component: Self.Component) -> Self.Component { + return component + } + + /// Enables support for 'for..in' loops by combining the + /// results of all iterations into a single result. + public static func buildArray(_ components: [Self.Component]) -> Self.Component { + return components.flatMap { + $0 + } + } + + /// If declared, this will be called on the partial result of an 'if' + /// #available' block to allow the result builder to erase type + /// information. + public static func buildLimitedAvailability(_ component: Self.Component) -> Self.Component { + return component + } + + /// If declared, this will be called on the partial result from the outermost + /// block statement to produce the final returned result. + public static func buildFinalResult(_ component: Component) -> FinalResult { + return .init(component) + } +} + +public extension SimpleStringLiteralSegmentListSyntax { + init(@SimpleStringLiteralSegmentListBuilder itemsBuilder: () throws -> SimpleStringLiteralSegmentListSyntax) rethrows { + self = try itemsBuilder() + } +} + @resultBuilder public struct SpecializeAttributeArgumentListBuilder { /// The type of individual statement expressions in the transformed function, diff --git a/Tests/SwiftParserTest/Assertions.swift b/Tests/SwiftParserTest/Assertions.swift index 7b2daeeb873..95e5f1f3ddd 100644 --- a/Tests/SwiftParserTest/Assertions.swift +++ b/Tests/SwiftParserTest/Assertions.swift @@ -732,7 +732,7 @@ class TriviaRemover: SyntaxRewriter { var ancestor = Syntax(token) while let parent = ancestor.parent { ancestor = parent - if ancestor.is(StringLiteralExprSyntax.self) || ancestor.is(RegexLiteralExprSyntax.self) { + if ancestor.is(StringLiteralExprSyntax.self) || ancestor.is(RegexLiteralExprSyntax.self) || ancestor.is(SimpleStringLiteralExprSyntax.self) { // Don't mess with indentation inside string or regex literals. // BasicFormat doesn't know where to re-apply newlines and how much to indent the string literal contents. return token diff --git a/Tests/SwiftParserTest/translated/DiagnoseAvailabilityTests.swift b/Tests/SwiftParserTest/translated/DiagnoseAvailabilityTests.swift index 687171a2c87..2d8f20d2828 100644 --- a/Tests/SwiftParserTest/translated/DiagnoseAvailabilityTests.swift +++ b/Tests/SwiftParserTest/translated/DiagnoseAvailabilityTests.swift @@ -78,16 +78,9 @@ final class DiagnoseAvailabilityTests: XCTestCase { ) } - func testDiagnoseAvailability8() { - assertParse( - """ - // https://github.com/apple/swift/issues/51114 - // Missing/wrong warning message for '*' or 'swift' platform. - """ - ) - } - func testDiagnoseAvailability9() { + // https://github.com/apple/swift/issues/51114 + // Missing/wrong warning message for '*' or 'swift' platform. assertParse( """ @available(*, deprecated: 4.2) @@ -159,14 +152,26 @@ final class DiagnoseAvailabilityTests: XCTestCase { ) } - func testDiagnoseAvailability17() { + func testDiagnoseAvailability17a() { + assertParse( + #""" + @available(*, unavailable, message: "1️⃣\("message")") + func interpolatedMessage() {} + """#, + diagnostics: [ + DiagnosticSpec(message: "argument cannot be an interpolated string literal") + ] + ) + } + + func testDiagnoseAvailability17b() { assertParse( #""" - @available(*, unavailable, message: "\("message")") + @available(*, unavailable, message: "1️⃣\(someCall())") func interpolatedMessage() {} """#, diagnostics: [ - // TODO: Old parser expected error on line 1: 'message' cannot be an interpolated string literal + DiagnosticSpec(message: "argument cannot be an interpolated string literal") ] ) } @@ -178,7 +183,6 @@ final class DiagnoseAvailabilityTests: XCTestCase { foobar message. """) func multilineMessage() {} - multilineMessage() """# ) } @@ -196,27 +200,42 @@ final class DiagnoseAvailabilityTests: XCTestCase { func testDiagnoseAvailability20() { assertParse( ##""" - @available(*, unavailable, message: #""" + @available(*, unavailable, message: 1️⃣#""" foobar message. """#) func extendedEscapedMultilineMessage() {} """##, diagnostics: [ - // TODO: Old parser expected error on line 1: 'message' cannot be an extended escaping string literal - ] + DiagnosticSpec( + message: "argument cannot be an extended escaping string literal", + fixIts: ["remove '#' and '#'"] + ) + ], + fixedSource: ##""" + @available(*, unavailable, message: """ + foobar message. + """) + func extendedEscapedMultilineMessage() {} + """## ) } func testDiagnoseAvailability21() { assertParse( ##""" - @available(*, unavailable, renamed: #"available()"#) + @available(*, unavailable, renamed: 1️⃣#"available()"#) func extendedEscapedRenamed() {} """##, diagnostics: [ - // TODO: Old parser expected error on line 1: 'renamed' cannot be an extended escaping string literal - ] + DiagnosticSpec( + message: "argument cannot be an extended escaping string literal", + fixIts: ["remove '#' and '#'"] + ) + ], + fixedSource: #""" + @available(*, unavailable, renamed: "available()") + func extendedEscapedRenamed() {} + """# ) } - } From 4226e7a58773d92b0f90ed30e1ebd5538a26eded Mon Sep 17 00:00:00 2001 From: Kim de Vos Date: Sat, 5 Aug 2023 00:00:23 +0200 Subject: [PATCH 2/2] Simplify TriviaRemover --- Tests/SwiftParserTest/Assertions.swift | 32 +++++++++++++++++--------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/Tests/SwiftParserTest/Assertions.swift b/Tests/SwiftParserTest/Assertions.swift index 95e5f1f3ddd..6a3df1e8b62 100644 --- a/Tests/SwiftParserTest/Assertions.swift +++ b/Tests/SwiftParserTest/Assertions.swift @@ -727,20 +727,30 @@ func assertParse( } } +/// Removes trivia from all tokens that don’t occur inside multiline string +/// literals. +/// +/// We keep trivia inside multiline string literals because the indentation of +/// the closing quote of a multi-line string literals has impact on how much +/// leading trivia is stripped from the literal’s content. class TriviaRemover: SyntaxRewriter { - override func visit(_ token: TokenSyntax) -> TokenSyntax { - var ancestor = Syntax(token) - while let parent = ancestor.parent { - ancestor = parent - if ancestor.is(StringLiteralExprSyntax.self) || ancestor.is(RegexLiteralExprSyntax.self) || ancestor.is(SimpleStringLiteralExprSyntax.self) { - // Don't mess with indentation inside string or regex literals. - // BasicFormat doesn't know where to re-apply newlines and how much to indent the string literal contents. - return token - } + override func visit(_ node: StringLiteralExprSyntax) -> ExprSyntax { + if node.openingQuote.tokenKind == .multilineStringQuote { + return ExprSyntax(node) + } else { + return super.visit(node) } - if token.parent?.is(StringSegmentSyntax.self) ?? false { - return token + } + + override func visit(_ node: SimpleStringLiteralExprSyntax) -> ExprSyntax { + if node.openingQuote.tokenKind == .multilineStringQuote { + return ExprSyntax(node) + } else { + return super.visit(node) } + } + + override func visit(_ token: TokenSyntax) -> TokenSyntax { return token.with(\.leadingTrivia, []).with(\.trailingTrivia, []) } }