mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
prefer relevant types when completing cast type (IDEA-167190, IDEA-156868)
This commit is contained in:
+1
-1
@@ -290,7 +290,7 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
|
||||
if (SmartCastProvider.shouldSuggestCast(parameters)) {
|
||||
SmartCastProvider.addCastVariants(parameters, element -> {
|
||||
SmartCastProvider.addCastVariants(parameters, result.getPrefixMatcher(), element -> {
|
||||
registerClassFromTypeElement(element, session);
|
||||
result.addElement(PrioritizedLookupElement.withPriority(element, 1));
|
||||
});
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.patterns.PsiJavaPatterns;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.NameUtil;
|
||||
@@ -43,6 +42,8 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
@@ -51,11 +52,11 @@ public class JavaCompletionSorting {
|
||||
}
|
||||
|
||||
public static CompletionResultSet addJavaSorting(final CompletionParameters parameters, CompletionResultSet result) {
|
||||
final PsiElement position = parameters.getPosition();
|
||||
final ExpectedTypeInfo[] expectedTypes = PsiJavaPatterns.psiElement().beforeLeaf(PsiJavaPatterns.psiElement().withText(".")).accepts(position) ? ExpectedTypeInfo.EMPTY_ARRAY : JavaSmartCompletionContributor.getExpectedTypes(parameters);
|
||||
final CompletionType type = parameters.getCompletionType();
|
||||
final boolean smart = type == CompletionType.SMART;
|
||||
final boolean afterNew = JavaSmartCompletionContributor.AFTER_NEW.accepts(position);
|
||||
PsiElement position = parameters.getPosition();
|
||||
ExpectedTypeInfo[] expectedTypes = getExpectedTypesWithDfa(parameters, position);
|
||||
CompletionType type = parameters.getCompletionType();
|
||||
boolean smart = type == CompletionType.SMART;
|
||||
boolean afterNew = JavaSmartCompletionContributor.AFTER_NEW.accepts(position);
|
||||
|
||||
List<LookupElementWeigher> afterProximity = new ArrayList<>();
|
||||
afterProximity.add(new PreferContainingSameWords(expectedTypes));
|
||||
@@ -91,6 +92,18 @@ public class JavaCompletionSorting {
|
||||
return result.withRelevanceSorter(sorter);
|
||||
}
|
||||
|
||||
private static ExpectedTypeInfo[] getExpectedTypesWithDfa(CompletionParameters parameters, PsiElement position) {
|
||||
if (psiElement().beforeLeaf(psiElement().withText(".")).accepts(position)) {
|
||||
return ExpectedTypeInfo.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
ExpectedTypeInfo castExpectation = SmartCastProvider.getParenthesizedCastExpectationByOperandType(position);
|
||||
if (castExpectation != null) {
|
||||
return new ExpectedTypeInfo[]{castExpectation};
|
||||
}
|
||||
return JavaSmartCompletionContributor.getExpectedTypes(parameters);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static LookupElementWeigher recursion(CompletionParameters parameters, final ExpectedTypeInfo[] expectedInfos) {
|
||||
final PsiElement position = parameters.getPosition();
|
||||
@@ -147,17 +160,20 @@ public class JavaCompletionSorting {
|
||||
PsiUtil.ensureValidType(itemType);
|
||||
|
||||
for (final ExpectedTypeInfo expectedInfo : expectedInfos) {
|
||||
final PsiType defaultType = expectedInfo.getDefaultType();
|
||||
final PsiType expectedType = expectedInfo.getType();
|
||||
PsiType expectedType = expectedInfo.getType();
|
||||
|
||||
assert expectedType.isValid();
|
||||
assert defaultType.isValid();
|
||||
|
||||
if (defaultType != expectedType && defaultType.isAssignableFrom(itemType)) {
|
||||
return ExpectedTypeMatching.ofDefaultType;
|
||||
}
|
||||
if (expectedType.isAssignableFrom(itemType)) {
|
||||
return ExpectedTypeMatching.expected;
|
||||
if (expectedInfo.getKind() == ExpectedTypeInfo.TYPE_OR_SUPERTYPE) {
|
||||
if (itemType.isAssignableFrom(expectedType)) {
|
||||
return ExpectedTypeMatching.expected;
|
||||
}
|
||||
} else {
|
||||
PsiType defaultType = expectedInfo.getDefaultType();
|
||||
if (defaultType != expectedType && defaultType.isAssignableFrom(itemType)) {
|
||||
return ExpectedTypeMatching.ofDefaultType;
|
||||
}
|
||||
if (expectedType.isAssignableFrom(itemType)) {
|
||||
return ExpectedTypeMatching.expected;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -480,7 +496,10 @@ public class JavaCompletionSorting {
|
||||
}
|
||||
}
|
||||
}
|
||||
return preferByMemberName(myExpectedMemberName, itemType);
|
||||
ExpectedTypeMatching byName = preferByMemberName(myExpectedMemberName, itemType);
|
||||
if (byName != ExpectedTypeMatching.normal) {
|
||||
return byName;
|
||||
}
|
||||
}
|
||||
|
||||
return getExpectedTypeMatching(item, myExpectedTypes, myExpectedMemberName);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.ExpectedTypeInfo;
|
||||
import com.intellij.codeInsight.ExpectedTypeInfoImpl;
|
||||
import com.intellij.codeInsight.ExpectedTypesProvider;
|
||||
import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.completion.simple.RParenthTailType;
|
||||
import com.intellij.codeInsight.guess.GuessManager;
|
||||
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementDecorator;
|
||||
@@ -17,12 +19,16 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
||||
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
|
||||
import com.intellij.psi.impl.source.tree.java.PsiEmptyExpressionImpl;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.patterns.PlatformPatterns.psiElement;
|
||||
|
||||
/**
|
||||
@@ -48,10 +54,10 @@ class SmartCastProvider extends CompletionProvider<CompletionParameters> {
|
||||
|
||||
@Override
|
||||
protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
|
||||
addCastVariants(parameters, result);
|
||||
addCastVariants(parameters, result.getPrefixMatcher(), result);
|
||||
}
|
||||
|
||||
static void addCastVariants(@NotNull CompletionParameters parameters, @NotNull Consumer<LookupElement> result) {
|
||||
static void addCastVariants(@NotNull CompletionParameters parameters, PrefixMatcher matcher, @NotNull Consumer<LookupElement> result) {
|
||||
if (!shouldSuggestCast(parameters)) return;
|
||||
|
||||
PsiElement position = parameters.getPosition();
|
||||
@@ -60,9 +66,15 @@ class SmartCastProvider extends CompletionProvider<CompletionParameters> {
|
||||
|
||||
if (insideCast) {
|
||||
PsiElement parent = parenthesisOwner.getParent();
|
||||
if (parent instanceof PsiParenthesizedExpression && parent.getParent() instanceof PsiReferenceExpression) {
|
||||
for (ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes((PsiParenthesizedExpression)parent, false)) {
|
||||
result.consume(PsiTypeLookupItem.createLookupItem(info.getType(), parent));
|
||||
if (parent instanceof PsiParenthesizedExpression) {
|
||||
if (parent.getParent() instanceof PsiReferenceExpression) {
|
||||
for (ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes((PsiParenthesizedExpression)parent, false)) {
|
||||
result.consume(PsiTypeLookupItem.createLookupItem(info.getType(), parent));
|
||||
}
|
||||
}
|
||||
ExpectedTypeInfo info = getParenthesizedCastExpectationByOperandType(position);
|
||||
if (info != null) {
|
||||
addHierarchyTypes(parameters, matcher, info, type -> result.consume(PsiTypeLookupItem.createLookupItem(type, parent)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -92,10 +104,48 @@ class SmartCastProvider extends CompletionProvider<CompletionParameters> {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static ExpectedTypeInfo getParenthesizedCastExpectationByOperandType(PsiElement position) {
|
||||
PsiElement parenthesisOwner = getParenthesisOwner(position);
|
||||
PsiExpression operand = getCastedExpression(parenthesisOwner);
|
||||
if (operand == null || !(parenthesisOwner.getParent() instanceof PsiParenthesizedExpression)) return null;
|
||||
|
||||
PsiType dfaType = GuessManager.getInstance(operand.getProject()).getControlFlowExpressionType(operand);
|
||||
if (dfaType != null) {
|
||||
return new ExpectedTypeInfoImpl(dfaType, ExpectedTypeInfo.TYPE_OR_SUPERTYPE, dfaType, TailType.NONE, null, () -> null);
|
||||
}
|
||||
|
||||
PsiType type = operand.getType();
|
||||
return type == null || type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) ? null :
|
||||
new ExpectedTypeInfoImpl(type, ExpectedTypeInfo.TYPE_OR_SUBTYPE, type, TailType.NONE, null, () -> null);
|
||||
}
|
||||
|
||||
private static void addHierarchyTypes(CompletionParameters parameters, PrefixMatcher matcher, ExpectedTypeInfo info, Consumer<PsiType> result) {
|
||||
PsiType infoType = info.getType();
|
||||
PsiClass infoClass = PsiUtil.resolveClassInClassTypeOnly(infoType);
|
||||
if (info.getKind() == ExpectedTypeInfo.TYPE_OR_SUPERTYPE) {
|
||||
InheritanceUtil.processSupers(infoClass, true, superClass -> {
|
||||
if (!CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) {
|
||||
result.consume(JavaPsiFacade.getElementFactory(superClass.getProject()).createType(superClass));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
JavaInheritorsGetter.processInheritors(parameters, Collections.singleton((PsiClassType)infoType), matcher, type -> {
|
||||
if (!infoType.equals(type)) {
|
||||
result.consume(type);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static PsiType getCastedExpressionType(PsiElement parenthesisOwner) {
|
||||
PsiExpression operand = getCastedExpression(parenthesisOwner);
|
||||
return operand == null ? null : operand.getType();
|
||||
}
|
||||
|
||||
private static PsiExpression getCastedExpression(PsiElement parenthesisOwner) {
|
||||
if (parenthesisOwner instanceof PsiTypeCastExpression) {
|
||||
final PsiExpression operand = ((PsiTypeCastExpression)parenthesisOwner).getOperand();
|
||||
return operand == null ? null : operand.getType();
|
||||
return ((PsiTypeCastExpression)parenthesisOwner).getOperand();
|
||||
}
|
||||
|
||||
if (parenthesisOwner instanceof PsiParenthesizedExpression) {
|
||||
@@ -104,7 +154,7 @@ class SmartCastProvider extends CompletionProvider<CompletionParameters> {
|
||||
next = next.getNextSibling();
|
||||
}
|
||||
if (next instanceof PsiExpression) {
|
||||
return ((PsiExpression)next).getType();
|
||||
return (PsiExpression)next;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
public class Super {
|
||||
|
||||
static void foo(Object o) {
|
||||
if (o instanceof SString) {
|
||||
((S<caret>) o)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SString implements java.io.Serializable, nonImported.SzNameInTheEnd {}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
public class Super {
|
||||
|
||||
static void foo(CharSequence o) {
|
||||
((<caret>) o)
|
||||
}
|
||||
|
||||
}
|
||||
+6
@@ -74,4 +74,10 @@ public class FooImpl extends Foo {
|
||||
|
||||
void testCastInstanceofedQualifierInExpressionLambda() { doTest() }
|
||||
|
||||
void testPreferCastExpressionSuperTypes() {
|
||||
myFixture.addClass('package nonImported; public interface SzNameInTheEnd {}')
|
||||
configureByTestName()
|
||||
myFixture.assertPreferredCompletionItems 0, 'SString', 'SzNameInTheEnd', 'Serializable'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
@@ -1250,4 +1250,9 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase {
|
||||
}
|
||||
|
||||
public void testQualifyOuterClassCall() { doActionTest(); }
|
||||
|
||||
public void testExpressionSubtypesInCast() {
|
||||
configureByTestName();
|
||||
myFixture.assertPreferredCompletionItems(0, "String", "StringBuffer", "StringBuilder");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user