1 /*
   2  * Copyright (c) 2018, 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 package java.lang.constant;
  26 
  27 import jdk.internal.lang.annotation.Foldable;
  28 
  29 import java.lang.invoke.MethodHandles;
  30 import java.lang.invoke.MethodType;
  31 import java.lang.invoke.TypeDescriptor;
  32 import java.util.List;
  33 import java.util.stream.Collectors;
  34 import java.util.stream.Stream;
  35 
  36 import static java.util.Objects.requireNonNull;
  37 
  38 /**
  39  * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
  40  * {@linkplain MethodType} constant.
  41  *
  42  * @apiNote In the future, if the Java language permits, {@linkplain MethodTypeDesc}
  43  * may become a {@code sealed} interface, which would prohibit subclassing except
  44  * by explicitly permitted types.  Non-platform classes should not implement
  45  * {@linkplain MethodTypeDesc} directly.
  46  *
  47  * @since 12
  48  */
  49 public interface MethodTypeDesc
  50         extends ConstantDesc,
  51                 Constable,
  52                 TypeDescriptor.OfMethod<ClassDesc, MethodTypeDesc> {
  53     /**
  54      * Creates a {@linkplain MethodTypeDesc} given a method descriptor string.
  55      *
  56      * @param descriptor a method descriptor string
  57      * @return a {@linkplain MethodTypeDesc} describing the desired method type
  58      * @throws NullPointerException if any argument is {@code null}
  59      * @throws IllegalArgumentException if the descriptor string is not a valid
  60      * method descriptor
  61      * @jvms 4.3.3 Method Descriptors
  62      */
  63     @Foldable
  64     static MethodTypeDesc ofDescriptor(String descriptor) {
  65         return MethodTypeDescImpl.ofDescriptor(descriptor);
  66     }
  67 
  68     /**
  69      * Returns a {@linkplain MethodTypeDesc} given the return type and parameter
  70      * types.
  71      *
  72      * @param returnDesc a {@linkplain ClassDesc} describing the return type
  73      * @param paramDescs {@linkplain ClassDesc}s describing the argument types
  74      * @return a {@linkplain MethodTypeDesc} describing the desired method type
  75      * @throws NullPointerException if any argument is {@code null}
  76      */
  77     @Foldable
  78     static MethodTypeDesc of(ClassDesc returnDesc, ClassDesc... paramDescs) {
  79         return new MethodTypeDescImpl(returnDesc, paramDescs);
  80     }
  81 
  82     /**
  83      * Gets the return type of the method type described by this {@linkplain MethodTypeDesc}.
  84      *
  85      * @return a {@link ClassDesc} describing the return type of the method type
  86      */
  87     @Foldable
  88     ClassDesc returnType();
  89 
  90     /**
  91      * Returns the number of parameters of the method type described by
  92      * this {@linkplain MethodTypeDesc}.
  93      * @return the number of parameters
  94      */
  95     @Foldable
  96     int parameterCount();
  97 
  98     /**
  99      * Returns the parameter type of the {@code index}'th parameter of the method type
 100      * described by this {@linkplain MethodTypeDesc}.
 101      *
 102      * @param index the index of the parameter to retrieve
 103      * @return a {@link ClassDesc} describing the desired parameter type
 104      * @throws IndexOutOfBoundsException if the index is outside the half-open
 105      * range {[0, parameterCount())}
 106      */
 107     @Foldable
 108     ClassDesc parameterType(int index);
 109 
 110     /**
 111      * Returns the parameter types as an immutable {@link List}.
 112      *
 113      * @return a {@link List} of {@link ClassDesc} describing the parameter types
 114      */
 115     List<ClassDesc> parameterList();
 116 
 117     /**
 118      * Returns the parameter types as an array.
 119      *
 120      * @return an array of {@link ClassDesc} describing the parameter types
 121      */
 122     ClassDesc[] parameterArray();
 123 
 124     /**
 125      * Returns a {@linkplain MethodTypeDesc} that is identical to
 126      * this one, except with the specified return type.
 127      *
 128      * @param returnType a {@link ClassDesc} describing the new return type
 129      * @return a {@linkplain MethodTypeDesc} describing the desired method type
 130      * @throws NullPointerException if any argument is {@code null}
 131      */
 132     @Foldable
 133     MethodTypeDesc changeReturnType(ClassDesc returnType);
 134 
 135     /**
 136      * Returns a {@linkplain MethodTypeDesc} that is identical to this one,
 137      * except that a single parameter type has been changed to the specified type.
 138      *
 139      * @param index the index of the parameter to change
 140      * @param paramType a {@link ClassDesc} describing the new parameter type
 141      * @return a {@linkplain MethodTypeDesc} describing the desired method type
 142      * @throws NullPointerException if any argument is {@code null}
 143      * @throws IndexOutOfBoundsException if the index is outside the half-open
 144      * range {[0, parameterCount)}
 145      */
 146     @Foldable
 147     MethodTypeDesc changeParameterType(int index, ClassDesc paramType);
 148 
 149     /**
 150      * Returns a {@linkplain MethodTypeDesc} that is identical to this one,
 151      * except that a range of parameter types have been removed.
 152      *
 153      * @param start the index of the first parameter to remove
 154      * @param end the index after the last parameter to remove
 155      * @return a {@linkplain MethodTypeDesc} describing the desired method type
 156      * @throws IndexOutOfBoundsException if {@code start} is outside the half-open
 157      * range {[0, parameterCount)}, or {@code end} is outside the closed range
 158      * {@code [0, parameterCount]}
 159      */
 160     @Foldable
 161     MethodTypeDesc dropParameterTypes(int start, int end);
 162 
 163     /**
 164      * Returns a {@linkplain MethodTypeDesc} that is identical to this one,
 165      * except that a range of additional parameter types have been inserted.
 166      *
 167      * @param pos the index at which to insert the first inserted parameter
 168      * @param paramTypes {@link ClassDesc}s describing the new parameter types
 169      *                   to insert
 170      * @return a {@linkplain MethodTypeDesc} describing the desired method type
 171      * @throws NullPointerException if any argument is {@code null}
 172      * @throws IndexOutOfBoundsException if {@code pos} is outside the closed
 173      * range {[0, parameterCount]}
 174      */
 175     @Foldable
 176     MethodTypeDesc insertParameterTypes(int pos, ClassDesc... paramTypes);
 177 
 178     /**
 179      * Returns the method type descriptor string.
 180      *
 181      * @return the method type descriptor string
 182      * @jvms 4.3.3 Method Descriptors
 183      */
 184     default String descriptorString() {
 185         return String.format("(%s)%s",
 186                              Stream.of(parameterArray())
 187                                    .map(ClassDesc::descriptorString)
 188                                    .collect(Collectors.joining()),
 189                              returnType().descriptorString());
 190     }
 191 
 192     /**
 193      * Returns a human-readable descriptor for this method type, using the
 194      * canonical names for parameter and return types.
 195      *
 196      * @return the human-readable descriptor for this method type
 197      */
 198     default String displayDescriptor() {
 199         return String.format("(%s)%s",
 200                              Stream.of(parameterArray())
 201                                    .map(ClassDesc::displayName)
 202                                    .collect(Collectors.joining(",")),
 203                              returnType().displayName());
 204     }
 205 
 206     /**
 207      * Compares the specified object with this descriptor for equality.  Returns
 208      * {@code true} if and only if the specified object is also a
 209      * {@linkplain MethodTypeDesc} both have the same arity, their return types
 210      * are equal, and each pair of corresponding parameter types are equal.
 211      *
 212      * @param o the other object
 213      * @return whether this descriptor is equal to the other object
 214      */
 215     boolean equals(Object o);
 216 }