blob: 3f1342ad77dd40983ba57915a1f959fa49e61615 [file] [log] [blame]
// Copyright 2015 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.query2.engine;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
/**
* A predicate for targets included in the visibility list of a rule.
*
* <p>A rule's visibility is described by a set of {@link QueryVisibility}. Each element
* in the set corresponds to an entry in the rule's visibility attribute, or an entry in the
* packages attribute of an included package_group.
*/
public abstract class QueryVisibility<T> {
/** Returns true if the visibility specification includes the given target's package. */
public abstract boolean contains(T target);
/** Global visibility. */
@SuppressWarnings("unchecked") // Safe covariant cast.
public static <T> QueryVisibility<T> everything() {
return (QueryVisibility<T>) (Object) EVERYTHING;
}
private static final QueryVisibility<?> EVERYTHING = new QueryVisibility<Object>() {
@Override
public boolean contains(Object target) {
return true;
}
@Override
public String toString() {
return "QueryVisibility(//visibility:public)";
}
};
/**
* Empty visibility.
*
* <p>This is useful as a sentinel to indicate that a package specification could be parsed into
* a {@link QueryVisibility}. Same-package visibility is handled separately by
* {@link VisibleFunction}.
*/
@SuppressWarnings("unchecked") // Safe covariant cast.
public static <T> QueryVisibility<T> nothing() {
return (QueryVisibility<T>) (Object) NOTHING;
}
private static final QueryVisibility<?> NOTHING = new QueryVisibility<Object>() {
@Override
public boolean contains(Object target) {
return false;
}
@Override
public String toString() {
return "QueryVisibility(//visibility:private)";
}
};
/**
* Same-package visibility.
*
* <p>Targets are always visible to other targets in the same package. Additionally, targets
* under java/ are always visible to the corresponding package in javatests/.
*/
public static <T> QueryVisibility<T> samePackage(T from, TargetAccessor<T> accessor) {
return new SamePackageVisibility<>(from, accessor);
}
private static final class SamePackageVisibility<T> extends QueryVisibility<T> {
private static final String JAVA_PREFIX = "java/";
private static final String JAVATESTS_PREFIX = "javatests/";
private final String packageName;
private final TargetAccessor<T> accessor;
public SamePackageVisibility(T target, TargetAccessor<T> accessor) {
this.packageName = accessor.getPackage(target);
this.accessor = accessor;
}
@Override
public boolean contains(T target) {
String other = accessor.getPackage(target);
if (packageName.equals(other)) {
return true;
}
// packages in java/ are always visible from the corresponding package in javatests/
if (other.startsWith(JAVATESTS_PREFIX)
&& packageName.equals(JAVA_PREFIX + other.substring(JAVATESTS_PREFIX.length()))) {
return true;
}
return false;
}
@Override
public String toString() {
return String.format("QueryVisibility(samePackage=%s)", "<PACKAGE>");
}
}
}