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