Skip to content

Commit 5f953da

Browse files
committed
[Dependency scanning] Parse JSON output into Swift data structures.
1 parent d6484c8 commit 5f953da

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
//===--------------- ModuleDependencyGraph.swift --------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
import Foundation
13+
14+
enum ModuleDependencyId: Hashable {
15+
case swift(String)
16+
case clang(String)
17+
18+
var moduleName: String {
19+
switch self {
20+
case .swift(let name): return name
21+
case .clang(let name): return name
22+
}
23+
}
24+
}
25+
26+
extension ModuleDependencyId: Codable {
27+
enum CodingKeys: CodingKey {
28+
case swift
29+
case clang
30+
}
31+
32+
init(from decoder: Decoder) throws {
33+
let container = try decoder.container(keyedBy: CodingKeys.self)
34+
do {
35+
let moduleName = try container.decode(String.self, forKey: .swift)
36+
self = .swift(moduleName)
37+
} catch {
38+
let moduleName = try container.decode(String.self, forKey: .clang)
39+
self = .clang(moduleName)
40+
}
41+
}
42+
43+
func encode(to encoder: Encoder) throws {
44+
var container = encoder.container(keyedBy: CodingKeys.self)
45+
switch self {
46+
case .swift(let moduleName):
47+
try container.encode(moduleName, forKey: .swift)
48+
case .clang(let moduleName):
49+
try container.encode(moduleName, forKey: .clang)
50+
}
51+
}
52+
}
53+
54+
/// Bridging header
55+
struct BridgingHeader: Codable {
56+
var path: String
57+
var sourceFiles: [String]
58+
var moduleDependencies: [String]
59+
}
60+
61+
/// Details specific to Swift modules.
62+
struct SwiftModuleDetails: Codable {
63+
/// The module interface from which this module was built, if any.
64+
var moduleInterfacePath: String?
65+
66+
/// The bridging header, if any.
67+
var bridgingHeader: BridgingHeader?
68+
}
69+
70+
/// Details specific to Clang modules.
71+
struct ClangModuleDetails: Codable {
72+
/// The path to the module map used to build this module.
73+
var moduleMapPath: String
74+
}
75+
76+
struct ModuleDependencies: Codable {
77+
/// The path for the module.
78+
var modulePath: String
79+
80+
/// The source files used to build this module.
81+
var sourceFiles: [String] = []
82+
83+
/// The set of direct module dependencies of this module.
84+
var directDependencies: [ModuleDependencyId] = []
85+
86+
/// Specific details of a particular kind of module.
87+
var details: Details
88+
89+
/// Specific details of a particular kind of module.
90+
enum Details {
91+
/// Swift modules may be built from a module interface, and may have
92+
/// a bridging header.
93+
case swift(SwiftModuleDetails)
94+
95+
/// Clang modules are built from a module map file.
96+
case clang(ClangModuleDetails)
97+
}
98+
}
99+
100+
extension ModuleDependencies.Details: Codable {
101+
enum CodingKeys: CodingKey {
102+
case swift
103+
case clang
104+
}
105+
106+
init(from decoder: Decoder) throws {
107+
let container = try decoder.container(keyedBy: CodingKeys.self)
108+
do {
109+
let details = try container.decode(SwiftModuleDetails.self, forKey: .swift)
110+
self = .swift(details)
111+
} catch {
112+
let details = try container.decode(ClangModuleDetails.self, forKey: .clang)
113+
self = .clang(details)
114+
}
115+
}
116+
117+
func encode(to encoder: Encoder) throws {
118+
var container = encoder.container(keyedBy: CodingKeys.self)
119+
switch self {
120+
case .swift(let details):
121+
try container.encode(details, forKey: .swift)
122+
case .clang(let details):
123+
try container.encode(details, forKey: .clang)
124+
}
125+
}
126+
}
127+
128+
/// Describes the complete set of dependencies for a Swift module, including
129+
/// all of the Swift and C modules and source files it depends on.
130+
struct ModuleDependencyGraph: Codable {
131+
/// The name of the main module.
132+
var mainModuleName: String
133+
134+
/// The complete set of modules discovered
135+
var modules: [ModuleDependencyId: ModuleDependencies] = [:]
136+
137+
/// Information about the main module.
138+
var mainModule: ModuleDependencies { modules[.swift(mainModuleName)]! }
139+
}
140+
141+
let fileName = CommandLine.arguments[1]
142+
let data = try! Data(contentsOf: URL(fileURLWithPath: fileName))
143+
144+
let decoder = JSONDecoder()
145+
let moduleDependencyGraph = try! decoder.decode(
146+
ModuleDependencyGraph.self, from: data)
147+
print(moduleDependencyGraph)

test/ScanDependencies/module_deps.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,22 @@
22
// RUN: mkdir -p %t/clang-module-cache
33
// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h
44

5+
// Check the contents of the JSON output
56
// RUN: %FileCheck %s < %t/deps.json
7+
8+
// Check the make-style dependencies file
69
// RUN: %FileCheck %s -check-prefix CHECK-MAKE-DEPS < %t/deps.d
710

11+
// Check that the JSON parses correctly into the canonical Swift data
12+
// structures.
13+
14+
// RUN: %target-build-swift %S/Inputs/ModuleDependencyGraph.swift -o %t/main
15+
// RUN: %target-codesign %t/main
16+
// RUN: %target-run %t/main %t/deps.json
17+
18+
// REQUIRES: executable_test
19+
// REQUIRES: objc_interop
20+
821
import C
922
import E
1023

0 commit comments

Comments
 (0)