mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-30 02:09:59 +07:00
[java] IDEA-326473 Implement unnamed patterns
GitOrigin-RevId: 1b5db700434306be23d07e38905537025e2cc892
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1c2bbc906a
commit
ab550ac4c0
@@ -132,6 +132,7 @@ feature.pattern.guard.and.record.patterns=Pattern guards and record patterns
|
||||
feature.record.patterns.in.for.each=Record patterns in for-each loops
|
||||
feature.enum.qualified.name.in.switch=Qualified enum as a constant in switch
|
||||
feature.string.templates=String templates
|
||||
feature.unnamed.vars=Unnamed patterns and variables
|
||||
|
||||
find.searching.for.references.to.class.progress=Searching for references to class {0}...
|
||||
find.usages.panel.title.derived.classes.cap=Derived classes
|
||||
@@ -644,3 +645,4 @@ inspection.extract.method.dont.suggest.parameters=Don''t suggest extracting meth
|
||||
inspection.extract.method.dont.suggest.length=Don\u2019t suggest extracting methods as short as this
|
||||
notification.file.system.issue=File Operation Issue
|
||||
notification.content.cannot.move.file=Cannot move ''{0}'' into ''{1}'': {2}
|
||||
intention.family.name.replace.with.unnamed.pattern=Replace with unnamed pattern
|
||||
|
||||
@@ -837,13 +837,13 @@ public final class HighlightUtil {
|
||||
|
||||
static HighlightInfo.Builder checkUnderscore(@NotNull PsiIdentifier identifier, @NotNull LanguageLevel languageLevel) {
|
||||
if ("_".equals(identifier.getText())) {
|
||||
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_9)) {
|
||||
PsiElement parent = identifier.getParent();
|
||||
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_9) && !(parent instanceof PsiUnnamedPattern)) {
|
||||
String text = JavaErrorBundle.message("underscore.identifier.error");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(identifier).descriptionAndTooltip(text);
|
||||
}
|
||||
else if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
|
||||
PsiElement parent = identifier.getParent();
|
||||
if (parent instanceof PsiParameter && ((PsiParameter)parent).getDeclarationScope() instanceof PsiLambdaExpression) {
|
||||
if (parent instanceof PsiParameter parameter && parameter.getDeclarationScope() instanceof PsiLambdaExpression) {
|
||||
String text = JavaErrorBundle.message("underscore.lambda.identifier");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(identifier).descriptionAndTooltip(text);
|
||||
}
|
||||
|
||||
@@ -2122,6 +2122,12 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitUnnamedPattern(@NotNull PsiUnnamedPattern pattern) {
|
||||
super.visitUnnamedPattern(pattern);
|
||||
add(checkFeature(pattern, HighlightingFeature.UNNAMED_PATTERNS_AND_VARIABLES));
|
||||
}
|
||||
|
||||
private HighlightInfo.Builder checkFeature(@NotNull PsiElement element, @NotNull HighlightingFeature feature) {
|
||||
return HighlightUtil.checkFeature(element, feature, myLanguageLevel, myFile);
|
||||
}
|
||||
|
||||
@@ -77,14 +77,14 @@ public enum HighlightingFeature {
|
||||
return until == useSiteLevel;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
boolean isLimited() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
ENUM_QUALIFIED_NAME_IN_SWITCH(LanguageLevel.JDK_21, "feature.enum.qualified.name.in.switch"),
|
||||
STRING_TEMPLATES(LanguageLevel.JDK_21_PREVIEW, "feature.string.templates");
|
||||
STRING_TEMPLATES(LanguageLevel.JDK_21_PREVIEW, "feature.string.templates"),
|
||||
UNNAMED_PATTERNS_AND_VARIABLES(LanguageLevel.JDK_21_PREVIEW, "feature.unnamed.vars");
|
||||
|
||||
public static final @NonNls String JDK_INTERNAL_PREVIEW_FEATURE = "jdk.internal.PreviewFeature";
|
||||
public static final @NonNls String JDK_INTERNAL_JAVAC_PREVIEW_FEATURE = "jdk.internal.javac.PreviewFeature";
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.intellij.codeInsight.daemon.ImplicitUsageProvider;
|
||||
import com.intellij.codeInsight.daemon.JavaErrorBundle;
|
||||
import com.intellij.codeInsight.daemon.UnusedImportProvider;
|
||||
import com.intellij.codeInsight.daemon.impl.*;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.ReplaceWithUnnamedPatternFix;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInsight.intention.QuickFixFactory;
|
||||
import com.intellij.codeInsight.intention.impl.PriorityIntentionActionWrapper;
|
||||
@@ -399,15 +400,27 @@ class PostHighlightingVisitor {
|
||||
}
|
||||
else if (parameter instanceof PsiPatternVariable variable) {
|
||||
HighlightInfo.Builder highlightInfo = checkUnusedParameter(parameter, identifier, null);
|
||||
PsiPattern pattern = variable.getPattern();
|
||||
if (highlightInfo != null) {
|
||||
if (declarationScope.getParent() instanceof PsiSwitchBlock) {
|
||||
IntentionAction action = variable.getParent() instanceof PsiDeconstructionPattern
|
||||
IntentionAction action = null;
|
||||
if (HighlightingFeature.UNNAMED_PATTERNS_AND_VARIABLES.isAvailable(parameter)) {
|
||||
if (pattern instanceof PsiTypeTestPattern && pattern.getParent() instanceof PsiDeconstructionList) {
|
||||
PsiRecordComponent component = JavaPsiPatternUtil.getRecordComponentForPattern(pattern);
|
||||
PsiTypeElement checkType = ((PsiTypeTestPattern)pattern).getCheckType();
|
||||
if (component != null && checkType != null && checkType.getType().isAssignableFrom(component.getType())) {
|
||||
action = new ReplaceWithUnnamedPatternFix(pattern).asIntention();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (action == null && declarationScope.getParent() instanceof PsiSwitchBlock) {
|
||||
action = variable.getParent() instanceof PsiDeconstructionPattern
|
||||
? quickFixFactory.createDeleteFix(parameter)
|
||||
: quickFixFactory.createRenameToIgnoredFix(parameter, false);
|
||||
highlightInfo.registerFix(action, null, null, null, null);
|
||||
}
|
||||
else if (!(variable.getPattern() instanceof PsiTypeTestPattern pattern && pattern.getParent() instanceof PsiDeconstructionList)) {
|
||||
IntentionAction action = quickFixFactory.createDeleteFix(parameter);
|
||||
else if (!(pattern instanceof PsiTypeTestPattern && pattern.getParent() instanceof PsiDeconstructionList)) {
|
||||
action = quickFixFactory.createDeleteFix(parameter);
|
||||
}
|
||||
if (action != null) {
|
||||
highlightInfo.registerFix(action, null, null, null, null);
|
||||
}
|
||||
return highlightInfo;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// 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.quickfix;
|
||||
|
||||
import com.intellij.java.analysis.JavaAnalysisBundle;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.modcommand.PsiUpdateModCommandAction;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ReplaceWithUnnamedPatternFix extends PsiUpdateModCommandAction<PsiPattern> {
|
||||
public ReplaceWithUnnamedPatternFix(@NotNull PsiPattern element) {
|
||||
super(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiPattern element) {
|
||||
return Presentation.of(getFamilyName()).withFixAllOption(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getFamilyName() {
|
||||
return JavaAnalysisBundle.message("intention.family.name.replace.with.unnamed.pattern");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invoke(@NotNull ActionContext context, @NotNull PsiPattern pattern, @NotNull ModPsiUpdater updater) {
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.project());
|
||||
pattern.replace(createUnnamedPattern(factory));
|
||||
}
|
||||
|
||||
private static PsiUnnamedPattern createUnnamedPattern(PsiElementFactory factory) {
|
||||
PsiInstanceOfExpression expr = (PsiInstanceOfExpression)factory
|
||||
.createExpressionFromText("x instanceof R(_)", null);
|
||||
PsiDeconstructionPattern pattern = (PsiDeconstructionPattern)Objects.requireNonNull(expr.getPattern());
|
||||
return ((PsiUnnamedPattern)pattern.getDeconstructionList().getDeconstructionComponents()[0]);
|
||||
}
|
||||
}
|
||||
@@ -482,6 +482,10 @@ public abstract class JavaElementVisitor extends PsiElementVisitor {
|
||||
visitExpression(expression);
|
||||
}
|
||||
|
||||
public void visitUnnamedPattern(@NotNull PsiUnnamedPattern pattern) {
|
||||
visitPattern(pattern);
|
||||
}
|
||||
|
||||
public void visitUsesStatement(@NotNull PsiUsesStatement statement) {
|
||||
visitModuleStatement(statement);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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.psi;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents an unnamed pattern (single '_' inside deconstruction pattern, like {@code R(_)}).
|
||||
* Not to be confused with type pattern with unnamed variable (like {@code R(int _)})
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public interface PsiUnnamedPattern extends PsiPrimaryPattern {
|
||||
/**
|
||||
* @return implicit type element (empty)
|
||||
*/
|
||||
@NotNull PsiTypeElement getTypeElement();
|
||||
}
|
||||
@@ -37,6 +37,20 @@ public class PatternParser {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean parseUnnamedPattern(final PsiBuilder builder) {
|
||||
PsiBuilder.Marker patternStart = builder.mark();
|
||||
if (builder.getTokenType() == JavaTokenType.IDENTIFIER &&
|
||||
"_".equals(builder.getTokenText())) {
|
||||
emptyElement(builder, JavaElementType.TYPE);
|
||||
builder.advanceLexer();
|
||||
done(patternStart, JavaElementType.UNNAMED_PATTERN);
|
||||
return true;
|
||||
}
|
||||
patternStart.rollbackTo();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Nullable("when not pattern")
|
||||
PsiBuilder.Marker preParsePattern(final PsiBuilder builder, boolean parensAllowed) {
|
||||
PsiBuilder.Marker patternStart = builder.mark();
|
||||
@@ -100,6 +114,9 @@ public class PatternParser {
|
||||
parsePattern(builder, true);
|
||||
isFirst = false;
|
||||
}
|
||||
else if (parseUnnamedPattern(builder)) {
|
||||
isFirst = false;
|
||||
}
|
||||
else {
|
||||
int flags = ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD | ReferenceParser.VAR_TYPE;
|
||||
myParser.getReferenceParser().parseType(builder, flags);
|
||||
|
||||
@@ -63,7 +63,11 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
List<TypeAnnotationProvider> arrayComponentAnnotations = new SmartList<>();
|
||||
|
||||
PsiElement parent = getParent();
|
||||
for (PsiElement child = getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
PsiElement firstChild = getFirstChild();
|
||||
if (firstChild == null && parent instanceof PsiUnnamedPattern) {
|
||||
type = JavaPsiPatternUtil.getDeconstructedImplicitPatternType((PsiPattern)parent);
|
||||
}
|
||||
for (PsiElement child = firstChild; child != null; child = child.getNextSibling()) {
|
||||
if (child instanceof PsiComment || child instanceof PsiWhiteSpace) continue;
|
||||
|
||||
if (child instanceof PsiAnnotation) {
|
||||
|
||||
@@ -57,7 +57,7 @@ public interface ElementType extends JavaTokenType, JavaDocTokenType, JavaElemen
|
||||
CONTINUE_STATEMENT, RETURN_STATEMENT, THROW_STATEMENT, SYNCHRONIZED_STATEMENT, TRY_STATEMENT, LABELED_STATEMENT, ASSERT_STATEMENT,
|
||||
YIELD_STATEMENT);
|
||||
|
||||
TokenSet JAVA_PATTERN_BIT_SET = TokenSet.create(TYPE_TEST_PATTERN, PARENTHESIZED_PATTERN, DECONSTRUCTION_PATTERN);
|
||||
TokenSet JAVA_PATTERN_BIT_SET = TokenSet.create(TYPE_TEST_PATTERN, PARENTHESIZED_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, PATTERN_GUARD));
|
||||
|
||||
@@ -139,6 +139,7 @@ public interface JavaElementType {
|
||||
IElementType ANNOTATION_ARRAY_INITIALIZER = new JavaCompositeElementType("ANNOTATION_ARRAY_INITIALIZER", () -> new PsiArrayInitializerMemberValueImpl());
|
||||
IElementType RECEIVER_PARAMETER = new JavaCompositeElementType("RECEIVER", () -> new PsiReceiverParameterImpl());
|
||||
IElementType MODULE_REFERENCE = new JavaCompositeElementType("MODULE_REFERENCE", () -> new PsiJavaModuleReferenceElementImpl());
|
||||
IElementType UNNAMED_PATTERN = new JavaCompositeElementType("UNNAMED_PATTERN", () -> new PsiUnnamedPatternImpl());
|
||||
IElementType TYPE_TEST_PATTERN = new JavaCompositeElementType("TYPE_TEST_PATTERN", () -> new PsiTypeTestPatternImpl());
|
||||
IElementType PATTERN_VARIABLE = new JavaCompositeElementType("PATTERN_VARIABLE", () -> new PsiPatternVariableImpl());
|
||||
IElementType DECONSTRUCTION_PATTERN = new JavaCompositeElementType("DECONSTRUCTION_PATTERN", () -> new PsiDeconstructionPatternImpl());
|
||||
|
||||
@@ -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);
|
||||
private final TokenSet PRIMARY_PATTERN_SET = TokenSet.create(TYPE_TEST_PATTERN, DECONSTRUCTION_PATTERN, PARENTHESIZED_PATTERN, UNNAMED_PATTERN);
|
||||
|
||||
public PsiDeconstructionListImpl() {
|
||||
super(DECONSTRUCTION_LIST);
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// 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.psi.impl.source.tree.java;
|
||||
|
||||
import com.intellij.psi.JavaElementVisitor;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiTypeElement;
|
||||
import com.intellij.psi.PsiUnnamedPattern;
|
||||
import com.intellij.psi.impl.source.Constants;
|
||||
import com.intellij.psi.impl.source.tree.CompositePsiElement;
|
||||
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class PsiUnnamedPatternImpl extends CompositePsiElement implements PsiUnnamedPattern, Constants {
|
||||
public PsiUnnamedPatternImpl() {
|
||||
super(UNNAMED_PATTERN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PsiTypeElement getTypeElement() {
|
||||
PsiTypeElement type = (PsiTypeElement)findPsiChildByType(JavaElementType.TYPE);
|
||||
assert type != null; // guaranteed by parser
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof JavaElementVisitor) {
|
||||
((JavaElementVisitor)visitor).visitUnnamedPattern(this);
|
||||
}
|
||||
else {
|
||||
visitor.visitElement(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PsiUnnamedPattern";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,6 +209,9 @@ public final class JavaPsiPatternUtil {
|
||||
else if (pattern instanceof PsiTypeTestPattern) {
|
||||
return ((PsiTypeTestPattern)pattern).getCheckType();
|
||||
}
|
||||
else if (pattern instanceof PsiUnnamedPattern) {
|
||||
return ((PsiUnnamedPattern)pattern).getTypeElement();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -229,11 +232,8 @@ public final class JavaPsiPatternUtil {
|
||||
else if (pattern instanceof PsiParenthesizedPattern) {
|
||||
return findUnconditionalPattern(((PsiParenthesizedPattern)pattern).getPattern());
|
||||
}
|
||||
else if (pattern instanceof PsiDeconstructionPattern) {
|
||||
return (PsiDeconstructionPattern)pattern;
|
||||
}
|
||||
else if (pattern instanceof PsiTypeTestPattern) {
|
||||
return (PsiTypeTestPattern)pattern;
|
||||
else if (pattern instanceof PsiDeconstructionPattern || pattern instanceof PsiTypeTestPattern || pattern instanceof PsiUnnamedPattern) {
|
||||
return (PsiPrimaryPattern)pattern;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -243,7 +243,7 @@ public final class JavaPsiPatternUtil {
|
||||
if (unconditionalPattern instanceof PsiDeconstructionPattern) {
|
||||
return forDomination && dominates(getPatternType(unconditionalPattern), type);
|
||||
}
|
||||
else if (unconditionalPattern instanceof PsiTypeTestPattern) {
|
||||
else if (unconditionalPattern instanceof PsiTypeTestPattern || unconditionalPattern instanceof PsiUnnamedPattern) {
|
||||
return dominates(getPatternType(unconditionalPattern), type);
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
public class UnnamedPatterns {
|
||||
record R(int a, int b) {}
|
||||
|
||||
void test(Object obj) {
|
||||
if (obj instanceof <error descr="As of Java 9, '_' is a keyword, and may not be used as an identifier">_</error>) {}
|
||||
|
||||
if (obj instanceof R(_, _)) {}
|
||||
if (obj instanceof R(int a, _)) {
|
||||
System.out.println(a);
|
||||
}
|
||||
if (obj instanceof R(_, int b)) {
|
||||
System.out.println(b);
|
||||
}
|
||||
if (obj instanceof R(_, _, <error descr="Incorrect number of nested patterns: expected 2 but found 3">_)</error>) {
|
||||
}
|
||||
}
|
||||
|
||||
void testSwitch(Object obj) {
|
||||
switch (obj) {
|
||||
case R(_, var b) -> {
|
||||
}
|
||||
case <error descr="Label is dominated by a preceding case label 'R(_, var b)'">R(var c, var b)</error> -> {
|
||||
}
|
||||
case <error descr="Label is dominated by a preceding case label 'R(_, var b)'">R(int a, _)</error> -> {
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
public class UnnamedPatterns {
|
||||
record R(int a, int b) {}
|
||||
|
||||
void test(Object obj) {
|
||||
if (obj instanceof <error descr="As of Java 9, '_' is a keyword, and may not be used as an identifier">_</error>) {}
|
||||
|
||||
if (obj instanceof R(<error descr="Unnamed patterns and variables are not supported at language level '20'">_</error>, <error descr="Unnamed patterns and variables are not supported at language level '20'">_</error>)) {}
|
||||
if (obj instanceof R(int a, <error descr="Unnamed patterns and variables are not supported at language level '20'">_</error>)) {
|
||||
System.out.println(a);
|
||||
}
|
||||
if (obj instanceof R(<error descr="Unnamed patterns and variables are not supported at language level '20'">_</error>, int b)) {
|
||||
System.out.println(b);
|
||||
}
|
||||
if (obj instanceof R(<error descr="Unnamed patterns and variables are not supported at language level '20'">_</error>, <error descr="Unnamed patterns and variables are not supported at language level '20'">_</error>, <error descr="Unnamed patterns and variables are not supported at language level '20'">_</error>)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Apply all 'Replace with unnamed pattern' fixes in file" "true"
|
||||
public class Test {
|
||||
record R(int x, int y) {}
|
||||
void test(Object obj) {
|
||||
if (obj instanceof R(_, _)) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with unnamed pattern" "true-preview"
|
||||
public class Test {
|
||||
record R(int x, int y) {}
|
||||
void test(Object obj) {
|
||||
if (obj instanceof R(_, int b)) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with unnamed pattern" "true-preview"
|
||||
public class Test {
|
||||
record R(int x, int y) {}
|
||||
void test(Object obj) {
|
||||
switch(obj) {
|
||||
case R(_, int b) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Apply all 'Replace with unnamed pattern' fixes in file" "true"
|
||||
public class Test {
|
||||
record R(int x, int y) {}
|
||||
void test(Object obj) {
|
||||
if (obj instanceof R(int <caret>a, int b)) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with unnamed pattern" "false"
|
||||
public class Test {
|
||||
record R(Object cmp) {}
|
||||
void test(Object obj) {
|
||||
if (obj instanceof R(String <caret>a)) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with unnamed pattern" "true-preview"
|
||||
public class Test {
|
||||
record R(int x, int y) {}
|
||||
void test(Object obj) {
|
||||
if (obj instanceof R(int <caret>a, int b)) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Replace with unnamed pattern" "true-preview"
|
||||
public class Test {
|
||||
record R(int x, int y) {}
|
||||
void test(Object obj) {
|
||||
switch(obj) {
|
||||
case R(int <caret>a, int b) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
class Test {
|
||||
record R(int x, int y) {}
|
||||
void test(Object obj) {
|
||||
if (obj instanceof R(_, var b)) {
|
||||
return;
|
||||
}
|
||||
if (<warning descr="Condition 'obj instanceof R(var a, var b)' is always 'false'">obj instanceof R(var a, var b)</warning>) {
|
||||
return;
|
||||
}
|
||||
if (<warning descr="Condition 'obj instanceof R(int a, _)' is always 'false'">obj instanceof R(int a, _)</warning>) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
PsiJavaFile:RecordUnnamed0.java
|
||||
PsiDeconstructionPattern
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:Point
|
||||
PsiJavaCodeReferenceElement:Point
|
||||
PsiIdentifier:Point('Point')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiDeconstructionList
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiUnnamedPattern
|
||||
PsiTypeElement:
|
||||
<empty list>
|
||||
PsiIdentifier:_('_')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
@@ -0,0 +1,26 @@
|
||||
PsiJavaFile:RecordUnnamed1.java
|
||||
PsiDeconstructionPattern
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:Point
|
||||
PsiJavaCodeReferenceElement:Point
|
||||
PsiIdentifier:Point('Point')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiDeconstructionList
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiTypeTestPattern
|
||||
PsiPatternVariable:x
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:int
|
||||
PsiKeyword:int('int')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:x('x')
|
||||
PsiJavaToken:COMMA(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiUnnamedPattern
|
||||
PsiTypeElement:
|
||||
<empty list>
|
||||
PsiIdentifier:_('_')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
@@ -0,0 +1,26 @@
|
||||
PsiJavaFile:RecordUnnamed2.java
|
||||
PsiDeconstructionPattern
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:Point
|
||||
PsiJavaCodeReferenceElement:Point
|
||||
PsiIdentifier:Point('Point')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiDeconstructionList
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiUnnamedPattern
|
||||
PsiTypeElement:
|
||||
<empty list>
|
||||
PsiIdentifier:_('_')
|
||||
PsiJavaToken:COMMA(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiTypeTestPattern
|
||||
PsiPatternVariable:y
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:int
|
||||
PsiKeyword:int('int')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:y('y')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
@@ -0,0 +1,22 @@
|
||||
PsiJavaFile:RecordUnnamed3.java
|
||||
PsiDeconstructionPattern
|
||||
PsiModifierList:
|
||||
<empty list>
|
||||
PsiTypeElement:Point
|
||||
PsiJavaCodeReferenceElement:Point
|
||||
PsiIdentifier:Point('Point')
|
||||
PsiReferenceParameterList
|
||||
<empty list>
|
||||
PsiDeconstructionList
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiUnnamedPattern
|
||||
PsiTypeElement:
|
||||
<empty list>
|
||||
PsiIdentifier:_('_')
|
||||
PsiJavaToken:COMMA(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiUnnamedPattern
|
||||
PsiTypeElement:
|
||||
<empty list>
|
||||
PsiIdentifier:_('_')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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.quickfix;
|
||||
|
||||
import com.intellij.codeInsight.daemon.LightIntentionActionTestCase;
|
||||
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase.JAVA_21;
|
||||
|
||||
public class ChangeToUnnamedPatternTest extends LightIntentionActionTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
enableInspectionTool(new UnusedDeclarationInspectionBase());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected LightProjectDescriptor getProjectDescriptor() {
|
||||
return JAVA_21;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/changeToUnnamed";
|
||||
}
|
||||
}
|
||||
@@ -96,6 +96,14 @@ public class LightPatternsHighlightingTest extends LightJavaCodeInsightFixtureTe
|
||||
public void testNotAnnotationsInDeconstructionType() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testUnnamedPatterns() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testUnnamedPatternsUnavailable() {
|
||||
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_20, this::doTest);
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
myFixture.configureByFile(getTestName(false) + ".java");
|
||||
|
||||
@@ -52,6 +52,10 @@ public class DataFlowInspection21Test extends DataFlowInspectionTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testUnnamedPatterns() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testPatternInStreamNotComplex() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@ public class PatternParserTest extends JavaParsingTestCase {
|
||||
public void testRecord10() { doParserTest("Rec r"); }
|
||||
public void testRecord11() { doParserTest("Rec(var x) r"); }
|
||||
public void testRecord12() { doParserTest("Rec(String)"); }
|
||||
public void testRecordUnnamed0() { doParserTest("Point(_)"); }
|
||||
public void testRecordUnnamed1() { doParserTest("Point(int x, _)"); }
|
||||
public void testRecordUnnamed2() { doParserTest("Point(_, int y)"); }
|
||||
public void testRecordUnnamed3() { doParserTest("Point(_, _)"); }
|
||||
|
||||
private void doParserTest(String text) {
|
||||
doParserTest(text, builder -> {
|
||||
|
||||
@@ -491,6 +491,9 @@ public class EquivalenceChecker {
|
||||
}
|
||||
pattern1 = JavaPsiPatternUtil.skipParenthesizedPatternDown(pattern1);
|
||||
pattern2 = JavaPsiPatternUtil.skipParenthesizedPatternDown(pattern2);
|
||||
if (pattern1 instanceof PsiUnnamedPattern && pattern2 instanceof PsiUnnamedPattern) {
|
||||
return EXACT_MATCH;
|
||||
}
|
||||
if (pattern1 instanceof PsiTypeTestPattern && pattern2 instanceof PsiTypeTestPattern) {
|
||||
return Match.exact(primaryPatternsMatch((PsiTypeTestPattern)pattern1, (PsiTypeTestPattern)pattern2));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user