[java-highlighting] Fix bug about applying "Create missing switch branch" fix produces a red code

(IDEA-278884)

GitOrigin-RevId: 690fa0ae782ee065b35e91f6d1e0df846bd9369f
This commit is contained in:
Andrey.Cherkasov
2021-11-11 03:47:25 +03:00
committed by intellij-monorepo-bot
parent e722456de1
commit 086e760e08
17 changed files with 185 additions and 87 deletions

View File

@@ -783,11 +783,12 @@ public class SwitchBlockHighlightingModel {
@NotNull List<PsiCaseLabelElement> elements,
@NotNull List<HighlightInfo> results) {
Set<PsiClass> missingClasses;
Map<PsiClass, PsiPattern> patternClasses = null;
if (elements.isEmpty()) {
missingClasses = Collections.emptySet();
}
else {
Map<PsiClass, PsiPattern> patternClasses = new HashMap<>();
patternClasses = new HashMap<>();
for (PsiCaseLabelElement element : elements) {
PsiPattern patternLabelElement = ObjectUtils.tryCast(element, PsiPattern.class);
if (patternLabelElement == null) continue;
@@ -821,15 +822,42 @@ public class SwitchBlockHighlightingModel {
}
HighlightInfo info = createCompletenessInfoForSwitch(!elements.isEmpty());
if (!missingClasses.isEmpty()) {
List<String> allNames = findAllNames(elements, missingClasses, patternClasses);
Set<String> missingCases = new SmartHashSet<>();
missingClasses.forEach(aClass -> missingCases.add(aClass.getQualifiedName()));
IntentionAction fix =
getFixFactory().createAddMissingSealedClassBranchesFix(myBlock, missingCases, StreamEx.of(missingCases).toList());
IntentionAction fix = getFixFactory().createAddMissingSealedClassBranchesFix(myBlock, missingCases, allNames);
QuickFixAction.registerQuickFixAction(info, fix);
}
results.add(info);
}
@NotNull
private static List<String> findAllNames(@NotNull List<PsiCaseLabelElement> elements,
@NotNull Set<PsiClass> missingClasses,
@NotNull Map<PsiClass, PsiPattern> patternClasses) {
List<String> result = new ArrayList<>();
elements.forEach(element -> result.add(element.getText()));
for (PsiClass aClass : missingClasses) {
String className = aClass.getQualifiedName();
PsiPattern pattern = patternClasses.get(aClass);
if (pattern != null) {
result.add(result.lastIndexOf(pattern.getText()) + 1, className);
}
else {
pattern =
StreamEx.of(elements).select(PsiPattern.class).findFirst(who -> JavaPsiPatternUtil.dominates(who, TypeUtils.getType(aClass)))
.orElse(null);
if (pattern != null) {
result.add(result.indexOf(pattern.getText()), aClass.getQualifiedName());
}
else {
result.add(aClass.getQualifiedName());
}
}
}
return result;
}
@NotNull
private static Collection<PsiClass> getPermittedClasses(@NotNull PsiClass psiClass) {
PsiReferenceList permitsList = psiClass.getPermitsList();

View File

@@ -1,21 +0,0 @@
// "Create missing switch branch 'Sub2'" "true"
sealed abstract class I {
}
final class Sub1 extends I {
}
final class Sub2 extends I {
}
class Test {
void testI(I i) {
switch (i) {
case Sub1 s1:
System.out.println("ok");
break;
case Sub2 sub2:
break;
}
}
}

View File

@@ -1,18 +0,0 @@
// "Create missing branches: 'Scratch.X', and 'Scratch.Parent.X'" "true"
class Scratch {
sealed interface Parent {
record X() implements Parent {}
}
record X() implements Parent {}
record Y() implements Parent {}
void test(Parent parent) {
switch (parent) {
case Y y -> {}
case X x -> {
}
case Parent.X x -> {
}
}
}
}

View File

@@ -0,0 +1,19 @@
// "Create missing switch branch 'Ab'" "true"
sealed interface A {}
sealed interface Aa extends A {}
final class Aaa implements Aa {}
final class Aab implements Aa {}
final class Ab implements A {}
public class Test {
void test(A a) {
switch (a) {
case Aaa x -> {
}
case Aab x -> {
}
case Ab ab -> {
}
}
}
}

View File

@@ -0,0 +1,18 @@
// "Create missing switch branch 'Sub1'" "true"
sealed interface I {}
sealed interface J extends I {}
final class Sub1 implements I, J {}
final class Sub2 implements I {}
class Test {
void test(I i) {
switch (i) {
case Sub2 sub2:
break;
case Sub1 sub1:
break;
case J j:
break;
}
}
}

View File

@@ -0,0 +1,20 @@
// "Create missing switch branch 'Sub1'" "true"
sealed interface I {}
sealed interface J extends I {}
final class Sub1 implements I, J {}
final class Sub2 implements I {}
class Test {
void test(I i) {
switch (i) {
case Sub1 sub1 && Math.random() > 0.5:
break;
case Sub1 sub1:
break;
case Sub2 sub2:
break;
case J j:
break;
}
}
}

View File

@@ -6,12 +6,12 @@ final class Sub2 implements I {}
class Test {
void test(I i) {
switch (i) {
case Sub1 sub1 && sub1 != null:
break;
case Sub2 sub2:
case Sub1 sub1 && Math.random() > 0.5:
break;
case Sub1 sub1:
break;
case Sub2 sub2:
break;
}
}
}

View File

@@ -0,0 +1,17 @@
// "Create missing switch branch 'Sub1'" "true"
sealed interface I {}
final class Sub1 implements I {}
final class Sub2 implements I {}
class Test {
void test(I i) {
switch (i) {
case Sub1 sub1 && Math.random() > 0.5 -> {}
case Sub1 sub1 && Math.random() > 0.1 -> {}
case Sub1 sub1 && Math.random() > 0.5 -> {}
case Sub1 sub1 -> {
}
case Sub2 sub2 -> {}
}
}
}

View File

@@ -1,19 +0,0 @@
// "Create missing switch branch 'Sub2'" "true"
sealed abstract class I {
}
final class Sub1 extends I {
}
final class Sub2 extends I {
}
class Test {
void testI(I i) {
switch (i<caret>) {
case Sub1 s1:
System.out.println("ok");
break;
}
}
}

View File

@@ -1,14 +0,0 @@
// "Create missing branches: 'Scratch.X', and 'Scratch.Parent.X'" "true"
class Scratch {
sealed interface Parent {
record X() implements Parent {}
}
record X() implements Parent {}
record Y() implements Parent {}
void test(Parent parent) {
switch (parent<caret>) {
case Y y -> {}
}
}
}

View File

@@ -0,0 +1,17 @@
// "Create missing switch branch 'Ab'" "true"
sealed interface A {}
sealed interface Aa extends A {}
final class Aaa implements Aa {}
final class Aab implements Aa {}
final class Ab implements A {}
public class Test {
void test(A a) {
switch (a<caret>) {
case Aaa x -> {
}
case Aab x -> {
}
}
}
}

View File

@@ -0,0 +1,16 @@
// "Create missing switch branch 'Sub1'" "true"
sealed interface I {}
sealed interface J extends I {}
final class Sub1 implements I, J {}
final class Sub2 implements I {}
class Test {
void test(I i) {
switch (i<caret>) {
case Sub2 sub2:
break;
case J j:
break;
}
}
}

View File

@@ -0,0 +1,18 @@
// "Create missing switch branch 'Sub1'" "true"
sealed interface I {}
sealed interface J extends I {}
final class Sub1 implements I, J {}
final class Sub2 implements I {}
class Test {
void test(I i) {
switch (i<caret>) {
case Sub1 sub1 && Math.random() > 0.5:
break;
case Sub2 sub2:
break;
case J j:
break;
}
}
}

View File

@@ -6,7 +6,7 @@ final class Sub2 implements I {}
class Test {
void test(I i) {
switch (i<caret>) {
case Sub1 sub1 && sub1 != null:
case Sub1 sub1 && Math.random() > 0.5:
break;
case Sub2 sub2:
break;

View File

@@ -0,0 +1,15 @@
// "Create missing switch branch 'Sub1'" "true"
sealed interface I {}
final class Sub1 implements I {}
final class Sub2 implements I {}
class Test {
void test(I i) {
switch (i<caret>) {
case Sub1 sub1 && Math.random() > 0.5 -> {}
case Sub1 sub1 && Math.random() > 0.1 -> {}
case Sub1 sub1 && Math.random() > 0.5 -> {}
case Sub2 sub2 -> {}
}
}
}

View File

@@ -2,11 +2,9 @@
package com.siyeh.ig.fixes;
import com.intellij.codeInsight.intention.FileModifier;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiSwitchBlock;
import com.intellij.psi.PsiSwitchLabelStatementBase;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.InspectionGadgetsBundle;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -46,6 +44,10 @@ public class CreateSealedClassMissingSwitchBranchesFix extends CreateMissingSwit
@Override
protected @NotNull Function<PsiSwitchLabelStatementBase, List<String>> getCaseExtractor() {
return label -> Collections.emptyList();
return label -> {
PsiCaseLabelElementList list = label.getCaseLabelElementList();
if (list == null) return Collections.emptyList();
return ContainerUtil.map(list.getElements(), PsiCaseLabelElement::getText);
};
}
}

View File

@@ -82,7 +82,7 @@ public final class CreateSwitchBranchesUtil {
return PsiTreeUtil.getChildrenOfTypeAsList(block.getBody(), PsiSwitchLabelStatementBase.class);
}
Map<String, String> prevToNext =
StreamEx.of(allNames).pairMap(Couple::of).toMap(c -> c.getFirst(), c -> c.getSecond());
StreamEx.of(allNames).distinct().pairMap(Couple::of).toMap(c -> c.getFirst(), c -> c.getSecond());
List<String> missingLabels = StreamEx.of(allNames).filter(missingNames::contains).toList();
String nextLabel = getNextLabel(prevToNext, missingLabels);
PsiElement bodyElement = body.getFirstBodyElement();
@@ -90,8 +90,8 @@ public final class CreateSwitchBranchesUtil {
while (bodyElement != null) {
PsiSwitchLabelStatementBase label = ObjectUtils.tryCast(bodyElement, PsiSwitchLabelStatementBase.class);
if (label != null) {
List<String> constants = caseExtractor.apply(label);
while (nextLabel != null && constants.contains(nextLabel)) {
List<String> caseLabelNames = caseExtractor.apply(label);
while (nextLabel != null && caseLabelNames.contains(nextLabel)) {
addedLabels.add(addSwitchLabelStatementBefore(missingLabels.get(0), bodyElement, switchBlock, isRuleBasedFormat, isPatternsGenerated));
missingLabels.remove(0);
if (missingLabels.isEmpty()) {