anonym to lambda: rename conflicting locals (IDEA-120221)

This commit is contained in:
Anna Kozlova
2014-03-26 12:34:12 +01:00
parent 72203e26ef
commit a4f36f237c
3 changed files with 88 additions and 48 deletions

View File

@@ -38,10 +38,7 @@ import com.intellij.util.containers.hash.LinkedHashMap;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* User: anna
@@ -93,11 +90,6 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
final ForbiddenRefsChecker checker = new ForbiddenRefsChecker(methods[0], aClass);
body.accept(checker);
if (!checker.hasForbiddenRefs()) {
PsiResolveHelper helper = PsiResolveHelper.SERVICE.getInstance(body.getProject());
for (PsiLocalVariable local : checker.getLocals()) {
final String localName = local.getName();
if (localName != null && helper.resolveReferencedVariable(localName, aClass) != null) return;
}
final PsiElement lBrace = aClass.getLBrace();
LOG.assertTrue(lBrace != null);
final TextRange rangeInElement = new TextRange(0, aClass.getStartOffsetInParent() + lBrace.getStartOffsetInParent());
@@ -131,6 +123,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
final PsiElement element = descriptor.getPsiElement();
if (element instanceof PsiNewExpression) {
final PsiAnonymousClass anonymousClass = ((PsiNewExpression)element).getAnonymousClass();
LOG.assertTrue(anonymousClass != null);
ChangeContextUtil.encodeContextInfo(anonymousClass, true);
final PsiElement lambdaContext = anonymousClass.getParent().getParent();
@@ -139,14 +132,32 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
final PsiMethod method = anonymousClass.getMethods()[0];
LOG.assertTrue(method != null);
final PsiCodeBlock body = method.getBody();
LOG.assertTrue(body != null);
final ForbiddenRefsChecker checker = new ForbiddenRefsChecker(method, anonymousClass);
body.accept(checker);
PsiResolveHelper helper = PsiResolveHelper.SERVICE.getInstance(body.getProject());
final Set<PsiLocalVariable> conflictingLocals = checker.getLocals();
for (Iterator<PsiLocalVariable> iterator = conflictingLocals.iterator(); iterator.hasNext(); ) {
PsiLocalVariable local = iterator.next();
final String localName = local.getName();
if (localName == null || helper.resolveReferencedVariable(localName, anonymousClass) == null) {
iterator.remove();
}
}
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
giveUniqueNames(project, lambdaContext, elementFactory, body, conflictingLocals.toArray(new PsiVariable[conflictingLocals.size()]));
final String lambdaWithTypesDeclared = composeLambdaText(method, true);
final String withoutTypesDeclared = composeLambdaText(method, false);
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
PsiLambdaExpression lambdaExpression =
(PsiLambdaExpression)elementFactory.createExpressionFromText(withoutTypesDeclared, anonymousClass);
final PsiCodeBlock body = method.getBody();
LOG.assertTrue(body != null);
final PsiStatement[] statements = body.getStatements();
PsiElement copy = body.copy();
if (statements.length == 1 && statements[0] instanceof PsiReturnStatement) {
@@ -160,42 +171,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
LOG.assertTrue(lambdaBody != null);
lambdaBody.replace(copy);
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
final Map<PsiParameter, String> names = new HashMap<PsiParameter, String>();
for (PsiParameter parameter : lambdaExpression.getParameterList().getParameters()) {
String parameterName = parameter.getName();
final String uniqueVariableName = codeStyleManager.suggestUniqueVariableName(parameterName, lambdaContext, false);
if (!Comparing.equal(parameterName, uniqueVariableName)) {
names.put(parameter, uniqueVariableName);
}
}
final LinkedHashMap<PsiElement, PsiElement> replacements = new LinkedHashMap<PsiElement, PsiElement>();
lambdaExpression.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitParameter(PsiParameter parameter) {
final String newName = names.get(parameter);
if (newName != null) {
replacements.put(parameter.getNameIdentifier(), elementFactory.createIdentifier(newName));
}
}
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
super.visitReferenceExpression(expression);
final PsiElement resolve = expression.resolve();
if (resolve instanceof PsiParameter) {
final String newName = names.get(resolve);
if (newName != null) {
replacements.put(expression, elementFactory.createExpressionFromText(newName, expression));
}
}
}
});
for (PsiElement psiElement : replacements.keySet()) {
psiElement.replace(replacements.get(psiElement));
}
giveUniqueNames(project, lambdaContext, elementFactory, lambdaExpression, lambdaExpression.getParameterList().getParameters());
final PsiNewExpression newExpression = (PsiNewExpression)anonymousClass.getParent();
lambdaExpression = (PsiLambdaExpression)newExpression.replace(lambdaExpression);
@@ -243,6 +219,49 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
}
}
private static void giveUniqueNames(Project project,
PsiElement lambdaContext,
final PsiElementFactory elementFactory,
PsiElement body,
PsiVariable[] parameters) {
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
final Map<PsiVariable, String> names = new HashMap<PsiVariable, String>();
for (PsiVariable parameter : parameters) {
String parameterName = parameter.getName();
final String uniqueVariableName = codeStyleManager.suggestUniqueVariableName(parameterName, lambdaContext, false);
if (!Comparing.equal(parameterName, uniqueVariableName)) {
names.put(parameter, uniqueVariableName);
}
}
final LinkedHashMap<PsiElement, PsiElement> replacements = new LinkedHashMap<PsiElement, PsiElement>();
body.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitVariable(PsiVariable variable) {
final String newName = names.get(variable);
if (newName != null) {
replacements.put(variable.getNameIdentifier(), elementFactory.createIdentifier(newName));
}
}
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
super.visitReferenceExpression(expression);
final PsiElement resolve = expression.resolve();
if (resolve instanceof PsiParameter) {
final String newName = names.get(resolve);
if (newName != null) {
replacements.put(expression, elementFactory.createExpressionFromText(newName, expression));
}
}
}
});
for (PsiElement psiElement : replacements.keySet()) {
psiElement.replace(replacements.get(psiElement));
}
}
private static boolean isInferred(PsiLambdaExpression lambdaExpression, PsiType interfaceType) {
return interfaceType == null || !LambdaUtil.isLambdaFullyInferred(lambdaExpression, interfaceType) || !LambdaUtil.isFunctionalType(interfaceType);
}

View File

@@ -0,0 +1,9 @@
// "Replace with lambda" "true"
class X1 {
Runnable m() {
String s;
return () -> {
String s1;
};
}
}

View File

@@ -0,0 +1,12 @@
// "Replace with lambda" "true"
class X1 {
Runnable m() {
String s;
return new Run<caret>nable() {
@Override
public void run() {
String s;
}
};
}
}