mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-highlighting] IDEA-324654 Fixes to find missed and covered classes
GitOrigin-RevId: 07311efb7bd08b055b5b662be12ea59b9fdfc7d5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
4054012fb4
commit
51ab1f234c
+16
-26
@@ -29,7 +29,7 @@ import java.util.*;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.intellij.codeInsight.daemon.impl.analysis.SwitchBlockHighlightingModel.findMissedClassesForSealed;
|
||||
import static com.intellij.codeInsight.daemon.impl.analysis.SwitchBlockHighlightingModel.findMissedClasses;
|
||||
import static com.intellij.codeInsight.daemon.impl.analysis.SwitchBlockHighlightingModel.oneOfUnconditional;
|
||||
|
||||
final class PatternHighlightingModel {
|
||||
@@ -503,7 +503,7 @@ final class PatternHighlightingModel {
|
||||
/**
|
||||
* Try to reduce sealed classes to their supertypes or if selectorType is covered any of types,then return selectorType.
|
||||
* Previous sealed classes are not excluded because they can be used in another combination.
|
||||
* This method uses {@link SwitchBlockHighlightingModel#findMissedClassesForSealed(PsiType, List, List, PsiElement) findMissedClassesForSealed}
|
||||
* This method uses {@link SwitchBlockHighlightingModel#findMissedClasses(PsiType, List, List, PsiElement) findMissedClassesForSealed}
|
||||
* To prevent recursive calls, only TypeTest descriptions are passed to this method.
|
||||
*/
|
||||
@NotNull
|
||||
@@ -532,30 +532,20 @@ final class PatternHighlightingModel {
|
||||
StreamEx.of(patterns).select(PatternTypeTestDescription.class).collect(Collectors.toSet());
|
||||
Set<PatternTypeTestDescription> toAdd = new HashSet<>();
|
||||
Set<PsiType> existedTypes = typeTestDescriptions.stream().map(t -> t.type()).collect(Collectors.toSet());
|
||||
boolean unconditionalCovers = false;
|
||||
for (PatternTypeTestDescription description : typeTestDescriptions) {
|
||||
if (oneOfUnconditional(description.type(), selectorType)) {
|
||||
toAdd.add(new PatternTypeTestDescription(selectorType));
|
||||
changed = true;
|
||||
unconditionalCovers = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!unconditionalCovers) {
|
||||
Set<PsiClass> visitedCovered = findMissedClassesForSealed(selectorType, new ArrayList<>(typeTestDescriptions), new ArrayList<>(), context).coveredClasses();
|
||||
for (PsiClass covered : visitedCovered) {
|
||||
PsiClassType classType = TypeUtils.getType(covered);
|
||||
if (!existedTypes.contains(classType)) {
|
||||
if (oneOfUnconditional(selectorType, classType)) {
|
||||
toAdd.add(new PatternTypeTestDescription(classType));
|
||||
changed = true;
|
||||
}
|
||||
//find something upper. let's change to selectorType
|
||||
if (oneOfUnconditional(classType, selectorType)) {
|
||||
toAdd.add(new PatternTypeTestDescription(selectorType));
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
Set<PsiClass> visitedCovered =
|
||||
findMissedClasses(selectorType, new ArrayList<>(typeTestDescriptions), new ArrayList<>(), context).coveredClasses();
|
||||
for (PsiClass covered : visitedCovered) {
|
||||
PsiClassType classType = TypeUtils.getType(covered);
|
||||
if (!existedTypes.contains(classType)) {
|
||||
if (oneOfUnconditional(selectorType, classType)) {
|
||||
toAdd.add(new PatternTypeTestDescription(classType));
|
||||
changed = true;
|
||||
}
|
||||
//find something upper. let's change to selectorType
|
||||
if (oneOfUnconditional(classType, selectorType)) {
|
||||
toAdd.add(new PatternTypeTestDescription(selectorType));
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-19
@@ -515,6 +515,7 @@ public class SwitchBlockHighlightingModel {
|
||||
|
||||
/**
|
||||
* Finds the missed and covered classes for a sealed selector type.
|
||||
* If a selector type is not sealed classes, it will be checked if it is covered by one of elements or enumConstants
|
||||
*
|
||||
* @param selectorType the selector type
|
||||
* @param elements the pattern descriptions, unconditional
|
||||
@@ -522,10 +523,10 @@ public class SwitchBlockHighlightingModel {
|
||||
* @param context the context element (parent of pattern descriptions)
|
||||
* @return the container of missed and covered classes (may contain classes outside the selector type hierarchy)
|
||||
*/
|
||||
static @NotNull SealedResult findMissedClassesForSealed(@NotNull PsiType selectorType,
|
||||
@NotNull List<PatternDescription> elements,
|
||||
@NotNull List<PsiEnumConstant> enumConstants,
|
||||
@NotNull PsiElement context) {
|
||||
static @NotNull SealedResult findMissedClasses(@NotNull PsiType selectorType,
|
||||
@NotNull List<PatternDescription> elements,
|
||||
@NotNull List<PsiEnumConstant> enumConstants,
|
||||
@NotNull PsiElement context) {
|
||||
//Used to keep dependencies. The last dependency is one of the selector types.
|
||||
record ClassWithDependencies(PsiClass mainClass, List<PsiClass> dependencies) {
|
||||
}
|
||||
@@ -535,19 +536,13 @@ public class SwitchBlockHighlightingModel {
|
||||
Set<PsiClass> missingClasses = new LinkedHashSet<>();
|
||||
|
||||
LinkedHashMap<PsiClass, PsiType> permittedPatternClasses = findPermittedClasses(elements);
|
||||
HashSet<PsiType> usedTypes = new HashSet<>(permittedPatternClasses.values());
|
||||
//according JEP 440-441 only direct abstract sealed classes are allowed (14.11.1.1)
|
||||
Set<PsiClass> sealedUpperClasses = findSealedUpperClasses(permittedPatternClasses.keySet());
|
||||
|
||||
List<PatternTypeTestDescription> typeTestPatternsOutOfSealed = StreamEx.of(elements)
|
||||
.select(PatternTypeTestDescription.class)
|
||||
.filter(pattern -> !usedTypes.contains(pattern.type()))
|
||||
.toList();
|
||||
List<PatternTypeTestDescription> typeTestPatterns = ContainerUtil.filterIsInstance(elements, PatternTypeTestDescription.class);
|
||||
|
||||
Set<PsiClass> selectorClasses = StreamEx.of(getAllTypes(selectorType))
|
||||
.map(type -> PsiUtil.resolveClassInClassTypeOnly(TypeConversionUtil.erasure(type)))
|
||||
.nonNull()
|
||||
.toSet();
|
||||
Set<PsiClass> selectorClasses = ContainerUtil.map2SetNotNull(getAllTypes(selectorType),
|
||||
type -> PsiUtil.resolveClassInClassTypeOnly(TypeConversionUtil.erasure(type)));
|
||||
if (selectorClasses.isEmpty()) return new SealedResult(Collections.emptySet(), Collections.emptySet());
|
||||
|
||||
Queue<ClassWithDependencies> nonVisited = new ArrayDeque<>();
|
||||
@@ -589,13 +584,12 @@ public class SwitchBlockHighlightingModel {
|
||||
if (TypeConversionUtil.areTypesConvertible(targetType, selectorType) ||
|
||||
//we should consider items from the intersections in the usual way
|
||||
oneOfUnconditional(targetType, selectorType)) {
|
||||
if (//check a case, when we have something, which not in sealed hierarchy, but covers some leaves
|
||||
!ContainerUtil.exists(typeTestPatternsOutOfSealed, pattern -> oneOfUnconditional(pattern.type(), targetType)) &&
|
||||
//check if it is an enum and it is covered by all enums
|
||||
if (//check if it is an enum and it is covered by all enums
|
||||
!(psiClass.isEnum() && findMissingEnumConstant(psiClass, enumConstants).isEmpty()) &&
|
||||
//check if it is a record, and it is covered by record patterns (deconstruction)
|
||||
!(psiClass.isRecord() &&
|
||||
checkRecordPatternExhaustivenessForDescription(elements, targetType, context).isExhaustive())) {
|
||||
!(psiClass.isRecord() && checkRecordPatternExhaustivenessForDescription(elements, targetType, context).isExhaustive()) &&
|
||||
//check a case, when we have something, which not in sealed hierarchy, but covers some leaves
|
||||
!ContainerUtil.exists(typeTestPatterns, pattern -> oneOfUnconditional(pattern.type(), targetType))) {
|
||||
missingClasses.add(psiClass);
|
||||
visitedNotCovered.addAll(peeked.dependencies);
|
||||
}
|
||||
@@ -1231,7 +1225,7 @@ public class SwitchBlockHighlightingModel {
|
||||
}else{
|
||||
List<PatternDescription> descriptions = preparePatternDescription(elements);
|
||||
List<PsiEnumConstant> enumConstants = StreamEx.of(elements).map(element -> getEnumConstant(element)).nonNull().toList();
|
||||
List<PsiClass> missedSealedClasses = StreamEx.of(findMissedClassesForSealed(selectorType, descriptions, enumConstants, myBlock).missedClasses())
|
||||
List<PsiClass> missedSealedClasses = StreamEx.of(findMissedClasses(selectorType, descriptions, enumConstants, myBlock).missedClasses())
|
||||
.sortedBy(t->t.getQualifiedName())
|
||||
.toList();
|
||||
missedClasses = new LinkedHashSet<>();
|
||||
|
||||
Reference in New Issue
Block a user