Migrate `AvailableXcodesInfo`, `XcodeProperties`, and `XcodeVersionRuleData` to builtin Starlark (with Starlark-consistent names).

The names of these things being very similar is likely to be confusing in the future, but we can address that after we've migrated them to apple_support. Fortunately they're only really used to communicate between the Xcode rules internally, so refactoring them shouldn't have many downstream effects.

This change does not cover `XcodeConfigInfo`, since it's a bit more complicated.

PiperOrigin-RevId: 625652603
Change-Id: Ic3c024f4b4f60c8fa93f68aa61e939215c965227
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/ObjcRules.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/ObjcRules.java
index 9e476dc..73890c8 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/ObjcRules.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/ObjcRules.java
@@ -21,9 +21,6 @@
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider.RuleSet;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
-import com.google.devtools.build.lib.rules.apple.AvailableXcodesInfo;
-import com.google.devtools.build.lib.rules.apple.XcodeVersionProperties;
-import com.google.devtools.build.lib.rules.apple.XcodeVersionRuleData;
 import com.google.devtools.build.lib.rules.core.CoreRules;
 import com.google.devtools.build.lib.rules.objc.AppleStarlarkCommon;
 import com.google.devtools.build.lib.rules.objc.AppleToolchain;
@@ -58,10 +55,7 @@
     builder.addRuleDefinition(new EmptyRule("xcode_config_alias") {});
     builder.addRuleDefinition(new EmptyRule("xcode_version") {});
 
-    builder.addStarlarkBuiltinsInternal("AvailableXcodesInfo", AvailableXcodesInfo.PROVIDER);
     builder.addStarlarkBuiltinsInternal("XcodeConfigInfo", XcodeConfigInfo.PROVIDER);
-    builder.addStarlarkBuiltinsInternal("XcodeProperties", XcodeVersionProperties.PROVIDER);
-    builder.addStarlarkBuiltinsInternal("XcodeVersionRuleData", XcodeVersionRuleData.PROVIDER);
 
     builder.addStarlarkBuiltinsInternal("apple_common", new AppleStarlarkCommon());
     builder.addStarlarkBootstrap(new AppleBootstrap());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/AvailableXcodesApi.java b/src/main/java/com/google/devtools/build/lib/rules/apple/AvailableXcodesApi.java
deleted file mode 100644
index 50ca965..0000000
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/AvailableXcodesApi.java
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2024 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.devtools.build.docgen.annot.StarlarkConstructor;
-import com.google.devtools.build.lib.starlarkbuildapi.FileApi;
-import com.google.devtools.build.lib.starlarkbuildapi.core.ProviderApi;
-import net.starlark.java.annot.Param;
-import net.starlark.java.annot.ParamType;
-import net.starlark.java.annot.StarlarkMethod;
-import net.starlark.java.eval.EvalException;
-import net.starlark.java.eval.NoneType;
-import net.starlark.java.eval.Sequence;
-import net.starlark.java.eval.StarlarkThread;
-
-/** Provider structure for {@code AvailableXcodesInfo} provider. */
-interface AvailableXcodesApi<FileT extends FileApi> extends ProviderApi {
-
-  @StarlarkMethod(
-      name = "AvailableXcodesApi",
-      useStarlarkThread = true,
-      parameters = {
-        @Param(
-            name = "versions",
-            positional = false,
-            named = true,
-            defaultValue = "None",
-            allowedTypes = {@ParamType(type = NoneType.class), @ParamType(type = Sequence.class)},
-            documented = false),
-        @Param(
-            name = "default",
-            positional = false,
-            named = true,
-            defaultValue = "None",
-            allowedTypes = {
-              @ParamType(type = NoneType.class),
-              @ParamType(type = XcodeVersionRuleData.class)
-            },
-            documented = false),
-      },
-      selfCall = true,
-      documented = false)
-  @StarlarkConstructor
-  public AvailableXcodesInfo createInfo(
-      Object availableXcodes, Object defaultVersion, StarlarkThread thread) throws EvalException;
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/AvailableXcodesInfo.java b/src/main/java/com/google/devtools/build/lib/rules/apple/AvailableXcodesInfo.java
deleted file mode 100644
index 8bf4361..0000000
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/AvailableXcodesInfo.java
+++ /dev/null
@@ -1,91 +0,0 @@
-// 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.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.BuiltinProvider;
-import com.google.devtools.build.lib.packages.NativeInfo;
-import javax.annotation.Nullable;
-import net.starlark.java.annot.StarlarkMethod;
-import net.starlark.java.eval.EvalException;
-import net.starlark.java.eval.Sequence;
-import net.starlark.java.eval.Starlark;
-import net.starlark.java.eval.StarlarkThread;
-
-/** The available Xcode versions computed from the {@code available_xcodes} rule. */
-@Immutable
-public class AvailableXcodesInfo extends NativeInfo {
-  /** Starlark name for this provider. */
-  public static final String STARLARK_NAME = "AvailableXcodesInfo";
-
-  /** Provider identifier for {@link AvailableXcodesInfo}. */
-  public static final BuiltinProvider<AvailableXcodesInfo> PROVIDER = new Provider();
-
-  private final Iterable<XcodeVersionRuleData> availableXcodes;
-  private final XcodeVersionRuleData defaultVersion;
-
-  public AvailableXcodesInfo(
-      Iterable<XcodeVersionRuleData> availableXcodes, XcodeVersionRuleData defaultVersion) {
-    this.availableXcodes = availableXcodes;
-    this.defaultVersion = defaultVersion;
-  }
-
-  @Override
-  public BuiltinProvider<AvailableXcodesInfo> getProvider() {
-    return PROVIDER;
-  }
-
-  /** Returns the available Xcode versions from {@code available_xcodes}. */
-  @StarlarkMethod(
-      name = "available_versions",
-      structField = true,
-      doc = "Returns the available Xcode versions from available_xcodes.")
-  public Iterable<XcodeVersionRuleData> getAvailableVersions() {
-    return availableXcodes;
-  }
-
-  /** Returns the default Xcode version from {@code available_xcodes}. */
-  @StarlarkMethod(
-      name = "default_version",
-      structField = true,
-      doc = "Returns the default Xcode version from available_xcodes.")
-  public XcodeVersionRuleData getDefaultVersion() {
-    return defaultVersion;
-  }
-
-  /** Provider class for {@link XcodeVersionRuleData} objects. */
-  public static class Provider extends BuiltinProvider<AvailableXcodesInfo>
-      implements AvailableXcodesApi<Artifact> {
-    private Provider() {
-      super(AvailableXcodesInfo.STARLARK_NAME, AvailableXcodesInfo.class);
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public AvailableXcodesInfo createInfo(
-        Object availableXcodes, Object defaultVersion, StarlarkThread thread) throws EvalException {
-      Sequence<XcodeVersionRuleData> availableXcodesSequence =
-          nullIfNone(availableXcodes, Sequence.class);
-      return new AvailableXcodesInfo(
-          Sequence.cast(availableXcodesSequence, XcodeVersionRuleData.class, "availableXcodes"),
-          nullIfNone(defaultVersion, XcodeVersionRuleData.class));
-    }
-
-    @Nullable
-    private static <T> T nullIfNone(Object object, Class<T> type) {
-      return object != Starlark.NONE ? type.cast(object) : null;
-    }
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionProperties.java b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionProperties.java
deleted file mode 100644
index 314ea08..0000000
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionProperties.java
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2016 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.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
-import com.google.common.base.Strings;
-import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.BuiltinProvider;
-import com.google.devtools.build.lib.packages.NativeInfo;
-import com.google.devtools.build.lib.starlarkbuildapi.apple.XcodePropertiesApi;
-import java.util.Objects;
-import javax.annotation.Nullable;
-import net.starlark.java.annot.StarlarkMethod;
-import net.starlark.java.eval.EvalException;
-import net.starlark.java.eval.Starlark;
-import net.starlark.java.eval.StarlarkThread;
-
-/** A tuple containing information about a version of Xcode and its properties. */
-@Immutable
-public class XcodeVersionProperties extends NativeInfo implements XcodePropertiesApi {
-  /** Starlark identifier for XcodeVersionProperties provider. */
-  public static final Provider PROVIDER = new Provider();
-
-  /** Starlark name for the XcodeVersionProperties provider. */
-  public static final String STARLARK_NAME = "XcodeProperties";
-
-  @VisibleForTesting public static final String DEFAULT_IOS_SDK_VERSION = "8.4";
-  @VisibleForTesting public static final String DEFAULT_VISIONOS_SDK_VERSION = "1.0";
-  @VisibleForTesting public static final String DEFAULT_WATCHOS_SDK_VERSION = "2.0";
-  @VisibleForTesting public static final String DEFAULT_MACOS_SDK_VERSION = "10.11";
-  @VisibleForTesting public static final String DEFAULT_TVOS_SDK_VERSION = "9.0";
-
-  private final Optional<DottedVersion> xcodeVersion;
-  private final DottedVersion defaultIosSdkVersion;
-  private final DottedVersion defaultVisionosSdkVersion;
-  private final DottedVersion defaultWatchosSdkVersion;
-  private final DottedVersion defaultTvosSdkVersion;
-  private final DottedVersion defaultMacosSdkVersion;
-
-  /**
-   * Creates and returns a tuple representing no known Xcode property information (defaults are used
-   * where applicable).
-   */
-  // TODO(bazel-team): The Xcode version should be a well-defined value, either specified by the
-  // user, evaluated on the local system, or set to a sensible default.
-  // Unfortunately, until the local system evaluation hook is created, this constraint would break
-  // some users.
-  @StarlarkMethod(
-      name = "unknownXcodeVersionProperties",
-      documented = false,
-      useStarlarkThread = true)
-  public XcodeVersionProperties unknownXcodeVersionProperties(StarlarkThread thread) {
-    return new XcodeVersionProperties(null);
-  }
-
-  /**
-   * Constructor for when only the Xcode version is specified, but no property information is
-   * specified.
-   */
-  public XcodeVersionProperties(Object xcodeVersion) {
-    this(xcodeVersion, null, null, null, null, null);
-  }
-
-  /**
-   * General constructor. Some (nullable) properties may be left unspecified. In these cases, a
-   * semi-sensible default will be assigned to the property value.
-   */
-  XcodeVersionProperties(
-      @Nullable Object xcodeVersion,
-      @Nullable String defaultIosSdkVersion,
-      @Nullable String defaultVisionosSdkVersion,
-      @Nullable String defaultWatchosSdkVersion,
-      @Nullable String defaultTvosSdkVersion,
-      @Nullable String defaultMacosSdkVersion) {
-    this.xcodeVersion =
-        Starlark.isNullOrNone(xcodeVersion)
-            ? Optional.absent()
-            : Optional.of((DottedVersion) xcodeVersion);
-    this.defaultIosSdkVersion =
-        Strings.isNullOrEmpty(defaultIosSdkVersion)
-            ? DottedVersion.fromStringUnchecked(DEFAULT_IOS_SDK_VERSION)
-            : DottedVersion.fromStringUnchecked(defaultIosSdkVersion);
-    this.defaultVisionosSdkVersion =
-        Strings.isNullOrEmpty(defaultVisionosSdkVersion)
-            ? DottedVersion.fromStringUnchecked(DEFAULT_VISIONOS_SDK_VERSION)
-            : DottedVersion.fromStringUnchecked(defaultVisionosSdkVersion);
-    this.defaultWatchosSdkVersion =
-        Strings.isNullOrEmpty(defaultWatchosSdkVersion)
-            ? DottedVersion.fromStringUnchecked(DEFAULT_WATCHOS_SDK_VERSION)
-            : DottedVersion.fromStringUnchecked(defaultWatchosSdkVersion);
-    this.defaultTvosSdkVersion =
-        Strings.isNullOrEmpty(defaultTvosSdkVersion)
-            ? DottedVersion.fromStringUnchecked(DEFAULT_TVOS_SDK_VERSION)
-            : DottedVersion.fromStringUnchecked(defaultTvosSdkVersion);
-    this.defaultMacosSdkVersion =
-        Strings.isNullOrEmpty(defaultMacosSdkVersion)
-            ? DottedVersion.fromStringUnchecked(DEFAULT_MACOS_SDK_VERSION)
-            : DottedVersion.fromStringUnchecked(defaultMacosSdkVersion);
-  }
-
-  @Override
-  public Provider getProvider() {
-    return PROVIDER;
-  }
-
-  /** Returns the Xcode version, or null if the Xcode version is unknown. */
-  @Nullable
-  @Override
-  public String getXcodeVersionString() {
-    if (xcodeVersion.isPresent()) {
-      return xcodeVersion.get().toString();
-    }
-    return null;
-  }
-
-  /** Returns the default iOS SDK version to use if this Xcode version is in use. */
-  @Nullable
-  @Override
-  public String getDefaultIosSdkVersionString() {
-    return defaultIosSdkVersion != null ? defaultIosSdkVersion.toString() : null;
-  }
-
-  /** Returns the default visionOS SDK version to use if this Xcode version is in use. */
-  @Nullable
-  @Override
-  public String getDefaultVisionosSdkVersionString() {
-    return defaultVisionosSdkVersion != null ? defaultVisionosSdkVersion.toString() : null;
-  }
-
-  /** Returns the default watchOS SDK version to use if this Xcode version is in use. */
-  @Nullable
-  @Override
-  public String getDefaultWatchosSdkVersionString() {
-    return defaultWatchosSdkVersion != null ? defaultWatchosSdkVersion.toString() : null;
-  }
-
-  /** Returns the default tvOS SDK version to use if this Xcode version is in use. */
-  @Nullable
-  @Override
-  public String getDefaultTvosSdkVersionString() {
-    return defaultTvosSdkVersion != null ? defaultTvosSdkVersion.toString() : null;
-  }
-
-  /** Returns the default macOS SDK version to use if this Xcode version is in use. */
-  @Nullable
-  @Override
-  public String getDefaultMacosSdkVersionString() {
-    return defaultMacosSdkVersion != null ? defaultMacosSdkVersion.toString() : null;
-  }
-
-  /** Returns the Xcode version, or {@link Optional#absent} if the Xcode version is unknown. */
-  public Optional<DottedVersion> getXcodeVersion() {
-    return xcodeVersion;
-  }
-
-  @Nullable
-  public DottedVersion getDefaultIosSdkVersion() {
-    return defaultIosSdkVersion;
-  }
-
-  @Nullable
-  public DottedVersion getDefaultVisionosSdkVersion() {
-    return defaultVisionosSdkVersion;
-  }
-
-  @Nullable
-  public DottedVersion getDefaultWatchosSdkVersion() {
-    return defaultWatchosSdkVersion;
-  }
-
-  @Nullable
-  public DottedVersion getDefaultTvosSdkVersion() {
-    return defaultTvosSdkVersion;
-  }
-
-  @Nullable
-  public DottedVersion getDefaultMacosSdkVersion() {
-    return defaultMacosSdkVersion;
-  }
-
-  @Override
-  public boolean equals(Object other) {
-    if (other == null) {
-      return false;
-    }
-    if (!(other instanceof XcodeVersionProperties otherData)) {
-      return false;
-    }
-    return xcodeVersion.equals(otherData.getXcodeVersion())
-        && defaultIosSdkVersion.equals(otherData.getDefaultIosSdkVersion())
-        && defaultVisionosSdkVersion.equals(otherData.getDefaultVisionosSdkVersion())
-        && defaultWatchosSdkVersion.equals(otherData.getDefaultWatchosSdkVersion())
-        && defaultTvosSdkVersion.equals(otherData.getDefaultTvosSdkVersion())
-        && defaultMacosSdkVersion.equals(otherData.getDefaultMacosSdkVersion());
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(
-        xcodeVersion,
-        defaultIosSdkVersion,
-        defaultVisionosSdkVersion,
-        defaultWatchosSdkVersion,
-        defaultTvosSdkVersion,
-        defaultMacosSdkVersion);
-  }
-
-  /** Provider class for {@link XcodeVersionProperties} objects. */
-  public static class Provider extends BuiltinProvider<XcodeVersionProperties>
-      implements XcodePropertiesApi.Provider {
-    private Provider() {
-      super(XcodePropertiesApi.NAME, XcodeVersionProperties.class);
-    }
-
-    @Override
-    public XcodePropertiesApi createInfo(
-        Object starlarkVersion,
-        Object starlarkDefaultIosSdkVersion,
-        Object starlarkDefaultVisionosSdkVersion,
-        Object starlarkDefaultWatchosSdkVersion,
-        Object starlarkDefaultTvosSdkVersion,
-        Object starlarkDefaultMacosSdkVersion,
-        StarlarkThread thread)
-        throws EvalException {
-      return new XcodeVersionProperties(
-          Starlark.isNullOrNone(starlarkVersion)
-              ? null
-              : DottedVersion.fromStringUnchecked((String) starlarkVersion),
-          Starlark.isNullOrNone(starlarkDefaultIosSdkVersion)
-              ? null
-              : (String) starlarkDefaultIosSdkVersion,
-          Starlark.isNullOrNone(starlarkDefaultVisionosSdkVersion)
-              ? null
-              : (String) starlarkDefaultVisionosSdkVersion,
-          Starlark.isNullOrNone(starlarkDefaultWatchosSdkVersion)
-              ? null
-              : (String) starlarkDefaultWatchosSdkVersion,
-          Starlark.isNullOrNone(starlarkDefaultTvosSdkVersion)
-              ? null
-              : (String) starlarkDefaultTvosSdkVersion,
-          Starlark.isNullOrNone(starlarkDefaultMacosSdkVersion)
-              ? null
-              : (String) starlarkDefaultMacosSdkVersion);
-    }
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionProviderApi.java b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionProviderApi.java
deleted file mode 100644
index b2a4fcd2..0000000
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionProviderApi.java
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2024 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.devtools.build.docgen.annot.StarlarkConstructor;
-import com.google.devtools.build.lib.starlarkbuildapi.FileApi;
-import com.google.devtools.build.lib.starlarkbuildapi.core.ProviderApi;
-import net.starlark.java.annot.Param;
-import net.starlark.java.annot.ParamType;
-import net.starlark.java.annot.StarlarkMethod;
-import net.starlark.java.eval.EvalException;
-import net.starlark.java.eval.NoneType;
-import net.starlark.java.eval.Sequence;
-import net.starlark.java.eval.StarlarkThread;
-
-/** Provider structure for {@code XcodeVersionRuleData} */
-interface XcodeVersionProviderApi<FileT extends FileApi> extends ProviderApi {
-
-  @StarlarkMethod(
-      name = "XcodeVersionRuleData",
-      useStarlarkThread = true,
-      parameters = {
-        @Param(
-            name = "label",
-            positional = false,
-            named = true,
-            defaultValue = "None",
-            documented = false),
-        @Param(
-            name = "xcode_properties",
-            positional = false,
-            named = true,
-            defaultValue = "None",
-            documented = false),
-        @Param(
-            name = "aliases",
-            positional = false,
-            named = true,
-            defaultValue = "None",
-            allowedTypes = {@ParamType(type = NoneType.class), @ParamType(type = Sequence.class)},
-            documented = false),
-      },
-      selfCall = true,
-      documented = false)
-  @StarlarkConstructor
-  public XcodeVersionRuleData createInfo(
-      Object starlarkLabel,
-      Object starlarkXcodeProperties,
-      Object starlarkAliases,
-      StarlarkThread thread)
-      throws EvalException;
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionRuleData.java b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionRuleData.java
deleted file mode 100644
index 44babde..0000000
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersionRuleData.java
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2015 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.ImmutableList;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.BuiltinProvider;
-import com.google.devtools.build.lib.packages.NativeInfo;
-import java.util.List;
-import java.util.Objects;
-import javax.annotation.Nullable;
-import net.starlark.java.annot.StarlarkMethod;
-import net.starlark.java.eval.EvalException;
-import net.starlark.java.eval.Sequence;
-import net.starlark.java.eval.Starlark;
-import net.starlark.java.eval.StarlarkThread;
-
-/**
- * A tuple containing the information in a single target of the {@code xcode_version} rule. A single
- * target of this rule contains an official version label decided by Apple, a number of supported
- * aliases one might use to reference this version, and various properties of the Xcode version
- * (such as default SDK versions).
- *
- * <p>For example, one may want to reference official Xcode version 7.0.1 using the "7" or "7.0"
- * aliases. This official version of Xcode may have a default supported iOS SDK of 9.0.
- */
-@Immutable
-public class XcodeVersionRuleData extends NativeInfo {
-  private static final String NAME = "XcodeVersionRuleData";
-
-  private final Label label;
-  private final XcodeVersionProperties xcodeVersionProperties;
-  private final ImmutableList<String> aliases;
-  public static final Provider PROVIDER = new Provider();
-
-  XcodeVersionRuleData(
-      Label label, XcodeVersionProperties xcodeVersionProperties, List<String> aliases) {
-    this.label = label;
-    this.xcodeVersionProperties = xcodeVersionProperties;
-    this.aliases = ImmutableList.copyOf(aliases);
-  }
-
-  @Override
-  public Provider getProvider() {
-    return PROVIDER;
-  }
-
-  /** Returns the label of the owning target of this provider. */
-  @StarlarkMethod(name = "label", structField = true, documented = false)
-  public Label getLabel() {
-    return label;
-  }
-
-  /** Returns the official Xcode version the owning {@code xcode_version} target is referencing. */
-  @StarlarkMethod(name = "version", structField = true, documented = false)
-  public DottedVersion getVersion() {
-    return xcodeVersionProperties.getXcodeVersion().get();
-  }
-
-  /** Returns the properties of the {@code xcode_version} target's referenced Xcode version. */
-  @StarlarkMethod(name = "xcode_version_properties", structField = true, documented = false)
-  public XcodeVersionProperties getXcodeVersionProperties() {
-    return xcodeVersionProperties;
-  }
-
-  /** Returns the accepted string aliases for this Xcode version. */
-  @StarlarkMethod(name = "aliases", structField = true, documented = false)
-  public List<String> getAliases() {
-    return aliases;
-  }
-
-  @Override
-  public boolean equals(Object other) {
-    if (other == null) {
-      return false;
-    }
-    if (!(other instanceof XcodeVersionRuleData otherData)) {
-      return false;
-    }
-    return (getVersion().equals(otherData.getVersion())
-        && xcodeVersionProperties
-            .getXcodeVersion()
-            .equals(otherData.getXcodeVersionProperties().getXcodeVersion())
-        && xcodeVersionProperties
-            .getDefaultIosSdkVersion()
-            .equals(otherData.getXcodeVersionProperties().getDefaultIosSdkVersion())
-        && xcodeVersionProperties
-            .getDefaultVisionosSdkVersion()
-            .equals(otherData.getXcodeVersionProperties().getDefaultVisionosSdkVersion())
-        && xcodeVersionProperties
-            .getDefaultWatchosSdkVersion()
-            .equals(otherData.getXcodeVersionProperties().getDefaultWatchosSdkVersion())
-        && xcodeVersionProperties
-            .getDefaultTvosSdkVersion()
-            .equals(otherData.getXcodeVersionProperties().getDefaultTvosSdkVersion())
-        && xcodeVersionProperties
-            .getDefaultMacosSdkVersion()
-            .equals(otherData.getXcodeVersionProperties().getDefaultMacosSdkVersion()));
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(getVersion(), xcodeVersionProperties);
-  }
-
-  /** Provider class for {@link XcodeVersionRuleData} objects. */
-  public static class Provider extends BuiltinProvider<XcodeVersionRuleData>
-      implements XcodeVersionProviderApi<Artifact> {
-    private Provider() {
-      super(XcodeVersionRuleData.NAME, XcodeVersionRuleData.class);
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public XcodeVersionRuleData createInfo(
-        Object starlarkLabel,
-        Object starlarkXcodeProperties,
-        Object starlarkAliases,
-        StarlarkThread thread)
-        throws EvalException {
-      Sequence<String> aliases = nullIfNone(starlarkAliases, Sequence.class);
-      return new XcodeVersionRuleData(
-          nullIfNone(starlarkLabel, Label.class),
-          nullIfNone(starlarkXcodeProperties, XcodeVersionProperties.class),
-          Sequence.cast(aliases, String.class, "aliases"));
-    }
-
-    @Nullable
-    private static <T> T nullIfNone(Object object, Class<T> type) {
-      return object != Starlark.NONE ? type.cast(object) : null;
-    }
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/apple/XcodePropertiesApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/apple/XcodePropertiesApi.java
deleted file mode 100644
index de66586..0000000
--- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/apple/XcodePropertiesApi.java
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright 2018 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.starlarkbuildapi.apple;
-
-import com.google.devtools.build.docgen.annot.DocCategory;
-import com.google.devtools.build.docgen.annot.StarlarkConstructor;
-import com.google.devtools.build.lib.starlarkbuildapi.core.ProviderApi;
-import com.google.devtools.build.lib.starlarkbuildapi.core.StructApi;
-import javax.annotation.Nullable;
-import net.starlark.java.annot.Param;
-import net.starlark.java.annot.ParamType;
-import net.starlark.java.annot.StarlarkBuiltin;
-import net.starlark.java.annot.StarlarkMethod;
-import net.starlark.java.eval.EvalException;
-import net.starlark.java.eval.NoneType;
-import net.starlark.java.eval.StarlarkThread;
-
-/** A provider containing information about a version of Xcode and its properties. */
-@StarlarkBuiltin(
-    name = "XcodeProperties",
-    category = DocCategory.PROVIDER,
-    doc = "A provider containing information about a version of Xcode and its properties.")
-public interface XcodePropertiesApi extends StructApi {
-  String NAME = "XcodeProperties";
-
-  @StarlarkMethod(
-      name = "xcode_version",
-      doc = "The Xcode version, or <code>None</code> if the Xcode version is unknown.",
-      structField = true,
-      allowReturnNones = true)
-  @Nullable
-  String getXcodeVersionString();
-
-  @StarlarkMethod(
-      name = "default_ios_sdk_version",
-      doc =
-          "The default iOS SDK version for this version of Xcode, or <code>None</code> if "
-              + "unknown.",
-      structField = true,
-      allowReturnNones = true)
-  @Nullable
-  String getDefaultIosSdkVersionString();
-
-  @StarlarkMethod(
-      name = "default_visionos_sdk_version",
-      doc =
-          "The default visionOS SDK version for this version of Xcode, or <code>None</code> if "
-              + "unknown.",
-      structField = true,
-      allowReturnNones = true)
-  @Nullable
-  String getDefaultVisionosSdkVersionString();
-
-  @StarlarkMethod(
-      name = "default_watchos_sdk_version",
-      doc =
-          "The default watchOS SDK version for this version of Xcode, or <code>None</code> if "
-              + "unknown.",
-      structField = true,
-      allowReturnNones = true)
-  @Nullable
-  String getDefaultWatchosSdkVersionString();
-
-  @StarlarkMethod(
-      name = "default_tvos_sdk_version",
-      doc =
-          "The default tvOS SDK version for this version of Xcode, or <code>None</code> if "
-              + "unknown.",
-      structField = true,
-      allowReturnNones = true)
-  @Nullable
-  String getDefaultTvosSdkVersionString();
-
-  @StarlarkMethod(
-      name = "default_macos_sdk_version",
-      doc =
-          "The default macOS SDK version for this version of Xcode, or <code>None</code> if "
-              + "unknown.",
-      structField = true,
-      allowReturnNones = true)
-  @Nullable
-  String getDefaultMacosSdkVersionString();
-
-  /** The provider implementing this can construct XcodeProperties objects. */
-  @StarlarkBuiltin(name = "Provider", doc = "", documented = false)
-  interface Provider extends ProviderApi {
-
-    @StarlarkMethod(
-        name = NAME,
-        useStarlarkThread = true,
-        parameters = {
-          @Param(
-              name = "version",
-              doc = "",
-              positional = false,
-              allowedTypes = {
-                @ParamType(type = NoneType.class),
-                @ParamType(type = String.class),
-              },
-              named = true,
-              defaultValue = "None"),
-          @Param(
-              name = "default_ios_sdk_version",
-              doc = "",
-              positional = false,
-              allowedTypes = {
-                @ParamType(type = NoneType.class),
-                @ParamType(type = String.class),
-              },
-              named = true,
-              defaultValue = "None"),
-          @Param(
-              name = "default_visionos_sdk_version",
-              doc = "",
-              positional = false,
-              allowedTypes = {
-                @ParamType(type = NoneType.class),
-                @ParamType(type = String.class),
-              },
-              named = true,
-              defaultValue = "None"),
-          @Param(
-              name = "default_watchos_sdk_version",
-              doc = "",
-              positional = false,
-              allowedTypes = {
-                @ParamType(type = NoneType.class),
-                @ParamType(type = String.class),
-              },
-              named = true,
-              defaultValue = "None"),
-          @Param(
-              name = "default_tvos_sdk_version",
-              doc = "",
-              positional = false,
-              allowedTypes = {
-                @ParamType(type = NoneType.class),
-                @ParamType(type = String.class),
-              },
-              named = true,
-              defaultValue = "None"),
-          @Param(
-              name = "default_macos_sdk_version",
-              doc = "",
-              positional = false,
-              allowedTypes = {
-                @ParamType(type = NoneType.class),
-                @ParamType(type = String.class),
-              },
-              named = true,
-              defaultValue = "None"),
-        },
-        selfCall = true,
-        documented = false)
-    @StarlarkConstructor
-    XcodePropertiesApi createInfo(
-        Object version,
-        Object defaultIosSdkVersion,
-        Object defaultVisionosSdkVersion,
-        Object defaultWatchosSdkVersion,
-        Object defaultTvosSdkVersion,
-        Object defaultMacosSdkVersion,
-        StarlarkThread thread)
-        throws EvalException;
-  }
-}
diff --git a/src/main/starlark/builtins_bzl/common/objc/apple_common.bzl b/src/main/starlark/builtins_bzl/common/objc/apple_common.bzl
index 703d69e..dedbede 100644
--- a/src/main/starlark/builtins_bzl/common/objc/apple_common.bzl
+++ b/src/main/starlark/builtins_bzl/common/objc/apple_common.bzl
@@ -16,6 +16,7 @@
 
 load(":common/objc/apple_env.bzl", "apple_host_system_env", "target_apple_env")
 load(":common/objc/linking_support.bzl", "AppleDebugOutputsInfo", "linking_support")
+load(":common/xcode/providers.bzl", "XcodeVersionPropertiesInfo")
 
 native_apple_common = _builtins.internal.apple_common
 
@@ -23,7 +24,7 @@
     apple_toolchain = lambda: native_apple_common.apple_toolchain(),
     platform_type = native_apple_common.platform_type,
     platform = native_apple_common.platform,
-    XcodeProperties = _builtins.internal.XcodeProperties,
+    XcodeProperties = XcodeVersionPropertiesInfo,
     XcodeVersionConfig = _builtins.internal.XcodeConfigInfo,
     Objc = native_apple_common.Objc,
     AppleDynamicFramework = native_apple_common.AppleDynamicFramework,
diff --git a/src/main/starlark/builtins_bzl/common/xcode/available_xcodes.bzl b/src/main/starlark/builtins_bzl/common/xcode/available_xcodes.bzl
index 564af85..e5e38ac 100644
--- a/src/main/starlark/builtins_bzl/common/xcode/available_xcodes.bzl
+++ b/src/main/starlark/builtins_bzl/common/xcode/available_xcodes.bzl
@@ -14,17 +14,19 @@
 
 """Rule definition for the available_xcodes rule."""
 
+load(":common/xcode/providers.bzl", "AvailableXcodesInfo", "XcodeVersionRuleInfo")
+
 def _available_xcodes_impl(ctx):
     available_versions = [
-        target[_builtins.internal.XcodeVersionRuleData]
+        target[XcodeVersionRuleInfo]
         for target in ctx.attr.versions
     ]
-    default_version = ctx.attr.default[_builtins.internal.XcodeVersionRuleData]
+    default_version = ctx.attr.default[XcodeVersionRuleInfo]
 
     return [
-        _builtins.internal.AvailableXcodesInfo(
-            default = default_version,
-            versions = available_versions,
+        AvailableXcodesInfo(
+            available_versions = available_versions,
+            default_version = default_version,
         ),
     ]
 
@@ -33,12 +35,12 @@
         "default": attr.label(
             doc = "The default Xcode version for this platform.",
             mandatory = True,
-            providers = [[_builtins.internal.XcodeVersionRuleData]],
+            providers = [[XcodeVersionRuleInfo]],
             flags = ["NONCONFIGURABLE"],
         ),
         "versions": attr.label_list(
             doc = "The Xcode versions that are available on this platform.",
-            providers = [[_builtins.internal.XcodeVersionRuleData]],
+            providers = [[XcodeVersionRuleInfo]],
             flags = ["NONCONFIGURABLE"],
         ),
     },
@@ -48,4 +50,5 @@
 selection of an official Xcode version from the collectively available Xcodes.
         """,
     implementation = _available_xcodes_impl,
+    provides = [AvailableXcodesInfo],
 )
diff --git a/src/main/starlark/builtins_bzl/common/xcode/providers.bzl b/src/main/starlark/builtins_bzl/common/xcode/providers.bzl
new file mode 100644
index 0000000..b60fd9b
--- /dev/null
+++ b/src/main/starlark/builtins_bzl/common/xcode/providers.bzl
@@ -0,0 +1,104 @@
+# Copyright 2024 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.
+
+"""Definitions of providers used by the Xcode rules and their clients."""
+
+AvailableXcodesInfo = provider(
+    doc = """\
+The available Xcode versions computed from the `available_xcodes` rule.
+""",
+    fields = {
+        "available_versions": """\
+The available Xcode versions from `available_xcodes`.
+""",
+        "default_version": """\
+The default Xcode version from `available_xcodes`.
+""",
+    },
+)
+
+def _xcode_version_properties_info_init(
+        xcode_version,
+        default_ios_sdk_version = "8.4",
+        default_macos_sdk_version = "9.0",
+        default_tvos_sdk_version = "10.11",
+        default_watchos_sdk_version = "2.0",
+        default_visionos_sdk_version = "1.0"):
+    # Ensure that all fields get default values if they weren't specified.
+    return {
+        "xcode_version": xcode_version,
+        "default_ios_sdk_version": default_ios_sdk_version,
+        "default_macos_sdk_version": default_macos_sdk_version,
+        "default_tvos_sdk_version": default_tvos_sdk_version,
+        "default_watchos_sdk_version": default_watchos_sdk_version,
+        "default_visionos_sdk_version": default_visionos_sdk_version,
+    }
+
+XcodeVersionPropertiesInfo, _new_xcode_version_properties_info = provider(
+    doc = """\
+Information about a specific Xcode version, such as its default SDK versions.
+""",
+    fields = {
+        "xcode_version": """\
+A string representing the Xcode version number, or `None` if it is unknown.
+""",
+        "default_ios_sdk_version": """\
+A string representing the default iOS SDK version number for this version of
+Xcode, or `None` if it is unknown.
+""",
+        "default_macos_sdk_version": """\
+A string representing the default macOS SDK version number for this version of
+Xcode, or `None` if it is unknown.
+""",
+        "default_tvos_sdk_version": """\
+A string representing the default tvOS SDK version number for this version of
+Xcode, or `None` if it is unknown.
+""",
+        "default_watchos_sdk_version": """\
+A string representing the default watchOS SDK version number for this version of
+Xcode, or `None` if it is unknown.
+""",
+        "default_visionos_sdk_version": """\
+A string representing the default visionOS SDK version number for this version
+of Xcode, or `None` if it is unknown.
+""",
+    },
+    init = _xcode_version_properties_info_init,
+)
+
+XcodeVersionRuleInfo = provider(
+    doc = """\
+The information in a single target of the `xcode_version` rule. A single target
+of this rule contains an official version label decided by Apple, a number of
+supported aliases one might use to reference this version, and various
+properties of the Xcode version (such as default SDK versions).
+
+For example, one may want to reference official Xcode version 7.0.1 using the
+"7" or "7.0" aliases. This official version of Xcode may have a default
+supported iOS SDK of 9.0.
+""",
+    fields = {
+        "aliases": """\
+A list of strings denoting aliases that can be used to reference this Xcode
+version.
+""",
+        "label": """\
+The build `Label` of the `xcode_version` target that propagated this provider.
+""",
+        "xcode_version_properties": """\
+An `XcodeVersionPropertiesInfo` provider that contains the details about this
+Xcode version, such as its default SDK versions.
+""",
+    },
+)
diff --git a/src/main/starlark/builtins_bzl/common/xcode/xcode_config.bzl b/src/main/starlark/builtins_bzl/common/xcode/xcode_config.bzl
index 97facf38..3619db7 100644
--- a/src/main/starlark/builtins_bzl/common/xcode/xcode_config.bzl
+++ b/src/main/starlark/builtins_bzl/common/xcode/xcode_config.bzl
@@ -14,28 +14,28 @@
 
 """Rule definition for the xcode_config rule."""
 
-load(":common/objc/apple_common.bzl", "apple_common")
+load(":common/xcode/providers.bzl", "AvailableXcodesInfo", "XcodeVersionPropertiesInfo", "XcodeVersionRuleInfo")
 load(":common/xcode/semantics.bzl", "unavailable_xcode_message")
 
 def _xcode_config_impl(ctx):
     apple_fragment = ctx.fragments.apple
     cpp_fragment = ctx.fragments.cpp
 
-    explicit_default_version = ctx.attr.default[_builtins.internal.XcodeVersionRuleData] if ctx.attr.default else None
+    explicit_default_version = ctx.attr.default[XcodeVersionRuleInfo] if ctx.attr.default else None
     explicit_versions = [
-        target[_builtins.internal.XcodeVersionRuleData]
+        target[XcodeVersionRuleInfo]
         for target in ctx.attr.versions
     ] if ctx.attr.versions else []
     remote_versions = [
         target
-        for target in ctx.attr.remote_versions[_builtins.internal.AvailableXcodesInfo].available_versions
+        for target in ctx.attr.remote_versions[AvailableXcodesInfo].available_versions
     ] if ctx.attr.remote_versions else []
     local_versions = [
         target
-        for target in ctx.attr.local_versions[_builtins.internal.AvailableXcodesInfo].available_versions
+        for target in ctx.attr.local_versions[AvailableXcodesInfo].available_versions
     ] if ctx.attr.local_versions else []
 
-    local_default_version = ctx.attr.local_versions[_builtins.internal.AvailableXcodesInfo].default_version if ctx.attr.local_versions else None
+    local_default_version = ctx.attr.local_versions[AvailableXcodesInfo].default_version if ctx.attr.local_versions else None
     xcode_version_properties = None
     availability = "unknown"
 
@@ -108,7 +108,7 @@
 `local_versions` is set.
 """,
             flags = ["NONCONFIGURABLE"],
-            providers = [[_builtins.internal.XcodeVersionRuleData]],
+            providers = [[XcodeVersionRuleInfo]],
         ),
         "versions": attr.label_list(
             doc = """\
@@ -119,7 +119,7 @@
 `local_versions` is set.
 """,
             flags = ["NONCONFIGURABLE"],
-            providers = [[_builtins.internal.XcodeVersionRuleData]],
+            providers = [[XcodeVersionRuleInfo]],
         ),
         "remote_versions": attr.label(
             doc = """\
@@ -128,7 +128,7 @@
 version. This may not be set if `versions` is set.
 """,
             flags = ["NONCONFIGURABLE"],
-            providers = [[_builtins.internal.AvailableXcodesInfo]],
+            providers = [[AvailableXcodesInfo]],
         ),
         "local_versions": attr.label(
             doc = """\
@@ -137,7 +137,7 @@
 version. This may not be set if `versions` is set.
 """,
             flags = ["NONCONFIGURABLE"],
-            providers = [[_builtins.internal.AvailableXcodesInfo]],
+            providers = [[AvailableXcodesInfo]],
         ),
     },
     doc = """\
@@ -164,7 +164,7 @@
 def _duplicate_alias_error(alias, versions):
     labels_containing_alias = []
     for version in versions:
-        if alias in version.aliases or (str(version.version) == alias):
+        if alias in version.aliases or (version.xcode_version_properties.xcode_version == alias):
             labels_containing_alias.append(str(version.label))
     return "'{}' is registered to multiple labels ({}) in a single xcode_config rule".format(
         alias,
@@ -181,11 +181,12 @@
                 fail(_duplicate_alias_error(alias, versions))
             else:
                 version_map[alias] = version
-        if str(version.version) not in version.aliases:  # only add the version if it's not also an alias
-            if str(version.version) in version_map:
-                fail(_duplicate_alias_error(str(version.version), versions))
+        version_string = version.xcode_version_properties.xcode_version
+        if version_string not in version.aliases:  # only add the version if it's not also an alias
+            if version_string in version_map:
+                fail(_duplicate_alias_error(version_string, versions))
             else:
-                version_map[str(version.version)] = version
+                version_map[version_string] = version
     return version_map
 
 def _resolve_xcode_from_local_and_remote(
@@ -205,8 +206,9 @@
     # We don't make this assumption for remote xcode_versions.
     mutually_available_versions = {}
     for version in local_versions:
-        if str(version.version) in remote_alias_to_version_map:
-            mutually_available_versions[str(version.version)] = remote_alias_to_version_map[str(version.version)]
+        version_string = version.xcode_version_properties.xcode_version
+        if version_string in remote_alias_to_version_map:
+            mutually_available_versions[version_string] = remote_alias_to_version_map[version_string]
 
     # We'd log an event here if we could!!
     if xcode_version_flag:
@@ -215,7 +217,7 @@
         availability = "BOTH"
 
         if remote_version_from_flag and local_version_from_flag:
-            local_version_from_remote_versions = remote_alias_to_version_map.get(str(local_version_from_flag.version))
+            local_version_from_remote_versions = remote_alias_to_version_map.get(local_version_from_flag.xcode_version_properties.xcode_version)
             if local_version_from_remote_versions:
                 return remote_version_from_flag.xcode_version_properties, availability
             else:
@@ -229,8 +231,8 @@
                      " to continue using dynamic execution. If you really did intend to use" +
                      " local version {1}, please specify it fully with --xcode_version={1}.").format(
                         xcode_version_flag,
-                        local_version_from_flag.version,
-                        remote_version_from_flag.version,
+                        local_version_from_flag.xcode_version_properties.xcode_version,
+                        remote_version_from_flag.xcode_version_properties.xcode_version,
                         remote_version_from_flag.aliases,
                     ),
                 )
@@ -271,8 +273,8 @@
                  " re-run your command.").format(
                     xcode_version_flag,
                     unavailable_xcode_message,
-                    ", ".join([str(version.version) for version in local_versions]),
-                    ", ".join([str(version.version) for version in remote_versions]),
+                    ", ".join([version.xcode_version_properties.xcode_version for version in local_versions]),
+                    ", ".join([version.xcode_version_properties.xcode_version for version in remote_versions]),
                 ),
             )
 
@@ -286,20 +288,20 @@
             ("Using a local Xcode version, '{}', since there are no" +
              " remotely available Xcodes on this machine. Consider downloading one of the" +
              " remotely available Xcode versions ({}) in order to get the best build" +
-             " performance.").format(local_default_version.version, ", ".join([str(version.version) for version in remote_versions])),
+             " performance.").format(local_default_version.xcode_version_properties.xcode_version, ", ".join([version.xcode_version_properties.xcode_version for version in remote_versions])),
         )
         local_version = local_default_version
         availability = "LOCAL"
-    elif (str(local_default_version.version) in remote_alias_to_version_map):
+    elif (local_default_version.xcode_version_properties.xcode_version in remote_alias_to_version_map):
         #  If the local default version is also available remotely, use it.
         availability = "BOTH"
-        local_version = remote_alias_to_version_map.get(str(local_default_version.version))
+        local_version = remote_alias_to_version_map.get(local_default_version.xcode_version_properties.xcode_version)
     else:
         # If an alias of the local default version is available remotely, use it.
         for version_number in local_default_version.aliases:
             if version_number in remote_alias_to_version_map:
                 availability = "BOTH"
-                local_version = remote_alias_to_version_map.get(str(version_number))
+                local_version = remote_alias_to_version_map.get(version_number)
                 break
 
     if local_version:
@@ -308,18 +310,21 @@
     # The local default is not available remotely.
     if prefer_mutual_xcode:
         # If we prefer a mutually available version, the newest one.
-        newest_version = _builtins.internal.apple_common.dotted_version("0.0")
+        newest_version = "0.0"
         default_version = None
         for _, version in mutually_available_versions.items():
-            if version.version.compare_to(newest_version) > 0:
+            if _compare_version_strings(version.xcode_version_properties.xcode_version, newest_version) > 0:
                 default_version = version
-                newest_version = default_version.version
+                newest_version = default_version.xcode_version_properties.xcode_version
 
         return default_version.xcode_version_properties, "BOTH"
     else:
         # Use the local default
         return local_default_version.xcode_version_properties, "LOCAL"
 
+def _compare_version_strings(first, second):
+    return _builtins.internal.apple_common.dotted_version(first).compare_to(_builtins.internal.apple_common.dotted_version(second))
+
 def _resolve_explicitly_defined_version(
         explicit_versions,
         explicit_default_version,
@@ -334,7 +339,7 @@
     if not explicit_versions:
         if explicit_default_version:
             fail("default label must be contained in versions attribute")
-        return apple_common.XcodeProperties(version = None)
+        return XcodeVersionPropertiesInfo(xcode_version = None)
 
     if not explicit_default_version:
         fail("if any versions are specified, a default version must be specified")
@@ -350,7 +355,7 @@
                  "If you believe you have '{0}' installed, try running \"bazel shutdown\", and then " +
                  "re-run your command.").format(xcode_version_flag),
             )
-    return alias_to_versions.get(str(explicit_default_version.version)).xcode_version_properties
+    return alias_to_versions.get(explicit_default_version.xcode_version_properties.xcode_version).xcode_version_properties
 
 def _dotted_version_or_default(field, default):
     return _builtins.internal.apple_common.dotted_version(field) or default
diff --git a/src/main/starlark/builtins_bzl/common/xcode/xcode_config_alias.bzl b/src/main/starlark/builtins_bzl/common/xcode/xcode_config_alias.bzl
index 4d21a0d..ae7ecd2 100644
--- a/src/main/starlark/builtins_bzl/common/xcode/xcode_config_alias.bzl
+++ b/src/main/starlark/builtins_bzl/common/xcode/xcode_config_alias.bzl
@@ -24,11 +24,12 @@
 """
 
 load(":common/objc/apple_common.bzl", "apple_common")
+load(":common/xcode/providers.bzl", "XcodeVersionPropertiesInfo")
 
 def _xcode_config_alias_impl(ctx):
     xcode_config = ctx.attr._xcode_config
     return [
-        xcode_config[apple_common.XcodeProperties],
+        xcode_config[XcodeVersionPropertiesInfo],
         xcode_config[apple_common.XcodeVersionConfig],
     ]
 
diff --git a/src/main/starlark/builtins_bzl/common/xcode/xcode_version.bzl b/src/main/starlark/builtins_bzl/common/xcode/xcode_version.bzl
index f963645..be51fcb 100644
--- a/src/main/starlark/builtins_bzl/common/xcode/xcode_version.bzl
+++ b/src/main/starlark/builtins_bzl/common/xcode/xcode_version.bzl
@@ -14,11 +14,11 @@
 
 """Rule definition for the xcode_version rule."""
 
-load(":common/objc/apple_common.bzl", "apple_common")
+load(":common/xcode/providers.bzl", "XcodeVersionPropertiesInfo", "XcodeVersionRuleInfo")
 
 def _xcode_version_impl(ctx):
-    xcode_version_properties = apple_common.XcodeProperties(
-        version = ctx.attr.version,
+    xcode_version_properties = XcodeVersionPropertiesInfo(
+        xcode_version = ctx.attr.version,
         default_ios_sdk_version = ctx.attr.default_ios_sdk_version,
         default_visionos_sdk_version = ctx.attr.default_visionos_sdk_version,
         default_watchos_sdk_version = ctx.attr.default_watchos_sdk_version,
@@ -27,9 +27,9 @@
     )
     return [
         xcode_version_properties,
-        _builtins.internal.XcodeVersionRuleData(
+        XcodeVersionRuleInfo(
             label = ctx.label,
-            xcode_properties = xcode_version_properties,
+            xcode_version_properties = xcode_version_properties,
             aliases = ctx.attr.aliases,
         ),
         DefaultInfo(runfiles = ctx.runfiles()),
diff --git a/src/test/java/com/google/devtools/build/lib/rules/apple/AvailableXcodesTest.java b/src/test/java/com/google/devtools/build/lib/rules/apple/AvailableXcodesTest.java
index eba4ee9..5d69547 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/apple/AvailableXcodesTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/apple/AvailableXcodesTest.java
@@ -16,9 +16,13 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.packages.Provider;
+import com.google.devtools.build.lib.packages.StarlarkProvider;
+import com.google.devtools.build.lib.packages.StructImpl;
+import net.starlark.java.eval.Sequence;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -26,6 +30,16 @@
 /** Unit tests for the {@code available_xcodes} rule. */
 @RunWith(JUnit4.class)
 public final class AvailableXcodesTest extends BuildViewTestCase {
+  private static final Provider.Key AVAILABLE_XCODES_PROVIDER_KEY =
+      new StarlarkProvider.Key(
+          Label.parseCanonicalUnchecked("@_builtins//:common/xcode/providers.bzl"),
+          "AvailableXcodesInfo");
+
+  private static final Provider.Key XCODE_VERSION_PROPERTIES_PROVIDER_KEY =
+      new StarlarkProvider.Key(
+          Label.parseCanonicalUnchecked("@_builtins//:common/xcode/providers.bzl"),
+          "XcodeVersionPropertiesInfo");
+
   @Test
   public void testXcodeVersionCanBeReadFromNative() throws Exception {
     scratch.file(
@@ -62,23 +76,25 @@
         """);
 
     ConfiguredTarget nativeTarget = getConfiguredTarget("//examples/apple:my_xcodes");
-    AvailableXcodesInfo availableXcodesInfo = nativeTarget.get(AvailableXcodesInfo.PROVIDER);
+    StructImpl availableXcodesInfo = (StructImpl) nativeTarget.get(AVAILABLE_XCODES_PROVIDER_KEY);
     ConfiguredTarget version8 = getConfiguredTarget("//examples/apple:xcode_8");
-    XcodeVersionProperties version8properties = version8.get(XcodeVersionProperties.PROVIDER);
+    StructImpl version8properties =
+        (StructImpl) version8.get(XCODE_VERSION_PROPERTIES_PROVIDER_KEY);
     ConfiguredTarget version9 = getConfiguredTarget("//examples/apple:xcode_9");
-    XcodeVersionProperties version9properties = version9.get(XcodeVersionProperties.PROVIDER);
-    assertThat(availableXcodesInfo.getAvailableVersions()).hasSize(2);
-    assertThat(
-            Iterables.get(availableXcodesInfo.getAvailableVersions(), 0)
-                .getXcodeVersionProperties())
+    StructImpl version9properties =
+        (StructImpl) version9.get(XCODE_VERSION_PROPERTIES_PROVIDER_KEY);
+    Sequence<StructImpl> availableVersions =
+        Sequence.cast(
+            availableXcodesInfo.getValue("available_versions"),
+            StructImpl.class,
+            "available_versions");
+    assertThat(availableVersions).hasSize(2);
+    assertThat(availableVersions.get(0).getValue("xcode_version_properties"))
         .isEqualTo(version8properties);
-    assertThat(
-            Iterables.get(availableXcodesInfo.getAvailableVersions(), 1)
-                .getXcodeVersionProperties())
+    assertThat(availableVersions.get(1).getValue("xcode_version_properties"))
         .isEqualTo(version9properties);
-    assertThat(availableXcodesInfo.getDefaultVersion().getVersion().toString()).isEqualTo("8");
-    assertThat(availableXcodesInfo.getDefaultVersion().getXcodeVersionProperties())
-        .isEqualTo(version8properties);
+    StructImpl defaultVersion = availableXcodesInfo.getValue("default_version", StructImpl.class);
+    assertThat(defaultVersion.getValue("xcode_version_properties")).isEqualTo(version8properties);
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/rules/apple/XcodeVersionTest.java b/src/test/java/com/google/devtools/build/lib/rules/apple/XcodeVersionTest.java
index 4cdbbaa..3602e40 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/apple/XcodeVersionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/apple/XcodeVersionTest.java
@@ -32,6 +32,10 @@
  */
 @RunWith(JUnit4.class)
 public final class XcodeVersionTest extends BuildViewTestCase {
+  private static final Provider.Key XCODE_VERSION_PROPERTIES_PROVIDER_KEY =
+      new StarlarkProvider.Key(
+          Label.parseCanonicalUnchecked("@_builtins//:common/xcode/providers.bzl"),
+          "XcodeVersionPropertiesInfo");
 
   @Test
   public void testXcodeVersionCanBeReadFromStarlark() throws Exception {
@@ -115,11 +119,12 @@
         """);
 
     ConfiguredTarget nativeTarget = getConfiguredTarget("//examples/apple:my_xcode");
-    XcodeVersionProperties xcodeProperties = nativeTarget.get(XcodeVersionProperties.PROVIDER);
-    assertThat(xcodeProperties.getXcodeVersion().get().toString()).isEqualTo("8");
-    assertThat(xcodeProperties.getDefaultIosSdkVersion().toString()).isEqualTo("9.0");
-    assertThat(xcodeProperties.getDefaultWatchosSdkVersion().toString()).isEqualTo("9.1");
-    assertThat(xcodeProperties.getDefaultTvosSdkVersion().toString()).isEqualTo("9.2");
-    assertThat(xcodeProperties.getDefaultMacosSdkVersion().toString()).isEqualTo("9.3");
+    StructImpl xcodeProperties =
+        (StructImpl) nativeTarget.get(XCODE_VERSION_PROPERTIES_PROVIDER_KEY);
+    assertThat(xcodeProperties.getValue("xcode_version")).isEqualTo("8");
+    assertThat(xcodeProperties.getValue("default_ios_sdk_version")).isEqualTo("9.0");
+    assertThat(xcodeProperties.getValue("default_watchos_sdk_version")).isEqualTo("9.1");
+    assertThat(xcodeProperties.getValue("default_tvos_sdk_version")).isEqualTo("9.2");
+    assertThat(xcodeProperties.getValue("default_macos_sdk_version")).isEqualTo("9.3");
   }
 }