Skip to content

Commit 8554f6d

Browse files
authored
Merge pull request #223 from benlangmuir/comdb-index-store-path
Infer index store path from compilation database
2 parents 94585a7 + 3f7b307 commit 8554f6d

File tree

8 files changed

+170
-25
lines changed

8 files changed

+170
-25
lines changed

Sources/SKCore/CompilationDatabase.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ extension CompilationDatabase.Command {
6060
public protocol CompilationDatabase {
6161
typealias Command = CompilationDatabaseCompileCommand
6262
subscript(_ path: URL) -> [Command] { get }
63+
var allCommands: AnySequence<Command> { get }
6364
}
6465

6566
/// Loads the compilation database located in `directory`, if any.
@@ -104,6 +105,8 @@ public struct JSONCompilationDatabase: CompilationDatabase, Equatable {
104105
return []
105106
}
106107

108+
public var allCommands: AnySequence<Command> { AnySequence(commands) }
109+
107110
public mutating func add(_ command: Command) {
108111
let url = command.url
109112
pathToCommands[url, default: []].append(commands.count)

Sources/SKCore/CompilationDatabaseBuildSystem.swift

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,20 @@ public final class CompilationDatabaseBuildSystem {
3131

3232
let fileSystem: FileSystem
3333

34+
public lazy var indexStorePath: AbsolutePath? = {
35+
if let allCommands = self.compdb?.allCommands {
36+
for command in allCommands {
37+
let args = command.commandLine
38+
for i in args.indices.reversed() {
39+
if args[i] == "-index-store-path" && i != args.endIndex - 1 {
40+
return try? AbsolutePath(validating: args[i+1])
41+
}
42+
}
43+
}
44+
}
45+
return nil
46+
}()
47+
3448
public init(projectRoot: AbsolutePath? = nil, fileSystem: FileSystem = localFileSystem) {
3549
self.fileSystem = fileSystem
3650
if let path = projectRoot {
@@ -41,9 +55,9 @@ public final class CompilationDatabaseBuildSystem {
4155

4256
extension CompilationDatabaseBuildSystem: BuildSystem {
4357

44-
// FIXME: derive from the compiler arguments.
45-
public var indexStorePath: AbsolutePath? { return nil }
46-
public var indexDatabasePath: AbsolutePath? { return nil }
58+
public var indexDatabasePath: AbsolutePath? {
59+
indexStorePath?.parentDirectory.appending(component: "IndexDatabase")
60+
}
4761

4862
public func settings(for uri: DocumentURI, _ language: Language) -> FileBuildSettings? {
4963
guard let url = uri.fileURL else {

Sources/SourceKit/SourceKitServer+Options.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,13 @@ extension SourceKitServer {
2424
/// Additional arguments to pass to `clangd` on the command-line.
2525
public var clangdOptions: [String]
2626

27-
public init(buildSetup: BuildSetup = .default, clangdOptions: [String] = []) {
27+
/// Additional options for the index.
28+
public var indexOptions: IndexOptions
29+
30+
public init(buildSetup: BuildSetup = .default, clangdOptions: [String] = [], indexOptions: IndexOptions = .init()) {
2831
self.buildSetup = buildSetup
2932
self.clangdOptions = clangdOptions
33+
self.indexOptions = indexOptions
3034
}
3135
}
3236
}

Sources/SourceKit/SourceKitServer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ extension SourceKitServer {
293293

294294
func initialize(_ req: Request<InitializeRequest>) {
295295

296-
var indexOptions = IndexOptions()
296+
var indexOptions = self.options.indexOptions
297297
if case .dictionary(let options) = req.params.initializationOptions {
298298
if case .bool(let listenToUnitEvents) = options["listenToUnitEvents"] {
299299
indexOptions.listenToUnitEvents = listenToUnitEvents

Sources/SourceKit/Workspace.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ public final class Workspace {
100100
log("cannot setup build integration for workspace at URI \(rootUri) because the URI it is not a valid file URL")
101101
}
102102

103-
if let storePath = buildSettings.indexStorePath,
104-
let dbPath = buildSettings.indexDatabasePath,
103+
if let storePath = indexOptions.indexStorePath ?? settings.indexStorePath,
104+
let dbPath = indexOptions.indexDatabasePath ?? settings.indexDatabasePath,
105105
let libPath = toolchainRegistry.default?.libIndexStore
106106
{
107107
do {
@@ -121,11 +121,17 @@ public final class Workspace {
121121

122122
public struct IndexOptions {
123123

124+
/// Override the index-store-path provided by the build system.
125+
public var indexStorePath: AbsolutePath?
126+
127+
/// Override the index-database-path provided by the build system.
128+
public var indexDatabasePath: AbsolutePath?
129+
124130
/// *For Testing* Whether the index should listen to unit events, or wait for
125131
/// explicit calls to pollForUnitChangesAndWait().
126132
public var listenToUnitEvents: Bool
127133

128-
public init(listenToUnitEvents: Bool = true) {
134+
public init(indexStorePath: AbsolutePath? = nil, indexDatabasePath: AbsolutePath? = nil, listenToUnitEvents: Bool = true) {
129135
self.listenToUnitEvents = listenToUnitEvents
130136
}
131137
}

Sources/sourcekit-lsp/main.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ func parseArguments() throws -> CommandLineOptions {
4949
let buildFlagsLinker = parser.add(option: "-Xlinker", kind: [String].self, strategy: .oneByOne, usage: "Pass flag through to all linker invocations")
5050
let buildFlagsSwift = parser.add(option: "-Xswiftc", kind: [String].self, strategy: .oneByOne, usage: "Pass flag through to all Swift compiler invocations")
5151
let clangdOptions = parser.add(option: "-Xclangd", kind: [String].self, strategy: .oneByOne, usage: "Pass options to clangd command-line")
52+
let indexStorePath = parser.add(option: "-index-store-path", kind: PathArgument.self, usage: "Override index-store-path from the build system")
53+
let indexDatabasePath = parser.add(option: "-index-db-path", kind: PathArgument.self, usage: "Override index-database-path from the build system")
5254

5355
let parsedArguments = try parser.parse(arguments)
5456

@@ -77,6 +79,13 @@ func parseArguments() throws -> CommandLineOptions {
7779
result.serverOptions.clangdOptions = options
7880
}
7981

82+
if let path = parsedArguments.get(indexStorePath)?.path {
83+
result.serverOptions.indexOptions.indexStorePath = path
84+
}
85+
if let path = parsedArguments.get(indexDatabasePath)?.path {
86+
result.serverOptions.indexOptions.indexDatabasePath = path
87+
}
88+
8089
if let logLevel = parsedArguments.get(loggingOption) {
8190
Logger.shared.currentLevel = logLevel
8291
} else {

Tests/SKCoreTests/CompilationDatabaseTests.swift

Lines changed: 120 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -186,24 +186,127 @@ final class CompilationDatabaseTests: XCTestCase {
186186
}
187187

188188
func testCompilationDatabaseBuildSystem() {
189-
let fs = InMemoryFileSystem()
190-
try! fs.createDirectory(AbsolutePath("/a"))
191-
try! fs.writeFileContents(AbsolutePath("/a/compile_commands.json"), bytes: """
192-
[
193-
{
194-
"file": "/a/a.swift",
195-
"directory": "/a",
196-
"arguments": ["swiftc", "-swift-version", "4", "/a/a.swift"]
197-
}
198-
]
199-
""")
189+
checkCompilationDatabaseBuildSystem("""
190+
[
191+
{
192+
"file": "/a/a.swift",
193+
"directory": "/a",
194+
"arguments": ["swiftc", "-swift-version", "4", "/a/a.swift"]
195+
}
196+
]
197+
""") { buildSystem in
198+
let settings = buildSystem.settings(for: DocumentURI(URL(fileURLWithPath: "/a/a.swift")), .swift)
199+
XCTAssertNotNil(settings)
200+
XCTAssertEqual(settings?.workingDirectory, "/a")
201+
XCTAssertEqual(settings?.compilerArguments, ["-swift-version", "4", "/a/a.swift"])
202+
XCTAssertNil(buildSystem.indexStorePath)
203+
XCTAssertNil(buildSystem.indexDatabasePath)
204+
}
205+
}
200206

201-
let buildSystem: BuildSystem = CompilationDatabaseBuildSystem(
202-
projectRoot: AbsolutePath("/a"), fileSystem: fs)
207+
func testCompilationDatabaseBuildSystemIndexStoreSwift0() {
208+
checkCompilationDatabaseBuildSystem("[]") { buildSystem in
209+
XCTAssertNil(buildSystem.indexStorePath)
210+
}
211+
}
203212

204-
let settings = buildSystem.settings(for: DocumentURI(URL(fileURLWithPath: "/a/a.swift")), .swift)
205-
XCTAssertNotNil(settings)
206-
XCTAssertEqual(settings?.workingDirectory, "/a")
207-
XCTAssertEqual(settings?.compilerArguments, ["-swift-version", "4", "/a/a.swift"])
213+
func testCompilationDatabaseBuildSystemIndexStoreSwift1() {
214+
checkCompilationDatabaseBuildSystem("""
215+
[
216+
{
217+
"file": "/a/a.swift",
218+
"directory": "/a",
219+
"arguments": ["swiftc", "-swift-version", "4", "/a/a.swift", "-index-store-path", "/b"]
220+
}
221+
]
222+
""") { buildSystem in
223+
XCTAssertEqual(buildSystem.indexStorePath, AbsolutePath("/b"))
224+
XCTAssertEqual(buildSystem.indexDatabasePath, AbsolutePath("/IndexDatabase"))
225+
}
208226
}
227+
228+
func testCompilationDatabaseBuildSystemIndexStoreSwift2() {
229+
checkCompilationDatabaseBuildSystem("""
230+
[
231+
{
232+
"file": "/a/a.swift",
233+
"directory": "/a",
234+
"arguments": ["swiftc", "-swift-version", "4", "/a/a.swift"]
235+
},
236+
{
237+
"file": "/a/b.swift",
238+
"directory": "/a",
239+
"arguments": ["swiftc", "-swift-version", "4", "/a/b.swift"]
240+
},
241+
{
242+
"file": "/a/c.swift",
243+
"directory": "/a",
244+
"arguments": ["swiftc", "-swift-version", "4", "/a/c.swift", "-index-store-path", "/b"]
245+
}
246+
]
247+
""") { buildSystem in
248+
XCTAssertEqual(buildSystem.indexStorePath, AbsolutePath("/b"))
249+
}
250+
}
251+
252+
func testCompilationDatabaseBuildSystemIndexStoreSwift3() {
253+
checkCompilationDatabaseBuildSystem("""
254+
[
255+
{
256+
"file": "/a/a.swift",
257+
"directory": "/a",
258+
"arguments": ["swiftc", "-index-store-path", "/b", "-swift-version", "4", "/a/a.swift"]
259+
}
260+
]
261+
""") { buildSystem in
262+
XCTAssertEqual(buildSystem.indexStorePath, AbsolutePath("/b"))
263+
}
264+
}
265+
266+
func testCompilationDatabaseBuildSystemIndexStoreSwift4() {
267+
checkCompilationDatabaseBuildSystem("""
268+
[
269+
{
270+
"file": "/a/a.swift",
271+
"directory": "/a",
272+
"arguments": ["swiftc", "-swift-version", "4", "/a/c.swift", "-index-store-path"]
273+
}
274+
]
275+
""") { buildSystem in
276+
XCTAssertNil(buildSystem.indexStorePath)
277+
}
278+
}
279+
280+
func testCompilationDatabaseBuildSystemIndexStoreClang() {
281+
checkCompilationDatabaseBuildSystem("""
282+
[
283+
{
284+
"file": "/a/a.cpp",
285+
"directory": "/a",
286+
"arguments": ["clang", "/a/a.cpp"]
287+
},
288+
{
289+
"file": "/a/b.cpp",
290+
"directory": "/a",
291+
"arguments": ["clang", "/a/b.cpp"]
292+
},
293+
{
294+
"file": "/a/c.cpp",
295+
"directory": "/a",
296+
"arguments": ["clang", "/a/c.cpp", "-index-store-path", "/b"]
297+
}
298+
]
299+
""") { buildSystem in
300+
XCTAssertEqual(buildSystem.indexStorePath, AbsolutePath("/b"))
301+
XCTAssertEqual(buildSystem.indexDatabasePath, AbsolutePath("/IndexDatabase"))
302+
}
303+
}
304+
}
305+
306+
private func checkCompilationDatabaseBuildSystem(_ compdb: ByteString, file: StaticString = #file, line: UInt = #line, block: (BuildSystem) -> ()) {
307+
let fs = InMemoryFileSystem()
308+
XCTAssertNoThrow(try fs.createDirectory(AbsolutePath("/a")), file: file, line: line)
309+
XCTAssertNoThrow(try fs.writeFileContents(AbsolutePath("/a/compile_commands.json"), bytes: compdb), file: file, line: line)
310+
let buildSystem: BuildSystem = CompilationDatabaseBuildSystem(projectRoot: AbsolutePath("/a"), fileSystem: fs)
311+
block(buildSystem)
209312
}

Tests/SKCoreTests/XCTestManifests.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ extension CompilationDatabaseTests {
2222
// to regenerate.
2323
static let __allTests__CompilationDatabaseTests = [
2424
("testCompilationDatabaseBuildSystem", testCompilationDatabaseBuildSystem),
25+
("testCompilationDatabaseBuildSystemIndexStoreClang", testCompilationDatabaseBuildSystemIndexStoreClang),
26+
("testCompilationDatabaseBuildSystemIndexStoreSwift0", testCompilationDatabaseBuildSystemIndexStoreSwift0),
27+
("testCompilationDatabaseBuildSystemIndexStoreSwift1", testCompilationDatabaseBuildSystemIndexStoreSwift1),
28+
("testCompilationDatabaseBuildSystemIndexStoreSwift2", testCompilationDatabaseBuildSystemIndexStoreSwift2),
29+
("testCompilationDatabaseBuildSystemIndexStoreSwift3", testCompilationDatabaseBuildSystemIndexStoreSwift3),
30+
("testCompilationDatabaseBuildSystemIndexStoreSwift4", testCompilationDatabaseBuildSystemIndexStoreSwift4),
2531
("testDecodeCompDBCommand", testDecodeCompDBCommand),
2632
("testEncodeCompDBCommand", testEncodeCompDBCommand),
2733
("testJSONCompilationDatabaseCoding", testJSONCompilationDatabaseCoding),

0 commit comments

Comments
 (0)