blob: 26821b0bafecbdaf1c872488124a065a8882f34b [file] [log] [blame]
cparsons2415cb42018-05-01 10:32:30 -07001// Copyright 2018 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.
14package com.google.devtools.build.lib.packages;
15
16import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
nharmata55d2da32020-11-18 16:17:04 -080017import com.google.devtools.build.lib.util.Fingerprint;
cparsons2415cb42018-05-01 10:32:30 -070018import javax.annotation.Nullable;
adonovan450c7ad2020-09-14 13:00:21 -070019import net.starlark.java.eval.Printer;
adonovan450c7ad2020-09-14 13:00:21 -070020import net.starlark.java.syntax.Location;
cparsons2415cb42018-05-01 10:32:30 -070021
22/**
adonovandd000462020-11-06 12:57:38 -080023 * Base class for declared providers {@see Provider} built into Blaze.
cparsons2415cb42018-05-01 10:32:30 -070024 *
adonovandd000462020-11-06 12:57:38 -080025 * <p>Every subclass of {@link BuiltinProvider} should have exactly one instance. If multiple
26 * instances of the same subclass are instantiated, they are considered equivalent. This design is
27 * motivated by the need for serialization. Starlark providers are readily identified by the pair
28 * (.bzl file name, sequence number during execution). BuiltinProviders need an analogous
29 * serializable identifier, yet JVM classes (notoriously) don't have a predictable initialization
30 * order, so we can't use a sequence number. A distinct subclass for each built-in provider acts as
31 * that identifier.
cparsons2415cb42018-05-01 10:32:30 -070032 *
33 * <p>Implementations of native declared providers should subclass this class, and define a method
34 * in the subclass definition to create instances of its corresponding Info object. The method
gregce8345b792020-05-15 13:23:29 -070035 * should be annotated with {@link StarlarkMethod} with {@link StarlarkMethod#selfCall} set to true,
36 * and with {@link StarlarkConstructor} for the info type it constructs.
cparsons2415cb42018-05-01 10:32:30 -070037 */
38@Immutable
adonovana11e2d02019-12-06 07:11:35 -080039public abstract class BuiltinProvider<T extends Info> implements Provider {
adonovandd000462020-11-06 12:57:38 -080040 private final Key key;
cparsons2415cb42018-05-01 10:32:30 -070041 private final String name;
42 private final Class<T> valueClass;
43
jhorvitz9302ebd2021-06-28 11:09:06 -070044 protected BuiltinProvider(String name, Class<T> valueClass) {
adonovandd000462020-11-06 12:57:38 -080045 this.key = new Key(name, getClass());
46 this.name = name;
47 this.valueClass = valueClass;
48 }
49
cparsons2415cb42018-05-01 10:32:30 -070050 public Class<T> getValueClass() {
51 return valueClass;
52 }
53
cparsons2415cb42018-05-01 10:32:30 -070054 /**
adonovandd000462020-11-06 12:57:38 -080055 * Defines the equivalence relation: all BuiltinProviders of the same Java class are equal,
56 * regardless of {@code name} or {@code valueClass}.
cparsons2415cb42018-05-01 10:32:30 -070057 */
58 @Override
59 public final boolean equals(@Nullable Object other) {
60 return other != null && this.getClass().equals(other.getClass());
61 }
62
cparsons2415cb42018-05-01 10:32:30 -070063 @Override
64 public final int hashCode() {
65 return getClass().hashCode();
66 }
67
68 @Override
69 public boolean isExported() {
70 return true;
71 }
72
73 @Override
adonovandd000462020-11-06 12:57:38 -080074 public Key getKey() {
cparsons2415cb42018-05-01 10:32:30 -070075 return key;
76 }
77
78 @Override
79 public Location getLocation() {
80 return Location.BUILTIN;
81 }
82
83 @Override
84 public String getPrintableName() {
85 return name;
86 }
87
88 @Override
Googler34f70582019-11-25 12:27:34 -080089 public void repr(Printer printer) {
adonovandd000462020-11-06 12:57:38 -080090 // TODO(adonovan): change to '<provider name>'.
jhorvitz9302ebd2021-06-28 11:09:06 -070091 printer.append("<function " + name + ">");
cparsons2415cb42018-05-01 10:32:30 -070092 }
cparsonsabeb8512018-06-11 12:44:06 -070093
gregce74d84d42020-04-17 10:02:03 -070094 /** Returns the identifier of this provider. */
95 public StarlarkProviderIdentifier id() {
jhorvitz9302ebd2021-06-28 11:09:06 -070096 return StarlarkProviderIdentifier.forKey(key);
cparsons075ab1e2018-08-07 14:20:20 -070097 }
adonovandd000462020-11-06 12:57:38 -080098
99 /**
100 * Implement this to mark that a built-in provider should be exported with certain name to
101 * Starlark. Broken: only works for rules, not for aspects. DO NOT USE FOR NEW CODE!
102 *
103 * @deprecated Use declared providers mechanism exclusively to expose providers to both native and
104 * Starlark code.
105 */
106 @Deprecated
107 public interface WithLegacyStarlarkName {
108 String getStarlarkName();
109 }
110
111 /** A serializable reference to a {@link BuiltinProvider}. */
adonovandd000462020-11-06 12:57:38 -0800112 @Immutable
113 public static final class Key extends Provider.Key {
114 private final String name;
115 private final Class<? extends Provider> providerClass;
116
117 public Key(String name, Class<? extends Provider> providerClass) {
118 this.name = name;
119 this.providerClass = providerClass;
120 }
121
122 public String getName() {
123 return name;
124 }
125
126 public Class<? extends Provider> getProviderClass() {
127 return providerClass;
128 }
129
130 @Override
nharmata55d2da32020-11-18 16:17:04 -0800131 void fingerprint(Fingerprint fp) {
132 // True => native
133 fp.addBoolean(true);
134 fp.addString(name);
135 }
136
137 @Override
adonovandd000462020-11-06 12:57:38 -0800138 public int hashCode() {
139 return providerClass.hashCode();
140 }
141
142 @Override
143 public boolean equals(Object obj) {
144 return obj instanceof Key && providerClass.equals(((Key) obj).providerClass);
145 }
146
147 @Override
148 public String toString() {
149 return name;
150 }
151 }
cparsons2415cb42018-05-01 10:32:30 -0700152}