[java] inline local: treatment for anonymous class's arguments (IDEA-279485)

GitOrigin-RevId: 5493352d47e8d6fe7a60495dddb7f23876f90db9
This commit is contained in:
Anna Kozlova
2021-10-01 22:00:57 +02:00
committed by intellij-monorepo-bot
parent ad3c351ee5
commit f1ff0aa821
8 changed files with 74 additions and 23 deletions

View File

@@ -174,11 +174,11 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
final List<PsiElement> innerClassesWithUsages = new ArrayList<>();
final List<PsiElement> innerClassUsages = new ArrayList<>();
final PsiElement containingClass = PsiTreeUtil.getParentOfType(local, PsiClass.class, PsiLambdaExpression.class);
final PsiElement containingClass = DefUseUtil.getContainingClassOrLambda(local);
for (PsiElement element : allRefs) {
PsiElement innerClass = element;
while (innerClass != null) {
final PsiElement parentPsiClass = PsiTreeUtil.getParentOfType(innerClass.getParent(), PsiClass.class, PsiLambdaExpression.class);
final PsiElement parentPsiClass = DefUseUtil.getContainingClassOrLambda(innerClass.getParent());
if (parentPsiClass == containingClass) {
if (innerClass != element) {
innerClassesWithUsages.add(innerClass);

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.psi.controlFlow;
import com.intellij.codeInsight.ExceptionUtil;
@@ -1809,13 +1809,21 @@ final class ControlFlowAnalyzer extends JavaElementVisitor {
@Override
public void visitClass(PsiClass aClass) {
startElement(aClass);
List<PsiVariable> array = new ArrayList<>();
// anonymous or local class
if (aClass instanceof PsiAnonymousClass) {
final PsiElement arguments = PsiTreeUtil.getChildOfType(aClass, PsiExpressionList.class);
if (arguments != null) arguments.accept(this);
PsiElement next = arguments != null ? arguments.getNextSibling() : aClass.getFirstChild();
while (next != null) {
addUsedVariables(array, next);
next = next.getNextSibling();
}
}
List<PsiVariable> array = new ArrayList<>();
addUsedVariables(array, aClass);
else {
addUsedVariables(array, aClass);
}
for (PsiVariable var : array) {
ProgressManager.checkCanceled();
generateReadInstruction(var);

View File

@@ -266,11 +266,11 @@ public final class DefUseUtil {
*/
public static PsiElement @NotNull [] getDefs(@NotNull PsiCodeBlock body, @NotNull PsiVariable def, @NotNull PsiElement ref, boolean rethrow) {
if (def instanceof PsiLocalVariable && ref instanceof PsiReferenceExpression && ((PsiReferenceExpression)ref).resolve() == def) {
final PsiElement defContainer = PsiTreeUtil.getParentOfType(def, PsiClass.class, PsiLambdaExpression.class);
PsiElement refContainer = PsiTreeUtil.getParentOfType(ref, PsiClass.class, PsiLambdaExpression.class);
final PsiElement defContainer = getContainingClassOrLambda(def);
PsiElement refContainer = getContainingClassOrLambda(ref);
while (defContainer != refContainer && refContainer != null) {
ref = refContainer;
refContainer = PsiTreeUtil.getParentOfType(refContainer.getParent(), PsiClass.class, PsiLambdaExpression.class);
refContainer = getContainingClassOrLambda(refContainer.getParent());
}
}
@@ -328,6 +328,21 @@ public final class DefUseUtil {
return PsiElement.EMPTY_ARRAY;
}
}
@Nullable
public static PsiElement getContainingClassOrLambda(@NotNull PsiElement element) {
PsiElement currentClass;
while (true) {
currentClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, PsiLambdaExpression.class);
if (currentClass instanceof PsiAnonymousClass &&
PsiTreeUtil.isAncestor(((PsiAnonymousClass)currentClass).getArgumentList(), element, false)) {
element = currentClass;
}
else {
return currentClass;
}
}
}
public static PsiElement @NotNull [] getRefs(@NotNull PsiCodeBlock body, @NotNull PsiVariable def, @NotNull PsiElement ref) {
return getRefs(body, def, ref, false);

View File

@@ -0,0 +1,10 @@
class X {
void use() {
int x = 2;
new A(x, x = 3, <caret>x){};
}
static class A {
A(int x1, int x2, int x3) {}
}
}

View File

@@ -0,0 +1,10 @@
class X {
void use() {
int x = 2;
new A(x, 3, 3){};
}
static class A {
A(int x1, int x2, int x3) {}
}
}

View File

@@ -0,0 +1,10 @@
class X {
void use() {
int x = 2;
new A(x, x = 3, <caret>x) {};
}
static class A {
A(int x1, int x2, int x3) {}
}
}

View File

@@ -0,0 +1,10 @@
class X {
void use() {
int x = 2;
new A(x, 3, 3) {};
}
static class A {
A(int x1, int x2, int x3) {}
}
}

View File

@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// 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.java.refactoring.inline;
import com.intellij.JavaTestUtil;
@@ -221,6 +207,8 @@ public class InlineLocalTest extends LightJavaCodeInsightTestCase {
public void testNoCastAroundLambda() { doTest(true, LanguageLevel.JDK_1_8); }
public void testNoCastWithVar() { doTest(true, LanguageLevel.JDK_10); }
public void testDiamondInAnonymousClass() { doTest(true, LanguageLevel.JDK_11); }
public void testAssignmentInAnonymousClass() { doTest(true); }
public void testAssignmentInAnonymousClass2() { doTest(true); }
public void testUncheckedCast() {
doTest(true);