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  * @run testng TestErasure
 29  */
 30 
 31 import static org.testng.Assert.*;
 32 import org.testng.annotations.*;
 33 
 34 import java.lang.reflect.code.type.ArrayType;
 35 import java.lang.reflect.code.type.ClassType;
 36 import java.lang.reflect.code.type.JavaType;
 37 import java.lang.reflect.code.type.PrimitiveType;
 38 import java.lang.reflect.code.type.TypeVarRef;
 39 import java.lang.reflect.code.type.WildcardType.BoundKind;
 40 import java.util.ArrayList;
 41 import java.util.List;
 42 
 43 @Test
 44 public class TestErasure {
 45 
 46     @Test(dataProvider = "typesAndErasures")
 47     public void testErasure(String testName, TypeAndErasure<?> typeAndErasure) {
 48         assertEquals(typeAndErasure.type.erasure(), typeAndErasure.erasure);
 49         assertEquals(typeAndErasure.type.toBasicType(), typeAndErasure.erasure.toBasicType());
 50         assertEquals(typeAndErasure.type.toNominalDescriptor(), typeAndErasure.erasure.toNominalDescriptor());
 51     }
 52 
 53     @DataProvider
 54     public static Object[][] typesAndErasures() {
 55         List<TypeAndErasure<?>> typeAndErasures = new ArrayList<>();
 56         typeAndErasures.addAll(primitives());
 57         typeAndErasures.addAll(references());
 58         typeAndErasures.addAll(genericReferences());
 59         typeAndErasures.addAll(arrays());
 60         typeAndErasures.addAll(typeVars());
 61         return typeAndErasures.stream()
 62                 .map(t -> new Object[] { t.type.toString(), t })
 63                 .toArray(Object[][]::new);
 64     }
 65 
 66     static List<TypeAndErasure<PrimitiveType>> primitives() {
 67         return List.of(
 68                 new TypeAndErasure<>(JavaType.BOOLEAN, JavaType.BOOLEAN),
 69                 new TypeAndErasure<>(JavaType.CHAR, JavaType.CHAR),
 70                 new TypeAndErasure<>(JavaType.BYTE, JavaType.BYTE),
 71                 new TypeAndErasure<>(JavaType.SHORT, JavaType.SHORT),
 72                 new TypeAndErasure<>(JavaType.INT, JavaType.INT),
 73                 new TypeAndErasure<>(JavaType.FLOAT, JavaType.FLOAT),
 74                 new TypeAndErasure<>(JavaType.LONG, JavaType.LONG),
 75                 new TypeAndErasure<>(JavaType.DOUBLE, JavaType.DOUBLE),
 76                 new TypeAndErasure<>(JavaType.VOID, JavaType.VOID));
 77     }
 78 
 79     static List<TypeAndErasure<ClassType>> references() {
 80         return List.of(
 81                 new TypeAndErasure<>(JavaType.J_L_STRING, JavaType.J_L_STRING),
 82                 new TypeAndErasure<>(JavaType.J_L_OBJECT, JavaType.J_L_OBJECT));
 83     }
 84 
 85     static List<TypeAndErasure<ClassType>> genericReferences() {
 86         JavaType LIST = JavaType.type(List.class);
 87         List<TypeAndErasure<ClassType>> genericTypes = new ArrayList<>();
 88         BoundKind[] kinds = new BoundKind[] { null, BoundKind.EXTENDS, BoundKind.SUPER };
 89         for (BoundKind kind : kinds) {
 90             for (TypeAndErasure<ClassType> t : references()) {
 91                 JavaType arg = t.type;
 92                 if (kind != null) {
 93                     arg = JavaType.wildcard(kind, arg);
 94                 }
 95                 genericTypes.add(new TypeAndErasure<>(JavaType.parameterized(LIST, arg), LIST));
 96             }
 97             for (TypeAndErasure<PrimitiveType> t : primitives()) {
 98                 JavaType arg = JavaType.array(t.type);
 99                 if (kind != null) {
100                     arg = JavaType.wildcard(kind, arg);
101                 }
102                 genericTypes.add(new TypeAndErasure<>(JavaType.parameterized(LIST, arg), LIST));
103             }
104         }
105         return genericTypes;
106     }
107 
108     static List<TypeAndErasure<ArrayType>> arrays() {
109         List<TypeAndErasure<ArrayType>> arrayTypes = new ArrayList<>();
110         for (int dims = 1 ; dims <= 3 ; dims++) {
111             for (TypeAndErasure<PrimitiveType> t : primitives()) {
112                 if (t.type.isVoid()) continue; // void is not a valid array component type
113                 arrayTypes.add(new TypeAndErasure<>(JavaType.array(t.type, dims), JavaType.array(t.erasure, dims)));
114             }
115             for (TypeAndErasure<ClassType> t : references()) {
116                 arrayTypes.add(new TypeAndErasure<>(JavaType.array(t.type, dims), JavaType.array(t.erasure, dims)));
117             }
118             for (TypeAndErasure<ClassType> t : genericReferences()) {
119                 arrayTypes.add(new TypeAndErasure<>(JavaType.array(t.type, dims), JavaType.array(t.erasure, dims)));
120             }
121         }
122         return arrayTypes;
123     }
124 
125     static List<TypeAndErasure<TypeVarRef>> typeVars() {
126         List<TypeAndErasure<TypeVarRef>> typeVars = new ArrayList<>();
127         for (int dims = 1 ; dims <= 3 ; dims++) {
128             for (TypeAndErasure<ClassType> t : references()) {
129                 typeVars.add(new TypeAndErasure<>(JavaType.typeVarRef("X", JavaType.J_L_OBJECT, t.type), t.erasure));
130             }
131             for (TypeAndErasure<ClassType> t : genericReferences()) {
132                 typeVars.add(new TypeAndErasure<>(JavaType.typeVarRef("X", JavaType.J_L_OBJECT, t.type), t.erasure));
133             }
134             for (TypeAndErasure<ArrayType> t : arrays()) {
135                 typeVars.add(new TypeAndErasure<>(JavaType.typeVarRef("X", JavaType.J_L_OBJECT, t.type), t.erasure));
136             }
137         }
138         return typeVars;
139     }
140 
141     record TypeAndErasure<T extends JavaType>(T type, JavaType erasure) { }
142 }