Skip to content

Commit 5d108b7

Browse files
Restore per-class and android resource tracking that got lost with K2
1 parent 08fee50 commit 5d108b7

File tree

6 files changed

+69
-16
lines changed

6 files changed

+69
-16
lines changed

src/main/kotlin/io/bazel/kotlin/plugin/jdeps/BaseJdepsGenExtension.kt

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,47 @@
11
package io.bazel.kotlin.plugin.jdeps
22

3+
import com.google.common.io.ByteStreams
34
import com.google.devtools.build.lib.view.proto.Deps
5+
import com.google.protobuf.ByteString
46
import io.bazel.kotlin.builder.utils.jars.JarOwner
57
import org.jetbrains.kotlin.config.CompilerConfiguration
68
import java.io.BufferedOutputStream
79
import java.io.File
810
import java.nio.file.Paths
11+
import java.security.MessageDigest
12+
import java.util.jar.JarFile
13+
import java.util.stream.Collectors
914

1015
abstract class BaseJdepsGenExtension(
1116
protected val configuration: CompilerConfiguration,
1217
) {
1318
protected fun onAnalysisCompleted(
1419
explicitClassesCanonicalPaths: Set<String>,
1520
implicitClassesCanonicalPaths: Set<String>,
21+
usedResources: Set<String>,
1622
) {
1723
val directDeps = configuration.getList(JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES)
1824
val targetLabel = configuration.getNotNull(JdepsGenConfigurationKeys.TARGET_LABEL)
1925
val explicitDeps = createDepsMap(explicitClassesCanonicalPaths)
2026

21-
doWriteJdeps(directDeps, targetLabel, explicitDeps, implicitClassesCanonicalPaths)
27+
doWriteJdeps(directDeps, targetLabel, explicitDeps, implicitClassesCanonicalPaths, usedResources)
2228

2329
doStrictDeps(configuration, targetLabel, directDeps, explicitDeps)
2430
}
2531

32+
/**
33+
* Compute hash of internal jar class ABI definition.
34+
*/
35+
protected fun getHashFromJarEntry(
36+
jarPath: String,
37+
internalPath: String,
38+
): ByteArray {
39+
val jarFile = JarFile(jarPath)
40+
val entry = jarFile.getEntry(internalPath)
41+
val bytes = ByteStreams.toByteArray(jarFile.getInputStream(entry))
42+
return MessageDigest.getInstance("SHA-256").digest(bytes)
43+
}
44+
2645
/**
2746
* Returns a map of jars to classes loaded from those jars.
2847
*/
@@ -43,7 +62,10 @@ abstract class BaseJdepsGenExtension(
4362
targetLabel: String,
4463
explicitDeps: Map<String, List<String>>,
4564
implicitClassesCanonicalPaths: Set<String>,
65+
usedResources: Set<String>,
4666
) {
67+
val trackClassUsage = configuration.getNotNull(JdepsGenConfigurationKeys.TRACK_CLASS_USAGE).equals("on")
68+
val trackResourceUsage = configuration.getNotNull(JdepsGenConfigurationKeys.TRACK_RESOURCE_USAGE).equals("on")
4769
val implicitDeps = createDepsMap(implicitClassesCanonicalPaths)
4870

4971
// Build and write out deps.proto
@@ -53,10 +75,26 @@ abstract class BaseJdepsGenExtension(
5375
rootBuilder.success = true
5476
rootBuilder.ruleLabel = targetLabel
5577

56-
explicitDeps.forEach { (jarPath, _) ->
78+
explicitDeps.toSortedMap().forEach { (jarPath, usedClasses) ->
5779
val dependency = Deps.Dependency.newBuilder()
5880
dependency.kind = Deps.Dependency.Kind.EXPLICIT
5981
dependency.path = jarPath
82+
83+
if (trackClassUsage) {
84+
// Add tracked classes and their (compile time) hash into final output, as needed for
85+
// compilation avoidance.
86+
usedClasses.stream().sorted().collect(Collectors.toList()).forEach { it ->
87+
val name = it.replace(".class", "").replace("/", ".")
88+
val hash = ByteString.copyFrom(getHashFromJarEntry(jarPath, it))
89+
val usedClass: Deps.UsedClass = Deps.UsedClass.newBuilder()
90+
.setFullyQualifiedName(name)
91+
.setInternalPath(it)
92+
.setHash(hash)
93+
.build()
94+
dependency.addUsedClasses(usedClass)
95+
}
96+
}
97+
6098
rootBuilder.addDependency(dependency)
6199
}
62100

@@ -67,6 +105,12 @@ abstract class BaseJdepsGenExtension(
67105
rootBuilder.addDependency(dependency)
68106
}
69107

108+
if (trackResourceUsage) {
109+
usedResources.sorted().forEach { resource ->
110+
rootBuilder.addUsedResources(resource)
111+
}
112+
}
113+
70114
BufferedOutputStream(File(jdepsOutput).outputStream()).use {
71115
it.write(rootBuilder.buildSorted().toByteArray())
72116
}

src/main/kotlin/io/bazel/kotlin/plugin/jdeps/JdepsGenExtension.kt

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ class JdepsGenExtension(
377377
bindingTrace: BindingTrace,
378378
files: Collection<KtFile>,
379379
): AnalysisResult? {
380-
onAnalysisCompleted(explicitClassesCanonicalPaths, implicitClassesCanonicalPaths)
380+
onAnalysisCompleted(explicitClassesCanonicalPaths, implicitClassesCanonicalPaths, usedResources)
381381

382382
return super.analysisCompleted(project, module, bindingTrace, files)
383383
}
@@ -454,19 +454,6 @@ class JdepsGenExtension(
454454
}
455455
}
456456

457-
/**
458-
* Compute hash of internal jar class ABI definition.
459-
*/
460-
private fun getHashFromJarEntry(
461-
jarPath: String,
462-
internalPath: String,
463-
): ByteArray {
464-
val jarFile = JarFile(jarPath)
465-
val entry = jarFile.getEntry(internalPath)
466-
val bytes = ByteStreams.toByteArray(jarFile.getInputStream(entry))
467-
return MessageDigest.getInstance("SHA-256").digest(bytes)
468-
}
469-
470457
private fun doStrictDeps(
471458
compilerConfiguration: CompilerConfiguration,
472459
targetLabel: String,

src/main/kotlin/io/bazel/kotlin/plugin/jdeps/k2/ClassUsageRecorder.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ private const val ANONYMOUS = "<anonymous>"
2020
class ClassUsageRecorder(
2121
internal val explicitClassesCanonicalPaths: MutableSet<String> = mutableSetOf(),
2222
internal val implicitClassesCanonicalPaths: MutableSet<String> = mutableSetOf(),
23+
internal val usedResources: MutableSet<String> = mutableSetOf(),
2324
private val seen: MutableSet<ClassId> = mutableSetOf(),
2425
private val results: MutableMap<String, SortedSet<String>> = sortedMapOf(),
2526
private val rootPath: String = Paths.get("").toAbsolutePath().toString() + "/",
@@ -99,6 +100,10 @@ class ClassUsageRecorder(
99100
addFile(binaryClass, isExplicit)
100101
}
101102

103+
internal fun recordResource(resourceId: String) {
104+
usedResources.add(resourceId)
105+
}
106+
102107
private fun addFile(
103108
path: String,
104109
isExplicit: Boolean,

src/main/kotlin/io/bazel/kotlin/plugin/jdeps/k2/JdepsGenExtension2.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ internal class JdepsGenExtension2(
1414
onAnalysisCompleted(
1515
classUsageRecorder.explicitClassesCanonicalPaths,
1616
classUsageRecorder.implicitClassesCanonicalPaths,
17+
classUsageRecorder.usedResources,
1718
)
1819
}
1920
}

src/main/kotlin/io/bazel/kotlin/plugin/jdeps/k2/JdepsK2Utils.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.bazel.kotlin.plugin.jdeps.k2
22

33
import org.jetbrains.kotlin.descriptors.SourceElement
4+
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
5+
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
46
import org.jetbrains.kotlin.fir.java.JavaBinarySourceElement
57
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
68
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement

src/main/kotlin/io/bazel/kotlin/plugin/jdeps/k2/checker/expression/QualifiedAccessChecker.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
88
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirQualifiedAccessExpressionChecker
99
import org.jetbrains.kotlin.fir.declarations.FirConstructor
1010
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
11+
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
1112
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
1213
import org.jetbrains.kotlin.fir.expressions.arguments
1314
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
1415
import org.jetbrains.kotlin.fir.references.toResolvedFunctionSymbol
1516
import org.jetbrains.kotlin.fir.types.isExtensionFunctionType
1617
import org.jetbrains.kotlin.fir.types.isUnit
1718
import org.jetbrains.kotlin.fir.types.resolvedType
19+
import org.jetbrains.kotlin.KtSourceElement
1820

1921
internal class QualifiedAccessChecker(
2022
private val classUsageRecorder: ClassUsageRecorder,
@@ -66,5 +68,17 @@ internal class QualifiedAccessChecker(
6668
classUsageRecorder.recordConeType(it, context, isExplicit = false)
6769
}
6870
}
71+
72+
// track android resources
73+
getResourceName(expression)?.let {
74+
classUsageRecorder.recordResource(it)
75+
}
76+
}
77+
78+
private fun getResourceName(expression: FirQualifiedAccessExpression): String? {
79+
return (expression as? FirPropertyAccessExpression)
80+
?.source
81+
?.getElementTextInContextForDebug()
82+
?.takeIf { ".R." in it || it.startsWith("R.") }
6983
}
7084
}

0 commit comments

Comments
 (0)