IDEA-86826 Inline method with empty varargs

This commit is contained in:
Maxim.Medvedev
2012-05-31 13:25:58 +04:00
parent 8770783313
commit b1069cdb90
4 changed files with 87 additions and 77 deletions
@@ -368,19 +368,22 @@ public class GrClosureSignatureUtil {
boolean partial) {
if (checkForOnlyMapParam(signature, args.length)) return ArgInfo.empty_array();
GrClosureParameter[] params = signature.getParameters();
if (args.length > params.length && !signature.isVarargs()) return null;
if (args.length > params.length && !signature.isVarargs() && !partial) return null;
int optional = getOptionalParamCount(signature, false);
int notOptional = params.length - optional;
if (signature.isVarargs()) notOptional--;
if (notOptional > args.length && !partial) return null;
final ArgInfo<Arg>[] map = mapSimple(params, args, typeComputer, context);
final ArgInfo<Arg>[] map = mapSimple(params, args, typeComputer, context, false);
if (map != null) return map;
if (signature.isVarargs()) {
return new ParameterMapperForVararg<Arg>(context, params, args, typeComputer).isApplicable();
}
return null;
if (!partial) return null;
return mapSimple(params, args, typeComputer, context, true);
}
private static boolean checkForOnlyMapParam(@NotNull GrClosureSignature signature, final int argCount) {
@@ -395,19 +398,25 @@ public class GrClosureSignatureUtil {
private static <Arg> ArgInfo<Arg>[] mapSimple(@NotNull GrClosureParameter[] params,
@NotNull Arg[] args,
@NotNull Function<Arg, PsiType> typeComputer,
@NotNull GroovyPsiElement context) {
@NotNull GroovyPsiElement context,
boolean partial) {
if (args.length > params.length && !partial) return null;
ArgInfo<Arg>[] map = new ArgInfo[params.length];
int optional = getOptionalParamCount(params, false);
int notOptional = params.length - optional;
int optionalArgs = args.length - notOptional;
if (notOptional > args.length && !partial) return null;
int cur = 0;
for (int i = 0; i < args.length; i++, cur++) {
while (optionalArgs == 0 && cur < params.length && params[cur].isOptional()) {
cur++;
}
if (cur == params.length) return null;
if (cur == params.length) return partial ? map : null;
if (params[cur].isOptional()) optionalArgs--;
if (!isAssignableByConversion(params[cur].getType(), typeComputer.fun(args[i]), context)) return null;
if (!isAssignableByConversion(params[cur].getType(), typeComputer.fun(args[i]), context)) return partial ? map : null;
map[cur] = new ArgInfo<Arg>(args[i]);
}
for (int i = 0; i < map.length; i++) {
@@ -668,7 +677,9 @@ public class GrClosureSignatureUtil {
if (hasNamedArgs) {
if (params.length == 0) return null;
PsiType type = params[0].getType();
if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) {
if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP) ||
type == null ||
type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) {
innerArgs.add(new InnerArg(new GrMapType(context.getResolveScope()), namedArgs));
}
else {
@@ -32,18 +32,18 @@ import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.inline.InlineOptionsDialog;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrBlockStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrIfStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement;
@@ -53,6 +53,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
@@ -431,65 +432,76 @@ public class GroovyInlineMethodUtil {
* @param method given method
*/
public static void replaceParametersWithArguments(GrCallExpression call, GrMethod method) throws IncorrectOperationException {
GrParameter[] parameters = method.getParameters();
if (parameters.length == 0) return;
GrArgumentList argumentList = call.getArgumentList();
if (argumentList == null) {
setDefaultValuesToParameters(method, null, call);
return;
}
// first parameter may have map type
final GrNamedArgument[] namedArguments = argumentList.getNamedArguments();
boolean firstParamIsMap = namedArguments.length > 0;
ArrayList<GrExpression> exprs = new ArrayList<GrExpression>();
if (firstParamIsMap) {
StringBuilder mapArg = new StringBuilder();
mapArg.append('[');
for (GrNamedArgument namedArgument : namedArguments) {
mapArg.append(namedArgument.getText()).append(", ");
}
Project project = call.getProject();
mapArg.delete(mapArg.length() - 2, mapArg.length());
mapArg.append(']');
exprs.add(GroovyPsiElementFactory.getInstance(call.getProject()).createExpressionFromText(mapArg.toString()));
GrClosureSignature signature = GrClosureSignatureUtil.createSignature(call);
if (signature == null) {
return;
}
GrClosureSignatureUtil.ArgInfo<PsiElement>[] infos = GrClosureSignatureUtil.mapParametersToArguments(
signature,
call.getNamedArguments(),
call.getExpressionArguments(),
call.getClosureArguments(),
call, true, false
);
if (infos == null) return;
ContainerUtil.addAll(exprs, argumentList.getExpressionArguments());
ContainerUtil.addAll(exprs, call.getClosureArguments());
for (int i = 0; i < infos.length; i++) {
GrClosureSignatureUtil.ArgInfo<PsiElement> argInfo = infos[i];
GrParameter parameter = parameters[i];
GrParameter[] parameters = method.getParameters();
if (parameters.length == 0) return;
GrParameter firstParam = parameters[0];
while (exprs.size() > parameters.length) {
exprs.remove(exprs.size() - 1);
}
int nonDefault = 0;
for (GrParameter parameter : parameters) {
if (!(firstParam == parameter && firstParamIsMap)) {
if (parameter.getDefaultInitializer() == null) {
nonDefault++;
}
final GrExpression arg = inferArg(signature, parameters, parameter, argInfo, project);
if (arg != null) {
replaceAllOccurrencesWithExpression(method, call, arg, parameter);
}
}
nonDefault = exprs.size() - nonDefault - (firstParamIsMap ? 1 : 0);
// Parameters that will be replaced by its default values
Set<String> nameFilter = new HashSet<String>();
for (GrParameter parameter : parameters) {
if (!(firstParam == parameter && firstParamIsMap)) {
GrExpression initializer = parameter.getDefaultInitializer();
if (initializer != null) {
if (nonDefault > 0) {
nonDefault--;
}
else {
nameFilter.add(parameter.getName());
}
@Nullable
private static GrExpression inferArg(GrClosureSignature signature,
GrParameter[] parameters,
GrParameter parameter,
GrClosureSignatureUtil.ArgInfo<PsiElement> argInfo,
Project project) {
if (argInfo == null) return null;
List<PsiElement> arguments = argInfo.args;
if (argInfo.isMultiArg) { //arguments for Map and varArg
final PsiType type = parameter.getDeclaredType();
return GroovyRefactoringUtil.generateArgFromMultiArg(signature.getSubstitutor(), arguments, type, project);
}
else { //arguments for simple parameters
if (arguments.size() == 1) { //arg exists
PsiElement arg = arguments.iterator().next();
if (isVararg(parameter, parameters)) {
if (arg instanceof GrSafeCastExpression) {
PsiElement expr = ((GrSafeCastExpression)arg).getOperand();
if (expr instanceof GrListOrMap && !((GrListOrMap)expr).isMap()) {
return ((GrListOrMap)expr);
}
}
}
return (GrExpression)arg;
}
else { //arg is skipped. Parameter is optional
return parameter.getDefaultInitializer();
}
}
}
setDefaultValuesToParameters(method, nameFilter, call);
setValuesToParameters(method, call, exprs, nameFilter);
private static boolean isVararg(GrParameter p, GrParameter[] parameters) {
return parameters[parameters.length - 1] == p && p.getType() instanceof PsiArrayType;
}
/**
@@ -515,32 +527,6 @@ public class GroovyInlineMethodUtil {
}
}
/**
* Replace first m parameters by given values, where m is length of given values vector
*
* @param method
* @param call
* @param values values vector
* @param nameFilter
*/
private static void setValuesToParameters(GrMethod method, GrCallExpression call, List<GrExpression> values, Set<String> nameFilter)
throws IncorrectOperationException {
GrParameter[] parameters = method.getParameters();
if (parameters.length == 0) return;
if (nameFilter == null) nameFilter = new HashSet<String>();
int i = 0;
for (GrExpression value : values) {
while (i < parameters.length && nameFilter.contains(parameters[i].getName())) i++;
if (i < parameters.length) {
GrParameter parameter = parameters[i];
replaceAllOccurrencesWithExpression(method, call, value, parameter);
}
i++;
}
}
private static void replaceAllOccurrencesWithExpression(GrMethod method,
GrCallExpression call,
GrExpression oldExpression,
@@ -103,6 +103,8 @@ public class InlineMethodTest extends LightCodeInsightFixtureTestCase {
public void testSideEffectInitializer() {doTest();}
public void testVarargs() {doTest();}
public void testInlineAll() throws Throwable {
doTest(new GroovyInlineHandler() {
@Override
@@ -0,0 +1,11 @@
def foo(String s, int... var) {
bar(var)
}
<selection>foo</selection>('a')
-----
def foo(String s, int... var) {
bar(var)
}
bar([] as int[])