1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
/// Provides a stable and unique identity for ``Syntax`` nodes.
///
/// Note that two nodes might have the same contents even if their IDs are
/// different. For example two different ``FunctionDeclSyntax`` nodes
/// might have the exact same contents but if they occur at a different
/// location in the source file, they have different IDs.
///
/// Also note that the ID of a syntax node changes when it is anchored in a
/// different syntax tree. Modifying any node in the syntax tree a node is
/// contained in generates a copy of that tree and thus changes the IDs of all
/// nodes in the tree, not just the modified node's children.
public struct SyntaxIdentifier: Comparable, Hashable, Sendable {
/// Represents a unique value for a node within its own tree.
///
/// This is similar to ``SyntaxIdentifier`` but does not store the root ID of the tree.
/// It can thus be transferred across trees that are structurally equivalent, for example two copies of the same tree
/// that live in different processes.
public struct SyntaxIndexInTree: Hashable, Sendable {
/// When traversing the syntax tree using a depth-first traversal, the index at which the node will be visited.
let indexInTree: UInt32
init(indexInTree: UInt32) {
self.indexInTree = indexInTree
}
/// Converts the ``SyntaxIdentifier/SyntaxIndexInTree`` to an opaque value that can be serialized.
/// The opaque value can be restored to a ``SyntaxIdentifier/SyntaxIndexInTree`` using ``init(fromOpaque:)``.
///
/// - Note: The contents of the opaque value are not specified and clients should not rely on them.
public func toOpaque() -> UInt64 {
return UInt64(indexInTree)
}
/// Creates a ``SyntaxIdentifier/SyntaxIndexInTree`` from an opaque value obtained using ``toOpaque()``.
public init(fromOpaque opaque: UInt64) {
self.indexInTree = UInt32(opaque)
}
}
/// Unique value for the root node.
///
/// Multiple trees may have the same 'rootId' if their root RawSyntax is the
/// same instance. This guarantees that the trees with the same 'rootId' have
/// exact the same structure. But, two trees with exactly the same structure
/// might still have different 'rootId's.
let rootId: RawSyntax.ID
/// Unique value for a node within its own tree.
public let indexInTree: SyntaxIndexInTree
/// Forms a ``SyntaxIdentifier`` from an ``SyntaxIdentifier/SyntaxIndexInTree`` inside a ``Syntax`` node that
/// constitutes the tree's root.
///
/// Returns `nil` if `root` is not the root of a syntax tree or if `indexInTree` points to a node that is not within
/// the tree spanned up by `root`.
///
/// - Warning: ``SyntaxIdentifier/SyntaxIndexInTree`` is not stable with regard to insertion or deletions of nodes
/// into a syntax tree. There are only two scenarios where it is valid to share ``SyntaxIndexInTree`` between syntax
/// trees with different nodes:
/// (1) If two trees are guaranteed to be exactly the same eg. because they were parsed using the same version of
/// `SwiftParser` from the same source code.
/// (2) If a tree was mutated by only replacing tokens with other tokens. No nodes must have been inserted or
/// removed during the process, including tokens that are marked as ``SourcePresence/missing``.
public static func fromIndexInTree(
_ indexInTree: SyntaxIndexInTree,
relativeToRoot root: some SyntaxProtocol
) -> SyntaxIdentifier? {
guard !root.hasParent, Int(truncatingIfNeeded: indexInTree.indexInTree) < root.raw.totalNodes else {
return nil
}
return SyntaxIdentifier(rootId: root.raw.id, indexInTree: indexInTree)
}
/// A ``SyntaxIdentifier`` compares less than another ``SyntaxIdentifier`` if the node at that identifier occurs first
/// during a depth-first traversal of the tree. This implies that nodes with an earlier ``AbsolutePosition`` also
/// have a lower ``SyntaxIdentifier``.
public static func < (lhs: SyntaxIdentifier, rhs: SyntaxIdentifier) -> Bool {
guard lhs.rootId == rhs.rootId else {
// Nodes in different trees are not comparable.
return false
}
return lhs.indexInTree.indexInTree < rhs.indexInTree.indexInTree
}
}
|