/*
* Copyright (c) 2006 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal.state;
import java.util.*;
import javax.annotation.*;
import static java.lang.reflect.Modifier.isStatic;
import mockit.internal.util.*;
public final class ParameterNames
{
private static final Map<String, Map<String, String[]>> classesToMethodsToParameters =
new HashMap<String, Map<String, String[]>>();
private static final String[] NO_PARAMETERS = new String[0];
private ParameterNames() {}
public static boolean hasNamesForClass(@Nonnull String classDesc)
{
return classesToMethodsToParameters.containsKey(classDesc);
}
public static void registerName(
@Nonnull String classDesc, @Nonnegative int memberAccess, @Nonnull String memberName, @Nonnull String memberDesc,
@Nonnull String desc, @Nonnull String name, @Nonnegative int index)
{
if ("this".equals(name)) {
return;
}
Map<String, String[]> methodsToParameters = classesToMethodsToParameters.get(classDesc);
if (methodsToParameters == null) {
methodsToParameters = new HashMap<String, String[]>();
classesToMethodsToParameters.put(classDesc, methodsToParameters);
}
String methodKey = memberName + memberDesc;
String[] parameterNames = methodsToParameters.get(methodKey);
if (parameterNames == null) {
int sumOfArgumentSizes = getSumOfArgumentSizes(memberDesc);
parameterNames = sumOfArgumentSizes == 0 ? NO_PARAMETERS : new String[sumOfArgumentSizes];
methodsToParameters.put(methodKey, parameterNames);
}
int i = index - (isStatic(memberAccess) ? 0 : 1);
if (i < parameterNames.length) {
parameterNames[i] = name;
if (isDoubleSizeType(desc.charAt(0))) {
parameterNames[i + 1] = "";
}
}
}
@SuppressWarnings("MethodWithMultipleLoops")
private static int getSumOfArgumentSizes(@Nonnull String memberDesc)
{
int sum = 0;
int i = 1;
while (true) {
char c = memberDesc.charAt(i);
i++;
if (c == ')') {
return sum;
}
if (c == 'L') {
while (memberDesc.charAt(i) != ';') i++;
i++;
sum++;
}
else if (c == '[') {
while ((c = memberDesc.charAt(i)) == '[') i++;
if (isDoubleSizeType(c)) { // if the array element type is double size...
i++;
sum++; // ...then count it here, otherwise let the outer loop count it
}
}
else if (isDoubleSizeType(c)) {
sum += 2;
}
else {
sum++;
}
}
}
private static boolean isDoubleSizeType(char typeCode) { return typeCode == 'D' || typeCode == 'J'; }
@Nonnull
public static String getName(@Nonnull TestMethod method, @Nonnegative int index)
{
String name = getName(method.testClassDesc, method.testMethodDesc, index);
return name == null ? "param" + index : name;
}
@Nullable
public static String getName(@Nonnull String classDesc, @Nonnull String methodDesc, @Nonnegative int index)
{
Map<String, String[]> methodsToParameters = classesToMethodsToParameters.get(classDesc);
if (methodsToParameters == null) {
return null;
}
String[] parameterNames = methodsToParameters.get(methodDesc);
int n = parameterNames.length;
int i = 0;
int j = 0;
while (true) {
String name = parameterNames[i];
if (j == index || name == null) {
return name;
}
i++;
if (i == n) {
break;
}
String nextName = parameterNames[i];
if (nextName.isEmpty()) {
i++;
}
j++;
}
return null;
}
}