View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit.internal.reflection;
7   
8   import static mockit.internal.reflection.MethodReflection.JAVA_LANG;
9   import static mockit.internal.util.Utilities.JAVA8;
10  
11  import edu.umd.cs.findbugs.annotations.NonNull;
12  
13  import java.lang.reflect.Method;
14  
15  import mockit.Invocation;
16  import mockit.internal.util.AutoBoxing;
17  import mockit.internal.util.GeneratedClasses;
18  
19  import org.checkerframework.checker.index.qual.NonNegative;
20  
21  public final class ParameterReflection {
22      @NonNull
23      public static final Class<?>[] NO_PARAMETERS = {};
24  
25      private ParameterReflection() {
26      }
27  
28      @NonNull
29      static String getParameterTypesDescription(@NonNull Class<?>[] paramTypes) {
30          StringBuilder paramTypesDesc = new StringBuilder(200);
31          paramTypesDesc.append('(');
32  
33          String sep = "";
34  
35          for (Class<?> paramType : paramTypes) {
36              String typeName = JAVA_LANG.matcher(paramType.getCanonicalName()).replaceAll("");
37              paramTypesDesc.append(sep).append(typeName);
38              sep = ", ";
39          }
40  
41          paramTypesDesc.append(')');
42          return paramTypesDesc.toString();
43      }
44  
45      @NonNull
46      public static Class<?>[] getArgumentTypesFromArgumentValues(@NonNull Object... args) {
47          if (args.length == 0) {
48              return NO_PARAMETERS;
49          }
50  
51          Class<?>[] argTypes = new Class<?>[args.length];
52  
53          for (int i = 0; i < args.length; i++) {
54              argTypes[i] = getArgumentTypeFromArgumentValue(i, args);
55          }
56  
57          return argTypes;
58      }
59  
60      @NonNull
61      private static Class<?> getArgumentTypeFromArgumentValue(int i, @NonNull Object[] args) {
62          Object arg = args[i];
63  
64          if (arg == null) {
65              throw new IllegalArgumentException("Invalid null value passed as argument " + i);
66          }
67  
68          Class<?> argType;
69  
70          if (arg instanceof Class<?>) {
71              argType = (Class<?>) arg;
72              args[i] = null;
73          } else {
74              argType = GeneratedClasses.getMockedClass(arg);
75          }
76  
77          return argType;
78      }
79  
80      @NonNull
81      public static Object[] argumentsWithExtraFirstValue(@NonNull Object[] args, @NonNull Object firstValue) {
82          Object[] args2 = new Object[1 + args.length];
83          args2[0] = firstValue;
84          System.arraycopy(args, 0, args2, 1, args.length);
85          return args2;
86      }
87  
88      static boolean hasMoreSpecificTypes(@NonNull Class<?>[] currentTypes, @NonNull Class<?>[] previousTypes) {
89          for (int i = 0; i < currentTypes.length; i++) {
90              Class<?> current = wrappedIfPrimitive(currentTypes[i]);
91              Class<?> previous = wrappedIfPrimitive(previousTypes[i]);
92  
93              if (current != previous && previous.isAssignableFrom(current)) {
94                  return true;
95              }
96          }
97  
98          return false;
99      }
100 
101     @NonNull
102     private static Class<?> wrappedIfPrimitive(@NonNull Class<?> parameterType) {
103         if (parameterType.isPrimitive()) {
104             Class<?> wrapperType = AutoBoxing.getWrapperType(parameterType);
105             assert wrapperType != null;
106             return wrapperType;
107         }
108 
109         return parameterType;
110     }
111 
112     static boolean acceptsArgumentTypes(@NonNull Class<?>[] paramTypes, @NonNull Class<?>[] argTypes,
113             int firstParameter) {
114         for (int i = firstParameter; i < paramTypes.length; i++) {
115             Class<?> parType = paramTypes[i];
116             Class<?> argType = argTypes[i - firstParameter];
117 
118             if (!isSameTypeIgnoringAutoBoxing(parType, argType) && !parType.isAssignableFrom(argType)) {
119                 return false;
120             }
121         }
122 
123         return true;
124     }
125 
126     static boolean isSameTypeIgnoringAutoBoxing(@NonNull Class<?> firstType, @NonNull Class<?> secondType) {
127         return firstType == secondType || firstType.isPrimitive() && isWrapperOfPrimitiveType(firstType, secondType)
128                 || secondType.isPrimitive() && isWrapperOfPrimitiveType(secondType, firstType);
129     }
130 
131     private static boolean isWrapperOfPrimitiveType(@NonNull Class<?> primitiveType, @NonNull Class<?> otherType) {
132         return primitiveType == AutoBoxing.getPrimitiveType(otherType);
133     }
134 
135     static int indexOfFirstRealParameter(@NonNull Class<?>[] mockParameterTypes,
136             @NonNull Class<?>[] realParameterTypes) {
137         int extraParameters = mockParameterTypes.length - realParameterTypes.length;
138 
139         if (extraParameters == 1) {
140             return mockParameterTypes[0] == Invocation.class ? 1 : -1;
141         }
142 
143         if (extraParameters != 0) {
144             return -1;
145         }
146 
147         return 0;
148     }
149 
150     static boolean matchesParameterTypes(@NonNull Class<?>[] declaredTypes, @NonNull Class<?>[] specifiedTypes,
151             int firstParameter) {
152         for (int i = firstParameter; i < declaredTypes.length; i++) {
153             Class<?> declaredType = declaredTypes[i];
154             Class<?> specifiedType = specifiedTypes[i - firstParameter];
155 
156             if (!isSameTypeIgnoringAutoBoxing(declaredType, specifiedType)) {
157                 return false;
158             }
159         }
160 
161         return true;
162     }
163 
164     @NonNegative
165     public static int getParameterCount(@NonNull Method method) {
166         // noinspection Since15
167         return JAVA8 ? method.getParameterCount() : method.getParameterTypes().length;
168     }
169 }