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 jdk.incubator.code.dialect.java;
 27 
 28 import java.lang.constant.ClassDesc;
 29 import java.lang.constant.MethodTypeDesc;
 30 
 31 import jdk.incubator.code.dialect.core.CoreType;
 32 import jdk.incubator.code.dialect.java.impl.MethodRefImpl;
 33 import java.lang.invoke.MethodHandle;
 34 import java.lang.invoke.MethodHandles;
 35 import java.lang.invoke.MethodType;
 36 import java.lang.reflect.Method;
 37 import jdk.incubator.code.TypeElement;
 38 import jdk.incubator.code.dialect.core.FunctionType;
 39 
 40 import java.util.List;
 41 
 42 import static jdk.incubator.code.dialect.core.CoreType.functionType;
 43 
 44 /**
 45  * The symbolic reference to a Java method.
 46  */
 47 public sealed interface MethodRef extends JavaRef, TypeVariableType.Owner
 48         permits MethodRefImpl {
 49 
 50     TypeElement refType();
 51 
 52     String name();
 53 
 54     FunctionType type();
 55 
 56     // Resolutions to methods and method handles
 57 
 58     // Resolve to static or instance method declared on referenced class
 59     Method resolveToDirectMethod(MethodHandles.Lookup l) throws ReflectiveOperationException;
 60 
 61     // Resolve to static or instance method declared on referenced class
 62     MethodHandle resolveToDirectHandle(MethodHandles.Lookup l) throws ReflectiveOperationException;
 63 
 64     Method resolveToMethod(MethodHandles.Lookup l, JavaOp.InvokeOp.InvokeKind kind) throws ReflectiveOperationException;
 65 
 66     // For InvokeKind.SUPER the specialCaller == l.lookupClass() for Lookup::findSpecial
 67     MethodHandle resolveToHandle(MethodHandles.Lookup l, JavaOp.InvokeOp.InvokeKind kind) throws ReflectiveOperationException;
 68 
 69     // Factories
 70 
 71     static MethodRef method(Method m) {
 72         return method(m.getDeclaringClass(), m.getName(),
 73                 m.getReturnType(),
 74                 m.getParameterTypes());
 75     }
 76 
 77     static MethodRef method(Class<?> refType, String name, MethodType mt) {
 78         return method(refType, name, mt.returnType(), mt.parameterList());
 79     }
 80 
 81     static MethodRef method(Class<?> refType, String name, Class<?> retType, Class<?>... params) {
 82         return method(refType, name, retType, List.of(params));
 83     }
 84 
 85     static MethodRef method(Class<?> refType, String name, Class<?> retType, List<Class<?>> params) {
 86         return method(JavaType.type(refType), name, JavaType.type(retType), params.stream().map(JavaType::type).toList());
 87     }
 88 
 89 
 90     static MethodRef method(TypeElement refType, String name, FunctionType type) {
 91         return new MethodRefImpl(refType, name, type);
 92     }
 93 
 94     static MethodRef method(TypeElement refType, String name, TypeElement retType, TypeElement... params) {
 95         return method(refType, name, functionType(retType, params));
 96     }
 97 
 98     static MethodRef method(TypeElement refType, String name, TypeElement retType, List<? extends TypeElement> params) {
 99         return method(refType, name, functionType(retType, params));
100     }
101 
102 
103     // MethodTypeDesc factories
104     // @@@ Where else to place them?
105 
106     static FunctionType ofNominalDescriptor(MethodTypeDesc d) {
107         return CoreType.functionType(
108                 JavaType.type(d.returnType()),
109                 d.parameterList().stream().map(JavaType::type).toList());
110     }
111 
112     static MethodTypeDesc toNominalDescriptor(FunctionType t) {
113         return MethodTypeDesc.of(
114                 toClassDesc(t.returnType()),
115                 t.parameterTypes().stream().map(MethodRef::toClassDesc).toList());
116     }
117 
118     private static ClassDesc toClassDesc(TypeElement e) {
119         if (!(e instanceof JavaType jt)) {
120             throw new IllegalArgumentException();
121         }
122 
123         return jt.toNominalDescriptor();
124     }
125 }