[java] inline parameter: find defs of local variables used inside lambda parameter initializer (IDEA-278368)

GitOrigin-RevId: eac35d3e7067592031f483a6ca7fe29ce26e56db
This commit is contained in:
Anna Kozlova
2021-09-16 19:24:16 +02:00
committed by intellij-monorepo-bot
parent 04daf179e3
commit b09b860649
5 changed files with 75 additions and 27 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.refactoring.inline;
import com.intellij.codeInsight.ExceptionUtil;
@@ -42,7 +42,6 @@ import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.InlineUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
@@ -173,27 +172,6 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
final String localName = local.getName();
final List<PsiElement> innerClassesWithUsages = Collections.synchronizedList(new ArrayList<>());
final List<PsiElement> innerClassUsages = Collections.synchronizedList(new ArrayList<>());
final PsiElement containingClass = PsiTreeUtil.getParentOfType(local, PsiClass.class, PsiLambdaExpression.class);
for (PsiElement element : allRefs) {
PsiElement innerClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, PsiLambdaExpression.class);
while (innerClass != containingClass && innerClass != null) {
final PsiElement parentPsiClass = PsiTreeUtil.getParentOfType(innerClass.getParent(), PsiClass.class, PsiLambdaExpression.class);
if (parentPsiClass == containingClass) {
if (innerClass instanceof PsiLambdaExpression) {
if (PsiTreeUtil.isAncestor(innerClass, local, false)) {
innerClassesWithUsages.add(element);
innerClass = parentPsiClass;
continue;
}
}
innerClassesWithUsages.add(innerClass);
innerClassUsages.add(element);
}
innerClass = parentPsiClass;
}
}
final PsiCodeBlock containerBlock = PsiTreeUtil.getParentOfType(local, PsiCodeBlock.class);
if (containerBlock == null) {
final String message = RefactoringBundle.getCannotRefactorMessage(
@@ -201,10 +179,16 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
CommonRefactoringUtil.showErrorHint(project, editor, message, getRefactoringName(local), HelpID.INLINE_VARIABLE);
return null;
}
final List<PsiElement> innerClassUsages = Collections.synchronizedList(new ArrayList<>());
final PsiElement containingClass = PsiTreeUtil.getParentOfType(local, PsiClass.class, PsiLambdaExpression.class);
final PsiExpression defToInline;
try {
defToInline = getDefToInline(local, innerClassesWithUsages.isEmpty() ? refExpr : innerClassesWithUsages.get(0), containerBlock, true);
PsiElement refToInline = getRefToInline(local, allRefs, innerClassUsages, containingClass);
defToInline = getDefToInline(local,
refToInline != null ? refToInline : refExpr,
containerBlock, true);
if (defToInline == null) {
final String key = refExpr == null ? "variable.has.no.initializer" : "variable.has.no.dominating.definition";
String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message(key, localName));
@@ -365,6 +349,33 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
};
}
@Nullable
static PsiElement getRefToInline(@NotNull PsiLocalVariable local,
@NotNull Collection<PsiElement> allRefs,
List<PsiElement> innerClassUsages,
PsiElement containingClass) {
final List<PsiElement> innerClassesWithUsages = Collections.synchronizedList(new ArrayList<>());
for (PsiElement element : allRefs) {
PsiElement innerClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, PsiLambdaExpression.class);
while (innerClass != containingClass && innerClass != null) {
final PsiElement parentPsiClass = PsiTreeUtil.getParentOfType(innerClass.getParent(), PsiClass.class, PsiLambdaExpression.class);
if (parentPsiClass == containingClass) {
if (innerClass instanceof PsiLambdaExpression) {
if (PsiTreeUtil.isAncestor(innerClass, local, false)) {
innerClassesWithUsages.add(element);
innerClass = parentPsiClass;
continue;
}
}
innerClassesWithUsages.add(innerClass);
innerClassUsages.add(element);
}
innerClass = parentPsiClass;
}
}
return innerClassesWithUsages.isEmpty() ? null : innerClassesWithUsages.get(0);
}
@NotNull
static List<SmartPsiElementPointer<PsiExpression>> inlineOccurrences(@NotNull Project project,
@NotNull PsiVariable local,

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.refactoring.inline;
import com.intellij.codeInsight.ExceptionUtil;
@@ -26,6 +26,7 @@ import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.JavaPsiConstructorUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
@@ -107,7 +108,12 @@ public class InlineParameterExpressionProcessor extends BaseRefactoringProcessor
final PsiElement element = expression.resolve();
if (element instanceof PsiLocalVariable) {
final PsiLocalVariable localVariable = (PsiLocalVariable)element;
final PsiElement[] elements = DefUseUtil.getDefs(myCallingBlock, localVariable, expression);
final List<PsiElement> innerClassUsages = Collections.synchronizedList(new ArrayList<>());
final PsiElement containingClass = PsiTreeUtil.getParentOfType(localVariable, PsiClass.class, PsiLambdaExpression.class);
PsiElement refToInline = InlineLocalHandler.getRefToInline(localVariable,
Collections.singletonList(expression),
innerClassUsages, containingClass);
final PsiElement[] elements = DefUseUtil.getDefs(myCallingBlock, localVariable, ObjectUtils.notNull(refToInline, expression));
if (elements.length == 1) {
PsiExpression localInitializer = null;
if (elements[0] instanceof PsiLocalVariable) {

View File

@@ -0,0 +1,14 @@
interface A {
void foo(int i);
}
class B {
B(A <caret>a) {
System.out.println(a);
}
}
class C {
{
int k = 42;
B b = new B(i1 -> i1 + k);
}
}

View File

@@ -0,0 +1,13 @@
interface A {
void foo(int i);
}
class B {
B() {
System.out.println((A) i1 -> i1 + 42);
}
}
class C {
{
B b = new B();
}
}

View File

@@ -98,6 +98,10 @@ public class InlineParameterTest extends LightRefactoringTestCase {
doTest(false);
}
public void testInlineLambdaWithOuterRef() {
doTest(false);
}
public void testRefThis() {
doTest(false);
}