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