Skip to content
Open
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
4 changes: 2 additions & 2 deletions docs/kotlin.md
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,8 @@ Call this in the WORKSPACE file to setup the Kotlin rules.
| <a id="kotlin_repositories-is_bzlmod"></a>is_bzlmod | <p align="center"> - </p> | `False` |
| <a id="kotlin_repositories-compiler_repository_name"></a>compiler_repository_name | for the kotlinc compiler repository. | `"com_github_jetbrains_kotlin"` |
| <a id="kotlin_repositories-ksp_repository_name"></a>ksp_repository_name | <p align="center"> - </p> | `"com_github_google_ksp"` |
| <a id="kotlin_repositories-compiler_release"></a>compiler_release | version provider from versions.bzl. | `struct(sha256 = "1ba08a8b45da99339a0601134cc037b54cf85e9bc0edbe76dcbd27c2d684a977", url_templates = ["https://github.com/JetBrains/kotlin/releases/download/v{version}/kotlin-compiler-{version}.zip"], version = "2.1.21")` |
| <a id="kotlin_repositories-ksp_compiler_release"></a>ksp_compiler_release | (internal) version provider from versions.bzl. | `struct(sha256 = "44e965bb067b2bb5cd9184dab2c3dea6e3eab747d341c07645bb4c88f09e49c8", url_templates = ["https://github.com/google/ksp/releases/download/{version}/artifacts.zip"], version = "2.1.21-2.0.1")` |
| <a id="kotlin_repositories-compiler_release"></a>compiler_release | version provider from versions.bzl. | `struct(sha256 = "81f0264c9073b5cbbdb3ff8418cf2c5dac076879fc156fa1a6462f5a5acc4420", url_templates = ["https://github.com/JetBrains/kotlin/releases/download/v{version}/kotlin-compiler-{version}.zip"], version = "2.2.20")` |
| <a id="kotlin_repositories-ksp_compiler_release"></a>ksp_compiler_release | (internal) version provider from versions.bzl. | `struct(sha256 = "91599210c8f332fe5d16dd5704821daf50f3e0d06c6a122fd895276f6e55b598", url_templates = ["https://github.com/google/ksp/releases/download/{version}/artifacts.zip"], version = "2.2.20-2.0.4")` |


<a id="versions.use_repository"></a>
Expand Down
12 changes: 3 additions & 9 deletions kotlin/compiler/compiler.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.

load("@com_github_jetbrains_kotlin//:artifacts.bzl", "KOTLINC_ARTIFACTS")
load("@com_github_jetbrains_kotlin//:artifacts.bzl", "KOTLINC_ARTIFACTS", _KOTLIN_STDLIBS = "KOTLIN_STDLIBS")
load("//kotlin:jvm.bzl", "kt_jvm_import")
load("//kotlin/internal:defs.bzl", _KT_COMPILER_REPO = "KT_COMPILER_REPO")

KOTLIN_STDLIBS = [
"//kotlin/compiler:annotations",
"//kotlin/compiler:kotlin-stdlib",
"//kotlin/compiler:kotlin-stdlib-jdk7",
"//kotlin/compiler:kotlin-stdlib-jdk8",
"//kotlin/compiler:kotlinx-coroutines-core-jvm",
"//kotlin/compiler:trove4j",
]
# Re-export KOTLIN_STDLIBS for use by other BUILD files
KOTLIN_STDLIBS = _KOTLIN_STDLIBS

def _import_artifacts(artifacts, rule_kind):
_import_labels(artifacts.plugin, rule_kind)
Expand Down
10 changes: 2 additions & 8 deletions src/main/kotlin/BUILD.release.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

load("@com_github_jetbrains_kotlin//:artifacts.bzl", "KOTLIN_STDLIBS")
load("@rules_java//java:defs.bzl", "java_binary", "java_import")

java_import(
Expand Down Expand Up @@ -78,14 +79,7 @@ java_binary(

java_binary(
name = "jdeps_merger",
data = [
"@com_github_jetbrains_kotlin//:annotations",
"@com_github_jetbrains_kotlin//:kotlin-stdlib",
"@com_github_jetbrains_kotlin//:kotlin-stdlib-jdk7",
"@com_github_jetbrains_kotlin//:kotlin-stdlib-jdk8",
"@com_github_jetbrains_kotlin//:kotlinx-coroutines-core-jvm",
"@com_github_jetbrains_kotlin//:trove4j",
],
data = KOTLIN_STDLIBS,
jvm_flags = [
"-XX:-MaxFDLimit",
],
Expand Down
5 changes: 4 additions & 1 deletion src/main/kotlin/bootstrap.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ def kt_bootstrap_library(name, deps = [], neverlink_deps = [], srcs = [], visibi
**kwargs
)

# Filter out compiler-specific kwargs that ktlint doesn't understand
ktlint_kwargs = {k: v for k, v in kwargs.items() if k not in ["kotlinc_opts"]}

_ktlint_test(
name = "%s_ktlint_test" % name,
srcs = srcs,
Expand All @@ -51,7 +54,7 @@ def kt_bootstrap_library(name, deps = [], neverlink_deps = [], srcs = [], visibi
visibility = ["//visibility:private"],
config = "//:ktlint_editorconfig",
tags = ["no-ide", "ktlint"],
**kwargs
**ktlint_kwargs
)

def kt_bootstrap_binary(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class KotlinJvmTaskExecutor

context.execute("compile classes") {
preprocessedTask.apply {
sequenceOf(
listOf(
runCatching {
context.execute("kotlinc") {
if (compileKotlin) {
Expand All @@ -80,6 +80,9 @@ class KotlinJvmTaskExecutor
inputs.directDependenciesList.forEach {
flag("direct_dependencies", it)
}
inputs.classpathList.forEach {
flag("full_classpath", it)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reasoning behind this change?

}
flag("strict_kotlin_deps", info.strictKotlinDeps)
}
}.given(outputs.jar)
Expand Down
10 changes: 2 additions & 8 deletions src/main/kotlin/io/bazel/kotlin/generate/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
load("//kotlin:jvm.bzl", "kt_jvm_binary", "kt_jvm_import", "kt_jvm_library")
load("//kotlin/compiler:compiler.bzl", _KOTLIN_STDLIBS = "KOTLIN_STDLIBS")

# Work around neverlink.
kt_jvm_import(
name = "kotlinc_jar",
jars = [
"@com_github_jetbrains_kotlin//:kotlin-compiler",
],
deps = [
"//kotlin/compiler:annotations",
"//kotlin/compiler:kotlin-stdlib",
"//kotlin/compiler:kotlin-stdlib-jdk7",
"//kotlin/compiler:kotlin-stdlib-jdk8",
"//kotlin/compiler:kotlinx-coroutines-core-jvm",
"//kotlin/compiler:trove4j",
],
deps = _KOTLIN_STDLIBS,
)

kt_jvm_library(
Expand Down
3 changes: 3 additions & 0 deletions src/main/kotlin/io/bazel/kotlin/plugin/jdeps/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ kt_bootstrap_library(
"k2/checker/declaration/*.kt",
"k2/checker/expression/*.kt",
]),
kotlinc_opts = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just convert this to an array type so that we aren't messing around with dict key,values like this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have any strong opinion about that

"-Xcontext-parameters": "",
},
visibility = ["//src:__subpackages__"],
deps = [
"//kotlin/compiler:kotlin-compiler",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,69 @@ abstract class BaseJdepsGenExtension(
) {
val directDeps = configuration.getList(JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES)
val targetLabel = configuration.getNotNull(JdepsGenConfigurationKeys.TARGET_LABEL)
val explicitDeps = createDepsMap(explicitClassesCanonicalPaths)
val fullClasspath = configuration.getList(JdepsGenConfigurationKeys.FULL_CLASSPATH)

doWriteJdeps(directDeps, targetLabel, explicitDeps, implicitClassesCanonicalPaths)
// Create mapping from canonical paths to original classpath paths
val canonicalToClasspath = createCanonicalToClasspathMap(fullClasspath)

val explicitDeps = createDepsMap(explicitClassesCanonicalPaths, canonicalToClasspath)

doWriteJdeps(
directDeps,
targetLabel,
explicitDeps,
implicitClassesCanonicalPaths,
canonicalToClasspath,
)

doStrictDeps(configuration, targetLabel, directDeps, explicitDeps)
}

/**
* Creates a mapping from canonical filesystem paths to original classpath paths.
* This ensures jdeps uses the same paths that were on the compiler's classpath.
* When multiple classpath entries point to the same canonical file, prefer runfiles paths.
*/
private fun createCanonicalToClasspathMap(classpathEntries: List<String>): Map<String, String> {
val mapping = mutableMapOf<String, String>()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these jdeps changes related to this supporting Kotlin 2.2 or is this fixing something independent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Supporting kotlin 2.2. I don't understand what exactly changed on kotlinc's side, but without these changes the tests fail


// Create canonical -> original mapping
// Process entries and prefer runfiles paths over execroot paths
classpathEntries.forEach { classpathPath ->
try {
val canonicalPath = File(classpathPath).canonicalPath
val existing = mapping[canonicalPath]
// Only update if no existing entry, or if current path is a runfiles path
// and existing is not
if (existing == null ||
(classpathPath.contains("/runfiles/") && !existing.contains("/runfiles/"))
) {
mapping[canonicalPath] = classpathPath
}
} catch (e: Exception) {
// If we can't resolve, just use the original path for both
mapping[classpathPath] = classpathPath
}
}
return mapping
}

/**
* Returns a map of jars to classes loaded from those jars.
* Uses the canonical-to-classpath mapping to preserve original classpath paths.
*/
private fun createDepsMap(classes: Set<String>): Map<String, List<String>> {
private fun createDepsMap(
classes: Set<String>,
canonicalToClasspath: Map<String, String>,
): Map<String, List<String>> {
val jarsToClasses = mutableMapOf<String, MutableList<String>>()
classes.forEach {
val parts = it.split("!/")
val jarPath = parts[0]
if (jarPath.endsWith(".jar")) {
jarsToClasses.computeIfAbsent(jarPath) { ArrayList() }.add(parts[1])
val canonicalJarPath = parts[0]
if (canonicalJarPath.endsWith(".jar")) {
// Map back to original classpath path
val classpathJarPath = canonicalToClasspath[canonicalJarPath] ?: canonicalJarPath
jarsToClasses.computeIfAbsent(classpathJarPath) { ArrayList() }.add(parts[1])
}
}
return jarsToClasses
Expand All @@ -43,8 +89,9 @@ abstract class BaseJdepsGenExtension(
targetLabel: String,
explicitDeps: Map<String, List<String>>,
implicitClassesCanonicalPaths: Set<String>,
canonicalToClasspath: Map<String, String>,
) {
val implicitDeps = createDepsMap(implicitClassesCanonicalPaths)
val implicitDeps = createDepsMap(implicitClassesCanonicalPaths, canonicalToClasspath)

// Build and write out deps.proto
val jdepsOutput = configuration.getNotNull(JdepsGenConfigurationKeys.OUTPUT_JDEPS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ class JdepsGenCommandLineProcessor : CommandLineProcessor {
required = false,
allowMultipleOccurrences = true,
)
val FULL_CLASSPATH_OPTION: CliOption =
CliOption(
"full_classpath",
"<List>",
"Full classpath used for compilation (includes all transitive dependencies and stdlib)",
required = false,
allowMultipleOccurrences = true,
)
val STRICT_KOTLIN_DEPS_OPTION: CliOption =
CliOption("strict_kotlin_deps", "<String>", "Report strict deps violations", required = true)
}
Expand All @@ -36,6 +44,7 @@ class JdepsGenCommandLineProcessor : CommandLineProcessor {
OUTPUT_JDEPS_FILE_OPTION,
TARGET_LABEL_OPTION,
DIRECT_DEPENDENCIES_OPTION,
FULL_CLASSPATH_OPTION,
STRICT_KOTLIN_DEPS_OPTION,
)

Expand All @@ -52,6 +61,11 @@ class JdepsGenCommandLineProcessor : CommandLineProcessor {
JdepsGenConfigurationKeys.DIRECT_DEPENDENCIES,
value,
)
FULL_CLASSPATH_OPTION ->
configuration.appendList(
JdepsGenConfigurationKeys.FULL_CLASSPATH,
value,
)
STRICT_KOTLIN_DEPS_OPTION ->
configuration.put(
JdepsGenConfigurationKeys.STRICT_KOTLIN_DEPS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,13 @@ object JdepsGenConfigurationKeys {
CompilerConfigurationKey.create(
JdepsGenCommandLineProcessor.DIRECT_DEPENDENCIES_OPTION.description,
)

/**
* Full classpath used for compilation (includes all transitive dependencies and stdlib).
* Used for mapping canonical filesystem paths back to original classpath paths.
*/
val FULL_CLASSPATH: CompilerConfigurationKey<List<String>> =
CompilerConfigurationKey.create(
JdepsGenCommandLineProcessor.FULL_CLASSPATH_OPTION.description,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ import org.jetbrains.kotlin.fir.declarations.toAnnotationClassLikeSymbol
internal class BasicDeclarationChecker(
private val classUsageRecorder: ClassUsageRecorder,
) : FirBasicDeclarationChecker(MppCheckerKind.Common) {
override fun check(
declaration: FirDeclaration,
context: CheckerContext,
reporter: DiagnosticReporter,
) {
context(context: CheckerContext, reporter: DiagnosticReporter)
override fun check(declaration: FirDeclaration) {
declaration.annotations.forEach { annotation ->
annotation.toAnnotationClassLikeSymbol(context.session)?.let {
classUsageRecorder.recordClass(it, context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@ internal class CallableChecker(
* Tracks the return type & type parameters of a callable declaration. Function parameters are
* tracked in [FunctionChecker].
*/
override fun check(
declaration: FirCallableDeclaration,
context: CheckerContext,
reporter: DiagnosticReporter,
) {
context(context: CheckerContext, reporter: DiagnosticReporter)
override fun check(declaration: FirCallableDeclaration) {
// return type
declaration.returnTypeRef.let { classUsageRecorder.recordTypeRef(it, context) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ import org.jetbrains.kotlin.fir.resolve.getSuperTypes
internal class ClassLikeChecker(
private val classUsageRecorder: ClassUsageRecorder,
) : FirClassLikeChecker(MppCheckerKind.Common) {
override fun check(
declaration: FirClassLikeDeclaration,
context: CheckerContext,
reporter: DiagnosticReporter,
) {
context(context: CheckerContext, reporter: DiagnosticReporter)
override fun check(declaration: FirClassLikeDeclaration) {
declaration.symbol.let { classUsageRecorder.recordClass(it, context) }
// [recordClass] also handles supertypes, but this marks direct supertypes as explicit
declaration.symbol.getSuperTypes(context.session, recursive = false).forEach {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,8 @@ import org.jetbrains.kotlin.name.ClassId
internal class FileChecker(
private val classUsageRecorder: ClassUsageRecorder,
) : FirFileChecker(MppCheckerKind.Common) {
override fun check(
declaration: FirFile,
context: CheckerContext,
reporter: DiagnosticReporter,
) {
context(context: CheckerContext, reporter: DiagnosticReporter)
override fun check(declaration: FirFile) {
declaration.imports.filterIsInstance<FirResolvedImport>().forEach { import ->
// check for classlike import (class, interface, object, enum, annotation, etc)
if (import.resolvesToClass(context)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@ internal class FunctionChecker(
* Tracks the value parameters of a function declaration. Return type & type parameters are
* tracked in [CallableChecker].
*/
override fun check(
declaration: FirFunction,
context: CheckerContext,
reporter: DiagnosticReporter,
) {
context(context: CheckerContext, reporter: DiagnosticReporter)
override fun check(declaration: FirFunction) {
// function parameters
declaration.valueParameters.forEach { valueParam ->
valueParam.returnTypeRef.let { classUsageRecorder.recordTypeRef(it, context) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,8 @@ import org.jetbrains.kotlin.fir.types.resolvedType
internal class QualifiedAccessChecker(
private val classUsageRecorder: ClassUsageRecorder,
) : FirQualifiedAccessExpressionChecker(MppCheckerKind.Common) {
override fun check(
expression: FirQualifiedAccessExpression,
context: CheckerContext,
reporter: DiagnosticReporter,
) {
context(context: CheckerContext, reporter: DiagnosticReporter)
override fun check(expression: FirQualifiedAccessExpression) {
// track function's owning class
val resolvedCallableSymbol = expression.toResolvedCallableSymbol()
resolvedCallableSymbol?.containerSource?.binaryClass()?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
internal class ResolvedQualifierChecker(
private val classUsageRecorder: ClassUsageRecorder,
) : FirResolvedQualifierChecker(MppCheckerKind.Common) {
override fun check(
expression: FirResolvedQualifier,
context: CheckerContext,
reporter: DiagnosticReporter,
) {
context(context: CheckerContext, reporter: DiagnosticReporter)
override fun check(expression: FirResolvedQualifier) {
expression.symbol?.let {
classUsageRecorder.recordClass(it, context)
}
Expand Down
5 changes: 4 additions & 1 deletion src/main/starlark/core/compile/cli/compile.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ def compile_kotlin_for_jvm(
args.add("-module-name", module_name)
args.add_joined("-cp", classpath, join_with = path_separator)
for (k, v) in kotlinc_opts.items():
args.add(k, v)
if v:
args.add(k, v)
else:
args.add(k)
args.add_all(srcs)

actions.run(
Expand Down
Loading