mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-61551 Introduce variable: provide more options for nested scopes
GitOrigin-RevId: b0819c27e58ff3f2c6d39f70a5a2ef37f1fe1361
This commit is contained in:
committed by
intellij-monorepo-bot
parent
f843918254
commit
b4e18d3d47
+87
-5
@@ -70,6 +70,7 @@ import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author dsl
|
||||
@@ -122,6 +123,24 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
// For debug/test purposes
|
||||
return formatDescription(0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static IntroduceVariableBase.JavaReplaceChoice allOccurrencesInside(PsiElement parent,
|
||||
int sameKeywordCount,
|
||||
String finalKeyword) {
|
||||
return new JavaReplaceChoice(ReplaceChoice.ALL, null, false) {
|
||||
@Override
|
||||
public PsiExpression[] filter(ExpressionOccurrenceManager manager) {
|
||||
return StreamEx.of(manager.getOccurrences()).filter(expr -> PsiTreeUtil.isAncestor(parent, expr, true))
|
||||
.toArray(PsiExpression.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatDescription(int occurrencesCount) {
|
||||
return JavaRefactoringBundle.message("replace.occurrences.inside.statement", occurrencesCount, finalKeyword, sameKeywordCount);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(IntroduceVariableBase.class);
|
||||
@@ -1220,15 +1239,78 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
}
|
||||
|
||||
if (myOccurrences.size() > 1 && !myCantReplaceAll) {
|
||||
JavaReplaceChoice choice = occurrencesMap.containsKey(JavaReplaceChoice.NO_WRITE)
|
||||
? new JavaReplaceChoice(ReplaceChoice.ALL, JavaRefactoringBundle.message("replace.all.read.and.write"),
|
||||
false)
|
||||
: JavaReplaceChoice.ALL;
|
||||
occurrencesMap.put(choice, myOccurrences);
|
||||
if (occurrencesMap.containsKey(JavaReplaceChoice.NO_WRITE)) {
|
||||
JavaReplaceChoice choice = new JavaReplaceChoice(
|
||||
ReplaceChoice.ALL, JavaRefactoringBundle.message("replace.all.read.and.write"), false);
|
||||
occurrencesMap.put(choice, myOccurrences);
|
||||
}
|
||||
else {
|
||||
generateScopeBasedChoices(expr, occurrencesMap);
|
||||
occurrencesMap.put(JavaReplaceChoice.ALL, myOccurrences);
|
||||
}
|
||||
}
|
||||
}
|
||||
return occurrencesMap;
|
||||
}
|
||||
|
||||
private void generateScopeBasedChoices(PsiExpression expr,
|
||||
LinkedHashMap<JavaReplaceChoice, List<PsiExpression>> occurrencesMap) {
|
||||
Comparator<PsiElement> treeOrder = (e1, e2) -> {
|
||||
if (PsiTreeUtil.isAncestor(e1, e2, true)) return 1;
|
||||
if (PsiTreeUtil.isAncestor(e2, e1, true)) return -1;
|
||||
return 0;
|
||||
};
|
||||
PsiElement physical = getPhysicalElement(expr);
|
||||
TreeMap<PsiElement, List<PsiExpression>> groupByBlock =
|
||||
StreamEx.of(myOccurrences).groupingBy(e -> PsiTreeUtil.findCommonParent(e, physical),
|
||||
() -> new TreeMap<>(treeOrder), Collectors.toList());
|
||||
assert !groupByBlock.isEmpty();
|
||||
List<PsiExpression> currentOccurrences = new ArrayList<>();
|
||||
Map<String, Integer> counts = new HashMap<>();
|
||||
groupByBlock.forEach((parent, occurrences) -> {
|
||||
PsiElement nextParent = groupByBlock.higherKey(parent);
|
||||
if (nextParent == null) return;
|
||||
currentOccurrences.addAll(occurrences);
|
||||
if (currentOccurrences.size() == 1) return;
|
||||
PsiElement current = parent.getParent();
|
||||
String keyword = null;
|
||||
while (current != nextParent) {
|
||||
if (current instanceof PsiIfStatement || current instanceof PsiWhileStatement || current instanceof PsiForStatement ||
|
||||
current instanceof PsiTryStatement) {
|
||||
keyword = current.getFirstChild().getText();
|
||||
}
|
||||
else if (current instanceof PsiDoWhileStatement) {
|
||||
keyword = "do-while";
|
||||
}
|
||||
else if (current instanceof PsiForeachStatement) {
|
||||
keyword = "for-each";
|
||||
}
|
||||
else if (current instanceof PsiLambdaExpression) {
|
||||
keyword = "lambda";
|
||||
}
|
||||
if (keyword != null) {
|
||||
break;
|
||||
}
|
||||
current = current.getParent();
|
||||
}
|
||||
if (keyword == null && nextParent instanceof PsiIfStatement) {
|
||||
PsiStatement thenBranch = ((PsiIfStatement)nextParent).getThenBranch();
|
||||
PsiStatement elseBranch = ((PsiIfStatement)nextParent).getElseBranch();
|
||||
if (PsiTreeUtil.isAncestor(thenBranch, parent, false)) {
|
||||
keyword = "if-then";
|
||||
} else if (PsiTreeUtil.isAncestor(elseBranch, parent, false)) {
|
||||
keyword = "else";
|
||||
}
|
||||
}
|
||||
if (keyword != null) {
|
||||
int sameKeywordCount = counts.merge(keyword, 1, Integer::sum);
|
||||
if (sameKeywordCount <= 2) {
|
||||
JavaReplaceChoice choice = JavaReplaceChoice.allOccurrencesInside(parent, sameKeywordCount, keyword);
|
||||
occurrencesMap.put(choice, new ArrayList<>(currentOccurrences));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected static String getRefactoringName() {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
class C {
|
||||
private int bar() {
|
||||
return 42;
|
||||
}
|
||||
public void foo() {
|
||||
if (true) {
|
||||
if (false) {
|
||||
int i = bar() + 1;
|
||||
int j = bar() - 1;
|
||||
} else {
|
||||
int i = bar() <caret>+ 1;
|
||||
int j = bar() + 1;
|
||||
}
|
||||
} else {
|
||||
if (true) {
|
||||
int i = bar() + 1;
|
||||
int j = bar() + 1;
|
||||
} else {
|
||||
int i = bar() + 1;
|
||||
int j = bar() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
class C {
|
||||
private int bar() {
|
||||
return 42;
|
||||
}
|
||||
public void foo() {
|
||||
if (true) {
|
||||
if (false) {
|
||||
int i = bar() + 1;
|
||||
int j = bar() - 1;
|
||||
} else {
|
||||
int i1 = bar() + 1;
|
||||
int i = i1;
|
||||
int j = i1;
|
||||
}
|
||||
} else {
|
||||
if (true) {
|
||||
int i = bar() + 1;
|
||||
int j = bar() + 1;
|
||||
} else {
|
||||
int i = bar() + 1;
|
||||
int j = bar() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
class C {
|
||||
private int bar() {
|
||||
return 42;
|
||||
}
|
||||
public void foo() {
|
||||
if (true) {
|
||||
if (false) {
|
||||
int i = bar() + 1;
|
||||
int j = bar() - 1;
|
||||
} else {
|
||||
int i = bar() <caret>+ 1;
|
||||
int j = bar() + 1;
|
||||
}
|
||||
} else {
|
||||
if (true) {
|
||||
int i = bar() + 1;
|
||||
int j = bar() + 1;
|
||||
} else {
|
||||
int i = bar() + 1;
|
||||
int j = bar() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
class C {
|
||||
private int bar() {
|
||||
return 42;
|
||||
}
|
||||
public void foo() {
|
||||
if (true) {
|
||||
int i1 = bar() + 1;
|
||||
if (false) {
|
||||
int i = i1;
|
||||
int j = bar() - 1;
|
||||
} else {
|
||||
int i = i1;
|
||||
int j = i1;
|
||||
}
|
||||
} else {
|
||||
if (true) {
|
||||
int i = bar() + 1;
|
||||
int j = bar() + 1;
|
||||
} else {
|
||||
int i = bar() + 1;
|
||||
int j = bar() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
class C {
|
||||
private int bar() {
|
||||
return 42;
|
||||
}
|
||||
public void foo() {
|
||||
if (true) {
|
||||
if (false) {
|
||||
int i = bar() + 1;
|
||||
int j = bar() - 1;
|
||||
} else {
|
||||
int i = bar() <caret>+ 1;
|
||||
int j = bar() + 1;
|
||||
}
|
||||
} else {
|
||||
if (true) {
|
||||
int i = bar() + 1;
|
||||
int j = bar() + 1;
|
||||
} else {
|
||||
int i = bar() + 1;
|
||||
int j = bar() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
class C {
|
||||
private int bar() {
|
||||
return 42;
|
||||
}
|
||||
public void foo() {
|
||||
int i1 = bar() + 1;
|
||||
if (true) {
|
||||
if (false) {
|
||||
int i = i1;
|
||||
int j = bar() - 1;
|
||||
} else {
|
||||
int i = i1;
|
||||
int j = i1;
|
||||
}
|
||||
} else {
|
||||
if (true) {
|
||||
int i = i1;
|
||||
int j = i1;
|
||||
} else {
|
||||
int i = i1;
|
||||
int j = i1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class C {
|
||||
Supplier<Supplier<String>> test(String s) {
|
||||
System.out.println(s.trim()+s.trim());
|
||||
return () -> {
|
||||
System.out.println(s.trim()+s.trim());
|
||||
return () -> {
|
||||
return s.t<caret>rim() + s.trim();
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class C {
|
||||
Supplier<Supplier<String>> test(String s) {
|
||||
System.out.println(s.trim()+s.trim());
|
||||
return () -> {
|
||||
System.out.println(s.trim()+s.trim());
|
||||
return () -> {
|
||||
String trim = s.trim();
|
||||
return trim + trim;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class C {
|
||||
Supplier<Supplier<String>> test(String s) {
|
||||
System.out.println(s.trim()+s.trim());
|
||||
return () -> {
|
||||
System.out.println(s.trim()+s.trim());
|
||||
return () -> {
|
||||
return s.t<caret>rim() + s.trim();
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class C {
|
||||
Supplier<Supplier<String>> test(String s) {
|
||||
System.out.println(s.trim()+s.trim());
|
||||
return () -> {
|
||||
String trim = s.trim();
|
||||
System.out.println(trim + trim);
|
||||
return () -> {
|
||||
return trim + trim;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
+20
@@ -175,6 +175,26 @@ public class InplaceIntroduceVariableTest extends AbstractJavaInplaceIntroduceTe
|
||||
invokeEditorAction(IdeActions.ACTION_EDITOR_ENTER);
|
||||
});
|
||||
}
|
||||
|
||||
public void testInBlock1() {
|
||||
doTestReplaceChoice("Replace 0 occurrences in 'else' block");
|
||||
}
|
||||
|
||||
public void testInBlock2() {
|
||||
doTestReplaceChoice("Replace 0 occurrences in 'if-then' block");
|
||||
}
|
||||
|
||||
public void testInBlock3() {
|
||||
doTestReplaceChoice("Replace all 0 occurrences");
|
||||
}
|
||||
|
||||
public void testInBlockLambda1() {
|
||||
doTestReplaceChoice("Replace 0 occurrences in 'lambda' block");
|
||||
}
|
||||
|
||||
public void testInBlockLambda2() {
|
||||
doTestReplaceChoice("Replace 0 occurrences in outer 'lambda' block");
|
||||
}
|
||||
|
||||
private void doTestStopEditing(Consumer<AbstractInplaceIntroducer> pass) {
|
||||
String name = getTestName(true);
|
||||
|
||||
@@ -609,4 +609,5 @@ replace.inside.current.lambda=Create variable inside current lambda
|
||||
replace.as.separate.operation=Extract as ''{0}'' operation
|
||||
replace.all.read.and.write=Replace read and write occurrences (will change semantics!)
|
||||
replace.all.and.extract=Replace all {0} occurrences and extract as ''{1}'' operation
|
||||
replace.lambda.chain.detected=Lambda chain detected
|
||||
replace.lambda.chain.detected=Lambda chain detected
|
||||
replace.occurrences.inside.statement=Replace {0} occurrences in{2, choice, 1#|2# outer} ''{1}'' block
|
||||
|
||||
Reference in New Issue
Block a user