dslomov | f129657 | 2017-08-22 16:29:06 +0200 | [diff] [blame] | 1 | // Copyright 2017 The Bazel Authors. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | package com.google.devtools.build.lib.packages; |
| 15 | |
Googler | d327b80 | 2023-06-06 16:51:36 -0700 | [diff] [blame] | 16 | import static com.google.common.base.MoreObjects.firstNonNull; |
| 17 | |
dslomov | f129657 | 2017-08-22 16:29:06 +0200 | [diff] [blame] | 18 | import com.google.common.collect.ImmutableCollection; |
adonovan | 121224e | 2020-05-18 08:39:45 -0700 | [diff] [blame] | 19 | import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; |
adonovan | dd00046 | 2020-11-06 12:57:38 -0800 | [diff] [blame] | 20 | import javax.annotation.Nullable; |
adonovan | 450c7ad | 2020-09-14 13:00:21 -0700 | [diff] [blame] | 21 | import net.starlark.java.eval.EvalException; |
| 22 | import net.starlark.java.eval.Starlark; |
| 23 | import net.starlark.java.eval.StarlarkSemantics; |
| 24 | import net.starlark.java.syntax.Location; |
dslomov | f129657 | 2017-08-22 16:29:06 +0200 | [diff] [blame] | 25 | |
adonovan | 7202d10 | 2019-12-09 13:58:57 -0800 | [diff] [blame] | 26 | /** |
| 27 | * Abstract base class for implementations of {@link StructImpl} that expose |
adonovan | 121224e | 2020-05-18 08:39:45 -0700 | [diff] [blame] | 28 | * StarlarkCallable-annotated fields (not just methods) to Starlark code. Subclasses must be |
| 29 | * immutable. |
adonovan | 7202d10 | 2019-12-09 13:58:57 -0800 | [diff] [blame] | 30 | */ |
adonovan | dd00046 | 2020-11-06 12:57:38 -0800 | [diff] [blame] | 31 | // TODO(adonovan): ensure that all subclasses are named *Info and not *Provider. |
| 32 | // (Info is to object as Provider is to class.) |
adonovan | 121224e | 2020-05-18 08:39:45 -0700 | [diff] [blame] | 33 | @Immutable |
adonovan | 7202d10 | 2019-12-09 13:58:57 -0800 | [diff] [blame] | 34 | public abstract class NativeInfo extends StructImpl { |
dslomov | f129657 | 2017-08-22 16:29:06 +0200 | [diff] [blame] | 35 | |
Googler | d327b80 | 2023-06-06 16:51:36 -0700 | [diff] [blame] | 36 | private final Location location; |
| 37 | |
adonovan | dd00046 | 2020-11-06 12:57:38 -0800 | [diff] [blame] | 38 | protected NativeInfo() { |
| 39 | this(Location.BUILTIN); |
adonovan | 7202d10 | 2019-12-09 13:58:57 -0800 | [diff] [blame] | 40 | } |
| 41 | |
adonovan | dd00046 | 2020-11-06 12:57:38 -0800 | [diff] [blame] | 42 | // TODO(adonovan): most subclasses pass Location.BUILTIN most of the time. |
| 43 | // Make only those classes that pass a real location pay for it. |
Googler | d327b80 | 2023-06-06 16:51:36 -0700 | [diff] [blame] | 44 | protected NativeInfo(@Nullable Location location) { |
| 45 | this.location = firstNonNull(location, Location.BUILTIN); |
| 46 | } |
| 47 | |
| 48 | @Override |
| 49 | public final Location getCreationLocation() { |
| 50 | return location; |
adonovan | 7202d10 | 2019-12-09 13:58:57 -0800 | [diff] [blame] | 51 | } |
cparsons | 6c1c066 | 2018-02-05 02:01:28 -0800 | [diff] [blame] | 52 | |
adonovan | 121224e | 2020-05-18 08:39:45 -0700 | [diff] [blame] | 53 | @Override |
| 54 | public boolean isImmutable() { |
| 55 | return true; // immutable and Starlark-hashable |
| 56 | } |
| 57 | |
Googler | 15a700c | 2019-11-27 12:45:29 -0800 | [diff] [blame] | 58 | // TODO(adonovan): logically this should be a parameter of getValue |
| 59 | // and getFieldNames or an instance field of this object. |
adonovan | b85d0b7 | 2020-05-08 11:59:19 -0700 | [diff] [blame] | 60 | private static final StarlarkSemantics SEMANTICS = StarlarkSemantics.DEFAULT; |
Googler | 15a700c | 2019-11-27 12:45:29 -0800 | [diff] [blame] | 61 | |
Googler | 3d50c6a | 2022-07-06 03:50:04 -0700 | [diff] [blame] | 62 | @Nullable |
dslomov | f129657 | 2017-08-22 16:29:06 +0200 | [diff] [blame] | 63 | @Override |
cparsons | 6c1c066 | 2018-02-05 02:01:28 -0800 | [diff] [blame] | 64 | public Object getValue(String name) throws EvalException { |
adonovan | 29535e0 | 2020-07-28 20:45:35 -0700 | [diff] [blame] | 65 | // TODO(adonovan): this seems unnecessarily complicated: |
| 66 | // Starlark's x.name and getattr(x, name) already check the |
| 67 | // annotated fields/methods first, so there's no need to handle them here. |
| 68 | // Similarly, Starlark.dir checks annotated fields/methods first, so |
| 69 | // there's no need for getFieldNames to report them. |
| 70 | // The only code that would notice any difference is direct Java |
| 71 | // calls to getValue/getField names; they should instead |
| 72 | // use getattr and dir. However, dir does report methods, |
| 73 | // not just fields. |
| 74 | |
gregce | 8345b79 | 2020-05-15 13:23:29 -0700 | [diff] [blame] | 75 | // @StarlarkMethod(structField=true) -- Java field |
adonovan | e71be21 | 2019-12-06 10:07:32 -0800 | [diff] [blame] | 76 | if (getFieldNames().contains(name)) { |
cparsons | 4803293 | 2018-04-18 09:39:02 -0700 | [diff] [blame] | 77 | try { |
adonovan | 29535e0 | 2020-07-28 20:45:35 -0700 | [diff] [blame] | 78 | return Starlark.getAnnotatedField(SEMANTICS, this, name); |
cparsons | 4803293 | 2018-04-18 09:39:02 -0700 | [diff] [blame] | 79 | } catch (InterruptedException exception) { |
| 80 | // Struct fields on NativeInfo objects are supposed to behave well and not throw |
| 81 | // exceptions, as they should be logicless field accessors. If this occurs, it's |
| 82 | // indicative of a bad NativeInfo implementation. |
| 83 | throw new IllegalStateException( |
adonovan | e71be21 | 2019-12-06 10:07:32 -0800 | [diff] [blame] | 84 | String.format( |
| 85 | "Access of field %s was unexpectedly interrupted, but should be " |
| 86 | + "uninterruptible. This is indicative of a bad provider implementation.", |
| 87 | name)); |
cparsons | 4803293 | 2018-04-18 09:39:02 -0700 | [diff] [blame] | 88 | } |
cparsons | 6c1c066 | 2018-02-05 02:01:28 -0800 | [diff] [blame] | 89 | } |
adonovan | e71be21 | 2019-12-06 10:07:32 -0800 | [diff] [blame] | 90 | return null; |
dslomov | f129657 | 2017-08-22 16:29:06 +0200 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | @Override |
brandjon | d331fa7 | 2017-12-28 07:38:31 -0800 | [diff] [blame] | 94 | public ImmutableCollection<String> getFieldNames() { |
adonovan | 29535e0 | 2020-07-28 20:45:35 -0700 | [diff] [blame] | 95 | return Starlark.getAnnotatedFieldNames(SEMANTICS, this); |
dslomov | f129657 | 2017-08-22 16:29:06 +0200 | [diff] [blame] | 96 | } |
dslomov | f129657 | 2017-08-22 16:29:06 +0200 | [diff] [blame] | 97 | } |