blob: 33f430ca8045204953a8c02c8c68bf88a86130ba [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;
adonovandd000462020-11-06 12:57:38 -080017import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
nharmata55d2da32020-11-18 16:17:04 -080018import com.google.devtools.build.lib.util.Fingerprint;
cparsons2415cb42018-05-01 10:32:30 -070019import javax.annotation.Nullable;
adonovan450c7ad2020-09-14 13:00:21 -070020import net.starlark.java.eval.Printer;
adonovan450c7ad2020-09-14 13:00:21 -070021import net.starlark.java.syntax.Location;
cparsons2415cb42018-05-01 10:32:30 -070022
23/**
adonovandd000462020-11-06 12:57:38 -080024 * Base class for declared providers {@see Provider} built into Blaze.
cparsons2415cb42018-05-01 10:32:30 -070025 *
adonovandd000462020-11-06 12:57:38 -080026 * <p>Every subclass of {@link BuiltinProvider} should have exactly one instance. If multiple
27 * instances of the same subclass are instantiated, they are considered equivalent. This design is
28 * motivated by the need for serialization. Starlark providers are readily identified by the pair
29 * (.bzl file name, sequence number during execution). BuiltinProviders need an analogous
30 * serializable identifier, yet JVM classes (notoriously) don't have a predictable initialization
31 * order, so we can't use a sequence number. A distinct subclass for each built-in provider acts as
32 * that identifier.
cparsons2415cb42018-05-01 10:32:30 -070033 *
34 * <p>Implementations of native declared providers should subclass this class, and define a method
35 * in the subclass definition to create instances of its corresponding Info object. The method
gregce8345b792020-05-15 13:23:29 -070036 * should be annotated with {@link StarlarkMethod} with {@link StarlarkMethod#selfCall} set to true,
37 * and with {@link StarlarkConstructor} for the info type it constructs.
cparsons2415cb42018-05-01 10:32:30 -070038 */
39@Immutable
adonovana11e2d02019-12-06 07:11:35 -080040public abstract class BuiltinProvider<T extends Info> implements Provider {
adonovandd000462020-11-06 12:57:38 -080041 private final Key key;
cparsons2415cb42018-05-01 10:32:30 -070042 private final String name;
43 private final Class<T> valueClass;
44
adonovandd000462020-11-06 12:57:38 -080045 public BuiltinProvider(String name, Class<T> valueClass) {
46 this.key = new Key(name, getClass());
47 this.name = name;
48 this.valueClass = valueClass;
49 }
50
cparsons2415cb42018-05-01 10:32:30 -070051 public Class<T> getValueClass() {
52 return valueClass;
53 }
54
cparsons2415cb42018-05-01 10:32:30 -070055 /**
adonovandd000462020-11-06 12:57:38 -080056 * Defines the equivalence relation: all BuiltinProviders of the same Java class are equal,
57 * regardless of {@code name} or {@code valueClass}.
cparsons2415cb42018-05-01 10:32:30 -070058 */
59 @Override
60 public final boolean equals(@Nullable Object other) {
61 return other != null && this.getClass().equals(other.getClass());
62 }
63
cparsons2415cb42018-05-01 10:32:30 -070064 @Override
65 public final int hashCode() {
66 return getClass().hashCode();
67 }
68
69 @Override
70 public boolean isExported() {
71 return true;
72 }
73
74 @Override
adonovandd000462020-11-06 12:57:38 -080075 public Key getKey() {
cparsons2415cb42018-05-01 10:32:30 -070076 return key;
77 }
78
79 @Override
80 public Location getLocation() {
81 return Location.BUILTIN;
82 }
83
84 @Override
85 public String getPrintableName() {
86 return name;
87 }
88
89 @Override
Googler34f70582019-11-25 12:27:34 -080090 public void repr(Printer printer) {
adonovandd000462020-11-06 12:57:38 -080091 // TODO(adonovan): change to '<provider name>'.
cparsons2415cb42018-05-01 10:32:30 -070092 printer.append("<function " + getPrintableName() + ">");
93 }
cparsonsabeb8512018-06-11 12:44:06 -070094
gregce74d84d42020-04-17 10:02:03 -070095 /** Returns the identifier of this provider. */
96 public StarlarkProviderIdentifier id() {
97 return StarlarkProviderIdentifier.forKey(getKey());
cparsons075ab1e2018-08-07 14:20:20 -070098 }
adonovandd000462020-11-06 12:57:38 -080099
100 /**
101 * Implement this to mark that a built-in provider should be exported with certain name to
102 * Starlark. Broken: only works for rules, not for aspects. DO NOT USE FOR NEW CODE!
103 *
104 * @deprecated Use declared providers mechanism exclusively to expose providers to both native and
105 * Starlark code.
106 */
107 @Deprecated
108 public interface WithLegacyStarlarkName {
109 String getStarlarkName();
110 }
111
112 /** A serializable reference to a {@link BuiltinProvider}. */
113 @AutoCodec
114 @Immutable
115 public static final class Key extends Provider.Key {
116 private final String name;
117 private final Class<? extends Provider> providerClass;
118
119 public Key(String name, Class<? extends Provider> providerClass) {
120 this.name = name;
121 this.providerClass = providerClass;
122 }
123
124 public String getName() {
125 return name;
126 }
127
128 public Class<? extends Provider> getProviderClass() {
129 return providerClass;
130 }
131
132 @Override
nharmata55d2da32020-11-18 16:17:04 -0800133 void fingerprint(Fingerprint fp) {
134 // True => native
135 fp.addBoolean(true);
136 fp.addString(name);
137 }
138
139 @Override
adonovandd000462020-11-06 12:57:38 -0800140 public int hashCode() {
141 return providerClass.hashCode();
142 }
143
144 @Override
145 public boolean equals(Object obj) {
146 return obj instanceof Key && providerClass.equals(((Key) obj).providerClass);
147 }
148
149 @Override
150 public String toString() {
151 return name;
152 }
153 }
cparsons2415cb42018-05-01 10:32:30 -0700154}