Skip to content

Commit a265508

Browse files
authored
Fix nested top-level apps not being parsed properly (#136)
1 parent fd10cfd commit a265508

File tree

15 files changed

+575
-452
lines changed

15 files changed

+575
-452
lines changed

Example/HelloWorld/BUILD

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,19 +193,21 @@ ios_application(
193193
families = ["iphone", "ipad"],
194194
infoplists = ["Resources/Info.plist"],
195195
minimum_os_version = IOS_MINIMUM_OS_VERSION,
196+
watch_application = ":HelloWorldWatchApp",
196197
deps = [":HelloWorldLib"],
197198
)
198199

199200
watchos_application(
200201
name = "HelloWorldWatchApp",
201202
bundle_id = "com.example.HelloWorld.Watch",
202-
extensions = [":HelloWorldWatchExtension"],
203+
extension = ":HelloWorldWatchExtension",
203204
infoplists = ["Resources/WatchApp-Info.plist"],
204205
minimum_os_version = WATCHOS_MINIMUM_OS_VERSION,
205206
)
206207

207208
watchos_extension(
208209
name = "HelloWorldWatchExtension",
210+
application_extension = True,
209211
bundle_id = "com.example.HelloWorld.Watch.extension",
210212
infoplists = ["Resources/WatchExt-Info.plist"],
211213
minimum_os_version = WATCHOS_MINIMUM_OS_VERSION,

Sources/SourceKitBazelBSP/RequestHandlers/BuildTargets/BazelTargetGraphReport.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,23 @@ struct BazelTargetGraphReport: Codable, Equatable {
2626
struct TopLevelTarget: Codable, Equatable {
2727
let label: String
2828
let ruleType: String
29-
let platform: String
30-
let minimumOsVersion: String
31-
let cpuArch: String
3229
let isTest: Bool
30+
let configId: UInt32
3331
}
3432

3533
struct DependencyTarget: Codable, Equatable {
3634
let label: String
37-
let parents: [String]
35+
let configId: UInt32
36+
}
37+
38+
struct Configuration: Codable, Equatable {
39+
let id: UInt32
40+
let platform: String
41+
let minimumOsVersion: String
42+
let cpuArch: String
3843
}
3944

4045
let topLevelTargets: [TopLevelTarget]
4146
let dependencyTargets: [DependencyTarget]
47+
let configurations: [Configuration]
4248
}

Sources/SourceKitBazelBSP/RequestHandlers/BuildTargets/BazelTargetQuerier.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,7 @@ final class BazelTargetQuerier {
9494
dependencyKindsFilter.append(contentsOf: testBundleRules)
9595

9696
let topLevelKindsFilter = supportedTopLevelRuleTypes.map { $0.rawValue }
97-
98-
// Collect the top-level targets -> collect these targets' dependencies
99-
let providedTargetsQuerySet = "set(\(userProvidedTargets.joined(separator: " ")))"
97+
let topLevelDepsFilter = Self.queryDepsString(forTargets: userProvidedTargets)
10098

10199
// Build exclusion clauses if filters are provided
102100
let topLevelExclusions = config.baseConfig.topLevelTargetsToExclude
@@ -110,7 +108,7 @@ final class BazelTargetQuerier {
110108
? "" : " except set(\(dependencyExclusions.joined(separator: " ")))"
111109

112110
let topLevelTargetsQuery = """
113-
let topLevelTargets = kind("\(topLevelKindsFilter.joined(separator: "|"))", \(providedTargetsQuerySet))\(topLevelExceptClause) in \
111+
let topLevelTargets = kind("\(topLevelKindsFilter.joined(separator: "|"))", \(topLevelDepsFilter))\(topLevelExceptClause) in \
114112
$topLevelTargets \
115113
union \
116114
(kind("\(dependencyKindsFilter.joined(separator: "|"))", deps($topLevelTargets))\(dependencyExceptClause))

Sources/SourceKitBazelBSP/RequestHandlers/BuildTargets/BazelTargetQuerierParser.swift

Lines changed: 131 additions & 141 deletions
Large diffs are not rendered by default.

Sources/SourceKitBazelBSP/RequestHandlers/BuildTargets/BazelTargetStore.swift

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ enum BazelTargetStoreError: Error, LocalizedError {
4545
case unableToMapBazelLabelToParents(String)
4646
case unableToMapBazelLabelToTopLevelRuleType(String)
4747
case unableToMapBazelLabelToTopLevelConfig(String)
48+
case unableToMapBazelLabelToParentConfig(String)
49+
case unableToMapConfigToTopLevelLabels(UInt32)
4850
case noCachedAquery
4951

5052
var errorDescription: String? {
@@ -57,6 +59,10 @@ enum BazelTargetStoreError: Error, LocalizedError {
5759
return "Unable to map '\(label)' to its top-level rule type"
5860
case .unableToMapBazelLabelToTopLevelConfig(let label):
5961
return "Unable to map '\(label)' to its top-level configuration"
62+
case .unableToMapBazelLabelToParentConfig(let label):
63+
return "Unable to map '\(label)' to its parent configuration"
64+
case .unableToMapConfigToTopLevelLabels(let config):
65+
return "Unable to map configuration '\(config)' to its top-level labels"
6066
case .noCachedAquery:
6167
return "No cached aquery result found in the store."
6268
}
@@ -126,14 +132,6 @@ final class BazelTargetStoreImpl: BazelTargetStore, @unchecked Sendable {
126132
return bspURIs
127133
}
128134

129-
/// Retrieves the list of top-level apps that a given Bazel target label belongs to.
130-
func bazelLabelToParents(forBazelLabel label: String) throws -> [String] {
131-
guard let parents = cqueryResult?.bazelLabelToParentsMap[label] else {
132-
throw BazelTargetStoreError.unableToMapBazelLabelToParents(label)
133-
}
134-
return parents
135-
}
136-
137135
/// Retrieves the top-level rule type for a given Bazel **top-level** target label.
138136
func topLevelRuleType(forBazelLabel label: String) throws -> TopLevelRuleType {
139137
guard let ruleType = cqueryResult?.topLevelLabelToRuleMap[label] else {
@@ -150,20 +148,33 @@ final class BazelTargetStoreImpl: BazelTargetStore, @unchecked Sendable {
150148
return config
151149
}
152150

151+
/// Retrieves the configuration for a given Bazel target label.
152+
func parentConfig(forBazelLabel label: String) throws -> UInt32 {
153+
guard let config = cqueryResult?.bazelLabelToParentConfigMap[label] else {
154+
throw BazelTargetStoreError.unableToMapBazelLabelToParentConfig(label)
155+
}
156+
return config
157+
}
158+
159+
/// Retrieves the list of top-level labels for a given configuration.
160+
func topLevelLabels(forConfig config: UInt32) throws -> [String] {
161+
guard let labels = cqueryResult?.configurationToTopLevelLabelsMap[config] else {
162+
throw BazelTargetStoreError.unableToMapConfigToTopLevelLabels(config)
163+
}
164+
return labels
165+
}
166+
153167
/// Provides the bazel label containing **platform information** for a given BSP URI.
154168
/// This is used to determine the correct set of compiler flags for the target / platform combo.
155169
func platformBuildLabelInfo(forBSPURI uri: URI) throws -> BazelTargetPlatformInfo {
156170
let bazelLabel = try bazelTargetLabel(forBSPURI: uri)
157-
let parents = try bazelLabelToParents(forBazelLabel: bazelLabel)
171+
let configId = try parentConfig(forBazelLabel: bazelLabel)
172+
let parents = try topLevelLabels(forConfig: configId)
158173
// FIXME: When a target can compile to multiple platforms, the way Xcode handles it is by selecting
159174
// the one matching your selected simulator in the IDE. We don't have any sort of special IDE integration
160175
// at the moment, so for now we just select the first parent.
176+
// We are also not processing the different variants at all (see FIXME in BazelTargetQuerierParser.swift).
161177
let parentToUse = parents[0]
162-
if parents.count > 1 {
163-
logger.warning(
164-
"Target \(uri.description, privacy: .public) has multiple top-level parents; will pick the first one: \(parentToUse, privacy: .public)"
165-
)
166-
}
167178
let rule = try topLevelRuleType(forBazelLabel: parentToUse)
168179
let config = try topLevelConfigInfo(forBazelLabel: parentToUse)
169180
return BazelTargetPlatformInfo(
@@ -220,7 +231,7 @@ final class BazelTargetStoreImpl: BazelTargetStore, @unchecked Sendable {
220231

221232
reportQueue.async { [weak self] in
222233
guard let self = self else { return }
223-
let outputPath = self.initializedConfig.outputPath
234+
let outputPath: String = self.initializedConfig.outputPath
224235
let fileName = "sourcekit-bazel-bsp-graph.json"
225236
self.writeReport(toPath: outputPath + "/" + fileName)
226237
}
@@ -253,29 +264,38 @@ extension BazelTargetStoreImpl {
253264
private func generateGraphReport() throws -> BazelTargetGraphReport {
254265
logger.info("Generating graph report")
255266
var reportTopLevel: [BazelTargetGraphReport.TopLevelTarget] = []
267+
var reportConfigurations: [UInt32: BazelTargetGraphReport.Configuration] = [:]
256268
let topLevelTargets = cqueryResult?.topLevelTargets ?? []
257269
for (label, ruleType) in topLevelTargets {
258270
let topLevelConfig = try topLevelConfigInfo(forBazelLabel: label)
271+
let configId = try parentConfig(forBazelLabel: label)
259272
reportTopLevel.append(
260273
.init(
261274
label: label,
262275
ruleType: ruleType.rawValue,
276+
isTest: ruleType.testBundleRule != nil,
277+
configId: configId
278+
)
279+
)
280+
reportConfigurations[configId] = .init(
281+
.init(
282+
id: configId,
263283
platform: topLevelConfig.platform,
264284
minimumOsVersion: topLevelConfig.minimumOsVersion,
265-
cpuArch: topLevelConfig.cpuArch,
266-
isTest: ruleType.testBundleRule != nil
285+
cpuArch: topLevelConfig.cpuArch
267286
)
268287
)
269288
}
270289
var reportDependencies: [BazelTargetGraphReport.DependencyTarget] = []
271290
let dependencyTargets = cqueryResult?.buildTargets.compactMap { $0.displayName } ?? []
272291
for label in dependencyTargets {
273-
let parents = try bazelLabelToParents(forBazelLabel: label)
274-
reportDependencies.append(.init(label: label, parents: parents))
292+
let configId = try parentConfig(forBazelLabel: label)
293+
reportDependencies.append(.init(label: label, configId: configId))
275294
}
276295
return BazelTargetGraphReport(
277296
topLevelTargets: reportTopLevel,
278-
dependencyTargets: reportDependencies
297+
dependencyTargets: reportDependencies,
298+
configurations: reportConfigurations.values.sorted(by: { $0.id < $1.id })
279299
)
280300
}
281301
}

Sources/SourceKitBazelBSP/RequestHandlers/BuildTargets/BuildTargetsHandler.swift

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,6 @@ final class BuildTargetsHandler {
5757
reply(.success(WorkspaceBuildTargetsResponse(targets: [])))
5858
}
5959
let result = try targetStore.fetchTargets()
60-
logger.debug("Found \(result.count, privacy: .public) targets")
61-
logger.logFullObjectInMultipleLogMessages(
62-
level: .debug,
63-
header: "Target list",
64-
result.map { $0.id.uri.stringValue }.joined(separator: ", "),
65-
)
6660
return result
6761
}
6862
connection?.finishTask(id: taskId, status: .ok)

Sources/SourceKitBazelBSP/RequestHandlers/BuildTargets/ProcessedCqueryResult.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@ struct ProcessedCqueryResult {
3030
let bspURIsToSrcsMap: [URI: SourcesItem]
3131
let srcToBspURIsMap: [URI: [URI]]
3232
let topLevelLabelToRuleMap: [String: TopLevelRuleType]
33-
let bazelLabelToParentsMap: [String: [String]]
33+
let configurationToTopLevelLabelsMap: [UInt32: [String]]
34+
let bazelLabelToParentConfigMap: [String: UInt32]
3435
}

Sources/SourceKitBazelBSP/RequestHandlers/BuildTargets/TopLevelRuleType.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ public enum TopLevelRuleType: String, CaseIterable, ExpressibleByArgument, Senda
5050
case visionosUiTest = "visionos_ui_test"
5151
case visionosBuildTest = "visionos_build_test"
5252

53+
/// The suffix that is added to the test rule name to get the bundle target name.
54+
/// e.g. HelloWorldTests -> HelloWorldTests.__internal__.__test_bundle
5355
static var testBundleRuleSuffix: String {
5456
return ".__internal__.__test_bundle"
5557
}

Sources/SourceKitBazelBSP/RequestHandlers/SKOptions/BazelTargetCompilerArgsExtractor.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,12 @@ extension BazelTargetCompilerArgsExtractor {
321321
continue
322322
}
323323

324+
// Indexing doesn't seem to like this attribute
325+
if arg == "-Xfrontend" && arg == "-const-gather-protocols-file" {
326+
index += 4
327+
continue
328+
}
329+
324330
// Skip -emit-const-values-path for now, this causes permission issues in bazel-out
325331
if arg == "-emit-const-values-path" {
326332
index += 2

Tests/BazelProtobufBindingsTests/BazelProtobufBindingsTests.swift

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,12 @@ import Testing
2626
struct BazelProtobufBindingsTests {
2727
@Test("parses action graph from aquery protobuf output")
2828
func testBazelProtobuf_readBinaryData() throws {
29-
guard let url = Bundle.module.url(forResource: "actions", withExtension: "pb") else {
30-
Issue.record("actions.pb is not found in Resouces.")
31-
return
32-
}
33-
34-
guard let data = try? Data(contentsOf: url) else {
35-
Issue.record("Fail to read actions.pb at url: \(url.path())")
36-
return
37-
}
38-
39-
guard let actionGraph = try? BazelProtobufBindings.parseActionGraph(data: data) else {
40-
Issue.record("Fail to parse actions.pb")
41-
return
42-
}
29+
let url = try #require(
30+
Bundle.module.url(forResource: "actions", withExtension: "pb"),
31+
"actions.pb is not found in Resources."
32+
)
33+
let data = try Data(contentsOf: url)
34+
let actionGraph = try BazelProtobufBindings.parseActionGraph(data: data)
4335

4436
let expected = [
4537
"//HelloWorld:HelloWorldLib",
@@ -55,23 +47,15 @@ struct BazelProtobufBindingsTests {
5547

5648
@Test("testing compiler flags from action graph")
5749
func testBazelProtobuf_compilerArguments() throws {
58-
guard let url = Bundle.module.url(forResource: "actions", withExtension: "pb") else {
59-
Issue.record("actions.pb is not found in Resouces.")
60-
return
61-
}
62-
63-
guard let data = try? Data(contentsOf: url) else {
64-
Issue.record("Fail to read actions.pb at url: \(url.path())")
65-
return
66-
}
67-
68-
guard let actionGraph = try? BazelProtobufBindings.parseActionGraph(data: data) else {
69-
Issue.record("Fail to parse actions.pb")
70-
return
71-
}
50+
let url = try #require(
51+
Bundle.module.url(forResource: "actions", withExtension: "pb"),
52+
"actions.pb is not found in Resources."
53+
)
54+
let data = try Data(contentsOf: url)
55+
let actionGraph = try BazelProtobufBindings.parseActionGraph(data: data)
7256

7357
// //HelloWorld:TodoModels -> targetID: 1
74-
guard let action = actionGraph.actions.first(where: { $0.targetID == 1 }) else { return }
58+
let action = try #require(actionGraph.actions.first(where: { $0.targetID == 1 }))
7559

7660
let actual = action.arguments
7761
let expected = [

0 commit comments

Comments
 (0)