1
2
3
4
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
167 return JAVA8 ? method.getParameterCount() : method.getParameterTypes().length;
168 }
169 }