Add an xcode_config_alias rule that is an alias to the current xcode_config rule in use and expose data in XcodeConfigProvider to Skylark.

This gives us a way to discover Xcode version information from Skylark in a way other than by AppleConfiguration, which in turn makes it possible to remove said data (and thus dependencies on BUILD files) from AppleConfiguration.

Work towards https://github.com/bazelbuild/bazel/issues/3424 .

RELNOTES: None.
PiperOrigin-RevId: 166311454
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index 6111fe9..97a55c0 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -88,6 +88,7 @@
 import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions;
 import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
 import com.google.devtools.build.lib.rules.apple.AppleToolchain;
+import com.google.devtools.build.lib.rules.apple.XcodeConfigAlias.XcodeConfigAliasRule;
 import com.google.devtools.build.lib.rules.apple.XcodeConfigRule;
 import com.google.devtools.build.lib.rules.apple.XcodeVersionRule;
 import com.google.devtools.build.lib.rules.apple.cpp.AppleCcToolchainRule;
@@ -592,6 +593,7 @@
           builder.addRuleDefinition(new ObjcRuleClasses.WatchApplicationBundleRule());
           builder.addRuleDefinition(new ObjcRuleClasses.CrosstoolRule());
           builder.addRuleDefinition(new XcodeConfigRule());
+          builder.addRuleDefinition(new XcodeConfigAliasRule());
           builder.addRuleDefinition(new XcodeVersionRule());
         }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleConfiguration.java
index fed8366..618647a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleConfiguration.java
@@ -461,7 +461,7 @@
     name = "single_arch_platform",
     doc = "The platform of the current configuration. This should only be invoked in a context "
         + "where only a single architecture may be supported; consider "
-        + "<a href='#multi_arch_platform'>mutli_arch_platform</a> for other cases.",
+        + "<a href='#multi_arch_platform'>multi_arch_platform</a> for other cases.",
     structField = true
   )
   public ApplePlatform getSingleArchPlatform() {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfig.java b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfig.java
index 42b3296..d2b5859 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfig.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfig.java
@@ -152,7 +152,7 @@
 
     return new RuleConfiguredTargetBuilder(ruleContext)
         .addProvider(RunfilesProvider.class, RunfilesProvider.EMPTY)
-        .addProvider(xcodeVersions)
+        .addNativeDeclaredProvider(xcodeVersions)
         .addNativeDeclaredProvider(xcodeVersionProperties)
         .build();
   }
@@ -337,7 +337,7 @@
     XcodeConfigProvider versions = ruleContext.getPrerequisite(
         XcodeConfigRule.XCODE_CONFIG_ATTR_NAME,
         RuleConfiguredTarget.Mode.TARGET,
-        XcodeConfigProvider.class);
+        XcodeConfigProvider.PROVIDER);
     DottedVersion fromProvider = versions.getMinimumOsForPlatformType(platformType);
     DottedVersion fromConfig = config.getMinimumOsForPlatformType(platformType);
     // This sanity check is there to keep this provider in sync with AppleConfiguration until the
@@ -355,7 +355,7 @@
     XcodeConfigProvider versions = ruleContext.getPrerequisite(
         XcodeConfigRule.XCODE_CONFIG_ATTR_NAME,
         RuleConfiguredTarget.Mode.TARGET,
-        XcodeConfigProvider.class);
+        XcodeConfigProvider.PROVIDER);
     DottedVersion fromProvider = versions.getSdkVersionForPlatform(platform);
     DottedVersion fromConfig = ruleContext.getFragment(AppleConfiguration.class)
         .getSdkVersionForPlatform(platform);
@@ -373,7 +373,8 @@
   public static DottedVersion getXcodeVersion(RuleContext ruleContext) {
     XcodeConfigProvider versions = ruleContext.getPrerequisite(
         XcodeConfigRule.XCODE_CONFIG_ATTR_NAME,
-        RuleConfiguredTarget.Mode.TARGET, XcodeConfigProvider.class);
+        RuleConfiguredTarget.Mode.TARGET,
+        XcodeConfigProvider.PROVIDER);
     DottedVersion fromProvider = versions.getXcodeVersion();
     DottedVersion fromConfig = ruleContext.getFragment(AppleConfiguration.class).getXcodeVersion();
     // This sanity check is there to keep this provider in sync with AppleConfiguration until the
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfigAlias.java b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfigAlias.java
new file mode 100644
index 0000000..f3b56a5
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfigAlias.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.apple;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.analysis.AliasProvider;
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+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.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.analysis.VisibilityProvider;
+import com.google.devtools.build.lib.analysis.VisibilityProviderImpl;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.rules.AliasConfiguredTarget;
+
+/**
+ * Implementation of the {@code xcode_config_alias} rule.
+ *
+ * <p>This rule is an alias to the {@code xcode_config} rule currently in use, which is in turn
+ * depends on the current configuration, in particular, the value of the {@code --xcode_config}
+ * flag.
+ */
+public class XcodeConfigAlias implements RuleConfiguredTargetFactory {
+  @Override
+  public ConfiguredTarget create(RuleContext ruleContext)
+      throws InterruptedException, RuleErrorException {
+    ConfiguredTarget actual = (ConfiguredTarget) ruleContext.getPrerequisite(
+        XcodeConfigRule.XCODE_CONFIG_ATTR_NAME, Mode.TARGET);
+    return new AliasConfiguredTarget(
+        ruleContext,
+        actual,
+        ImmutableMap.of(
+            AliasProvider.class,
+            AliasProvider.fromAliasRule(ruleContext.getLabel(), actual),
+            VisibilityProvider.class,
+            new VisibilityProviderImpl(ruleContext.getVisibility())));
+  }
+
+  /**
+   * Rule definition for the {@code xcode_config_alias} rule.
+   *
+   * <p>This rule is an alias to the {@code xcode_config} rule currently in use, which is in turn
+   * depends on the current configuration, in particular, the value of the {@code --xcode_config}
+   * flag.
+   *
+   * <p>This is intentionally undocumented for users; the workspace is expected to contain exactly
+   * one instance of this rule under {@code @bazel_tools//tools/osx} and people who want to get
+   * data this rule provides should depend on that one.
+   */
+  public static class XcodeConfigAliasRule implements RuleDefinition {
+
+    @Override
+    public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment environment) {
+      return builder
+          .requiresConfigurationFragments(AppleConfiguration.class)
+          .removeAttribute("licenses")
+          .removeAttribute("distribs")
+          .build();
+    }
+
+    @Override
+    public Metadata getMetadata() {
+      return Metadata.builder()
+          .name("xcode_config_alias")
+          .ancestors(BaseRuleClasses.BaseRule.class, AppleToolchain.RequiresXcodeConfigRule.class)
+          .factoryClass(XcodeConfigAlias.class)
+          .build();
+    }
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfigProvider.java b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfigProvider.java
index ce138da..d711bd4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfigProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfigProvider.java
@@ -14,15 +14,29 @@
 package com.google.devtools.build.lib.rules.apple;
 
 import com.google.common.base.Preconditions;
-import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.packages.NativeInfo;
+import com.google.devtools.build.lib.packages.NativeProvider;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
 import javax.annotation.Nullable;
 
 /**
  * The set of Apple versions computed from command line options and the {@code xcode_config} rule.
  */
 @Immutable
-public class XcodeConfigProvider implements TransitiveInfoProvider {
+@SkylarkModule(
+    name = XcodeConfigProvider.SKYLARK_NAME,
+    doc = "The set of Apple versions computed from command line options and the xcode_config rule.")
+public class XcodeConfigProvider extends NativeInfo {
+  /** Skylark name for this provider. */
+  public static final String SKYLARK_NAME = "XcodeVersionConfig";
+
+  /** Provider identifier for {@link XcodeConfigProvider}. */
+  public static final NativeProvider<XcodeConfigProvider> PROVIDER =
+      new NativeProvider<XcodeConfigProvider>(XcodeConfigProvider.class, SKYLARK_NAME) {};
+
   private final DottedVersion iosSdkVersion;
   private final DottedVersion iosMinimumOsVersion;
   private final DottedVersion watchosSdkVersion;
@@ -39,6 +53,7 @@
       DottedVersion tvosSdkVersion, DottedVersion tvosMinimumOsVersion,
       DottedVersion macosSdkVersion, DottedVersion macosMinimumOsVersion,
       DottedVersion xcodeVersion) {
+    super(PROVIDER, ImmutableMap.of());
     this.iosSdkVersion = Preconditions.checkNotNull(iosSdkVersion);
     this.iosMinimumOsVersion = Preconditions.checkNotNull(iosMinimumOsVersion);
     this.watchosSdkVersion = Preconditions.checkNotNull(watchosSdkVersion);
@@ -50,10 +65,18 @@
     this.xcodeVersion = xcodeVersion;
   }
 
+  @SkylarkCallable(name = "xcode_version",
+      doc = "Returns the Xcode version that is being used to build.<p>"
+          + "This will return <code>None</code> if no Xcode versions are available.",
+      allowReturnNones = true)
   public DottedVersion getXcodeVersion() {
     return xcodeVersion;
   }
 
+  @SkylarkCallable(
+      name = "minimum_os_for_platform_type",
+      doc = "The minimum compatible OS version for target simulator and devices for a particular "
+          + "platform type.")
   public DottedVersion getMinimumOsForPlatformType(ApplePlatform.PlatformType platformType) {
     // TODO(b/37240784): Look into using only a single minimum OS flag tied to the current
     // apple_platform_type.
@@ -71,6 +94,10 @@
     }
   }
 
+  @SkylarkCallable(
+      name = "sdk_version_for_platform",
+      doc = "The version of the platform SDK that will be used to build targets for the given "
+          + "platform.")
   public DottedVersion getSdkVersionForPlatform(ApplePlatform platform) {
     switch (platform) {
       case IOS_DEVICE:
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleSkylarkCommon.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleSkylarkCommon.java
index 4291fbe..be4df25 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleSkylarkCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleSkylarkCommon.java
@@ -26,6 +26,7 @@
 import com.google.devtools.build.lib.rules.apple.ApplePlatform.PlatformType;
 import com.google.devtools.build.lib.rules.apple.AppleToolchain;
 import com.google.devtools.build.lib.rules.apple.DottedVersion;
+import com.google.devtools.build.lib.rules.apple.XcodeConfigProvider;
 import com.google.devtools.build.lib.rules.apple.XcodeVersionProperties;
 import com.google.devtools.build.lib.rules.objc.ObjcProvider.Key;
 import com.google.devtools.build.lib.skylarkinterface.Param;
@@ -151,6 +152,15 @@
   }
 
   @SkylarkCallable(
+      name = XcodeConfigProvider.SKYLARK_NAME,
+      doc = "The constructor/key for the <code>XcodeVersionConfig</code> provider.",
+      structField =  true
+  )
+  public Provider getXcodeVersionConfigConstructor() {
+    return XcodeConfigProvider.PROVIDER;
+  }
+
+  @SkylarkCallable(
     // TODO(b/63899207): This currently does not match ObjcProvider.SKYLARK_NAME as it requires
     // a migration of existing skylark rules.
     name = "Objc",