Skip to content

Commit

Permalink
Add symbolName property for some syntax nodes
Browse files Browse the repository at this point in the history
`FunctionDecl`, `InitializerDecl`, `SubscriptDecl`, `EnumCaseElement`, and `MacroDecl` gained a new computed property: `symbolName`

The `symbolName` property provides a string representation of the declaration's name along with its parameter labels. For example, a function `func greet(name: String)` will have the symbol name `greet(name:)`.
  • Loading branch information
Matejkob committed Apr 8, 2024
1 parent 62e240a commit 616978f
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 20 deletions.
5 changes: 5 additions & 0 deletions Release Notes/601.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## New APIs

- `FunctionDecl`, `InitializerDecl`, `SubscriptDecl`, `EnumCaseElement`, and `MacroDecl` gained a new computed property: `symbolName`
- Description: The `symbolName` property provides a string representation of the declaration's name along with its parameter labels. For example, a function `func greet(name: String)` will have the symbol name `greet(name:)`.
- Issue: https://github.com/apple/swift-syntax/issues/2488
- Pull Request: https://github.com/apple/swift-syntax/pull/2583

## API Behavior Changes

## Deprecations
Expand Down
20 changes: 0 additions & 20 deletions Release Notes/610.md

This file was deleted.

142 changes: 142 additions & 0 deletions Sources/SwiftSyntax/SymbolName.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

extension FunctionDeclSyntax {
/// The symbol name of the function declaration.
///
/// The symbol name is a string representation of the function name along with its parameter labels.
/// For example, a function `func greet(name: String)` will have the symbol name `greet(name:)`.
public var symbolName: String {
SwiftSyntax.symbolName(
fromBaseName: name.trimmedDescription,
andParameters: signature.parameterClause
)
}
}

extension InitializerDeclSyntax {
/// The symbol name of the initializer declaration.
///
/// The symbol name is a string representation of the initializer along with its parameter labels.
/// For example, an initializer `init(name: String)` will have the symbol name `init(name:)`.
public var symbolName: String {
SwiftSyntax.symbolName(
// FIXME: If the syntax tree is not generated by parser can this be other token than init?
fromBaseName: "init",
andParameters: signature.parameterClause
)
}
}

extension SubscriptDeclSyntax {
/// The symbol name of the subscript declaration.
///
/// The symbol name is a string representation of the subscript along with its parameter labels.
/// For example, a subscript `subscript(index: Int)` will have the symbol name `subscript(_:)`.
public var symbolName: String {
SwiftSyntax.symbolName(
fromBaseName: "subscript",
andParameters: parameterClause
)
}
}

extension EnumCaseElementSyntax {
/// The symbol name of the enum case element.
///
/// The symbol name is a string representation of the enum case name along with its associated value labels (if any).
/// For example, an enum case `case foo(bar: Int)` will have the symbol name `foo(bar:)`.
public var symbolName: String {
let caseName = name.text

guard let associatedValue = parameterClause else {
return caseName
}

let argumentNames = associatedValue.parameters
.map { parameter in
guard let firstName = parameter.firstName else {
return "_:"
}

return firstName.text + ":"
}
.joined()

return "\(caseName)(\(argumentNames))"
}
}

extension MacroDeclSyntax {
/// The symbol name of the macro declaration.
///
/// The symbol name is a string representation of the macro name along with its parameter labels.
/// For example, a macro `macro greet(name: String)` will have the symbol name `greet(name:)`.
public var symbolName: String {
SwiftSyntax.symbolName(
fromBaseName: name.trimmedDescription,
andParameters: signature.parameterClause
)
}
}

/// Generates the symbol name by combining the base name and parameter labels.
///
/// - Parameters:
/// - baseName: The base name of the symbol (e.g., function name, initializer, subscript).
/// - parameters: The function parameter clause containing the parameter labels.
/// - Returns: The symbol name with the base name and parameter labels combined.
private func symbolName(
fromBaseName baseName: String,
andParameters parameters: FunctionParameterClauseSyntax
) -> String {
let argumentNames = parameters.parameters
.map { parameter in
let argumentLabelText = parameter.argumentName?.text ?? "_"
return argumentLabelText + ":"
}
.joined()

return "\(baseName)(\(argumentNames))"
}

extension FunctionParameterSyntax {
/// The argument name (label) of the function parameter.
///
/// If the parameter has two names (e.g., `external internal: Int`), the first name is considered the argument label.
/// If the parameter has only one name and it's not a subscript parameter, it is considered the argument label.
fileprivate var argumentName: TokenSyntax? {
// If we have two names, the first one is the argument label
if secondName != nil {
return firstName.asIdentifierToken
}

// If we have only one name, it might be an argument label.
if let superParent = parent?.parent?.parent, superParent.is(SubscriptDeclSyntax.self) {
return nil
}

return firstName.asIdentifierToken
}
}

extension TokenSyntax {
/// Converts the token to an identifier token if it represents an identifier.
///
/// - Returns: The trimmed token if it is an identifier or dollar identifier, otherwise `nil`.
fileprivate var asIdentifierToken: TokenSyntax? {
switch tokenKind {
case .identifier, .dollarIdentifier: return self.trimmed
default: return nil
}
}
}

0 comments on commit 616978f

Please sign in to comment.