From 892733995b4494b1409b448bad4afe4758bb484f Mon Sep 17 00:00:00 2001 From: Evgeny Veretennikov Date: Mon, 1 Dec 2025 17:27:53 +0300 Subject: [PATCH] Fix transitive proto_library dependencies for scala_proto_library Resolves issue where imports from transitive proto_library dependencies were not resolved in IntelliJ. The plugin now correctly adds scalapb JAR files from transitive proto_library dependencies to the module classpath, enabling proper import resolution for scala_proto_library targets with nested proto dependencies. Fixes [BAZEL-2695](https://youtrack.jetbrains.com/issue/BAZEL-2695) --- .../mapper/normal/AspectBazelProjectMapper.kt | 110 +++++++++++++++--- 1 file changed, 96 insertions(+), 14 deletions(-) diff --git a/plugin-bazel/src/main/kotlin/org/jetbrains/bazel/sync/workspace/mapper/normal/AspectBazelProjectMapper.kt b/plugin-bazel/src/main/kotlin/org/jetbrains/bazel/sync/workspace/mapper/normal/AspectBazelProjectMapper.kt index ed516d1fbb..dee79f288e 100644 --- a/plugin-bazel/src/main/kotlin/org/jetbrains/bazel/sync/workspace/mapper/normal/AspectBazelProjectMapper.kt +++ b/plugin-bazel/src/main/kotlin/org/jetbrains/bazel/sync/workspace/mapper/normal/AspectBazelProjectMapper.kt @@ -129,11 +129,11 @@ class AspectBazelProjectMapper( } val interfacesAndBinariesFromTargetsToImport = measure("Collect interfaces and classes from targets to import") { - collectInterfacesAndClasses(targetsToImport) + collectInterfacesAndClasses(targetsToImport, allTargets) } val outputJarsLibraries = measure("Create output jars libraries") { - calculateOutputJarsLibraries(targetsToImport) + calculateOutputJarsLibraries(targetsToImport, allTargets) } val annotationProcessorLibraries = measure("Create AP libraries") { @@ -163,7 +163,7 @@ class AspectBazelProjectMapper( } val librariesFromDepsAndTargets = measure("Libraries from targets and deps") { - createLibraries(targetsAsLibraries, repoMapping) + + createLibraries(targetsAsLibraries, repoMapping, allTargets) + librariesFromDeps.values .flatten() .distinct() @@ -176,6 +176,7 @@ class AspectBazelProjectMapper( librariesFromDeps, librariesFromDepsAndTargets, interfacesAndBinariesFromTargetsToImport, + allTargets, ) } val librariesToImport = @@ -256,6 +257,7 @@ class AspectBazelProjectMapper( private fun calculateOutputJarsLibraries( targetsToImport: Sequence, + allTargets: Map, ): Map> = targetsToImport .filter { shouldCreateOutputJarsLibrary(it) } @@ -265,6 +267,7 @@ class AspectBazelProjectMapper( target, onlyOutputJars = true, isInternalTarget = true, + allTargets, )?.let { library -> target.label() to listOf(library) } @@ -456,9 +459,10 @@ class AspectBazelProjectMapper( libraryDependencies: Map>, librariesToImport: Map, interfacesAndBinariesFromTargetsToImport: Map>, + allTargets: Map, ): Map> { val targetsToJdepsJars = - getAllJdepsDependencies(targetsToImport, libraryDependencies, librariesToImport) + getAllJdepsDependencies(targetsToImport, libraryDependencies, librariesToImport, allTargets) val libraryNameToLibraryValueMap = HashMap() return targetsToJdepsJars.mapValues { target -> val interfacesAndBinariesFromTarget = @@ -490,6 +494,7 @@ class AspectBazelProjectMapper( targetsToImport: Map, libraryDependencies: Map>, librariesToImport: Map, + allTargets: Map, ): Map> { val jdepsJars = withContext(Dispatchers.IO) { @@ -521,6 +526,7 @@ class AspectBazelProjectMapper( librariesToImport, outputJarsFromTransitiveDepsCache, allJdepsJars, + allTargets, ) targetLabel to jarsFromJdeps - transitiveJdepsJars } @@ -537,10 +543,11 @@ class AspectBazelProjectMapper( librariesToImport: Map, outputJarsFromTransitiveDepsCache: ConcurrentHashMap>, allJdepsJars: Set, + allTargets: Map, ): Set = outputJarsFromTransitiveDepsCache.getOrPut(targetOrLibrary) { val jarsFromTargets = - targetsToImport[targetOrLibrary]?.let { getTargetOutputJarsSet(it) + getTargetInterfaceJarsSet(it) }.orEmpty() + targetsToImport[targetOrLibrary]?.let { getTargetOutputJarsSet(it, allTargets) + getTargetInterfaceJarsSet(it) }.orEmpty() val jarsFromLibraries = librariesToImport[targetOrLibrary]?.let { it.outputs + it.interfaceJars }.orEmpty() val outputJars = @@ -563,6 +570,7 @@ class AspectBazelProjectMapper( librariesToImport, outputJarsFromTransitiveDepsCache, allJdepsJars, + allTargets, ) } outputJars @@ -630,7 +638,11 @@ class AspectBazelProjectMapper( ) } - private suspend fun createLibraries(targets: Map, repoMapping: RepoMapping): Map = + private suspend fun createLibraries( + targets: Map, + repoMapping: RepoMapping, + allTargets: Map, + ): Map = withContext(Dispatchers.Default) { targets .map { (targetId, targetInfo) -> @@ -640,6 +652,7 @@ class AspectBazelProjectMapper( targetInfo = targetInfo, onlyOutputJars = false, isInternalTarget = isTargetTreatedAsInternal(targetId.assumeResolved(), repoMapping), + allTargets = allTargets, )?.let { library -> targetId to library } @@ -654,8 +667,9 @@ class AspectBazelProjectMapper( targetInfo: TargetInfo, onlyOutputJars: Boolean, isInternalTarget: Boolean, + allTargets: Map, ): Library? { - val outputs = getTargetOutputJarPaths(targetInfo) + getIntellijPluginJars(targetInfo) + val outputs = getTargetOutputJarPaths(targetInfo, allTargets) + getIntellijPluginJars(targetInfo) val sources = getSourceJarPaths(targetInfo) val interfaceJars = getTargetInterfaceJarsSet(targetInfo).toSet() val dependencies: List = if (!onlyOutputJars) targetInfo.dependenciesList else emptyList() @@ -700,8 +714,8 @@ class AspectBazelProjectMapper( private fun List.resolvePaths() = map { bazelPathsResolver.resolve(it) }.toSet() - private fun getTargetOutputJarPaths(targetInfo: TargetInfo) = - getTargetOutputJarsList(targetInfo) + private fun getTargetOutputJarPaths(targetInfo: TargetInfo, allTargets: Map) = + getTargetOutputJarsList(targetInfo, allTargets) .toSet() private fun getIntellijPluginJars(targetInfo: TargetInfo): Set { @@ -718,13 +732,21 @@ class AspectBazelProjectMapper( .flatMap { it.sourceJarsList } .resolvePaths() - private fun getTargetOutputJarsSet(targetInfo: TargetInfo) = getTargetOutputJarsList(targetInfo).toSet() + private fun getTargetOutputJarsSet(targetInfo: TargetInfo, allTargets: Map) = + getTargetOutputJarsList(targetInfo, allTargets).toSet() - private fun getTargetOutputJarsList(targetInfo: TargetInfo) = - targetInfo.jvmTargetInfo.jarsList + private fun getTargetOutputJarsList(targetInfo: TargetInfo, allTargets: Map): List { + val directJars = targetInfo.jvmTargetInfo.jarsList .flatMap { it.binaryJarsList } .map { bazelPathsResolver.resolve(it) } + return if (targetInfo.kind == "scala_proto_library") { + directJars + getTransitiveProtoScalapbJars(targetInfo, allTargets) + } else { + directJars + } + } + private fun getTargetInterfaceJarsSet(targetInfo: TargetInfo) = getTargetInterfaceJarsList(targetInfo).toSet() private fun getTargetInterfaceJarsList(targetInfo: TargetInfo) = @@ -732,11 +754,71 @@ class AspectBazelProjectMapper( .flatMap { it.interfaceJarsList } .map { bazelPathsResolver.resolve(it) } - private fun collectInterfacesAndClasses(targets: Sequence) = + /** + * Finds scalapb JAR files for transitive proto_library dependencies of a scala_proto_library. + * This ensures that imports from transitive proto dependencies are resolved correctly. + */ + private fun getTransitiveProtoScalapbJars(scalaProtoTarget: TargetInfo, allTargets: Map): List { + val transitiveProtoTargets = findTransitiveProtoLibraries(scalaProtoTarget, allTargets) + return transitiveProtoTargets.mapNotNull { protoTarget -> + findScalapbJarForProtoTarget(protoTarget) + } + } + + /** + * Finds all transitive proto_library dependencies of a scala_proto_library target. + * Excludes direct scala_proto_library dependencies to avoid duplicating JARs that are already + * included by the plugin's standard processing. + */ + private fun findTransitiveProtoLibraries(target: TargetInfo, allTargets: Map): Set { + val visitedTargets = mutableSetOf