blob: c373247621f222eff6dfb1e84a5a114213852b77 [file] [log] [blame]
// Copyright 2020 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.skyframe;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Interner;
import com.google.devtools.build.lib.actions.ActionLookupKey;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.concurrent.BlazeInterners;
import com.google.devtools.build.lib.packages.AspectClass;
import com.google.devtools.build.lib.packages.AspectDescriptor;
import com.google.devtools.build.lib.packages.AspectParameters;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.skyframe.SkyFunctionName;
import javax.annotation.Nullable;
/** The class responsible for creating & interning the various types of AspectKeys. */
public final class AspectKeyCreator {
private AspectKeyCreator() {}
public static AspectKey createAspectKey(
AspectDescriptor aspectDescriptor, ConfiguredTargetKey baseConfiguredTargetKey) {
return createAspectKey(
aspectDescriptor, /*baseKeys=*/ ImmutableList.of(), baseConfiguredTargetKey);
}
public static AspectKey createAspectKey(
AspectDescriptor aspectDescriptor,
ImmutableList<AspectKey> baseKeys,
ConfiguredTargetKey baseConfiguredTargetKey) {
return AspectKey.createAspectKey(baseConfiguredTargetKey, baseKeys, aspectDescriptor);
}
public static TopLevelAspectsKey createTopLevelAspectsKey(
ImmutableList<AspectClass> topLevelAspectsClasses,
Label targetLabel,
@Nullable BuildConfigurationValue configuration,
ImmutableMap<String, String> topLevelAspectsParameters) {
return TopLevelAspectsKey.createInternal(
topLevelAspectsClasses,
targetLabel,
ConfiguredTargetKey.builder().setLabel(targetLabel).setConfiguration(configuration).build(),
topLevelAspectsParameters);
}
/** Common superclass for {@link AspectKey} and {@link TopLevelAspectsKey}. */
public abstract static class AspectBaseKey implements ActionLookupKey {
private final ConfiguredTargetKey baseConfiguredTargetKey;
private final int hashCode;
private AspectBaseKey(ConfiguredTargetKey baseConfiguredTargetKey, int hashCode) {
this.baseConfiguredTargetKey = baseConfiguredTargetKey;
this.hashCode = hashCode;
}
/** Returns the key for the base configured target for this aspect. */
public final ConfiguredTargetKey getBaseConfiguredTargetKey() {
return baseConfiguredTargetKey;
}
@Override
public final int hashCode() {
return hashCode;
}
}
// Specific subtypes of aspect keys.
/** Represents an aspect applied to a particular target. */
@AutoCodec
public static final class AspectKey extends AspectBaseKey {
private static final Interner<AspectKey> interner = BlazeInterners.newWeakInterner();
private final ImmutableList<AspectKey> baseKeys;
private final AspectDescriptor aspectDescriptor;
private AspectKey(
ConfiguredTargetKey baseConfiguredTargetKey,
ImmutableList<AspectKey> baseKeys,
AspectDescriptor aspectDescriptor,
int hashCode) {
super(baseConfiguredTargetKey, hashCode);
this.baseKeys = baseKeys;
this.aspectDescriptor = aspectDescriptor;
}
@AutoCodec.VisibleForSerialization
@AutoCodec.Instantiator
static AspectKey createAspectKey(
ConfiguredTargetKey baseConfiguredTargetKey,
ImmutableList<AspectKey> baseKeys,
AspectDescriptor aspectDescriptor) {
return interner.intern(
new AspectKey(
baseConfiguredTargetKey,
baseKeys,
aspectDescriptor,
Objects.hashCode(baseConfiguredTargetKey, baseKeys, aspectDescriptor)));
}
@Override
public SkyFunctionName functionName() {
return SkyFunctions.ASPECT;
}
/**
* Gets the name of the aspect that would be returned by the corresponding value's {@code
* aspectValue.getAspect().getAspectClass().getName()}, if the value could be produced.
*
* <p>Only needed for reporting errors in BEP when the key's AspectValue fails evaluation.
*/
public String getAspectName() {
return aspectDescriptor.getDescription();
}
@Override
public Label getLabel() {
return getBaseConfiguredTargetKey().getLabel();
}
public AspectClass getAspectClass() {
return aspectDescriptor.getAspectClass();
}
@Nullable
public AspectParameters getParameters() {
return aspectDescriptor.getParameters();
}
public AspectDescriptor getAspectDescriptor() {
return aspectDescriptor;
}
@Nullable
public ImmutableList<AspectKey> getBaseKeys() {
return baseKeys;
}
public String getDescription() {
if (baseKeys.isEmpty()) {
return String.format("%s of %s", aspectDescriptor.getAspectClass().getName(), getLabel());
} else {
return String.format(
"%s on top of %s", aspectDescriptor.getAspectClass().getName(), baseKeys);
}
}
/**
* Returns the key of the configured target of the aspect; that is, the configuration in which
* the aspect will be evaluated.
*/
@Override
@Nullable
public BuildConfigurationKey getConfigurationKey() {
return getBaseConfiguredTargetKey().getConfigurationKey();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof AspectKey)) {
return false;
}
AspectKey that = (AspectKey) other;
return hashCode() == that.hashCode()
&& Objects.equal(baseKeys, that.baseKeys)
&& Objects.equal(getBaseConfiguredTargetKey(), that.getBaseConfiguredTargetKey())
&& Objects.equal(aspectDescriptor, that.aspectDescriptor);
}
public String prettyPrint() {
if (getLabel() == null) {
return "null";
}
String baseKeysString = baseKeys.isEmpty() ? "" : String.format(" (over %s)", baseKeys);
return String.format(
"%s with aspect %s%s",
getLabel(), aspectDescriptor.getAspectClass().getName(), baseKeysString);
}
@Override
public String toString() {
return (baseKeys == null ? getLabel() : baseKeys.toString())
+ "#"
+ aspectDescriptor
+ " "
+ getBaseConfiguredTargetKey()
+ " "
+ aspectDescriptor.getParameters();
}
AspectKey withLabel(Label label) {
ImmutableList.Builder<AspectKey> newBaseKeys = ImmutableList.builder();
for (AspectKey baseKey : baseKeys) {
newBaseKeys.add(baseKey.withLabel(label));
}
return createAspectKey(
ConfiguredTargetKey.builder()
.setLabel(label)
.setConfigurationKey(getBaseConfiguredTargetKey().getConfigurationKey())
.build(),
newBaseKeys.build(),
aspectDescriptor);
}
}
/**
* The key for top level aspects specified by --aspects option and their parameters specified by
* --aspects_parameters applied on a top level target.
*/
@AutoCodec
public static final class TopLevelAspectsKey extends AspectBaseKey {
private static final Interner<TopLevelAspectsKey> interner = BlazeInterners.newWeakInterner();
private final ImmutableList<AspectClass> topLevelAspectsClasses;
private final Label targetLabel;
private final ImmutableMap<String, String> topLevelAspectsParameters;
@AutoCodec.Instantiator
@AutoCodec.VisibleForSerialization
static TopLevelAspectsKey createInternal(
ImmutableList<AspectClass> topLevelAspectsClasses,
Label targetLabel,
ConfiguredTargetKey baseConfiguredTargetKey,
ImmutableMap<String, String> topLevelAspectsParameters) {
return interner.intern(
new TopLevelAspectsKey(
topLevelAspectsClasses,
targetLabel,
baseConfiguredTargetKey,
topLevelAspectsParameters,
Objects.hashCode(
topLevelAspectsClasses,
targetLabel,
baseConfiguredTargetKey,
topLevelAspectsParameters)));
}
private TopLevelAspectsKey(
ImmutableList<AspectClass> topLevelAspectsClasses,
Label targetLabel,
ConfiguredTargetKey baseConfiguredTargetKey,
ImmutableMap<String, String> topLevelAspectsParameters,
int hashCode) {
super(baseConfiguredTargetKey, hashCode);
this.topLevelAspectsClasses = topLevelAspectsClasses;
this.targetLabel = targetLabel;
this.topLevelAspectsParameters = topLevelAspectsParameters;
}
@Override
public SkyFunctionName functionName() {
return SkyFunctions.TOP_LEVEL_ASPECTS;
}
@Override
public BuildConfigurationKey getConfigurationKey() {
return getBaseConfiguredTargetKey().getConfigurationKey();
}
ImmutableList<AspectClass> getTopLevelAspectsClasses() {
return topLevelAspectsClasses;
}
ImmutableMap<String, String> getTopLevelAspectsParameters() {
return topLevelAspectsParameters;
}
@Override
public Label getLabel() {
return targetLabel;
}
String getDescription() {
return String.format(
"%s with parameters %s on %s",
topLevelAspectsClasses, topLevelAspectsParameters, targetLabel);
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof TopLevelAspectsKey)) {
return false;
}
TopLevelAspectsKey that = (TopLevelAspectsKey) o;
return hashCode() == that.hashCode()
&& Objects.equal(targetLabel, that.targetLabel)
&& Objects.equal(getBaseConfiguredTargetKey(), that.getBaseConfiguredTargetKey())
&& Objects.equal(topLevelAspectsClasses, that.topLevelAspectsClasses)
&& Objects.equal(topLevelAspectsParameters, that.topLevelAspectsParameters);
}
}
}