Skip to content

[6.0] Make swift-syntax build without warnings #2571

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,8 @@ public let EXPR_NODES: [Node] = [
),

Node(
kind: .canImportExpr,
kind: ._canImportExpr,
base: .expr,
deprecationMessage: "'canImport' directives are now represented as a `FunctionCallExpr`",
nameForDiagnostics: "'canImport' expression",
children: [
Child(
Expand All @@ -233,7 +232,7 @@ public let EXPR_NODES: [Node] = [
),
Child(
name: "versionInfo",
kind: .node(kind: .canImportVersionInfo),
kind: .node(kind: ._canImportVersionInfo),
isOptional: true
),
Child(
Expand All @@ -244,9 +243,8 @@ public let EXPR_NODES: [Node] = [
),

Node(
kind: .canImportVersionInfo,
kind: ._canImportVersionInfo,
base: .expr,
deprecationMessage: "'canImport' directives are now represented as a `FunctionCallExpr`",
nameForDiagnostics: nil,
children: [
Child(
Expand Down
13 changes: 11 additions & 2 deletions CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,17 @@ public struct KeywordSpec {
///
/// This is typically used to mark APIs as SPI when the keyword is part of an experimental language feature.
public var apiAttributes: AttributeListSyntax {
guard isExperimental else { return "" }
return AttributeListSyntax("@_spi(ExperimentalLanguageFeatures)").with(\.trailingTrivia, .newline)
let attrList = AttributeListSyntax {
if isExperimental {
let experimentalSPI: AttributeListSyntax = """
#if compiler(>=5.8)
@_spi(ExperimentalLanguageFeatures)
#endif
"""
experimentalSPI.with(\.trailingTrivia, .newline)
}
}
return attrList.with(\.trailingTrivia, attrList.isEmpty ? [] : .newline)
}

/// Initializes a new `KeywordSpec` instance.
Expand Down
18 changes: 6 additions & 12 deletions CodeGeneration/Sources/SyntaxSupport/Node.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ public class Node {
/// The kind of node’s supertype. This kind must have `isBase == true`
public let base: SyntaxNodeKind

/// If this syntax node has been deprecated, a message that describes the deprecation.
public let deprecationMessage: String?

/// The experimental feature the node is part of, or `nil` if this isn't
/// for an experimental feature.
public let experimentalFeature: ExperimentalFeature?
Expand Down Expand Up @@ -109,9 +106,6 @@ public class Node {
"""
experimentalSPI.with(\.trailingTrivia, .newline)
}
if let deprecationMessage {
"@available(*, deprecated, message: \(literal: deprecationMessage))"
}
if forRaw {
"@_spi(RawSyntax)"
}
Expand All @@ -133,7 +127,6 @@ public class Node {
init(
kind: SyntaxNodeKind,
base: SyntaxNodeKind,
deprecationMessage: String? = nil,
experimentalFeature: ExperimentalFeature? = nil,
nameForDiagnostics: String?,
documentation: String? = nil,
Expand All @@ -146,7 +139,6 @@ public class Node {

self.kind = kind
self.base = base
self.deprecationMessage = deprecationMessage
self.experimentalFeature = experimentalFeature
self.nameForDiagnostics = nameForDiagnostics
self.documentation = SwiftSyntax.Trivia.docCommentTrivia(from: documentation)
Expand Down Expand Up @@ -241,7 +233,11 @@ public class Node {
// This will repeat the syntax type before and after the dot, which is
// a little unfortunate, but it's the only way I found to get docc to
// generate a fully-qualified type + member.
return " - \($0.node.doccLink).``\($0.node.syntaxType)/\(childName)``"
if $0.node.isAvailableInDocc {
return " - \($0.node.doccLink).``\($0.node.syntaxType)/\(childName)``"
} else {
return " - \($0.node.doccLink).`\($0.node.syntaxType)/\(childName)`"
}
} else {
return " - \($0.node.doccLink)"
}
Expand All @@ -265,7 +261,7 @@ public class Node {

let list =
SYNTAX_NODES
.filter { $0.base == self.kind && !$0.isExperimental }
.filter { $0.base == self.kind && !$0.isExperimental && !$0.kind.isDeprecated }
.map { "- \($0.kind.doccLink)" }
.joined(separator: "\n")

Expand All @@ -288,7 +284,6 @@ public class Node {
init(
kind: SyntaxNodeKind,
base: SyntaxNodeKind,
deprecationMessage: String? = nil,
experimentalFeature: ExperimentalFeature? = nil,
nameForDiagnostics: String?,
documentation: String? = nil,
Expand All @@ -298,7 +293,6 @@ public class Node {
self.kind = kind
precondition(base == .syntaxCollection)
self.base = base
self.deprecationMessage = deprecationMessage
self.experimentalFeature = experimentalFeature
self.nameForDiagnostics = nameForDiagnostics
self.documentation = SwiftSyntax.Trivia.docCommentTrivia(from: documentation)
Expand Down
23 changes: 21 additions & 2 deletions CodeGeneration/Sources/SyntaxSupport/String+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,18 @@
//===----------------------------------------------------------------------===//

public extension StringProtocol {
var withFirstCharacterLowercased: String { prefix(1).lowercased() + dropFirst() }
var withFirstCharacterUppercased: String { prefix(1).uppercased() + dropFirst() }
var withFirstCharacterLowercased: String {
guard first?.isLetter ?? false else {
return String(first!) + dropFirst().withFirstCharacterLowercased
}
return prefix(1).lowercased() + dropFirst()
}
var withFirstCharacterUppercased: String {
guard first?.isLetter ?? false else {
return String(first!) + dropFirst().withFirstCharacterUppercased
}
return prefix(1).uppercased() + dropFirst()
}
var backtickedIfNeeded: String {
if Keyword.allCases.map(\.spec).contains(where: {
$0.name == self && ($0.isLexerClassified || $0.name == "Type" || $0.name == "Protocol")
Expand All @@ -23,3 +33,12 @@ public extension StringProtocol {
}
}
}

extension String {
public var droppingLeadingUnderscores: String {
if first == "_" {
return String(self.dropFirst())
}
return self
}
}
43 changes: 38 additions & 5 deletions CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import SwiftSyntaxBuilder
public enum SyntaxNodeKind: String, CaseIterable {
// Please keep this list sorted alphabetically

case _canImportExpr
case _canImportVersionInfo
case accessorBlock
case accessorDecl
case accessorDeclList
Expand Down Expand Up @@ -47,8 +49,6 @@ public enum SyntaxNodeKind: String, CaseIterable {
case booleanLiteralExpr
case borrowExpr
case breakStmt
case canImportExpr
case canImportVersionInfo
case catchClause
case catchClauseList
case catchItem
Expand Down Expand Up @@ -355,14 +355,25 @@ public enum SyntaxNodeKind: String, CaseIterable {
}
}

/// Whether the node is public API and not underscored/deprecated and can thus be referenced in docc links.
public var isAvailableInDocc: Bool {
if let node = SYNTAX_NODE_MAP[self], node.isExperimental {
return false
} else if isDeprecated {
return false
} else {
return true
}
}

/// If this node is non-experimental a docc link wrapped in two backticks.
///
/// For experimental nodes, the node's type name in code font.
public var doccLink: String {
if let node = SYNTAX_NODE_MAP[self], node.isExperimental {
return "`\(syntaxType)`"
} else {
if isAvailableInDocc {
return "``\(syntaxType)``"
} else {
return "`\(syntaxType)`"
}
}

Expand Down Expand Up @@ -405,6 +416,8 @@ public enum SyntaxNodeKind: String, CaseIterable {
/// deprecated.
public var deprecatedRawValue: String? {
switch self {
case ._canImportExpr: return "canImportExpr"
case ._canImportVersionInfo: return "canImportVersionInfo"
case .accessorDeclList: return "accessorList"
case .accessorParameters: return "accessorParameter"
case .associatedTypeDecl: return "associatedtypeDecl"
Expand Down Expand Up @@ -475,4 +488,24 @@ public enum SyntaxNodeKind: String, CaseIterable {
default: return nil
}
}

public var deprecationMessage: String? {
switch self {
case ._canImportExpr: return "'canImport' directives are now represented as a `FunctionCallExpr`"
case ._canImportVersionInfo: return "'canImport' directives are now represented as a `FunctionCallExpr`"
default: return nil
}
}

public var isDeprecated: Bool {
return rawValue.first == "_"
}

var deprecationAttribute: AttributeSyntax? {
if let deprecationMessage = deprecationMessage {
AttributeSyntax("@available(*, deprecated, message: \(literal: deprecationMessage)")
} else {
AttributeSyntax(#"@available(*, deprecated, renamed: "\#(syntaxType)")"#)
}
}
}
14 changes: 11 additions & 3 deletions CodeGeneration/Sources/SyntaxSupport/SyntaxNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,24 @@
//
//===----------------------------------------------------------------------===//

public let SYNTAX_NODES: [Node] =
(COMMON_NODES
private let unsortedSyntaxNodes: [Node] =
COMMON_NODES
+ EXPR_NODES
+ DECL_NODES
+ ATTRIBUTE_NODES
+ STMT_NODES
+ GENERIC_NODES
+ TYPE_NODES
+ PATTERN_NODES
+ AVAILABILITY_NODES).sorted { $0.kind.syntaxType.description < $1.kind.syntaxType.description }
+ AVAILABILITY_NODES

public let SYNTAX_NODES: [Node] =
unsortedSyntaxNodes
.sorted { (lhs: Node, rhs: Node) -> Bool in
let lhsSortKey = lhs.kind.syntaxType.description.droppingLeadingUnderscores
let rhsSortKey = rhs.kind.syntaxType.description.droppingLeadingUnderscores
return lhsSortKey < rhsSortKey
}

/// A lookup table of nodes indexed by their kind.
public let SYNTAX_NODE_MAP: [SyntaxNodeKind: Node] = Dictionary(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ fileprivate extension Node {
func rawSyntaxNodesFile(nodesStartingWith: [Character]) -> SourceFileSyntax {
return SourceFileSyntax(leadingTrivia: copyrightHeader) {
for node in SYNTAX_NODES
where node.kind.isBase && nodesStartingWith.contains(node.kind.syntaxType.description.first!) {
where node.kind.isBase
&& nodesStartingWith.contains(node.kind.syntaxType.description.droppingLeadingUnderscores.first!)
&& !node.kind.isDeprecated
{
DeclSyntax(
"""
\(node.apiAttributes(forRaw: true))\
Expand All @@ -51,7 +54,8 @@ func rawSyntaxNodesFile(nodesStartingWith: [Character]) -> SourceFileSyntax {
)
}

for node in SYNTAX_NODES where nodesStartingWith.contains(node.kind.syntaxType.description.first!) {
for node in SYNTAX_NODES
where nodesStartingWith.contains(node.kind.syntaxType.description.droppingLeadingUnderscores.first!) {
try! StructDeclSyntax(
"""
\(node.apiAttributes(forRaw: true))\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,19 @@ import SwiftSyntaxBuilder
import SyntaxSupport
import Utils

func deprecationAttribute(for syntaxKind: SyntaxNodeKind) -> AttributeSyntax {
if let deprecationMessage = syntaxKind.deprecationMessage {
return AttributeSyntax("@available(*, deprecated, message: \(literal: deprecationMessage))")
}
return AttributeSyntax(#"@available(*, deprecated, renamed: "\#(syntaxKind.syntaxType)")"#)
}

let renamedSyntaxNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
for syntaxKind in SyntaxNodeKind.allCases.sorted(by: { $0.deprecatedRawValue ?? "" < $1.deprecatedRawValue ?? "" }) {
if let deprecatedName = syntaxKind.deprecatedRawValue {
DeclSyntax(
"""
@available(*, deprecated, renamed: "\(syntaxKind.syntaxType)")
\(deprecationAttribute(for: syntaxKind))
public typealias \(raw: deprecatedName.withFirstCharacterUppercased)Syntax = \(syntaxKind.syntaxType)
"""
)
Expand All @@ -33,6 +40,7 @@ let renamedSyntaxNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
if let deprecatedName = syntaxKind.deprecatedRawValue {
DeclSyntax(
"""
\(deprecationAttribute(for: syntaxKind))
static var \(raw: deprecatedName): Self {
return .\(syntaxKind.varOrCaseName)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ let nodesSections: String = {
let baseTypes = ["\(baseKind.syntaxType)", "\(baseKind.syntaxType)Protocol", "Missing\(baseKind.syntaxType)"]
let leafTypes =
SYNTAX_NODES
.filter({ $0.base == baseKind && !$0.kind.isMissing && !$0.isExperimental })
.filter({ $0.base == baseKind && !$0.kind.isMissing && !$0.isExperimental && !$0.kind.isDeprecated })
.map(\.kind.syntaxType.description)
addSection(heading: heading, types: baseTypes + leafTypes)
}
Expand All @@ -56,22 +56,24 @@ let nodesSections: String = {
}
return [node.kind.syntaxType.description]
+ node.elementChoices
.filter { SYNTAX_NODE_MAP[$0] != nil && !SYNTAX_NODE_MAP[$0]!.isExperimental }
.filter { SYNTAX_NODE_MAP[$0] != nil && !SYNTAX_NODE_MAP[$0]!.isExperimental && !$0.isDeprecated }
.map(\.syntaxType.description)
.filter { !handledSyntaxTypes.contains($0) }
})
)

addSection(
heading: "Attributes",
types: ATTRIBUTE_NODES.filter({ !$0.isExperimental }).map(\.kind.syntaxType.description).sorted()
types: ATTRIBUTE_NODES.filter({ !$0.isExperimental && !$0.kind.isDeprecated }).map(\.kind.syntaxType.description)
.sorted()
)

addSection(
heading: "Miscellaneous Syntax",
types: SYNTAX_NODES.filter({ !$0.isExperimental }).map(\.kind.syntaxType.description).filter({
!handledSyntaxTypes.contains($0)
})
types: SYNTAX_NODES.filter({ !$0.isExperimental && !$0.kind.isDeprecated }).map(\.kind.syntaxType.description)
.filter({
!handledSyntaxTypes.contains($0)
})
)

addSection(heading: "Traits", types: TRAITS.map { "\($0.protocolName)" })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import Utils
func syntaxNode(nodesStartingWith: [Character]) -> SourceFileSyntax {
SourceFileSyntax(leadingTrivia: copyrightHeader) {
for node in SYNTAX_NODES.compactMap(\.layoutNode)
where nodesStartingWith.contains(node.kind.syntaxType.description.first!) {
where nodesStartingWith.contains(node.kind.syntaxType.description.droppingLeadingUnderscores.first!) {
// We are actually handling this node now
try! StructDeclSyntax(
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class ValidateSyntaxNodes: XCTestCase {
failures,
expectedFailures: [
ValidationFailure(
node: .canImportVersionInfo,
node: ._canImportVersionInfo,
message: "has base kind 'ExprSyntax' but type name doesn’t have 'ExprSyntax' suffix"
),
ValidationFailure(
Expand Down Expand Up @@ -535,7 +535,7 @@ class ValidateSyntaxNodes: XCTestCase {
expectedFailures: [
ValidationFailure(node: .accessorParameters, message: "could conform to trait 'NamedDecl' but does not"),
ValidationFailure(node: .availabilityCondition, message: "could conform to trait 'Parenthesized' but does not"),
ValidationFailure(node: .canImportExpr, message: "could conform to trait 'Parenthesized' but does not"),
ValidationFailure(node: ._canImportExpr, message: "could conform to trait 'Parenthesized' but does not"),
ValidationFailure(
node: .differentiabilityArguments,
message: "could conform to trait 'Parenthesized' but does not"
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftBasicFormat/BasicFormat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ open class BasicFormat: SyntaxRewriter {
return true
case .ifConfigClauseList:
return true
case .memberDeclList:
case .memberBlockItemList:
return true
case .switchCaseList:
return true
Expand Down
Loading