Add an "alias" rule.

This will be used to replace RedirectChaser so that we don't need to load packages during configuration creation anymore.

--
MOS_MIGRATED_REVID=121935989
diff --git a/src/main/java/com/google/devtools/build/lib/rules/Alias.java b/src/main/java/com/google/devtools/build/lib/rules/Alias.java
new file mode 100644
index 0000000..540bcc9
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/Alias.java
@@ -0,0 +1,120 @@
+// 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;
+
+import static com.google.devtools.build.lib.packages.Attribute.ANY_RULE;
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.LicensesProvider;
+import com.google.devtools.build.lib.analysis.LicensesProviderImpl;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
+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.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.util.FileTypeSet;
+
+/**
+ * Implementation of the <code>alias</code> rule.
+ */
+public class Alias implements RuleConfiguredTargetFactory {
+  @Override
+  public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException {
+    ConfiguredTarget actual = (ConfiguredTarget) ruleContext.getPrerequisite("actual", Mode.TARGET);
+    return new AliasConfiguredTarget(
+        actual,
+        ImmutableMap.of(
+            AliasProvider.class, AliasProvider.fromAliasRule(ruleContext.getLabel(), actual),
+            VisibilityProvider.class, new VisibilityProviderImpl(ruleContext.getVisibility()),
+            LicensesProvider.class, LicensesProviderImpl.of(ruleContext)));
+  }
+
+  /**
+   * Rule definition.
+   */
+  public static class AliasRule implements RuleDefinition {
+    @Override
+    public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+      return builder
+          /*<!-- #BLAZE_RULE(alias).ATTRIBUTE(actual) -->
+          The target this alias refers to. It does not need to be a rule, it can also be an input
+          file.
+          <!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
+          .add(attr("actual", LABEL)
+              .allowedFileTypes(FileTypeSet.ANY_FILE)
+              .allowedRuleClasses(ANY_RULE)
+              .mandatory())
+          .build();
+    }
+
+    @Override
+    public Metadata getMetadata() {
+      return Metadata.builder()
+          .name("alias")
+          .factoryClass(Alias.class)
+          .ancestors(BaseRuleClasses.BaseRule.class)
+          .build();
+    }
+  }
+}
+
+/*<!-- #BLAZE_RULE (NAME = alias, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
+
+<p>
+  The <code>alias</code> rule creates another name a rule can be referred to as.
+</p>
+
+<p>
+  Aliasing only works for "regular" targets. In particular, <code>package_group</code>,
+    <code>config_setting</code> and <code>test_suite</code> rules cannot be aliased.
+</p>
+
+<p>
+  The alias rule has its own visibility and license declaration. In all other respects, it behaves
+  like the rule it references with some minor exceptions:
+
+  <ul>
+    <li>
+      Tests are not run if their alias is mentioned on the command line
+    </li>
+    <li>
+      When defining environment groups, the aliases to <code>environment</code> rules are not
+      supported. They are not supported in the <code>--target_environment</code> command line
+      option, either.
+    </li>
+  </ul>
+</p>
+
+<h4 id="alias_example">Examples</h4>
+
+<pre class="code">
+filegroup(
+    name = "data",
+    srcs = ["data.txt"],
+)
+
+alias(
+    name = 'other',
+    actual = ':data',
+)
+</pre>
+
+<!-- #END_BLAZE_RULE -->*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/AliasConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/rules/AliasConfiguredTarget.java
new file mode 100644
index 0000000..c7d2387
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/AliasConfiguredTarget.java
@@ -0,0 +1,111 @@
+// 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;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.FileProvider;
+import com.google.devtools.build.lib.analysis.SkylarkProviders;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.syntax.ClassObject;
+import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+
+/**
+ * This configured target pretends to be whatever type of target "actual" is, returning its
+ * transitive info providers and target, but returning its own label.
+ *
+ * <p>Transitive info providers can also be overridden.
+ */
+@Immutable
+public final class AliasConfiguredTarget implements ConfiguredTarget, ClassObject {
+  private final ConfiguredTarget configuredTarget;
+  private final ImmutableMap<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider>
+      overrides;
+
+  public AliasConfiguredTarget(ConfiguredTarget actual,
+      ImmutableMap<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> overrides) {
+    configuredTarget = actual;
+    this.overrides = overrides;
+  }
+
+  @Override
+  public <P extends TransitiveInfoProvider> P getProvider(Class<P> provider) {
+    if (overrides.containsKey(provider)) {
+      return provider.cast(overrides.get(provider));
+    }
+
+    return configuredTarget == null ? null : configuredTarget.getProvider(provider);
+  }
+
+  @Override
+  public Label getLabel() {
+    return configuredTarget.getLabel();
+  }
+
+  @Override
+  public Object get(String providerKey) {
+    return configuredTarget == null ? null : configuredTarget.get(providerKey);
+  }
+
+  @Override
+  public Target getTarget() {
+    return configuredTarget == null ? null : configuredTarget.getTarget();
+  }
+
+  @Override
+  public BuildConfiguration getConfiguration() {
+    return configuredTarget.getConfiguration();
+  }
+
+  /* ClassObject methods */
+
+  @Override
+  public Object getValue(String name) {
+    if (name.equals("label")) {
+      return getLabel();
+    } else if (name.equals("files")) {
+      // A shortcut for files to build in Skylark. FileConfiguredTarget and RunleConfiguredTarget
+      // always has FileProvider and Error- and PackageGroupConfiguredTarget-s shouldn't be
+      // accessible in Skylark.
+      return SkylarkNestedSet.of(Artifact.class, configuredTarget == null
+          ? NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER)
+          : getProvider(FileProvider.class).getFilesToBuild());
+    }
+    return configuredTarget == null ? null : configuredTarget.get(name);
+  }
+
+  @Override
+  public ImmutableCollection<String> getKeys() {
+    ImmutableList.Builder<String> result = ImmutableList.<String>builder().add("label", "files");
+    if (configuredTarget != null) {
+        result.addAll(configuredTarget.getProvider(SkylarkProviders.class).getKeys());
+    }
+    return result.build();
+  }
+
+  @Override
+  public String errorMessage(String name) {
+    // Use the default error message.
+    return null;
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/AliasProvider.java b/src/main/java/com/google/devtools/build/lib/rules/AliasProvider.java
new file mode 100644
index 0000000..a6950b2
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/AliasProvider.java
@@ -0,0 +1,79 @@
+// 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;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.util.Preconditions;
+
+/**
+ * A provider that gives information about the aliases a rule was resolved through.
+ */
+@Immutable
+public final class AliasProvider implements TransitiveInfoProvider {
+  // We don't expect long alias chains, so it's better to have a list instead of a nested set
+  private final ImmutableList<Label> aliasChain;
+
+  public AliasProvider(ImmutableList<Label> aliasChain) {
+    Preconditions.checkState(!aliasChain.isEmpty());
+    this.aliasChain = aliasChain;
+  }
+
+  public static AliasProvider fromAliasRule(Label label, ConfiguredTarget actual) {
+    ImmutableList.Builder<Label> chain = ImmutableList.builder();
+    chain.add(label);
+    AliasProvider dep = actual.getProvider(AliasProvider.class);
+    if (dep != null) {
+      chain.addAll(dep.getAliasChain());
+    }
+
+    return new AliasProvider(chain.build());
+  }
+
+  /**
+   * Returns the label by which it was referred to in the BUILD file.
+   *
+   * <p>For non-alias rules, it's the label of the rule itself, for alias rules, it's the label of
+   * the alias rule.
+   */
+  public static Label getDependencyLabel(TransitiveInfoCollection dep) {
+    AliasProvider aliasProvider = dep.getProvider(AliasProvider.class);
+    return aliasProvider != null
+        ? aliasProvider.getAliasChain().get(0)
+        : dep.getLabel();
+  }
+
+  /**
+   * Returns the list of aliases from top to bottom (i.e. the last alias depends on the actual
+   * resolved target and the first alias is the one that was in the attribute of the rule currently
+   * being analyzed)
+   */
+  public ImmutableList<Label> getAliasChain() {
+    return aliasChain;
+  }
+
+  public static String printVisibilityChain(ConfiguredTarget target) {
+    AliasProvider aliasProvider = target.getProvider(AliasProvider.class);
+    if (aliasProvider == null) {
+      return "";
+    }
+
+    return " (aliased through '" + Joiner.on("' -> '").join(aliasProvider.getAliasChain()) + "')";
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java
index 44f637f..ffe2fca 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java
@@ -372,7 +372,7 @@
 
     for (AbstractConfiguredTarget current : knownLabels) {
       builder.put(
-          current.getLabel(),
+          AliasProvider.getDependencyLabel(current),
           ImmutableList.copyOf(current.getProvider(FileProvider.class).getFilesToBuild()));
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/Bind.java b/src/main/java/com/google/devtools/build/lib/rules/repository/Bind.java
index 6ea3ede..a832903 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/Bind.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/Bind.java
@@ -14,107 +14,20 @@
 
 package com.google.devtools.build.lib.rules.repository;
 
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableList;
-import com.google.devtools.build.lib.actions.Artifact;
+import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
-import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.RuleContext;
-import com.google.devtools.build.lib.analysis.SkylarkProviders;
 import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
-import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
-import com.google.devtools.build.lib.collect.nestedset.Order;
-import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.rules.AliasConfiguredTarget;
+import com.google.devtools.build.lib.rules.AliasProvider;
 import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
-import com.google.devtools.build.lib.syntax.ClassObject;
-import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
 
 /**
  * Implementation for the bind rule.
  */
 public class Bind implements RuleConfiguredTargetFactory {
 
-  /**
-   * This configured target pretends to be whatever type of target "actual" is, returning its
-   * transitive info providers and target, but returning the label for the //external target.
-   */
-  private static class BindConfiguredTarget implements ConfiguredTarget, ClassObject {
-
-    private Label label;
-    private ConfiguredTarget configuredTarget;
-    private BuildConfiguration config;
-
-    BindConfiguredTarget(RuleContext ruleContext) {
-      label = ruleContext.getRule().getLabel();
-      config = ruleContext.getConfiguration();
-      // TODO(bazel-team): we should special case ConfiguredTargetFactory.createConfiguredTarget,
-      // not cast down here.
-      configuredTarget = (ConfiguredTarget) ruleContext.getPrerequisite("actual", Mode.TARGET);
-    }
-
-    @Override
-    public <P extends TransitiveInfoProvider> P getProvider(Class<P> provider) {
-      return configuredTarget == null ? null : configuredTarget.getProvider(provider);
-    }
-
-    @Override
-    public Label getLabel() {
-      return label;
-    }
-
-    @Override
-    public Object get(String providerKey) {
-      return configuredTarget == null ? null : configuredTarget.get(providerKey);
-    }
-
-    @Override
-    public Target getTarget() {
-      return configuredTarget == null ? null : configuredTarget.getTarget();
-    }
-
-    @Override
-    public BuildConfiguration getConfiguration() {
-      return config;
-    }
-
-    /* ClassObject methods */
-
-    @Override
-    public Object getValue(String name) {
-      if (name.equals("label")) {
-        return getLabel();
-      } else if (name.equals("files")) {
-        // A shortcut for files to build in Skylark. FileConfiguredTarget and RunleConfiguredTarget
-        // always has FileProvider and Error- and PackageGroupConfiguredTarget-s shouldn't be
-        // accessible in Skylark.
-        return SkylarkNestedSet.of(Artifact.class, configuredTarget == null
-            ? NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER)
-            : getProvider(FileProvider.class).getFilesToBuild());
-      }
-      return configuredTarget == null ? null : configuredTarget.get(name);
-    }
-
-    @SuppressWarnings("cast")
-    @Override
-    public ImmutableCollection<String> getKeys() {
-      ImmutableList.Builder<String> result = ImmutableList.<String>builder().add("label", "files");
-      if (configuredTarget != null) {
-          result.addAll(
-              configuredTarget.getProvider(SkylarkProviders.class).getKeys());
-      }
-      return result.build();
-    }
-
-    @Override
-    public String errorMessage(String name) {
-      // Use the default error message.
-      return null;
-    }
-  }
-
   @Override
   public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException {
     if (ruleContext.getPrerequisite("actual", Mode.TARGET) == null) {
@@ -122,6 +35,10 @@
           ruleContext.getLabel()));
       return null;
     }
-    return new BindConfiguredTarget(ruleContext);
+
+    ConfiguredTarget actual = (ConfiguredTarget) ruleContext.getPrerequisite("actual", Mode.TARGET);
+    return new AliasConfiguredTarget(actual,
+        ImmutableMap.<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider>of(
+            AliasProvider.class, AliasProvider.fromAliasRule(ruleContext.getLabel(), actual)));
   }
 }