File: SwiftAPIDigester.swift

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (152 lines) | stat: -rw-r--r-- 4,994 bytes parent folder | download
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import Foundation

/// A wrapper for the swift-api-digester tool.
struct SwiftAPIDigester {
    /// The path to `swift-api-digester` executable in the toolchain
    let executableURL: URL

    init(executableURL: URL) {
        self.executableURL = executableURL
    }

    struct Output: Decodable {
        let ABIRoot: SDKNode

        static func parse(_ bytes: Data) throws -> Output {
            let decoder = JSONDecoder()
            return try decoder.decode(Output.self, from: bytes)
        }
    }

    struct SDKNodeInherit<Parent: Decodable, Body: Decodable>: Decodable {
        let parent: Parent
        let body: Body

        init(from decoder: Decoder) throws {
            self.parent = try Parent(from: decoder)
            self.body = try Body(from: decoder)
        }
    }

    enum SDKNode: Decodable {
        case root(SDKNodeRoot)
        case decl(SDKNodeDecl)
        case typeDecl(SDKNodeDeclType)
        case typeNominal(SDKNodeTypeNominal)
        case unknown(SDKNodeBody)

        var body: SDKNodeBody {
            switch self {
            case .root(let node): return node.parent
            case .decl(let node): return node.parent
            case .typeDecl(let node): return node.parent.parent
            case .typeNominal(let node): return node.parent.parent
            case .unknown(let node): return node
            }
        }

        var decl: SDKNodeDecl? {
            switch self {
            case .root: return nil
            case .decl(let node): return node
            case .typeDecl(let node): return node.parent
            case .typeNominal: return nil
            case .unknown: return nil
            }
        }

        enum CodingKeys: CodingKey {
            case kind
        }

        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            switch try container.decode(String.self, forKey: .kind) {
            case "Root":
                self = try .root(SDKNodeRoot(from: decoder))
            case "TypeDecl":
                self = try .typeDecl(SDKNodeDeclType(from: decoder))
            case "TypeNominal":
                self = try .typeNominal(SDKNodeTypeNominal(from: decoder))
            case "Var", "Function":
                self = try .decl(SDKNodeDecl(from: decoder))
            default:
                self = try .unknown(SwiftAPIDigester.SDKNodeBody(from: decoder))
            }
        }
    }

    struct SDKNodeBody: Decodable {
        let kind: String
        let name: String
        let printedName: String
        let children: [SDKNode]?

        enum CodingKeys: CodingKey {
            case kind
            case name
            case printedName
            case children
        }
    }

    typealias SDKNodeRoot = SDKNodeInherit<SDKNodeBody, SDKNodeRootBody>
    struct SDKNodeRootBody: Codable {
        let json_format_version: Int
    }

    struct SDKNodeDeclBody: Codable {
        let declKind: String
        let usr: String
        let mangledName: String
        let moduleName: String
        let declAttributes: [String]?
        let spi_group_names: [String]?
        let `static`: Bool?
    }

    struct SDKNodeDeclTypeBody: Codable {}
    struct SDKNodeTypeBody: Codable {}
    struct SDKNodeTypeNominalBody: Codable {
        let usr: String?
    }

    typealias SDKNodeDecl = SDKNodeInherit<SDKNodeBody, SDKNodeDeclBody>
    typealias SDKNodeDeclType = SDKNodeInherit<SDKNodeDecl, SDKNodeDeclTypeBody>
    typealias SDKNodeType = SDKNodeInherit<SDKNodeBody, SDKNodeTypeBody>
    typealias SDKNodeTypeNominal = SDKNodeInherit<SDKNodeType, SDKNodeTypeNominalBody>

    @available(macOS 11, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
    func dumpSDK(moduleName: String, arguments: [String]) throws -> Output {
        #if os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
            fatalError("WITExtractor does not support platforms where Foundation.Process is unavailable")
        #else
            var args = [
                "-dump-sdk",
                "-module", moduleName,
                // Emit output to stdout
                "-o", "-",
            ]
            args += arguments
            let process = Process()
            process.executableURL = executableURL
            process.arguments = args
            let stdoutPipe = Pipe()
            process.standardOutput = stdoutPipe
            try process.run()
            guard let output = try stdoutPipe.fileHandleForReading.readToEnd() else {
                throw SwiftAPIDigesterError.unexpectedEmptyOutput
            }
            process.waitUntilExit()
            guard process.terminationStatus == 0 else {
                throw SwiftAPIDigesterError.nonZeroExitCode(process.terminationStatus, arguments: args)
            }
            return try Output.parse(output)
        #endif
    }
}

enum SwiftAPIDigesterError: Error {
    case unexpectedEmptyOutput
    case nonZeroExitCode(Int32, arguments: [String])
}