Snap for 9746098 from e4697353d03a4a6d18e081c0cd8d7ed39bb25977 to udc-d1-release

Change-Id: I800c5671f61564f3492fa6de16219bdcdcb97c46
diff --git a/BUILD b/BUILD
index c72ec85..ea03023 100644
--- a/BUILD
+++ b/BUILD
@@ -12,6 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
 licenses(["notice"])
 
 exports_files(["LICENSE"])
diff --git a/METADATA b/METADATA
index 9e9632a..f0d76c2 100644
--- a/METADATA
+++ b/METADATA
@@ -11,8 +11,8 @@
     type: GIT
     value: "https://team.googlesource.com/kotlin-rules/rules"
   }
-  version: "0904db290987a7e48a708369e5093b6d033769e7"
-  last_upgrade_date { year: 2022 month: 12 day: 14}
+  version: "6c074b6ce60b1ccfdc17bcf5e0566f497a869790"
+  last_upgrade_date { year: 2023 month: 3 day: 13}
   license_type: NOTICE
 }
 
diff --git a/WORKSPACE b/WORKSPACE
index 5d01cdd..bf7ad0f 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -59,10 +59,10 @@
 
 http_archive(
     name = "dagger",
-    strip_prefix = "dagger-dagger-2.28.1",
+    strip_prefix = "dagger-dagger-2.44.2",
     build_file = "@//bazel:dagger.BUILD",
-    sha256 = "9e69ab2f9a47e0f74e71fe49098bea908c528aa02fa0c5995334447b310d0cdd",
-    urls = ["https://github.com/google/dagger/archive/dagger-2.28.1.zip"],
+    sha256 = "cbff42063bfce78a08871d5a329476eb38c96af9cf20d21f8b412fee76296181",
+    urls = ["https://github.com/google/dagger/archive/dagger-2.44.2.zip"],
 )
 load("@dagger//:workspace_defs.bzl", "DAGGER_ARTIFACTS", "DAGGER_REPOSITORIES")
 
@@ -70,7 +70,7 @@
 http_archive(
     name = "kotlinc",
     build_file = "@//bazel:kotlinc.BUILD",
-    sha256 = "8412b31b808755f0c0d336dbb8c8443fa239bf32ddb3cdb81b305b25f0ad279e",
+    sha256 = "4c3fa7bc1bb9ef3058a2319d8bcc3b7196079f88e92fdcd8d304a46f4b6b5787",
     strip_prefix = "kotlinc",
     urls = [
         "https://github.com/JetBrains/kotlin/releases/download/v{0}/kotlin-compiler-{0}.zip".format(KT_VERSION[1:].replace("_", ".")),
diff --git a/bazel/BUILD b/bazel/BUILD
index cc77038..303a377 100644
--- a/bazel/BUILD
+++ b/bazel/BUILD
@@ -43,3 +43,10 @@
         "@maven//:org_jacoco_org_jacoco_cli",
     ],
 )
+
+genrule(
+    name = "stub_tool",
+    outs = ["stub_tool.sh"],
+    cmd = "exit 1",
+    executable = True,
+)
diff --git a/bazel/deploy_jar_freshness_golden_test.bzl b/bazel/deploy_jar_freshness_golden_test.bzl
index 9e36132..a6524eb 100644
--- a/bazel/deploy_jar_freshness_golden_test.bzl
+++ b/bazel/deploy_jar_freshness_golden_test.bzl
@@ -14,6 +14,8 @@
 
 """Test on *_deploy.jar freshness"""
 
+load("//:visibility.bzl", "RULES_KOTLIN")
+
 def _deploy_jar_freshness_golden_test_impl(ctx):
     test_command = """
       if ! cmp $1 $2 ; then
diff --git a/bazel/stubs.bzl b/bazel/stubs.bzl
index 95f5b87..5d041f4 100644
--- a/bazel/stubs.bzl
+++ b/bazel/stubs.bzl
@@ -15,10 +15,13 @@
 """Stubs"""
 
 load("@bazel_skylib//lib:sets.bzl", "sets")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
-def register_extension_info(**_kwargs):
+def _empty_fn(*_args, **_kwargs):
     pass
 
+register_extension_info = _empty_fn
+
 FORBIDDEN_DEP_PACKAGES = sets.make([])
 
 EXEMPT_DEPS = sets.make([])
@@ -33,5 +36,21 @@
 
 BASE_JVMOPTS = []
 
-def select_java_language_version(**_kwargs):
+def select_java_language_level(**_kwargs):
     return "11"
+
+registry_checks_for_package = _empty_fn
+
+LINT_REGISTRY = None  # Only ever passed to registry_checks_for_package
+
+def _run_lint_on_library(ctx, output, *_args, **_kwargs):
+    ctx.actions.write(output, "Android Lint Disabled")
+    return output
+
+lint_actions = struct(
+    run_lint_on_library = _run_lint_on_library,
+    get_android_lint_baseline_file = _empty_fn,
+)
+
+def check_compiler_opt_allowlist(_label):
+    pass
diff --git a/kotlin/common.bzl b/kotlin/common.bzl
index 3789b0c..76bb57b 100644
--- a/kotlin/common.bzl
+++ b/kotlin/common.bzl
@@ -14,42 +14,22 @@
 
 """Common Kotlin definitions."""
 
+# go/keep-sorted start
+load("//kotlin/jvm/internal_do_not_use/util:file_factory.bzl", "FileFactory")
+load("//kotlin/jvm/internal_do_not_use/util:run_deploy_jar.bzl", "kt_run_deploy_jar")
+load("//kotlin/jvm/internal_do_not_use/util:srcjars.bzl", "kt_srcjars")
+load("//toolchains/kotlin_jvm:androidlint_toolchains.bzl", "androidlint_toolchains")
+load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN")
 load("@bazel_skylib//lib:sets.bzl", "sets")
+load("//bazel:stubs.bzl", "lint_actions")
 load("//bazel:stubs.bzl", "BASE_JVMOPTS")
 load("//bazel:stubs.bzl", "DEFAULT_BUILTIN_PROCESSORS")
-load(":file_factory.bzl", "FileFactory")
+# go/keep-sorted end
 
 # TODO: Remove the _ALLOWED_*_RULES lists to determine which rules
 # are accepted dependencies to Kotlin rules as the approach does not scale
 # because it will require a cl + release for every new rule.
 
-_ALLOWED_ANDROID_RULES = [
-    "aar_import",
-    "android_library",
-    "kt_android_library_helper",
-]
-
-_ALLOWED_JVM_RULES = [
-    "_java_grpc_library",
-    "_java_lite_grpc_library",
-    "af_internal_guice_module",  # b/142743220
-    "af_internal_jbcsrc_library",  # added with b/143872075
-    "af_internal_soyinfo_generator",  # b/143872075
-    "java_import",
-    "java_library",
-    "java_lite_proto_library",
-    "java_mutable_proto_library",
-    "java_proto_library",
-    "java_wrap_cc",  # b/152799927
-    "jvm_import",
-    "_kmp_library",
-    "kt_grpc_library_helper",
-    "kt_jvm_library_helper",
-    "kt_jvm_import",
-    "kt_proto_library_helper",
-    "_j2kt_jvm_library_rule",  # b/233055549
-]
-
 _EXT = struct(
     KT = ".kt",
     JAVA = ".java",
@@ -78,6 +58,9 @@
 def _is_dir(file, basename):
     return file.is_directory and file.basename == basename
 
+def _is_file(file, extension):
+    return (not file.is_directory) and file.path.endswith(extension)
+
 def _is_kt_src(src):
     """Decides if `src` Kotlin code.
 
@@ -86,7 +69,7 @@
       -  a tree-artifact expected to contain only Kotlin source files
     """
 
-    return src.path.endswith(_EXT.KT) or _is_dir(src, "kotlin")
+    return _is_file(src, _EXT.KT) or _is_dir(src, "kotlin")
 
 # Compute module name based on target (b/139403883), similar to Swift
 def _derive_module_name(ctx):
@@ -142,11 +125,11 @@
 
         # Create a srcjar for the .java stubs generated by kapt,
         # mostly to filter out non-.java stub outputs, e.g. .kapt_metadata.
-        stub_srcjars.append(_create_jar(
+        stub_srcjars.append(kt_srcjars.zip(
             ctx,
             toolchain,
             file_factory.declare_file("stubs-srcjar.jar"),
-            kt_inputs = [stubs_dir],
+            srcs = [stubs_dir],
             ignore_not_allowed_files = True,
         ))
 
@@ -319,7 +302,7 @@
         java_runtime = toolchain.turbine_java_runtime
         if not java_runtime:
             java_runtime = toolchain.java_runtime
-        _actions_run_deploy_jar(
+        kt_run_deploy_jar(
             ctx = ctx,
             java_runtime = java_runtime,
             deploy_jar = toolchain.turbine,
@@ -331,53 +314,24 @@
             progress_message = progress_message,
         )
 
-def _derive_gen_class_jar(
-        ctx,
-        toolchain,
-        manifest_proto,
-        javac_jar,
-        java_srcs = []):
-    """Returns the annotation processor-generated classes contained in given Jar."""
-    if not manifest_proto:
-        return None
-    if not javac_jar:
-        fail("There must be a javac Jar if there was annotation processing")
-    if not java_srcs:
-        # If there weren't any hand-written .java srcs, just use Javac's output
-        return javac_jar
-
-    # Run GenClass tool to derive gen_class_jar by filtering hand-written sources.
-    # cf. Bazel's JavaCompilationHelper#createGenJarAction
-    result = FileFactory(ctx, javac_jar).declare_file("-gen.jar")
-
-    genclass_args = ctx.actions.args()
-    genclass_args.add("--manifest_proto", manifest_proto)
-    genclass_args.add("--class_jar", javac_jar)
-    genclass_args.add("--output_jar", result)
-
-    _actions_run_deploy_jar(
-        ctx = ctx,
-        java_runtime = toolchain.java_runtime,
-        deploy_jar = toolchain.genclass,
-        inputs = [manifest_proto, javac_jar],
-        outputs = [result],
-        args = [genclass_args],
-        mnemonic = "KtGenClassJar",
-        progress_message = "Deriving %{output}",
-    )
-
-    return result
-
 def _kt_plugins_map(
+        android_lint_singlejar_plugins = depset(),
+        android_lint_libjar_plugin_infos = [],
         java_plugin_infos = [],
         kt_compiler_plugin_infos = []):
     """A struct containing all the plugin types understood by rules_kotlin.
 
     Args:
-      java_plugin_infos: (list[JavaPluginInfo])
-      kt_compiler_plugin_infos: (list[KtCompilerPluginInfo])
+        android_lint_singlejar_plugins:  (depset[File]) Android Lint checkers.
+            Each JAR is self-contained and should be loaded in an isolated classloader.
+        android_lint_libjar_plugin_infos: (list[JavaInfo]) Android Lint checkers.
+            All infos share transitive dependencies and should be loaded in a combined classloader.
+        java_plugin_infos: (list[JavaPluginInfo])
+        kt_compiler_plugin_infos: (list[KtCompilerPluginInfo])
     """
     return struct(
+        android_lint_singlejar_plugins = android_lint_singlejar_plugins,
+        android_lint_libjar_plugin_infos = android_lint_libjar_plugin_infos,
         java_plugin_infos = java_plugin_infos,
         kt_compiler_plugin_infos = kt_compiler_plugin_infos,
     )
@@ -387,7 +341,6 @@
         file_factory,
         kt_srcs = [],
         common_srcs = [],
-        coverage_srcs = [],
         java_srcs_and_dirs = [],
         kotlincopts = [],
         compile_jdeps = depset(),
@@ -397,7 +350,9 @@
         plugins = _kt_plugins_map(),
         friend_jars = depset(),
         enforce_strict_deps = False,
-        enforce_complete_jdeps = False):
+        enforce_complete_jdeps = False,
+        mnemonic = None,
+        message_prefix = ""):
     direct_inputs = []
     transitive_inputs = []
     outputs = []
@@ -435,7 +390,7 @@
 
     output = file_factory.declare_file(".jar")
     kotlinc_args.add("-d", output)
-    outputs.append(output)
+    outputs.insert(0, output)  # The param file name is derived from the 0th output
     kotlinc_args.add_all(kt_srcs)
     direct_inputs.extend(kt_srcs)
     kotlinc_args.add_all(common_srcs)
@@ -459,36 +414,126 @@
         arguments = [kotlinc_args],
         inputs = depset(direct = direct_inputs, transitive = transitive_inputs),
         outputs = outputs,
-        mnemonic = "Kt2JavaCompile",
-        progress_message = "Compiling Kotlin For Java Runtime: %s" % _get_original_kt_target_label(ctx),
+        mnemonic = mnemonic,
+        progress_message = message_prefix + str(_get_original_kt_target_label(ctx)),
         execution_requirements = {
             "worker-key-mnemonic": "Kt2JavaCompile",
         },
     )
 
-    srcjar = _create_jar(
+    return struct(
+        output_jar = output,
+        compile_jar = kt_ijar,
+    )
+
+def _kt_compile(
+        ctx,
+        file_factory,
+        kt_srcs = [],
+        common_srcs = [],
+        coverage_srcs = [],
+        java_srcs_and_dirs = [],
+        kt_hdrs = None,
+        common_hdrs = None,
+        kotlincopts = [],
+        compile_jdeps = depset(),
+        toolchain = None,
+        classpath = [],
+        directdep_jars = depset(),
+        plugins = _kt_plugins_map(),
+        friend_jars = depset(),
+        enforce_strict_deps = False,
+        enforce_complete_jdeps = False):
+    # TODO: don't run jvm-abi-gen plugin here if we have headers
+    kotlinc_full_result = _run_kotlinc(
+        ctx,
+        kt_srcs = kt_srcs,
+        common_srcs = common_srcs,
+        java_srcs_and_dirs = java_srcs_and_dirs,
+        file_factory = file_factory,
+        kotlincopts = kotlincopts,
+        compile_jdeps = compile_jdeps,
+        toolchain = toolchain,
+        classpath = classpath,
+        directdep_jars = directdep_jars,
+        plugins = plugins,
+        friend_jars = friend_jars,
+        enforce_strict_deps = enforce_strict_deps,
+        enforce_complete_jdeps = enforce_complete_jdeps,
+        mnemonic = "Kt2JavaCompile",
+        message_prefix = "Compiling for Java runtime: ",
+    )
+
+    srcjar = kt_srcjars.zip(
         ctx,
         toolchain,
         file_factory.declare_file("-kt-src.jar"),
-        kt_inputs = kt_srcs,
-        common_inputs = common_srcs,
+        srcs = kt_srcs,
+        common_srcs = common_srcs,
     )
 
+    output_jar = kotlinc_full_result.output_jar
     if ctx.coverage_instrumented():
-        output = _offline_instrument_jar(
+        output_jar = _offline_instrument_jar(
             ctx,
             toolchain,
-            output,
+            output_jar,
             kt_srcs + common_srcs + coverage_srcs,
         )
 
+    # Use un-instrumented Jar at compile-time to avoid double-instrumenting inline functions
+    # (see b/110763361 for the comparable Gradle issue)
+    compile_jar = kotlinc_full_result.compile_jar
+    if toolchain.header_gen_tool:
+        kotlinc_header_result = _run_kotlinc(
+            ctx,
+            kt_srcs = kt_hdrs,
+            common_srcs = common_hdrs,
+            java_srcs_and_dirs = java_srcs_and_dirs,
+            file_factory = file_factory.derive("-abi"),
+            kotlincopts = kotlincopts,
+            compile_jdeps = compile_jdeps,
+            toolchain = toolchain,
+            classpath = classpath,
+            directdep_jars = directdep_jars,
+            plugins = plugins,
+            friend_jars = friend_jars,
+            enforce_strict_deps = enforce_strict_deps,
+            enforce_complete_jdeps = enforce_complete_jdeps,
+            mnemonic = "Kt2JavaHeaderCompile",
+            message_prefix = "Computing Kotlin ABI interface Jar: ",
+        )
+        compile_jar = kotlinc_header_result.compile_jar
+
     result = dict(
-        output_jar = output,
-        compile_jar = kt_ijar,
+        output_jar = output_jar,
+        compile_jar = compile_jar,
         source_jar = srcjar,
     )
     return struct(java_info = JavaInfo(**result), **result)
 
+def _derive_headers(
+        ctx,
+        toolchain,
+        file_factory,
+        srcs):
+    if not srcs or not toolchain.header_gen_tool:
+        return srcs
+
+    output_dir = file_factory.declare_directory("-headers")
+    args = ctx.actions.args()
+    args.add(output_dir.path, format = "-output_dir=%s")
+    args.add_joined(srcs, format_joined = "-sources=%s", join_with = ",")
+    ctx.actions.run(
+        executable = toolchain.header_gen_tool,
+        arguments = [args],
+        inputs = srcs,
+        outputs = [output_dir],
+        mnemonic = "KtDeriveHeaders",
+        progress_message = "Deriving %s: %s" % (output_dir.basename, _get_original_kt_target_label(ctx)),
+    )
+    return [output_dir]
+
 def _get_original_kt_target_label(ctx):
     label = ctx.label
     if label.name.find("_DO_NOT_DEPEND") > 0:
@@ -534,7 +579,7 @@
     )
 
 def _offline_instrument_jar(ctx, toolchain, jar, srcs = []):
-    if not jar.basename.endswith(".jar"):
+    if not _is_file(jar, _EXT.JAR):
         fail("Expect JAR input but got %s" % jar)
     file_factory = FileFactory(ctx, jar)
 
@@ -613,174 +658,6 @@
 
     return merged_jdeps_file
 
-def _expand_zip(ctx, toolchain, dir, input):
-    args = ctx.actions.args()
-    args.add("unzip", input)
-    args.add(dir.path)
-
-    _actions_run_deploy_jar(
-        ctx = ctx,
-        java_runtime = toolchain.java_runtime,
-        deploy_jar = toolchain.source_jar_zipper,
-        inputs = [input],
-        outputs = [dir],
-        args = [args],
-        mnemonic = "SrcJarUnzip",
-    )
-
-    return dir
-
-def _create_jar(ctx, toolchain, out_jar, kt_inputs = [], common_inputs = [], ignore_not_allowed_files = False):
-    args = ctx.actions.args()
-    args.add("zip")
-    args.add(out_jar)
-    args.add_joined("--kotlin_srcs", kt_inputs, join_with = ",")
-    args.add_joined("--common_srcs", common_inputs, join_with = ",")
-    if ignore_not_allowed_files:
-        args.add("-i")
-
-    _actions_run_deploy_jar(
-        ctx = ctx,
-        java_runtime = toolchain.java_runtime,
-        deploy_jar = toolchain.source_jar_zipper,
-        inputs = kt_inputs + common_inputs,
-        outputs = [out_jar],
-        args = [args],
-        mnemonic = "KtJar",
-        progress_message = "Create Jar (kotlin/common.bzl): %{output}",
-    )
-
-    return out_jar
-
-def _create_jar_from_tree_artifacts(ctx, toolchain, output_jar, input_dirs):
-    """Packs a sequence of tree artifacts into a single jar.
-
-    Given the following file directory structure,
-        /usr/home/a/x/1.txt
-        /usr/home/b/y/1.txt
-    with an input_dirs as [
-        "/usr/home/a",
-        "/usr/home/b",
-    ],
-    The tool produces a jar with in-archive structure of,
-        x/1.txt
-        y/1.txt
-
-    The function fails on the duplicate jar entry case. e.g. if we pass an
-    input_dirs as [
-        "/usr/home/a/x",
-        "/usr/home/b/y",
-    ],
-    then the blaze action would fail with an error message.
-        "java.lang.IllegalStateException: 1.txt has the same path as 1.txt!
-        If it is intended behavior rename one or both of them."
-
-    Args:
-        ctx: The build rule context.
-        toolchain: Toolchain containing the jar tool.
-        output_jar: The jar to be produced by this action.
-        input_dirs: A sequence of tree artifacts to be zipped.
-
-    Returns:
-        The generated output jar, i.e. output_jar
-    """
-
-    args = ctx.actions.args()
-    args.add("zip_resources")
-    args.add(output_jar)
-    args.add_joined(
-        "--input_dirs",
-        input_dirs,
-        join_with = ",",
-        omit_if_empty = False,
-        expand_directories = False,
-    )
-
-    _actions_run_deploy_jar(
-        ctx = ctx,
-        java_runtime = toolchain.java_runtime,
-        deploy_jar = toolchain.source_jar_zipper,
-        inputs = input_dirs,
-        outputs = [output_jar],
-        args = [args],
-        mnemonic = "KtJarActionFromTreeArtifacts",
-        progress_message = "Create Jar %{output}",
-    )
-
-    return output_jar
-
-def _DirSrcjarSyncer(ctx, kt_toolchain, file_factory):
-    _dirs = []
-    _srcjars = []
-
-    def add_dirs(dirs):
-        if not dirs:
-            return
-
-        _dirs.extend(dirs)
-        _srcjars.append(
-            _create_jar_from_tree_artifacts(
-                ctx,
-                kt_toolchain,
-                file_factory.declare_file("%s.srcjar" % len(_srcjars)),
-                dirs,
-            ),
-        )
-
-    def add_srcjars(srcjars):
-        if not srcjars:
-            return
-
-        for srcjar in srcjars:
-            _dirs.append(
-                _expand_zip(
-                    ctx,
-                    kt_toolchain,
-                    file_factory.declare_directory("%s.expand" % len(_dirs)),
-                    srcjar,
-                ),
-            )
-        _srcjars.extend(srcjars)
-
-    return struct(
-        add_dirs = add_dirs,
-        add_srcjars = add_srcjars,
-        dirs = _dirs,
-        srcjars = _srcjars,
-    )
-
-def _actions_run_deploy_jar(
-        ctx,
-        java_runtime,
-        deploy_jar,
-        inputs,
-        args = [],
-        deploy_jsa = None,
-        **kwargs):
-    java_args = ctx.actions.args()
-    java_inputs = []
-    if deploy_jsa:
-        java_args.add("-Xshare:auto")
-        java_args.add(deploy_jsa, format = "-XX:SharedArchiveFile=%s")
-        java_args.add("-XX:-VerifySharedSpaces")
-        java_args.add("-XX:-ValidateSharedClassPaths")
-        java_inputs.append(deploy_jsa)
-    java_args.add("-jar", deploy_jar)
-    java_inputs.append(deploy_jar)
-
-    java_depset = depset(direct = java_inputs, transitive = [java_runtime[DefaultInfo].files])
-    if type(inputs) == "depset":
-        all_inputs = depset(transitive = [java_depset, inputs])
-    else:
-        all_inputs = depset(direct = inputs, transitive = [java_depset])
-
-    ctx.actions.run(
-        executable = str(java_runtime[java_common.JavaRuntimeInfo].java_executable_exec_path),
-        inputs = all_inputs,
-        arguments = BASE_JVMOPTS + [java_args] + args,
-        **kwargs
-    )
-
 def _check_srcs_package(target_package, srcs, attr_name):
     """Makes sure the given srcs live in the given package."""
 
@@ -790,6 +667,27 @@
             fail(("Please do not depend on %s directly in %s.  Either move it to this package or " +
                   "depend on an appropriate rule in its package.") % (src.owner, attr_name))
 
+def _split_srcs_by_language(srcs, common_srcs, java_syncer):
+    srcs_set = sets.make(srcs)
+    common_srcs_set = sets.make(common_srcs)
+
+    overlapping_srcs_set = sets.intersection(srcs_set, common_srcs_set)
+    if sets.length(overlapping_srcs_set) != 0:
+        fail("Overlap between srcs and common_srcs: %s" % sets.to_list(overlapping_srcs_set))
+
+    # Split sources, as java requires a separate compile step.
+    kt_srcs = [s for s in srcs if _is_kt_src(s)]
+    java_srcs = [s for s in srcs if _is_file(s, _EXT.JAVA)]
+    java_syncer.add_dirs([s for s in srcs if _is_dir(s, "java")])
+    java_syncer.add_srcjars([s for s in srcs if _is_file(s, _EXT.SRCJAR)])
+
+    expected_srcs_set = sets.make(kt_srcs + java_srcs + java_syncer.dirs + java_syncer.srcjars)
+    unexpected_srcs_set = sets.difference(srcs_set, expected_srcs_set)
+    if sets.length(unexpected_srcs_set) != 0:
+        fail("Unexpected srcs: %s" % sets.to_list(unexpected_srcs_set))
+
+    return (kt_srcs, java_srcs)
+
 # TODO: Streamline API to generate less actions.
 def _kt_jvm_library(
         ctx,
@@ -804,15 +702,11 @@
         output = None,
         output_srcjar = None,  # Will derive default filename if not set.
         deps = [],
-        codegen_output_java_infos = [],  # JavaInfo sequence from kt_codegen_plugin.
         exports = [],  # passthrough for JavaInfo constructor
         runtime_deps = [],  # passthrough for JavaInfo constructor
         native_libraries = [],  # passthrough of CcInfo for JavaInfo constructor
         plugins = _kt_plugins_map(),
-        pre_processed_java_plugin_processors = sets.make([]),
         exported_plugins = [],
-        android_lint_plugins = [],
-        android_lint_rules_jars = depset(),  # Depset with standalone Android Lint rules Jars
         javacopts = [],
         kotlincopts = [],
         compile_jdeps = depset(),
@@ -832,26 +726,25 @@
         fail("Missing or invalid kt_toolchain")
 
     file_factory = FileFactory(ctx, output)
-    deps = list(deps)  # Defensive copy
+    static_deps = list(deps)  # Defensive copy
 
-    # Split sources, as java requires a separate compile step.
-    kt_srcs = [s for s in srcs if _is_kt_src(s)]
-    java_srcs = [s for s in srcs if s.path.endswith(_EXT.JAVA)]
-    java_syncer = _DirSrcjarSyncer(ctx, kt_toolchain, file_factory)
-    java_syncer.add_dirs([s for s in srcs if _is_dir(s, "java")])
-    java_syncer.add_srcjars([s for s in srcs if s.path.endswith(_EXT.SRCJAR)])
+    kt_codegen_processing_env = dict(
+        pre_processed_processors = depset(),
+        codegen_output_java_infos = [],
+    )
 
-    expected_srcs = sets.make(kt_srcs + java_srcs + java_syncer.dirs + java_syncer.srcjars)
-    unexpected_srcs = sets.difference(sets.make(srcs), expected_srcs)
-    if sets.length(unexpected_srcs) != 0:
-        fail("Unexpected srcs: %s" % sets.to_list(unexpected_srcs))
+    pre_processed_processors = kt_codegen_processing_env["pre_processed_processors"]
+    generative_deps = kt_codegen_processing_env["codegen_output_java_infos"]
+
+    java_syncer = kt_srcjars.DirSrcjarSyncer(ctx, kt_toolchain, file_factory)
+    kt_srcs, java_srcs = _split_srcs_by_language(srcs, common_srcs, java_syncer)
 
     # TODO: Remove this special case
     if kt_srcs and ("flogger" in [p.plugin_id for p in plugins.kt_compiler_plugin_infos]):
-        deps.append(kt_toolchain.flogger_runtime)
+        static_deps.append(kt_toolchain.flogger_runtime)
 
-    if srcs or common_srcs or rule_family != _RULE_FAMILY.ANDROID_LIBRARY:
-        deps.extend(kt_toolchain.kotlin_libs)
+    if kt_srcs or common_srcs or rule_family != _RULE_FAMILY.ANDROID_LIBRARY:
+        static_deps.extend(kt_toolchain.kotlin_libs)
 
     # Skip srcs package check for android_library targets with no kotlin sources: b/239725424
     if rule_family != _RULE_FAMILY.ANDROID_LIBRARY or kt_srcs:
@@ -859,17 +752,19 @@
         _check_srcs_package(ctx.label.package, common_srcs, "common_srcs")
         _check_srcs_package(ctx.label.package, coverage_srcs, "coverage_srcs")
 
-    full_classpath = _create_classpath(java_toolchain, deps + codegen_output_java_infos)
+    # Includes generative deps from codegen.
+    extended_deps = static_deps + generative_deps
+    full_classpath = _create_classpath(java_toolchain, extended_deps)
 
     # Collect all plugin data, including processors to run and all plugin classpaths,
     # whether they have processors or not (b/120995492).
     # This may include go/errorprone plugin classpaths that kapt will ignore.
-    java_plugin_datas = [info.plugins for info in plugins.java_plugin_infos] + [dep.plugins for dep in deps]
+    java_plugin_datas = [info.plugins for info in plugins.java_plugin_infos] + [dep.plugins for dep in static_deps]
     plugin_processors = [
         cls
         for p in java_plugin_datas
         for cls in p.processor_classes.to_list()
-        if not sets.contains(pre_processed_java_plugin_processors, cls)
+        if cls not in pre_processed_processors.to_list()
     ]
     plugin_classpaths = depset(transitive = [p.processor_jars for p in java_plugin_datas])
 
@@ -877,6 +772,20 @@
     out_srcjars = []
     out_compilejars = []
 
+    kt_hdrs = _derive_headers(
+        ctx,
+        toolchain = kt_toolchain,
+        file_factory = file_factory.derive("-kt"),
+        # TODO: prohibit overlap of srcs and common_srcs
+        srcs = kt_srcs,
+    )
+    common_hdrs = _derive_headers(
+        ctx,
+        toolchain = kt_toolchain,
+        file_factory = file_factory.derive("-common"),
+        srcs = common_srcs,
+    )
+
     # Kotlin compilation requires two passes when annotation processing is
     # required. The initial pass processes the annotations and generates
     # additional sources and the following pass compiles the Kotlin code.
@@ -887,8 +796,8 @@
         kapt_outputs = _kapt(
             ctx,
             file_factory = file_factory,
-            kt_srcs = kt_srcs,
-            common_srcs = common_srcs,
+            kt_srcs = kt_hdrs,
+            common_srcs = common_hdrs,
             java_srcs = java_srcs,
             plugin_processors = plugin_processors,
             plugin_classpaths = plugin_classpaths,
@@ -908,12 +817,14 @@
 
     kotlinc_result = None
     if kt_srcs or common_srcs:
-        kotlinc_result = _run_kotlinc(
+        kotlinc_result = _kt_compile(
             ctx,
             kt_srcs = kt_srcs,
             common_srcs = common_srcs,
             coverage_srcs = coverage_srcs,
             java_srcs_and_dirs = java_srcs + java_syncer.dirs,
+            kt_hdrs = kt_hdrs,
+            common_hdrs = common_hdrs,
             file_factory = file_factory.derive("-kt"),
             kotlincopts = kotlincopts,
             compile_jdeps = compile_jdeps,
@@ -924,9 +835,6 @@
             enforce_strict_deps = enforce_strict_deps,
             enforce_complete_jdeps = enforce_complete_jdeps,
         )
-
-        # Use un-instrumented Jar at compile-time to avoid double-instrumenting inline functions
-        # (see b/110763361 for the comparable Gradle issue)
         out_compilejars.append(kotlinc_result.compile_jar)
         out_srcjars.append(kotlinc_result.source_jar)
         out_jars.append(kotlinc_result.output_jar)
@@ -937,7 +845,7 @@
     )
     if classpath_resources_dirs:
         out_jars.append(
-            _create_jar_from_tree_artifacts(
+            kt_srcjars.zip_resources(
                 ctx,
                 kt_toolchain,
                 file_factory.declare_file("-dir-res.jar"),
@@ -947,11 +855,10 @@
 
     javac_java_info = None
     java_native_headers_jar = None
-    java_gensrcjar = None
-    java_genjar = None
     is_android_library_without_kt_srcs = rule_family == _RULE_FAMILY.ANDROID_LIBRARY and not kt_srcs
+
     if java_srcs or java_syncer.srcjars or classpath_resources:
-        javac_deps = deps + codegen_output_java_infos  # Defensive copy
+        javac_deps = extended_deps  # Defensive copy
         if kapt_outputs.java_info:
             javac_deps.append(kapt_outputs.java_info)
         if kotlinc_result:
@@ -963,6 +870,12 @@
                 javac_deps.append(kt_toolchain.coverage_runtime)
 
         javac_out = output if is_android_library_without_kt_srcs else file_factory.declare_file("-java.jar")
+
+        annotation_plugins = list(plugins.java_plugin_infos)
+
+        # Enable annotation processing for java-only sources to enable data binding
+        enable_annotation_processing = not kt_srcs
+
         javac_java_info = java_common.compile(
             ctx,
             source_files = java_srcs,
@@ -978,17 +891,16 @@
             # all sources of default flags (for Ellipsis builds, see b/125452475).
             # TODO: remove default_javac_flags here once java_common.compile is fixed.
             javac_opts = ctx.fragments.java.default_javac_flags + javacopts,
-            plugins = plugins.java_plugin_infos,
+            plugins = annotation_plugins,
             strict_deps = "DEFAULT",
             java_toolchain = java_toolchain,
             neverlink = neverlink,
-            # Enable annotation processing for java-only sources to enable data binding
-            enable_annotation_processing = not kt_srcs,
+            enable_annotation_processing = enable_annotation_processing,
             annotation_processor_additional_outputs = annotation_processor_additional_outputs,
             annotation_processor_additional_inputs = annotation_processor_additional_inputs,
         )
 
-        # Directly return the JavaInfo from java.compile() for java-only andorid_library targets
+        # Directly return the JavaInfo from java.compile() for java-only android_library targets
         # to avoid creating a new JavaInfo. See b/239847857 for additional context.
         if is_android_library_without_kt_srcs:
             return struct(
@@ -1001,14 +913,25 @@
         out_compilejars.extend(javac_java_info.compile_jars.to_list())  # unpack singleton depset
         java_native_headers_jar = javac_java_info.outputs.native_headers
 
-        if kt_srcs:
-            java_gensrcjar = kapt_outputs.srcjar
-            java_genjar = _derive_gen_class_jar(ctx, kt_toolchain, kapt_outputs.manifest, javac_out, java_srcs)
-        else:
-            java_gensrcjar = javac_java_info.annotation_processing.source_jar
-            java_genjar = javac_java_info.annotation_processing.class_jar
-            if java_gensrcjar:
-                java_syncer.add_srcjars([java_gensrcjar])
+    java_gensrcjar = None
+    java_genjar = None
+    if pre_processed_processors:
+        java_gen_srcjars = kt_codegen_processing_env["java_gen_srcjar"]
+        kt_gen_srcjars = kt_codegen_processing_env["kt_gen_srcjar"]
+        java_gensrcjar = file_factory.declare_file("-java_info_generated_source_jar.srcjar")
+        _singlejar(
+            ctx,
+            inputs = java_gen_srcjars + kt_gen_srcjars,
+            output = java_gensrcjar,
+            singlejar = java_toolchain.single_jar,
+            mnemonic = "JavaInfoGeneratedSourceJar",
+        )
+
+    elif javac_java_info:
+        java_gensrcjar = javac_java_info.annotation_processing.source_jar
+        java_genjar = javac_java_info.annotation_processing.class_jar
+        if java_gensrcjar:
+            java_syncer.add_srcjars([java_gensrcjar])
 
     jdeps_output = None
     compile_jdeps_output = None
@@ -1017,6 +940,54 @@
     # TODO: Move severity overrides to config file when possible again
     blocking_action_outs = []
 
+    # TODO: Remove the is_android_library_without_kt_srcs condition once KtAndroidLint
+    # uses the same lint checks with AndroidLint
+
+    if not is_android_library_without_kt_srcs:
+        lint_flags = [
+            "--java-language-level",  # b/159950410
+            kt_toolchain.java_language_version,
+            "--kotlin-language-level",
+            kt_toolchain.kotlin_language_version,
+            "--nowarn",  # Check for "errors", which includes custom checks that report errors.
+            "--XallowBaselineSuppress",  # allow baseline exemptions of otherwise unsuppressable errors
+            "--exitcode",  # fail on error
+            "--fullpath",  # reduce file path clutter in reported issues
+            "--text",
+            "stdout",  # also log to stdout
+        ]
+        if disable_lint_checks and disable_lint_checks != [""]:
+            lint_flags.append("--disable")
+            lint_flags.append(",".join(disable_lint_checks))
+
+        android_lint_out = lint_actions.run_lint_on_library(
+            ctx,
+            runner = kt_toolchain.android_lint_runner,
+            output = file_factory.declare_file("_android_lint_output.xml"),
+            srcs = kt_srcs + java_srcs + common_srcs,
+            source_jars = java_syncer.srcjars,
+            classpath = full_classpath,
+            manifest = manifest,
+            merged_manifest = merged_manifest,
+            resource_files = resource_files,
+            baseline_file = androidlint_toolchains.get_baseline(ctx),
+            config = kt_toolchain.android_lint_config,
+            android_lint_plugins_depset = depset(
+                order = "preorder",
+                transitive = [plugin_classpaths] + [
+                    dep.transitive_runtime_jars
+                    for dep in plugins.android_lint_libjar_plugin_infos
+                ],
+            ),
+            android_lint_rules = plugins.android_lint_singlejar_plugins,
+            lint_flags = lint_flags,
+            extra_input_depsets = [p.processor_data for p in java_plugin_datas] + [depset([java_genjar] if java_genjar else [])],
+            testonly = testonly,
+            android_java8_libs = kt_toolchain.android_java8_apis_desugared,
+            mnemonic = "KtAndroidLint",  # so LSA extractor can distinguish Kotlin (b/189442586)
+        )
+        blocking_action_outs.append(android_lint_out)
+
     if output_srcjar == None:
         output_srcjar = file_factory.declare_file("-src.jar")
     compile_jar = file_factory.declare_file("-compile.jar")
@@ -1045,7 +1016,7 @@
         output_jar = output,
         compile_jar = compile_jar,
         source_jar = output_srcjar,
-        deps = deps,
+        deps = static_deps,
         exports = exports,
         exported_plugins = exported_plugins,
         runtime_deps = runtime_deps,
@@ -1079,6 +1050,10 @@
     if not jars:
         fail("Must import at least one JAR")
 
+    _check_srcs_package(ctx.label.package, jars, "jars")
+    if srcjar:
+        _check_srcs_package(ctx.label.package, [srcjar], "srcjar")
+
     file_factory = FileFactory(ctx, jars[0])
     deps = java_common.merge(deps + kt_toolchain.kotlin_libs)
 
@@ -1186,8 +1161,6 @@
     return pos, neg
 
 common = struct(
-    ALLOWED_ANDROID_RULES = _ALLOWED_ANDROID_RULES,
-    ALLOWED_JVM_RULES = _ALLOWED_JVM_RULES,
     JAR_FILE_TYPE = _JAR_FILE_TYPE,
     JVM_FLAGS = BASE_JVMOPTS,
     KT_FILE_TYPES = _KT_FILE_TYPES,
@@ -1196,7 +1169,7 @@
     SRCJAR_FILE_TYPES = _SRCJAR_FILE_TYPES,
     collect_proguard_specs = _collect_proguard_specs,
     collect_providers = _collect_providers,
-    create_jar_from_tree_artifacts = _create_jar_from_tree_artifacts,
+    create_jar_from_tree_artifacts = kt_srcjars.zip_resources,
     common_kapt_and_kotlinc_args = _common_kapt_and_kotlinc_args,
     is_kt_src = _is_kt_src,
     kt_jvm_import = _kt_jvm_import,
diff --git a/kotlin/compiler_opt.bzl b/kotlin/compiler_opt.bzl
index e7a89d5..a44fdfc 100644
--- a/kotlin/compiler_opt.bzl
+++ b/kotlin/compiler_opt.bzl
@@ -24,23 +24,22 @@
 `kt_compiler_opt` targets is also limited, to prevent misuse.
 """
 
+load("//bazel:stubs.bzl", "check_compiler_opt_allowlist")
+load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN")
+
 # Intentionally private to prevent misuse.
 _KtCompilerOptInfo = provider(
     doc = "A restricted set of kotlinc opts",
     fields = {"opts": "list[string]"},
 )
 
-_ALLOWED_ROOTS = [
-]
-
 _ALLOWED_VISIBILITY_NAMES = [
     "__pkg__",
     "__subpackages__",
 ]
 
 def _kt_compiler_opt_impl(ctx):
-    if not any([ctx.label.package.startswith(p) for p in _ALLOWED_ROOTS]):
-        fail("kt_compiler_opt is only allowed under " + str(_ALLOWED_ROOTS))
+    check_compiler_opt_allowlist(ctx.label)
 
     visibility_groups = [v for v in ctx.attr.visibility if not v.name in _ALLOWED_VISIBILITY_NAMES]
     if len(visibility_groups) > 0:
diff --git a/kotlin/compiler_plugin.bzl b/kotlin/compiler_plugin.bzl
index 3527aee..15b7ff7 100644
--- a/kotlin/compiler_plugin.bzl
+++ b/kotlin/compiler_plugin.bzl
@@ -14,6 +14,8 @@
 
 """A rule for declaring and passing kotlinc plugins."""
 
+load("//:visibility.bzl", "RULES_KOTLIN")
+
 _KtCompilerPluginInfo = provider(
     doc = "Info for running a plugin that directly registers itself to kotlinc extension points",
     fields = dict(
@@ -69,14 +71,3 @@
         KtCompilerPluginInfo,
     ],
 )
-
-def _get_exported_plugins(_target, ctx_rule):
-    return [t[KtCompilerPluginInfo] for t in getattr(ctx_rule.attr, "exported_plugins", []) if (KtCompilerPluginInfo in t)]
-
-kt_compiler_plugin_visitor = struct(
-    name = "compiler_plugins",
-    visit_target = _get_exported_plugins,
-    filter_edge = None,
-    finish_expansion = None,
-    process_unvisited_target = None,
-)
diff --git a/kotlin/dex_aspects.bzl b/kotlin/dex_aspects.bzl
deleted file mode 100644
index 3d2730b..0000000
--- a/kotlin/dex_aspects.bzl
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2022 Google LLC. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the License);
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""kt_dex_aspects"""
-
-# (b/259111128) Magic provider to get DexArchiveAspect to traverse into this rule
-_TraverseMeInfo = platform_common.ToolchainInfo
-
-_EXTRA_DEPS_ATTRS = dict(
-    _build_stamp_deps = attr.label_list(
-        doc = """
-            (b/259111128) Magic attr to get DexArchiveAspect to traverse into this rule
-        """,
-    ),
-)
-
-def _set_extra_deps_attrs(deps):
-    return {"$build_stamp_deps": deps}
-
-kt_dex_aspects = struct(
-    TraverseMeInfo = _TraverseMeInfo,
-    TRAVERSE_ME_INFO = _TraverseMeInfo(),
-    extra_deps_attrs = _EXTRA_DEPS_ATTRS,
-    set_extra_deps_attrs = _set_extra_deps_attrs,
-)
diff --git a/kotlin/file_factory.bzl b/kotlin/file_factory.bzl
deleted file mode 100644
index 25c2837..0000000
--- a/kotlin/file_factory.bzl
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright 2022 Google LLC. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the License);
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""FileFactory"""
-
-def FileFactory(ctx, base, suffix = None):
-    """Creates files with names derived from some base file
-
-    Including the name of a rule is not always enough to guarantee unique filenames. For example,
-    helper functions that declare their own output files may be called multiple times in the same
-    rule impl.
-
-    Args:
-        ctx: ctx
-        base: [File] The file to derive other filenames from
-        suffix: [Optional[string]] An additional suffix to differentiate declared files
-
-    Returns:
-        FileFactory
-    """
-
-    base_name = base.basename.rsplit(".", 1)[0] + (suffix or "")
-
-    def declare_directory(suffix):
-        return ctx.actions.declare_directory(base_name + suffix, sibling = base)
-
-    def declare_file(suffix):
-        return ctx.actions.declare_file(base_name + suffix, sibling = base)
-
-    def derive(suffix):
-        return FileFactory(ctx, base, suffix)
-
-    return struct(
-        declare_directory = declare_directory,
-        declare_file = declare_file,
-        derive = derive,
-    )
diff --git a/kotlin/direct_jdeps.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/BUILD
similarity index 60%
copy from kotlin/direct_jdeps.bzl
copy to kotlin/jvm/internal_do_not_use/traverse_exports/BUILD
index f242989..6db3c1e 100644
--- a/kotlin/direct_jdeps.bzl
+++ b/kotlin/jvm/internal_do_not_use/traverse_exports/BUILD
@@ -12,15 +12,18 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""kt_traverse_exports visitor for exposing jdeps files from direct deps."""
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
 
-def _get_jdeps(target, _ctx_rule):
-    return [out.compile_jdeps for out in target[JavaInfo].java_outputs if out.compile_jdeps]
+package(default_visibility = ["//:internal"])
 
-kt_direct_jdeps_visitor = struct(
-    name = "direct_jdeps",
-    visit_target = _get_jdeps,
-    filter_edge = None,
-    process_unvisited_target = None,
-    finish_expansion = None,
+licenses(["notice"])
+
+bzl_library(
+    name = "traverse_exports_bzl",
+    srcs = glob(["*.bzl"]),
+    deps = [
+        "//:visibility_bzl",
+        "//kotlin:for_traverse_exports_bzl",
+        "@bazel_skylib//lib:sets",
+    ],
 )
diff --git a/kotlin/jvm/internal_do_not_use/traverse_exports/codegen_plugin.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/codegen_plugin.bzl
new file mode 100644
index 0000000..84a0960
--- /dev/null
+++ b/kotlin/jvm/internal_do_not_use/traverse_exports/codegen_plugin.bzl
@@ -0,0 +1,33 @@
+# Copyright 2022 Google LLC. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""kt_codegen_plugin_visitor"""
+
+load("//kotlin:codegen_plugin.internal.bzl", "KtCodegenPluginInfo")
+load("//:visibility.bzl", "RULES_KOTLIN")
+
+def _get_kt_codegen_plugins(_target, ctx_rule):
+    return [
+        t[KtCodegenPluginInfo]
+        for t in getattr(ctx_rule.attr, "exported_plugins", [])
+        if KtCodegenPluginInfo in t
+    ]
+
+kt_codegen_plugin_visitor = struct(
+    name = "codegen_plugins",
+    visit_target = _get_kt_codegen_plugins,
+    filter_edge = None,
+    finish_expansion = None,
+    process_unvisited_target = None,
+)
diff --git a/kotlin/direct_jdeps.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/compiler_plugin.bzl
similarity index 60%
copy from kotlin/direct_jdeps.bzl
copy to kotlin/jvm/internal_do_not_use/traverse_exports/compiler_plugin.bzl
index f242989..a5c65c4 100644
--- a/kotlin/direct_jdeps.bzl
+++ b/kotlin/jvm/internal_do_not_use/traverse_exports/compiler_plugin.bzl
@@ -12,15 +12,22 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""kt_traverse_exports visitor for exposing jdeps files from direct deps."""
+"""kt_compiler_plugin_visitor"""
 
-def _get_jdeps(target, _ctx_rule):
-    return [out.compile_jdeps for out in target[JavaInfo].java_outputs if out.compile_jdeps]
+load("//:visibility.bzl", "RULES_KOTLIN")
+load("//kotlin:compiler_plugin.bzl", "KtCompilerPluginInfo")
 
-kt_direct_jdeps_visitor = struct(
-    name = "direct_jdeps",
-    visit_target = _get_jdeps,
+def _get_exported_plugins(_target, ctx_rule):
+    return [
+        t[KtCompilerPluginInfo]
+        for t in getattr(ctx_rule.attr, "exported_plugins", [])
+        if (KtCompilerPluginInfo in t)
+    ]
+
+kt_compiler_plugin_visitor = struct(
+    name = "compiler_plugins",
+    visit_target = _get_exported_plugins,
     filter_edge = None,
-    process_unvisited_target = None,
     finish_expansion = None,
+    process_unvisited_target = None,
 )
diff --git a/kotlin/direct_jdeps.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/direct_jdeps.bzl
similarity index 84%
rename from kotlin/direct_jdeps.bzl
rename to kotlin/jvm/internal_do_not_use/traverse_exports/direct_jdeps.bzl
index f242989..8bbb75f 100644
--- a/kotlin/direct_jdeps.bzl
+++ b/kotlin/jvm/internal_do_not_use/traverse_exports/direct_jdeps.bzl
@@ -14,8 +14,14 @@
 
 """kt_traverse_exports visitor for exposing jdeps files from direct deps."""
 
+load("//:visibility.bzl", "RULES_KOTLIN")
+
 def _get_jdeps(target, _ctx_rule):
-    return [out.compile_jdeps for out in target[JavaInfo].java_outputs if out.compile_jdeps]
+    return [
+        out.compile_jdeps
+        for out in target[JavaInfo].java_outputs
+        if out.compile_jdeps
+    ]
 
 kt_direct_jdeps_visitor = struct(
     name = "direct_jdeps",
diff --git a/kotlin/forbidden_deps.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/forbidden_deps.bzl
similarity index 97%
rename from kotlin/forbidden_deps.bzl
rename to kotlin/jvm/internal_do_not_use/traverse_exports/forbidden_deps.bzl
index 67a04fb..fa1db86 100644
--- a/kotlin/forbidden_deps.bzl
+++ b/kotlin/jvm/internal_do_not_use/traverse_exports/forbidden_deps.bzl
@@ -22,6 +22,7 @@
 
 load("@bazel_skylib//lib:sets.bzl", "sets")
 load("//bazel:stubs.bzl", "EXEMPT_DEPS", "FORBIDDEN_DEP_PACKAGES")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 def _error(target, msg):
     return (str(target.label), msg)
diff --git a/kotlin/friend_jars.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/friend_jars.bzl
similarity index 95%
rename from kotlin/friend_jars.bzl
rename to kotlin/jvm/internal_do_not_use/traverse_exports/friend_jars.bzl
index 1be3f63..68cf1a6 100644
--- a/kotlin/friend_jars.bzl
+++ b/kotlin/jvm/internal_do_not_use/traverse_exports/friend_jars.bzl
@@ -12,7 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""TODO: Write module docstring."""
+"""kt_friend_visitor"""
+
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 def is_eligible_friend(target, friend):
     """
@@ -25,7 +27,7 @@
       4. `target` in `test/java/` pkg, `friend` in parallel `main/java/` pkg
 
     Args:
-      target: (target) The current target
+      target: (Target) The current target
       friend: (Target) A potential friend of `target`
 
     Returns:
diff --git a/kotlin/java_plugin.internal.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/java_plugin.bzl
similarity index 90%
rename from kotlin/java_plugin.internal.bzl
rename to kotlin/jvm/internal_do_not_use/traverse_exports/java_plugin.bzl
index 69e7bb5..b993b75 100644
--- a/kotlin/java_plugin.internal.bzl
+++ b/kotlin/jvm/internal_do_not_use/traverse_exports/java_plugin.bzl
@@ -19,11 +19,12 @@
 from the way that java targets handles plugins.
 """
 
+load("//:visibility.bzl", "RULES_KOTLIN")
+
 def _get_java_plugins(_target, ctx_rule):
-    exported_plugins = getattr(ctx_rule.attr, "exported_plugins", [])
     return [
         t[JavaPluginInfo].plugins
-        for t in exported_plugins
+        for t in getattr(ctx_rule.attr, "exported_plugins", [])
         if JavaPluginInfo in t
     ]
 
diff --git a/kotlin/jvm/internal_do_not_use/traverse_exports/traverse_exports.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/traverse_exports.bzl
new file mode 100644
index 0000000..f0f9e6a
--- /dev/null
+++ b/kotlin/jvm/internal_do_not_use/traverse_exports/traverse_exports.bzl
@@ -0,0 +1,122 @@
+# Copyright 2022 Google LLC. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Combined aspect for all rules_kotlin behaviours that need to traverse exports."""
+
+load(":compiler_plugin.bzl", "kt_compiler_plugin_visitor")
+load(":direct_jdeps.bzl", "kt_direct_jdeps_visitor")
+load(":forbidden_deps.bzl", "kt_forbidden_deps_visitor")
+load(":friend_jars.bzl", "kt_friend_jars_visitor", "kt_friend_labels_visitor")
+load(":java_plugin.bzl", "java_plugin_visitor")
+load("//:visibility.bzl", "RULES_KOTLIN")
+
+# java_xxx_proto_library don't populate java_outputs but we can get them through
+# required_aspect_providers from their proto_library deps.
+_DEPS_AS_EXPORTS_RULES = [
+    "java_proto_library",
+    "java_lite_proto_library",
+    "java_mutable_proto_library",
+]
+
+_NO_SRCS_DEPS_AS_EXPORTS_RULES = [
+    "proto_library",
+]
+
+# visitor = struct[T](
+#     name = string,
+#     visit_target = function(Target, ctx.rule): list[T],
+#     filter_edge = None|(function(src: ?, dest: Target): bool),
+#     process_unvisited_target = None|(function(Target): list[T]),
+#     finish_expansion = None|(function(depset[T]): depset[T]),
+# )
+_VISITORS = [
+    kt_forbidden_deps_visitor,
+    kt_direct_jdeps_visitor,
+    kt_compiler_plugin_visitor,
+    kt_friend_jars_visitor,
+    kt_friend_labels_visitor,
+    java_plugin_visitor,
+]
+
+_KtTraverseExportsInfo = provider(
+    doc = "depsets for transitive info about exports",
+    fields = {
+        v.name: ("depset[%s]" % v.name)
+        for v in _VISITORS
+    },
+)
+
+_EMPTY_KT_TRAVERSE_EXPORTS_INFO = _KtTraverseExportsInfo(**{
+    v.name: depset()
+    for v in _VISITORS
+})
+
+def _aspect_impl(target, ctx):
+    if not (JavaInfo in target):
+        # Ignore non-JVM targets. This also chops-up the
+        # traversal domain at these targets.
+        # TODO: Support non-JVM targets for KMP
+        return _EMPTY_KT_TRAVERSE_EXPORTS_INFO
+
+    exports = []
+    exports.extend(getattr(ctx.rule.attr, "exports", []))  # exports list is frozen
+    if ctx.rule.kind in _DEPS_AS_EXPORTS_RULES:
+        exports.extend(ctx.rule.attr.deps)
+    elif ctx.rule.kind in _NO_SRCS_DEPS_AS_EXPORTS_RULES and not ctx.rule.attr.srcs:
+        exports.extend(ctx.rule.attr.deps)
+
+    return _KtTraverseExportsInfo(**{
+        v.name: depset(
+            direct = v.visit_target(target, ctx.rule),
+            transitive = [
+                getattr(e[_KtTraverseExportsInfo], v.name)
+                for e in exports
+                if (not v.filter_edge or v.filter_edge(target, e))
+            ],
+        )
+        for v in _VISITORS
+    })
+
+_aspect = aspect(
+    implementation = _aspect_impl,
+    provides = [_KtTraverseExportsInfo],
+    # Transitively check exports, since they are effectively directly depended on.
+    # "deps" needed for rules that treat deps as exports (usually absent srcs).
+    attr_aspects = ["exports", "deps"],
+    required_aspect_providers = [JavaInfo],  # to get at JavaXxxProtoAspects' JavaInfos
+)
+
+def _create_visitor_expand(visitor):
+    def _visitor_expand(targets, root = None):
+        direct = []
+        transitive = []
+        for t in targets:
+            if (not visitor.filter_edge or visitor.filter_edge(root, t)):
+                if _KtTraverseExportsInfo in t:
+                    transitive.append(getattr(t[_KtTraverseExportsInfo], visitor.name))
+                elif visitor.process_unvisited_target:
+                    direct.extend(visitor.process_unvisited_target(t))
+
+        expanded_set = depset(direct = direct, transitive = transitive)
+        return visitor.finish_expansion(expanded_set) if visitor.finish_expansion else expanded_set
+
+    return _visitor_expand
+
+kt_traverse_exports = struct(
+    aspect = _aspect,
+    **{
+        "expand_" + v.name: _create_visitor_expand(v)
+        for v in _VISITORS
+    }
+)
diff --git a/kotlin/direct_jdeps.bzl b/kotlin/jvm/internal_do_not_use/util/BUILD
similarity index 60%
copy from kotlin/direct_jdeps.bzl
copy to kotlin/jvm/internal_do_not_use/util/BUILD
index f242989..bcfec8d 100644
--- a/kotlin/direct_jdeps.bzl
+++ b/kotlin/jvm/internal_do_not_use/util/BUILD
@@ -12,15 +12,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""kt_traverse_exports visitor for exposing jdeps files from direct deps."""
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
 
-def _get_jdeps(target, _ctx_rule):
-    return [out.compile_jdeps for out in target[JavaInfo].java_outputs if out.compile_jdeps]
+package(default_visibility = ["//:internal"])
 
-kt_direct_jdeps_visitor = struct(
-    name = "direct_jdeps",
-    visit_target = _get_jdeps,
-    filter_edge = None,
-    process_unvisited_target = None,
-    finish_expansion = None,
+licenses(["notice"])
+
+bzl_library(
+    name = "util_bzl",
+    srcs = glob(["*.bzl"]),
+    deps = [
+        "//:visibility_bzl",
+        "@bazel_tools//tools/jdk:jvmopts",
+    ],
 )
diff --git a/kotlin/jvm/internal_do_not_use/util/class_file_selectors.bzl b/kotlin/jvm/internal_do_not_use/util/class_file_selectors.bzl
new file mode 100644
index 0000000..d5341c8
--- /dev/null
+++ b/kotlin/jvm/internal_do_not_use/util/class_file_selectors.bzl
@@ -0,0 +1,57 @@
+# Copyright 2022 Google LLC. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Selects bytecode class files with a matched source file in srcjars."""
+
+load("//:visibility.bzl", "RULES_KOTLIN")
+
+def gen_java_info_generated_class_jar(ctx, file_factory, kt_toolchain, input_jars, srcjars):
+    """Generates a class jar with class file jar entries matching files in the give srcjars.
+
+    Args:
+      ctx: A rule context.
+      file_factory: A file factory in responsible for file creation under the current context.
+      kt_toolchain: The toolchain for kotlin builds.
+      input_jars: A sequence of jar files from which class files are selected.
+      srcjars: A sequence of source jar files that the selection references to.
+    Returns:
+      The output jar file, i.e. output_jar.
+    """
+    output_jar = file_factory.declare_file("-java_info_generated_class_jar.jar")
+    input_jars = depset(input_jars)
+    transformer_env_files = depset(srcjars)
+
+    transformer_entry_point = "com.google.devtools.jar.transformation.ClassFileSelectorBySourceFile"
+    transformer_jars = kt_toolchain.class_file_selector_by_source_file[JavaInfo].transitive_runtime_jars
+    jar_transformer = kt_toolchain.jar_transformer[DefaultInfo].files_to_run
+
+    args = ctx.actions.args()
+    args.add_joined("--input_jars", input_jars, join_with = ",")
+    args.add_joined("--transformer_jars", transformer_jars, join_with = ",")
+    args.add("--transformer_entry_point", transformer_entry_point)
+    args.add_joined("--transformer_env_files", transformer_env_files, join_with = ",")
+    args.add("--result", output_jar)
+    ctx.actions.run(
+        inputs = depset(transitive = [
+            input_jars,
+            transformer_jars,
+            transformer_env_files,
+        ]),
+        outputs = [output_jar],
+        arguments = [args],
+        progress_message = "Generating JavaInfo.generated_class_jar into %{output}",
+        mnemonic = "ClassFileSelectorBySourceFile",
+        executable = jar_transformer,
+    )
+    return output_jar
diff --git a/kotlin/jvm/internal_do_not_use/util/file_factory.bzl b/kotlin/jvm/internal_do_not_use/util/file_factory.bzl
new file mode 100644
index 0000000..2e076c3
--- /dev/null
+++ b/kotlin/jvm/internal_do_not_use/util/file_factory.bzl
@@ -0,0 +1,59 @@
+# Copyright 2022 Google LLC. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""FileFactory"""
+
+load("//:visibility.bzl", "RULES_KOTLIN")
+
+def FileFactory(ctx, base):
+    """Creates files with names derived from some base file or prefix
+
+    Including the name of a rule is not always enough to guarantee unique filenames. For example,
+    helper functions that declare their own output files may be called multiple times in the same
+    rule impl.
+
+    Args:
+        ctx: ctx
+        base: [File|string] The file to derive other filenames from, or an exact base prefix
+
+    Returns:
+        FileFactory
+    """
+
+    if type(base) == "File":
+        base = _scrub_base_file(ctx, base)
+
+    def declare_directory(suffix):
+        return ctx.actions.declare_directory(base + suffix)
+
+    def declare_file(suffix):
+        return ctx.actions.declare_file(base + suffix)
+
+    def derive(suffix):
+        return FileFactory(ctx, base + suffix)
+
+    return struct(
+        base_as_path = ctx.bin_dir.path + "/" + ctx.label.package + "/" + base,
+        declare_directory = declare_directory,
+        declare_file = declare_file,
+        derive = derive,
+    )
+
+def _scrub_base_file(ctx, file):
+    if not file.extension:
+        fail("Base file must have an extension: was %s" % (file.path))
+    if file.owner.package != ctx.label.package:
+        fail("Base file must be from ctx package: was %s expected %s" % (file.owner.package, ctx.label.package))
+
+    return file.short_path.removeprefix(ctx.label.package + "/").rsplit(".", 1)[0]
diff --git a/kotlin/jvm/internal_do_not_use/util/run_deploy_jar.bzl b/kotlin/jvm/internal_do_not_use/util/run_deploy_jar.bzl
new file mode 100644
index 0000000..14c784b
--- /dev/null
+++ b/kotlin/jvm/internal_do_not_use/util/run_deploy_jar.bzl
@@ -0,0 +1,54 @@
+# Copyright 2022 Google LLC. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""kt_run_deploy_jar"""
+
+# go/keep-sorted start
+load("//:visibility.bzl", "RULES_KOTLIN")
+load("//bazel:stubs.bzl", "BASE_JVMOPTS")
+# go/keep-sorted end
+
+def kt_run_deploy_jar(
+        ctx,
+        java_runtime,
+        deploy_jar,
+        inputs,
+        args = [],
+        deploy_jsa = None,
+        **kwargs):
+    """An analogue to ctx.actions.run for _deploy.jar executables."""
+
+    java_args = ctx.actions.args()
+    java_inputs = []
+    if deploy_jsa:
+        java_args.add("-Xshare:auto")
+        java_args.add(deploy_jsa, format = "-XX:SharedArchiveFile=%s")
+        java_args.add("-XX:-VerifySharedSpaces")
+        java_args.add("-XX:-ValidateSharedClassPaths")
+        java_inputs.append(deploy_jsa)
+    java_args.add("-jar", deploy_jar)
+    java_inputs.append(deploy_jar)
+
+    java_depset = depset(direct = java_inputs, transitive = [java_runtime[DefaultInfo].files])
+    if type(inputs) == "depset":
+        all_inputs = depset(transitive = [java_depset, inputs])
+    else:
+        all_inputs = depset(direct = inputs, transitive = [java_depset])
+
+    ctx.actions.run(
+        executable = str(java_runtime[java_common.JavaRuntimeInfo].java_executable_exec_path),
+        inputs = all_inputs,
+        arguments = BASE_JVMOPTS + [java_args] + args,
+        **kwargs
+    )
diff --git a/kotlin/jvm/internal_do_not_use/util/srcjars.bzl b/kotlin/jvm/internal_do_not_use/util/srcjars.bzl
new file mode 100644
index 0000000..becf573
--- /dev/null
+++ b/kotlin/jvm/internal_do_not_use/util/srcjars.bzl
@@ -0,0 +1,183 @@
+# Copyright 2022 Google LLC. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""kt_srcjars"""
+
+# go/keep-sorted start
+load("//:visibility.bzl", "RULES_KOTLIN")
+load(":run_deploy_jar.bzl", "kt_run_deploy_jar")
+# go/keep-sorted end
+
+def _zip(
+        ctx,
+        kt_jvm_toolchain,
+        out_jar,
+        srcs = [],
+        common_srcs = [],
+        ignore_not_allowed_files = False):
+    """Creates a srcjar from a set of Kotlin and Java srcs
+
+    Paths inside the srcjar are derived from the package name in the source file.
+    """
+
+    args = ctx.actions.args()
+    args.add("zip")
+    args.add(out_jar)
+    args.add_joined("--kotlin_srcs", srcs, join_with = ",")
+    args.add_joined("--common_srcs", common_srcs, join_with = ",")
+    if ignore_not_allowed_files:
+        args.add("-i")
+
+    kt_run_deploy_jar(
+        ctx = ctx,
+        java_runtime = kt_jvm_toolchain.java_runtime,
+        deploy_jar = kt_jvm_toolchain.source_jar_zipper,
+        inputs = srcs + common_srcs,
+        outputs = [out_jar],
+        args = [args],
+        mnemonic = "KtJar",
+        progress_message = "Create Jar (kotlin/common.bzl): %{output}",
+    )
+
+    return out_jar
+
+def _unzip(
+        ctx,
+        kt_jvm_toolchain,
+        dir,
+        input):
+    args = ctx.actions.args()
+    args.add("unzip", input)
+    args.add(dir.path)
+
+    kt_run_deploy_jar(
+        ctx = ctx,
+        java_runtime = kt_jvm_toolchain.java_runtime,
+        deploy_jar = kt_jvm_toolchain.source_jar_zipper,
+        inputs = [input],
+        outputs = [dir],
+        args = [args],
+        mnemonic = "SrcJarUnzip",
+    )
+
+    return dir
+
+def _zip_resources(ctx, kt_jvm_toolchain, output_jar, input_dirs):
+    """Packs a sequence of tree artifacts into a single jar.
+
+    Given the following file directory structure,
+        /usr/home/a/x/1.txt
+        /usr/home/b/y/1.txt
+    with an input_dirs as [
+        "/usr/home/a",
+        "/usr/home/b",
+    ],
+    The tool produces a jar with in-archive structure of,
+        x/1.txt
+        y/1.txt
+
+    The function fails on the duplicate jar entry case. e.g. if we pass an
+    input_dirs as [
+        "/usr/home/a/x",
+        "/usr/home/b/y",
+    ],
+    then the blaze action would fail with an error message.
+        "java.lang.IllegalStateException: 1.txt has the same path as 1.txt!
+        If it is intended behavior rename one or both of them."
+
+    Args:
+        ctx: The build rule context.
+        kt_jvm_toolchain: Toolchain containing the jar tool.
+        output_jar: The jar to be produced by this action.
+        input_dirs: A sequence of tree artifacts to be zipped.
+
+    Returns:
+        The generated output jar, i.e. output_jar
+    """
+
+    args = ctx.actions.args()
+    args.add("zip_resources")
+    args.add(output_jar)
+    args.add_joined(
+        "--input_dirs",
+        input_dirs,
+        join_with = ",",
+        omit_if_empty = False,
+        expand_directories = False,
+    )
+
+    kt_run_deploy_jar(
+        ctx = ctx,
+        java_runtime = kt_jvm_toolchain.java_runtime,
+        deploy_jar = kt_jvm_toolchain.source_jar_zipper,
+        inputs = input_dirs,
+        outputs = [output_jar],
+        args = [args],
+        mnemonic = "KtJarActionFromTreeArtifacts",
+        progress_message = "Create Jar %{output}",
+    )
+
+    return output_jar
+
+def _DirSrcjarSyncer(
+        ctx,
+        kt_jvm_toolchain,
+        file_factory):
+    """Synchronizes the contents of a set of srcjar files and tree-artifacts"""
+
+    _dirs = []
+    _srcjars = []
+
+    def add_dirs(dirs):
+        if not dirs:
+            return
+
+        _dirs.extend(dirs)
+        _srcjars.append(
+            _zip_resources(
+                ctx,
+                kt_jvm_toolchain,
+                file_factory.declare_file("%s-codegen.srcjar" % len(_srcjars)),
+                dirs,
+            ),
+        )
+
+    def add_srcjars(srcjars):
+        if not srcjars:
+            return
+
+        for srcjar in srcjars:
+            _dirs.append(
+                _unzip(
+                    ctx,
+                    kt_jvm_toolchain,
+                    file_factory.declare_directory("%s.expand" % len(_dirs)),
+                    srcjar,
+                ),
+            )
+        _srcjars.extend(srcjars)
+
+    return struct(
+        add_dirs = add_dirs,
+        add_srcjars = add_srcjars,
+        dirs = _dirs,
+        srcjars = _srcjars,
+    )
+
+kt_srcjars = struct(
+    zip = _zip,
+    unzip = _unzip,
+    zip_resources = _zip_resources,
+    DirSrcjarSyncer = _DirSrcjarSyncer,
+)
diff --git a/kotlin/jvm_compile.bzl b/kotlin/jvm_compile.bzl
index 4139150..9b195b4 100644
--- a/kotlin/jvm_compile.bzl
+++ b/kotlin/jvm_compile.bzl
@@ -17,7 +17,7 @@
 load(":common.bzl", "common")
 load(":compiler_plugin.bzl", "KtCompilerPluginInfo")
 load(":traverse_exports.bzl", "kt_traverse_exports")
-load("@bazel_skylib//lib:sets.bzl", "sets")
+load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN")
 
 _RULE_FAMILY = common.RULE_FAMILY
 
@@ -115,10 +115,7 @@
         # Allow passing either a target or a provider until all callers are updated
         java_toolchain = java_toolchain[java_common.JavaToolchainInfo]
 
-    srcs = list(srcs)
-    classpath_resources = list(classpath_resources)
     java_infos = []
-    codegen_output_java_infos = []
 
     # The r_java field only support Android resources Jar files. For now, verify
     # that the name of the jar matches "_resources.jar". This check does not to
@@ -132,17 +129,13 @@
                      "'*_resources.jar'.")
         r_java_infos.append(r_java)
 
-    pre_processed_java_plugin_processors = sets.make([])
-
     # Skip deps validation check for any android_library target with no kotlin sources: b/239721906
     has_kt_srcs = any([common.is_kt_src(src) for src in srcs])
     if rule_family != _RULE_FAMILY.ANDROID_LIBRARY or has_kt_srcs:
         kt_traverse_exports.expand_forbidden_deps(deps + runtime_deps + exports)
 
     for dep in deps:
-        if False:
-            pass
-        elif JavaInfo in dep:
+        if JavaInfo in dep:
             java_infos.append(dep[JavaInfo])
         else:
             fail("Unexpected dependency (must provide JavaInfo): %s" % dep.label)
@@ -152,13 +145,10 @@
 
     return common.kt_jvm_library(
         ctx,
-        android_lint_plugins = [p[JavaInfo] for p in android_lint_plugins],
-        android_lint_rules_jars = android_lint_rules_jars,
         classpath_resources = classpath_resources,
         common_srcs = common_srcs,
         coverage_srcs = coverage_srcs,
                 deps = r_java_infos + java_infos,
-        codegen_output_java_infos = codegen_output_java_infos,
         disable_lint_checks = disable_lint_checks,
         exported_plugins = [e[JavaPluginInfo] for e in exported_plugins if (JavaPluginInfo in e)],
         # Not all exported targets contain a JavaInfo (e.g. some only have CcInfo)
@@ -176,7 +166,13 @@
         output = output,
         output_srcjar = output_srcjar,
         plugins = common.kt_plugins_map(
-            java_plugin_infos = [plugin[JavaPluginInfo] for plugin in plugins if (JavaPluginInfo in plugin)],
+            android_lint_singlejar_plugins = android_lint_rules_jars,
+            android_lint_libjar_plugin_infos = [p[JavaInfo] for p in android_lint_plugins],
+            java_plugin_infos = [
+                plugin[JavaPluginInfo]
+                for plugin in plugins
+                if (JavaPluginInfo in plugin)
+            ],
             kt_compiler_plugin_infos =
                 kt_traverse_exports.expand_compiler_plugins(deps).to_list() + [
                     plugin[KtCompilerPluginInfo]
@@ -184,7 +180,6 @@
                     if (KtCompilerPluginInfo in plugin)
                 ],
         ),
-        pre_processed_java_plugin_processors = pre_processed_java_plugin_processors,
         resource_files = resource_files,
         runtime_deps = [d[JavaInfo] for d in runtime_deps if JavaInfo in d],
         srcs = srcs,
diff --git a/kotlin/jvm_import.bzl b/kotlin/jvm_import.bzl
index c42bb96..5f7c6ed 100644
--- a/kotlin/jvm_import.bzl
+++ b/kotlin/jvm_import.bzl
@@ -20,6 +20,7 @@
 load("//toolchains/kotlin_jvm:java_toolchains.bzl", "java_toolchains")
 load("@bazel_skylib//lib:dicts.bzl", "dicts")
 load(":compiler_plugin.bzl", "KtCompilerPluginInfo")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 def _kt_jvm_import_impl(ctx):
     kt_jvm_toolchain = kt_jvm_toolchains.get(ctx)
@@ -72,12 +73,10 @@
     java_toolchains.attrs,
     kt_jvm_toolchains.attrs,
     deps = attr.label_list(
-        # We allow android rule deps to make importing android JARs easier.
-        allow_rules = common.ALLOWED_JVM_RULES + common.ALLOWED_ANDROID_RULES,
         aspects = [kt_traverse_exports.aspect],
         providers = [
             # Each provider-set expands on allow_rules
-            [JavaInfo],
+            [JavaInfo],  # We allow android rule deps to make importing android JARs easier.
         ],
         doc = """The list of libraries this library directly depends on at compile-time. For Java
                  and Kotlin libraries listed, the Jars they build as well as the transitive closure
@@ -115,10 +114,9 @@
         doc = """Proguard specifications to go along with this library.""",
     ),
     runtime_deps = attr.label_list(
-        # TODO: Delete common.ALLOWED_ANDROID_RULES
-        allow_rules = common.ALLOWED_JVM_RULES + common.ALLOWED_ANDROID_RULES,
         providers = [
             # Each provider-set expands on allow_rules
+            [JavaInfo],
             [CcInfo],  # for JNI / native dependencies
         ],
         aspects = [kt_traverse_exports.aspect],
diff --git a/kotlin/jvm_library.bzl b/kotlin/jvm_library.bzl
index 916e358..9485bcf 100644
--- a/kotlin/jvm_library.bzl
+++ b/kotlin/jvm_library.bzl
@@ -17,6 +17,10 @@
 load(":jvm_library.internal.bzl", "kt_jvm_library_helper")
 load("//bazel:stubs.bzl", "register_extension_info")
 load("@bazel_skylib//lib:dicts.bzl", "dicts")
+load("//bazel:stubs.bzl", "lint_actions")
+load("//bazel:stubs.bzl", "LINT_REGISTRY")
+load("//bazel:stubs.bzl", "registry_checks_for_package")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 def kt_jvm_library(
         name,
@@ -106,6 +110,11 @@
         transitive_configs = transitive_configs,
         **dicts.add(
             kwargs,
+            {
+                # Dictionary necessary to set private attributes.
+                "$android_lint_baseline_file": lint_actions.get_android_lint_baseline_file(native.package_name()),
+                "$android_lint_plugins": registry_checks_for_package(LINT_REGISTRY, native.package_name()),
+            },
         )
     )
 
diff --git a/kotlin/jvm_library.internal.bzl b/kotlin/jvm_library.internal.bzl
index 85b9e52..22e6ef1 100644
--- a/kotlin/jvm_library.internal.bzl
+++ b/kotlin/jvm_library.internal.bzl
@@ -15,6 +15,7 @@
 """Kotlin kt_jvm_library rule."""
 
 load("//kotlin:compiler_opt.bzl", "kotlincopts_attrs", "merge_kotlincopts")
+load("//toolchains/kotlin_jvm:androidlint_toolchains.bzl", "androidlint_toolchains")
 load("//toolchains/kotlin_jvm:java_toolchains.bzl", "java_toolchains")
 load("//toolchains/kotlin_jvm:kt_jvm_toolchains.bzl", "kt_jvm_toolchains")
 load("@bazel_skylib//lib:dicts.bzl", "dicts")
@@ -124,6 +125,7 @@
     ]
 
 _KT_JVM_LIBRARY_ATTRS = dicts.add(
+    androidlint_toolchains.attrs,
     java_toolchains.attrs,
     kotlincopts_attrs(),
     kt_jvm_toolchains.attrs,
@@ -137,9 +139,9 @@
         allow_files = True,
     ),
     deps = attr.label_list(
-        allow_rules = common.ALLOWED_JVM_RULES,
         providers = [
             # Each provider-set expands on allow_rules
+            [JavaInfo],
         ],
         aspects = [
             kt_traverse_exports.aspect,
@@ -171,9 +173,9 @@
                      will not run kotlinc plugins""",
     ),
     exports = attr.label_list(
-        allow_rules = common.ALLOWED_JVM_RULES,
         providers = [
             # Each provider-set expands on allow_rules
+            [JavaInfo],
         ],
         aspects = [
             kt_traverse_exports.aspect,
@@ -214,9 +216,9 @@
                          go/be#java_library.resources.""",
     ),
     runtime_deps = attr.label_list(
-        allow_rules = common.ALLOWED_JVM_RULES,
         providers = [
             # Each provider-set expands on allow_rules
+            [JavaInfo],
             [CcInfo],  # for JNI / native dependencies
         ],
         aspects = [
diff --git a/kotlin/jvm_test.bzl b/kotlin/jvm_test.bzl
index 1c19902..2a85a66 100644
--- a/kotlin/jvm_test.bzl
+++ b/kotlin/jvm_test.bzl
@@ -16,6 +16,7 @@
 
 load(":jvm_library.bzl", "kt_jvm_library")
 load("//bazel:stubs.bzl", "register_extension_info")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 def _lib_name(name):
     return "%s_DO_NOT_DEPEND_LIB" % name
diff --git a/kotlin/rules.bzl b/kotlin/rules.bzl
index 8d0188b..f08a1f2 100644
--- a/kotlin/rules.bzl
+++ b/kotlin/rules.bzl
@@ -14,10 +14,16 @@
 
 """Kotlin rules."""
 
+load("//kotlin:compiler_opt.bzl", _kt_compiler_opt = "kt_compiler_opt")
+load("//kotlin:compiler_plugin_export.bzl", _kt_compiler_plugin_export = "kt_compiler_plugin_export")
 load("//kotlin:jvm_import.bzl", _kt_jvm_import = "kt_jvm_import")
 load("//kotlin:jvm_library.bzl", _kt_jvm_library = "kt_jvm_library")
 load("//kotlin:jvm_test.bzl", _kt_jvm_test = "kt_jvm_test")
 
+kt_compiler_opt = _kt_compiler_opt
+
+kt_compiler_plugin_export = _kt_compiler_plugin_export
+
 kt_jvm_import = _kt_jvm_import
 
 kt_jvm_library = _kt_jvm_library
diff --git a/kotlin/traverse_exports.bzl b/kotlin/traverse_exports.bzl
index a8ce86f..8157ec1 100644
--- a/kotlin/traverse_exports.bzl
+++ b/kotlin/traverse_exports.bzl
@@ -14,108 +14,7 @@
 
 """Combined aspect for all rules_kotlin behaviours that need to traverse exports."""
 
-load(":compiler_plugin.bzl", "kt_compiler_plugin_visitor")
-load(":direct_jdeps.bzl", "kt_direct_jdeps_visitor")
-load(":forbidden_deps.bzl", "kt_forbidden_deps_visitor")
-load(":friend_jars.bzl", "kt_friend_jars_visitor", "kt_friend_labels_visitor")
-load(":java_plugin.internal.bzl", "java_plugin_visitor")
+load("//kotlin/jvm/internal_do_not_use/traverse_exports:traverse_exports.bzl", _kt_traverse_exports = "kt_traverse_exports")
+load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN")
 
-# java_xxx_proto_library don't populate java_outputs but we can get them through
-# required_aspect_providers from their proto_library deps.
-_DEPS_AS_EXPORTS_RULES = [
-    "java_proto_library",
-    "java_lite_proto_library",
-    "java_mutable_proto_library",
-]
-
-_NO_SRCS_DEPS_AS_EXPORTS_RULES = [
-    "proto_library",
-]
-
-# visitor = struct[T](
-#     name = string,
-#     visit_target = function(Target, ctx.rule): list[T],
-#     filter_edge = None|(function(src: ?, dest: Target): bool),
-#     process_unvisited_target = None|(function(Target): list[T]),
-#     finish_expansion = None|(function(depset[T]): depset[T]),
-# )
-_VISITORS = [
-    kt_forbidden_deps_visitor,
-    kt_direct_jdeps_visitor,
-    kt_compiler_plugin_visitor,
-    kt_friend_jars_visitor,
-    kt_friend_labels_visitor,
-    java_plugin_visitor,
-]
-
-_KtTraverseExportsInfo = provider(
-    doc = "depsets for transitive info about exports",
-    fields = {
-        v.name: ("depset[%s]" % v.name)
-        for v in _VISITORS
-    },
-)
-
-_EMPTY_KT_TRAVERSE_EXPORTS_INFO = _KtTraverseExportsInfo(**{
-    v.name: depset()
-    for v in _VISITORS
-})
-
-def _aspect_impl(target, ctx):
-    if not (JavaInfo in target):
-        # Ignore non-JVM targets. This also chops-up the
-        # traversal domain at these targets.
-        # TODO: Support non-JVM targets for KMP
-        return _EMPTY_KT_TRAVERSE_EXPORTS_INFO
-
-    exports = []
-    exports.extend(getattr(ctx.rule.attr, "exports", []))  # exports list is frozen
-    if ctx.rule.kind in _DEPS_AS_EXPORTS_RULES:
-        exports.extend(ctx.rule.attr.deps)
-    elif ctx.rule.kind in _NO_SRCS_DEPS_AS_EXPORTS_RULES and not ctx.rule.attr.srcs:
-        exports.extend(ctx.rule.attr.deps)
-
-    return _KtTraverseExportsInfo(**{
-        v.name: depset(
-            direct = v.visit_target(target, ctx.rule),
-            transitive = [
-                getattr(e[_KtTraverseExportsInfo], v.name)
-                for e in exports
-                if (not v.filter_edge or v.filter_edge(target, e))
-            ],
-        )
-        for v in _VISITORS
-    })
-
-_aspect = aspect(
-    implementation = _aspect_impl,
-    provides = [_KtTraverseExportsInfo],
-    # Transitively check exports, since they are effectively directly depended on.
-    # "deps" needed for rules that treat deps as exports (usually absent srcs).
-    attr_aspects = ["exports", "deps"],
-    required_aspect_providers = [JavaInfo],  # to get at JavaXxxProtoAspects' JavaInfos
-)
-
-def _create_visitor_expand(visitor):
-    def _visitor_expand(targets, root = None):
-        direct = []
-        transitive = []
-        for t in targets:
-            if (not visitor.filter_edge or visitor.filter_edge(root, t)):
-                if _KtTraverseExportsInfo in t:
-                    transitive.append(getattr(t[_KtTraverseExportsInfo], visitor.name))
-                elif visitor.process_unvisited_target:
-                    direct.extend(visitor.process_unvisited_target(t))
-
-        expanded_set = depset(direct = direct, transitive = transitive)
-        return visitor.finish_expansion(expanded_set) if visitor.finish_expansion else expanded_set
-
-    return _visitor_expand
-
-kt_traverse_exports = struct(
-    aspect = _aspect,
-    **{
-        "expand_" + v.name: _create_visitor_expand(v)
-        for v in _VISITORS
-    }
-)
+kt_traverse_exports = _kt_traverse_exports
diff --git a/tests/analysis/assert_failure_test.bzl b/tests/analysis/assert_failure_test.bzl
index b266c2a..2a742c3 100644
--- a/tests/analysis/assert_failure_test.bzl
+++ b/tests/analysis/assert_failure_test.bzl
@@ -15,6 +15,7 @@
 """An assertion for analysis failure."""
 
 load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 def _assert_failure_test_impl(ctx):
     env = analysistest.begin(ctx)
diff --git a/tests/analysis/compiler_plugin/propagation/assert_propagation_test.bzl b/tests/analysis/compiler_plugin/propagation/assert_propagation_test.bzl
index fe8c9dc..0c1b02a 100644
--- a/tests/analysis/compiler_plugin/propagation/assert_propagation_test.bzl
+++ b/tests/analysis/compiler_plugin/propagation/assert_propagation_test.bzl
@@ -17,6 +17,7 @@
 load("@bazel_skylib//lib:sets.bzl", "sets")
 load("@bazel_skylib//rules:build_test.bzl", "build_test")
 load("//kotlin:traverse_exports.bzl", "kt_traverse_exports")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 def _assert_propagation_impl(ctx):
     expected_ids = sets.make(ctx.attr.expected_plugin_ids)
diff --git a/tests/analysis/compiler_plugin/provider_ctor/fake_compiler_plugin.bzl b/tests/analysis/compiler_plugin/provider_ctor/fake_compiler_plugin.bzl
index d4a6bac..194025d 100644
--- a/tests/analysis/compiler_plugin/provider_ctor/fake_compiler_plugin.bzl
+++ b/tests/analysis/compiler_plugin/provider_ctor/fake_compiler_plugin.bzl
@@ -15,6 +15,7 @@
 """A fake impl of kt_compiler_plugin."""
 
 load("//kotlin:compiler_plugin.bzl", "KtCompilerPluginInfo")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 def _kt_fake_compiler_plugin_impl(ctx):
     return [
diff --git a/tests/analysis/compiler_plugin/provider_output/assert_compiler_plugin_test.bzl b/tests/analysis/compiler_plugin/provider_output/assert_compiler_plugin_test.bzl
index 9b2951e..f4e1849 100644
--- a/tests/analysis/compiler_plugin/provider_output/assert_compiler_plugin_test.bzl
+++ b/tests/analysis/compiler_plugin/provider_output/assert_compiler_plugin_test.bzl
@@ -16,6 +16,7 @@
 
 load("//kotlin:compiler_plugin.bzl", "KtCompilerPluginInfo")
 load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 def _test_impl(ctx):
     env = analysistest.begin(ctx)
diff --git a/tests/analysis/for_test.bzl b/tests/analysis/for_test.bzl
index 434c1a4..2a75726 100644
--- a/tests/analysis/for_test.bzl
+++ b/tests/analysis/for_test.bzl
@@ -16,6 +16,7 @@
 
 load("//kotlin:jvm_library.bzl", "kt_jvm_library")
 load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 def _kt_jvm_library_for_test(name, **kwargs):
     kt_jvm_library(
diff --git a/tests/analysis/internal_do_not_use/util/file_factory/BUILD b/tests/analysis/internal_do_not_use/util/file_factory/BUILD
new file mode 100644
index 0000000..d92e379
--- /dev/null
+++ b/tests/analysis/internal_do_not_use/util/file_factory/BUILD
@@ -0,0 +1,41 @@
+# Copyright 2022 Google LLC. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+load(":happy_test.bzl", "file_factory_happy_test")
+load(":check_base_file_valid.bzl", "check_base_file_valid")
+load("//tests/analysis:assert_failure_test.bzl", "assert_failure_test")
+
+licenses(["notice"])
+
+file_factory_happy_test(
+    name = "happy_test",
+)
+
+assert_failure_test(
+    name = "base_without_extension_test",
+    msg_contains = "file must have an extension",
+    target_under_test = check_base_file_valid(
+        name = "base_without_extension",
+        base_file = "BUILD",
+    ),
+)
+
+assert_failure_test(
+    name = "base_from_other_package_test",
+    msg_contains = "file must be from ctx package",
+    target_under_test = check_base_file_valid(
+        name = "base_from_other_package",
+        base_file = "//tests/analysis/internal_do_not_use/util/file_factory/sub",
+    ),
+)
diff --git a/tests/analysis/internal_do_not_use/util/file_factory/check_base_file_valid.bzl b/tests/analysis/internal_do_not_use/util/file_factory/check_base_file_valid.bzl
new file mode 100644
index 0000000..9ca1f05
--- /dev/null
+++ b/tests/analysis/internal_do_not_use/util/file_factory/check_base_file_valid.bzl
@@ -0,0 +1,38 @@
+# Copyright 2022 Google LLC. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Happy tests for FileFactory."""
+
+load("//kotlin/jvm/internal_do_not_use/util:file_factory.bzl", "FileFactory")
+load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS")
+load("//:visibility.bzl", "RULES_KOTLIN")
+
+def _check_base_file_valid_impl(ctx):
+    FileFactory(ctx, ctx.file.base_file)
+    return []
+
+_check_base_file_valid = rule(
+    implementation = _check_base_file_valid_impl,
+    attrs = dict(
+        base_file = attr.label(allow_single_file = True, mandatory = True),
+    ),
+)
+
+def check_base_file_valid(name, tags = [], **kwargs):
+    _check_base_file_valid(
+        name = name,
+        tags = tags + ONLY_FOR_ANALYSIS_TEST_TAGS,
+        **kwargs
+    )
+    return name
diff --git a/tests/analysis/internal_do_not_use/util/file_factory/happy_test.bzl b/tests/analysis/internal_do_not_use/util/file_factory/happy_test.bzl
new file mode 100644
index 0000000..1a2a655
--- /dev/null
+++ b/tests/analysis/internal_do_not_use/util/file_factory/happy_test.bzl
@@ -0,0 +1,78 @@
+# Copyright 2022 Google LLC. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""file_factory_happy_test"""
+
+load("//kotlin/jvm/internal_do_not_use/util:file_factory.bzl", "FileFactory")
+load("//:visibility.bzl", "RULES_KOTLIN")
+
+def _test_base_from_file(ctx, pkg_path):
+    base_file = ctx.actions.declare_file("file/base.txt")
+    factory = FileFactory(ctx, base_file)
+
+    _assert_equals(pkg_path + "/file/base", factory.base_as_path)
+
+    return [base_file]
+
+def _test_declare(ctx, pkg_path):
+    factory = FileFactory(ctx, "string/base")
+
+    _assert_equals(pkg_path + "/string/base", factory.base_as_path)
+
+    a_file = factory.declare_file("a.txt")
+    _assert_equals(pkg_path + "/string/basea.txt", a_file.path)
+
+    b_dir = factory.declare_directory("b_dir")
+    _assert_equals(pkg_path + "/string/baseb_dir", b_dir.path)
+
+    return [a_file, b_dir]
+
+def _test_derive(ctx, pkg_path):
+    factory = FileFactory(ctx, "")
+
+    # Once
+    factory_once = factory.derive("once")
+    _assert_equals(pkg_path + "/once", factory_once.base_as_path)
+
+    # Twice
+    factory_twice = factory_once.derive("/twice")
+    _assert_equals(pkg_path + "/once/twice", factory_twice.base_as_path)
+
+def _assert_equals(expected, actual):
+    if expected != actual:
+        fail("Expected '%s' but was '%s'" % (expected, actual))
+
+def _file_factory_happy_test_impl(ctx):
+    pkg_path = ctx.bin_dir.path + "/" + ctx.label.package
+    all_files = []
+
+    all_files.extend(_test_base_from_file(ctx, pkg_path))
+    all_files.extend(_test_declare(ctx, pkg_path))
+    _test_derive(ctx, pkg_path)
+
+    ctx.actions.run_shell(
+        outputs = all_files,
+        command = "exit 1",
+    )
+
+    test_script = ctx.actions.declare_file(ctx.label.name + "_test.sh")
+    ctx.actions.write(test_script, "#!/bin/bash", True)
+    return [
+        DefaultInfo(executable = test_script),
+    ]
+
+file_factory_happy_test = rule(
+    implementation = _file_factory_happy_test_impl,
+    test = True,
+)
diff --git a/kotlin/direct_jdeps.bzl b/tests/analysis/internal_do_not_use/util/file_factory/sub/BUILD
similarity index 60%
copy from kotlin/direct_jdeps.bzl
copy to tests/analysis/internal_do_not_use/util/file_factory/sub/BUILD
index f242989..db873cf 100644
--- a/kotlin/direct_jdeps.bzl
+++ b/tests/analysis/internal_do_not_use/util/file_factory/sub/BUILD
@@ -12,15 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""kt_traverse_exports visitor for exposing jdeps files from direct deps."""
+licenses(["notice"])
 
-def _get_jdeps(target, _ctx_rule):
-    return [out.compile_jdeps for out in target[JavaInfo].java_outputs if out.compile_jdeps]
-
-kt_direct_jdeps_visitor = struct(
-    name = "direct_jdeps",
-    visit_target = _get_jdeps,
-    filter_edge = None,
-    process_unvisited_target = None,
-    finish_expansion = None,
+genrule(
+    name = "sub",
+    outs = ["sub.txt"],
+    cmd = "touch $(OUTS)",
+    visibility = ["//tests/analysis/internal_do_not_use/util/file_factory:__pkg__"],
 )
diff --git a/tests/analysis/jvm_compile_test.bzl b/tests/analysis/jvm_compile_test.bzl
index b361f5a..a8fd460 100644
--- a/tests/analysis/jvm_compile_test.bzl
+++ b/tests/analysis/jvm_compile_test.bzl
@@ -22,6 +22,7 @@
 load("//toolchains/kotlin_jvm:kt_jvm_toolchains.bzl", "kt_jvm_toolchains")
 load("@bazel_skylib//rules:build_test.bzl", "build_test")
 load(":assert_failure_test.bzl", "assert_failure_test")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 def _impl(ctx):
     # As additional capabilites need to be tested, this rule should support
diff --git a/tests/analysis/jvm_import_test.bzl b/tests/analysis/jvm_import_test.bzl
index a3bfd19..6e56c02 100644
--- a/tests/analysis/jvm_import_test.bzl
+++ b/tests/analysis/jvm_import_test.bzl
@@ -19,6 +19,7 @@
 load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
 load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS", "create_file")
 load(":assert_failure_test.bzl", "assert_failure_test")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 def _impl(ctx):
     env = analysistest.begin(ctx)
diff --git a/tests/analysis/jvm_library/treeartifacts_srcs/BUILD b/tests/analysis/jvm_library/treeartifacts_srcs/BUILD
new file mode 100644
index 0000000..3d724c4
--- /dev/null
+++ b/tests/analysis/jvm_library/treeartifacts_srcs/BUILD
@@ -0,0 +1,104 @@
+# Copyright 2022 Google LLC. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+load("//tests/analysis:for_test.bzl", "rules_for_test")
+load("//tests/analysis:assert_failure_test.bzl", "assert_failure_test")
+load("//tests/analysis:jvm_library_test.bzl", "jvm_library_test")
+load("//tests/analysis:util.bzl", "create_dir")
+
+package(default_testonly = True)
+
+licenses(["notice"])
+
+jvm_library_test(
+    name = "treeartifact_basename_kotlin_test",
+    target_under_test = rules_for_test.kt_jvm_library(
+        name = "treeartifact_basename_kotlin",
+        srcs = [
+            create_dir(
+                name = "treeartifact_extension/kotlin",
+                srcs = [
+                    "Input.java",  # TODO: Reject this source
+                ],
+            ),
+        ],
+    ),
+)
+
+jvm_library_test(
+    name = "treeartifact_basename_java_test",
+    target_under_test = rules_for_test.kt_jvm_library(
+        name = "treeartifact_basename_java",
+        srcs = [
+            create_dir(
+                name = "treeartifact_extension/java",
+                srcs = [
+                    "Input.kt",  # TODO: Reject this source
+                ],
+            ),
+        ],
+    ),
+)
+
+assert_failure_test(
+    name = "treeartifact_extension_kt_test",
+    msg_contains = "/treeartifact_extension.kt",
+    target_under_test = rules_for_test.kt_jvm_library(
+        name = "treeartifact_extension_kt",
+        srcs = [
+            create_dir(
+                name = "treeartifact_extension.kt",
+            ),
+        ],
+    ),
+)
+
+assert_failure_test(
+    name = "treeartifact_extension_java_test",
+    msg_contains = "/treeartifact_extension.java",
+    target_under_test = rules_for_test.kt_jvm_library(
+        name = "treeartifact_extension_java",
+        srcs = [
+            create_dir(
+                name = "treeartifact_extension.java",
+            ),
+        ],
+    ),
+)
+
+assert_failure_test(
+    name = "treeartifact_extension_srcjar_test",
+    msg_contains = "/treeartifact_extension.srcjar",
+    target_under_test = rules_for_test.kt_jvm_library(
+        name = "treeartifact_extension_srcjar",
+        srcs = [
+            create_dir(
+                name = "treeartifact_extension.srcjar",
+            ),
+        ],
+    ),
+)
+
+assert_failure_test(
+    name = "treeartifact_no_extension_test",
+    msg_contains = "/treeartifact_no_extension",
+    target_under_test = rules_for_test.kt_jvm_library(
+        name = "treeartifact_no_extension",
+        srcs = [
+            create_dir(
+                name = "treeartifact_no_extension_dir",
+            ),
+        ],
+    ),
+)
diff --git a/tests/analysis/jvm_library/treeartifacts_srcs/Input.java b/tests/analysis/jvm_library/treeartifacts_srcs/Input.java
new file mode 100644
index 0000000..e675bc1
--- /dev/null
+++ b/tests/analysis/jvm_library/treeartifacts_srcs/Input.java
@@ -0,0 +1,16 @@
+/*
+ * * Copyright 2022 Google LLC. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
diff --git a/tests/analysis/jvm_library/treeartifacts_srcs/Input.kt b/tests/analysis/jvm_library/treeartifacts_srcs/Input.kt
new file mode 100644
index 0000000..e675bc1
--- /dev/null
+++ b/tests/analysis/jvm_library/treeartifacts_srcs/Input.kt
@@ -0,0 +1,16 @@
+/*
+ * * Copyright 2022 Google LLC. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
diff --git a/tests/analysis/jvm_library_test.bzl b/tests/analysis/jvm_library_test.bzl
index 6435cc5..d51e6e1 100644
--- a/tests/analysis/jvm_library_test.bzl
+++ b/tests/analysis/jvm_library_test.bzl
@@ -15,10 +15,11 @@
 """Kotlin kt_jvm_library rule tests."""
 
 load("//kotlin:jvm_library.bzl", "kt_jvm_library")
-load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS", "create_file", "get_action_arg")
+load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS", "create_file", "get_action", "get_arg")
 load("@bazel_skylib//lib:sets.bzl", "sets")
 load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
 load(":assert_failure_test.bzl", "assert_failure_test")
+load("//:visibility.bzl", "RULES_KOTLIN")
 
 _DEFAULT_LIST = ["__default__"]
 
@@ -84,8 +85,17 @@
         actual[JavaInfo].plugins.processor_classes.to_list(),
     )
 
+    kt_2_java_compile = get_action(actions, "Kt2JavaCompile")
+
+    if kt_2_java_compile:
+        asserts.true(
+            env,
+            kt_2_java_compile.outputs.to_list()[0].basename.endswith(".jar"),
+            "Expected first output to be a JAR (this affects the param file name).",
+        )
+
     if ctx.attr.expected_friend_jar_names != _DEFAULT_LIST:
-        friend_paths_arg = get_action_arg(actions, "Kt2JavaCompile", "-Xfriend-paths=")
+        friend_paths_arg = get_arg(kt_2_java_compile, "-Xfriend-paths=")
         friend_jar_names = [p.rsplit("/", 1)[1] for p in friend_paths_arg.split(",")] if friend_paths_arg else []
         asserts.set_equals(env, sets.make(ctx.attr.expected_friend_jar_names), sets.make(friend_jar_names))
 
diff --git a/tests/analysis/util.bzl b/tests/analysis/util.bzl
index cec0cc3..5e7e487 100644
--- a/tests/analysis/util.bzl
+++ b/tests/analysis/util.bzl
@@ -14,6 +14,8 @@
 
 """Some utils"""
 
+load("//:visibility.bzl", "RULES_KOTLIN")
+
 # Mark targets that's aren't expected to build, but are needed for analysis test assertions.
 ONLY_FOR_ANALYSIS_TEST_TAGS = ["manual", "nobuilder", "only_for_analysis_test"]
 
@@ -35,23 +37,17 @@
 
 def _create_dir_impl(ctx):
     dir = ctx.actions.declare_directory(ctx.attr.name)
-    if ctx.files.srcs:
-        ctx.actions.run_shell(
-            command = "mkdir -p {0} && cp {1} {0}".format(
-                dir.path + "/" + ctx.attr.subdir,
-                " ".join([s.path for s in ctx.files.srcs]),
-            ),
-            inputs = ctx.files.srcs,
-            outputs = [dir],
-        )
-    else:
-        ctx.actions.run_shell(
-            command = "mkdir -p {0}".format(
-                dir.path + "/" + ctx.attr.subdir,
-            ),
-            inputs = ctx.files.srcs,
-            outputs = [dir],
-        )
+
+    command = "mkdir -p {0} " + ("&& cp {1} {0}" if ctx.files.srcs else "# {1}")
+    ctx.actions.run_shell(
+        command = command.format(
+            dir.path + "/" + ctx.attr.subdir,
+            " ".join([s.path for s in ctx.files.srcs]),
+        ),
+        inputs = ctx.files.srcs,
+        outputs = [dir],
+    )
+
     return [DefaultInfo(files = depset([dir]))]
 
 _create_dir = rule(
@@ -62,7 +58,10 @@
     ),
 )
 
-def create_dir(name, subdir, srcs):
+def create_dir(
+        name,
+        subdir = None,
+        srcs = None):
     _create_dir(
         name = name,
         subdir = subdir,
@@ -70,16 +69,15 @@
     )
     return name
 
-def get_action_arg(actions, mnemonic, arg_name):
-    """Get a named arg from a specific action
+def get_action(actions, mnemonic):
+    """Get a specific action
 
     Args:
       actions: [List[Action]]
       mnemonic: [string] Identify the action whose args to search
-      arg_name: [string]
 
     Returns:
-      [Optional[string]] The arg value, or None if it couldn't be found
+      [Optional[action]] The arg value, or None if it couldn't be found
     """
     menmonic_actions = [a for a in actions if a.mnemonic == mnemonic]
     if len(menmonic_actions) == 0:
@@ -87,8 +85,22 @@
     elif len(menmonic_actions) > 1:
         fail("Expected a single '%s' action" % mnemonic)
 
-    mnemonic_action = menmonic_actions[0]
-    arg_values = [a for a in mnemonic_action.argv if a.startswith(arg_name)]
+    return menmonic_actions[0]
+
+def get_arg(action, arg_name):
+    """Get a named arg from a specific action
+
+    Args:
+      action: [Optional[Action]]
+      arg_name: [string]
+
+    Returns:
+      [Optional[string]] The arg value, or None if it couldn't be found
+    """
+    if not action:
+        return None
+
+    arg_values = [a for a in action.argv if a.startswith(arg_name)]
     if len(arg_values) == 0:
         return None
     elif len(arg_values) > 1:
diff --git a/tests/jvm/java/functions/BUILD b/tests/jvm/java/functions/BUILD
index 67c0e9e..677869f 100644
--- a/tests/jvm/java/functions/BUILD
+++ b/tests/jvm/java/functions/BUILD
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # This package tests importing extension functions.
-load("//kotlin:rules.bzl", "kt_jvm_import", "kt_jvm_library")
+load("//kotlin:rules.bzl", "kt_jvm_library")
 
 licenses(["notice"])
 
@@ -41,53 +41,34 @@
     ],
 )
 
-java_import(
-    name = "car-jar",
-    jars = ["//tests/jvm/java/functions/car:car_lib-jar"],
-    tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO,
-)
-
 kt_jvm_library(
-    name = "car_demo_jar_lib",
+    name = "car_demo_import_lib",
     srcs = ["CarDemo.kt"],
     tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO,
     deps = [
-        ":car-jar",
+        "//tests/jvm/java/functions/car:car_lib_import",
     ],
 )
 
 # This binary includes extension functions defined in an separate jar file, which
 # may be problematic if the metadata is stripped by ijar.
 java_test(
-    name = "car_jar_demo",
+    name = "car_import_demo",
     main_class = "functions.CarDemo",
-    tags = ["darwin_x86_64_compatible"] +
-           _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO,
+    tags = ["darwin_x86_64_compatible"] + _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO,
     runtime_deps = [
-        ":car_demo_jar_lib",
+        ":car_demo_import_lib",
         "@kotlinc//:kotlin_stdlib",
     ],
 )
 
-kt_jvm_import(
-    name = "car-inline-jar",
-    jars = [
-        "//tests/jvm/java/functions/car:car_inline_lib-jar",
-        "//tests/jvm/java/functions/car:car_extra_lib-jar",
-    ],
-    tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO,
-    deps = [
-        ":car-jar",
-    ],
-)
-
 kt_jvm_library(
     name = "car_demo_inline_lib",
     srcs = ["CarInlineDemo.kt"],
     tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO,
     deps = [
-        ":car-inline-jar",
-        ":car-jar",
+        "//tests/jvm/java/functions/car:car_inline_and_extra_lib_import",
+        "//tests/jvm/java/functions/car:car_lib_import",
     ],
 )
 
@@ -96,8 +77,7 @@
 java_test(
     name = "car_inline_demo",
     main_class = "functions.CarInlineDemo",
-    tags = ["darwin_x86_64_compatible"] +
-           _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO,
+    tags = ["darwin_x86_64_compatible"] + _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO,
     runtime_deps = [
         ":car_demo_inline_lib",
         "@kotlinc//:kotlin_stdlib",
diff --git a/tests/jvm/java/functions/car/BUILD b/tests/jvm/java/functions/car/BUILD
index 81f0f43..5417fd4 100644
--- a/tests/jvm/java/functions/car/BUILD
+++ b/tests/jvm/java/functions/car/BUILD
@@ -12,27 +12,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("//kotlin:rules.bzl", "kt_jvm_library")
+load("//kotlin:rules.bzl", "kt_jvm_import", "kt_jvm_library")
 
 package(default_visibility = ["//tests/jvm/java/functions:__subpackages__"])
 
 licenses(["notice"])
 
-# Make Jar files produced by helper targets visible to tests in parent package
-filegroup(
-    name = "car_lib-jar",
-    srcs = ["libcar_lib.jar"],
-)
-
-filegroup(
-    name = "car_inline_lib-jar",
-    srcs = ["libcar_inline_lib.jar"],
-)
-
-filegroup(
-    name = "car_extra_lib-jar",
-    srcs = ["libcar_extra_lib.jar"],
-)
+# During coverage builds, every library gets a dep on JaCoCo (Java Code Coverage).
+# Libjars, from libraries, only include their direct sources. Together, these behaviours
+# trigger an ImportDepsChecker error for :car-jar and :car-inline-jar. To prevent that, we disable
+# coverage builds on all downstream targets.
+_NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO = ["nozapfhahn"]
 
 kt_jvm_library(
     name = "car_lib",
@@ -40,8 +30,12 @@
         "Car.kt",
         "CarUtils.kt",
     ],
-    deps = [
-    ],
+)
+
+java_import(
+    name = "car_lib_import",
+    jars = [":libcar_lib.jar"],
+    tags = ["incomplete-deps"] + _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO,
 )
 
 kt_jvm_library(
@@ -49,6 +43,7 @@
     srcs = [
         "CarInlineUtils.kt",
     ],
+    visibility = ["//visibility:private"],
     deps = [
         ":car_lib",
     ],
@@ -59,7 +54,20 @@
     srcs = [
         "CarExtraUtils.kt",
     ],
+    visibility = ["//visibility:private"],
     deps = [
         ":car_lib",
     ],
 )
+
+kt_jvm_import(
+    name = "car_inline_and_extra_lib_import",
+    jars = [
+        ":libcar_inline_lib.jar",
+        ":libcar_extra_lib.jar",
+    ],
+    tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO,
+    deps = [
+        ":car_lib_import",
+    ],
+)
diff --git a/toolchains/kotlin_jvm/androidlint_toolchains.bzl b/toolchains/kotlin_jvm/androidlint_toolchains.bzl
new file mode 100644
index 0000000..b4c2208
--- /dev/null
+++ b/toolchains/kotlin_jvm/androidlint_toolchains.bzl
@@ -0,0 +1,37 @@
+# Copyright 2022 Google LLC. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Android Lint toolchain for Kotlin."""
+
+load("//bazel:stubs.bzl", "lint_actions")
+load("//:visibility.bzl", "RULES_KOTLIN")
+
+_ATTRS = dict(
+    _android_lint_baseline_file = attr.label(
+        allow_single_file = True,
+        cfg = "exec",
+    ),
+)
+
+def _set_baselines():
+    return {
+        # `$foo` is used to set `_foo`
+        "$android_lint_baseline_file": lint_actions.get_android_lint_baseline_file(native.package_name()),
+    }
+
+androidlint_toolchains = struct(
+    attrs = _ATTRS,
+    get_baseline = lambda ctx: getattr(ctx.file, "_android_lint_baseline_file", None),
+    set_baselines = _set_baselines,
+)
diff --git a/toolchains/kotlin_jvm/java_toolchains.bzl b/toolchains/kotlin_jvm/java_toolchains.bzl
index 63dec4e..74095de 100644
--- a/toolchains/kotlin_jvm/java_toolchains.bzl
+++ b/toolchains/kotlin_jvm/java_toolchains.bzl
@@ -14,6 +14,8 @@
 
 """Java toolchain for Kotlin."""
 
+load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN")
+
 _ATTRS = dict(
     _java_toolchain = attr.label(
         default = Label(
diff --git a/toolchains/kotlin_jvm/kt_jvm_toolchains.bzl b/toolchains/kotlin_jvm/kt_jvm_toolchains.bzl
index cc73d81..41fb769 100644
--- a/toolchains/kotlin_jvm/kt_jvm_toolchains.bzl
+++ b/toolchains/kotlin_jvm/kt_jvm_toolchains.bzl
@@ -14,14 +14,15 @@
 
 """Kotlin toolchain."""
 
-load("//bazel:stubs.bzl", "select_java_language_version")
+load("//bazel:stubs.bzl", "select_java_language_level")
+load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN")
 
 # Work around to toolchains in Google3.
 KtJvmToolchainInfo = provider()
 
-KT_VERSION = "v1_7_21"
+KT_VERSION = "v1_8_10"
 
-KT_LANG_VERSION = "1.7"
+KT_LANG_VERSION = "1.8"
 
 # Kotlin JVM toolchain type label
 _TYPE = Label("//toolchains/kotlin_jvm:kt_jvm_toolchain_type")
@@ -78,6 +79,12 @@
 
         # Allows a no source files to create an empty jar.
         "-Xallow-no-source-files",
+
+        # TODO: Remove this flag
+        "-Xuse-old-innerclasses-logic",
+
+        # TODO: Remove this flag
+        "-Xno-source-debug-extension",
     ] + other_flags
 
     # --define=extra_kt_jvm_opts is for overriding from command line.
@@ -98,11 +105,15 @@
 
 def _kt_jvm_toolchain_impl(ctx):
     kt_jvm_toolchain = dict(
+        android_java8_apis_desugared = ctx.attr.android_java8_apis_desugared,
+        android_lint_config = ctx.file.android_lint_config,
+        android_lint_runner = ctx.attr.android_lint_runner[DefaultInfo].files_to_run,
         build_marker = ctx.file.build_marker,
         coverage_instrumenter = ctx.attr.coverage_instrumenter[DefaultInfo].files_to_run,
         # Don't require JavaInfo provider for integration test convenience.
         coverage_runtime = ctx.attr.coverage_runtime[JavaInfo] if JavaInfo in ctx.attr.coverage_runtime else None,
         genclass = ctx.file.genclass,
+        header_gen_tool = ctx.attr.header_gen_tool[DefaultInfo].files_to_run if ctx.attr.header_gen_tool else None,
         jar_tool = ctx.attr.jar_tool[DefaultInfo].files_to_run,
         java_language_version = ctx.attr.java_language_version,
         java_runtime = ctx.attr.java_runtime,
@@ -129,6 +140,20 @@
 
 kt_jvm_toolchain = rule(
     attrs = dict(
+        android_java8_apis_desugared = attr.bool(
+            # Reflects a select in build rules.
+            doc = "Whether Java 8 API desugaring is enabled",
+            mandatory = True,
+        ),
+        android_lint_config = attr.label(
+            cfg = "exec",
+            allow_single_file = [".xml"],
+        ),
+        android_lint_runner = attr.label(
+            default = "//bazel:stub_tool",
+            executable = True,
+            cfg = "exec",
+        ),
         build_marker = attr.label(
             default = "//tools:build_marker",
             allow_single_file = [".jar"],
@@ -151,6 +176,11 @@
             cfg = "exec",
             allow_single_file = True,
         ),
+        header_gen_tool = attr.label(
+            executable = True,
+            allow_single_file = True,
+            cfg = "exec",
+        ),
         jar_tool = attr.label(
             default = "@bazel_tools//tools/jdk:jar",
             executable = True,
@@ -200,8 +230,6 @@
             default = [
                 "@kotlinc//:kotlin_reflect",
                 "@kotlinc//:kotlin_stdlib",
-                "@kotlinc//:kotlin_stdlib_jdk7",
-                "@kotlinc//:kotlin_stdlib_jdk8",
                 "@kotlinc//:kotlin_test_not_testonly",
             ],
             cfg = "target",
@@ -250,13 +278,12 @@
 
 def _declare(**kwargs):
     kt_jvm_toolchain(
-        # TODO: use select_java_language_level() after support for Java 8 is dropped
-        jvm_target = select_java_language_version(
-            # The JVM bytecode version to output
-            java8 = "1.8",
-            java11 = "11",
-            java_head = "18",  # https://kotlinlang.org/docs/compiler-reference.html#jvm-target-version
-        ),
+        android_java8_apis_desugared = select({
+            "//conditions:default": False,
+        }),
+        # The JVM bytecode version to output
+        # https://kotlinlang.org/docs/compiler-reference.html#jvm-target-version
+        jvm_target = "11",
         **kwargs
     )
 
diff --git a/tools/bin/source_jar_zipper_deploy.jar b/tools/bin/source_jar_zipper_deploy.jar
index 5f283fe..8c6309e 100755
--- a/tools/bin/source_jar_zipper_deploy.jar
+++ b/tools/bin/source_jar_zipper_deploy.jar
Binary files differ
diff --git a/tools/java/com/google/devtools/kotlin/SourceJarZipper.kt b/tools/java/com/google/devtools/kotlin/SourceJarZipper.kt
index ac57efe..c2d34d8 100644
--- a/tools/java/com/google/devtools/kotlin/SourceJarZipper.kt
+++ b/tools/java/com/google/devtools/kotlin/SourceJarZipper.kt
@@ -52,15 +52,16 @@
 }
 
 /**
- * Checks for duplicates and add an entry into [errors] if found any, otherwise adds a pair
- * of [zipPath] and [sourcePath] to the receiver
- * @receiver a mutable map of path to path, where keys are relative paths of files inside the
- * resulting .jar, and values are full paths of files
- * @param[zipPath] relative path inside the jar, built either from package name
- * (e.g. package com.google.foo -> com/google/foo/FileName.kt) or by resolving the file name
- * relatively the directory it came from (e.g. foo/bar/1/2.txt came from foo/bar -> 1/2.txt)
+ * Checks for duplicates and adds an entry into [errors] if one is found, otherwise adds a pair of
+ * [zipPath] and [sourcePath] to the receiver
+ *
+ * @param[zipPath] relative path inside the jar, built either from package name (e.g. package
+ *   com.google.foo -> com/google/foo/FileName.kt) or by resolving the file name relative to the
+ *   directory it came from (e.g. foo/bar/1/2.txt came from foo/bar -> 1/2.txt)
  * @param[sourcePath] full path of file into its file system
  * @param[errors] list of strings describing catched errors
+ * @receiver a mutable map of path to path, where keys are relative paths of files inside the
+ *   resulting .jar, and values are full paths of files
  */
 fun MutableMap<Path, Path>.checkForDuplicatesAndSetFilePathToPathInsideJar(
   zipPath: Path,
@@ -78,6 +79,12 @@
   }
 }
 
+private fun clearSingletonEmptyPath(list: MutableList<Path>) {
+  if (list.size == 1 && list[0].toString() == "") {
+    list.clear()
+  }
+}
+
 fun MutableMap<Path, Path>.writeToStream(
   zipper: ZipOutputStream,
   prefix: String = "",
@@ -124,9 +131,8 @@
   }
 
   override fun run() {
-    check(kotlinSrcs.isNotEmpty() or commonSrcs.isNotEmpty()) {
-      "Expected at least one source file."
-    }
+    clearSingletonEmptyPath(kotlinSrcs)
+    clearSingletonEmptyPath(commonSrcs)
 
     // Validating files and getting paths for resulting .jar in one cycle
     // for each _srcs list
@@ -188,9 +194,6 @@
       }
     }
 
-    if (ktZipPathToSourcePath.isEmpty() && commonZipPathToSourcePath.isEmpty()) {
-      errors.add("Expected at least one valid source file .kt or .java")
-    }
     check(errors.isEmpty()) { errors.joinToString("\n") }
 
     ZipOutputStream(BufferedOutputStream(Files.newOutputStream(outputJar))).use { zipper ->
@@ -243,6 +246,8 @@
   val inputDirs = mutableListOf<Path>()
 
   override fun run() {
+    clearSingletonEmptyPath(inputDirs)
+
     val filePathToOutputPath = mutableMapOf<Path, Path>()
     val errors = mutableListOf<String>()
 
diff --git a/kotlin/direct_jdeps.bzl b/visibility.bzl
similarity index 60%
copy from kotlin/direct_jdeps.bzl
copy to visibility.bzl
index f242989..328e2e5 100644
--- a/kotlin/direct_jdeps.bzl
+++ b/visibility.bzl
@@ -12,15 +12,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""kt_traverse_exports visitor for exposing jdeps files from direct deps."""
+"""Bzl visibility lists for rules_kotlin"""
 
-def _get_jdeps(target, _ctx_rule):
-    return [out.compile_jdeps for out in target[JavaInfo].java_outputs if out.compile_jdeps]
+RULES_KOTLIN = ["//..."]
 
-kt_direct_jdeps_visitor = struct(
-    name = "direct_jdeps",
-    visit_target = _get_jdeps,
-    filter_edge = None,
-    process_unvisited_target = None,
-    finish_expansion = None,
-)
+TOOLS_KOTLIN = [
+]
+
+# bzl files in these packages have access to internal parts of rules_kotlin, so think carefully
+# before expanding the list.
+RULES_DEFS_THAT_COMPILE_KOTLIN = RULES_KOTLIN + [
+]