@@ -25,7 +25,7 @@ import func TSCBasic.resolveSymlinks
25
25
/// A single compilation database command.
26
26
///
27
27
/// See https://clang.llvm.org/docs/JSONCompilationDatabase.html
28
- package struct CompilationDatabaseCompileCommand : Equatable {
28
+ package struct CompilationDatabaseCompileCommand : Equatable , Codable {
29
29
30
30
/// The working directory for the compilation.
31
31
package var directory : String
@@ -45,9 +45,40 @@ package struct CompilationDatabaseCompileCommand: Equatable {
45
45
self . commandLine = commandLine
46
46
self . output = output
47
47
}
48
- }
49
48
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
+ }
51
82
52
83
/// The `DocumentURI` for this file. If `filename` is relative and `directory` is
53
84
/// absolute, returns the concatenation. However, if both paths are relative,
@@ -124,9 +155,7 @@ package struct FixedCompilationDatabase: CompilationDatabase, Equatable {
124
155
SourceItem ( uri: URI ( filePath: directory, isDirectory: true ) , kind: . directory, generated: false )
125
156
]
126
157
}
127
- }
128
158
129
- extension FixedCompilationDatabase {
130
159
/// Loads the compilation database located in `directory`, if any.
131
160
/// - Returns: `nil` if `compile_flags.txt` was not found
132
161
package init ? ( directory: AbsolutePath , _ fileSystem: FileSystem = localFileSystem) throws {
@@ -173,16 +202,48 @@ extension FixedCompilationDatabase {
173
202
/// ```
174
203
///
175
204
/// 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 ] = [ ]
179
208
180
209
package init ( _ commands: [ CompilationDatabaseCompileCommand ] = [ ] ) {
181
210
for command in commands {
182
211
add ( command)
183
212
}
184
213
}
185
214
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
+
186
247
package subscript( _ uri: DocumentURI ) -> [ CompilationDatabaseCompileCommand ] {
187
248
if let indices = pathToCommands [ uri] {
188
249
return indices. map { commands [ $0] }
@@ -199,7 +260,7 @@ package struct JSONCompilationDatabase: CompilationDatabase, Equatable {
199
260
}
200
261
}
201
262
202
- package mutating func add( _ command: CompilationDatabaseCompileCommand ) {
263
+ private mutating func add( _ command: CompilationDatabaseCompileCommand ) {
203
264
let uri = command. uri
204
265
pathToCommands [ uri, default: [ ] ] . append ( commands. count)
205
266
@@ -216,79 +277,7 @@ package struct JSONCompilationDatabase: CompilationDatabase, Equatable {
216
277
}
217
278
}
218
279
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
-
255
280
enum CompilationDatabaseDecodingError : Error {
256
281
case missingCommandOrArguments
257
282
case fixedDatabaseDecodingError
258
283
}
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