Skip to content

Commit 3753837

Browse files
committed
Review CompilationDatabase.swift
1 parent bc9ee37 commit 3753837

File tree

1 file changed

+70
-81
lines changed

1 file changed

+70
-81
lines changed

Sources/BuildSystemIntegration/CompilationDatabase.swift

Lines changed: 70 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import func TSCBasic.resolveSymlinks
2525
/// A single compilation database command.
2626
///
2727
/// See https://clang.llvm.org/docs/JSONCompilationDatabase.html
28-
package struct CompilationDatabaseCompileCommand: Equatable {
28+
package struct CompilationDatabaseCompileCommand: Equatable, Codable {
2929

3030
/// The working directory for the compilation.
3131
package var directory: String
@@ -45,9 +45,40 @@ package struct CompilationDatabaseCompileCommand: Equatable {
4545
self.commandLine = commandLine
4646
self.output = output
4747
}
48-
}
4948

50-
extension CompilationDatabase.Command {
49+
private enum CodingKeys: String, CodingKey {
50+
case directory
51+
case file
52+
case command
53+
case arguments
54+
case output
55+
}
56+
57+
package init(from decoder: Decoder) throws {
58+
let container = try decoder.container(keyedBy: CodingKeys.self)
59+
self.directory = try container.decode(String.self, forKey: .directory)
60+
self.filename = try container.decode(String.self, forKey: .file)
61+
self.output = try container.decodeIfPresent(String.self, forKey: .output)
62+
if let arguments = try container.decodeIfPresent([String].self, forKey: .arguments) {
63+
self.commandLine = arguments
64+
} else if let command = try container.decodeIfPresent(String.self, forKey: .command) {
65+
#if os(Windows)
66+
self.commandLine = splitWindowsCommandLine(command, initialCommandName: true)
67+
#else
68+
self.commandLine = splitShellEscapedCommand(command)
69+
#endif
70+
} else {
71+
throw CompilationDatabaseDecodingError.missingCommandOrArguments
72+
}
73+
}
74+
75+
package func encode(to encoder: Encoder) throws {
76+
var container = encoder.container(keyedBy: CodingKeys.self)
77+
try container.encode(directory, forKey: .directory)
78+
try container.encode(filename, forKey: .file)
79+
try container.encode(commandLine, forKey: .arguments)
80+
try container.encodeIfPresent(output, forKey: .output)
81+
}
5182

5283
/// The `DocumentURI` for this file. If `filename` is relative and `directory` is
5384
/// absolute, returns the concatenation. However, if both paths are relative,
@@ -124,9 +155,7 @@ package struct FixedCompilationDatabase: CompilationDatabase, Equatable {
124155
SourceItem(uri: URI(filePath: directory, isDirectory: true), kind: .directory, generated: false)
125156
]
126157
}
127-
}
128158

129-
extension FixedCompilationDatabase {
130159
/// Loads the compilation database located in `directory`, if any.
131160
/// - Returns: `nil` if `compile_flags.txt` was not found
132161
package init?(directory: AbsolutePath, _ fileSystem: FileSystem = localFileSystem) throws {
@@ -173,16 +202,48 @@ extension FixedCompilationDatabase {
173202
/// ```
174203
///
175204
/// See https://clang.llvm.org/docs/JSONCompilationDatabase.html
176-
package struct JSONCompilationDatabase: CompilationDatabase, Equatable {
177-
var pathToCommands: [DocumentURI: [Int]] = [:]
178-
var commands: [CompilationDatabaseCompileCommand] = []
205+
package struct JSONCompilationDatabase: CompilationDatabase, Equatable, Codable {
206+
private var pathToCommands: [DocumentURI: [Int]] = [:]
207+
private var commands: [CompilationDatabaseCompileCommand] = []
179208

180209
package init(_ commands: [CompilationDatabaseCompileCommand] = []) {
181210
for command in commands {
182211
add(command)
183212
}
184213
}
185214

215+
package init(from decoder: Decoder) throws {
216+
var container = try decoder.unkeyedContainer()
217+
while !container.isAtEnd {
218+
self.add(try container.decode(Command.self))
219+
}
220+
}
221+
222+
/// Loads the compilation database located in `directory`, if any.
223+
///
224+
/// - Returns: `nil` if `compile_commands.json` was not found
225+
package init?(directory: AbsolutePath, _ fileSystem: FileSystem = localFileSystem) throws {
226+
let path = directory.appending(component: "compile_commands.json")
227+
try self.init(file: path, fileSystem)
228+
}
229+
230+
/// Loads the compilation database from `file`
231+
/// - Returns: `nil` if the file does not exist
232+
package init?(file: AbsolutePath, _ fileSystem: FileSystem = localFileSystem) throws {
233+
guard fileSystem.exists(file) else {
234+
return nil
235+
}
236+
let bytes = try fileSystem.readFileContents(file)
237+
try bytes.withUnsafeData { data in
238+
self = try JSONDecoder().decode(JSONCompilationDatabase.self, from: data)
239+
}
240+
}
241+
242+
package func encode(to encoder: Encoder) throws {
243+
var container = encoder.unkeyedContainer()
244+
try commands.forEach { try container.encode($0) }
245+
}
246+
186247
package subscript(_ uri: DocumentURI) -> [CompilationDatabaseCompileCommand] {
187248
if let indices = pathToCommands[uri] {
188249
return indices.map { commands[$0] }
@@ -199,7 +260,7 @@ package struct JSONCompilationDatabase: CompilationDatabase, Equatable {
199260
}
200261
}
201262

202-
package mutating func add(_ command: CompilationDatabaseCompileCommand) {
263+
private mutating func add(_ command: CompilationDatabaseCompileCommand) {
203264
let uri = command.uri
204265
pathToCommands[uri, default: []].append(commands.count)
205266

@@ -216,79 +277,7 @@ package struct JSONCompilationDatabase: CompilationDatabase, Equatable {
216277
}
217278
}
218279

219-
extension JSONCompilationDatabase: Codable {
220-
package init(from decoder: Decoder) throws {
221-
var container = try decoder.unkeyedContainer()
222-
while !container.isAtEnd {
223-
self.add(try container.decode(Command.self))
224-
}
225-
}
226-
227-
package func encode(to encoder: Encoder) throws {
228-
var container = encoder.unkeyedContainer()
229-
try commands.forEach { try container.encode($0) }
230-
}
231-
}
232-
233-
extension JSONCompilationDatabase {
234-
/// Loads the compilation database located in `directory`, if any.
235-
///
236-
/// - Returns: `nil` if `compile_commands.json` was not found
237-
package init?(directory: AbsolutePath, _ fileSystem: FileSystem = localFileSystem) throws {
238-
let path = directory.appending(component: "compile_commands.json")
239-
try self.init(file: path, fileSystem)
240-
}
241-
242-
/// Loads the compilation database from `file`
243-
/// - Returns: `nil` if the file does not exist
244-
package init?(file: AbsolutePath, _ fileSystem: FileSystem = localFileSystem) throws {
245-
guard fileSystem.exists(file) else {
246-
return nil
247-
}
248-
let bytes = try fileSystem.readFileContents(file)
249-
try bytes.withUnsafeData { data in
250-
self = try JSONDecoder().decode(JSONCompilationDatabase.self, from: data)
251-
}
252-
}
253-
}
254-
255280
enum CompilationDatabaseDecodingError: Error {
256281
case missingCommandOrArguments
257282
case fixedDatabaseDecodingError
258283
}
259-
260-
extension CompilationDatabase.Command: Codable {
261-
private enum CodingKeys: String, CodingKey {
262-
case directory
263-
case file
264-
case command
265-
case arguments
266-
case output
267-
}
268-
269-
package init(from decoder: Decoder) throws {
270-
let container = try decoder.container(keyedBy: CodingKeys.self)
271-
self.directory = try container.decode(String.self, forKey: .directory)
272-
self.filename = try container.decode(String.self, forKey: .file)
273-
self.output = try container.decodeIfPresent(String.self, forKey: .output)
274-
if let arguments = try container.decodeIfPresent([String].self, forKey: .arguments) {
275-
self.commandLine = arguments
276-
} else if let command = try container.decodeIfPresent(String.self, forKey: .command) {
277-
#if os(Windows)
278-
self.commandLine = splitWindowsCommandLine(command, initialCommandName: true)
279-
#else
280-
self.commandLine = splitShellEscapedCommand(command)
281-
#endif
282-
} else {
283-
throw CompilationDatabaseDecodingError.missingCommandOrArguments
284-
}
285-
}
286-
287-
package func encode(to encoder: Encoder) throws {
288-
var container = encoder.container(keyedBy: CodingKeys.self)
289-
try container.encode(directory, forKey: .directory)
290-
try container.encode(filename, forKey: .file)
291-
try container.encode(commandLine, forKey: .arguments)
292-
try container.encodeIfPresent(output, forKey: .output)
293-
}
294-
}

0 commit comments

Comments
 (0)