Create new Starlark provider InstrumentedFilesInfo

This object is opaque but can be constructed with a new API method coverage_common.instrumented_files_info(). This should be a drop-in replacement for returning instrumented_files in rule implementation functions, as that syntax is going away.

See https://docs.google.com/document/d/14A9HK8Jn2jErMayLEE3nrNJIxNfZWN_slFbhgtS6-aM for details.

Progress toward #6241

RELNOTES: None.
PiperOrigin-RevId: 232310117
diff --git a/src/main/java/com/google/devtools/build/docgen/SymbolFamilies.java b/src/main/java/com/google/devtools/build/docgen/SymbolFamilies.java
index caa91de..8d0fca4 100644
--- a/src/main/java/com/google/devtools/build/docgen/SymbolFamilies.java
+++ b/src/main/java/com/google/devtools/build/docgen/SymbolFamilies.java
@@ -60,6 +60,7 @@
 import com.google.devtools.build.skydoc.fakebuildapi.repository.FakeRepositoryModule;
 import com.google.devtools.build.skydoc.fakebuildapi.test.FakeAnalysisFailureInfoProvider;
 import com.google.devtools.build.skydoc.fakebuildapi.test.FakeAnalysisTestResultInfoProvider;
+import com.google.devtools.build.skydoc.fakebuildapi.test.FakeCoverageCommon;
 import com.google.devtools.build.skydoc.fakebuildapi.test.FakeTestingModule;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
@@ -190,9 +191,12 @@
     PlatformBootstrap platformBootstrap = new PlatformBootstrap(new FakePlatformCommon());
     PyBootstrap pyBootstrap = new PyBootstrap(new FakePyInfoProvider());
     RepositoryBootstrap repositoryBootstrap = new RepositoryBootstrap(new FakeRepositoryModule());
-    TestingBootstrap testingBootstrap = new TestingBootstrap(new FakeTestingModule(),
-        new FakeAnalysisFailureInfoProvider(),
-        new FakeAnalysisTestResultInfoProvider());
+    TestingBootstrap testingBootstrap =
+        new TestingBootstrap(
+            new FakeTestingModule(),
+            new FakeCoverageCommon(),
+            new FakeAnalysisFailureInfoProvider(),
+            new FakeAnalysisTestResultInfoProvider());
 
     topLevelBootstrap.addBindingsToBuilder(envBuilder);
     androidBootstrap.addBindingsToBuilder(envBuilder);
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleConfiguredTargetUtil.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleConfiguredTargetUtil.java
index 5e3c977..54eb63f 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleConfiguredTargetUtil.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleConfiguredTargetUtil.java
@@ -29,12 +29,10 @@
 import com.google.devtools.build.lib.analysis.RunfilesSupport;
 import com.google.devtools.build.lib.analysis.SkylarkProviderValidationUtil;
 import com.google.devtools.build.lib.analysis.Whitelist;
-import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector;
-import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector.InstrumentationSpec;
+import com.google.devtools.build.lib.analysis.test.CoverageCommon;
 import com.google.devtools.build.lib.analysis.test.InstrumentedFilesInfo;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
-import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.packages.AdvertisedProviderSet;
 import com.google.devtools.build.lib.packages.FunctionSplitTransitionWhitelist;
@@ -62,8 +60,6 @@
 import com.google.devtools.build.lib.syntax.SkylarkSemantics;
 import com.google.devtools.build.lib.syntax.SkylarkType;
 import com.google.devtools.build.lib.syntax.Type;
-import com.google.devtools.build.lib.util.FileType;
-import com.google.devtools.build.lib.util.FileTypeSet;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -242,23 +238,14 @@
     }
   }
 
+  @SuppressWarnings("unchecked") // Casting SkylarkList to List<String> is checked by cast().
   private static void addInstrumentedFiles(
       StructImpl insStruct, RuleContext ruleContext, RuleConfiguredTargetBuilder builder)
       throws EvalException {
     Location insLoc = insStruct.getCreationLoc();
-    FileTypeSet fileTypeSet = FileTypeSet.ANY_FILE;
+    List<String> extensions = null;
     if (insStruct.getFieldNames().contains("extensions")) {
-      @SuppressWarnings("unchecked")
-      List<String> exts = cast("extensions", insStruct, SkylarkList.class, String.class, insLoc);
-      if (exts.isEmpty()) {
-        fileTypeSet = FileTypeSet.NO_FILE;
-      } else {
-        FileType[] fileTypes = new FileType[exts.size()];
-        for (int i = 0; i < fileTypes.length; i++) {
-          fileTypes[i] = FileType.of(exts.get(i));
-        }
-        fileTypeSet = FileTypeSet.of(fileTypes);
-      }
+      extensions = cast("extensions", insStruct, SkylarkList.class, String.class, insLoc);
     }
     List<String> dependencyAttributes = Collections.emptyList();
     if (insStruct.getFieldNames().contains("dependency_attributes")) {
@@ -270,17 +257,13 @@
       sourceAttributes =
           cast("source_attributes", insStruct, SkylarkList.class, String.class, insLoc);
     }
-    InstrumentationSpec instrumentationSpec =
-        new InstrumentationSpec(fileTypeSet)
-            .withSourceAttributes(sourceAttributes.toArray(new String[0]))
-            .withDependencyAttributes(dependencyAttributes.toArray(new String[0]));
     InstrumentedFilesInfo instrumentedFilesProvider =
-        InstrumentedFilesCollector.collect(
+        CoverageCommon.createInstrumentedFilesInfo(
+            insStruct.getCreationLoc(),
             ruleContext,
-            instrumentationSpec,
-            InstrumentedFilesCollector.NO_METADATA_COLLECTOR,
-            /* rootFiles= */ Collections.emptySet(),
-            /* reportedToActualSources= */ NestedSetBuilder.create(Order.STABLE_ORDER));
+            sourceAttributes,
+            dependencyAttributes,
+            extensions);
     builder.addNativeDeclaredProvider(instrumentedFilesProvider);
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/CoverageCommon.java b/src/main/java/com/google/devtools/build/lib/analysis/test/CoverageCommon.java
new file mode 100644
index 0000000..a6817ae
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/analysis/test/CoverageCommon.java
@@ -0,0 +1,108 @@
+// Copyright 2019 The Bazel Authors. 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.
+
+package com.google.devtools.build.lib.analysis.test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext;
+import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector.InstrumentationSpec;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkbuildapi.test.CoverageCommonApi;
+import com.google.devtools.build.lib.skylarkbuildapi.test.InstrumentedFilesInfoApi;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.Runtime;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+import com.google.devtools.build.lib.util.FileType;
+import com.google.devtools.build.lib.util.FileTypeSet;
+import java.util.Arrays;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Helper functions for Starlark to access coverage-related infrastructure. */
+public class CoverageCommon implements CoverageCommonApi<SkylarkRuleContext> {
+
+  @Override
+  @SuppressWarnings("unchecked") // Casting extensions param is verified by Starlark interpreter.
+  public InstrumentedFilesInfoApi instrumentedFilesInfo(
+      SkylarkRuleContext skylarkRuleContext,
+      SkylarkList<String> sourceAttributes,
+      SkylarkList<String> dependencyAttributes,
+      Object extensions,
+      Location location)
+      throws EvalException {
+    List<String> extensionsList =
+        extensions == Runtime.NONE
+            ? null
+            : SkylarkList.castList((List<?>) extensions, String.class, "extensions");
+
+    return createInstrumentedFilesInfo(
+        location,
+        skylarkRuleContext.getRuleContext(),
+        sourceAttributes,
+        dependencyAttributes,
+        extensionsList);
+  }
+
+  /**
+   * Returns a {@link InstrumentedFilesInfo} for the rule defined by the given rule context and
+   * various named parameters that define the "instrumentation specification" of the rule. For
+   * example, the instrumented sources are determined given the values of the attributes named in
+   * {@code sourceAttributes} given by the {@code ruleContext}.
+   *
+   * @param location the Starlark location that the instrumentation specification was defined
+   * @param ruleContext the rule context
+   * @param sourceAttributes a list of attribute names which contain source files for the rule
+   * @param dependencyAttributes a list of attribute names which contain dependencies that might
+   *     propagate instances of {@link InstrumentedFilesInfo}
+   * @param extensions file extensions used to filter files from source_attributes. If null, all
+   *     files on the source attributes will be treated as instrumented. Otherwise, only files with
+   *     extensions listed in {@code extensions} will be used
+   */
+  public static InstrumentedFilesInfo createInstrumentedFilesInfo(
+      Location location,
+      RuleContext ruleContext,
+      List<String> sourceAttributes,
+      List<String> dependencyAttributes,
+      @Nullable List<String> extensions) {
+    FileTypeSet fileTypeSet = FileTypeSet.ANY_FILE;
+    if (extensions != null) {
+      if (extensions.isEmpty()) {
+        fileTypeSet = FileTypeSet.NO_FILE;
+      } else {
+        FileType[] fileTypes = new FileType[extensions.size()];
+        Arrays.setAll(fileTypes, i -> FileType.of(extensions.get(i)));
+        fileTypeSet = FileTypeSet.of(fileTypes);
+      }
+    }
+    InstrumentationSpec instrumentationSpec =
+        new InstrumentationSpec(fileTypeSet)
+            .withSourceAttributes(sourceAttributes.toArray(new String[0]))
+            .withDependencyAttributes(dependencyAttributes.toArray(new String[0]));
+    return InstrumentedFilesCollector.collect(
+        ruleContext,
+        instrumentationSpec,
+        InstrumentedFilesCollector.NO_METADATA_COLLECTOR,
+        /* rootFiles= */ ImmutableList.of(),
+        /* reportedToActualSources= */ NestedSetBuilder.create(Order.STABLE_ORDER));
+  }
+
+  @Override
+  public void repr(SkylarkPrinter printer) {
+    printer.append("<coverage_common>");
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/InstrumentedFilesInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/test/InstrumentedFilesInfo.java
index cf59445..95c1fdb 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/test/InstrumentedFilesInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/test/InstrumentedFilesInfo.java
@@ -21,11 +21,12 @@
 import com.google.devtools.build.lib.packages.BuiltinProvider;
 import com.google.devtools.build.lib.packages.Info;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
+import com.google.devtools.build.lib.skylarkbuildapi.test.InstrumentedFilesInfoApi;
 import com.google.devtools.build.lib.util.Pair;
 
 /** An implementation class for the InstrumentedFilesProvider interface. */
 @AutoCodec
-public final class InstrumentedFilesInfo extends Info {
+public final class InstrumentedFilesInfo extends Info implements InstrumentedFilesInfoApi {
   /** Singleton provider instance for {@link InstrumentedFilesInfo}. */
   public static final InstrumentedFilesProvider SKYLARK_CONSTRUCTOR =
       new InstrumentedFilesProvider();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/TestingSupportRules.java b/src/main/java/com/google/devtools/build/lib/rules/test/TestingSupportRules.java
index b0251ce..2f73703 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/TestingSupportRules.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/TestingSupportRules.java
@@ -18,6 +18,7 @@
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider.RuleSet;
 import com.google.devtools.build.lib.analysis.test.AnalysisFailureInfo;
 import com.google.devtools.build.lib.analysis.test.AnalysisTestResultInfo;
+import com.google.devtools.build.lib.analysis.test.CoverageCommon;
 import com.google.devtools.build.lib.rules.core.CoreRules;
 import com.google.devtools.build.lib.skylarkbuildapi.test.TestingBootstrap;
 
@@ -34,6 +35,7 @@
     builder.addSkylarkBootstrap(
         new TestingBootstrap(
             new SkylarkTestingModule(),
+            new CoverageCommon(),
             AnalysisFailureInfo.SKYLARK_CONSTRUCTOR,
             AnalysisTestResultInfo.SKYLARK_CONSTRUCTOR));
   }
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/BUILD b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/BUILD
index aca2d7d..40f1563 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/BUILD
@@ -19,6 +19,7 @@
     name = "test",
     srcs = glob(["*.java"]),
     deps = [
+        "//src/main/java/com/google/devtools/build/lib:events",
         "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
         "//src/main/java/com/google/devtools/build/lib:syntax",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/CoverageCommonApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/CoverageCommonApi.java
new file mode 100644
index 0000000..0133ae8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/CoverageCommonApi.java
@@ -0,0 +1,82 @@
+// Copyright 2019 The Bazel Authors. 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.
+
+package com.google.devtools.build.lib.skylarkbuildapi.test;
+
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkbuildapi.SkylarkRuleContextApi;
+import com.google.devtools.build.lib.skylarkinterface.Param;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+
+/** Helper functions for Starlark to access coverage-related infrastructure */
+@SkylarkModule(
+    name = "coverage_common",
+    doc = "Helper functions for Starlark to access coverage-related infrastructure.")
+public interface CoverageCommonApi<RuleContextT extends SkylarkRuleContextApi>
+    extends SkylarkValue {
+
+  @SkylarkCallable(
+      name = "instrumented_files_info",
+      doc =
+          "Creates a new execution info provider. Use this provider to specify special"
+              + "environments requirements needed to run tests.",
+      parameters = {
+        @Param(
+            name = "ctx",
+            positional = true,
+            named = true,
+            type = SkylarkRuleContextApi.class,
+            doc = "The rule context."),
+        @Param(
+            name = "source_attributes",
+            doc = "A list of attribute names which contain source files for this rule.",
+            positional = false,
+            named = true,
+            defaultValue = "[]",
+            type = SkylarkList.class),
+        @Param(
+            name = "dependency_attributes",
+            doc =
+                "A list of attribute names which contain dependencies that might include "
+                    + "instrumented files.",
+            positional = false,
+            named = true,
+            defaultValue = "[]",
+            type = SkylarkList.class),
+        @Param(
+            name = "extensions",
+            doc =
+                "File extensions used to filter files from source_attributes. For example, 'js'. "
+                    + "If not provided (or None), then all files from source_attributes will be "
+                    + "added to instrumented files, if an empty list is provided, then "
+                    + "no files from source attributes will be added.",
+            positional = false,
+            named = true,
+            noneable = true,
+            defaultValue = "None",
+            type = SkylarkList.class),
+      },
+      useLocation = true)
+  public InstrumentedFilesInfoApi instrumentedFilesInfo(
+      RuleContextT skylarkRuleContext,
+      SkylarkList<String> sourceAttributes,
+      SkylarkList<String> dependencyAttributes,
+      Object extensions,
+      Location location)
+      throws EvalException;
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/InstrumentedFilesInfoApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/InstrumentedFilesInfoApi.java
new file mode 100644
index 0000000..cb03e91
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/InstrumentedFilesInfoApi.java
@@ -0,0 +1,30 @@
+// Copyright 2019 The Bazel Authors. 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.
+
+package com.google.devtools.build.lib.skylarkbuildapi.test;
+
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
+
+/** Contains information about instrumented files sources and instrumentation metadata. */
+@SkylarkModule(
+    name = "InstrumentedFilesInfo",
+    category = SkylarkModuleCategory.NONE,
+    doc =
+        "Contains information about instrumented file sources and instrumentation metadata "
+            + "for purposes of code coverage. Rule targets which return an instance of this "
+            + "provider signal to the build system that certain sources should be targeted for "
+            + "code coverage analysis.")
+public interface InstrumentedFilesInfoApi extends SkylarkValue {}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/TestingBootstrap.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/TestingBootstrap.java
index 745df17..d29ee12 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/TestingBootstrap.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test/TestingBootstrap.java
@@ -25,13 +25,17 @@
 public class TestingBootstrap implements Bootstrap {
 
   private final TestingModuleApi testingModule;
+  private final CoverageCommonApi<?> coverageCommon;
   private final AnalysisFailureInfoProviderApi analysisFailureInfoProvider;
   private final AnalysisTestResultInfoProviderApi testResultInfoProvider;
 
-  public TestingBootstrap(TestingModuleApi testingModule,
+  public TestingBootstrap(
+      TestingModuleApi testingModule,
+      CoverageCommonApi<?> coverageCommon,
       AnalysisFailureInfoProviderApi analysisFailureInfoProvider,
       AnalysisTestResultInfoProviderApi testResultInfoProvider) {
     this.testingModule = testingModule;
+    this.coverageCommon = coverageCommon;
     this.analysisFailureInfoProvider = analysisFailureInfoProvider;
     this.testResultInfoProvider = testResultInfoProvider;
   }
@@ -39,6 +43,7 @@
   @Override
   public void addBindingsToBuilder(ImmutableMap.Builder<String, Object> builder) {
     builder.put("testing", testingModule);
+    builder.put("coverage_common", coverageCommon);
     builder.put("AnalysisFailureInfo", analysisFailureInfoProvider);
     builder.put("AnalysisTestResultInfo", testResultInfoProvider);
   }
diff --git a/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java b/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
index df8988b..a57c1a0 100644
--- a/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
+++ b/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
@@ -94,6 +94,7 @@
 import com.google.devtools.build.skydoc.fakebuildapi.repository.FakeRepositoryModule;
 import com.google.devtools.build.skydoc.fakebuildapi.test.FakeAnalysisFailureInfoProvider;
 import com.google.devtools.build.skydoc.fakebuildapi.test.FakeAnalysisTestResultInfoProvider;
+import com.google.devtools.build.skydoc.fakebuildapi.test.FakeCoverageCommon;
 import com.google.devtools.build.skydoc.fakebuildapi.test.FakeTestingModule;
 import com.google.devtools.build.skydoc.rendering.MarkdownRenderer;
 import com.google.devtools.build.skydoc.rendering.ProviderInfo;
@@ -486,9 +487,12 @@
     ProtoBootstrap protoBootstrap = new ProtoBootstrap(new FakeProtoInfoApiProvider());
     PyBootstrap pyBootstrap = new PyBootstrap(new FakePyInfoProvider());
     RepositoryBootstrap repositoryBootstrap = new RepositoryBootstrap(new FakeRepositoryModule());
-    TestingBootstrap testingBootstrap = new TestingBootstrap(new FakeTestingModule(),
-        new FakeAnalysisFailureInfoProvider(),
-        new FakeAnalysisTestResultInfoProvider());
+    TestingBootstrap testingBootstrap =
+        new TestingBootstrap(
+            new FakeTestingModule(),
+            new FakeCoverageCommon(),
+            new FakeAnalysisFailureInfoProvider(),
+            new FakeAnalysisTestResultInfoProvider());
 
     ImmutableMap.Builder<String, Object> envBuilder = ImmutableMap.builder();
 
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/test/BUILD b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/test/BUILD
index 906407b..b07c5f9 100644
--- a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/test/BUILD
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/test/BUILD
@@ -16,6 +16,7 @@
         "//src/main/java/com/google/devtools/build/lib:events",
         "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
         "//src/main/java/com/google/devtools/build/lib:syntax",
+        "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi",
         "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/test",
         "//third_party:guava",
     ],
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/test/FakeCoverageCommon.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/test/FakeCoverageCommon.java
new file mode 100644
index 0000000..d2216c8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/test/FakeCoverageCommon.java
@@ -0,0 +1,39 @@
+// Copyright 2019 The Bazel Authors. 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.
+
+package com.google.devtools.build.skydoc.fakebuildapi.test;
+
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkbuildapi.SkylarkRuleContextApi;
+import com.google.devtools.build.lib.skylarkbuildapi.test.CoverageCommonApi;
+import com.google.devtools.build.lib.skylarkbuildapi.test.InstrumentedFilesInfoApi;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+
+/** Fake implementation of {@link CoverageCommonApi}. */
+public class FakeCoverageCommon implements CoverageCommonApi<SkylarkRuleContextApi> {
+
+  @Override
+  public InstrumentedFilesInfoApi instrumentedFilesInfo(
+      SkylarkRuleContextApi skylarkRuleContext,
+      SkylarkList<String> sourceAttributes,
+      SkylarkList<String> dependencyAttributes,
+      Object extensions,
+      Location location) {
+    return null;
+  }
+
+  @Override
+  public void repr(SkylarkPrinter printer) {}
+}
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
index c5493ed..29decc0 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
@@ -653,7 +653,7 @@
   }
 
   @Test
-  public void testInstrumentedFilesProviderWithCodeCoverageDiabled() throws Exception {
+  public void testInstrumentedFilesProviderWithCodeCoverageDisabled() throws Exception {
     scratch.file(
         "test/skylark/extension.bzl",
         "def custom_rule_impl(ctx):",
@@ -680,7 +680,7 @@
 
     assertThat(target.getLabel().toString()).isEqualTo("//test/skylark:cr");
     InstrumentedFilesInfo provider = target.get(InstrumentedFilesInfo.SKYLARK_CONSTRUCTOR);
-    assertWithMessage("InstrumentedFilesProvider should be set.").that(provider).isNotNull();
+    assertWithMessage("InstrumentedFilesInfo should be set.").that(provider).isNotNull();
     assertThat(ActionsTestUtil.baseArtifactNames(provider.getInstrumentedFiles())).isEmpty();
   }
 
@@ -712,7 +712,70 @@
 
     assertThat(target.getLabel().toString()).isEqualTo("//test/skylark:cr");
     InstrumentedFilesInfo provider = target.get(InstrumentedFilesInfo.SKYLARK_CONSTRUCTOR);
-    assertWithMessage("InstrumentedFilesProvider should be set.").that(provider).isNotNull();
+    assertWithMessage("InstrumentedFilesInfo should be set.").that(provider).isNotNull();
+    assertThat(ActionsTestUtil.baseArtifactNames(provider.getInstrumentedFiles()))
+        .containsExactly("a.txt", "A.java");
+  }
+
+  @Test
+  public void testInstrumentedFilesInfo_coverageDisabled() throws Exception {
+    scratch.file(
+        "test/skylark/extension.bzl",
+        "def custom_rule_impl(ctx):",
+        "  return struct(instrumented_files=struct(",
+        "      extensions = ['txt'],",
+        "      source_attributes = ['attr1'],",
+        "      dependency_attributes = ['attr2']))",
+        "",
+        "custom_rule = rule(implementation = custom_rule_impl,",
+        "  attrs = {",
+        "      'attr1': attr.label_list(mandatory = True, allow_files=True),",
+        "      'attr2': attr.label_list(mandatory = True)})");
+
+    scratch.file(
+        "test/skylark/BUILD",
+        "load('//test/skylark:extension.bzl', 'custom_rule')",
+        "",
+        "java_library(name='jl', srcs = [':A.java'])",
+        "custom_rule(name = 'cr', attr1 = [':a.txt', ':a.random'], attr2 = [':jl'])");
+
+    useConfiguration("--nocollect_code_coverage");
+
+    ConfiguredTarget target = getConfiguredTarget("//test/skylark:cr");
+
+    InstrumentedFilesInfo provider = target.get(InstrumentedFilesInfo.SKYLARK_CONSTRUCTOR);
+    assertWithMessage("InstrumentedFilesInfo should be set.").that(provider).isNotNull();
+    assertThat(ActionsTestUtil.baseArtifactNames(provider.getInstrumentedFiles())).isEmpty();
+  }
+
+  @Test
+  public void testInstrumentedFilesInfo_coverageEnabled() throws Exception {
+    scratch.file(
+        "test/skylark/extension.bzl",
+        "def custom_rule_impl(ctx):",
+        "  return [coverage_common.instrumented_files_info(ctx,",
+        "      extensions = ['txt'],",
+        "      source_attributes = ['attr1'],",
+        "      dependency_attributes = ['attr2'])]",
+        "",
+        "custom_rule = rule(implementation = custom_rule_impl,",
+        "  attrs = {",
+        "      'attr1': attr.label_list(mandatory = True, allow_files=True),",
+        "      'attr2': attr.label_list(mandatory = True)})");
+
+    scratch.file(
+        "test/skylark/BUILD",
+        "load('//test/skylark:extension.bzl', 'custom_rule')",
+        "",
+        "java_library(name='jl', srcs = [':A.java'])",
+        "custom_rule(name = 'cr', attr1 = [':a.txt', ':a.random'], attr2 = [':jl'])");
+
+    useConfiguration("--collect_code_coverage");
+
+    ConfiguredTarget target = getConfiguredTarget("//test/skylark:cr");
+
+    InstrumentedFilesInfo provider = target.get(InstrumentedFilesInfo.SKYLARK_CONSTRUCTOR);
+    assertWithMessage("InstrumentedFilesInfo should be set.").that(provider).isNotNull();
     assertThat(ActionsTestUtil.baseArtifactNames(provider.getInstrumentedFiles()))
         .containsExactly("a.txt", "A.java");
   }