[java] IDEA-345498 Remove explicit Java 20-preview support and parenthesized patterns

GitOrigin-RevId: 8d646035979e3ec0a7de3c6f58a4e6ec9967bdbd
This commit is contained in:
Tagir Valeev
2024-02-08 13:13:28 +01:00
committed by intellij-monorepo-bot
parent c56dbec5f8
commit d0cf7b359a
117 changed files with 262 additions and 1418 deletions

View File

@@ -787,9 +787,7 @@ public final class HighlightControlFlowUtil {
LanguageLevel level = PsiUtil.getLanguageLevel(refLabel);
//this assignment is covered by com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil.checkOutsideDeclaredCantBeAssignmentInGuard
boolean isAssignment = context instanceof PsiReferenceExpression psiExpression && PsiUtil.isAccessedForWriting(psiExpression);
if (((level == LanguageLevel.JDK_20_PREVIEW && refLabel != PsiTreeUtil.getParentOfType(variable, PsiSwitchLabelStatementBase.class)) ||
(level != LanguageLevel.JDK_20_PREVIEW && !isAssignment &&
!PsiTreeUtil.isAncestor(guardExpression, variable, false))) &&
if (!isAssignment && !PsiTreeUtil.isAncestor(guardExpression, variable, false) &&
!isEffectivelyFinal(variable, refLabel, context)) {
String message = JavaErrorBundle.message("guarded.pattern.variable.must.be.final");
HighlightInfo.Builder builder = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(context).descriptionAndTooltip(message);

View File

@@ -358,9 +358,6 @@ public final class HighlightUtil {
if (expressionVariable == null) {
return null;
}
if (PsiUtil.getLanguageLevel(expressionVariable) == LanguageLevel.JDK_20_PREVIEW) {
return null;
}
if (!PsiUtil.isAccessedForWriting(expressionVariable)) {
return null;
}
@@ -3842,6 +3839,7 @@ public final class HighlightUtil {
if (PsiUtil.isAvailable(feature, element)) return;
if (feature.isLimited()) return; //no reason for applying it because it can be outdated
LanguageLevel applicableLevel = getApplicableLevel(element.getContainingFile(), feature);
if (applicableLevel == LanguageLevel.JDK_X) return; // do not suggest to use experimental level
registrar.add(getFixFactory().createIncreaseLanguageLevelFix(applicableLevel));
registrar.add(getFixFactory().createUpgradeSdkFor(applicableLevel));
registrar.add(getFixFactory().createShowModulePropertiesFix(element));

View File

@@ -878,9 +878,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!hasErrorResults()) HighlightUtil.checkInstanceOfApplicable(expression, myErrorSink);
if (!hasErrorResults()) add(GenericsHighlightUtil.checkInstanceOfGenericType(myLanguageLevel, expression));
if (!hasErrorResults() &&
myLanguageLevel.isAtLeast(LanguageLevel.JDK_16) &&
JavaFeature.PATTERNS.isSufficient(myLanguageLevel) &&
// 5.20.2 Removed restriction on pattern instanceof for unconditional patterns (JEP 432, 440)
(myLanguageLevel.isLessThan(LanguageLevel.JDK_21) && myLanguageLevel != LanguageLevel.JDK_20_PREVIEW)) {
!JavaFeature.PATTERN_GUARDS_AND_RECORD_PATTERNS.isSufficient(myLanguageLevel)) {
add(HighlightUtil.checkInstanceOfPatternSupertype(expression));
}
}
@@ -2003,16 +2003,10 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
// suggest increasing the language level.
}
@Override
public void visitParenthesizedPattern(@NotNull PsiParenthesizedPattern pattern) {
super.visitParenthesizedPattern(pattern);
add(checkFeature(pattern, JavaFeature.PARENTHESIZED_PATTERNS));
}
@Override
public void visitPatternVariable(@NotNull PsiPatternVariable variable) {
super.visitPatternVariable(variable);
if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_20_PREVIEW) && variable.getPattern() instanceof PsiDeconstructionPattern) {
if (variable.getPattern() instanceof PsiDeconstructionPattern) {
String message = JavaErrorBundle.message("identifier.is.not.allowed.here");
add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(variable).descriptionAndTooltip(message));
}

View File

@@ -44,7 +44,6 @@ public enum HighlightingFeature {
LOCAL_INTERFACES(JavaFeature.LOCAL_INTERFACES),
LOCAL_ENUMS(JavaFeature.LOCAL_ENUMS),
INNER_STATICS(JavaFeature.INNER_STATICS),
PARENTHESIZED_PATTERNS(JavaFeature.PARENTHESIZED_PATTERNS),
PATTERNS_IN_SWITCH(JavaFeature.PATTERNS_IN_SWITCH),
PATTERN_GUARDS_AND_RECORD_PATTERNS(JavaFeature.PATTERN_GUARDS_AND_RECORD_PATTERNS),
RECORD_PATTERNS_IN_FOR_EACH(JavaFeature.RECORD_PATTERNS_IN_FOR_EACH),

View File

@@ -12,7 +12,6 @@ import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.modcommand.ModCommandAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.PsiClassType.ClassResolveResult;
import com.intellij.psi.util.*;
@@ -57,14 +56,6 @@ final class PatternHighlightingModel {
errorSink.accept(info);
return true;
}
PsiJavaCodeReferenceElement ref = typeElement.getInnermostComponentReferenceElement();
if (recordClass.hasTypeParameters() && ref != null && ref.getTypeParameterCount() == 0 &&
PsiUtil.getLanguageLevel(deconstructionPattern).isLessThan(LanguageLevel.JDK_20_PREVIEW)) {
String message = JavaErrorBundle.message("error.raw.deconstruction", typeElement.getText());
HighlightInfo.Builder info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(message);
errorSink.accept(info);
return true;
}
PsiSubstitutor substitutor = resolveResult.getSubstitutor();
PsiRecordComponent[] recordComponents = recordClass.getRecordComponents();
PsiPattern[] deconstructionComponents = deconstructionPattern.getDeconstructionList().getDeconstructionComponents();
@@ -220,9 +211,6 @@ final class PatternHighlightingModel {
static RecordExhaustivenessResult checkRecordExhaustiveness(@NotNull List<? extends PsiCaseLabelElement> elements,
@NotNull PsiType selectorType,
@NotNull PsiElement context) {
if (PsiUtil.getLanguageLevel(context) == LanguageLevel.JDK_20_PREVIEW) {
return PatternHighlightingModelJava20Preview.checkRecordExhaustiveness(elements);
}
return checkRecordPatternExhaustivenessForDescription(preparePatternDescription(elements), selectorType, context);
}

View File

@@ -1,310 +0,0 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.daemon.impl.analysis;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.PsiClassType.ClassResolveResult;
import com.intellij.psi.util.JavaPsiPatternUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.containers.SmartHashSet;
import com.siyeh.ig.psiutils.TypeUtils;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import static com.intellij.codeInsight.daemon.impl.analysis.PatternHighlightingModel.RecordExhaustivenessResult;
import static com.intellij.psi.PsiModifier.ABSTRACT;
import static com.intellij.psi.PsiModifier.SEALED;
final class PatternHighlightingModelJava20Preview {
/**
* Old implementation for Java 20 PREVIEW
*/
@NotNull
static RecordExhaustivenessResult checkRecordExhaustiveness(@NotNull List<? extends PsiCaseLabelElement> caseElements) {
List<PsiPrimaryPattern> unconditionalPatterns =
ContainerUtil.mapNotNull(caseElements, element -> JavaPsiPatternUtil.findUnconditionalPattern(element));
List<PsiDeconstructionPattern> unconditionalDeconstructions =
ContainerUtil.filterIsInstance(unconditionalPatterns, PsiDeconstructionPattern.class);
if (unconditionalDeconstructions.isEmpty()) {
return RecordExhaustivenessResult.createExhaustiveResult(); //no deconstruction
}
PsiDeconstructionPattern scope = unconditionalDeconstructions.get(0);
MultiMap<PsiType, PsiDeconstructionPattern> deconstructionGroups =
ContainerUtil.groupBy(unconditionalDeconstructions, deconstruction -> JavaPsiPatternUtil.getPatternType(deconstruction));
MultiMap<PsiType, PsiTypeTestPattern> typeTestPatterns =
ContainerUtil.groupBy(
ContainerUtil.filterIsInstance(unconditionalPatterns, PsiTypeTestPattern.class),
pattern -> JavaPsiPatternUtil.getPatternType(pattern));
RecordExhaustivenessResult result = RecordExhaustivenessResult.createExhaustiveResult();
for (Map.Entry<PsiType, Collection<PsiDeconstructionPattern>> entry : deconstructionGroups.entrySet()) {
PsiType type = entry.getKey();
if (type == null) continue;
Collection<PsiTypeTestPattern> patterns = typeTestPatterns.get(type);
if (!patterns.isEmpty()) {
for (PsiPrimaryPattern pattern : patterns) {
//check, there is a non-deconstruction pattern, which cover it
if (JavaPsiPatternUtil.isUnconditionalForType(pattern, type)) {
return RecordExhaustivenessResult.createExhaustiveResult();
}
}
}
ClassResolveResult resolve = PsiUtil.resolveGenericsClassInType(PsiUtil.captureToplevelWildcards(type, scope));
PsiClass selectorClass = resolve.getElement();
PsiSubstitutor substitutor = resolve.getSubstitutor();
if (selectorClass == null) continue;
List<PsiType> recordTypes =
ContainerUtil.map(selectorClass.getRecordComponents(), component -> substitutor.substitute(component.getType()));
List<List<PsiPattern>> deconstructionComponentsGroup = ContainerUtil.map(entry.getValue(), deconstruction -> Arrays.asList(
deconstruction.getDeconstructionList().getDeconstructionComponents()));
if (ContainerUtil.exists(deconstructionComponentsGroup, group -> group.size() != recordTypes.size())) {
return RecordExhaustivenessResult.createExhaustiveResult(); //it checked before, don't repeat error
}
RecordExhaustivenessResult currentResult = findExhaustiveInGroup(type, recordTypes, deconstructionComponentsGroup);
result.merge(currentResult);
}
return result;
}
/**
* Old implementation for Java 20 PREVIEW
*/
@NotNull
private static RecordExhaustivenessResult findExhaustiveInGroup(@NotNull PsiType currentRecordType,
@NotNull List<? extends PsiType> leftRecordTypes,
@NotNull List<? extends List<PsiPattern>> deconstructions) {
if (leftRecordTypes.isEmpty() || ContainerUtil.exists(deconstructions, t -> t.size() == 0)) {
//there is no deconstruction, a case with an empty set of labels is considered before, don't repeat errors
return RecordExhaustivenessResult.createExhaustiveResult();
}
PsiType typeToCheck = leftRecordTypes.get(0);
//A case with unresolved type checks before, don't repeat errors
if (typeToCheck == null) return RecordExhaustivenessResult.createExhaustiveResult();
MultiMap<PsiType, List<PsiPattern>> groupedByType = ContainerUtil.groupBy(deconstructions,
deconstructionComponents -> JavaPsiPatternUtil.getPatternType(
deconstructionComponents.get(0)));
List<GroupExhaustiveness> groupsExhaustiveness = getGroupsExhaustiveness(currentRecordType, leftRecordTypes, groupedByType);
if (groupsExhaustiveness.isEmpty()) return RecordExhaustivenessResult.createNotBeAdded();
List<PsiPattern> checkedExhaustivePatterns = new ArrayList<>();
Map<PsiType, BranchesExhaustiveness> notExhaustive = new LinkedHashMap<>();
for (GroupExhaustiveness group : groupsExhaustiveness) {
if (!group.branchesExhaustiveness().result().isExhaustive()) {
PsiType notExhaustiveType = group.psiType();
notExhaustive.put(notExhaustiveType, group.branchesExhaustiveness());
continue;
}
Collection<List<PsiPattern>> lists = groupedByType.get(group.psiType());
if (lists.isEmpty()) continue;
List<PsiPattern> next = lists.iterator().next();
if (next == null || next.isEmpty()) continue;
checkedExhaustivePatterns.add(next.get(0));
}
if (ContainerUtil.exists(checkedExhaustivePatterns, pattern -> JavaPsiPatternUtil.isUnconditionalForType(pattern, typeToCheck, true))) {
return RecordExhaustivenessResult.createExhaustiveResult(); // exhaustive even without not-exhaustive-subgroup
}
Set<PsiClass> missedClasses = findMissedClassesForSealed(typeToCheck, checkedExhaustivePatterns);
if (missedClasses.isEmpty() && !checkedExhaustivePatterns.isEmpty()) {
return RecordExhaustivenessResult.createExhaustiveResult(); //exhaustive even without not-exhaustive-subgroup
}
//if one of them is unconditional, return any of them
List<BranchesExhaustiveness> coveredPatterns =
ContainerUtil.filter(notExhaustive.values(), group ->
group.branches().stream()
.filter(t -> !t.isEmpty())
.map(patterns -> patterns.get(0))
.anyMatch(pattern -> JavaPsiPatternUtil.isUnconditionalForType(pattern, typeToCheck, true)));
if (!coveredPatterns.isEmpty()) {
RecordExhaustivenessResult nextResult = coveredPatterns.get(0).result();
nextResult.addNextType(currentRecordType, typeToCheck);
return nextResult;
}
return mergeMissedClasses(currentRecordType, leftRecordTypes, notExhaustive, missedClasses);
}
/**
* Old implementation for Java 20 PREVIEW
*/
@NotNull
private static RecordExhaustivenessResult mergeMissedClasses(@NotNull PsiType recordType,
@NotNull List<? extends PsiType> recordTypes,
@NotNull Map<PsiType, BranchesExhaustiveness> notExhaustiveBranches,
@NotNull Set<PsiClass> missedClasses) {
RecordExhaustivenessResult result = RecordExhaustivenessResult.createNotExhaustiveResult();
for (PsiClass missedClass : missedClasses) {
PsiClassType missedType = PsiTypesUtil.getClassType(missedClass);
BranchesExhaustiveness branchesExhaustiveness = notExhaustiveBranches.get(missedType);
if (branchesExhaustiveness == null) {
//There is a chance that branchExhaustiveness cover partially this new branch,
//but let's not recalculate and make it simple and fast.
//Otherwise, we have to process all classes in a permit list every time
result.addNewBranch(recordType, missedType, recordTypes);
}
else {
RecordExhaustivenessResult recordExhaustivenessResult = branchesExhaustiveness.result();
recordExhaustivenessResult.addNextType(recordType, missedType);
result.merge(recordExhaustivenessResult);
}
}
return result;
}
/**
* Old implementation for Java 20 PREVIEW
*/
private record GroupExhaustiveness(@NotNull PsiType psiType,
@NotNull PatternHighlightingModelJava20Preview.BranchesExhaustiveness branchesExhaustiveness) {
GroupExhaustiveness(@NotNull PsiType psiType, @NotNull RecordExhaustivenessResult result,
@NotNull Collection<List<PsiPattern>> branches) {
this(psiType, new BranchesExhaustiveness(result, branches));
}
}
/**
* Old implementation for Java 20 PREVIEW
*/
private record BranchesExhaustiveness(@NotNull RecordExhaustivenessResult result,
@NotNull Collection<List<PsiPattern>> branches) {
}
/**
* Old implementation for Java 20 PREVIEW
*/
@NotNull
private static List<GroupExhaustiveness> getGroupsExhaustiveness(@NotNull PsiType recordType,
@NotNull List<? extends PsiType> recordTypes,
@NotNull MultiMap<PsiType, List<PsiPattern>> groupedByType) {
MultiMap<PsiType, List<PsiPattern>> deconstructionGroups = getDeconstructionGroupsByType(groupedByType);
return ContainerUtil.map(deconstructionGroups.entrySet(), deconstructionGroup -> {
if (ContainerUtil.exists(deconstructionGroup.getValue(), t -> t == null || t.isEmpty())) {
return new GroupExhaustiveness(deconstructionGroup.getKey(),
RecordExhaustivenessResult.createNotBeAdded(), deconstructionGroup.getValue());
}
List<PsiPattern> firstElements = ContainerUtil.map(deconstructionGroup.getValue(), it -> it.get(0));
if (ContainerUtil.exists(firstElements, pattern -> pattern instanceof PsiDeconstructionPattern)) {
RecordExhaustivenessResult nestedResult = checkRecordExhaustiveness(firstElements);
if (!nestedResult.isExhaustive()) {
//support only first level deconstruction
if (nestedResult.canBeAdded() && nestedResult.missedBranchesByType.size() == 1) {
RecordExhaustivenessResult result = RecordExhaustivenessResult.createNotExhaustiveResult();
result.addNewBranch(recordType, null, recordTypes);
return new GroupExhaustiveness(deconstructionGroup.getKey(), result, deconstructionGroup.getValue());
}
else {
return new GroupExhaustiveness(deconstructionGroup.getKey(), RecordExhaustivenessResult.createNotBeAdded(),
deconstructionGroup.getValue());
}
}
}
RecordExhaustivenessResult result = findExhaustiveInGroup(
recordType, dropFirst(recordTypes), ContainerUtil.map(deconstructionGroup.getValue(), PatternHighlightingModelJava20Preview::dropFirst)
);
return new GroupExhaustiveness(deconstructionGroup.getKey(), result, deconstructionGroup.getValue());
});
}
/**
* Old implementation for Java 20 PREVIEW
*/
@NotNull
private static MultiMap<PsiType, List<PsiPattern>> getDeconstructionGroupsByType(@NotNull MultiMap<PsiType, List<PsiPattern>> groupedByType) {
MultiMap<PsiType, List<PsiPattern>> deconstructionGroups = MultiMap.create();
Set<PsiType> types = new HashSet<>(groupedByType.keySet());
for (PsiType currentType : types) {
for (PsiType compareType : groupedByType.keySet()) {
if (JavaPsiPatternUtil.dominates(compareType, currentType)) {
deconstructionGroups.putValues(currentType, groupedByType.get(compareType));
}
}
}
return deconstructionGroups;
}
/**
* Old implementation for Java 20 PREVIEW
*/
private static <T> List<T> dropFirst(List<T> list) {
return list.subList(1, list.size());
}
static @NotNull Set<PsiClass> findMissedClassesForSealed(@NotNull PsiType selectorType,
@NotNull List<? extends PsiCaseLabelElement> elements) {
LinkedHashMap<PsiClass, PsiPattern> patternClasses = findPatternClasses(elements);
List<PsiPrimaryPattern> unconditionalPatterns =
ContainerUtil.mapNotNull(elements, element -> JavaPsiPatternUtil.findUnconditionalPattern(element));
List<PsiTypeTestPattern> typeTestPatterns =
ContainerUtil.filterIsInstance(unconditionalPatterns, PsiTypeTestPattern.class);
PsiClass selectorClass = PsiUtil.resolveClassInClassTypeOnly(TypeConversionUtil.erasure(selectorType));
if (selectorClass == null) return Collections.emptySet();
Queue<PsiClass> nonVisited = new ArrayDeque<>();
nonVisited.add(selectorClass);
Set<PsiClass> visited = new SmartHashSet<>();
Set<PsiClass> missingClasses = new LinkedHashSet<>();
while (!nonVisited.isEmpty()) {
PsiClass psiClass = nonVisited.peek();
if (psiClass.hasModifierProperty(SEALED) && (psiClass.hasModifierProperty(ABSTRACT) ||
psiClass.equals(selectorClass))) {
for (PsiClass permittedClass : SwitchBlockHighlightingModel.PatternsInSwitchBlockHighlightingModel.getPermittedClasses(psiClass)) {
if (!visited.add(permittedClass)) continue;
PsiPattern pattern = patternClasses.get(permittedClass);
PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(selectorClass, permittedClass, PsiSubstitutor.EMPTY);
PsiType permittedType = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, substitutor);
if (pattern == null && (PsiUtil.getLanguageLevel(permittedClass).isLessThan(LanguageLevel.JDK_18) ||
TypeConversionUtil.areTypesConvertible(selectorType, permittedType)) ||
pattern != null && !JavaPsiPatternUtil.isUnconditionalForType(pattern, TypeUtils.getType(permittedClass), true)) {
nonVisited.add(permittedClass);
}
}
}
else {
visited.add(psiClass);
if (!ContainerUtil.exists(typeTestPatterns,
pattern -> JavaPsiPatternUtil.isUnconditionalForType(pattern, TypeUtils.getType(psiClass), true))) {
missingClasses.add(psiClass);
}
}
nonVisited.poll();
}
if (!selectorClass.hasModifierProperty(ABSTRACT)) {
missingClasses.add(selectorClass);
}
return missingClasses;
}
private static @NotNull LinkedHashMap<PsiClass, PsiPattern> findPatternClasses(@NotNull List<? extends PsiCaseLabelElement> elements) {
LinkedHashMap<PsiClass, PsiPattern> patternClasses = new LinkedHashMap<>();
for (PsiCaseLabelElement element : elements) {
PsiPattern pattern = SwitchBlockHighlightingModel.extractPattern(element);
if (pattern == null) continue;
PsiClass patternClass;
patternClass = PsiUtil.resolveClassInClassTypeOnly(JavaPsiPatternUtil.getPatternType(element));
if (patternClass != null) {
patternClasses.put(patternClass, pattern);
Set<PsiClass> classes = SwitchBlockHighlightingModel.returnAllPermittedClasses(patternClass);
for (PsiClass aClass : classes) {
patternClasses.put(aClass, pattern);
}
}
}
return patternClasses;
}
}

View File

@@ -1167,8 +1167,7 @@ public class SwitchBlockHighlightingModel {
AtomicBoolean reported = new AtomicBoolean();
dominatedLabels.forEach((overWhom, who) -> {
HighlightInfo.Builder info = createError(overWhom, JavaErrorBundle.message("switch.dominance.of.preceding.label", who.getText()));
if (PsiUtil.getLanguageLevel(who).isAtLeast(LanguageLevel.JDK_20_PREVIEW) &&
who instanceof PsiKeyword && PsiKeyword.DEFAULT.equals(who.getText()) ||
if (who instanceof PsiKeyword && PsiKeyword.DEFAULT.equals(who.getText()) ||
isInCaseNullDefaultLabel(who)) {
PsiSwitchLabelStatementBase labelStatementBase = PsiTreeUtil.getParentOfType(who, PsiSwitchLabelStatementBase.class);
if (labelStatementBase != null) {
@@ -1238,7 +1237,7 @@ public class SwitchBlockHighlightingModel {
}
List<PsiType> sealedTypes = getAbstractSealedTypes(selectorTypes);
if (!sealedTypes.isEmpty()) {
errorSink.accept(checkSealed(elements, selectorClass));
errorSink.accept(checkSealedClassCompleteness(mySelectorType, elements));
return;
}
//records are final; checking intersections are not needed
@@ -1255,18 +1254,6 @@ public class SwitchBlockHighlightingModel {
}
}
private HighlightInfo.Builder checkSealed(@NotNull List<? extends PsiCaseLabelElement> elements,
@Nullable PsiClass selectorClass) {
HighlightInfo.Builder info = checkSealedClassCompleteness(mySelectorType, elements);
if (info != null) {
return info;
}
if (selectorClass != null && PsiUtil.getLanguageLevel(selectorClass) == LanguageLevel.JDK_20_PREVIEW) {
return checkRecordExhaustiveness(elements, mySelectorType);
}
return null;
}
@NotNull
private static List<PsiType> getAbstractSealedTypes(@NotNull List<PsiType> selectorTypes) {
return selectorTypes.stream()
@@ -1312,9 +1299,7 @@ public class SwitchBlockHighlightingModel {
}
else if (labelElement instanceof PsiExpression) {
boolean isNullType = isNullType(labelElement);
if (isNullType &&
PsiUtil.getLanguageLevel(labelElement).isAtLeast(LanguageLevel.JDK_20_PREVIEW) &&
isInCaseNullDefaultLabel(labelElement)) {
if (isNullType && isInCaseNullDefaultLabel(labelElement)) {
// JEP 432
// A 'case null, default' label dominates all other switch labels.
//
@@ -1346,26 +1331,22 @@ public class SwitchBlockHighlightingModel {
private HighlightInfo.Builder checkSealedClassCompleteness(@NotNull PsiType selectorType,
@NotNull List<? extends PsiCaseLabelElement> elements) {
Set<PsiClass> missedClasses;
if (LanguageLevel.JDK_20_PREVIEW == PsiUtil.getLanguageLevel(myBlock)) {
missedClasses = PatternHighlightingModelJava20Preview.findMissedClassesForSealed(selectorType, elements);
}else{
List<PatternDescription> descriptions = preparePatternDescription(elements);
List<PsiEnumConstant> enumConstants = StreamEx.of(elements).map(element -> getEnumConstant(element)).nonNull().toList();
List<PsiClass> missedSealedClasses = StreamEx.of(findMissedClasses(selectorType, descriptions, enumConstants, myBlock).missedClasses())
.sortedBy(t->t.getQualifiedName())
.toList();
missedClasses = new LinkedHashSet<>();
//if T is intersection types, it is allowed to choose any of them to cover
for (PsiClass missedClass : missedSealedClasses) {
PsiClassType missedClassType = TypeUtils.getType(missedClass);
if (oneOfUnconditional(missedClassType, selectorType)) {
missedClasses.clear();
missedClasses.add(missedClass);
break;
}
else {
missedClasses.add(missedClass);
}
List<PatternDescription> descriptions = preparePatternDescription(elements);
List<PsiEnumConstant> enumConstants = StreamEx.of(elements).map(element -> getEnumConstant(element)).nonNull().toList();
List<PsiClass> missedSealedClasses = StreamEx.of(findMissedClasses(selectorType, descriptions, enumConstants, myBlock).missedClasses())
.sortedBy(t->t.getQualifiedName())
.toList();
missedClasses = new LinkedHashSet<>();
//if T is intersection types, it is allowed to choose any of them to cover
for (PsiClass missedClass : missedSealedClasses) {
PsiClassType missedClassType = TypeUtils.getType(missedClass);
if (oneOfUnconditional(missedClassType, selectorType)) {
missedClasses.clear();
missedClasses.add(missedClass);
break;
}
else {
missedClasses.add(missedClass);
}
}
if (missedClasses.isEmpty()) return null;

View File

@@ -8,10 +8,8 @@ import com.intellij.codeInspection.dataFlow.jvm.problems.JvmDfaProblem;
import com.intellij.codeInspection.dataFlow.types.DfTypes;
import com.intellij.codeInspection.util.InspectionMessage;
import com.intellij.java.analysis.JavaAnalysisBundle;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.JavaPsiPatternUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
@@ -352,12 +350,7 @@ public final class NullabilityProblemKind<T extends PsiElement> {
PsiCaseLabelElementList labelElementList = labelStatement.getCaseLabelElementList();
if (labelElementList == null) continue;
for (PsiCaseLabelElement element : labelElementList.getElements()) {
if (element instanceof PsiExpression && TypeConversionUtil.isNullType(((PsiExpression)element).getType())) return null;
if (PsiUtil.getLanguageLevel(element).isLessThan(LanguageLevel.JDK_20_PREVIEW) &&
element instanceof PsiPattern && expressionType != null &&
JavaPsiPatternUtil.isUnconditionalForType(element, expressionType)) {
return null;
}
if (element instanceof PsiExpression caseExpression && TypeConversionUtil.isNullType(caseExpression.getType())) return null;
}
}
}

View File

@@ -36,7 +36,6 @@ import com.intellij.codeInspection.dataFlow.types.DfTypes;
import com.intellij.codeInspection.dataFlow.value.*;
import com.intellij.codeInspection.dataFlow.value.DfaControlTransferValue.Trap;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.augment.PsiAugmentProvider;
import com.intellij.psi.impl.source.tree.java.PsiEmptyExpressionImpl;
@@ -1114,7 +1113,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
private void processPatternInInstanceof(@NotNull PsiPattern pattern, @NotNull PsiInstanceOfExpression expression,
@NotNull PsiType checkType) {
boolean potentiallyRedundantInstanceOf = pattern instanceof PsiTypeTestPattern ||
JavaPsiPatternUtil.skipParenthesizedPatternDown(pattern) instanceof PsiTypeTestPattern ||
pattern instanceof PsiTypeTestPattern ||
pattern instanceof PsiDeconstructionPattern dec && JavaPsiPatternUtil.hasUnconditionalComponents(dec);
DfaAnchor instanceofAnchor = potentiallyRedundantInstanceOf ? new JavaExpressionAnchor(expression) : null;
DeferredOffset endPatternOffset = new DeferredOffset();
@@ -1128,10 +1127,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
private void processPattern(@NotNull PsiPattern sourcePattern, @Nullable PsiPattern innerPattern,
@NotNull PsiType checkType, @Nullable DfaAnchor instanceofAnchor, @NotNull DeferredOffset endPatternOffset) {
if (innerPattern == null) return;
else if (innerPattern instanceof PsiParenthesizedPattern) {
PsiPattern unwrappedPattern = JavaPsiPatternUtil.skipParenthesizedPatternDown(innerPattern);
processPattern(sourcePattern, unwrappedPattern, checkType, instanceofAnchor, endPatternOffset);
}
else if (innerPattern instanceof PsiDeconstructionPattern deconstructionPattern) {
PsiPatternVariable variable = deconstructionPattern.getPatternVariable();
PsiType patternType = deconstructionPattern.getTypeElement().getType();
@@ -1186,10 +1181,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
@NotNull DeferredOffset endPatternOffset,
@NotNull DfaVariableValue patternDfaVar,
@Nullable DfaAnchor instanceofAnchor) {
boolean java20plus = PsiUtil.getLanguageLevel(myCodeFragment).isAtLeast(LanguageLevel.JDK_20_PREVIEW);
if (java20plus
? (sourcePattern == innerPattern || !JavaPsiPatternUtil.isUnconditionalForType(innerPattern, checkType))
: !JavaPsiPatternUtil.isUnconditionalForType(innerPattern, checkType)) {
if (sourcePattern == innerPattern || !JavaPsiPatternUtil.isUnconditionalForType(innerPattern, checkType)) {
addPatternTypeTest(innerPattern, instanceofAnchor, endPatternOffset, patternDfaVar);
}
else {

View File

@@ -18,7 +18,6 @@ package com.siyeh.ig.errorhandling;
import com.intellij.codeInspection.options.OptPane;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.JavaPsiPatternUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Query;
@@ -182,7 +181,7 @@ public final class ExceptionFromCatchWhichDoesntWrapInspection extends BaseInspe
if (!(pattern instanceof PsiTypeTestPattern)) {
return;
}
final PsiElement parent = JavaPsiPatternUtil.skipParenthesizedPatternUp(pattern.getParent());
final PsiElement parent = pattern.getParent();
if (parent instanceof PsiInstanceOfExpression instanceOfExpression) {
instanceOfExpression.getOperand().accept(this);
}

View File

@@ -488,8 +488,8 @@ public class EquivalenceChecker {
if (pattern1 == null || pattern2 == null) {
return EXACT_MISMATCH;
}
pattern1 = JavaPsiPatternUtil.skipParenthesizedPatternDown(pattern1);
pattern2 = JavaPsiPatternUtil.skipParenthesizedPatternDown(pattern2);
pattern1 = pattern1;
pattern2 = pattern2;
if (pattern1 instanceof PsiUnnamedPattern && pattern2 instanceof PsiUnnamedPattern) {
return EXACT_MATCH;
}
@@ -624,7 +624,7 @@ public class EquivalenceChecker {
private static PsiCaseLabelElement skipParenthesizedElementDown(@Nullable PsiCaseLabelElement element) {
if (element instanceof PsiPattern) {
return JavaPsiPatternUtil.skipParenthesizedPatternDown((PsiPattern)element);
return (PsiPattern)element;
}
if (element instanceof PsiExpression) {
return PsiUtil.skipParenthesizedExprDown((PsiExpression)element);

View File

@@ -147,28 +147,6 @@ public final class ParenthesesUtils {
else if (element instanceof PsiLambdaExpression lambdaExpression) {
removeParensFromLambdaExpression(lambdaExpression, ignoreClarifyingParentheses);
}
else if (element instanceof PsiPattern pattern) {
removeParensFromPattern(pattern, ignoreClarifyingParentheses);
}
}
private static void removeParensFromPattern(PsiPattern pattern, boolean ignoreClarifyingParentheses) {
if (pattern instanceof PsiParenthesizedPattern parenthesizedPattern) {
final PsiPattern innerPattern = parenthesizedPattern.getPattern();
if (innerPattern == null) {
return;
}
CommentTracker commentTracker = new CommentTracker();
commentTracker.markUnchanged(innerPattern);
PsiPattern newPattern = (PsiPattern)commentTracker.replaceAndRestoreComments(parenthesizedPattern, innerPattern);
removeParentheses(newPattern, ignoreClarifyingParentheses);
}
else if (pattern instanceof PsiDeconstructionPattern deconstructionPattern) {
final PsiPattern[] components = deconstructionPattern.getDeconstructionList().getDeconstructionComponents();
for (PsiPattern component : components) {
removeParentheses(component, ignoreClarifyingParentheses);
}
}
}
private static void removeParensFromLambdaExpression(PsiLambdaExpression lambdaExpression, boolean ignoreClarifyingParentheses) {
@@ -222,10 +200,6 @@ public final class ParenthesesUtils {
boolean ignoreClarifyingParentheses) {
final PsiExpression operand = instanceofExpression.getOperand();
removeParentheses(operand, ignoreClarifyingParentheses);
final PsiPrimaryPattern pattern = instanceofExpression.getPattern();
if (pattern != null) {
removeParensFromPattern(pattern, ignoreClarifyingParentheses);
}
}
private static void removeParensFromPolyadicExpression(@NotNull PsiPolyadicExpression polyadicExpression,

View File

@@ -17,9 +17,9 @@ package com.siyeh.ig.style;
import com.intellij.codeInspection.CleanupLocalInspectionTool;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
import com.intellij.codeInspection.options.OptPane;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.siyeh.InspectionGadgetsBundle;
@@ -103,18 +103,6 @@ public final class UnnecessaryParenthesesInspection extends BaseInspection imple
}
}
@Override
public void visitParenthesizedPattern(@NotNull PsiParenthesizedPattern pattern) {
final PsiElement parent = pattern.getParent();
if (parent instanceof PsiParenthesizedPattern) {
return;
}
if (!ErrorUtil.containsDeepError(pattern)) {
registerError(pattern);
}
super.visitParenthesizedPattern(pattern);
}
@Override
public void visitParenthesizedExpression(@NotNull PsiParenthesizedExpression expression) {
final PsiElement parent = expression.getParent();

View File

@@ -195,7 +195,6 @@ jdk.17.language.level.description=17 - Sealed types, always-strict floating-poin
jdk.18.language.level.description=18 - JavaDoc snippets
jdk.19.language.level.description=19 - No new language features
jdk.20.language.level.description=20 - No new language features
jdk.20.preview.language.level.description=20 (Preview) - Record patterns (2nd preview), pattern matching for switch (4th preview)
jdk.21.language.level.description=21 - Record patterns, pattern matching for switch
jdk.21.preview.language.level.description=21 (Preview) - String templates, unnamed classes and instance main methods etc.
jdk.22.language.level.description=22 - Unnamed variables and patterns

View File

@@ -59,63 +59,15 @@ public enum JavaFeature {
ALWAYS_STRICTFP(LanguageLevel.JDK_17, "feature.strictfp"),
INNER_NOT_CAPTURE_THIS(LanguageLevel.JDK_18, "feature.no.this.capture"),
JAVADOC_SNIPPETS(LanguageLevel.JDK_18, "feature.javadoc.snippets"),
PARENTHESIZED_PATTERNS(LanguageLevel.JDK_20_PREVIEW, "feature.parenthesised.patterns"){
@Override
public boolean isSufficient(@NotNull LanguageLevel useSiteLevel) {
LanguageLevel until = LanguageLevel.JDK_20_PREVIEW;
return until == useSiteLevel;
}
@Override
public boolean isLimited() {
return true;
}
},
PATTERNS_IN_SWITCH(LanguageLevel.JDK_21, "feature.patterns.in.switch") {
@Override
public boolean isSufficient(@NotNull LanguageLevel useSiteLevel) {
return super.isSufficient(useSiteLevel) || LanguageLevel.JDK_20_PREVIEW == useSiteLevel;
}
},
PATTERN_GUARDS_AND_RECORD_PATTERNS(LanguageLevel.JDK_21, "feature.pattern.guard.and.record.patterns"){
@Override
public boolean isSufficient(@NotNull LanguageLevel useSiteLevel) {
return super.isSufficient(useSiteLevel) || LanguageLevel.JDK_20_PREVIEW == useSiteLevel;
}
},
RECORD_PATTERNS_IN_FOR_EACH(LanguageLevel.JDK_20_PREVIEW, "feature.record.patterns.in.for.each"){
@Override
public boolean isSufficient(@NotNull LanguageLevel useSiteLevel) {
return LanguageLevel.JDK_20_PREVIEW == useSiteLevel.getSupportedLevel();
}
@Override
public boolean isLimited() {
return true;
}
},
VIRTUAL_THREADS(LanguageLevel.JDK_20_PREVIEW, "feature.virtual.threads") {
@Override
public boolean isSufficient(@NotNull LanguageLevel useSiteLevel) {
return LanguageLevel.JDK_20_PREVIEW == useSiteLevel.getSupportedLevel();
}
@Override
public boolean isLimited() {
return true;
}
},
FOREIGN_FUNCTIONS(LanguageLevel.JDK_20_PREVIEW, "feature.foreign.functions") {
@Override
public boolean isSufficient(@NotNull LanguageLevel useSiteLevel) {
return LanguageLevel.JDK_20_PREVIEW == useSiteLevel.getSupportedLevel();
}
@Override
public boolean isLimited() {
return true;
}
},
PATTERNS_IN_SWITCH(LanguageLevel.JDK_21, "feature.patterns.in.switch"),
PATTERN_GUARDS_AND_RECORD_PATTERNS(LanguageLevel.JDK_21, "feature.pattern.guard.and.record.patterns"),
/**
* Was a preview feature in Java 20 Preview.
* Keep the implementation, as it could reappear in the future.
*/
RECORD_PATTERNS_IN_FOR_EACH(LanguageLevel.JDK_X, "feature.record.patterns.in.for.each"),
VIRTUAL_THREADS(LanguageLevel.JDK_21, "feature.virtual.threads"),
FOREIGN_FUNCTIONS(LanguageLevel.JDK_21, "feature.foreign.functions"),
ENUM_QUALIFIED_NAME_IN_SWITCH(LanguageLevel.JDK_21, "feature.enum.qualified.name.in.switch"),
STRING_TEMPLATES(LanguageLevel.JDK_21_PREVIEW, "feature.string.templates"),
UNNAMED_PATTERNS_AND_VARIABLES(LanguageLevel.JDK_22, "feature.unnamed.vars") {

View File

@@ -44,7 +44,6 @@ public enum LanguageLevel {
JDK_18(JavaPsiBundle.messagePointer("jdk.18.language.level.description"), 18),
JDK_19(JavaPsiBundle.messagePointer("jdk.19.language.level.description"), 19),
JDK_20(JavaPsiBundle.messagePointer("jdk.20.language.level.description"), 20),
JDK_20_PREVIEW(JavaPsiBundle.messagePointer("jdk.20.preview.language.level.description"), 20),
JDK_21(JavaPsiBundle.messagePointer("jdk.21.language.level.description"), 21),
JDK_21_PREVIEW(JavaPsiBundle.messagePointer("jdk.21.preview.language.level.description"), 21),
JDK_22(JavaPsiBundle.messagePointer("jdk.22.language.level.description"), 22),
@@ -56,11 +55,13 @@ public enum LanguageLevel {
// except the tests that explicitly test the obsolete levels
@ApiStatus.Obsolete
JDK_17_PREVIEW(17, JDK_20_PREVIEW),
JDK_17_PREVIEW(17, JDK_21),
@ApiStatus.Obsolete
JDK_18_PREVIEW(18, JDK_20_PREVIEW),
JDK_18_PREVIEW(18, JDK_21),
@ApiStatus.Obsolete
JDK_19_PREVIEW(19, JDK_20_PREVIEW),
JDK_19_PREVIEW(19, JDK_21),
@ApiStatus.Obsolete
JDK_20_PREVIEW(20, JDK_21),
;
/**

View File

@@ -33,7 +33,7 @@ public class BasicPatternParser {
*/
@Contract(pure = true)
public boolean isPattern(final PsiBuilder builder) {
PsiBuilder.Marker patternStart = preParsePattern(builder, true);
PsiBuilder.Marker patternStart = preParsePattern(builder);
if (patternStart == null) {
return false;
}
@@ -56,13 +56,8 @@ public class BasicPatternParser {
@Nullable("when not pattern")
PsiBuilder.Marker preParsePattern(final PsiBuilder builder, boolean parensAllowed) {
PsiBuilder.Marker preParsePattern(final PsiBuilder builder) {
PsiBuilder.Marker patternStart = builder.mark();
if (parensAllowed) {
while (builder.getTokenType() == JavaTokenType.LPARENTH) {
builder.advanceLexer();
}
}
Boolean hasNoModifier = myParser.getDeclarationParser().parseModifierList(builder, PATTERN_MODIFIERS).second;
PsiBuilder.Marker type =
myParser.getReferenceParser().parseType(builder, BasicReferenceParser.EAT_LAST_DOT | BasicReferenceParser.WILDCARD);
@@ -87,16 +82,6 @@ public class BasicPatternParser {
}
PsiBuilder.@NotNull Marker parsePrimaryPattern(final PsiBuilder builder, boolean expectVar) {
if (builder.getTokenType() == JavaTokenType.LPARENTH) {
PsiBuilder.Marker parenPattern = builder.mark();
builder.advanceLexer();
parsePattern(builder);
if (!expect(builder, JavaTokenType.RPARENTH)) {
error(builder, JavaPsiBundle.message("expected.rparen"));
}
done(parenPattern, myJavaElementTypeContainer.PARENTHESIZED_PATTERN, myWhiteSpaceAndCommentSetHolder);
return parenPattern;
}
return parseTypeOrRecordPattern(builder, expectVar);
}

View File

@@ -334,7 +334,7 @@ public class BasicStatementParser {
@Contract(pure = true)
private boolean isRecordPatternInForEach(final PsiBuilder builder) {
PsiBuilder.Marker patternStart = myParser.getPatternParser().preParsePattern(builder, false);
PsiBuilder.Marker patternStart = myParser.getPatternParser().preParsePattern(builder);
if (patternStart == null) {
return false;
}

View File

@@ -211,8 +211,6 @@ public abstract class AbstractBasicJavaElementTypeFactory {
public final IElementType DECONSTRUCTION_PATTERN_VARIABLE;
public final IElementType PARENTHESIZED_PATTERN;
public final IElementType DEFAULT_CASE_LABEL_ELEMENT;
public final IElementType CASE_LABEL_ELEMENT_LIST;
@@ -335,7 +333,6 @@ public abstract class AbstractBasicJavaElementTypeFactory {
IElementType DECONSTRUCTION_PATTERN,
IElementType DECONSTRUCTION_LIST,
IElementType DECONSTRUCTION_PATTERN_VARIABLE,
IElementType PARENTHESIZED_PATTERN,
IElementType DEFAULT_CASE_LABEL_ELEMENT,
IElementType CASE_LABEL_ELEMENT_LIST,
ILazyParseableElementType CODE_BLOCK,
@@ -448,7 +445,6 @@ public abstract class AbstractBasicJavaElementTypeFactory {
this.DECONSTRUCTION_PATTERN = DECONSTRUCTION_PATTERN;
this.DECONSTRUCTION_LIST = DECONSTRUCTION_LIST;
this.DECONSTRUCTION_PATTERN_VARIABLE = DECONSTRUCTION_PATTERN_VARIABLE;
this.PARENTHESIZED_PATTERN = PARENTHESIZED_PATTERN;
this.DEFAULT_CASE_LABEL_ELEMENT = DEFAULT_CASE_LABEL_ELEMENT;
this.CASE_LABEL_ELEMENT_LIST = CASE_LABEL_ELEMENT_LIST;
this.CODE_BLOCK = CODE_BLOCK;

View File

@@ -84,7 +84,7 @@ public interface BasicElementTypes extends JavaTokenType, JavaDocTokenType, Basi
BASIC_YIELD_STATEMENT);
ParentAwareTokenSet BASIC_JAVA_PATTERN_BIT_SET =
ParentAwareTokenSet.create(BASIC_TYPE_TEST_PATTERN, BASIC_PARENTHESIZED_PATTERN, BASIC_DECONSTRUCTION_PATTERN, BASIC_UNNAMED_PATTERN);
ParentAwareTokenSet.create(BASIC_TYPE_TEST_PATTERN, BASIC_DECONSTRUCTION_PATTERN, BASIC_UNNAMED_PATTERN);
ParentAwareTokenSet BASIC_JAVA_CASE_LABEL_ELEMENT_BIT_SET =
ParentAwareTokenSet.orSet(BASIC_JAVA_PATTERN_BIT_SET, BASIC_EXPRESSION_BIT_SET, ParentAwareTokenSet.create(

View File

@@ -16,7 +16,10 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.*;
import com.intellij.psi.util.PsiPrecedenceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.CommonJavaRefactoringUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
@@ -365,7 +368,7 @@ public class ConvertSwitchToIfIntention extends PsiUpdateModCommandAction<PsiSwi
String expressionText,
CommentTracker commentTracker) {
String patternCondition = null;
PsiPattern normalizedPattern = JavaPsiPatternUtil.skipParenthesizedPatternDown(pattern);
PsiPattern normalizedPattern = pattern;
if (normalizedPattern instanceof PsiTypeTestPattern typeTestPattern) {
patternCondition = createIfCondition(typeTestPattern, expressionText, commentTracker);
}

View File

@@ -10,7 +10,6 @@ import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.JavaFeature;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.controlFlow.*;
import com.intellij.psi.util.PsiTreeUtil;
@@ -328,8 +327,7 @@ public final class EnhancedSwitchMigrationInspection extends AbstractBaseJavaLoc
if (branches.isEmpty()) {
return branches;
}
boolean java20plus = PsiUtil.getLanguageLevel(context).isAtLeast(LanguageLevel.JDK_20_PREVIEW);
if (!java20plus) {
if (!PsiUtil.isAvailable(JavaFeature.PATTERNS_IN_SWITCH, context)) {
return branches;
}
List<SwitchBranch> result = new ArrayList<>();

View File

@@ -305,10 +305,6 @@ public abstract class JavaElementVisitor extends PsiElementVisitor {
visitExpression(expression);
}
public void visitParenthesizedPattern(@NotNull PsiParenthesizedPattern pattern) {
visitPattern(pattern);
}
public void visitPattern(@NotNull PsiPattern pattern) {
visitElement(pattern);
}

View File

@@ -1,12 +0,0 @@
// 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;
import org.jetbrains.annotations.Nullable;
public interface PsiParenthesizedPattern extends PsiPrimaryPattern {
/**
* @return pattern inside parenthesis or null if pattern is incomplete
*/
@Nullable
PsiPattern getPattern();
}

View File

@@ -760,9 +760,7 @@ public final class PsiImplUtil {
*/
@Nullable
public static PsiSwitchLabelStatementBase getSwitchLabel(@NotNull PsiCaseLabelElement labelElement) {
PsiElement parent = labelElement instanceof PsiParenthesizedPattern
? JavaPsiPatternUtil.skipParenthesizedPatternUp(labelElement.getParent())
: PsiUtil.skipParenthesizedExprUp(labelElement.getParent());
PsiElement parent = PsiUtil.skipParenthesizedExprUp(labelElement.getParent());
if (parent instanceof PsiCaseLabelElementList) {
PsiElement grand = parent.getParent();
if (grand instanceof PsiSwitchLabelStatementBase) {

View File

@@ -55,7 +55,7 @@ public interface ElementType extends JavaTokenType, JavaDocTokenType, JavaElemen
TRY_STATEMENT, LABELED_STATEMENT, ASSERT_STATEMENT,
YIELD_STATEMENT);
TokenSet JAVA_PATTERN_BIT_SET = TokenSet.create(TYPE_TEST_PATTERN, PARENTHESIZED_PATTERN, DECONSTRUCTION_PATTERN, UNNAMED_PATTERN);
TokenSet JAVA_PATTERN_BIT_SET = TokenSet.create(TYPE_TEST_PATTERN, DECONSTRUCTION_PATTERN, UNNAMED_PATTERN);
TokenSet JAVA_CASE_LABEL_ELEMENT_BIT_SET =
TokenSet.orSet(JAVA_PATTERN_BIT_SET, EXPRESSION_BIT_SET, TokenSet.create(DEFAULT_CASE_LABEL_ELEMENT));

View File

@@ -213,9 +213,6 @@ public interface JavaElementType {
IElementType DECONSTRUCTION_PATTERN_VARIABLE =
new JavaCompositeElementType("DECONSTRUCTION_PATTERN_VARIABLE", () -> new PsiDeconstructionPatternVariableImpl(),
BASIC_DECONSTRUCTION_PATTERN_VARIABLE);
IElementType PARENTHESIZED_PATTERN =
new JavaCompositeElementType("PARENTHESIZED_PATTERN", () -> new PsiParenthesizedPatternImpl(),
BASIC_PARENTHESIZED_PATTERN);
IElementType DEFAULT_CASE_LABEL_ELEMENT =
new JavaCompositeElementType("DEFAULT_CASE_LABEL_ELEMENT", () -> new PsiDefaultLabelElementImpl(),
BASIC_DEFAULT_CASE_LABEL_ELEMENT);

View File

@@ -124,7 +124,6 @@ public class JavaElementTypeFactory extends AbstractBasicJavaElementTypeFactory
JavaElementType.DECONSTRUCTION_PATTERN,
JavaElementType.DECONSTRUCTION_LIST,
JavaElementType.DECONSTRUCTION_PATTERN_VARIABLE,
JavaElementType.PARENTHESIZED_PATTERN,
JavaElementType.DEFAULT_CASE_LABEL_ELEMENT,
JavaElementType.CASE_LABEL_ELEMENT_LIST,
JavaElementType.CODE_BLOCK,

View File

@@ -15,7 +15,7 @@ import org.jetbrains.annotations.Nullable;
import static com.intellij.psi.impl.source.tree.JavaElementType.*;
public class PsiDeconstructionListImpl extends CompositePsiElement implements PsiDeconstructionList {
private final TokenSet PRIMARY_PATTERN_SET = TokenSet.create(TYPE_TEST_PATTERN, DECONSTRUCTION_PATTERN, PARENTHESIZED_PATTERN, UNNAMED_PATTERN);
private final TokenSet PRIMARY_PATTERN_SET = TokenSet.create(TYPE_TEST_PATTERN, DECONSTRUCTION_PATTERN, UNNAMED_PATTERN);
public PsiDeconstructionListImpl() {
super(DECONSTRUCTION_LIST);

View File

@@ -1,48 +0,0 @@
// 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.impl.source.tree.java;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.Constants;
import com.intellij.psi.impl.source.tree.CompositePsiElement;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PsiParenthesizedPatternImpl extends CompositePsiElement implements PsiParenthesizedPattern, Constants {
public PsiParenthesizedPatternImpl() {
super(PARENTHESIZED_PATTERN);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor)visitor).visitParenthesizedPattern(this);
}
else {
visitor.visitElement(this);
}
}
@Override
public String toString() {
return "PsiParenthesizedPattern";
}
@Override
public @Nullable PsiPattern getPattern() {
return PsiTreeUtil.getChildOfType(this, PsiPattern.class);
}
@Override
public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
PsiElement lastParent,
@NotNull PsiElement place) {
final PsiPattern pattern = getPattern();
if (pattern == null) return true;
return pattern.processDeclarations(processor, state, null, place);
}
}

View File

@@ -3,7 +3,7 @@ package com.intellij.psi.impl.source.tree.java;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.ChildRole;
import com.intellij.psi.impl.source.tree.ElementType;
@@ -90,7 +90,7 @@ public class PsiSwitchLabelStatementImpl extends PsiSwitchLabelStatementBaseImpl
*/
private boolean shouldAnalyzePatternVariablesInCaseLabel(@NotNull PsiElement place) {
if (place instanceof PsiCodeBlock) return true;
boolean java20plus = PsiUtil.getLanguageLevel(place).isAtLeast(LanguageLevel.JDK_20_PREVIEW);
boolean patternInSwitch = PsiUtil.isAvailable(JavaFeature.PATTERNS_IN_SWITCH, place);
final AtomicBoolean thisSwitchLabelIsImmediate = new AtomicBoolean();
PsiTreeUtil.treeWalkUp(place, getParent(), (currentScope, __) -> {
@@ -104,7 +104,7 @@ public class PsiSwitchLabelStatementImpl extends PsiSwitchLabelStatementBaseImpl
immediateSwitchLabel = PsiTreeUtil.getPrevSiblingOfType(currentScope, PsiSwitchLabelStatementBase.class);
}
while (immediateSwitchLabel != null && !java20plus &&
while (immediateSwitchLabel != null && !patternInSwitch &&
(PsiTreeUtil.getPrevSiblingOfType(immediateSwitchLabel, PsiStatement.class) instanceof PsiSwitchLabelStatementBase &&
isCaseNull(immediateSwitchLabel))) {
/*

View File

@@ -36,7 +36,7 @@ public enum PatternResolveState {
for (PsiElement prev = pattern, current = prev.getParent(); prev != parent; prev = current, current = current.getParent()) {
if (current instanceof PsiInstanceOfExpression || current instanceof PsiParenthesizedExpression ||
current instanceof PsiDeconstructionList || current instanceof PsiDeconstructionPattern ||
current instanceof PsiParenthesizedPattern || current instanceof PsiPolyadicExpression &&
current instanceof PsiPolyadicExpression &&
(((PsiPolyadicExpression)current).getOperationTokenType() == JavaTokenType.ANDAND ||
((PsiPolyadicExpression)current).getOperationTokenType() == JavaTokenType.OROR)) {
continue;

View File

@@ -4,7 +4,6 @@ package com.intellij.psi.util;
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
@@ -102,30 +101,12 @@ public final class JavaPsiPatternUtil {
return "(" + checkType.getText() + ")" + operand.getText();
}
@Contract(value = "null -> null", pure = true)
public static @Nullable PsiPattern skipParenthesizedPatternDown(PsiPattern pattern) {
while (pattern instanceof PsiParenthesizedPattern) {
pattern = ((PsiParenthesizedPattern)pattern).getPattern();
}
return pattern;
}
public static PsiElement skipParenthesizedPatternUp(PsiElement parent) {
while (parent instanceof PsiParenthesizedPattern) {
parent = parent.getParent();
}
return parent;
}
/**
* @return extracted pattern variable or null if the pattern is incomplete or unknown
*/
@Contract(value = "null -> null", pure = true)
@Nullable
public static PsiPatternVariable getPatternVariable(@Nullable PsiCaseLabelElement pattern) {
if (pattern instanceof PsiParenthesizedPattern) {
return getPatternVariable(((PsiParenthesizedPattern)pattern).getPattern());
}
if (pattern instanceof PsiTypeTestPattern) {
return ((PsiTypeTestPattern)pattern).getPatternVariable();
}
@@ -138,10 +119,7 @@ public final class JavaPsiPatternUtil {
@Contract(value = "null -> null", pure = true)
@Nullable
public static PsiPrimaryPattern getTypedPattern(@Nullable PsiCaseLabelElement element) {
if (element instanceof PsiParenthesizedPattern) {
return getTypedPattern(((PsiParenthesizedPattern)element).getPattern());
}
else if (element instanceof PsiDeconstructionPattern) {
if (element instanceof PsiDeconstructionPattern) {
return ((PsiDeconstructionPattern)element);
}
else if (element instanceof PsiTypeTestPattern) {
@@ -164,9 +142,6 @@ public final class JavaPsiPatternUtil {
PsiPatternVariable variable = ((PsiTypeTestPattern)pattern).getPatternVariable();
return variable != null && !variable.isUnnamed();
}
else if (pattern instanceof PsiParenthesizedPattern) {
return containsNamedPatternVariable(((PsiParenthesizedPattern)pattern).getPattern());
}
else if (pattern instanceof PsiDeconstructionPattern) {
PsiDeconstructionPattern deconstructionPattern = (PsiDeconstructionPattern)pattern;
return deconstructionPattern.getPatternVariable() != null ||
@@ -203,9 +178,6 @@ public final class JavaPsiPatternUtil {
public static @Nullable PsiTypeElement getPatternTypeElement(@Nullable PsiCaseLabelElement pattern) {
if (pattern == null) return null;
if (pattern instanceof PsiParenthesizedPattern) {
return getPatternTypeElement(((PsiParenthesizedPattern)pattern).getPattern());
}
else if (pattern instanceof PsiDeconstructionPattern) {
return ((PsiDeconstructionPattern)pattern).getTypeElement();
}
@@ -226,10 +198,7 @@ public final class JavaPsiPatternUtil {
@Nullable
public static PsiPrimaryPattern findUnconditionalPattern(@Nullable PsiCaseLabelElement pattern) {
if (pattern == null || isGuarded(pattern)) return null;
if (pattern instanceof PsiParenthesizedPattern) {
return findUnconditionalPattern(((PsiParenthesizedPattern)pattern).getPattern());
}
else if (pattern instanceof PsiDeconstructionPattern || pattern instanceof PsiTypeTestPattern || pattern instanceof PsiUnnamedPattern) {
if (pattern instanceof PsiDeconstructionPattern || pattern instanceof PsiTypeTestPattern || pattern instanceof PsiUnnamedPattern) {
return (PsiPrimaryPattern)pattern;
}
return null;
@@ -316,15 +285,7 @@ public final class JavaPsiPatternUtil {
}
public static @Nullable PsiDeconstructionPattern findDeconstructionPattern(@Nullable PsiCaseLabelElement element) {
if (element instanceof PsiParenthesizedPattern) {
return findDeconstructionPattern(((PsiParenthesizedPattern)element).getPattern());
}
else if (element instanceof PsiDeconstructionPattern) {
return (PsiDeconstructionPattern)element;
}
else {
return null;
}
return ObjectUtils.tryCast(element, PsiDeconstructionPattern.class);
}
/**
@@ -334,9 +295,7 @@ public final class JavaPsiPatternUtil {
@Contract(value = "_,null -> false", pure = true)
public static boolean dominatesOverConstant(@NotNull PsiCaseLabelElement who, @Nullable PsiType overWhom) {
if (overWhom == null) return false;
if (PsiUtil.getLanguageLevel(who) != LanguageLevel.JDK_20_PREVIEW){
who = findUnconditionalPattern(who);
}
who = findUnconditionalPattern(who);
PsiType whoType = TypeConversionUtil.erasure(getPatternType(who));
if (whoType == null) return false;
PsiType overWhomType = null;
@@ -492,9 +451,6 @@ public final class JavaPsiPatternUtil {
*/
public static @Nullable PsiType getContextType(@NotNull PsiPattern pattern) {
PsiElement parent = pattern.getParent();
while (parent instanceof PsiParenthesizedPattern) {
parent = parent.getParent();
}
if (parent instanceof PsiInstanceOfExpression) {
return ((PsiInstanceOfExpression)parent).getOperand().getType();
}

View File

@@ -1,102 +0,0 @@
import java.util.List;
import java.util.Set;
class Main {
record EmptyBox() {}
record Point(int x, int y) {}
record Rect(Point point1, Point point2) {}
record Pair<T, U>(T t, U u) {}
record Rec(Object obj) {}
Point[] getPoints(int x) {
return new Point[0];
}
void ok1(Point[] points) {
for (Point(int x, int y) : points) {
System.out.println(x + y);
}
}
void ok2(EmptyBox[] emptyBoxes) {
for (EmptyBox() : emptyBoxes) {
System.out.println("Fill it up and send it back");
}
}
void ok3(List<Point> points) {
for (Point(final int a, final int b) : points) {
System.out.println(a + b);
}
}
void ok4(Iterable<Rect> rectangles) {
for (Rect(Point(final int x1, final int y1), final Point point2) : rectangles) {
System.out.println(x1 + y1);
}
}
void test1() {
System.out.println(<error descr="Cannot resolve symbol 'x'">x</error>);
for (Point(int x, int y) : getPoints(<error descr="Cannot resolve symbol 'x'">x</error>)) {
}
System.out.println(<error descr="Cannot resolve symbol 'y'">y</error>);
}
void test2(List<Integer> nums) {
for (<error descr="Deconstruction pattern can only be applied to a record, 'java.lang.Integer' is not a record">Integer</error>(int num) : nums) {
System.out.println();
}
}
void test3(Point[] points) {
for (Point(int x, <error descr="Incompatible types. Found: 'java.lang.Integer', required: 'int'">Integer y</error>) : points) {
System.out.println(x + y);
}
}
void test4(Rect[] rectangles) {
for (Rect(Point<error descr="Incorrect number of nested patterns: expected 2 but found 1">(int x1)</error>, Point point2): rectangles) {
System.out.println(x1 + <error descr="Cannot resolve symbol 'y1'">y1</error>);
}
}
void test5(Point[] points) {
for (Point(int x, int y, <error descr="Incorrect number of nested patterns: expected 2 but found 3">int z)</error> : points) {
System.out.println(x + y + z);
}
}
<T> void test6(Set<Pair<String, String>> pairs) {
for (<error descr="'Pair<String, String>' cannot be safely cast to 'Pair<T, String>'">Pair<T, String>(var t, var u)</error> : pairs) {}
}
void notExhaustive(Rec[] recs) {
for (<error descr="Pattern 'Main.Rec' is not exhaustive on 'Main.Rec'">Rec(String s)</error>: recs) {
System.out.println(s);
}
}
void testNamedRecordPattern(Object obj, List<Rect> rectangles) {
if (obj instanceof Point(int x, int y) <error descr="Identifier is not allowed here">point</error>) {
}
switch (obj) {
case Point(int x, int y) <error descr="Identifier is not allowed here">point</error> -> System.out.println("point");
case Rect(Point point1, Point(int x2, int y2) <error descr="Identifier is not allowed here">point2</error>) <error descr="Identifier is not allowed here">rect</error> -> System.out.println("rectangle");
}
for (Rect(Point(int x1, int y1) <error descr="Identifier is not allowed here">point1</error>, Point(int x2, int y2) <error descr="Identifier is not allowed here">point2</error>) : rectangles) {
System.out.println("blah blah blah");
}
}
void testInappropriateType(Object obj, String text) {
for(Point(int x1, int y1) : <error descr="Foreach not applicable to type 'java.lang.Object'">obj</error>){
System.out.println(x1);
}
for (Point(int x1, int y1) : <error descr="Foreach not applicable to type 'java.lang.String'">text</error>){
System.out.println(x1);
}
}
}

View File

@@ -1,165 +0,0 @@
import java.util.function.*;
class Test {
void test1(Object o, int mode) {
switch (o) {
case (Integer i) when i == <error descr="Variable used in guarded pattern should be final or effectively final">mode</error> -> System.out.println();
default -> {}
}
switch (o) {
case (Integer i) when (switch (o) {
case Integer ii when ii != <error descr="Variable used in guarded pattern should be final or effectively final">mode</error> -> 2;
default -> 1;
}) == <error descr="Variable used in guarded pattern should be final or effectively final">mode</error> -> System.out.println();
default -> {}
}
switch (o) {
case (Integer i) when (i = <error descr="Variable used in guarded pattern should be final or effectively final">mode</error>) > 0 -> System.out.println();
default -> {}
}
mode = 0;
}
void test2(Object o, final int mode) {
switch (o) {
case (Integer i) when (switch (<error descr="Variable used in guarded pattern should be final or effectively final">o</error>) {
case Integer ii when ii != mode -> 2;
default -> 1;
}) == mode -> o = null;
default -> {}
}
switch (o) {
case (Integer i) when (i = mode) > 0 -> System.out.println();
default -> {}
}
}
void test3(Object o, int mode) {
switch (o) {
case (Integer i) when i == mode -> System.out.println();
default -> {}
}
switch (o) {
case (Integer i) when (switch (o) {
case Integer ii when ii != mode -> 2;
default -> 1;
}) == mode -> System.out.println();
default -> {}
}
}
void testInstanceofPatterns(Object o, int mode) {
if (o instanceof Integer i && (i = mode) > 0) {
}
mode = 0;
}
void testNested(Object o, Integer in) {
switch (o) {
case Integer mode when (mode = 42) > 9:
switch (o) {
case (Integer i) when (i = <error descr="Variable used in guarded pattern should be final or effectively final">mode</error>) > 0 -> System.out.println();
default -> System.out.println();
}
default : break;
}
String str;
str = switch (o) {
case Integer mode when (mode = 42) > 9 ->
switch (o) {
case (Integer i) when (i = <error descr="Variable used in guarded pattern should be final or effectively final">mode</error>) > 0 -> "";
default -> "";
};
default -> "";
};
str = switch (o) {
case Integer mode when (mode = 42) > 9:
yield switch (o) {
case (Integer i) when (i = <error descr="Variable used in guarded pattern should be final or effectively final">mode</error>) > 0 -> "";
default -> "";
};
default: yield "";
};
// lambdas
str = switch (o) {
case Integer i when (i = <error descr="Variable used in guarded pattern should be final or effectively final">in</error>) > 0:
yield ((Function<Integer, String>)(x) -> (<error descr="Variable used in lambda expression should be final or effectively final">in</error> = 5) > 0 ? "" : null).apply(in);
default:
yield "";
};
Consumer<Integer> c = (mode) -> {
switch (o) {
case (Integer i) when (i = <error descr="Variable used in guarded pattern should be final or effectively final">in</error>) > 0 -> System.out.println();
default -> System.out.println();
}
<error descr="Variable used in lambda expression should be final or effectively final">in</error> = 1;
};
// try-with-resources
try (<error descr="Variable used as a try-with-resources resource should be final or effectively final">in</error>) {
switch (o) {
case AutoCloseable ii when (<error descr="Variable used in guarded pattern should be final or effectively final">in</error> = ii) != null: break;
default: break;
}
} catch (Exception e) {
}
// double nested
switch (o) {
case Integer mode when (mode = 42) > 9:
switch (o) {
case Integer i -> {
switch (o) {
case Integer ii when ii > <error descr="Variable used in guarded pattern should be final or effectively final">mode</error>:
break;
default:
break;
}
}
default -> System.out.println();
}
default:
break;
}
str = switch (o) {
case Integer mode when (mode) > 9:
yield switch (o) {
case Integer i -> {
yield switch (o) {
case Integer ii when ii > mode: yield "";
default: yield "";
};
}
default -> "";
};
default: yield "";
};
}
void declaredInWhenExpression(Object obj) {
switch (obj) {
case Integer i when new Function<Integer, Boolean>() {
@Override
public Boolean apply(Integer integer) {
System.out.println(integer++);
int num = 0;
System.out.println(++num);
return true;
}
}.apply(42) -> {}
default -> {}
}
switch (obj) {
case Integer i when switch (i) {
case 1 -> {
int num = 0;
++num;
yield num;
}
default -> 42;
} == 42 -> {}
default -> {}
}
}
}

View File

@@ -1,6 +1,6 @@
class Main {
void test(Object o) {
if (o instanceof ((String <caret>s) && s.length() > 1)) {
if (o instanceof String <caret>s && s.length() > 1) {
}
s = "fsfsdfsd";
}

View File

@@ -1,6 +1,6 @@
class Main {
void test(Object o) {
boolean b = o instanceof ((String <caret>s) && s.length() > 1);
boolean b = o instanceof String <caret>s && s.length() > 1;
s = "fsfsdfsd"; // unresolved
}
}

View File

@@ -1,7 +1,7 @@
class Main {
void test(Object o) {
switch (o) {
case ((Long <caret>l) && l != null) ->
case Long <caret>l when l != null ->
System.out.println("Long: " + l);
default ->
System.out.println();

View File

@@ -127,7 +127,7 @@ public class Main {
void test12(Integer integer) {
switch (integer) {
case 1, 2, <error descr="Invalid case label combination: a case label must consist of either a list of case constants or a single case pattern">Integer i1</error> when i1 > 5:
case 1, 2, <error descr="Invalid case label combination: a case label must consist of either a list of case constants or a list of case patterns">Integer i1</error> when i1 > 5:
case null:
System.out.println("blah blah blah");
break;
@@ -246,14 +246,14 @@ public class Main {
void test28(Object obj) {
switch (obj) {
case Integer i, <error descr="Invalid case label combination: a case label must not consist of more than one case pattern">String str</error> -> {}
case <error descr="Invalid case label combination: multiple patterns are allowed only if none of them declare any pattern variables">Integer i</error>, String str -> {}
default -> {}
}
}
void test28(String s) {
switch (s) {
case String str, <error descr="Invalid case label combination: a case label must consist of either a list of case constants or a single case pattern">"hello"</error>, "world" -> {}
case String str, <error descr="Invalid case label combination: a case label must consist of either a list of case constants or a list of case patterns">"hello"</error>, "world" -> {}
}
}

View File

@@ -1,7 +1,7 @@
class X {
int switchTest(Object obj) {
return switch (obj) {
case (String <error descr="Patterns in switch are not supported at language level '11'">s</error>) -> 1;
case Object(String <error descr="Patterns in switch are not supported at language level '11'">s</error>) -> 1;
case Integer <error descr="Patterns in switch are not supported at language level '11'">i</error> when predicate() -> 2;
case Integer <error descr="Patterns in switch are not supported at language level '11'">i</error> -> 3;
case default -> 4;
@@ -20,9 +20,6 @@ class X {
if (obj instanceof Integer <error descr="Patterns in 'instanceof' are not supported at language level '11'">i</error> && predicate()) {
return 1;
}
if (obj instanceof (String <error descr="Patterns in 'instanceof' are not supported at language level '11'">s</error>)) {
return 3;
}
return 2;
}

View File

@@ -1,7 +1,7 @@
class X {
int switchTest(Object obj) {
return switch (obj) {
case (String <error descr="Patterns in switch are not supported at language level '16'">s</error>) -> 1;
case Object(String <error descr="Patterns in switch are not supported at language level '16'">s</error>) -> 1;
case Integer <error descr="Patterns in switch are not supported at language level '16'">i</error> when predicate() -> 2;
case Integer <error descr="Patterns in switch are not supported at language level '16'">i</error> -> 3;
case default -> 4;
@@ -14,14 +14,13 @@ class X {
case <error descr="The label for the default case must only use the 'default' keyword, without 'case'">default</error> -> {}
}
}
record R(int x) {}
int instanceofTest(Object obj) {
if (obj instanceof <error descr="Parenthesized patterns are not supported at language level '16'">(Integer i)</error> && predicate()) {
if (obj instanceof <error descr="Pattern guards and record patterns are not supported at language level '16'">R(int i)</error> && predicate()) {
return 1;
}
if (obj instanceof <error descr="Parenthesized patterns are not supported at language level '16'">(String s)</error>) {
return 3;
}
return 2;
}

View File

@@ -1,79 +0,0 @@
class X {
void testDominance1(Object obj) {
switch (obj) {
default -> System.out.println("default");
case <error descr="Label is dominated by a preceding case label 'default'">Integer i</error> -> System.out.println("Integer");
case <error descr="Label is dominated by a preceding case label 'default'">String s</error> when s.isEmpty() -> System.out.println("empty String");
case <error descr="Label is dominated by a preceding case label 'default'">null</error> -> System.out.println("null");
}
}
void testDominance2(Object obj) {
switch (obj) {
case null, default -> System.out.println("null or default");
case <error descr="Label is dominated by a preceding case label 'default'">Integer i</error> -> System.out.println("Integer");
case <error descr="Label is dominated by a preceding case label 'default'">String s</error> when s.isEmpty() -> System.out.println("empty String");
}
}
void testDominance3(String s) {
switch (s) {
default -> System.out.println("default");
case "blah blah blah" -> System.out.println("blah blah blah");
case <error descr="Label is dominated by a preceding case label 'default'">null</error> -> System.out.println("null");
}
}
void testDominance4(String s) {
switch (s) {
case null, default -> System.out.println("null, default");
case <error descr="Label is dominated by a preceding case label 'default'">"blah blah blah"</error> -> System.out.println("blah blah blah");
}
}
void testUnconditionalPatternAndDefault1(String s) {
switch (s) {
case null, <error descr="'switch' has both an unconditional pattern and a default label">default</error> -> System.out.println("null, default");
case <error descr="'switch' has both an unconditional pattern and a default label">String str</error> -> System.out.println("String");
}
}
void testUnconditionalPatternAndDefault2(Integer j) {
switch (j) {
case <error descr="'switch' has both an unconditional pattern and a default label">Integer i</error> when true -> System.out.println("An integer");
<error descr="'switch' has both an unconditional pattern and a default label">default</error> -> System.out.println("default");
}
}
void testDuplicateUnconditionalPattern1(Integer j) {
switch (j) {
case <error descr="Duplicate unconditional pattern">Integer i</error> when true -> System.out.println("An integer");
case <error descr="Duplicate unconditional pattern">Number number</error> -> System.out.println("An integer");
}
}
void testDuplicateUnconditionalPattern2(Integer j) {
switch (j) {
case <error descr="Duplicate unconditional pattern">Integer i</error> when true -> System.out.println("An integer");
case <error descr="Duplicate unconditional pattern">Integer i</error> -> System.out.println("An integer");
}
}
record R1() {}
record R2() {}
void testNoVars(Object obj) {
switch(obj) {
case R1(), <error descr="Invalid case label combination: a case label must not consist of more than one case pattern">R2()</error> -> {}
default -> {}
}
}
void testCombination(Integer i) {
switch (i) {
case Integer a, <error descr="Invalid case label combination: a case label must not consist of more than one case pattern">Integer b</error> when i > 0 -> System.out.println(1);
case 1, 2, 3, <error descr="Invalid case label combination: a case label must consist of either a list of case constants or a single case pattern">Integer c</error> when i > 0 -> System.out.println(1);
case Integer d, <error descr="Invalid case label combination: a case label must consist of either a list of case constants or a single case pattern">4</error> when i > 0 -> System.out.println(1);
}
}
}

View File

@@ -1,7 +1,6 @@
class X {
int switchTest1(Object obj) {
return switch (obj) {
case <error descr="Parenthesized patterns are not supported at language level '21'">(String s)</error> -> 1;
case Integer i -> 3;
case default -> 4;
case null -> 10;
@@ -47,10 +46,10 @@ class X {
}
int instanceofTest(Object obj) {
if (obj instanceof (Integer i<error descr="')' expected"> </error>&& predicate())<error descr="Statement expected"><error descr="Unexpected token">)</error></error> {
if (obj instanceof<error descr="')' expected"><error descr="Type expected"> </error></error>(Integer<error descr="')' expected"> </error><error descr="Cannot resolve symbol 'i'">i</error> && predicate()<error descr="Unexpected token">)</error><error descr="Unexpected token">)</error> {
return 1;
}
if (obj instanceof <error descr="Parenthesized patterns are not supported at language level '21'">(String s)</error>) {
if (obj instanceof<error descr="')' expected"><error descr="Type expected"> </error></error>(String<error descr="')' expected"> </error><error descr="Cannot resolve symbol 's'">s</error><error descr="Unexpected token">)</error><error descr="Unexpected token">)</error> {
return 3;
}
return 2;

View File

@@ -1,7 +1,7 @@
class RecordPatternsAndWhenGuardsInJava18 {
void test(Object o) {
switch (o) {
case MyRecord(int <error descr="Patterns in switch are not supported at language level '18'">x</error>) <error descr="Patterns in switch are not supported at language level '18'">r</error> -> {
case MyRecord(int <error descr="Patterns in switch are not supported at language level '18'">x</error>) <error descr="Identifier is not allowed here"><error descr="Patterns in switch are not supported at language level '18'">r</error></error> -> {
}
case String <error descr="Patterns in switch are not supported at language level '18'">s</error> when s.length() > 10 -> {

View File

@@ -1,87 +0,0 @@
public class SwitchExhaustivenessIn20Java {
class A {}
class B extends A {}
sealed interface I<T> permits C, D {}
record C<T>(T t) implements I<T> {}
final class D implements I<String> {}
record Pair<T>(T x, T y){
}
void foo(Pair<I<? extends String>> pairI) {
switch (<error descr="'switch' statement does not cover all possible input values">pairI</error>) {
case Pair<I<? extends String>>(C<? extends CharSequence>(String i), D snd) -> {}
case Pair<I<? extends String>>(I<? extends CharSequence> fst, C snd) -> {}
case Pair<I<? extends String>>(D fst, I snd) -> {}
}
}
void foo2(Pair<I<? extends String>> pairI) {
switch (pairI) {
case Pair<I<? extends String>>(C<? extends CharSequence>(CharSequence i), D snd) -> {}
case Pair<I<? extends String>>(I<? extends CharSequence> fst, C snd) -> {}
case Pair<I<? extends String>>(D fst, I snd) -> {}
}
}
sealed interface L1 {
}
final class L21 implements L1 {
}
final class L22 implements L1 {
}
sealed interface Boxed permits Box, Box2 {}
record Box(L1 value) implements Boxed {}
record Box2(L1 value) implements Boxed {}
void foo3(Pair<Box> o) {
switch (o) {
case Pair(Box(L21 v1), Box(L22 v2)) -> {
}
case Pair(Box b1, Box b2) -> {
}
}
}
void foo4(Pair<Boxed> o) {
switch (o) {
case Pair<Boxed>(Box(L21 v1), Box2(L22 v2)) -> {
}
case Pair<Boxed>(Box(Object v1), Box(Object v2)) -> {
}
case Pair<Boxed>(Box2 b1, Boxed b2) -> {
}
case Pair<Boxed>(Box b1, Box2 b2) -> {
}
}
}
record PairString<T>(T t, String t2){}
void foo4(PairString<Boxed> o) {
switch (o) {
case PairString<Boxed>(Box(L21 v1), String t) -> {
}
case PairString<Boxed>(Box(L22 v2), String t2) -> {
}
case PairString<Boxed>(Box2 t, String t2) -> {
}
}
}
record StringPair<T>(String t2, T t) {
}
void foo5(StringPair<Boxed> o) {
switch (o) {
case StringPair<Boxed>(String t, Box(L21 v1)) -> {
}
case StringPair<Boxed>(String t2, Box2 t) -> {
}
case StringPair<Boxed>(String t2, Box t) -> {
}
}
}
}

View File

@@ -7,7 +7,7 @@ class Test {
case Object s -> System.out.println(s);
}
switch (o) {
case <error descr="Parenthesized patterns are not supported at language level '21'">(Object s)</error> when s != null -> System.out.println();
case Object s when s != null -> System.out.println();
default -> System.out.println();
}
}

View File

@@ -1,9 +0,0 @@
// "Replace explicit type with 'var'" "false"
class Main {
record Point(int x, int y) {}
void foo(Object obj) {
if (obj instanceof Point((((int<caret> x))), int y)) {
}
}
}

View File

@@ -1,9 +0,0 @@
// "Replace with a null check" "true-preview"
class Test {
void test(String s) {
Object object = s;
if(object != null) {
System.out.println("always");
}
}
}

View File

@@ -1,9 +0,0 @@
// "Replace with a null check" "true-preview"
class Test {
void test(String s) {
Object object = s;
if(object instanceof ((<caret>String s1))) {
System.out.println("always");
}
}
}

View File

@@ -75,7 +75,7 @@ public class ExceptionFromCatchWhichDoesntWrap {
void patternVariable() {
try {
} catch (Exception ex) {
if (ex instanceof ((RuntimeException rte))) {
if (ex instanceof RuntimeException rte) {
throw rte;
}
}
@@ -83,7 +83,7 @@ public class ExceptionFromCatchWhichDoesntWrap {
try {
} catch (Exception ex) {
switch (ex) {
case ((RuntimeException rte)) -> throw rte;
case RuntimeException rte -> throw rte;
default -> {}
}
}

View File

@@ -28,7 +28,7 @@ public class MultipleReturnPointsPerMethod
}
void test(List<Box<String>> list) {
for(Box(var text) : list){
for(<error descr="Record patterns in for-each loops are not supported at language level '20'">Box(var text)</error> : list){
int length = text.length();
}
}

View File

@@ -16,7 +16,7 @@ class Foo {
}
void test3(Rect[] rects) {
for (Rect(Point(<warning descr="Unnecessary 'final' on parameter 'x1'">final</warning> int x1, <warning descr="Unnecessary 'final' on parameter 'y1'">final</warning> int y1), <warning descr="Unnecessary 'final' on parameter 'point2'">final</warning> Point point2) : rects) {
for (<error descr="Record patterns in for-each loops are not supported at language level '21'">Rect(Point(<warning descr="Unnecessary 'final' on parameter 'x1'">final</warning> int x1, <warning descr="Unnecessary 'final' on parameter 'y1'">final</warning> int y1), <warning descr="Unnecessary 'final' on parameter 'point2'">final</warning> Point point2)</error> : rects) {
}
}

View File

@@ -5,7 +5,7 @@ public class ForEachPattern {
record IntBox(int i) {}
void bar1(Iterable<IntBox> i) {
int a = 1;
for (IntBox(int d) : i) {
for (<error descr="Record patterns in for-each loops are not supported at language level '21'">IntBox(int d)</error> : i) {
a = 2;
}
System.out.println(a == 1);
@@ -20,7 +20,7 @@ public class ForEachPattern {
private static void use(List<Point> points) {
int a = 0, b = 0;
for (Point(int x, int y) : points) {
for (<error descr="Record patterns in for-each loops are not supported at language level '21'">Point(int x, int y)</error> : points) {
if (x == 1) {
a = 1;
}

View File

@@ -20,7 +20,7 @@ class Main {
void test3(final Object obj) {
switch (obj) {
case Rect(Point(int <warning descr="Parameter 'x1' can have 'final' modifier">x1</warning>, int y1), Point point2) when (y1 = 42) == x1 -> {
case Rect(Point(int <warning descr="Parameter 'x1' can have 'final' modifier">x1</warning>, int y1), Point point2) when (<error descr="Cannot assign a value to variable 'y1', because it is declared outside the guard">y1</error> = 42) == x1 -> {
point2 = new Point(0, 0);
}
default -> {}
@@ -34,14 +34,14 @@ class Main {
}
void test5(final Point[] points) {
for (Point(int <warning descr="Variable 'x' can have 'final' modifier">x</warning>, int y) : points) {
for (<error descr="Record patterns in for-each loops are not supported at language level '21'">Point(int <warning descr="Variable 'x' can have 'final' modifier">x</warning>, int y)</error> : points) {
System.out.println(x);
y = 42;
}
}
void test6(final Rect[] rects) {
for (Rect(Point(int x1, int <warning descr="Variable 'y1' can have 'final' modifier">y1</warning>), Point <warning descr="Variable 'point2' can have 'final' modifier">point2</warning>) : rects) {
for (<error descr="Record patterns in for-each loops are not supported at language level '21'">Rect(Point(int x1, int <warning descr="Variable 'y1' can have 'final' modifier">y1</warning>), Point <warning descr="Variable 'point2' can have 'final' modifier">point2</warning>)</error> : rects) {
x1 = 42;
}
}

View File

@@ -6,18 +6,12 @@ PsiJavaFile:InstanceOfPattern3.java
PsiIdentifier:x('x')
PsiWhiteSpace(' ')
PsiKeyword:instanceof('instanceof')
PsiErrorElement:Type expected
<empty list>
PsiWhiteSpace(' ')
PsiErrorElement:Unparsed tokens
PsiJavaToken:LPARENTH('(')
PsiIdentifier:Foo('Foo')
PsiWhiteSpace(' ')
PsiParenthesizedPattern
PsiJavaToken:LPARENTH('(')
PsiTypeTestPattern
PsiPatternVariable:v
PsiModifierList:
<empty list>
PsiTypeElement:Foo
PsiJavaCodeReferenceElement:Foo
PsiIdentifier:Foo('Foo')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:v('v')
PsiJavaToken:RPARENTH(')')
PsiIdentifier:v('v')
PsiJavaToken:RPARENTH(')')

View File

@@ -6,18 +6,12 @@ test.java.file
IDENTIFIER
WHITE_SPACE
INSTANCEOF_KEYWORD
ERROR_ELEMENT
<empty list>
WHITE_SPACE
ERROR_ELEMENT
LPARENTH
IDENTIFIER
WHITE_SPACE
PARENTHESIZED_PATTERN
LPARENTH
TYPE_TEST_PATTERN
PATTERN_VARIABLE
MODIFIER_LIST
<empty list>
TYPE
JAVA_CODE_REFERENCE
IDENTIFIER
REFERENCE_PARAMETER_LIST
<empty list>
WHITE_SPACE
IDENTIFIER
RPARENTH
IDENTIFIER
RPARENTH

View File

@@ -1,28 +1,32 @@
PsiJavaFile:SwitchRulesWithPatternIncomplete1.java
PsiSwitchLabeledRule
PsiSwitchLabelStatement
PsiKeyword:case('case')
PsiWhiteSpace(' ')
PsiCaseLabelElementList
PsiParenthesizedPattern
PsiParenthesizedExpression:(Integer
PsiJavaToken:LPARENTH('(')
PsiTypeTestPattern
PsiPatternVariable:i
PsiModifierList:
<empty list>
PsiTypeElement:Integer
PsiJavaCodeReferenceElement:Integer
PsiIdentifier:Integer('Integer')
PsiReferenceParameterList
<empty list>
PsiWhiteSpace(' ')
PsiIdentifier:i('i')
PsiReferenceExpression:Integer
PsiReferenceParameterList
<empty list>
PsiIdentifier:Integer('Integer')
PsiErrorElement:')' expected
<empty list>
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiBlockStatement
PsiErrorElement:':' or '->' expected
<empty list>
PsiWhiteSpace(' ')
PsiExpressionStatement
PsiLambdaExpression
PsiParameterList:i
PsiParameter:i
PsiModifierList:
<empty list>
PsiIdentifier:i('i')
PsiWhiteSpace(' ')
PsiJavaToken:ARROW('->')
PsiWhiteSpace(' ')
PsiCodeBlock
PsiJavaToken:LBRACE('{')
PsiWhiteSpace(' ')
PsiJavaToken:RBRACE('}')
PsiJavaToken:RBRACE('}')
PsiErrorElement:';' expected
<empty list>

View File

@@ -1,28 +1,32 @@
test.java.file
SWITCH_LABELED_RULE
SWITCH_LABEL_STATEMENT
CASE_KEYWORD
WHITE_SPACE
CASE_LABEL_ELEMENT_LIST
PARENTHESIZED_PATTERN
PARENTH_EXPRESSION
LPARENTH
TYPE_TEST_PATTERN
PATTERN_VARIABLE
MODIFIER_LIST
<empty list>
TYPE
JAVA_CODE_REFERENCE
IDENTIFIER
REFERENCE_PARAMETER_LIST
<empty list>
WHITE_SPACE
IDENTIFIER
REFERENCE_EXPRESSION
REFERENCE_PARAMETER_LIST
<empty list>
IDENTIFIER
ERROR_ELEMENT
<empty list>
WHITE_SPACE
ARROW
WHITE_SPACE
BLOCK_STATEMENT
ERROR_ELEMENT
<empty list>
WHITE_SPACE
EXPRESSION_STATEMENT
LAMBDA_EXPRESSION
PARAMETER_LIST
PARAMETER
MODIFIER_LIST
<empty list>
IDENTIFIER
WHITE_SPACE
ARROW
WHITE_SPACE
CODE_BLOCK
LBRACE
WHITE_SPACE
RBRACE
RBRACE
ERROR_ELEMENT
<empty list>

View File

@@ -15,7 +15,7 @@ class Use {
switch (obj) {
case Rect(Point point1, Point point2) when point1.equals(point2) -> {}
case Rect(Point(int y1, int x1) point1, Point(int y2, int x2)) rect when x1 == x2 -> System.out.println(point1);
case ((Rect(((Point(((int x1)), ((int y1))))), Point(((int x2)), ((int y2))) point2))) -> System.out.println(point2);
case Rect(Point(int x1, int y1), Point(int x2, int y2) point2) -> System.out.println(point2);
default -> throw new IllegalStateException("Unexpected value: " + obj);
}
}

View File

@@ -16,7 +16,7 @@ class Use {
switch (obj) {
case Rect(Point point1, Point point2, int i) when point1.equals(point2) -> {}
case Rect(Point(int y1, int x1) point1, Point(int y2, int x2), int i) rect when x1 == x2 -> System.out.println(point1);
case ((Rect(((Point(((int x1)), ((int y1))))), Point(((int x2)), ((int y2))) point2, int i))) -> System.out.println(point2);
case Rect(Point(int x1, int y1), Point(int x2, int y2) point2, int i) -> System.out.println(point2);
default -> throw new IllegalStateException("Unexpected value: " + obj);
}
}

View File

@@ -17,7 +17,7 @@ class Use {
switch (obj) {
case Rect(Point point1, Point point2, int i) when point1.equals(point2) -> {}
case Rect(Point(int y1, int x1) point1, Point(int y2, int x2), int i) rect when x1 == x2 -> System.out.println(point1);
case ((Rect(((Point(((int x1)), ((int y1))))), Point(((int x2)), ((int y2))) point2, ((int i))))) -> System.out.println(point2);
case Rect(Point(int x1, int y1), Point(int x2, int y2) point2, int i) -> System.out.println(point2);
default -> throw new IllegalStateException("Unexpected value: " + obj);
}
}

View File

@@ -17,7 +17,7 @@ class Use {
switch (obj) {
case Rect(Point point2, Point point1, int i) when point2.equals(point1) -> {}
case Rect(Point(int y1, int x1) point2, Point(int y2, int x2), int i) rect when x1 == x2 -> System.out.println(point2);
case ((Rect(((Point(((int x1)), ((int y1))))), Point(((int x2)), ((int y2))) point1, ((int i))))) -> System.out.println(point1);
case Rect(Point(int x1, int y1), Point(int x2, int y2) point1, int i) -> System.out.println(point1);
default -> throw new IllegalStateException("Unexpected value: " + obj);
}
}

View File

@@ -17,7 +17,7 @@ class Use {
switch (obj) {
case Rect(Point point1, Point point2, int i) when point1.equals(point2) -> {}
case Rect(Point(int y1, int x1) point1, Point(int y2, int x2), int i) rect when x1 == x2 -> System.out.println(point1);
case ((Rect(((Point(((int x1)), ((int y1))))), Point(((int x2)), ((int y2))) point2, ((int i))))) -> System.out.println(point2);
case Rect(Point(int x1, int y1), Point(int x2, int y2) point2, int i) -> System.out.println(point2);
default -> {}
}
}

View File

@@ -17,7 +17,7 @@ class Use {
switch (obj) {
case Rect(int i, Point point2, Point point1) when point1.equals(point2) -> {}
case Rect(int i, Point(int y2, int x2), Point(int y1, int x1) point1) rect when x1 == x2 -> System.out.println(point1);
case ((Rect(((int i)), Point(((int x2)), ((int y2))) point2, ((Point(((int x1)), ((int y1)))))))) -> System.out.println(point2);
case Rect(int i, Point(int x2, int y2) point2, Point(int x1, int y1)) -> System.out.println(point2);
default -> {}
}
}

View File

@@ -11,7 +11,7 @@ class Use {
switch (obj) {
case Rect(Point point1, Point point2, int i) when point2.x() == 42 -> System.out.println(point2);
case Rect(Point(int y1, int x1) point1, Point(int y2, int x2), int i) rect when x1 == x2 -> System.out.println(point1);
case ((Rect(((Point(((int x1)), ((int y1))))), ((Point(((int x2)), ((int y2))) point2)), ((int i))))) -> System.out.println(point2);
case Rect(Point(int x1, int y1), Point(int x2, int y2) point2, int i) -> System.out.println(point2);
default -> throw new IllegalStateException("Unexpected value: " + obj);
}
}

View File

@@ -9,7 +9,7 @@ class Use {
switch (obj) {
case Rect(Point p2) when p2.x() == 42 -> System.out.println(p2);
case Rect(Point(int y2, int x2)) rect when x1 == x2 -> System.out.println(point1);
case ((Rect(((Point(((int x2)), ((int y2))) p2))))) -> System.out.println(p2);
case Rect(Point(int x2, int y2) p2) -> System.out.println(p2);
default -> throw new IllegalStateException("Unexpected value: " + obj);
}
}

View File

@@ -1,7 +0,0 @@
class X {
void test(Object obj) {
if (<selection>obj instanceof (String s)</selection> && s.length() > 5) {
System.out.println(s);
}
}
}

View File

@@ -1,7 +0,0 @@
class X {
void test(Object obj) {
if (<selection>obj instanceof (String s) && s.length() > 5</selection>) {
System.out.println(s);
}
}
}

View File

@@ -1,7 +0,0 @@
class X {
void test(Object obj) {
if (<selection>obj instanceof (String s) && s.length() > 5</selection>) {
System.out.println("found");
}
}
}

View File

@@ -1,11 +0,0 @@
class X {
void test(Object obj) {
if (newMethod(obj)) {
System.out.println("found");
}
}
private boolean newMethod(Object obj) {
return obj instanceof (String s) && s.length() > 5;
}
}

View File

@@ -12,6 +12,6 @@ public class MakeDefaultLastCaseFixTest extends LightQuickFixParameterizedTestCa
@Override
protected LanguageLevel getLanguageLevel() {
return LanguageLevel.JDK_20_PREVIEW;
return LanguageLevel.JDK_21;
}
}

View File

@@ -10,7 +10,7 @@ public class MakeVarEffectivelyFinalFixTest extends LightQuickFixParameterizedTe
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return LightJavaCodeInsightFixtureTestCase.JAVA_20;
return LightJavaCodeInsightFixtureTestCase.JAVA_21;
}
@Override

View File

@@ -14,7 +14,7 @@ public class ReplacePrimitiveWithBoxedTypeTest extends LightQuickFixParameterize
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return LightJavaCodeInsightFixtureTestCase.JAVA_20;
return LightJavaCodeInsightFixtureTestCase.JAVA_21;
}
}

View File

@@ -17,7 +17,7 @@ public class ReplaceWithConstantValueFixTest extends LightQuickFixParameterizedT
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return LightJavaCodeInsightFixtureTestCase.JAVA_20;
return LightJavaCodeInsightFixtureTestCase.JAVA_21;
}
@Override

View File

@@ -16,6 +16,6 @@ public class ReplaceWithTypePatternFixTest extends LightQuickFixParameterizedTes
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return LightJavaCodeInsightFixtureTestCase.JAVA_20;
return LightJavaCodeInsightFixtureTestCase.JAVA_21;
}
}

View File

@@ -13,7 +13,7 @@ public final class LanguageLevelTest {
@SuppressWarnings("UsagesOfObsoleteApi")
LanguageLevel jdk17Preview = LanguageLevel.JDK_17_PREVIEW;
assertTrue(jdk17Preview.isUnsupported());
assertEquals(LanguageLevel.JDK_20_PREVIEW, jdk17Preview.getSupportedLevel());
assertEquals(LanguageLevel.JDK_21, jdk17Preview.getSupportedLevel());
assertEquals(LanguageLevel.JDK_17, jdk17Preview.getNonPreviewLevel());
}
}

View File

@@ -2,9 +2,11 @@
package com.intellij.java.codeInsight.daemon;
import com.intellij.codeInspection.miscGenerics.RawUseOfParameterizedTypeInspection;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiPatternVariable;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
@@ -14,7 +16,7 @@ import java.util.Collection;
public class DeconstructionInferenceTest extends LightJavaCodeInsightFixtureTestCase {
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return JAVA_20;
return JAVA_21;
}
public void testSimple() {
@@ -137,7 +139,7 @@ public class DeconstructionInferenceTest extends LightJavaCodeInsightFixtureTest
}
}
""");
myFixture.checkHighlighting();
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_X, () -> myFixture.checkHighlighting());
}
public void testWildcardTypeParameterBound() {
@@ -294,6 +296,6 @@ public class DeconstructionInferenceTest extends LightJavaCodeInsightFixtureTest
}
""");
myFixture.enableInspections(new RawUseOfParameterizedTypeInspection());
myFixture.checkHighlighting();
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_X, () -> myFixture.checkHighlighting());
}
}

View File

@@ -16,7 +16,7 @@ public class JavacQuirksInspectionTest extends LightJavaCodeInsightFixtureTestCa
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return JAVA_20;
return JAVA_21;
}
@Override

View File

@@ -40,47 +40,39 @@ public class LightPatternsForSwitchHighlightingTest extends LightJavaCodeInsight
}
public void testPatternsInSwitchIn21Java() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
}
public void testPatternsInSwitchIn20Java() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_20_PREVIEW, this::doTest);
doTest();
}
public void testMismatchedDeconstructionIn21Java() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
doTest();
}
public void testIllegalFallthroughIn20Java() {
//there are no changes in 20->21
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
doTest();
}
public void testIllegalFallthroughIn21Java() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
doTest();
}
public void testUnconditionalDestructuringAndDefaultIn21Java() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
doTest();
}
public void testSwitchExhaustivenessIn21Java() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
doTest();
}
public void testSwitchExhaustivenessForDirectClassesIn21Java() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
doTest();
}
public void testSwitchExhaustivenessWithConcreteSealedClassesIn21Java() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
doTest();
}
public void testSwitchExhaustivenessForEnumsWithSealedClassesIn21Java() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
}
public void testSwitchExhaustivenessIn20Java() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_20_PREVIEW, this::doTest);
doTest();
}
public void testSwitchExhaustivenessWithSealedIntersection(){
@@ -88,7 +80,7 @@ public class LightPatternsForSwitchHighlightingTest extends LightJavaCodeInsight
}
public void testSwitchExhaustivenessWithGenericsIn21Java() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
doTest();
}
public void testSwitchSeveralPatternsUnnamed() {
@@ -96,11 +88,11 @@ public class LightPatternsForSwitchHighlightingTest extends LightJavaCodeInsight
}
public void testSwitchDominanceIn21Java() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
doTest();
}
public void testPatternMatchingInSwitchJava21() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
doTest();
}
public void testPatternMatchingWithGuard() {
@@ -122,12 +114,8 @@ public class LightPatternsForSwitchHighlightingTest extends LightJavaCodeInsight
doTest();
}
public void testEffectivelyFinal() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_20_PREVIEW, this::doTest);
}
public void testEffectivelyFinal21() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
doTest();
}

View File

@@ -69,10 +69,6 @@ public class LightPatternsHighlightingTest extends LightJavaCodeInsightFixtureTe
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_19, this::doTest);
}
public void testRecordPatternsInForEachJava20() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_20_PREVIEW, this::doTest);
}
public void testRecordPatternsInForEachJava21() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, () -> {
doTest();
@@ -81,16 +77,16 @@ public class LightPatternsHighlightingTest extends LightJavaCodeInsightFixtureTe
});
}
public void testDeconstructionInstanceOf20() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_20_PREVIEW, this::doTest);
public void testDeconstructionInstanceOf21() {
doTest();
}
public void testForEachPatternExhaustiveness() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_20_PREVIEW, this::doTest);
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_X, this::doTest);
}
public void testBoundTypeParameter() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_20_PREVIEW, this::doTest);
doTest();
}
public void testNotAnnotationsInDeconstructionType() {

View File

@@ -16,6 +16,6 @@ public class SplitSwitchBranchWithSeveralCaseValuesTest extends LightQuickFixPar
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return LightJavaCodeInsightFixtureTestCase.JAVA_20;
return LightJavaCodeInsightFixtureTestCase.JAVA_21;
}
}

View File

@@ -180,7 +180,7 @@ public class GotoDeclarationTest extends LightJavaCodeInsightTestCase {
}
public void testCaseNullAfterPatternMatching() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_20_PREVIEW, () -> doTestGoToField());
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, () -> doTestGoToField());
}
public void testCaseNullAfterPatternMatchingExpr() {

View File

@@ -18,7 +18,7 @@ public class BulkFileAttributesReadInspectionTest extends LightJavaCodeInsightFi
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_20;
return JAVA_21;
}
@Override

View File

@@ -8,7 +8,7 @@ import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
public class CapturingCleaner18InspectionTest extends LightJavaCodeInsightFixtureTestCase {
public class CapturingCleaner21InspectionTest extends LightJavaCodeInsightFixtureTestCase {
public void testCapturingCleaner() {doTest();}
@@ -26,7 +26,7 @@ public class CapturingCleaner18InspectionTest extends LightJavaCodeInsightFixtur
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_20;
return JAVA_21;
}
@NotNull

View File

@@ -1,53 +0,0 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.codeInspection;
import com.intellij.JavaTestUtil;
import com.intellij.testFramework.LightProjectDescriptor;
import org.jetbrains.annotations.NotNull;
public class DataFlowInspection20Test extends DataFlowInspectionTestCase {
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_20;
}
@Override
protected String getTestDataPath() {
return JavaTestUtil.getJavaTestDataPath() + "/inspection/dataFlow/fixture/";
}
public void testSealedClassCast() { doTest(); }
public void testCastToSealedInterface() { doTest(); }
public void testWhenPatterns() {
doTest();
}
public void testSwitchNullability() {
doTest();
}
public void testRecordPatterns() {
doTest();
}
public void testRecordPatternNested() {
doTest();
}
public void testRecordPatternAndWhen() {
doTest();
}
public void testNestedRecordPatterns() {
doTest();
}
public void testSuspiciousLabelElementsJava20() {
doTest();
}
public void testForEachPattern() {
myFixture.addClass("""
package org.jetbrains.annotations;
public @interface Range {
long from();
long to();
}""");
doTest();
}
}

View File

@@ -88,4 +88,39 @@ public class DataFlowInspection21Test extends DataFlowInspectionTestCase {
public void testChronoRange() {
doTest();
}
public void testSealedClassCast() { doTest(); }
public void testCastToSealedInterface() { doTest(); }
public void testWhenPatterns() {
doTest();
}
public void testSwitchNullability() {
doTest();
}
public void testRecordPatterns() {
doTest();
}
public void testRecordPatternNested() {
doTest();
}
public void testRecordPatternAndWhen() {
doTest();
}
public void testNestedRecordPatterns() {
doTest();
}
public void testSuspiciousLabelElementsJava20() {
doTest();
}
public void testForEachPattern() {
myFixture.addClass("""
package org.jetbrains.annotations;
public @interface Range {
long from();
long to();
}""");
doTest();
}
}

View File

@@ -18,7 +18,6 @@ import org.junit.platform.suite.api.Suite;
DataFlowInspection9Test.class,
DataFlowInspection11Test.class,
DataFlowInspection16Test.class,
DataFlowInspection20Test.class,
DataFlowInspection21Test.class,
DataFlowInspectionHeavyTest.class,
DataFlowInspectionAncientTest.class,

View File

@@ -66,10 +66,11 @@ public class DefUseTest extends LightJavaCodeInsightFixtureTestCase {
public void testFieldCouldBeUsedOutside() { doTest(); }
public void testForEachIterationParameter() { doTest(); }
public void testPatternVariable() { doTest(); }
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_20;
return JAVA_21;
}
private void doTest() {

View File

@@ -34,9 +34,9 @@ class DuplicateBranchesInEnhancedSwitchTest : LightJavaCodeInsightFixtureTestCas
fun testWhenClause1() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_21) { doTest() }
fun testWhenClause2() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_21) { doTest() }
fun testExpressionsWithComments() = doTest()
fun testNullDuplicatesPattern() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_20_PREVIEW) { doTest() }
fun testPatternDuplicatesNull() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_20_PREVIEW) { doTest() }
fun testNullDuplicatesDefault() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_20_PREVIEW) { doTest() }
fun testNullDuplicatesPattern() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_21) { doTest() }
fun testPatternDuplicatesNull() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_21) { doTest() }
fun testNullDuplicatesDefault() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_21) { doTest() }
fun testMixedCases() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_21_PREVIEW) { doTest() }
fun testDominatedUnnamedVariables() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_21_PREVIEW) { doTest() }

View File

@@ -33,7 +33,7 @@ public class ForEachWithRecordPatternCanBeUsedInspectionTest extends LightJavaCo
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return LightJavaCodeInsightFixtureTestCase.JAVA_20;
return LightJavaCodeInsightFixtureTestCase.JAVA_X;
}

View File

@@ -179,6 +179,6 @@ public class LocalCanBeFinalTest extends LightJavaCodeInsightFixtureTestCase {
public void testPatternVariables() {
myTool.REPORT_PATTERN_VARIABLES = true;
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_20_PREVIEW, this::doTest);
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, this::doTest);
}
}

View File

@@ -25,7 +25,7 @@ import org.jetbrains.annotations.NotNull;
public class PatternVariablesCanBeReplacedWithCastInspectionNotPreserveTest extends LightQuickFixParameterizedTestCase {
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return LightJavaCodeInsightFixtureTestCase.JAVA_20;
return LightJavaCodeInsightFixtureTestCase.JAVA_21;
}
@Override

View File

@@ -25,7 +25,7 @@ import org.jetbrains.annotations.NotNull;
public class PatternVariablesCanBeReplacedWithCastInspectionTest extends LightQuickFixParameterizedTestCase {
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return LightJavaCodeInsightFixtureTestCase.JAVA_20;
return LightJavaCodeInsightFixtureTestCase.JAVA_21;
}
@Override

View File

@@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
public class RedundantLengthCheckInspectionTest extends LightJavaCodeInsightFixtureTestCase {
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return JAVA_20;
return JAVA_21;
}
@Override

View File

@@ -19,8 +19,8 @@ class JavaKeywordsTest {
assertTrue(JavaLexer.isSoftKeyword("sealed", LanguageLevel.JDK_17))
assertFalse(JavaLexer.isKeyword("permits", LanguageLevel.JDK_17))
assertTrue(JavaLexer.isSoftKeyword("permits", LanguageLevel.JDK_17))
assertFalse(JavaLexer.isKeyword("when", LanguageLevel.JDK_20_PREVIEW))
assertTrue(JavaLexer.isSoftKeyword("when", LanguageLevel.JDK_20_PREVIEW))
assertFalse(JavaLexer.isKeyword("when", LanguageLevel.JDK_20))
assertFalse(JavaLexer.isSoftKeyword("when", LanguageLevel.JDK_20))
assertFalse(JavaLexer.isKeyword("when", LanguageLevel.JDK_21))
assertTrue(JavaLexer.isSoftKeyword("when", LanguageLevel.JDK_21))
}

View File

@@ -31,7 +31,7 @@ public class JavaFeatureSpecificSanityTest extends LightJavaCodeInsightFixtureTe
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_20;
return JAVA_21;
}
@Override

View File

@@ -53,6 +53,6 @@ public class FindUsagesTargetTest extends LightJavaCodeInsightFixtureTestCase {
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return JAVA_20;
return JAVA_21;
}
}

View File

@@ -972,18 +972,6 @@ public class ExtractMethodTest extends LightJavaCodeInsightTestCase {
doTestWithLanguageLevel(LanguageLevel.HIGHEST);
}
public void testParenthesizedPatternIntroduced() throws Exception {
doExitPointsTest(false);
}
public void testParenthesizedPatternIntroduced2() throws Exception {
doExitPointsTest(false);
}
public void testParenthesizedPatternIntroduced3() throws Exception {
doTestWithLanguageLevel(LanguageLevel.HIGHEST);
}
public void testRecordPatternIntroduced() throws Exception {
doExitPointsTest(false);
}

View File

@@ -28,7 +28,7 @@ public class UseOfConcreteClassInspectionTest extends LightJavaInspectionTestCas
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return JAVA_20;
return JAVA_21;
}
@Override

Some files were not shown because too many files have changed in this diff Show More