From f84cfecbf27910cf900af7b3fe005fc93bca71b1 Mon Sep 17 00:00:00 2001 From: Alex Hoppen Date: Sat, 1 Jun 2024 12:20:08 -0700 Subject: [PATCH] Make `CompilationDatabase` use `DocumentURI` instead of `URL` --- Sources/SKCore/CompilationDatabase.swift | 53 +++++++++++-------- .../CompilationDatabaseBuildSystem.swift | 19 +++---- .../CompilationDatabaseTests.swift | 8 +-- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Sources/SKCore/CompilationDatabase.swift b/Sources/SKCore/CompilationDatabase.swift index 63800ffb..cdd71e20 100644 --- a/Sources/SKCore/CompilationDatabase.swift +++ b/Sources/SKCore/CompilationDatabase.swift @@ -12,6 +12,7 @@ import Foundation import LSPLogging +import LanguageServerProtocol import SKSupport import struct TSCBasic.AbsolutePath @@ -47,15 +48,15 @@ public struct CompilationDatabaseCompileCommand: Equatable { extension CompilationDatabase.Command { - /// The `URL` for this file. If `filename` is relative and `directory` is + /// The `DocumentURI` for this file. If `filename` is relative and `directory` is /// absolute, returns the concatenation. However, if both paths are relative, /// it falls back to `filename`, which is more likely to be the identifier /// that a caller will be looking for. - public var url: URL { + public var uri: DocumentURI { if filename.hasPrefix("/") || !directory.hasPrefix("/") { - return URL(fileURLWithPath: filename) + return DocumentURI(filePath: filename, isDirectory: false) } else { - return URL(fileURLWithPath: directory).appendingPathComponent(filename, isDirectory: false) + return DocumentURI(URL(fileURLWithPath: directory).appendingPathComponent(filename, isDirectory: false)) } } } @@ -65,7 +66,7 @@ extension CompilationDatabase.Command { /// See https://clang.llvm.org/docs/JSONCompilationDatabase.html public protocol CompilationDatabase { typealias Command = CompilationDatabaseCompileCommand - subscript(_ path: URL) -> [Command] { get } + subscript(_ uri: DocumentURI) -> [Command] { get } var allCommands: AnySequence { get } } @@ -110,13 +111,13 @@ public func tryLoadCompilationDatabase( /// /// See https://clang.llvm.org/docs/JSONCompilationDatabase.html under Alternatives public struct FixedCompilationDatabase: CompilationDatabase, Equatable { - public var allCommands: AnySequence { AnySequence([]) } + public var allCommands: AnySequence { AnySequence([]) } private let fixedArgs: [String] private let directory: String - public subscript(path: URL) -> [Command] { - [Command(directory: directory, filename: path.path, commandLine: fixedArgs + [path.path])] + public subscript(path: DocumentURI) -> [CompilationDatabaseCompileCommand] { + [Command(directory: directory, filename: path.pseudoPath, commandLine: fixedArgs + [path.pseudoPath])] } } @@ -168,32 +169,38 @@ extension FixedCompilationDatabase { /// /// See https://clang.llvm.org/docs/JSONCompilationDatabase.html public struct JSONCompilationDatabase: CompilationDatabase, Equatable { - var pathToCommands: [URL: [Int]] = [:] - var commands: [Command] = [] + var pathToCommands: [DocumentURI: [Int]] = [:] + var commands: [CompilationDatabaseCompileCommand] = [] - public init(_ commands: [Command] = []) { - commands.forEach { try! add($0) } + public init(_ commands: [CompilationDatabaseCompileCommand] = []) { + for command in commands { + add(command) + } } - public subscript(_ url: URL) -> [Command] { - if let indices = pathToCommands[url] { + public subscript(_ uri: DocumentURI) -> [CompilationDatabaseCompileCommand] { + if let indices = pathToCommands[uri] { return indices.map { commands[$0] } } - if let indices = pathToCommands[url.resolvingSymlinksInPath()] { + if let fileURL = uri.fileURL, let indices = pathToCommands[DocumentURI(fileURL.resolvingSymlinksInPath())] { return indices.map { commands[$0] } } return [] } - public var allCommands: AnySequence { AnySequence(commands) } + public var allCommands: AnySequence { AnySequence(commands) } - public mutating func add(_ command: Command) throws { - let url = command.url - pathToCommands[url, default: []].append(commands.count) + public mutating func add(_ command: CompilationDatabaseCompileCommand) { + let uri = command.uri + pathToCommands[uri, default: []].append(commands.count) - let canonical = URL(fileURLWithPath: try resolveSymlinks(AbsolutePath(validating: url.path)).pathString) - if canonical != url { - pathToCommands[canonical, default: []].append(commands.count) + if let fileURL = uri.fileURL, + let symlinksResolved = try? resolveSymlinks(AbsolutePath(validating: fileURL.path)) + { + let canonical = DocumentURI(filePath: symlinksResolved.pathString, isDirectory: false) + if canonical != uri { + pathToCommands[canonical, default: []].append(commands.count) + } } commands.append(command) @@ -204,7 +211,7 @@ extension JSONCompilationDatabase: Codable { public init(from decoder: Decoder) throws { var container = try decoder.unkeyedContainer() while !container.isAtEnd { - try self.add(try container.decode(Command.self)) + self.add(try container.decode(Command.self)) } } diff --git a/Sources/SKCore/CompilationDatabaseBuildSystem.swift b/Sources/SKCore/CompilationDatabaseBuildSystem.swift index d601bd09..7dc4556d 100644 --- a/Sources/SKCore/CompilationDatabaseBuildSystem.swift +++ b/Sources/SKCore/CompilationDatabaseBuildSystem.swift @@ -106,12 +106,8 @@ extension CompilationDatabaseBuildSystem: BuildSystem { in buildTarget: ConfiguredTarget, language: Language ) async -> FileBuildSettings? { - guard let url = document.fileURL else { - // We can't determine build settings for non-file URIs. - return nil - } - guard let db = database(for: url), - let cmd = db[url].first + guard let db = database(for: document), + let cmd = db[document].first else { return nil } return FileBuildSettings( compilerArguments: Array(cmd.commandLine.dropFirst()), @@ -153,8 +149,8 @@ extension CompilationDatabaseBuildSystem: BuildSystem { self.watchedFiles.remove(uri) } - private func database(for url: URL) -> CompilationDatabase? { - if let path = try? AbsolutePath(validating: url.path) { + private func database(for uri: DocumentURI) -> CompilationDatabase? { + if let url = uri.fileURL, let path = try? AbsolutePath(validating: url.path) { return database(for: path) } return compdb @@ -212,10 +208,7 @@ extension CompilationDatabaseBuildSystem: BuildSystem { } public func fileHandlingCapability(for uri: DocumentURI) -> FileHandlingCapability { - guard let fileUrl = uri.fileURL else { - return .unhandled - } - if database(for: fileUrl) != nil { + if database(for: uri) != nil { return .handled } else { return .unhandled @@ -227,7 +220,7 @@ extension CompilationDatabaseBuildSystem: BuildSystem { return [] } return compdb.allCommands.map { - SourceFileInfo(uri: DocumentURI($0.url), isPartOfRootProject: true, mayContainTests: true) + SourceFileInfo(uri: $0.uri, isPartOfRootProject: true, mayContainTests: true) } } diff --git a/Tests/SKCoreTests/CompilationDatabaseTests.swift b/Tests/SKCoreTests/CompilationDatabaseTests.swift index 934c1aaa..27ddddeb 100644 --- a/Tests/SKCoreTests/CompilationDatabaseTests.swift +++ b/Tests/SKCoreTests/CompilationDatabaseTests.swift @@ -157,9 +157,9 @@ final class CompilationDatabaseTests: XCTestCase { let db = JSONCompilationDatabase([cmd1, cmd2, cmd3]) - XCTAssertEqual(db[URL(fileURLWithPath: "b")], [cmd1]) - XCTAssertEqual(db[URL(fileURLWithPath: "/c/b")], [cmd2]) - XCTAssertEqual(db[URL(fileURLWithPath: "/b")], [cmd3]) + XCTAssertEqual(db[DocumentURI(filePath: "b", isDirectory: false)], [cmd1]) + XCTAssertEqual(db[DocumentURI(filePath: "/c/b", isDirectory: false)], [cmd2]) + XCTAssertEqual(db[DocumentURI(filePath: "/b", isDirectory: false)], [cmd3]) } func testJSONCompilationDatabaseFromDirectory() throws { @@ -255,7 +255,7 @@ final class CompilationDatabaseTests: XCTestCase { XCTAssertNotNil(db) XCTAssertEqual( - db![URL(fileURLWithPath: "/a/b")], + db![DocumentURI(filePath: "/a/b", isDirectory: false)], [ CompilationDatabase.Command( directory: try AbsolutePath(validating: "/a").pathString,