mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-completion] IDEA-352185 Support JEP 455: completion for primitives in patterns
- primitives after `instanceof` - primitives after `case` - primitives in deconstruction records GitOrigin-RevId: c8ce9747b55605ab73be338d80b42fba41008220
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8416740b8c
commit
63bef6eeac
@@ -1168,6 +1168,37 @@ public class JavaKeywordCompletion {
|
||||
|
||||
if (JavaPatternCompletionUtil.insideDeconstructionList(position)) {
|
||||
JavaPatternCompletionUtil.suggestPrimitivesInsideDeconstructionListPattern(position, result);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((InstanceofTypeProvider.AFTER_INSTANCEOF.accepts(position)) &&
|
||||
position.getParent() instanceof PsiJavaCodeReferenceElement referenceElement &&
|
||||
referenceElement.getParent() instanceof PsiTypeElement typeElement &&
|
||||
(typeElement.getParent() instanceof PsiInstanceOfExpression ||
|
||||
(typeElement.getParent() instanceof PsiPatternVariable variable &&
|
||||
(variable.getParent() instanceof PsiInstanceOfExpression ||
|
||||
variable.getParent() instanceof PsiTypeTestPattern typeTestPattern &&
|
||||
typeTestPattern.getParent() instanceof PsiInstanceOfExpression)))) {
|
||||
PsiInstanceOfExpression instanceOfExpression = PsiTreeUtil.getParentOfType(position, PsiInstanceOfExpression.class);
|
||||
if (instanceOfExpression != null) {
|
||||
JavaPatternCompletionUtil.suggestPrimitiveTypesForPattern(position, instanceOfExpression.getOperand().getType(), result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (psiElement().afterLeaf(PsiKeyword.CASE).accepts(position) &&
|
||||
((position.getParent() instanceof PsiReferenceExpression referenceExpression &&
|
||||
referenceExpression.getParent() instanceof PsiCaseLabelElementList)
|
||||
|| (position.getParent() instanceof PsiJavaCodeReferenceElement referenceElement &&
|
||||
referenceElement.getParent() instanceof PsiTypeElement typeElement &&
|
||||
typeElement.getParent() instanceof PsiPatternVariable patternVariable &&
|
||||
patternVariable.getParent() instanceof PsiTypeTestPattern typeTestPattern &&
|
||||
typeTestPattern.getParent() instanceof PsiCaseLabelElementList))) {
|
||||
PsiSwitchBlock switchBlock = PsiTreeUtil.getParentOfType(position, PsiSwitchBlock.class);
|
||||
if (switchBlock != null && switchBlock.getExpression() != null) {
|
||||
JavaPatternCompletionUtil.suggestPrimitiveTypesForPattern(position, switchBlock.getExpression().getType(), result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
boolean afterNew = JavaSmartCompletionContributor.AFTER_NEW.accepts(position) &&
|
||||
|
||||
+37
-4
@@ -14,6 +14,7 @@ import com.intellij.psi.impl.source.JavaVarTypeUtil;
|
||||
import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import one.util.streamex.EntryStream;
|
||||
@@ -26,12 +27,25 @@ import java.util.function.Consumer;
|
||||
|
||||
public final class JavaPatternCompletionUtil {
|
||||
|
||||
private static final List<PsiType> PRIMITIVE_TYPES = List.of(
|
||||
PsiTypes.booleanType(),
|
||||
PsiTypes.byteType(),
|
||||
PsiTypes.charType(),
|
||||
PsiTypes.shortType(),
|
||||
PsiTypes.intType(),
|
||||
PsiTypes.floatType(),
|
||||
PsiTypes.doubleType(),
|
||||
PsiTypes.longType()
|
||||
);
|
||||
|
||||
public static boolean insideDeconstructionList(@NotNull PsiElement element) {
|
||||
if (!PsiUtil.isAvailable(JavaFeature.PATTERN_GUARDS_AND_RECORD_PATTERNS, element)) return false;
|
||||
return element.getParent() instanceof PsiJavaCodeReferenceElement ref &&
|
||||
ref.getParent() instanceof PsiTypeElement typeElement &&
|
||||
typeElement.getParent() instanceof PsiDeconstructionList;
|
||||
(typeElement.getParent() instanceof PsiDeconstructionList ||
|
||||
(typeElement.getParent() instanceof PsiPatternVariable patternVariable &&
|
||||
patternVariable.getParent() instanceof PsiTypeTestPattern typeTestPattern &&
|
||||
typeTestPattern.getParent() instanceof PsiDeconstructionList));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,9 +97,14 @@ public final class JavaPatternCompletionUtil {
|
||||
PsiRecordComponent component = getRecordComponentForDeconstructionComponent(currentPosition);
|
||||
if (component == null) return;
|
||||
PsiType type = component.getType();
|
||||
if (type instanceof PsiPrimitiveType) {
|
||||
LookupElement lookupItem = BasicExpressionCompletionContributor.createKeywordLookupItem(currentPosition, type.getCanonicalText());
|
||||
result.accept(new JavaKeywordCompletion.OverridableSpace(lookupItem, TailTypes.insertSpaceType()));
|
||||
if (!PsiUtil.isAvailable(JavaFeature.PRIMITIVE_TYPES_IN_PATTERNS, currentPosition)) {
|
||||
if (type instanceof PsiPrimitiveType) {
|
||||
LookupElement lookupItem = BasicExpressionCompletionContributor.createKeywordLookupItem(currentPosition, type.getCanonicalText());
|
||||
result.accept(new JavaKeywordCompletion.OverridableSpace(lookupItem, TailTypes.spaceType()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
suggestPrimitiveTypesForPattern(currentPosition, type, result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +138,20 @@ public final class JavaPatternCompletionUtil {
|
||||
return recordComponents[indexOfPattern];
|
||||
}
|
||||
|
||||
static void suggestPrimitiveTypesForPattern(@NotNull PsiElement currentPosition,
|
||||
@Nullable PsiType fromType,
|
||||
@NotNull Consumer<? super LookupElement> result) {
|
||||
if (fromType == null) return;
|
||||
if (!PsiUtil.isAvailable(JavaFeature.PRIMITIVE_TYPES_IN_PATTERNS, currentPosition)) return;
|
||||
for (PsiType primitiveType : PRIMITIVE_TYPES) {
|
||||
if (TypeConversionUtil.areTypesConvertible(fromType, primitiveType)) {
|
||||
LookupElement lookupItem =
|
||||
BasicExpressionCompletionContributor.createKeywordLookupItem(currentPosition, primitiveType.getCanonicalText());
|
||||
result.accept(new JavaKeywordCompletion.OverridableSpace(lookupItem, TailTypes.spaceType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests a full deconstruction list based on the given completion parameters and result set.
|
||||
*
|
||||
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.java.codeInsight.completion;
|
||||
|
||||
import com.intellij.pom.java.JavaFeature;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.testFramework.NeedsIndex;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class NormalPatternsPrimitiveCompletionTest extends NormalCompletionTestCase {
|
||||
@NotNull
|
||||
@Override
|
||||
protected LightProjectDescriptor getProjectDescriptor() {
|
||||
return new ProjectDescriptor(JavaFeature.PRIMITIVE_TYPES_IN_PATTERNS.getMinimumLevel());
|
||||
}
|
||||
|
||||
@NeedsIndex.Full
|
||||
public void testPatternPrimitiveRecordInstanceof() {
|
||||
myFixture.configureByText("a.java", """
|
||||
record Point(Integer x, int y);
|
||||
class X {
|
||||
void test(Object o) {
|
||||
if(o instanceof Point(fl<caret>)
|
||||
}
|
||||
}""");
|
||||
myFixture.completeBasic();
|
||||
myFixture.checkResult("""
|
||||
record Point(Integer x, int y);
|
||||
class X {
|
||||
void test(Object o) {
|
||||
if(o instanceof Point(float <caret>)
|
||||
}
|
||||
}""");
|
||||
}
|
||||
|
||||
@NeedsIndex.Full
|
||||
public void testPatternPrimitiveRecordInstanceof2() {
|
||||
myFixture.configureByText("a.java", """
|
||||
record Point(int x, int y);
|
||||
class X {
|
||||
void test(Object o) {
|
||||
if(o instanceof Point(int x, flo<caret>)
|
||||
}
|
||||
}""");
|
||||
myFixture.completeBasic();
|
||||
myFixture.checkResult("""
|
||||
record Point(int x, int y);
|
||||
class X {
|
||||
void test(Object o) {
|
||||
if(o instanceof Point(int x, float <caret>)
|
||||
}
|
||||
}""");
|
||||
}
|
||||
|
||||
@NeedsIndex.Full
|
||||
public void testPatternPrimitiveRecordInstanceofBeforeIdentifier() {
|
||||
myFixture.configureByText("a.java", """
|
||||
record Point(int x, int y);
|
||||
class X {
|
||||
void test(Object o) {
|
||||
if(o instanceof Point(int x, fl<caret> y))
|
||||
}
|
||||
}""");
|
||||
myFixture.completeBasic();
|
||||
myFixture.checkResult("""
|
||||
record Point(int x, int y);
|
||||
class X {
|
||||
void test(Object o) {
|
||||
if(o instanceof Point(int x, float <caret>y))
|
||||
}
|
||||
}""");
|
||||
}
|
||||
|
||||
@NeedsIndex.Full
|
||||
public void testPrimitiveRecordSwitch() {
|
||||
myFixture.configureByText("a.java", """
|
||||
record Point(int x, int y);
|
||||
class X {
|
||||
void test(Object o) {
|
||||
switch(o){
|
||||
case Point(int x, fl<caret> y) ->
|
||||
}
|
||||
}
|
||||
}""");
|
||||
myFixture.completeBasic();
|
||||
myFixture.checkResult("""
|
||||
record Point(int x, int y);
|
||||
class X {
|
||||
void test(Object o) {
|
||||
switch(o){
|
||||
case Point(int x, float y) ->
|
||||
}
|
||||
}
|
||||
}""");
|
||||
}
|
||||
|
||||
@NeedsIndex.Full
|
||||
public void testPrimitiveAfterCase() {
|
||||
myFixture.configureByText("a.java", """
|
||||
class X {
|
||||
void test(Object o) {
|
||||
switch(o){
|
||||
case flo<caret> ->
|
||||
}
|
||||
}
|
||||
}""");
|
||||
myFixture.completeBasic();
|
||||
myFixture.checkResult("""
|
||||
class X {
|
||||
void test(Object o) {
|
||||
switch(o){
|
||||
case float <caret>->
|
||||
}
|
||||
}
|
||||
}""");
|
||||
}
|
||||
|
||||
@NeedsIndex.Full
|
||||
public void testPrimitiveAfterCaseBeforeIdentifier() {
|
||||
myFixture.configureByText("a.java", """
|
||||
class X {
|
||||
void test(Object o) {
|
||||
switch(o){
|
||||
case d<caret> o ->
|
||||
}
|
||||
}
|
||||
}""");
|
||||
myFixture.completeBasic();
|
||||
myFixture.checkResult("""
|
||||
class X {
|
||||
void test(Object o) {
|
||||
switch(o){
|
||||
case double o ->
|
||||
}
|
||||
}
|
||||
}""");
|
||||
}
|
||||
@NeedsIndex.Full
|
||||
public void testPrimitiveAfterInstanceof() {
|
||||
myFixture.configureByText("a.java", """
|
||||
class X {
|
||||
void test(Object o) {
|
||||
if (o instanceof fl<caret>
|
||||
}
|
||||
}""");
|
||||
myFixture.completeBasic();
|
||||
myFixture.checkResult("""
|
||||
class X {
|
||||
void test(Object o) {
|
||||
if (o instanceof float <caret>
|
||||
}
|
||||
}""");
|
||||
}
|
||||
|
||||
@NeedsIndex.Full
|
||||
public void testPrimitiveAfterInstanceofBeforeIdentifier() {
|
||||
myFixture.configureByText("a.java", """
|
||||
class X {
|
||||
void test(Object o) {
|
||||
if (o instanceof fl<caret> a
|
||||
}
|
||||
}""");
|
||||
myFixture.completeBasic();
|
||||
myFixture.checkResult("""
|
||||
class X {
|
||||
void test(Object o) {
|
||||
if (o instanceof float <caret>a
|
||||
}
|
||||
}""");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user