Skip to content

Support indexing a file in the context of multiple targets #2038

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 13 additions & 32 deletions Contributor Documentation/BSP Extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface SourceKitInitializeBuildResponseData {
* for `swiftc` or `clang` invocations **/
indexStorePath?: string;

/** Whether the server implements the `buildTarget/outputPaths` request. */
/** Whether the server set the `outputPath` property in the `buildTarget/sources` request */
outputPathsProvider?: bool;

/** Whether the build server supports the `buildTarget/prepare` request */
Expand All @@ -46,37 +46,6 @@ If `data` contains a string value for the `workDoneProgressTitle` key, then the

`changes` can be `null` to indicate that all targets have changed.

## `buildTarget/outputPaths`

For all the source files in this target, the output paths that are used during indexing, ie. the `-index-unit-output-path` for the file, if it is specified in the compiler arguments or the file that is passed as `-o`, if `-index-unit-output-path` is not specified.

This allows SourceKit-LSP to remove index entries for source files that are removed from a target but remain present on disk.

The server communicates during the initialize handshake whether this method is supported or not by setting `outputPathsProvider: true` in `SourceKitInitializeBuildResponseData`.

- method: `buildTarget/outputPaths`
- params: `OutputPathsParams`
- result: `OutputPathsResult`

```ts
export interface BuildTargetOutputPathsParams {
/** A list of build targets to get the output paths for. */
targets: BuildTargetIdentifier[];
}

export interface BuildTargetOutputPathsItem {
/** The target these output file paths are for. */
target: BuildTargetIdentifier;

/** The output paths for all source files in this target. */
outputPaths: string[];
}

export interface BuildTargetOutputPathsResult {
items: BuildTargetOutputPathsItem[];
}
```

## `buildTarget/prepare`

The prepare build target request is sent from the client to the server to prepare the given list of build targets for editor functionality.
Expand Down Expand Up @@ -119,6 +88,18 @@ export interface SourceKitSourceItemData {
* inferring build settings from it. Listing header files in `buildTarget/sources` allows SourceKit-LSP to provide
* semantic functionality for header files if they haven't been included by any main file. **/
isHeader?: bool;

/**
* The output path that are is during indexing for this file, ie. the `-index-unit-output-path`, if it is specified
* in the compiler arguments or the file that is passed as `-o`, if `-index-unit-output-path` is not specified.
*
* This allows SourceKit-LSP to remove index entries for source files that are removed from a target but remain
* present on disk and to index a file that is part of multiple targets in the context of each target.
*
* The server communicates during the initialize handshake whether it populates this property by setting
* `outputPathsProvider: true` in `SourceKitInitializeBuildResponseData`.
*/
outputPath?: string;
}
```

Expand Down
1 change: 0 additions & 1 deletion Sources/BuildServerProtocol/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ add_library(BuildServerProtocol STATIC
Messages.swift

Messages/BuildShutdownRequest.swift
Messages/BuildTargetOutputPathsRequest.swift
Messages/BuildTargetPrepareRequest.swift
Messages/BuildTargetSourcesRequest.swift
Messages/InitializeBuildRequest.swift
Expand Down
1 change: 0 additions & 1 deletion Sources/BuildServerProtocol/Messages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ public import LanguageServerProtocol

fileprivate let requestTypes: [_RequestType.Type] = [
BuildShutdownRequest.self,
BuildTargetOutputPathsRequest.self,
BuildTargetPrepareRequest.self,
BuildTargetSourcesRequest.self,
CreateWorkDoneProgressRequest.self,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ public struct SourceItem: Codable, Hashable, Sendable {
/// Language-specific metadata about this source item.
public var data: LSPAny?

/// If `dataKind` is `sourceKit`, the `data` interpreted as `SourceKitSourceItemData`, otherwise `nil`.
public var sourceKitData: SourceKitSourceItemData? {
guard dataKind == .sourceKit else {
return nil
}
return SourceKitSourceItemData(fromLSPAny: data)
}

public init(
uri: URI,
kind: SourceItemKind,
Expand Down Expand Up @@ -126,9 +134,20 @@ public struct SourceKitSourceItemData: LSPAnyCodable, Codable {
/// semantic functionality for header files if they haven't been included by any main file.
public var isHeader: Bool?

public init(language: Language? = nil, isHeader: Bool? = nil) {
/// The output path that is used during indexing for this file, ie. the `-index-unit-output-path`, if it is specified
/// in the compiler arguments or the file that is passed as `-o`, if `-index-unit-output-path` is not specified.
///
/// This allows SourceKit-LSP to remove index entries for source files that are removed from a target but remain
/// present on disk.
///
/// The server communicates during the initialize handshake whether it populates this property by setting
/// `outputPathsProvider: true` in `SourceKitInitializeBuildResponseData`.
public var outputPath: String?

public init(language: Language? = nil, isHeader: Bool? = nil, outputPath: String? = nil) {
self.language = language
self.isHeader = isHeader
self.outputPath = outputPath
}

public init?(fromLSPDictionary dictionary: [String: LanguageServerProtocol.LSPAny]) {
Expand All @@ -138,6 +157,9 @@ public struct SourceKitSourceItemData: LSPAnyCodable, Codable {
if case .bool(let isHeader) = dictionary[CodingKeys.isHeader.stringValue] {
self.isHeader = isHeader
}
if case .string(let outputFilePath) = dictionary[CodingKeys.outputPath.stringValue] {
self.outputPath = outputFilePath
}
}

public func encodeToLSPAny() -> LanguageServerProtocol.LSPAny {
Expand All @@ -148,6 +170,9 @@ public struct SourceKitSourceItemData: LSPAnyCodable, Codable {
if let isHeader {
result[CodingKeys.isHeader.stringValue] = .bool(isHeader)
}
if let outputPath {
result[CodingKeys.outputPath.stringValue] = .string(outputPath)
}
return .dictionary(result)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ public struct SourceKitInitializeBuildResponseData: LSPAnyCodable, Codable, Send
public var watchers: [FileSystemWatcher]?

@available(*, deprecated, message: "Use initializer with alphabetical order of parameters")
@_disfavoredOverload
public init(
indexDatabasePath: String? = nil,
indexStorePath: String? = nil,
Expand Down
8 changes: 4 additions & 4 deletions Sources/BuildServerProtocol/SupportTypes/BuildTarget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ public struct BuildTarget: Codable, Hashable, Sendable {

public init(
id: BuildTargetIdentifier,
displayName: String?,
baseDirectory: URI?,
tags: [BuildTargetTag],
capabilities: BuildTargetCapabilities,
displayName: String? = nil,
baseDirectory: URI? = nil,
tags: [BuildTargetTag] = [],
capabilities: BuildTargetCapabilities = BuildTargetCapabilities(),
languageIds: [Language],
dependencies: [BuildTargetIdentifier],
dataKind: BuildTargetDataKind? = nil,
Expand Down
Loading