@Test
 public void testDisablingHeaderModulesWhenDependingOnModuleBuildTransitively() throws Exception {
   AnalysisMock.get()
       .ccSupport()
       .setupCrosstool(mockToolsConfig, MockCcSupport.HEADER_MODULES_FEATURE_CONFIGURATION);
   useConfiguration();
   scratch.file(
       "module/BUILD",
       "package(features = ['header_modules'])",
       "cc_library(",
       "    name = 'module',",
       "    srcs = ['a.cc', 'a.h'],",
       ")");
   scratch.file(
       "nomodule/BUILD",
       "package(features = ['-header_modules'])",
       "cc_library(",
       "    name = 'nomodule',",
       "    srcs = ['a.cc', 'a.h'],",
       "    deps = ['//module']",
       ")");
   CppCompileAction moduleAction = getCppCompileAction("//module:module");
   assertThat(moduleAction.getCompilerOptions()).contains("module_name://module:module");
   CppCompileAction noModuleAction = getCppCompileAction("//nomodule:nomodule");
   assertThat(noModuleAction.getCompilerOptions()).doesNotContain("module_name://module:module");
 }
 private List<String> getCompilationModeFlags(String... flags) throws Exception {
   AnalysisMock.get().ccSupport().setupCrosstool(mockToolsConfig, COMPILATION_MODE_FEATURES);
   useConfiguration(flags);
   scratch.overwriteFile("mode/BUILD", "cc_library(name = 'a', srcs = ['a.cc'])");
   getConfiguredTarget("//mode:a");
   Artifact objectArtifact = getBinArtifact("_objs/a/mode/a.pic.o", "//mode:a");
   CppCompileAction action = (CppCompileAction) getGeneratingAction(objectArtifact);
   return action.getCompilerOptions();
 }
 @Test
 public void testNoCppModuleMap() throws Exception {
   AnalysisMock.get()
       .ccSupport()
       .setupCrosstool(mockToolsConfig, "feature { name: 'no_legacy_features' }");
   useConfiguration();
   writeSimpleCcLibrary();
   assertNoCppModuleMapAction("//module:map");
 }
 @Test
 public void testDoNotCompileSourceFilesInHeaders() throws Exception {
   AnalysisMock.get()
       .ccSupport()
       .setupCrosstool(mockToolsConfig, MockCcSupport.HEADER_PROCESSING_FEATURE_CONFIGURATION);
   useConfiguration("--features=parse_headers");
   ConfiguredTarget x =
       scratchConfiguredTarget("x", "x", "cc_library(name = 'x', hdrs = ['x.cc'])");
   assertThat(getGeneratingAction(getBinArtifact("_objs/x/x/x.pic.o", x))).isNull();
 }
 @Test
 public void testCppModuleMap() throws Exception {
   AnalysisMock.get()
       .ccSupport()
       .setupCrosstool(mockToolsConfig, "feature { name: 'module_maps' }");
   useConfiguration();
   writeSimpleCcLibrary();
   CppModuleMapAction action = getCppModuleMapAction("//module:map");
   assertThat(ActionsTestUtil.baseArtifactNames(action.getDependencyArtifacts()))
       .containsExactly("stl.cppmap", "crosstool.cppmap");
   assertEquals(ImmutableSet.of("src module/a.h"), artifactsToStrings(action.getPrivateHeaders()));
   assertThat(action.getPublicHeaders()).isEmpty();
 }
  @Test
  public void testCompileUsingHeaderModulesTransitivelyWithTranstiveModuleMaps() throws Exception {
    AnalysisMock.get()
        .ccSupport()
        .setupCrosstool(
            mockToolsConfig,
            MockCcSupport.HEADER_MODULES_FEATURE_CONFIGURATION
                + "feature { name: 'transitive_module_maps' }");
    useConfiguration("--features=transitive_module_maps");
    setupPackagesForModuleTests(/*useHeaderModules=*/ true);

    getConfiguredTarget("//nomodule:f");
    Artifact fObjectArtifact = getBinArtifact("_objs/f/nomodule/f.pic.o", "//nomodule:f");
    CppCompileAction fObjectAction = (CppCompileAction) getGeneratingAction(fObjectArtifact);
    // Only the module map of f itself itself and the direct dependencies are needed.
    assertThat(getNonSystemModuleMaps(fObjectAction.getInputs()))
        .containsExactly(
            getGenfilesArtifact("y.cppmap", "//nomodule:y"),
            getGenfilesArtifact("z.cppmap", "//nomodule:z"),
            getGenfilesArtifact("a.cppmap", "//nomodule:a"),
            getGenfilesArtifact("f.cppmap", "//nomodule:f"),
            getGenfilesArtifact("e.cppmap", "//nomodule:e"));

    getConfiguredTarget("//nomodule:c");
    Artifact cObjectArtifact = getBinArtifact("_objs/c/nomodule/c.pic.o", "//nomodule:c");
    CppCompileAction cObjectAction = (CppCompileAction) getGeneratingAction(cObjectArtifact);
    assertThat(getNonSystemModuleMaps(cObjectAction.getInputs()))
        .containsExactly(
            getGenfilesArtifact("y.cppmap", "//nomodule:y"),
            getGenfilesArtifact("z.cppmap", "//nomodule:z"),
            getGenfilesArtifact("a.cppmap", "//nomodule:a"),
            getGenfilesArtifact("b.cppmap", "//module:b"),
            getGenfilesArtifact("c.cppmap", "//nomodule:e"));
    assertThat(getHeaderModuleFlags(cObjectAction.getCompilerOptions()))
        .containsExactly("b.pic.pcm");

    getConfiguredTarget("//nomodule:d");
    Artifact dObjectArtifact = getBinArtifact("_objs/d/nomodule/d.pic.o", "//nomodule:d");
    CppCompileAction dObjectAction = (CppCompileAction) getGeneratingAction(dObjectArtifact);
    assertThat(getNonSystemModuleMaps(dObjectAction.getInputs()))
        .containsExactly(
            getGenfilesArtifact("y.cppmap", "//nomodule:y"),
            getGenfilesArtifact("z.cppmap", "//nomodule:z"),
            getGenfilesArtifact("a.cppmap", "//nomodule:a"),
            getGenfilesArtifact("b.cppmap", "//module:b"),
            getGenfilesArtifact("c.cppmap", "//nomodule:c"),
            getGenfilesArtifact("d.cppmap", "//nomodule:d"));
    assertThat(getHeaderModuleFlags(dObjectAction.getCompilerOptions()))
        .containsExactly("b.pic.pcm");
  }
 @Test
 public void testProcessHeadersInCompileOnlyMode() throws Exception {
   AnalysisMock.get()
       .ccSupport()
       .setupCrosstool(mockToolsConfig, MockCcSupport.HEADER_PROCESSING_FEATURE_CONFIGURATION);
   useConfiguration("--features=parse_headers", "--process_headers_in_dependencies");
   ConfiguredTarget y =
       scratchConfiguredTarget(
           "foo",
           "y",
           "cc_library(name = 'x', deps = [':y'])",
           "cc_library(name = 'y', hdrs = ['y.h'])");
   assertThat(ActionsTestUtil.baseNamesOf(getOutputGroup(y, OutputGroupProvider.FILES_TO_COMPILE)))
       .isEqualTo("y.h.processed");
 }
 @Test
 public void testDoNotProcessHeadersInDependencies() throws Exception {
   AnalysisMock.get()
       .ccSupport()
       .setupCrosstool(mockToolsConfig, MockCcSupport.HEADER_PROCESSING_FEATURE_CONFIGURATION);
   useConfiguration("--features=parse_headers");
   ConfiguredTarget x =
       scratchConfiguredTarget(
           "foo",
           "x",
           "cc_library(name = 'x', deps = [':y'])",
           "cc_library(name = 'y', hdrs = ['y.h'])");
   assertThat(ActionsTestUtil.baseNamesOf(getOutputGroup(x, OutputGroupProvider.HIDDEN_TOP_LEVEL)))
       .isEmpty();
 }
 @Test
 public void testTopLevelHeaderModules() throws Exception {
   AnalysisMock.get()
       .ccSupport()
       .setupCrosstool(
           mockToolsConfig,
           MockCcSupport.HEADER_MODULES_FEATURE_CONFIGURATION
               + "feature { name: 'header_module_includes_dependencies' }");
   useConfiguration();
   setupPackagesForModuleTests(/*useHeaderModules=*/ false);
   getConfiguredTarget("//module:j");
   Artifact jObjectArtifact = getBinArtifact("_objs/j/module/j.pic.o", "//module:j");
   CppCompileAction jObjectAction = (CppCompileAction) getGeneratingAction(jObjectArtifact);
   assertThat(getHeaderModuleFlags(jObjectAction.getCompilerOptions()))
       .containsExactly("g.pic.pcm");
 }
 @Test
 public void testBuildHeaderModulesAsPrerequisites() throws Exception {
   AnalysisMock.get()
       .ccSupport()
       .setupCrosstool(mockToolsConfig, MockCcSupport.HEADER_MODULES_FEATURE_CONFIGURATION);
   useConfiguration();
   ConfiguredTarget x =
       scratchConfiguredTarget(
           "foo",
           "x",
           "package(features = ['header_modules'])",
           "cc_library(name = 'x', srcs = ['x.cc'], deps = [':y'])",
           "cc_library(name = 'y', hdrs = ['y.h'])");
   assertThat(
           ActionsTestUtil.baseNamesOf(
               getOutputGroup(x, OutputGroupProvider.COMPILATION_PREREQUISITES)))
       .isEqualTo("y.h y.pic.pcm y.cppmap stl.cppmap crosstool.cppmap x.cppmap x.cc");
 }
  @Test
  public void testCompileHeaderModules() throws Exception {
    AnalysisMock.get()
        .ccSupport()
        .setupCrosstool(
            mockToolsConfig,
            "" + "feature { name: 'header_modules' }" + "feature { name: 'module_maps' }");
    useConfiguration();
    scratch.file(
        "module/BUILD",
        "package(features = ['header_modules'])",
        "cc_library(",
        "    name = 'a',",
        "    srcs = ['a.h', 'a.cc'],",
        "    deps = ['b']",
        ")",
        "cc_library(",
        "    name = 'b',",
        "    srcs = ['b.h'],",
        "    textual_hdrs = ['t.h'],",
        ")");
    getConfiguredTarget("//module:b");
    Artifact bModuleArtifact = getBinArtifact("_objs/b/module/b.pic.pcm", "//module:b");
    CppCompileAction bModuleAction = (CppCompileAction) getGeneratingAction(bModuleArtifact);
    assertThat(bModuleAction.getIncludeScannerSources())
        .containsExactly(getSourceArtifact("module/b.h"), getSourceArtifact("module/t.h"));
    assertThat(bModuleAction.getInputs())
        .contains(getGenfilesArtifactWithNoOwner("module/b.cppmap"));

    getConfiguredTarget("//module:a");
    Artifact aObjectArtifact = getBinArtifact("_objs/a/module/a.pic.o", "//module:a");
    CppCompileAction aObjectAction = (CppCompileAction) getGeneratingAction(aObjectArtifact);
    assertThat(aObjectAction.getIncludeScannerSources())
        .containsExactly(
            getSourceArtifact("module/a.cc"),
            getSourceArtifact("module/b.h"),
            getSourceArtifact("module/t.h"));
    assertThat(aObjectAction.getInputs())
        .contains(getBinArtifact("_objs/b/module/b.pic.pcm", "//module:b"));
    assertThat(aObjectAction.getInputs())
        .contains(getGenfilesArtifactWithNoOwner("module/b.cppmap"));
    assertNoEvents();
  }
  @Test
  public void testCompileHeaderModulesTransitively() throws Exception {
    AnalysisMock.get()
        .ccSupport()
        .setupCrosstool(mockToolsConfig, MockCcSupport.HEADER_MODULES_FEATURE_CONFIGURATION);
    useConfiguration();
    setupPackagesForModuleTests(/*useHeaderModules=*/ false);

    // The //nomodule:f target only depends on non-module targets, thus it should be module-free.
    getConfiguredTarget("//nomodule:f");
    assertThat(getGeneratingAction(getBinArtifact("_objs/f/nomodule/f.pic.pcm", "//nomodule:f")))
        .isNull();
    Artifact fObjectArtifact = getBinArtifact("_objs/f/nomodule/f.pic.o", "//nomodule:f");
    CppCompileAction fObjectAction = (CppCompileAction) getGeneratingAction(fObjectArtifact);
    // Only the module map of f itself itself and the direct dependencies are needed.
    assertThat(getNonSystemModuleMaps(fObjectAction.getInputs()))
        .containsExactly(
            getGenfilesArtifact("f.cppmap", "//nomodule:f"),
            getGenfilesArtifact("e.cppmap", "//nomodule:e"));
    assertThat(getHeaderModules(fObjectAction.getInputs())).isEmpty();
    assertThat(fObjectAction.getIncludeScannerSources())
        .containsExactly(getSourceArtifact("nomodule/f.cc"));
    assertThat(getHeaderModuleFlags(fObjectAction.getCompilerOptions())).isEmpty();

    // The //nomodule:c target will get the header module for //module:b, which is a direct
    // dependency.
    getConfiguredTarget("//nomodule:c");
    assertThat(getGeneratingAction(getBinArtifact("_objs/c/nomodule/c.pic.pcm", "//nomodule:c")))
        .isNull();
    Artifact cObjectArtifact = getBinArtifact("_objs/c/nomodule/c.pic.o", "//nomodule:c");
    CppCompileAction cObjectAction = (CppCompileAction) getGeneratingAction(cObjectArtifact);
    assertThat(getNonSystemModuleMaps(cObjectAction.getInputs()))
        .containsExactly(
            getGenfilesArtifact("b.cppmap", "//module:b"),
            getGenfilesArtifact("c.cppmap", "//nomodule:e"));
    assertThat(getHeaderModules(cObjectAction.getInputs()))
        .containsExactly(getBinArtifact("_objs/b/module/b.pic.pcm", "//module:b"));
    // All headers of transitive dependencies that are built as modules are needed as entry points
    // for include scanning.
    assertThat(cObjectAction.getIncludeScannerSources())
        .containsExactly(getSourceArtifact("nomodule/c.cc"), getSourceArtifact("module/b.h"));
    assertThat(cObjectAction.getMainIncludeScannerSource())
        .isEqualTo(getSourceArtifact("nomodule/c.cc"));
    assertThat(getHeaderModuleFlags(cObjectAction.getCompilerOptions())).isEmpty();

    // The //nomodule:d target depends on //module:b via one indirection (//nomodule:c).
    getConfiguredTarget("//nomodule:d");
    assertThat(getGeneratingAction(getBinArtifact("_objs/d/nomodule/d.pic.pcm", "//nomodule:d")))
        .isNull();
    Artifact dObjectArtifact = getBinArtifact("_objs/d/nomodule/d.pic.o", "//nomodule:d");
    CppCompileAction dObjectAction = (CppCompileAction) getGeneratingAction(dObjectArtifact);
    // Module map 'c.cppmap' is needed because it is a direct dependency.
    assertThat(getNonSystemModuleMaps(dObjectAction.getInputs()))
        .containsExactly(
            getGenfilesArtifact("c.cppmap", "//nomodule:c"),
            getGenfilesArtifact("d.cppmap", "//nomodule:d"));
    assertThat(getHeaderModules(dObjectAction.getInputs()))
        .containsExactly(getBinArtifact("_objs/b/module/b.pic.pcm", "//module:b"));
    // All headers of transitive dependencies that are built as modules are needed as entry points
    // for include scanning.
    assertThat(dObjectAction.getIncludeScannerSources())
        .containsExactly(getSourceArtifact("module/b.h"), getSourceArtifact("nomodule/d.cc"));
    assertThat(getHeaderModuleFlags(dObjectAction.getCompilerOptions())).isEmpty();

    // The //module:j target depends on //module:g via //nomodule:h and on //module:b via
    // both //module:g and //nomodule:c.
    getConfiguredTarget("//module:j");
    Artifact jObjectArtifact = getBinArtifact("_objs/j/module/j.pic.o", "//module:j");
    CppCompileAction jObjectAction = (CppCompileAction) getGeneratingAction(jObjectArtifact);
    assertThat(getHeaderModules(jObjectAction.getInputs()))
        .containsExactly(
            getBinArtifact("_objs/b/module/b.pic.pcm", "//module:b"),
            getBinArtifact("_objs/g/module/g.pic.pcm", "//module:g"));
    assertThat(jObjectAction.getIncludeScannerSources())
        .containsExactly(
            getSourceArtifact("module/j.cc"),
            getSourceArtifact("module/b.h"),
            getSourceArtifact("module/g.h"));
    assertThat(jObjectAction.getMainIncludeScannerSource())
        .isEqualTo(getSourceArtifact("module/j.cc"));
    assertThat(getHeaderModuleFlags(jObjectAction.getCompilerOptions()))
        .containsExactly("b.pic.pcm", "g.pic.pcm");
  }