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 package java.lang.reflect.code.type;
 27 
 28 import java.lang.constant.ClassDesc;
 29 import java.lang.invoke.MethodHandles.Lookup;
 30 import java.lang.reflect.Array;
 31 import java.lang.reflect.GenericArrayType;
 32 import java.lang.reflect.Type;
 33 import java.lang.reflect.code.TypeElement;
 34 import java.util.List;
 35 
 36 /**
 37  * An array type.
 38  */
 39 public final class ArrayType implements JavaType {
 40 
 41     final JavaType componentType;
 42 
 43     ArrayType(JavaType componentType) {
 44         this.componentType = componentType;
 45     }
 46 
 47     @Override
 48     public Type resolve(Lookup lookup) throws ReflectiveOperationException {
 49         Type resolvedComponent = componentType.resolve(lookup);
 50         if (resolvedComponent instanceof Class<?> resolvedComponentClass) {
 51             return resolvedComponentClass.arrayType();
 52         } else { // generic array
 53             return makeReflectiveGenericArray(resolvedComponent);
 54         }
 55     }
 56 
 57     // Copied code in jdk.compiler module throws UOE
 58     private static GenericArrayType makeReflectiveGenericArray(Type component) {
 59 /*__throw new UnsupportedOperationException();__*/        return sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl.make(component);
 60     }
 61 
 62     /**
 63      * {@return the array type's component type}
 64      */
 65     public JavaType componentType() {
 66         return componentType;
 67     }
 68 
 69     /**
 70      * {@return the dimensions associated with this array type}
 71      */
 72     public int dimensions() {
 73         int dims = 0;
 74         JavaType current = this;
 75         while (current instanceof ArrayType at) {
 76             dims++;
 77             current = at.componentType();
 78         }
 79         return dims;
 80     }
 81 
 82     @Override
 83     public ExternalizedTypeElement externalize() {
 84         int dims = 0;
 85         TypeElement current = this;
 86         while (current instanceof ArrayType at) {
 87             dims++;
 88             current = at.componentType();
 89         }
 90         return new ExternalizedTypeElement("[".repeat(dims), List.of(current.externalize()));
 91     }
 92 
 93     @Override
 94     public String toString() {
 95         return externalize().toString();
 96     }
 97 
 98     @Override
 99     public boolean equals(Object o) {
100         if (this == o) return true;
101         return o instanceof ArrayType that &&
102                 componentType.equals(that.componentType);
103     }
104 
105     @Override
106     public int hashCode() {
107         return 17 * componentType.hashCode();
108     }
109 
110     @Override
111     public JavaType erasure() {
112         return JavaType.array(componentType.erasure());
113     }
114 
115     @Override
116     public JavaType toBasicType() {
117         return JavaType.J_L_OBJECT;
118     }
119 
120     @Override
121     public ClassDesc toNominalDescriptor() {
122         return componentType.toNominalDescriptor().arrayType();
123     }
124 }