Simplify Dependency and make it use AutoValue.

Part of work on toolchain transitions, #10523.

Closes #11460.

PiperOrigin-RevId: 312676534
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
index 0fa4dad..b5e6167 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
@@ -704,6 +704,7 @@
         ":config/transitions/configuration_transition",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/packages",
+        "//third_party:auto_value",
         "//third_party:guava",
         "//third_party:jsr305",
     ],
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/Dependency.java b/src/main/java/com/google/devtools/build/lib/analysis/Dependency.java
index f2a7e56..abfa5ed 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/Dependency.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/Dependency.java
@@ -13,19 +13,13 @@
 // limitations under the License.
 package com.google.devtools.build.lib.analysis;
 
+import com.google.auto.value.AutoValue;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.AspectDescriptor;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
 import javax.annotation.Nullable;
 
 /**
@@ -42,23 +36,16 @@
  * yet). No error or warning is reported in this case, because it is expected that rules sometimes
  * over-approximate the providers they supply in their definitions.
  */
+@AutoValue
 public abstract class Dependency {
   /** Builder to assist in creating dependency instances. */
-  public static class Builder {
-    private Label label;
-    private BuildConfiguration configuration;
-    private AspectCollection aspects = AspectCollection.EMPTY;
-    private List<String> transitionKeys = new ArrayList<>();
+  @AutoValue.Builder
+  public abstract static class Builder {
+    /** Sets the label of the target this dependency points to. */
+    public abstract Builder setLabel(Label label);
 
-    public Builder setLabel(Label label) {
-      this.label = Preconditions.checkNotNull(label);
-      return this;
-    }
-
-    public Builder setConfiguration(BuildConfiguration configuration) {
-      this.configuration = configuration;
-      return this;
-    }
+    /** Sets the configuration intended for this dependency. */
+    public abstract Builder setConfiguration(BuildConfiguration configuration);
 
     /** Explicitly set the configuration for this dependency to null. */
     public Builder withNullConfiguration() {
@@ -66,65 +53,42 @@
     }
 
     /** Add aspects to this Dependency. The same configuration is applied to all aspects. */
-    public Builder setAspects(AspectCollection aspects) {
-      this.aspects = aspects;
-      return this;
+    public abstract Builder setAspects(AspectCollection aspects);
+
+    /** Sets the keys of a configuration transition. */
+    public Builder setTransitionKey(String key) {
+      return setTransitionKeys(ImmutableList.of(key));
     }
 
-    public Builder addTransitionKey(String key) {
-      this.transitionKeys.add(key);
-      return this;
-    }
+    /** Sets the keys of a configuration transition. */
+    public abstract Builder setTransitionKeys(ImmutableList<String> keys);
 
-    public Builder addTransitionKeys(Collection<String> keys) {
-      this.transitionKeys = new ArrayList<>(keys);
-      return this;
-    }
+    // Not public.
+    abstract Dependency autoBuild();
 
     /** Returns the full Dependency instance. */
     public Dependency build() {
-      if (configuration == null) {
-        Preconditions.checkState(aspects.equals(AspectCollection.EMPTY));
-        return new NullConfigurationDependency(label, ImmutableList.copyOf(transitionKeys));
+      Dependency dependency = autoBuild();
+      if (dependency.getConfiguration() == null) {
+        Preconditions.checkState(
+            dependency.getAspects().equals(AspectCollection.EMPTY),
+            "Dependency with null Configuration cannot have aspects");
       }
-
-      // Use the target configuration for all aspects with none of their own.
-      Map<AspectDescriptor, BuildConfiguration> aspectConfigurations = new HashMap<>();
-      for (AspectDescriptor aspect : aspects.getAllAspects()) {
-        aspectConfigurations.put(aspect, configuration);
-      }
-      return new ExplicitConfigurationDependency(
-          label,
-          configuration,
-          aspects,
-          ImmutableMap.copyOf(aspectConfigurations),
-          ImmutableList.copyOf(transitionKeys));
+      return dependency;
     }
   }
 
   /** Returns a new {@link Builder} to create {@link Dependency} instances. */
   public static Builder builder() {
-    return new Builder();
-  }
-
-  protected final Label label;
-
-  /**
-   * Only the implementations below should extend this class. Use the factory methods above to
-   * create new Dependencies.
-   */
-  private Dependency(Label label) {
-    this.label = Preconditions.checkNotNull(label);
+    return new AutoValue_Dependency.Builder()
+        .setAspects(AspectCollection.EMPTY)
+        .setTransitionKeys(ImmutableList.of());
   }
 
   /** Returns the label of the target this dependency points to. */
-  public Label getLabel() {
-    return label;
-  }
+  public abstract Label getLabel();
 
-  /**
-   * Returns the explicit configuration intended for this dependency.
-   */
+  /** Returns the explicit configuration intended for this dependency. */
   @Nullable
   public abstract BuildConfiguration getConfiguration();
 
@@ -137,136 +101,19 @@
   public abstract AspectCollection getAspects();
 
   /** Returns the configuration an aspect should be evaluated with. */
-  public abstract BuildConfiguration getAspectConfiguration(AspectDescriptor aspect);
+  @Nullable
+  public BuildConfiguration getAspectConfiguration(AspectDescriptor aspect) {
+    return getConfiguration();
+  }
 
   /**
-   * Returns the keys of a configuration transition, if exist, associated with this dependency. See
-   * {@link ConfigurationTransition#apply} for more details. Normally, this returns an empty list,
-   * when there was no configuration transition in effect, or one with a single entry, when there
-   * was a specific configuration transition result that led to this. It may also return a list with
-   * multiple entries if the dependency has a null configuration, yet the outgoing edge has a split
-   * transition. In such cases all transition keys returned by the transition are tagged to the
-   * dependency.
+   * Returns the keys of a configuration transition, if any exist, associated with this dependency.
+   * See {@link ConfigurationTransition#apply} for more details. Normally, this returns an empty
+   * list, when there was no configuration transition in effect, or one with a single entry, when
+   * there was a specific configuration transition result that led to this. It may also return a
+   * list with multiple entries if the dependency has a null configuration, yet the outgoing edge
+   * has a split transition. In such cases all transition keys returned by the transition are tagged
+   * to the dependency.
    */
   public abstract ImmutableList<String> getTransitionKeys();
-
-  /**
-   * Implementation of a dependency with no configuration, suitable for, e.g., source files or
-   * visibility.
-   */
-  private static final class NullConfigurationDependency extends Dependency {
-    private final ImmutableList<String> transitionKeys;
-
-    public NullConfigurationDependency(Label label, ImmutableList<String> transitionKeys) {
-      super(label);
-      this.transitionKeys = Preconditions.checkNotNull(transitionKeys);
-    }
-
-    @Nullable
-    @Override
-    public BuildConfiguration getConfiguration() {
-      return null;
-    }
-
-    @Override
-    public AspectCollection getAspects() {
-      return AspectCollection.EMPTY;
-    }
-
-    @Override
-    public BuildConfiguration getAspectConfiguration(AspectDescriptor aspect) {
-      return null;
-    }
-
-    @Override
-    public ImmutableList<String> getTransitionKeys() {
-      return transitionKeys;
-    }
-
-    @Override
-    public int hashCode() {
-      return label.hashCode();
-    }
-
-    @Override
-    public boolean equals(Object other) {
-      if (!(other instanceof NullConfigurationDependency)) {
-        return false;
-      }
-      NullConfigurationDependency otherDep = (NullConfigurationDependency) other;
-      return label.equals(otherDep.label);
-    }
-
-    @Override
-    public String toString() {
-      return String.format("NullConfigurationDependency{label=%s}", label);
-    }
-  }
-
-  /**
-   * Implementation of a dependency with an explicitly set configuration.
-   */
-  private static final class ExplicitConfigurationDependency extends Dependency {
-    private final BuildConfiguration configuration;
-    private final AspectCollection aspects;
-    private final ImmutableMap<AspectDescriptor, BuildConfiguration> aspectConfigurations;
-    private final ImmutableList<String> transitionKeys;
-
-    public ExplicitConfigurationDependency(
-        Label label,
-        BuildConfiguration configuration,
-        AspectCollection aspects,
-        ImmutableMap<AspectDescriptor, BuildConfiguration> aspectConfigurations,
-        ImmutableList<String> transitionKeys) {
-      super(label);
-      this.configuration = Preconditions.checkNotNull(configuration);
-      this.aspects = Preconditions.checkNotNull(aspects);
-      this.aspectConfigurations = Preconditions.checkNotNull(aspectConfigurations);
-      this.transitionKeys = Preconditions.checkNotNull(transitionKeys);
-    }
-
-    @Override
-    public BuildConfiguration getConfiguration() {
-      return configuration;
-    }
-
-    @Override
-    public AspectCollection getAspects() {
-      return aspects;
-    }
-
-    @Override
-    public BuildConfiguration getAspectConfiguration(AspectDescriptor aspect) {
-      return aspectConfigurations.get(aspect);
-    }
-
-    @Override
-    public ImmutableList<String> getTransitionKeys() {
-      return transitionKeys;
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(label, configuration, aspectConfigurations, transitionKeys);
-    }
-
-    @Override
-    public boolean equals(Object other) {
-      if (!(other instanceof ExplicitConfigurationDependency)) {
-        return false;
-      }
-      ExplicitConfigurationDependency otherDep = (ExplicitConfigurationDependency) other;
-      return label.equals(otherDep.label)
-          && configuration.equals(otherDep.configuration)
-          && aspects.equals(otherDep.aspects)
-          && aspectConfigurations.equals(otherDep.aspectConfigurations);
-    }
-
-    @Override
-    public String toString() {
-      return String.format(
-          "%s{label=%s, configuration=%s, aspectConfigurations=%s}",
-          getClass().getSimpleName(), label, configuration, aspectConfigurations);
-    }
-  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
index 8fa0701..f0b8405 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
@@ -218,7 +218,7 @@
                   Dependency.builder()
                       .setLabel(dep.getLabel())
                       .withNullConfiguration()
-                      .addTransitionKeys(ImmutableList.copyOf(toOptions.keySet()))
+                      .setTransitionKeys(ImmutableList.copyOf(toOptions.keySet()))
                       .build();
             }
           }
@@ -338,6 +338,9 @@
                 .setLabel(dep.getLabel())
                 .setConfiguration(ctgValue.getConfiguration())
                 .setAspects(dep.getAspects())
+                // Explicitly do not set the transition key, since there is only one configuration
+                // and it matches the current one. This ignores the transition key set if this
+                // was a split transition.
                 .build());
         continue;
       }
@@ -429,7 +432,7 @@
                   .setLabel(originalDep.getLabel())
                   .setConfiguration(trimmedConfig)
                   .setAspects(originalDep.getAspects())
-                  .addTransitionKey(info.second)
+                  .setTransitionKey(info.second)
                   .build();
           Attribute attribute = attr.dependencyKind.getAttribute();
           if (attribute != null && attribute.getTransitionFactory().isSplit()) {