Supported "in" operator for all SkylarkIndexable objects. -- MOS_MIGRATED_REVID=135483694
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AbstractConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/analysis/AbstractConfiguredTarget.java index 107e64b..cbe5056 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/AbstractConfiguredTarget.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/AbstractConfiguredTarget.java
@@ -150,6 +150,24 @@ } @Override + public boolean containsKey(Object key, Location loc) throws EvalException { + if (!(key instanceof SkylarkClassObjectConstructor)) { + throw new EvalException(loc, String.format( + "Type Target only supports querying by object constructors, got %s instead", + EvalUtils.getDataTypeName(key))); + } + SkylarkClassObjectConstructor constructor = (SkylarkClassObjectConstructor) key; + SkylarkProviders provider = getProvider(SkylarkProviders.class); + if (provider != null) { + Object declaredProvider = provider.getDeclaredProvider(constructor.getKey()); + if (declaredProvider != null) { + return true; + } + } + return false; + } + + @Override public String errorMessage(String name) { return null; }
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 index 347c728..1c6eebd 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/AliasConfiguredTarget.java +++ b/src/main/java/com/google/devtools/build/lib/rules/AliasConfiguredTarget.java
@@ -96,6 +96,11 @@ } @Override + public boolean containsKey(Object key, Location loc) throws EvalException { + return actual != null && actual.containsKey(key, loc); + } + + @Override public Target getTarget() { return actual == null ? null : actual.getTarget(); }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java index 131ee54..15989ec 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java
@@ -95,17 +95,8 @@ * <p>Publicly accessible for reflection and compiled Skylark code. */ public static boolean in(Object lval, Object rval, Location location) throws EvalException { - if (rval instanceof SkylarkList) { - for (Object obj : (SkylarkList) rval) { - if (obj.equals(lval)) { - return true; - } - } - return false; - } else if (rval instanceof SkylarkDict) { - return ((SkylarkDict<?, ?>) rval).containsKey(lval); - } else if (rval instanceof SkylarkNestedSet) { - return ((SkylarkNestedSet) rval).expandedSet().contains(lval); + if (rval instanceof SkylarkQueryable) { + return ((SkylarkQueryable) rval).containsKey(lval, location); } else if (rval instanceof String) { if (lval instanceof String) { return ((String) rval).contains((String) lval);
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java index 49f6c58..fc5e9cf 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkDict.java
@@ -223,6 +223,11 @@ return this.get(key); } + @Override + public final boolean containsKey(Object key, Location loc) throws EvalException { + return this.containsKey(key); + } + public static <K, V> SkylarkDict<K, V> plus( SkylarkDict<? extends K, ? extends V> left, SkylarkDict<? extends K, ? extends V> right,
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkIndexable.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkIndexable.java index 18293f4..b33fb45 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkIndexable.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkIndexable.java
@@ -17,9 +17,9 @@ import com.google.devtools.build.lib.events.Location; /** - * Skylark values that support index access, i.e. object[key] + * Skylark values that support index access, i.e. `object[key]` */ -public interface SkylarkIndexable { +public interface SkylarkIndexable extends SkylarkQueryable { /** * Returns the value associated with the given key.
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java index 81cad2f..1c1c52b 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java
@@ -136,6 +136,16 @@ return list.get(index); } + @Override + public final boolean containsKey(Object key, Location loc) throws EvalException { + for (Object obj : this) { + if (obj.equals(key)) { + return true; + } + } + return false; + } + /** * Retrieve a sublist from a SkylarkList. * @param start start value
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java index 2a64d79..1657955 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java
@@ -78,7 +78,7 @@ + "nested sets." ) @Immutable -public final class SkylarkNestedSet implements Iterable<Object>, SkylarkValue { +public final class SkylarkNestedSet implements Iterable<Object>, SkylarkValue, SkylarkQueryable { private final SkylarkType contentType; @Nullable private final List<Object> items; @@ -272,4 +272,9 @@ } Printer.append(buffer, ")"); } + + @Override + public final boolean containsKey(Object key, Location loc) throws EvalException { + return (this.expandedSet().contains(key)); + } }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkQueryable.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkQueryable.java new file mode 100644 index 0000000..b278168 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkQueryable.java
@@ -0,0 +1,29 @@ +// 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.syntax; + +import com.google.devtools.build.lib.events.Location; + +/** + * Skylark values that support querying by other objects, i.e. `foo in object`. + * Semantics of the operation may differ, i.e. dicts check for keys and lists for values. + */ +public interface SkylarkQueryable { + + /** + * Returns whether the key is in the object. + */ + boolean containsKey(Object key, Location loc) throws EvalException; +}
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleImplementationFunctionsTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleImplementationFunctionsTest.java index 60b9643..719afd4 100644 --- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleImplementationFunctionsTest.java +++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleImplementationFunctionsTest.java
@@ -1041,6 +1041,87 @@ } @Test + public void testDeclaredProvidersInOperator() throws Exception { + scratch.file( + "test/foo.bzl", + "foo_provider = provider()", + "bar_provider = provider()", + "", + "def _inner_impl(ctx):", + " foo = foo_provider()", + " return [foo]", + "inner_rule = rule(", + " implementation = _inner_impl,", + ")", + "", + "def _outer_impl(ctx):", + " dep = ctx.attr.deps[0]", + " return struct(", + " foo = (foo_provider in dep),", // Should be true + " bar = (bar_provider in dep),", // Should be false + " )", + "outer_rule = rule(", + " implementation = _outer_impl,", + " attrs = {", + " 'deps': attr.label_list(),", + " }", + ")" + ); + scratch.file( + "test/BUILD", + "load(':foo.bzl', 'inner_rule', 'outer_rule')", + "inner_rule(name = 'dep_rule')", + "outer_rule(name = 'my_rule', deps = [':dep_rule'])"); + + ConfiguredTarget configuredTarget = getConfiguredTarget("//test:my_rule"); + Object foo = configuredTarget.getProvider(SkylarkProviders.class).getValue("foo"); + assertThat(foo).isInstanceOf(Boolean.class); + assertThat((Boolean) foo).isTrue(); + Object bar = configuredTarget.getProvider(SkylarkProviders.class).getValue("bar"); + assertThat(bar).isInstanceOf(Boolean.class); + assertThat((Boolean) bar).isFalse(); + } + + @Test + public void testDeclaredProvidersInOperatorInvalidKey() throws Exception { + scratch.file( + "test/foo.bzl", + "foo_provider = provider()", + "bar_provider = provider()", + "", + "def _inner_impl(ctx):", + " foo = foo_provider()", + " return [foo]", + "inner_rule = rule(", + " implementation = _inner_impl,", + ")", + "", + "def _outer_impl(ctx):", + " dep = ctx.attr.deps[0]", + " 'foo_provider' in dep", // Should throw an error here + "outer_rule = rule(", + " implementation = _outer_impl,", + " attrs = {", + " 'deps': attr.label_list(),", + " }", + ")" + ); + scratch.file( + "test/BUILD", + "load(':foo.bzl', 'inner_rule', 'outer_rule')", + "inner_rule(name = 'dep_rule')", + "outer_rule(name = 'my_rule', deps = [':dep_rule'])"); + + try { + getConfiguredTarget("//test:my_rule"); + fail(); + } catch (AssertionError expected) { + assertThat(expected.getMessage()).contains("Type Target only supports querying by object " + + "constructors, got string instead"); + } + } + + @Test public void testFilesForFileConfiguredTarget() throws Exception { Object result = evalRuleContextCode(createRuleContext("//foo:bar"), "ruleContext.attr.srcs[0].files");