|
1 | 1 | package com.uber.nullaway.generics; |
2 | 2 |
|
3 | 3 | import static com.uber.nullaway.NullabilityUtil.castToNonNull; |
| 4 | +import static com.uber.nullaway.generics.TypeMetadataBuilder.TYPE_METADATA_BUILDER; |
4 | 5 |
|
5 | 6 | import com.google.errorprone.util.ASTHelpers; |
6 | 7 | import com.sun.source.tree.AnnotatedTypeTree; |
|
14 | 15 | import com.sun.tools.javac.code.Symbol; |
15 | 16 | import com.sun.tools.javac.code.Type; |
16 | 17 | import com.sun.tools.javac.code.TypeMetadata; |
17 | | -import com.sun.tools.javac.util.ListBuffer; |
18 | 18 | import com.uber.nullaway.Config; |
19 | 19 | import com.uber.nullaway.Nullness; |
20 | | -import java.lang.invoke.MethodHandle; |
21 | | -import java.lang.invoke.MethodHandles; |
22 | | -import java.lang.invoke.MethodType; |
23 | 20 | import java.util.ArrayList; |
24 | 21 | import java.util.Collections; |
25 | 22 | import java.util.List; |
@@ -58,7 +55,8 @@ public Type visitParameterizedType(ParameterizedTypeTree tree, Void p) { |
58 | 55 | for (int i = 0; i < typeArguments.size(); i++) { |
59 | 56 | newTypeArgs.add(typeArguments.get(i).accept(this, null)); |
60 | 57 | } |
61 | | - Type finalType = TYPE_METADATA_BUILDER.createWithBaseTypeAndTypeArgs(baseType, newTypeArgs); |
| 58 | + Type finalType = |
| 59 | + TYPE_METADATA_BUILDER.createClassType(baseType, baseType.getEnclosingType(), newTypeArgs); |
62 | 60 | return finalType; |
63 | 61 | } |
64 | 62 |
|
@@ -97,181 +95,4 @@ public Type visitAnnotatedType(AnnotatedTypeTree annotatedType, Void unused) { |
97 | 95 | protected Type defaultAction(Tree node, Void unused) { |
98 | 96 | return castToNonNull(ASTHelpers.getType(node)); |
99 | 97 | } |
100 | | - |
101 | | - /** |
102 | | - * Abstracts over the different APIs for building {@link TypeMetadata} objects in different JDK |
103 | | - * versions. |
104 | | - */ |
105 | | - private interface TypeMetadataBuilder { |
106 | | - TypeMetadata create(com.sun.tools.javac.util.List<Attribute.TypeCompound> attrs); |
107 | | - |
108 | | - Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metaData); |
109 | | - |
110 | | - Type createWithBaseTypeAndTypeArgs(Type baseType, List<Type> typeArgs); |
111 | | - } |
112 | | - |
113 | | - /** |
114 | | - * Provides implementations for methods under TypeMetadataBuilder compatible with JDK 17 and |
115 | | - * earlier versions. |
116 | | - */ |
117 | | - private static class JDK17AndEarlierTypeMetadataBuilder implements TypeMetadataBuilder { |
118 | | - |
119 | | - @Override |
120 | | - public TypeMetadata create(com.sun.tools.javac.util.List<Attribute.TypeCompound> attrs) { |
121 | | - return new TypeMetadata(new TypeMetadata.Annotations(attrs)); |
122 | | - } |
123 | | - |
124 | | - /** |
125 | | - * Clones the given type with the specified Metadata for getting the right nullability |
126 | | - * annotations. |
127 | | - * |
128 | | - * @param typeToBeCloned The Type we want to clone with the required Nullability Metadata |
129 | | - * @param metadata The required Nullability metadata which is lost from the type |
130 | | - * @return Type after it has been cloned by applying the required Nullability metadata |
131 | | - */ |
132 | | - @Override |
133 | | - public Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metadata) { |
134 | | - return typeToBeCloned.cloneWithMetadata(metadata); |
135 | | - } |
136 | | - |
137 | | - @Override |
138 | | - public Type createWithBaseTypeAndTypeArgs(Type baseType, List<Type> typeArgs) { |
139 | | - return new Type.ClassType( |
140 | | - baseType.getEnclosingType(), |
141 | | - com.sun.tools.javac.util.List.from(typeArgs), |
142 | | - baseType.tsym, |
143 | | - baseType.getMetadata()); |
144 | | - } |
145 | | - } |
146 | | - |
147 | | - /** |
148 | | - * Provides implementations for methods under TypeMetadataBuilder compatible with the updates made |
149 | | - * to the library methods for Jdk 21. The implementation calls the logic specific to JDK 21 |
150 | | - * indirectly using MethodHandles since we still need the code to compile on earlier versions. |
151 | | - */ |
152 | | - private static class JDK21TypeMetadataBuilder implements TypeMetadataBuilder { |
153 | | - |
154 | | - private static final MethodHandle typeMetadataConstructorHandle = createHandle(); |
155 | | - private static final MethodHandle addMetadataHandle = |
156 | | - createVirtualMethodHandle(Type.class, TypeMetadata.class, Type.class, "addMetadata"); |
157 | | - private static final MethodHandle dropMetadataHandle = |
158 | | - createVirtualMethodHandle(Type.class, Class.class, Type.class, "dropMetadata"); |
159 | | - private static final MethodHandle getMetadataHandler = createGetMetadataHandle(); |
160 | | - private static final MethodHandle classTypeConstructorHandle = |
161 | | - createClassTypeConstructorHandle(); |
162 | | - |
163 | | - private static MethodHandle createHandle() { |
164 | | - MethodHandles.Lookup lookup = MethodHandles.lookup(); |
165 | | - MethodType mt = MethodType.methodType(void.class, com.sun.tools.javac.util.ListBuffer.class); |
166 | | - try { |
167 | | - return lookup.findConstructor(TypeMetadata.Annotations.class, mt); |
168 | | - } catch (NoSuchMethodException e) { |
169 | | - throw new RuntimeException(e); |
170 | | - } catch (IllegalAccessException e) { |
171 | | - throw new RuntimeException(e); |
172 | | - } |
173 | | - } |
174 | | - |
175 | | - private static MethodHandle createGetMetadataHandle() { |
176 | | - MethodHandles.Lookup lookup = MethodHandles.lookup(); |
177 | | - MethodType mt = MethodType.methodType(com.sun.tools.javac.util.List.class); |
178 | | - try { |
179 | | - return lookup.findVirtual(Type.class, "getMetadata", mt); |
180 | | - } catch (NoSuchMethodException | IllegalAccessException e) { |
181 | | - throw new RuntimeException(e); |
182 | | - } |
183 | | - } |
184 | | - |
185 | | - private static MethodHandle createClassTypeConstructorHandle() { |
186 | | - try { |
187 | | - MethodHandles.Lookup lookup = MethodHandles.lookup(); |
188 | | - MethodType methodType = |
189 | | - MethodType.methodType( |
190 | | - void.class, // return type for a constructor is void |
191 | | - Type.class, |
192 | | - com.sun.tools.javac.util.List.class, |
193 | | - Symbol.TypeSymbol.class, |
194 | | - com.sun.tools.javac.util.List.class); |
195 | | - return lookup.findConstructor(Type.ClassType.class, methodType); |
196 | | - } catch (NoSuchMethodException | IllegalAccessException e) { |
197 | | - throw new RuntimeException(e); |
198 | | - } |
199 | | - } |
200 | | - |
201 | | - /** |
202 | | - * Used to get a MethodHandle for a virtual method from the specified class |
203 | | - * |
204 | | - * @param retTypeClass Class to indicate the return type of the desired method |
205 | | - * @param paramTypeClass Class to indicate the parameter type of the desired method |
206 | | - * @param refClass Class within which the desired method is contained |
207 | | - * @param methodName Name of the desired method |
208 | | - * @return The appropriate MethodHandle for the virtual method |
209 | | - */ |
210 | | - private static MethodHandle createVirtualMethodHandle( |
211 | | - Class<?> retTypeClass, Class<?> paramTypeClass, Class<?> refClass, String methodName) { |
212 | | - MethodHandles.Lookup lookup = MethodHandles.lookup(); |
213 | | - MethodType mt = MethodType.methodType(retTypeClass, paramTypeClass); |
214 | | - try { |
215 | | - return lookup.findVirtual(refClass, methodName, mt); |
216 | | - } catch (NoSuchMethodException e) { |
217 | | - throw new RuntimeException(e); |
218 | | - } catch (IllegalAccessException e) { |
219 | | - throw new RuntimeException(e); |
220 | | - } |
221 | | - } |
222 | | - |
223 | | - @Override |
224 | | - public TypeMetadata create(com.sun.tools.javac.util.List<Attribute.TypeCompound> attrs) { |
225 | | - ListBuffer<Attribute.TypeCompound> b = new ListBuffer<>(); |
226 | | - b.appendList(attrs); |
227 | | - try { |
228 | | - return (TypeMetadata) typeMetadataConstructorHandle.invoke(b); |
229 | | - } catch (Throwable e) { |
230 | | - throw new RuntimeException(e); |
231 | | - } |
232 | | - } |
233 | | - |
234 | | - /** |
235 | | - * Calls dropMetadata and addMetadata using MethodHandles for JDK 21, which removed the previous |
236 | | - * cloneWithMetadata method. |
237 | | - * |
238 | | - * @param typeToBeCloned The Type we want to clone with the required Nullability metadata |
239 | | - * @param metadata The required Nullability metadata |
240 | | - * @return Cloned Type with the necessary Nullability metadata |
241 | | - */ |
242 | | - @Override |
243 | | - public Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metadata) { |
244 | | - try { |
245 | | - // In JDK 21 addMetadata works if there is no metadata associated with the type, so we |
246 | | - // create a copy without the existing metadata first and then add it |
247 | | - Type clonedTypeWithoutMetadata = |
248 | | - (Type) dropMetadataHandle.invoke(typeToBeCloned, metadata.getClass()); |
249 | | - return (Type) addMetadataHandle.invoke(clonedTypeWithoutMetadata, metadata); |
250 | | - } catch (Throwable e) { |
251 | | - throw new RuntimeException(e); |
252 | | - } |
253 | | - } |
254 | | - |
255 | | - @Override |
256 | | - public Type createWithBaseTypeAndTypeArgs(Type baseType, List<Type> typeArgs) { |
257 | | - try { |
258 | | - com.sun.tools.javac.util.List<TypeMetadata> metadata = |
259 | | - (com.sun.tools.javac.util.List<TypeMetadata>) getMetadataHandler.invoke(baseType); |
260 | | - return (Type) |
261 | | - classTypeConstructorHandle.invoke( |
262 | | - baseType.getEnclosingType(), |
263 | | - com.sun.tools.javac.util.List.from(typeArgs), |
264 | | - baseType.tsym, |
265 | | - metadata); |
266 | | - } catch (Throwable e) { |
267 | | - throw new RuntimeException(e); |
268 | | - } |
269 | | - } |
270 | | - } |
271 | | - |
272 | | - /** The TypeMetadataBuilder to be used for the current JDK version. */ |
273 | | - private static final TypeMetadataBuilder TYPE_METADATA_BUILDER = |
274 | | - Runtime.version().feature() >= 21 |
275 | | - ? new JDK21TypeMetadataBuilder() |
276 | | - : new JDK17AndEarlierTypeMetadataBuilder(); |
277 | 98 | } |
0 commit comments