## Starlark `cc_test` fixes.

* Restructure `cc_test` to use a toolchain alias. This will allow `cc_test` to work in Bazel (and tests) without a "dummy" toolchain needing to be registered.
This makes `cc_test` use the legacy flow when toolchains are not registered--requiring an additional flag if they are.
This is a temporary measure to permit switching off `native.cc_test` before [Optional Toolchains](https://github.com/bazelbuild/bazel/issues/14726) lands.

* Add coverage-related tools (e.g. collect_cc_coverage.sh) necessary for Bazel to collect coverage from cc_test(s)

PiperOrigin-RevId: 441494074
diff --git a/src/main/starlark/builtins_bzl/common/cc/cc_test.bzl b/src/main/starlark/builtins_bzl/common/cc/cc_test.bzl
index eccc897..cab1d87 100644
--- a/src/main/starlark/builtins_bzl/common/cc/cc_test.bzl
+++ b/src/main/starlark/builtins_bzl/common/cc/cc_test.bzl
@@ -47,20 +47,30 @@
     ),
     stamp = attr.int(values = [-1, 0, 1], default = 0),
     linkstatic = attr.bool(default = False),
-    malloc = attr.label(
-        default = Label("@//tools/cpp:cc_test_malloc"),
-        allow_rules = ["cc_library"],
-        # TODO(b/198254254): Add aspects. in progress
-        aspects = [],
-    ),
 )
+_cc_test_attrs.update(semantics.get_test_malloc_attr())
+_cc_test_attrs.update(semantics.get_test_toolchain_attr())
+_cc_test_attrs.update(semantics.get_coverage_attrs())
 
 def _cc_test_impl(ctx):
     binary_info, cc_info, providers = cc_binary_impl(ctx, [])
-    providers.append(testing.TestEnvironment(ctx.attr.env))
+    test_env = {}
+    test_env.update(ctx.attr.env)
+
+    coverage_runfiles, coverage_env = semantics.get_coverage_env(ctx)
+
+    runfiles_list = [binary_info.runfiles]
+    if coverage_runfiles:
+        runfiles_list.append(coverage_runfiles)
+
+    runfiles = ctx.runfiles()
+    runfiles = runfiles.merge_all(runfiles_list)
+
+    test_env.update(coverage_env)
+    providers.append(testing.TestEnvironment(test_env))
     providers.append(DefaultInfo(
         files = binary_info.files,
-        runfiles = binary_info.runfiles,
+        runfiles = runfiles,
         executable = binary_info.executable,
     ))
     return _handle_legacy_return(ctx, cc_info, providers)
@@ -79,13 +89,12 @@
         return providers
 
 def _impl(ctx):
-    cpp_config = ctx.fragments.cpp
-    cc_test_info = ctx.toolchains["@//tools/cpp:test_runner_toolchain_type"].cc_test_info
-
-    if not cpp_config.experimental_platform_cc_test() or cc_test_info.use_legacy_cc_test:
+    if semantics.should_use_legacy_cc_test(ctx):
         # This is the "legacy" cc_test flow
         return _cc_test_impl(ctx)
 
+    cc_test_info = ctx.attr._test_toolchain.cc_test_info
+
     binary_info, cc_info, providers = cc_binary_impl(ctx, cc_test_info.linkopts)
 
     test_providers = cc_test_info.get_runner.func(
@@ -114,8 +123,7 @@
             "cpp_link": exec_group(copy_from_rule = True),
         },
         toolchains = [
-            "@//tools/cpp:toolchain_type",
-            "@//tools/cpp:test_runner_toolchain_type",
+            "@" + semantics.get_repo() + "//tools/cpp:toolchain_type",
         ],
         incompatible_use_toolchain_transition = True,
         test = True,
diff --git a/src/main/starlark/builtins_bzl/common/cc/semantics.bzl b/src/main/starlark/builtins_bzl/common/cc/semantics.bzl
index 34a2908..5b9ea24 100644
--- a/src/main/starlark/builtins_bzl/common/cc/semantics.bzl
+++ b/src/main/starlark/builtins_bzl/common/cc/semantics.bzl
@@ -65,6 +65,60 @@
 def _get_grep_includes():
     return attr.label()
 
+def _get_test_toolchain_attr():
+    return {}
+
+def _get_test_malloc_attr():
+    return {}
+
+def _get_coverage_attrs():
+    return {
+        "_lcov_merger": attr.label(
+            default = "@bazel_tools//tools/test:lcov_merger",
+            executable = True,
+            cfg = "target",
+        ),
+        "_collect_cc_coverage": attr.label(
+            default = "@bazel_tools//tools/test:collect_cc_coverage",
+            executable = True,
+            cfg = "target",
+        ),
+    }
+
+def _get_coverage_env(ctx):
+    runfiles = ctx.runfiles()
+    test_env = {}
+    if ctx.configuration.coverage_enabled:
+        # Bazel’s coverage runner
+        # (https://github.com/bazelbuild/bazel/blob/3.0.0/tools/test/collect_coverage.sh)
+        # needs a binary called “lcov_merge.”  Its location is passed in the
+        # LCOV_MERGER environmental variable.  For builtin rules, this variable
+        # is set automatically based on a magic “$lcov_merger” or
+        # “:lcov_merger” attribute, but it’s not possible to create such
+        # attributes in Starlark.  Therefore we specify the variable ourselves.
+        # Note that the coverage runner runs in the runfiles root instead of
+        # the execution root, therefore we use “path” instead of “short_path.”
+        test_env["LCOV_MERGER"] = ctx.executable._lcov_merger.path
+
+        # C/C++ coverage instrumentation needs another binary that wraps gcov;
+        # see
+        # https://github.com/bazelbuild/bazel/blob/5.0.0/tools/test/collect_coverage.sh#L199.
+        # This is normally set from a hidden “$collect_cc_coverage” attribute;
+        # see
+        # https://github.com/bazelbuild/bazel/blob/5.0.0/src/main/java/com/google/devtools/build/lib/analysis/test/TestActionBuilder.java#L253-L258.
+        test_env["CC_CODE_COVERAGE_SCRIPT"] = ctx.executable._collect_cc_coverage.path
+
+        # The test runfiles need all applicable runfiles for the tools above.
+        runfiles = runfiles.merge_all([
+            ctx.attr._lcov_merger[DefaultInfo].default_runfiles,
+            ctx.attr._collect_cc_coverage[DefaultInfo].default_runfiles,
+        ])
+
+    return runfiles, test_env
+
+def _should_use_legacy_cc_test(_):
+    return True
+
 def _get_interface_deps_allowed_attr():
     return {}
 
@@ -122,4 +176,9 @@
     should_use_interface_deps_behavior = _should_use_interface_deps_behavior,
     check_experimental_cc_shared_library = _check_experimental_cc_shared_library,
     get_linkstatic_default = _get_linkstatic_default,
+    get_test_malloc_attr = _get_test_malloc_attr,
+    get_test_toolchain_attr = _get_test_toolchain_attr,
+    should_use_legacy_cc_test = _should_use_legacy_cc_test,
+    get_coverage_attrs = _get_coverage_attrs,
+    get_coverage_env = _get_coverage_env,
 )