Move ObjcProvider FLAG into a new provider type (TransitiveSourcesProvider) that is accessible to the c++ rules.

PiperOrigin-RevId: 166934390
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
index 7522d09..316f50e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
@@ -230,6 +230,14 @@
     return this;
   }
 
+  /** Adds a group of {@link TransitiveInfoProviderMap} instances. */
+  public <T extends TransitiveInfoProvider> RuleConfiguredTargetBuilder addProviderMaps(
+      Iterable<TransitiveInfoProviderMap> providerMaps) {
+    for (TransitiveInfoProviderMap providerMap : providerMaps) {
+      addProviders(providerMap);
+    }
+    return this;
+  }
 
   /**
    * Add a specific provider with a given value.
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index 3f28614..8cd4315 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -866,6 +866,17 @@
   }
 
   /**
+   * Returns all the providers of the specified type that are listed under the specified attribute
+   * of this target in the BUILD file, or an empty list of that attribute is not defined.
+   */
+  public <C extends TransitiveInfoProvider> Iterable<C> getPrerequisitesSafe(
+      String attributeName, Mode mode, final Class<C> classType) {
+    return attributes().has(attributeName)
+        ? getPrerequisites(attributeName, mode, classType)
+        : ImmutableList.of();
+  }
+
+  /**
    * Returns all the declared providers (native and Skylark) for the specified constructor under the
    * specified attribute of this target in the BUILD file.
    */
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
index 4856b0a..32c8cf9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
 import com.google.devtools.build.lib.actions.Artifact;
@@ -38,6 +39,7 @@
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
 import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.rules.apple.ApplePlatform;
 import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper.SourceCategory;
@@ -46,6 +48,7 @@
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables;
 import com.google.devtools.build.lib.rules.cpp.CppConfiguration.DynamicMode;
 import com.google.devtools.build.lib.rules.cpp.CppConfiguration.HeadersCheckingMode;
+import com.google.devtools.build.lib.rules.cpp.TransitiveSourcesProvider.SourceUsage;
 import com.google.devtools.build.lib.shell.ShellUtils;
 import com.google.devtools.build.lib.syntax.Type;
 import com.google.devtools.build.lib.util.FileType;
@@ -57,6 +60,7 @@
 import java.util.Map;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
+import java.util.stream.Collectors;
 import javax.annotation.Nullable;
 
 /**
@@ -219,12 +223,22 @@
     return new TransitiveLipoInfoProvider(scannableBuilder.build());
   }
 
+  /** Returns true if the given rule has sources in the target configuration. */
+  static boolean hasSourcesInTargetConfig(RuleContext ruleContext) {
+    return (ruleContext.attributes().has("srcs")
+        && ruleContext.attributes().getAttributeDefinition("srcs").getConfigurationTransition()
+            == ConfigurationTransition.NONE);
+  }
+
   /**
-   * Returns a list of ({@link Artifact}, {@link Label}) pairs. Each pair represents an input
-   * source file and the label of the rule that generates it (or the label of the source file
-   * itself if it is an input file).
+   * Returns a list of ({@link Artifact}, {@link Label}) pairs. Each pair represents an input source
+   * file and the label of the rule that generates it (or the label of the source file itself if it
+   * is an input file).
    */
-  List<Pair<Artifact, Label>> getSources() {
+  static List<Pair<Artifact, Label>> getSources(RuleContext ruleContext) {
+    if (!ruleContext.attributes().has("srcs")) {
+      return ImmutableList.of();
+    }
     Map<Artifact, Label> map = Maps.newLinkedHashMap();
     Iterable<? extends TransitiveInfoCollection> providers =
         ruleContext.getPrerequisitesIf("srcs", Mode.TARGET, FileProvider.class);
@@ -255,6 +269,15 @@
   }
 
   /**
+   * Returns a list of ({@link Artifact}, {@link Label}) pairs. Each pair represents an input source
+   * file and the label of the rule that generates it (or the label of the source file itself if it
+   * is an input file).
+   */
+  List<Pair<Artifact, Label>> getSources() {
+    return getSources(ruleContext);
+  }
+
+  /**
    * Returns the files from headers and does some sanity checks. Note that this method reports
    * warnings to the {@link RuleContext} as a side effect, and so should only be called once for any
    * given rule.
@@ -568,6 +591,40 @@
     }
   }
 
+  /** Computes the {@link TransitiveSourcesProvider} for this target using the given target. */
+  public static TransitiveSourcesProvider getTransitiveSourcesProvider(RuleContext ruleContext) {
+    List<String> sources =
+        getSources(ruleContext)
+            .stream()
+            .map(pair -> pair.getSecond().getCanonicalForm())
+            .collect(Collectors.toList());
+    return getTransitiveSourcesProvider(ruleContext, sources);
+  }
+
+  /** Computes the {@link TransitiveSourcesProvider} for this target using the given target. */
+  public static TransitiveSourcesProvider getTransitiveSourcesProvider(
+      RuleContext ruleContext, List<String> sources) {
+    TransitiveSourcesProvider.Builder result = new TransitiveSourcesProvider.Builder();
+    Iterable<TransitiveSourcesProvider> depTransitiveSourcesProviders =
+        ruleContext.getPrerequisitesSafe("deps", Mode.TARGET, TransitiveSourcesProvider.class);
+    for (SourceUsage sourceUsage : SourceUsage.values()) {
+      boolean sourceIsUsed = false;
+      // If dependencies use this source type, then the source type is used.
+      sourceIsUsed |=
+          (Lists.newArrayList(depTransitiveSourcesProviders)
+              .stream()
+              .anyMatch(provider -> provider.uses(sourceUsage)));
+
+      // If this target uses this source type, then the source type is used.
+      sourceIsUsed |= (sources.stream().anyMatch(source -> sourceUsage.matches(source)));
+
+      if (sourceIsUsed) {
+        result.doesUse(sourceUsage);
+      }
+    }
+    return result.build();
+  }
+
   /**
    * Creates the feature configuration for a given rule.
    *
@@ -611,6 +668,13 @@
 
     requestedFeatures.addAll(sourceCategory.getActionConfigSet());
 
+    // We check that this target has "srcs" in the target configuration to prevent failing in
+    // getSources() for rules like cc_embed_data, which have "srcs" in the data configuration.
+    if (hasSourcesInTargetConfig(ruleContext)
+        && getTransitiveSourcesProvider(ruleContext).uses(SourceUsage.OBJC)) {
+      requestedFeatures.add(CppRuleClasses.CONTAINS_OBJC_SOURCE);
+    }
+
     FeatureSpecification currentFeatureSpecification =
         FeatureSpecification.create(requestedFeatures.build(), unsupportedFeatures);
     try {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
index a7ffab3..6294cbe 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
@@ -68,6 +68,7 @@
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 import javax.annotation.Nullable;
 
 /**
@@ -1085,6 +1086,18 @@
           new CcLinkParamsInfo(
               createCcLinkParamsStore(ccLinkingOutputs, cppCompilationContext, forcePic)));
     }
+
+    if (CcCommon.hasSourcesInTargetConfig(ruleContext)) {
+      List<String> sources =
+          compilationUnitSources
+              .stream()
+              .map(cppSource -> cppSource.getSource().getExecPathString())
+              .collect(Collectors.toList());
+      providers.put(
+          TransitiveSourcesProvider.class,
+          CcCommon.getTransitiveSourcesProvider(ruleContext, sources));
+    }
+
     return new Info(
         providers.build(),
         outputGroups,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
index 06e4c9b..28c1735 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
@@ -365,4 +365,7 @@
 
   /** A string constant for the match-clif feature. */
   public static final String MATCH_CLIF = "match_clif";
+
+  /** A string constant for the contains_objc_source feature. */
+  public static final String CONTAINS_OBJC_SOURCE = "contains_objc_source";
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/TransitiveSourcesProvider.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/TransitiveSourcesProvider.java
new file mode 100644
index 0000000..a83ce68
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/TransitiveSourcesProvider.java
@@ -0,0 +1,67 @@
+// Copyright 2017 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.rules.cpp;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.util.FileTypeSet;
+
+/** Provides information on sources in the transitive closure of a target. */
+// TODO(b/65016770): Add SWIFT to this provider.
+public class TransitiveSourcesProvider implements TransitiveInfoProvider {
+
+  /** Signal that a certain source type is used. */
+  public enum SourceUsage {
+    CPP(FileTypeSet.of(CppFileTypes.CPP_SOURCE, CppFileTypes.OBJCPP_SOURCE)),
+    OBJC(FileTypeSet.of(CppFileTypes.OBJC_SOURCE));
+
+    private final FileTypeSet fileType;
+
+    SourceUsage(FileTypeSet fileType) {
+      this.fileType = fileType;
+    }
+
+    /** If true, the presence of the given source signals this source usage. */
+    public boolean matches(String fileName) {
+      return fileType.matches(fileName);
+    }
+  }
+
+  private final ImmutableList<SourceUsage> sources;
+
+  private TransitiveSourcesProvider(ImmutableList<SourceUsage> sources) {
+    this.sources = sources;
+  }
+
+  /** True if sources of the given type are used in this build. */
+  public boolean uses(SourceUsage source) {
+    return sources.contains(source);
+  }
+
+  /** Builder for TransitiveSourcesProvider */
+  public static class Builder {
+    private final ImmutableList.Builder<SourceUsage> sources = ImmutableList.builder();
+
+    /** Signals that the build uses sources of the provided type. */
+    public Builder doesUse(SourceUsage source) {
+      this.sources.add(source);
+      return this;
+    }
+
+    public TransitiveSourcesProvider build() {
+      return new TransitiveSourcesProvider(this.sources.build());
+    }
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
index 947d8e2..a65a9a5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
@@ -33,6 +33,7 @@
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector;
 import com.google.devtools.build.lib.analysis.test.InstrumentedFilesProvider;
@@ -141,6 +142,7 @@
             getDylibProtoProviders(ruleContext));
 
     Map<String, NestedSet<Artifact>> outputGroupCollector = new TreeMap<>();
+    ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector = ImmutableList.builder();
     multiArchBinarySupport.registerActions(
         platform,
         getExtraLinkArgs(ruleContext),
@@ -148,7 +150,8 @@
         getExtraLinkInputs(ruleContext),
         configToDepsCollectionMap,
         outputArtifact,
-        outputGroupCollector);
+        outputGroupCollector,
+        providerCollector);
 
     NestedSetBuilder<Artifact> filesToBuild =
         NestedSetBuilder.<Artifact>stableOrder().add(outputArtifact);
@@ -212,7 +215,10 @@
       }
     }
 
-    targetBuilder.addNativeDeclaredProvider(builder.build()).addOutputGroups(outputGroupCollector);
+    targetBuilder
+        .addNativeDeclaredProvider(builder.build())
+        .addProviderMaps(providerCollector.build())
+        .addOutputGroups(outputGroupCollector);
 
     InstrumentedFilesProvider instrumentedFilesProvider =
         InstrumentedFilesCollector.forward(ruleContext, "deps", "bundle_loader");
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStaticLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStaticLibrary.java
index b31f682..16eef28 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStaticLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStaticLibrary.java
@@ -28,6 +28,7 @@
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
@@ -106,6 +107,7 @@
         ruleContext.getPrerequisitesByConfiguration("deps", Mode.SPLIT, ObjcProtoProvider.class);
 
     Map<String, NestedSet<Artifact>> outputGroupCollector = new TreeMap<>();
+    ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector = ImmutableList.builder();
     for (BuildConfiguration childConfig : childConfigurationsAndToolchains.keySet()) {
       Iterable<ObjcProtoProvider> objcProtoProviders = objcProtoProvidersMap.get(childConfig);
       ProtobufSupport protoSupport =
@@ -143,6 +145,7 @@
               .setRuleContext(ruleContext)
               .setConfig(childConfig)
               .setOutputGroupCollector(outputGroupCollector)
+              .setProviderCollector(providerCollector)
               .build();
 
       compilationSupport
@@ -182,8 +185,8 @@
         .addNativeDeclaredProvider(objcProvider)
         .addNativeDeclaredProvider(
             new AppleStaticLibraryProvider(
-                ruleIntermediateArtifacts.combinedArchitectureArchive(),
-                objcProvider))
+                ruleIntermediateArtifacts.combinedArchitectureArchive(), objcProvider))
+        .addProviderMaps(providerCollector.build())
         .addOutputGroups(outputGroupCollector);
     return targetBuilder.build();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java b/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java
index e627a7a7..6f00706 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java
@@ -28,6 +28,7 @@
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.RunfilesSupport;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
 import com.google.devtools.build.lib.analysis.test.InstrumentedFilesProvider;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
@@ -125,10 +126,12 @@
             .build();
 
     Map<String, NestedSet<Artifact>> outputGroupCollector = new TreeMap<>();
+    ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector = ImmutableList.builder();
     CompilationSupport compilationSupport =
         new CompilationSupport.Builder()
             .setRuleContext(ruleContext)
             .setOutputGroupCollector(outputGroupCollector)
+            .setProviderCollector(providerCollector)
             .build();
 
     compilationSupport
@@ -188,6 +191,7 @@
             .addProvider(
                 InstrumentedFilesProvider.class,
                 compilationSupport.getInstrumentedFilesProvider(common))
+            .addProviderMaps(providerCollector.build())
             .addOutputGroups(outputGroupCollector);
 
     if (xcTestAppProvider.isPresent()) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
index b787ebc..c282b5f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
@@ -53,6 +53,7 @@
 import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
 import com.google.devtools.build.lib.analysis.actions.CommandLine;
 import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
 import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction;
@@ -302,6 +303,7 @@
   protected final boolean useDeps;
   protected final Map<String, NestedSet<Artifact>> outputGroupCollector;
   protected final CcToolchainProvider toolchain;
+  protected final ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector;
   protected final boolean isTestRule;
   protected final boolean usePch;
 
@@ -326,6 +328,7 @@
       boolean useDeps,
       Map<String, NestedSet<Artifact>> outputGroupCollector,
       CcToolchainProvider toolchain,
+      ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector,
       boolean isTestRule,
       boolean usePch) {
     this.ruleContext = ruleContext;
@@ -337,6 +340,7 @@
     this.useDeps = useDeps;
     this.isTestRule = isTestRule;
     this.outputGroupCollector = outputGroupCollector;
+    this.providerCollector = providerCollector;
     this.usePch = usePch;
     // TODO(b/62143697): Remove this check once all rules are using the crosstool support.
     if (ruleContext
@@ -360,6 +364,8 @@
     private CompilationAttributes compilationAttributes;
     private boolean useDeps = true;
     private Map<String, NestedSet<Artifact>> outputGroupCollector;
+    private ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector =
+        ImmutableList.builder();
     private boolean isObjcLibrary = false;
     private CcToolchainProvider toolchain;
     private boolean isTestRule = false;
@@ -449,6 +455,16 @@
     }
 
     /**
+     * Causes the provided list to be updated with providers that should be exported by this target.
+     */
+    public Builder setProviderCollector(
+        ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector) {
+      Preconditions.checkNotNull(providerCollector);
+      this.providerCollector = providerCollector;
+      return this;
+    }
+
+    /**
      * Returns a {@link CompilationSupport} instance. This is either a {@link
      * CrosstoolCompilationSupport} or {@link LegacyCompilationSupport} depending on the value of
      * --experimental_objc_crosstool.
@@ -485,6 +501,7 @@
             useDeps,
             outputGroupCollector,
             toolchain,
+            providerCollector,
             isTestRule,
             usePch);
       } else {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java
index 8241b68..cf37525 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CrosstoolCompilationSupport.java
@@ -38,11 +38,14 @@
 import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMapBuilder;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions.AppleBitcodeMode;
 import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CcCommon;
 import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper;
 import com.google.devtools.build.lib.rules.cpp.CcLibraryHelper.Info;
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.CollidingProvidesException;
@@ -62,7 +65,8 @@
 import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType;
 import com.google.devtools.build.lib.rules.cpp.NoProcessing;
 import com.google.devtools.build.lib.rules.cpp.PrecompiledFiles;
-import com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag;
+import com.google.devtools.build.lib.rules.cpp.TransitiveSourcesProvider;
+import com.google.devtools.build.lib.rules.cpp.TransitiveSourcesProvider.SourceUsage;
 import com.google.devtools.build.lib.rules.objc.ObjcVariablesExtension.VariableCategory;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.util.Collection;
@@ -103,9 +107,6 @@
 
   private static final String GENERATE_LINKMAP_FEATURE_NAME = "generate_linkmap";
 
-  /** Enabled if this target has objc sources in its transitive closure. */
-  private static final String CONTAINS_OBJC = "contains_objc_sources";
-
   private static final ImmutableList<String> ACTIVATED_ACTIONS =
       ImmutableList.of(
           "objc-compile",
@@ -136,6 +137,7 @@
         /*useDeps=*/ true,
         outputGroupCollector,
         null,
+        ImmutableList.builder(),
         /*isTestRule=*/ false,
         /*usePch=*/ true);
   }
@@ -159,6 +161,7 @@
       boolean useDeps,
       Map<String, NestedSet<Artifact>> outputGroupCollector,
       CcToolchainProvider toolchain,
+      ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector,
       boolean isTestRule,
       boolean usePch) {
     super(
@@ -169,6 +172,7 @@
         useDeps,
         outputGroupCollector,
         toolchain,
+        providerCollector,
         isTestRule,
         usePch);
   }
@@ -225,6 +229,15 @@
     Info info = helper.build();
     outputGroupCollector.putAll(info.getOutputGroups());
 
+    TransitiveSourcesProvider sourcesProvider =
+        info.getProviders().getProvider(TransitiveSourcesProvider.class);
+    if (sourcesProvider != null) {
+      TransitiveInfoProviderMapBuilder providersToPropagate =
+          new TransitiveInfoProviderMapBuilder();
+      providersToPropagate.add(sourcesProvider);
+      providerCollector.add(providersToPropagate.build());
+    }
+
     registerHeaderScanningActions(info, objcProvider, compilationArtifacts);
 
     return this;
@@ -258,7 +271,7 @@
                 outputArchive,
                 ccToolchain,
                 fdoSupport,
-                getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration, objcProvider))
+                getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration))
             .addActionInputs(objcProvider.getObjcLibraries())
             .addActionInputs(objcProvider.getCcLibraries())
             .addActionInputs(objcProvider.get(IMPORTED_LIBRARY).toSet())
@@ -309,10 +322,11 @@
 
     registerObjFilelistAction(objFiles, inputFileList);
 
-    LinkTargetType linkType = (objcProvider.is(Flag.USES_CPP))
-        ? LinkTargetType.OBJCPP_EXECUTABLE
-        : LinkTargetType.OBJC_EXECUTABLE;
-    
+    LinkTargetType linkType =
+        CcCommon.getTransitiveSourcesProvider(ruleContext).uses(SourceUsage.CPP)
+            ? LinkTargetType.OBJCPP_EXECUTABLE
+            : LinkTargetType.OBJC_EXECUTABLE;
+
     ObjcVariablesExtension.Builder extensionBuilder =
         new ObjcVariablesExtension.Builder()
             .setRuleContext(ruleContext)
@@ -334,7 +348,7 @@
                 binaryToLink,
                 toolchain,
                 fdoSupport,
-                getFeatureConfiguration(ruleContext, toolchain, buildConfiguration, objcProvider))
+                getFeatureConfiguration(ruleContext, toolchain, buildConfiguration))
             .setMnemonic("ObjcLink")
             .addActionInputs(bazelBuiltLibraries)
             .addActionInputs(objcProvider.getCcLibraries())
@@ -435,7 +449,7 @@
         new CcLibraryHelper(
                 ruleContext,
                 semantics,
-                getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration, objcProvider),
+                getFeatureConfiguration(ruleContext, ccToolchain, buildConfiguration),
                 CcLibraryHelper.SourceCategory.CC_AND_OBJC,
                 ccToolchain,
                 fdoSupport,
@@ -483,10 +497,7 @@
   }
 
   private FeatureConfiguration getFeatureConfiguration(
-      RuleContext ruleContext,
-      CcToolchainProvider ccToolchain,
-      BuildConfiguration configuration,
-      ObjcProvider objcProvider) {
+      RuleContext ruleContext, CcToolchainProvider ccToolchain, BuildConfiguration configuration) {
     boolean isHost = ruleContext.getConfiguration().isHostConfiguration();
     ImmutableSet.Builder<String> activatedCrosstoolSelectables =
         ImmutableSet.<String>builder()
@@ -537,8 +548,8 @@
     if (bitcodeMode != AppleBitcodeMode.NONE) {
       activatedCrosstoolSelectables.addAll(bitcodeMode.getFeatureNames());
     }
-    if (objcProvider.is(Flag.USES_OBJC)) {
-      activatedCrosstoolSelectables.add(CONTAINS_OBJC);
+    if (CcCommon.getTransitiveSourcesProvider(ruleContext).uses(SourceUsage.OBJC)) {
+      activatedCrosstoolSelectables.add(CppRuleClasses.CONTAINS_OBJC_SOURCE);
     }
 
     activatedCrosstoolSelectables.addAll(ruleContext.getFeatures());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java
index 24f1f98..1ca650d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java
@@ -31,6 +31,7 @@
 import com.google.devtools.build.lib.analysis.Runfiles;
 import com.google.devtools.build.lib.analysis.RunfilesProvider;
 import com.google.devtools.build.lib.analysis.RunfilesSupport;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
 import com.google.devtools.build.lib.analysis.test.ExecutionInfo;
 import com.google.devtools.build.lib.analysis.test.InstrumentedFilesProvider;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
@@ -158,8 +159,13 @@
                 ruleContext.getPrerequisites("deps", Mode.TARGET, J2ObjcEntryClassProvider.class))
             .build();
 
+    ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector = ImmutableList.builder();
     CompilationSupport compilationSupport =
-        new CompilationSupport.Builder().setRuleContext(ruleContext).setIsTestRule().build();
+        new CompilationSupport.Builder()
+            .setProviderCollector(providerCollector)
+            .setRuleContext(ruleContext)
+            .setIsTestRule()
+            .build();
 
     compilationSupport
         .registerLinkActions(
@@ -231,6 +237,7 @@
         .addNativeDeclaredProvider(new ExecutionInfo(execInfoMapBuilder.build()))
         .addNativeDeclaredProviders(testSupport.getExtraProviders())
         .addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider)
+        .addProviderMaps(providerCollector.build())
         .setRunfilesSupport(runfilesSupport, executable)
         .build();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java
index 8cd7c33..f34aab5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java
@@ -26,6 +26,7 @@
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.RunfilesProvider;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.syntax.Type;
@@ -94,8 +95,10 @@
             .setIntermediateArtifacts(ObjcRuleClasses.intermediateArtifacts(ruleContext))
             .build();
 
+    ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector = ImmutableList.builder();
     new CompilationSupport.Builder()
         .setRuleContext(ruleContext)
+        .setProviderCollector(providerCollector)
         .setIntermediateArtifacts(ObjcRuleClasses.intermediateArtifacts(ruleContext))
         .doNotUsePch()
         .build()
@@ -110,6 +113,7 @@
         .add(RunfilesProvider.class, RunfilesProvider.EMPTY)
         .addProvider(J2ObjcEntryClassProvider.class, j2ObjcEntryClassProvider)
         .addProvider(J2ObjcMappingFileProvider.class, j2ObjcMappingFileProvider)
+        .addProviderMaps(providerCollector.build())
         .addNativeDeclaredProvider(objcProvider)
         .build();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/LegacyCompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/LegacyCompilationSupport.java
index 52024af..c3a336b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/LegacyCompilationSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/LegacyCompilationSupport.java
@@ -17,7 +17,6 @@
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DEFINE;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DYNAMIC_FRAMEWORK_FILE;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FORCE_LOAD_LIBRARY;
-import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_CPP;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.HEADER;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE;
@@ -27,7 +26,6 @@
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.STATIC_FRAMEWORK_FILE;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.WEAK_SDK_FRAMEWORK;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.CLANG;
-import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.CLANG_PLUSPLUS;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.COMPILABLE_SRCS_TYPE;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.DSYMUTIL;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.HEADERS;
@@ -159,6 +157,7 @@
         useDeps,
         outputGroupCollector,
         toolchain,
+        ImmutableList.builder(),
         isTestRule,
         usePch);
   }
@@ -676,14 +675,7 @@
     CustomCommandLine.Builder commandLine =
         CustomCommandLine.builder()
             .addPath(xcrunwrapper(ruleContext).getExecutable().getExecPath());
-    if (objcProvider.is(USES_CPP)) {
-      commandLine
-        .add(CLANG_PLUSPLUS)
-        .add("-stdlib=libc++")
-        .add("-std=gnu++11");
-    } else {
-      commandLine.add(CLANG);
-    }
+    commandLine.add(CLANG);
 
     // TODO(b/36562173): Replace the "!isTestRule" condition with the presence of "-bundle" in
     // the command line.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/MultiArchBinarySupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/MultiArchBinarySupport.java
index 4da377c..79744d4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/MultiArchBinarySupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/MultiArchBinarySupport.java
@@ -25,6 +25,7 @@
 import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.platform.ToolchainInfo;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
@@ -128,6 +129,8 @@
    *     this support
    * @param outputMapCollector a map to which output groups created by compile action generation are
    *     added
+   * @param providerCollector a list to which provider maps created by compile and link action
+   *     generation are added
    * @throws RuleErrorException if there are attribute errors in the current rule context
    */
   public void registerActions(
@@ -137,7 +140,8 @@
       Iterable<Artifact> extraLinkInputs,
       ImmutableListMultimap<BuildConfiguration, TransitiveInfoCollection> configToDepsCollectionMap,
       Artifact outputLipoBinary,
-      Map<String, NestedSet<Artifact>> outputMapCollector)
+      Map<String, NestedSet<Artifact>> outputMapCollector,
+      ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector)
       throws RuleErrorException, InterruptedException {
 
     NestedSetBuilder<Artifact> binariesToLipo =
@@ -179,6 +183,7 @@
               .setRuleContext(ruleContext)
               .setConfig(dependencySpecificConfiguration.config())
               .setOutputGroupCollector(outputMapCollector)
+              .setProviderCollector(providerCollector)
               .build();
 
       compilationSupport
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java
index cd08ee7..cf1ab2e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java
@@ -23,10 +23,7 @@
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DEFINE;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DYNAMIC_FRAMEWORK_DIR;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DYNAMIC_FRAMEWORK_FILE;
-import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FLAG;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FORCE_LOAD_LIBRARY;
-import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_CPP;
-import static com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag.USES_OBJC;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.HEADER;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY;
 import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE;
@@ -71,10 +68,8 @@
 import com.google.devtools.build.lib.rules.cpp.CcLinkParams;
 import com.google.devtools.build.lib.rules.cpp.CcLinkParamsInfo;
 import com.google.devtools.build.lib.rules.cpp.CppCompilationContext;
-import com.google.devtools.build.lib.rules.cpp.CppFileTypes;
 import com.google.devtools.build.lib.rules.cpp.CppModuleMap;
 import com.google.devtools.build.lib.util.FileType;
-import com.google.devtools.build.lib.util.FileTypeSet;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.util.HashSet;
@@ -522,24 +517,6 @@
             && J2ObjcLibrary.J2OBJC_SUPPORTED_RULES.contains(context.getRule().getRuleClass())) {
           objcProvider.addAll(J2OBJC_LIBRARY, artifacts.getArchive().asSet());
         }
-
-        boolean usesCpp = false;
-        boolean usesObjc = false;
-        for (Artifact sourceFile :
-            Iterables.concat(artifacts.getSrcs(), artifacts.getNonArcSrcs())) {
-          usesCpp = usesCpp || ObjcRuleClasses.CPP_SOURCES.matches(sourceFile.getExecPath());
-          usesObjc =
-              usesObjc
-                  || FileTypeSet.of(CppFileTypes.OBJC_SOURCE, CppFileTypes.OBJCPP_SOURCE)
-                      .matches(sourceFile.getExecPath().getPathString());
-        }
-
-        if (usesCpp) {
-          objcProvider.add(FLAG, USES_CPP);
-        }
-        if (usesObjc) {
-          objcProvider.add(FLAG, USES_OBJC);
-        }
       }
 
       if (alwayslink) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImport.java
index 043605f..a32cc32 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImport.java
@@ -14,11 +14,13 @@
 
 package com.google.devtools.build.lib.rules.objc;
 
+import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.rules.cpp.CppModuleMap;
 import com.google.devtools.build.lib.rules.objc.ObjcCommon.ResourceAttributes;
@@ -56,8 +58,10 @@
     Iterable<Artifact> publicHeaders = compilationAttributes.hdrs();
     CppModuleMap moduleMap = intermediateArtifacts.moduleMap();
 
+    ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector = ImmutableList.builder();
     new CompilationSupport.Builder()
         .setRuleContext(ruleContext)
+        .setProviderCollector(providerCollector)
         .build()
         .registerGenerateModuleMapAction(moduleMap, publicHeaders)
         .validateAttributes();
@@ -66,6 +70,7 @@
 
     return ObjcRuleClasses.ruleConfiguredTarget(ruleContext, filesToBuild.build())
         .addNativeDeclaredProvider(common.getObjcProvider())
+        .addProviderMaps(providerCollector.build())
         .build();
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java
index bb7429f..85e08c1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java
@@ -14,11 +14,13 @@
 
 package com.google.devtools.build.lib.rules.objc;
 
+import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
 import com.google.devtools.build.lib.analysis.test.InstrumentedFilesProvider;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
@@ -67,10 +69,12 @@
         .addAll(common.getCompiledArchive().asSet());
 
     Map<String, NestedSet<Artifact>> outputGroupCollector = new TreeMap<>();
+    ImmutableList.Builder<TransitiveInfoProviderMap> providerCollector = ImmutableList.builder();
     CompilationSupport compilationSupport =
         new CompilationSupport.Builder()
             .setRuleContext(ruleContext)
             .setOutputGroupCollector(outputGroupCollector)
+            .setProviderCollector(providerCollector)
             .setIsObjcLibrary()
             .build();
 
@@ -96,8 +100,8 @@
         .addProvider(
             InstrumentedFilesProvider.class,
             compilationSupport.getInstrumentedFilesProvider(common))
-        .addNativeDeclaredProvider(
-            new CcLinkParamsInfo(new ObjcLibraryCcLinkParamsStore(common)))
+        .addNativeDeclaredProvider(new CcLinkParamsInfo(new ObjcLibraryCcLinkParamsStore(common)))
+        .addProviderMaps(providerCollector.build())
         .addOutputGroups(outputGroupCollector)
         .build();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
index 0970d96..a11c96f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java
@@ -343,19 +343,8 @@
    * flag. If the item is included in the key {@link #FLAG}, then the flag is considered set.
    */
   public enum Flag {
-    /**
-     * Indicates that C++ (or Objective-C++) is used in any source file. This affects how the linker
-     * is invoked.
-     */
-    USES_CPP,
-
-    /**
-     * Indicates that Objective-C (or Objective-C++) is used in any source file. This affects how
-     * the linker is invoked.
-     */
-    USES_OBJC,
-
     /** Indicates that Swift dependencies are present. This affects bundling actions. */
+    // TODO(b/65016770): Move to TransitiveSourcesProvider.
     USES_SWIFT,
 
     /**
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinaryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinaryTest.java
index 01754e5..b0d0953 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinaryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinaryTest.java
@@ -223,4 +223,9 @@
   public void testCompilesSources() throws Exception {
     checkCompilesSources(RULE_TYPE);
   }
+
+  @Test
+  public void testLinkActionWithTransitiveCppDependency() throws Exception {
+    checkLinkActionWithTransitiveCppDependency(RULE_TYPE, EXTRA_LINK_ARGS);
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyIosExtensionBinaryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyIosExtensionBinaryTest.java
index 0fadc47..f2416ea 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyIosExtensionBinaryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyIosExtensionBinaryTest.java
@@ -29,9 +29,10 @@
     return ObjcCrosstoolMode.OFF;
   }
 
+  @Override
   @Test
   public void testLinkActionWithTransitiveCppDependency() throws Exception {
-    checkLinkActionWithTransitiveCppDependency(RULE_TYPE, EXTRA_LINK_ARGS);
+    // Transitive source data is not known to the legacy rules.
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyObjcBinaryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyObjcBinaryTest.java
index d0c08a6..55475fe 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyObjcBinaryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyObjcBinaryTest.java
@@ -37,9 +37,10 @@
     return ObjcCrosstoolMode.OFF;
   }
 
+  @Override
   @Test
   public void testLinkActionWithTransitiveCppDependency() throws Exception {
-    checkLinkActionWithTransitiveCppDependency(RULE_TYPE, new ExtraLinkArgs());
+    // Transitive sources data is not available to the legacy rules.
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyObjcLibraryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyObjcLibraryTest.java
index 2028571..abbae40 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyObjcLibraryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/LegacyObjcLibraryTest.java
@@ -59,24 +59,6 @@
     useConfiguration(ObjcCrosstoolMode.OFF, args);
   }
 
-  @Override
-  @Test
-  public void testObjcSourcesFeatureCC() throws Exception {
-    // Features are not exported by legacy actions.
-  }
-
-  @Override
-  @Test
-  public void testObjcSourcesFeatureObjc() throws Exception {
-    // Features are not exported by legacy actions.
-  }
-
-  @Override
-  @Test
-  public void testObjcSourcesFeatureObjcPlusPlus() throws Exception {
-    // Features are not exported by legacy actions.
-  }
-
   @Test
   public void testLibFileIsCorrectForSlashInTargetName() throws Exception {
     ConfiguredTarget target =
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcBinaryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcBinaryTest.java
index 4775e2d..255841d 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcBinaryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcBinaryTest.java
@@ -935,4 +935,9 @@
   public void testGenruleDependency() throws Exception {
     checkGenruleDependency(RULE_TYPE);
   }
+
+  @Test
+  public void testLinkActionWithTransitiveCppDependency() throws Exception {
+    checkLinkActionWithTransitiveCppDependency(RULE_TYPE, new ExtraLinkArgs());
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
index 08b1d0b..056a607 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
@@ -1566,45 +1566,4 @@
   public void testCustomModuleMap() throws Exception {
     checkCustomModuleMap(RULE_TYPE);
   }
-
-  private boolean containsObjcFeature(String srcName) throws Exception {
-     MockObjcSupport.setup(
-        mockToolsConfig,
-        "feature {",
-        "  name: 'contains_objc_sources'",
-        "  flag_set {",
-        "    flag_group {",
-        "      flag: 'DUMMY_FLAG'",
-        "    }",
-        "    action: 'c++-compile'",
-        "  }",
-        "}");
-    createLibraryTargetWriter("//bottom:lib").setList("srcs", srcName).write();
-    createLibraryTargetWriter("//middle:lib")
-        .setList("srcs", "b.cc")
-        .setList("deps", "//bottom:lib")
-        .write();
-    createLibraryTargetWriter("//top:lib")
-        .setList("srcs", "a.cc")
-        .setList("deps", "//middle:lib")
-        .write();
-
-    CommandAction compileAction = compileAction("//top:lib", "a.o");
-    return compileAction.getArguments().contains("DUMMY_FLAG");
-  }
-
-  @Test
-  public void testObjcSourcesFeatureCC() throws Exception {
-    assertThat(containsObjcFeature("c.cc")).isFalse();
-  }
-
-  @Test
-  public void testObjcSourcesFeatureObjc() throws Exception {
-     assertThat(containsObjcFeature("c.m")).isTrue();
-  }
-
-  @Test
-  public void testObjcSourcesFeatureObjcPlusPlus() throws Exception {
-     assertThat(containsObjcFeature("c.mm")).isTrue();
-  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcRuleTestCase.java b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcRuleTestCase.java
index b48d242..7baa058 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcRuleTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcRuleTestCase.java
@@ -26,7 +26,6 @@
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.BundlingRule.FAMILIES_ATTR;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.BundlingRule.INFOPLIST_ATTR;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.CLANG;
-import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.CLANG_PLUSPLUS;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.DSYMUTIL;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.LIPO;
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.ReleaseBundlingRule.APP_ICON_ATTR;
@@ -644,9 +643,10 @@
     ruleType.scratchTarget(scratch, "srcs", "['c.m']", "deps", "['//lib2:lib2']");
 
     CommandAction action = linkAction("//x:x");
-    assertThat(action.getArguments().get(2))
-        .startsWith(
-            MOCK_XCRUNWRAPPER_PATH + " " + CLANG_PLUSPLUS + " -stdlib=libc++ -std=gnu++11");
+    String commandLine = Joiner.on(" ").join(action.getArguments());
+    assertThat(commandLine).contains("wrapped_clang++");
+    assertThat(commandLine).contains("-stdlib=libc++");
+    assertThat(commandLine).contains("-std=gnu++11");
   }
 
   protected Map<String, String> mobileProvisionProfiles(BundleMergeProtos.Control control) {
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/TransitiveSourcesTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/TransitiveSourcesTest.java
new file mode 100644
index 0000000..015c7d1
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/TransitiveSourcesTest.java
@@ -0,0 +1,85 @@
+// Copyright 2017 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.rules.objc;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.packages.util.MockObjcSupport;
+import com.google.devtools.build.lib.rules.cpp.CppCompileAction;
+import com.google.devtools.build.lib.rules.cpp.CppLinkAction;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for propagation of the presence of categories of source in the transitive deps of a target.
+ */
+@RunWith(JUnit4.class)
+public class TransitiveSourcesTest extends ObjcRuleTestCase {
+
+  @Before
+  public void setup() throws Exception {
+    MockObjcSupport.setup(
+        mockToolsConfig,
+        "feature {",
+        "  name: 'contains_objc_source'",
+        "  flag_set {",
+        "    flag_group {",
+        "      flag: 'DUMMY_FLAG'",
+        "    }",
+        "    action: 'c++-compile'",
+        "    action: 'c++-link-executable'",
+        "    action: 'objc++-executable'",
+        "  }",
+        "}");
+    useConfiguration();
+  }
+
+  private CppCompileAction getCppCompileAction(String label) throws Exception {
+    ConfiguredTarget target = getConfiguredTarget(label);
+    return actionsTestUtil()
+        .findTransitivePrerequisitesOf(
+            getFilesToBuild(target).iterator().next(), CppCompileAction.class)
+        .get(0);
+  }
+
+  private CppLinkAction getExecutableCppLinkAction(String label) throws Exception {
+    return (CppLinkAction) getGeneratingAction(getExecutable(label));
+  }
+
+  @Test
+  public void testCcBinaryTransitiveObjcFeature() throws Exception {
+    scratch.file("bottom/BUILD", "objc_library(name='lib', srcs=['a.m'])");
+    scratch.file("middle/BUILD", "cc_library(name='lib', srcs=['a.cc'], deps=['//bottom:lib'])");
+    scratch.file("top/BUILD", "cc_binary(name='bin', srcs=['a.cc'], deps=['//middle:lib'])");
+
+    assertThat(getCppCompileAction("//top:bin").getArguments()).contains("DUMMY_FLAG");
+    assertThat(getExecutableCppLinkAction("//top:bin").getArguments()).contains("DUMMY_FLAG");
+  }
+
+  @Test
+  public void testAppleBinaryTransitiveObjcFeature() throws Exception {
+    scratch.file("bottom/BUILD", "objc_library(name='lib', srcs=['a.m'])");
+    scratch.file("middle/BUILD", "cc_library(name='lib', srcs=['a.cc'], deps=['//bottom:lib'])");
+    scratch.file(
+        "top/BUILD",
+        "apple_binary(name='bin', platform_type='ios', srcs=['a.cc'], deps=['//middle:lib'])");
+
+    assertThat(getCppCompileAction("//top:bin").getArguments()).contains("DUMMY_FLAG");
+    assertThat(linkAction("//top:bin").getArguments()).contains("DUMMY_FLAG");
+  }
+}