blob: 9f99a01d0b2b7ff6888de2298a182119804f955b [file] [log] [blame]
// 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.packages;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import java.util.ArrayList;
import java.util.Objects;
/**
* Captures the the set of providers rules and aspects can advertise.
* It is either of:
* <ul>
* <li>a set of native and skylark providers</li>
* <li>"can have any provider" set that alias rules have.</li>
* </ul>
*
* <p>
* Native providers should in theory only contain subclasses of
* {@link com.google.devtools.build.lib.analysis.TransitiveInfoProvider}, but
* our current dependency structure does not allow a reference to that class here.
* </p>
*/
@Immutable
public final class AdvertisedProviderSet {
private final boolean canHaveAnyProvider;
private final ImmutableSet<Class<?>> nativeProviders;
private final ImmutableSet<SkylarkProviderIdentifier> skylarkProviders;
private AdvertisedProviderSet(boolean canHaveAnyProvider,
ImmutableSet<Class<?>> nativeProviders,
ImmutableSet<SkylarkProviderIdentifier> skylarkProviders) {
this.canHaveAnyProvider = canHaveAnyProvider;
this.nativeProviders = nativeProviders;
this.skylarkProviders = skylarkProviders;
}
public static final AdvertisedProviderSet ANY =
new AdvertisedProviderSet(true,
ImmutableSet.<Class<?>>of(),
ImmutableSet.<SkylarkProviderIdentifier>of());
public static final AdvertisedProviderSet EMPTY =
new AdvertisedProviderSet(false,
ImmutableSet.<Class<?>>of(),
ImmutableSet.<SkylarkProviderIdentifier>of());
public static AdvertisedProviderSet create(
ImmutableSet<Class<?>> nativeProviders,
ImmutableSet<SkylarkProviderIdentifier> skylarkProviders) {
if (nativeProviders.isEmpty() && skylarkProviders.isEmpty()) {
return EMPTY;
}
return new AdvertisedProviderSet(false, nativeProviders, skylarkProviders);
}
@Override
public int hashCode() {
return Objects.hash(canHaveAnyProvider, nativeProviders, skylarkProviders);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof AdvertisedProviderSet)) {
return false;
}
AdvertisedProviderSet that = (AdvertisedProviderSet) obj;
return Objects.equals(this.canHaveAnyProvider, that.canHaveAnyProvider)
&& Objects.equals(this.nativeProviders, that.nativeProviders)
&& Objects.equals(this.skylarkProviders, that.skylarkProviders);
}
@Override
public String toString() {
if (canHaveAnyProvider()) {
return "Any Provider";
}
return String.format(
"allowed native providers=%s, allowed Starlark providers=%s",
getNativeProviders(), getSkylarkProviders());
}
/** Checks whether the rule can have any provider.
*
* Used for alias rules.
*/
public boolean canHaveAnyProvider() {
return canHaveAnyProvider;
}
/**
* Get all advertised native providers.
*/
public ImmutableSet<Class<?>> getNativeProviders() {
return nativeProviders;
}
/**
* Get all advertised Skylark providers.
*/
public ImmutableSet<SkylarkProviderIdentifier> getSkylarkProviders() {
return skylarkProviders;
}
public static Builder builder() {
return new Builder();
}
/**
* Returns {@code true} if this provider set can have any provider, or if it advertises the
* specific native provider requested.
*/
public boolean advertises(Class<?> nativeProviderClass) {
if (canHaveAnyProvider()) {
return true;
}
return nativeProviders.contains(nativeProviderClass);
}
/**
* Returns {@code true} if this provider set can have any provider, or if it advertises the
* specific skylark provider requested.
*/
public boolean advertises(SkylarkProviderIdentifier skylarkProvider) {
if (canHaveAnyProvider()) {
return true;
}
return skylarkProviders.contains(skylarkProvider);
}
/** Builder for {@link AdvertisedProviderSet} */
public static class Builder {
private boolean canHaveAnyProvider;
private final ArrayList<Class<?>> nativeProviders;
private final ArrayList<SkylarkProviderIdentifier> skylarkProviders;
private Builder() {
nativeProviders = new ArrayList<>();
skylarkProviders = new ArrayList<>();
}
/**
* Advertise all providers inherited from a parent rule.
*/
public Builder addParent(AdvertisedProviderSet parentSet) {
Preconditions.checkState(!canHaveAnyProvider, "Alias rules inherit from no other rules");
Preconditions.checkState(!parentSet.canHaveAnyProvider(),
"Cannot inherit from alias rules");
nativeProviders.addAll(parentSet.getNativeProviders());
skylarkProviders.addAll(parentSet.getSkylarkProviders());
return this;
}
public Builder addNative(Class<?> nativeProvider) {
this.nativeProviders.add(nativeProvider);
return this;
}
public void canHaveAnyProvider() {
Preconditions.checkState(nativeProviders.isEmpty() && skylarkProviders.isEmpty());
this.canHaveAnyProvider = true;
}
public AdvertisedProviderSet build() {
if (canHaveAnyProvider) {
Preconditions.checkState(nativeProviders.isEmpty() && skylarkProviders.isEmpty());
return ANY;
}
return AdvertisedProviderSet.create(
ImmutableSet.copyOf(nativeProviders), ImmutableSet.copyOf(skylarkProviders));
}
public Builder addSkylark(String providerName) {
skylarkProviders.add(SkylarkProviderIdentifier.forLegacy(providerName));
return this;
}
public Builder addSkylark(SkylarkProviderIdentifier id) {
skylarkProviders.add(id);
return this;
}
public Builder addSkylark(Provider.Key id) {
skylarkProviders.add(SkylarkProviderIdentifier.forKey(id));
return this;
}
}
}