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.Executable;
 31 import java.lang.reflect.Type;
 32 import java.lang.reflect.TypeVariable;
 33 import java.util.List;
 34 
 35 /**
 36  * A type-variable reference.
 37  */
 38 public final class TypeVarRef implements JavaType {
 39 
 40     final String name;
 41     final Owner owner;
 42     final JavaType bound;
 43 
 44     TypeVarRef(String name, Owner owner, JavaType bound) {
 45         this.name = name;
 46         this.owner = owner;
 47         this.bound = bound;
 48     }
 49 
 50     @Override
 51     public Type resolve(Lookup lookup) throws ReflectiveOperationException {
 52         TypeVariable<?>[] typeVariables = switch (owner) {
 53             case MethodRef methodRef -> {
 54                 Executable method = ((MethodRef)owner).resolveToMember(lookup);
 55                 yield method.getTypeParameters();
 56             }
 57             case JavaType type -> {
 58                 Class<?> erasedDecl = (Class<?>)type.resolve(lookup);
 59                 yield erasedDecl.getTypeParameters();
 60             }
 61         };
 62         for (TypeVariable<?> tv : typeVariables) {
 63             if (tv.getName().equals(name)) {
 64                 return tv;
 65             }
 66         }
 67         throw new ReflectiveOperationException("Type-variable not found: " + name);
 68     }
 69 
 70     /**
 71      * {@return the type-variable name}
 72      */
 73     public String name() {
 74         return name;
 75     }
 76 
 77     /**
 78      * {@return the type-variable bound}
 79      */
 80     public JavaType bound() {
 81         return bound;
 82     }
 83 
 84     /**
 85      * {@return the owner of this type-variable}
 86      */
 87     public Owner owner() {
 88         return owner;
 89     }
 90 
 91     @Override
 92     public JavaType erasure() {
 93         return bound.erasure();
 94     }
 95 
 96     @Override
 97     public ExternalizedTypeElement externalize() {
 98         return new ExternalizedTypeElement(String.format("#%s::%s", owner, name),
 99                 List.of(bound.externalize()));
100     }
101 
102     @Override
103     public String toString() {
104         return externalize().toString();
105     }
106 
107     @Override
108     public boolean equals(Object o) {
109         if (this == o) return true;
110         return o instanceof TypeVarRef that &&
111                 name.equals(that.name) &&
112                 bound.equals(that.bound);
113     }
114 
115     @Override
116     public int hashCode() {
117         return name.hashCode();
118     }
119 
120     @Override
121     public JavaType toBasicType() {
122         return erasure().toBasicType();
123     }
124 
125     @Override
126     public ClassDesc toNominalDescriptor() {
127         return erasure().toNominalDescriptor();
128     }
129 
130     /**
131      * The owner of a type-variable - either a class or a method.
132      */
133     public sealed interface Owner permits ClassType, MethodRef { }
134 }