[java] inline parameter: find defs of local variables used inside lambda parameter...
authorAnna Kozlova <anna.kozlova@jetbrains.com>
Thu, 16 Sep 2021 17:24:16 +0000 (19:24 +0200)
committerintellij-monorepo-bot <intellij-monorepo-bot-no-reply@jetbrains.com>
Fri, 17 Sep 2021 06:32:27 +0000 (06:32 +0000)
GitOrigin-RevId: eac35d3e7067592031f483a6ca7fe29ce26e56db

java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java
java/java-impl/src/com/intellij/refactoring/inline/InlineParameterExpressionProcessor.java
java/java-tests/testData/refactoring/inlineParameter/InlineLambdaWithOuterRef.java [new file with mode: 0644]
java/java-tests/testData/refactoring/inlineParameter/InlineLambdaWithOuterRef.java.after [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/java/refactoring/inline/InlineParameterTest.java

index 7795cf2d73d6a6c16525b015a5fb9b6233d32788..b922f9096371d2847d002237e39dd7b1dc648d9c 100644 (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,
index 63fdf3d8a2e89aaacad36c5552e25309d3b76d8f..db9ccc8277f0af6222581d3e1c9a44205903805a 100644 (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) {
diff --git a/java/java-tests/testData/refactoring/inlineParameter/InlineLambdaWithOuterRef.java b/java/java-tests/testData/refactoring/inlineParameter/InlineLambdaWithOuterRef.java
new file mode 100644 (file)
index 0000000..d6c7be9
--- /dev/null
@@ -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);
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/inlineParameter/InlineLambdaWithOuterRef.java.after b/java/java-tests/testData/refactoring/inlineParameter/InlineLambdaWithOuterRef.java.after
new file mode 100644 (file)
index 0000000..cab4e2e
--- /dev/null
@@ -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();
+  }
+}
\ No newline at end of file
index 615d9978be5a5172531ef152a9834132624fa2c8..95e8b11181297e45cfe3abd43b6129598c6828d1 100644 (file)
@@ -98,6 +98,10 @@ public class InlineParameterTest extends LightRefactoringTestCase {
     doTest(false);
   }
 
+  public void testInlineLambdaWithOuterRef() {
+    doTest(false);
+  }
+
   public void testRefThis() {
     doTest(false);
   }