Skip to content

Commit 42aaad6

Browse files
Expose all target files to SourceKit-LSP (#8107)
Add `resources`, `ignored`, and `other` files to `BuildTarget` for use by SourceKit-LSP. This is tracked by rdar://139431738 as part of swiftlang/vscode-swift#562 ### Motivation: SourceKit-LSP needs to be able to determine which target contains a given DocC catalog in order to fulfill documentation related requests. However, the catalog is not listed as one of the `sources` or `headers`. Rather, it is part of `other` files in most cases. Expose all file types to SourceKit-LSP so that it can properly determine which target a given file belongs to. ### Modifications: Added three new properties to `BuildTarget`: `resources`, `ignored`, and `other` which are arrays of `URL` pointing to the given file types in the target. ### Result: SourceKit-LSP will be able to see all files contained within a given target.
1 parent f34907c commit 42aaad6

File tree

5 files changed

+102
-6
lines changed

5 files changed

+102
-6
lines changed

Sources/Build/BuildDescription/ClangModuleBuildDescription.swift

+10
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ public final class ClangModuleBuildDescription {
5757
self.target.underlying.resources + self.pluginDerivedResources
5858
}
5959

60+
/// The list of files in the target that were marked as ignored.
61+
public var ignored: [AbsolutePath] {
62+
self.target.underlying.ignored
63+
}
64+
65+
/// The list of other kinds of files in the target.
66+
public var others: [AbsolutePath] {
67+
self.target.underlying.others
68+
}
69+
6070
/// Path to the bundle generated for this module (if any).
6171
var bundlePath: AbsolutePath? {
6272
guard !self.resources.isEmpty else {

Sources/Build/BuildDescription/SwiftModuleBuildDescription.swift

+10
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,16 @@ public final class SwiftModuleBuildDescription {
108108
self.target.underlying.resources + self.pluginDerivedResources
109109
}
110110

111+
/// The list of files in the target that were marked as ignored.
112+
public var ignored: [AbsolutePath] {
113+
self.target.underlying.ignored
114+
}
115+
116+
/// The list of other kinds of files in the target.
117+
public var others: [AbsolutePath] {
118+
self.target.underlying.others
119+
}
120+
111121
/// The objects in this target, containing either machine code or bitcode
112122
/// depending on the build parameters used.
113123
public var objects: [AbsolutePath] {

Sources/SourceKitLSPAPI/BuildDescription.swift

+33
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ public protocol BuildTarget {
3737
/// Header files in the target
3838
var headers: [URL] { get }
3939

40+
/// The resource files in the target.
41+
var resources: [URL] { get }
42+
43+
/// Files in the target that were marked as ignored.
44+
var ignored: [URL] { get }
45+
46+
/// Other kinds of files in the target.
47+
var others: [URL] { get }
48+
4049
/// The name of the target. It should be possible to build a target by passing this name to `swift build --target`
4150
var name: String { get }
4251

@@ -72,6 +81,18 @@ private struct WrappedClangTargetBuildDescription: BuildTarget {
7281
return description.clangTarget.headers.map(\.asURL)
7382
}
7483

84+
var resources: [URL] {
85+
return description.resources.map { URL(fileURLWithPath: $0.path.pathString) }
86+
}
87+
88+
var ignored: [URL] {
89+
return description.ignored.map { URL(fileURLWithPath: $0.pathString) }
90+
}
91+
92+
var others: [URL] {
93+
return description.others.map { URL(fileURLWithPath: $0.pathString) }
94+
}
95+
7596
public var name: String {
7697
return description.clangTarget.name
7798
}
@@ -113,6 +134,18 @@ private struct WrappedSwiftTargetBuildDescription: BuildTarget {
113134

114135
var headers: [URL] { [] }
115136

137+
var resources: [URL] {
138+
return description.resources.map { URL(fileURLWithPath: $0.path.pathString) }
139+
}
140+
141+
var ignored: [URL] {
142+
return description.ignored.map { URL(fileURLWithPath: $0.pathString) }
143+
}
144+
145+
var others: [URL] {
146+
return description.others.map { URL(fileURLWithPath: $0.pathString) }
147+
}
148+
116149
func compileArguments(for fileURL: URL) throws -> [String] {
117150
// Note: we ignore the `fileURL` here as the expectation is that we get a command line for the entire target
118151
// in case of Swift.

Sources/SourceKitLSPAPI/PluginTargetBuildDescription.swift

+12
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ struct PluginTargetBuildDescription: BuildTarget {
4141

4242
var headers: [URL] { [] }
4343

44+
var resources: [URL] {
45+
return target.underlying.resources.map { URL(fileURLWithPath: $0.path.pathString) }
46+
}
47+
48+
var ignored: [URL] {
49+
return target.underlying.ignored.map { URL(fileURLWithPath: $0.pathString) }
50+
}
51+
52+
var others: [URL] {
53+
return target.underlying.others.map { URL(fileURLWithPath: $0.pathString) }
54+
}
55+
4456
var name: String {
4557
return target.name
4658
}

Tests/SourceKitLSPAPITests/SourceKitLSPAPITests.swift

+37-6
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,13 @@ final class SourceKitLSPAPITests: XCTestCase {
2626
func testBasicSwiftPackage() async throws {
2727
let fs = InMemoryFileSystem(emptyFiles:
2828
"/Pkg/Sources/exe/main.swift",
29+
"/Pkg/Sources/exe/README.md",
30+
"/Pkg/Sources/exe/exe.docc/GettingStarted.md",
31+
"/Pkg/Sources/exe/Resources/some_file.txt",
2932
"/Pkg/Sources/lib/lib.swift",
33+
"/Pkg/Sources/lib/README.md",
34+
"/Pkg/Sources/lib/lib.docc/GettingStarted.md",
35+
"/Pkg/Sources/lib/Resources/some_file.txt",
3036
"/Pkg/Plugins/plugin/plugin.swift"
3137
)
3238

@@ -37,9 +43,19 @@ final class SourceKitLSPAPITests: XCTestCase {
3743
Manifest.createRootManifest(
3844
displayName: "Pkg",
3945
path: "/Pkg",
46+
toolsVersion: .v5_10,
4047
targets: [
41-
TargetDescription(name: "exe", dependencies: ["lib"]),
42-
TargetDescription(name: "lib", dependencies: []),
48+
TargetDescription(
49+
name: "exe",
50+
dependencies: ["lib"],
51+
resources: [.init(rule: .copy, path: "Resources/some_file.txt")],
52+
type: .executable
53+
),
54+
TargetDescription(
55+
name: "lib",
56+
dependencies: [],
57+
resources: [.init(rule: .copy, path: "Resources/some_file.txt")]
58+
),
4359
TargetDescription(name: "plugin", type: .plugin, pluginCapability: .buildTool)
4460
]),
4561
],
@@ -67,21 +83,29 @@ final class SourceKitLSPAPITests: XCTestCase {
6783
graph: graph,
6884
partialArguments: [
6985
"-module-name", "exe",
86+
"-package-name", "pkg",
7087
"-emit-dependencies",
7188
"-emit-module",
72-
"-emit-module-path", "/path/to/build/\(plan.destinationBuildParameters.triple)/debug/exe.build/exe.swiftmodule"
89+
"-emit-module-path", "/path/to/build/\(plan.destinationBuildParameters.triple)/debug/Modules/exe.swiftmodule"
7390
],
91+
resources: [.init(filePath: "/Pkg/Sources/exe/Resources/some_file.txt")],
92+
ignoredFiles: [.init(filePath: "/Pkg/Sources/exe/exe.docc")],
93+
otherFiles: [.init(filePath: "/Pkg/Sources/exe/README.md")],
7494
isPartOfRootPackage: true
7595
)
7696
try description.checkArguments(
7797
for: "lib",
7898
graph: graph,
7999
partialArguments: [
80100
"-module-name", "lib",
101+
"-package-name", "pkg",
81102
"-emit-dependencies",
82103
"-emit-module",
83104
"-emit-module-path", "/path/to/build/\(plan.destinationBuildParameters.triple)/debug/Modules/lib.swiftmodule"
84105
],
106+
resources: [.init(filePath: "/Pkg/Sources/lib/Resources/some_file.txt")],
107+
ignoredFiles: [.init(filePath: "/Pkg/Sources/lib/lib.docc")],
108+
otherFiles: [.init(filePath: "/Pkg/Sources/lib/README.md")],
85109
isPartOfRootPackage: true
86110
)
87111
try description.checkArguments(
@@ -238,18 +262,25 @@ extension SourceKitLSPAPI.BuildDescription {
238262
for targetName: String,
239263
graph: ModulesGraph,
240264
partialArguments: [String],
265+
resources: [URL] = [],
266+
ignoredFiles: [URL] = [],
267+
otherFiles: [URL] = [],
241268
isPartOfRootPackage: Bool,
242269
destination: BuildParameters.Destination = .target
243270
) throws -> Bool {
244271
let target = try XCTUnwrap(graph.module(for: targetName))
245272
let buildTarget = try XCTUnwrap(self.getBuildTarget(for: target, destination: destination))
246273

247-
guard let file = buildTarget.sources.first else {
248-
XCTFail("build target \(targetName) contains no files")
274+
XCTAssertEqual(buildTarget.resources, resources, "build target \(targetName) contains unexpected resource files")
275+
XCTAssertEqual(buildTarget.ignored, ignoredFiles, "build target \(targetName) contains unexpected ignored files")
276+
XCTAssertEqual(buildTarget.others, otherFiles, "build target \(targetName) contains unexpected other files")
277+
278+
guard let source = buildTarget.sources.first else {
279+
XCTFail("build target \(targetName) contains no source files")
249280
return false
250281
}
251282

252-
let arguments = try buildTarget.compileArguments(for: file)
283+
let arguments = try buildTarget.compileArguments(for: source)
253284
let result = arguments.contains(partialArguments)
254285

255286
XCTAssertTrue(result, "could not match \(partialArguments) to actual arguments \(arguments)")

0 commit comments

Comments
 (0)