mirror of
https://github.com/apple/sourcekit-lsp.git
synced 2026-03-02 18:23:24 +01:00
When the compiler in `compile_commands.json` references a `swift` executable that’s a symlink to `swiftly`, SourceKit-LSP got confused because the `swift` executable doesn’t reside in a real toolchain, causing us to not provide any semantic functionality. When we discover that the `swift` executable reference in compile commands references a `swiftly` executable, use `swiftly use -p` to resolve the binary in the real toolchain and continue operating based on that. Fixes #2128 rdar://150301344
158 lines
5.0 KiB
Swift
158 lines
5.0 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
package import BuildServerProtocol
|
|
import Foundation
|
|
import LanguageServerProtocol
|
|
import SKLogging
|
|
|
|
extension BuildTargetIdentifier {
|
|
package static let dummy: BuildTargetIdentifier = BuildTargetIdentifier(uri: try! URI(string: "dummy://dummy"))
|
|
}
|
|
|
|
package enum BuildDestinationIdentifier {
|
|
case host
|
|
case target
|
|
|
|
/// A string that can be used to identify the build triple in a `BuildTargetIdentifier`.
|
|
///
|
|
/// `BuildSystemManager.canonicalBuildTargetIdentifier` picks the canonical target based on alphabetical
|
|
/// ordering. We rely on the string "destination" being ordered before "tools" so that we prefer a
|
|
/// `destination` (or "target") target over a `tools` (or "host") target.
|
|
var id: String {
|
|
switch self {
|
|
case .host:
|
|
return "tools"
|
|
case .target:
|
|
return "destination"
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: BuildTargetIdentifier for SwiftPM
|
|
|
|
extension BuildTargetIdentifier {
|
|
/// - Important: *For testing only*
|
|
package static func createSwiftPM(
|
|
target: String,
|
|
destination: BuildDestinationIdentifier
|
|
) throws -> BuildTargetIdentifier {
|
|
var components = URLComponents()
|
|
components.scheme = "swiftpm"
|
|
components.host = "target"
|
|
components.queryItems = [
|
|
URLQueryItem(name: "target", value: target),
|
|
URLQueryItem(name: "destination", value: destination.id),
|
|
]
|
|
|
|
struct FailedToConvertSwiftBuildTargetToUrlError: Swift.Error, CustomStringConvertible {
|
|
var target: String
|
|
var destination: String
|
|
|
|
var description: String {
|
|
return "Failed to generate URL for target: \(target), destination: \(destination)"
|
|
}
|
|
}
|
|
|
|
guard let url = components.url else {
|
|
throw FailedToConvertSwiftBuildTargetToUrlError(target: target, destination: destination.id)
|
|
}
|
|
|
|
return BuildTargetIdentifier(uri: URI(url))
|
|
}
|
|
|
|
static let forPackageManifest = BuildTargetIdentifier(uri: try! URI(string: "swiftpm://package-manifest"))
|
|
|
|
var swiftpmTargetProperties: (target: String, runDestination: String) {
|
|
get throws {
|
|
struct InvalidTargetIdentifierError: Swift.Error, CustomStringConvertible {
|
|
var target: BuildTargetIdentifier
|
|
|
|
var description: String {
|
|
return "Invalid target identifier \(target)"
|
|
}
|
|
}
|
|
guard let components = URLComponents(url: self.uri.arbitrarySchemeURL, resolvingAgainstBaseURL: false) else {
|
|
throw InvalidTargetIdentifierError(target: self)
|
|
}
|
|
let target = components.queryItems?.last(where: { $0.name == "target" })?.value
|
|
let runDestination = components.queryItems?.last(where: { $0.name == "destination" })?.value
|
|
|
|
guard let target, let runDestination else {
|
|
throw InvalidTargetIdentifierError(target: self)
|
|
}
|
|
|
|
return (target, runDestination)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: BuildTargetIdentifier for CompileCommands
|
|
|
|
extension BuildTargetIdentifier {
|
|
package static func createCompileCommands(compiler: String) throws -> BuildTargetIdentifier {
|
|
var components = URLComponents()
|
|
components.scheme = "compilecommands"
|
|
components.host = "target"
|
|
components.queryItems = [URLQueryItem(name: "compiler", value: compiler)]
|
|
|
|
struct FailedToConvertSwiftBuildTargetToUrlError: Swift.Error, CustomStringConvertible {
|
|
var compiler: String
|
|
|
|
var description: String {
|
|
return "Failed to generate URL for compiler: \(compiler)"
|
|
}
|
|
}
|
|
|
|
guard let url = components.url else {
|
|
throw FailedToConvertSwiftBuildTargetToUrlError(compiler: compiler)
|
|
}
|
|
|
|
return BuildTargetIdentifier(uri: URI(url))
|
|
}
|
|
|
|
var compileCommandsCompiler: String {
|
|
get throws {
|
|
struct InvalidTargetIdentifierError: Swift.Error, CustomStringConvertible {
|
|
var target: BuildTargetIdentifier
|
|
|
|
var description: String {
|
|
return "Invalid target identifier \(target)"
|
|
}
|
|
}
|
|
guard let components = URLComponents(url: self.uri.arbitrarySchemeURL, resolvingAgainstBaseURL: false) else {
|
|
throw InvalidTargetIdentifierError(target: self)
|
|
}
|
|
guard components.scheme == "compilecommands", components.host == "target" else {
|
|
throw InvalidTargetIdentifierError(target: self)
|
|
}
|
|
let compiler = components.queryItems?.last(where: { $0.name == "compiler" })?.value
|
|
|
|
guard let compiler else {
|
|
throw InvalidTargetIdentifierError(target: self)
|
|
}
|
|
|
|
return compiler
|
|
}
|
|
}
|
|
}
|
|
|
|
extension BuildTargetIdentifier: CustomLogStringConvertible {
|
|
package var description: String {
|
|
return uri.stringValue
|
|
}
|
|
|
|
package var redactedDescription: String {
|
|
return uri.stringValue.hashForLogging
|
|
}
|
|
}
|