1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 /*
 27  * @test
 28  * @modules jdk.incubator.code
 29  * @run testng TestErasure
 30  */
 31 
 32 import static org.testng.Assert.*;
 33 
 34 import org.testng.annotations.*;
 35 
 36 import jdk.incubator.code.type.ArrayType;
 37 import jdk.incubator.code.type.ClassType;
 38 import jdk.incubator.code.type.JavaType;
 39 import jdk.incubator.code.type.PrimitiveType;
 40 import jdk.incubator.code.type.TypeVariableType;
 41 import jdk.incubator.code.type.WildcardType.BoundKind;
 42 import java.util.ArrayList;
 43 import java.util.List;
 44 
 45 @Test
 46 public class TestErasure {
 47 
 48     @Test(dataProvider = "typesAndErasures")
 49     public void testErasure(String testName, TypeAndErasure<?> typeAndErasure) {
 50         assertEquals(typeAndErasure.type.erasure(), typeAndErasure.erasure);
 51         assertEquals(typeAndErasure.type.toBasicType(), typeAndErasure.erasure.toBasicType());
 52         assertEquals(typeAndErasure.type.toNominalDescriptor(), typeAndErasure.erasure.toNominalDescriptor());
 53     }
 54 
 55     @DataProvider
 56     public static Object[][] typesAndErasures() {
 57         List<TypeAndErasure<?>> typeAndErasures = new ArrayList<>();
 58         typeAndErasures.addAll(primitives());
 59         typeAndErasures.addAll(references());
 60         typeAndErasures.addAll(genericReferences());
 61         typeAndErasures.addAll(nestedReferences());
 62         typeAndErasures.addAll(arrays());
 63         typeAndErasures.addAll(typeVars());
 64         return typeAndErasures.stream()
 65                 .map(t -> new Object[] { t.type.toString(), t })
 66                 .toArray(Object[][]::new);
 67     }
 68 
 69     static List<TypeAndErasure<PrimitiveType>> primitives() {
 70         return List.of(
 71                 new TypeAndErasure<>(JavaType.BOOLEAN, JavaType.BOOLEAN),
 72                 new TypeAndErasure<>(JavaType.CHAR, JavaType.CHAR),
 73                 new TypeAndErasure<>(JavaType.BYTE, JavaType.BYTE),
 74                 new TypeAndErasure<>(JavaType.SHORT, JavaType.SHORT),
 75                 new TypeAndErasure<>(JavaType.INT, JavaType.INT),
 76                 new TypeAndErasure<>(JavaType.FLOAT, JavaType.FLOAT),
 77                 new TypeAndErasure<>(JavaType.LONG, JavaType.LONG),
 78                 new TypeAndErasure<>(JavaType.DOUBLE, JavaType.DOUBLE),
 79                 new TypeAndErasure<>(JavaType.VOID, JavaType.VOID));
 80     }
 81 
 82     static List<TypeAndErasure<ClassType>> references() {
 83         return List.of(
 84                 new TypeAndErasure<>(JavaType.J_L_STRING, JavaType.J_L_STRING),
 85                 new TypeAndErasure<>(JavaType.J_L_OBJECT, JavaType.J_L_OBJECT));
 86     }
 87 
 88     static List<TypeAndErasure<ClassType>> genericReferences() {
 89         JavaType LIST = JavaType.type(List.class);
 90         List<TypeAndErasure<ClassType>> genericTypes = new ArrayList<>();
 91         for (JavaType arg : typeArguments()) {
 92             genericTypes.add(new TypeAndErasure<>(JavaType.parameterized(LIST, arg), LIST));
 93         }
 94         return genericTypes;
 95     }
 96 
 97     static List<TypeAndErasure<ClassType>> nestedReferences() {
 98         List<TypeAndErasure<ClassType>> nestedTypes = new ArrayList<>();
 99         ClassType rawCase = JavaType.qualified(JavaType.type(Outer.class), "Inner");
100         nestedTypes.add(new TypeAndErasure<>(rawCase, rawCase));
101         BoundKind[] kinds = new BoundKind[] { null, BoundKind.EXTENDS, BoundKind.SUPER };
102         for (JavaType argOuter : typeArguments()) {
103             for (JavaType argInner : typeArguments()) {
104                 ClassType t = JavaType.parameterized(JavaType.type(Outer.class), argOuter);
105                 t = JavaType.qualified(t, "Inner");
106                 t = JavaType.parameterized(t, argInner);
107                 nestedTypes.add(new TypeAndErasure<>(t, rawCase));
108             }
109         }
110         return nestedTypes;
111     }
112 
113     static List<JavaType> typeArguments() {
114         List<JavaType> typeArgs = new ArrayList<>();
115         BoundKind[] kinds = new BoundKind[] { null, BoundKind.EXTENDS, BoundKind.SUPER };
116         for (BoundKind kind : kinds) {
117             for (TypeAndErasure<ClassType> t : references()) {
118                 JavaType arg = t.type;
119                 if (kind != null) {
120                     arg = JavaType.wildcard(kind, arg);
121                 }
122                 typeArgs.add(arg);
123             }
124             for (TypeAndErasure<PrimitiveType> t : primitives()) {
125                 JavaType arg = JavaType.array(t.type);
126                 if (kind != null) {
127                     arg = JavaType.wildcard(kind, arg);
128                 }
129                 typeArgs.add(arg);
130             }
131         }
132         return typeArgs;
133     }
134 
135     static List<TypeAndErasure<ArrayType>> arrays() {
136         List<TypeAndErasure<ArrayType>> arrayTypes = new ArrayList<>();
137         for (int dims = 1 ; dims <= 3 ; dims++) {
138             for (TypeAndErasure<PrimitiveType> t : primitives()) {
139                 if (t.type.isVoid()) continue; // void is not a valid array component type
140                 arrayTypes.add(new TypeAndErasure<>(JavaType.array(t.type, dims), JavaType.array(t.erasure, dims)));
141             }
142             for (TypeAndErasure<ClassType> t : references()) {
143                 arrayTypes.add(new TypeAndErasure<>(JavaType.array(t.type, dims), JavaType.array(t.erasure, dims)));
144             }
145             for (TypeAndErasure<ClassType> t : genericReferences()) {
146                 arrayTypes.add(new TypeAndErasure<>(JavaType.array(t.type, dims), JavaType.array(t.erasure, dims)));
147             }
148             for (TypeAndErasure<ClassType> t : nestedReferences()) {
149                 arrayTypes.add(new TypeAndErasure<>(JavaType.array(t.type, dims), JavaType.array(t.erasure, dims)));
150             }
151         }
152         return arrayTypes;
153     }
154 
155     static List<TypeAndErasure<TypeVariableType>> typeVars() {
156         List<TypeAndErasure<TypeVariableType>> typeVars = new ArrayList<>();
157         for (int dims = 1 ; dims <= 3 ; dims++) {
158             for (TypeAndErasure<ClassType> t : references()) {
159                 typeVars.add(new TypeAndErasure<>(JavaType.typeVarRef("X", JavaType.J_L_OBJECT, t.type), t.erasure));
160             }
161             for (TypeAndErasure<ClassType> t : genericReferences()) {
162                 typeVars.add(new TypeAndErasure<>(JavaType.typeVarRef("X", JavaType.J_L_OBJECT, t.type), t.erasure));
163             }
164             for (TypeAndErasure<ClassType> t : nestedReferences()) {
165                 typeVars.add(new TypeAndErasure<>(JavaType.typeVarRef("X", JavaType.J_L_OBJECT, t.type), t.erasure));
166             }
167             for (TypeAndErasure<ArrayType> t : arrays()) {
168                 typeVars.add(new TypeAndErasure<>(JavaType.typeVarRef("X", JavaType.J_L_OBJECT, t.type), t.erasure));
169             }
170         }
171         return typeVars;
172     }
173 
174     record TypeAndErasure<T extends JavaType>(T type, JavaType erasure) { }
175 
176     // used for the test
177     static class Outer<X> {
178         class Inner<X> { }
179     }
180 }