| // 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.MoreObjects; | 
 | import com.google.common.base.Preconditions; | 
 | import com.google.common.collect.ImmutableCollection; | 
 | 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.RuleContext; | 
 | import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; | 
 | import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider; | 
 | import com.google.devtools.build.lib.cmdline.Label; | 
 | import com.google.devtools.build.lib.collect.nestedset.Depset; | 
 | import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; | 
 | import com.google.devtools.build.lib.packages.Info; | 
 | import com.google.devtools.build.lib.packages.Provider; | 
 | import com.google.devtools.build.lib.skyframe.BuildConfigurationValue; | 
 | import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; | 
 | import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization; | 
 | import javax.annotation.Nullable; | 
 | import net.starlark.java.eval.EvalException; | 
 | import net.starlark.java.eval.Printer; | 
 | import net.starlark.java.eval.StarlarkSemantics; | 
 | import net.starlark.java.eval.Structure; | 
 |  | 
 | /** | 
 |  * This configured target pretends to be whatever type of target "actual" is, returning its label, | 
 |  * transitive info providers and target. | 
 |  * | 
 |  * <p>Transitive info providers can also be overridden. | 
 |  */ | 
 | @AutoCodec | 
 | @Immutable | 
 | public final class AliasConfiguredTarget implements ConfiguredTarget, Structure { | 
 |   private final Label label; | 
 |   private final BuildConfigurationValue.Key configurationKey; | 
 |   private final ConfiguredTarget actual; | 
 |   private final ImmutableMap<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> | 
 |       overrides; | 
 |   private final ImmutableMap<Label, ConfigMatchingProvider> configConditions; | 
 |  | 
 |   public AliasConfiguredTarget( | 
 |       RuleContext ruleContext, | 
 |       ConfiguredTarget actual, | 
 |       ImmutableMap<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> overrides) { | 
 |     this( | 
 |         ruleContext.getLabel(), | 
 |         Preconditions.checkNotNull(ruleContext.getConfigurationKey()), | 
 |         Preconditions.checkNotNull(actual), | 
 |         Preconditions.checkNotNull(overrides), | 
 |         ruleContext.getConfigConditions()); | 
 |   } | 
 |  | 
 |   @AutoCodec.Instantiator | 
 |   @VisibleForSerialization | 
 |   AliasConfiguredTarget( | 
 |       Label label, | 
 |       BuildConfigurationValue.Key configurationKey, | 
 |       ConfiguredTarget actual, | 
 |       ImmutableMap<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> overrides, | 
 |       ImmutableMap<Label, ConfigMatchingProvider> configConditions) { | 
 |     this.label = label; | 
 |     this.configurationKey = configurationKey; | 
 |     this.actual = actual; | 
 |     this.overrides = overrides; | 
 |     this.configConditions = configConditions; | 
 |   } | 
 |  | 
 |   @Override | 
 |   public boolean isImmutable() { | 
 |     return true; // immutable and Starlark-hashable | 
 |   } | 
 |  | 
 |   @Override | 
 |   public ImmutableMap<Label, ConfigMatchingProvider> getConfigConditions() { | 
 |     return configConditions; | 
 |   } | 
 |  | 
 |   @Override | 
 |   public <P extends TransitiveInfoProvider> P getProvider(Class<P> provider) { | 
 |     if (overrides.containsKey(provider)) { | 
 |       return provider.cast(overrides.get(provider)); | 
 |     } | 
 |  | 
 |     return actual.getProvider(provider); | 
 |   } | 
 |  | 
 |   @Override | 
 |   public Label getLabel() { | 
 |     return actual.getLabel(); | 
 |   } | 
 |  | 
 |   @Override | 
 |   public Object get(String providerKey) { | 
 |     return actual.get(providerKey); | 
 |   } | 
 |  | 
 |   @Nullable | 
 |   @Override | 
 |   public Info get(Provider.Key providerKey) { | 
 |     return actual.get(providerKey); | 
 |   } | 
 |  | 
 |   @Override | 
 |   public Object getIndex(StarlarkSemantics semantics, Object key) throws EvalException { | 
 |     return actual.getIndex(semantics, key); | 
 |   } | 
 |  | 
 |   @Override | 
 |   public boolean containsKey(StarlarkSemantics semantics, Object key) throws EvalException { | 
 |     return actual.containsKey(semantics, key); | 
 |   } | 
 |  | 
 |   @Override | 
 |   public BuildConfigurationValue.Key getConfigurationKey() { | 
 |     // This does not return actual.getConfigurationKey() because actual might be an input file, in | 
 |     // which case its configurationKey is null and we don't want to have rules that have a null | 
 |     // configurationKey. | 
 |     return configurationKey; | 
 |   } | 
 |  | 
 |   /* Structure methods */ | 
 |  | 
 |   @Override | 
 |   public Object getValue(String name) { | 
 |     if (name.equals(LABEL_FIELD)) { | 
 |       return getLabel(); | 
 |     } else if (name.equals(FILES_FIELD)) { | 
 |       // A shortcut for files to build in Starlark. FileConfiguredTarget and RuleConfiguredTarget | 
 |       // always has FileProvider and Error- and PackageGroupConfiguredTarget-s shouldn't be | 
 |       // accessible in Starlark. | 
 |       return Depset.of(Artifact.TYPE, getProvider(FileProvider.class).getFilesToBuild()); | 
 |     } | 
 |     return actual.getValue(name); | 
 |   } | 
 |  | 
 |   @Override | 
 |   public ImmutableCollection<String> getFieldNames() { | 
 |     return actual.getFieldNames(); | 
 |   } | 
 |  | 
 |   @Override | 
 |   public String getErrorMessageForUnknownField(String name) { | 
 |     // Use the default error message. | 
 |     return null; | 
 |   } | 
 |  | 
 |   @Override | 
 |   public ConfiguredTarget getActual() { | 
 |     // This will either dereference an alias chain, or return the final ConfiguredTarget. | 
 |     return actual.getActual(); | 
 |   } | 
 |  | 
 |   @Override | 
 |   public Label getOriginalLabel() { | 
 |     return label; | 
 |   } | 
 |  | 
 |   @Override | 
 |   public void repr(Printer printer) { | 
 |     printer.append("<alias target " + label + " of " + actual.getLabel() + ">"); | 
 |   } | 
 |  | 
 |   @Override | 
 |   public String toString() { | 
 |     return MoreObjects.toStringHelper(this) | 
 |         .add("label", label) | 
 |         .add("configurationKey", configurationKey) | 
 |         .add("actual", actual) | 
 |         .add("overrides", overrides) | 
 |         .add("configConditions", configConditions) | 
 |         .toString(); | 
 |   } | 
 | } |