mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
java smart completion: prefer all items with exactly expected type, not only classes (IDEA-169490)
This commit is contained in:
@@ -298,9 +298,9 @@ public class JavaCompletionSorting {
|
||||
private final CompletionParameters myParameters;
|
||||
private final CompletionLocation myLocation;
|
||||
|
||||
public PreferDefaultTypeWeigher(ExpectedTypeInfo[] expectedTypes, CompletionParameters parameters) {
|
||||
public PreferDefaultTypeWeigher(@NotNull ExpectedTypeInfo[] expectedTypes, CompletionParameters parameters) {
|
||||
super("defaultType");
|
||||
myExpectedTypes = expectedTypes == null ? null : ContainerUtil.map2Array(expectedTypes, ExpectedTypeInfo.class, info -> {
|
||||
myExpectedTypes = ContainerUtil.map2Array(expectedTypes, ExpectedTypeInfo.class, info -> {
|
||||
PsiType type = removeClassWildcard(info.getType());
|
||||
PsiType defaultType = removeClassWildcard(info.getDefaultType());
|
||||
if (type == info.getType() && defaultType == info.getDefaultType()) {
|
||||
@@ -328,25 +328,16 @@ public class JavaCompletionSorting {
|
||||
}
|
||||
}
|
||||
|
||||
if (myExpectedTypes == null) return MyResult.normal;
|
||||
|
||||
PsiType itemType = JavaCompletionUtil.getLookupElementType(item);
|
||||
if (itemType == null || !itemType.isValid()) return MyResult.normal;
|
||||
|
||||
if (object instanceof PsiClass) {
|
||||
for (final ExpectedTypeInfo info : myExpectedTypes) {
|
||||
if (TypeConversionUtil.erasure(info.getType().getDeepComponentType()).equals(TypeConversionUtil.erasure(itemType))) {
|
||||
return AbstractExpectedTypeSkipper.skips(item, myLocation) ? MyResult.expectedNoSelect : MyResult.exactlyExpected;
|
||||
}
|
||||
}
|
||||
if (isExactlyExpected(item, itemType)) {
|
||||
return AbstractExpectedTypeSkipper.skips(item, myLocation) ? MyResult.expectedNoSelect : MyResult.exactlyExpected;
|
||||
}
|
||||
|
||||
if (itemType == null) return MyResult.normal;
|
||||
|
||||
for (final ExpectedTypeInfo expectedInfo : myExpectedTypes) {
|
||||
final PsiType defaultType = expectedInfo.getDefaultType();
|
||||
final PsiType expectedType = expectedInfo.getType();
|
||||
if (!expectedType.isValid()) {
|
||||
return MyResult.normal;
|
||||
}
|
||||
|
||||
if (defaultType != expectedType) {
|
||||
if (defaultType.equals(itemType)) {
|
||||
@@ -365,6 +356,27 @@ public class JavaCompletionSorting {
|
||||
return MyResult.normal;
|
||||
}
|
||||
|
||||
private boolean isExactlyExpected(@NotNull LookupElement item, @Nullable PsiType itemType) {
|
||||
if (JavaCompletionUtil.SUPER_METHOD_PARAMETERS.get(item) != null) {
|
||||
return true;
|
||||
}
|
||||
if (itemType == null || itemType.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || hasUnboundTypeArguments(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ContainerUtil.exists(myExpectedTypes, info -> box(info.getType().getDeepComponentType()).equals(box(itemType)));
|
||||
}
|
||||
|
||||
private static boolean hasUnboundTypeArguments(@NotNull LookupElement item) {
|
||||
JavaMethodCallElement call = item.as(JavaMethodCallElement.CLASS_CONDITION_KEY);
|
||||
return call != null && !call.getInferenceSubstitutor().equals(PsiSubstitutor.EMPTY);
|
||||
}
|
||||
|
||||
private PsiType box(PsiType expectedType) {
|
||||
PsiClassType boxed = expectedType instanceof PsiPrimitiveType ? ((PsiPrimitiveType)expectedType).getBoxedType(myParameters.getPosition()) : null;
|
||||
return boxed != null ? boxed : expectedType;
|
||||
}
|
||||
|
||||
private static PsiType removeClassWildcard(PsiType type) {
|
||||
if (type instanceof PsiClassType) {
|
||||
final PsiClass psiClass = ((PsiClassType)type).resolve();
|
||||
|
||||
+7
-4
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiType;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -52,15 +53,13 @@ public class JavaMethodMergingContributor extends CompletionContributor {
|
||||
return AutoCompletionDecision.SHOW_LOOKUP;
|
||||
}
|
||||
|
||||
final PsiMethod method = (PsiMethod)o;
|
||||
final JavaChainLookupElement chain = item.as(JavaChainLookupElement.CLASS_CONDITION_KEY);
|
||||
final String name = method.getName() + "#" + (chain == null ? "" : chain.getQualifier().getLookupString());
|
||||
String name = joinLookupStrings(item);
|
||||
if (commonName != null && !commonName.equals(name)) {
|
||||
return AutoCompletionDecision.SHOW_LOOKUP;
|
||||
}
|
||||
|
||||
commonName = name;
|
||||
allMethods.add(method);
|
||||
allMethods.add((PsiMethod)o);
|
||||
}
|
||||
|
||||
for (LookupElement item : items) {
|
||||
@@ -73,6 +72,10 @@ public class JavaMethodMergingContributor extends CompletionContributor {
|
||||
return super.handleAutoCompletionPossibility(context);
|
||||
}
|
||||
|
||||
public static String joinLookupStrings(LookupElement item) {
|
||||
return StreamEx.of(item.getAllLookupStrings()).sorted().joining("#");
|
||||
}
|
||||
|
||||
public static LookupElement findBestOverload(LookupElement[] items) {
|
||||
LookupElement best = items[0];
|
||||
for (int i = 1; i < items.length; i++) {
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
class Map {
|
||||
static class Builder {}
|
||||
static Builder builder() {}
|
||||
}
|
||||
class BiMap extends Map {
|
||||
static class Builder extends Map.Builder {}
|
||||
static Builder builder() {}
|
||||
}
|
||||
|
||||
class Usage {
|
||||
Map.Builder b = bui<caret>
|
||||
}
|
||||
+10
-3
@@ -33,7 +33,7 @@ class SmartTypeCompletionOrderingTest extends CompletionSortingTestCase {
|
||||
}
|
||||
|
||||
void testJComponentAdd() throws Throwable {
|
||||
checkPreferredItems(0, "name", "b", "fooBean239", "foo", "this")
|
||||
checkPreferredItems(0, "name", "b", "fooBean239", "foo")
|
||||
}
|
||||
|
||||
void testJComponentAddNew() throws Throwable {
|
||||
@@ -323,7 +323,7 @@ class SmartTypeCompletionOrderingTest extends CompletionSortingTestCase {
|
||||
}
|
||||
|
||||
void testPreferLocalOverThis() {
|
||||
checkPreferredItems 0, 'value', 'this', 'hashCode'
|
||||
checkPreferredItems 0, 'value', 'hashCode', 'this'
|
||||
}
|
||||
|
||||
void testGetLogger() {
|
||||
@@ -339,7 +339,7 @@ class SmartTypeCompletionOrderingTest extends CompletionSortingTestCase {
|
||||
}
|
||||
|
||||
void testPreferLocalWildcardClassOverObject() {
|
||||
checkPreferredItems 0, 'type', 'Object.class'
|
||||
checkPreferredItems 0, 'type', 'forName', 'forName', 'Object.class'
|
||||
}
|
||||
|
||||
void testPreferStringsInStringConcatenation() {
|
||||
@@ -361,6 +361,13 @@ class SmartTypeCompletionOrderingTest extends CompletionSortingTestCase {
|
||||
assert lookup.items.size() == 2
|
||||
}
|
||||
|
||||
void testPreferGlobalMembersReturningExpectedType() {
|
||||
configureNoCompletion(getTestName(false) + ".java")
|
||||
def items = myFixture.complete(CompletionType.SMART, 2)
|
||||
assert LookupElementPresentation.renderElement(items[0]).itemText == 'Map.builder'
|
||||
assert LookupElementPresentation.renderElement(items[1]).itemText == 'BiMap.builder'
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return JavaTestUtil.getRelativeJavaTestDataPath() + BASE_PATH
|
||||
|
||||
+1
-1
@@ -830,7 +830,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase {
|
||||
}
|
||||
public void testNoClassLiteral() throws Exception {
|
||||
doActionTest();
|
||||
assertStringItems("Object.class", "getClass", "forName", "forName");
|
||||
assertStringItems("forName", "forName", "Object.class", "getClass");
|
||||
}
|
||||
|
||||
public void testClassLiteralInAnno2() throws Throwable {
|
||||
|
||||
+2
-3
@@ -51,9 +51,8 @@ public class GrMethodMergingContributor extends CompletionContributor {
|
||||
return AutoCompletionDecision.SHOW_LOOKUP;
|
||||
}
|
||||
|
||||
final PsiMethod method = (PsiMethod)o;
|
||||
final JavaChainLookupElement chain = item.as(JavaChainLookupElement.CLASS_CONDITION_KEY);
|
||||
final String name = method.getName() + "#" + (chain == null ? "" : chain.getQualifier().getLookupString());
|
||||
PsiMethod method = (PsiMethod)o;
|
||||
String name = JavaMethodMergingContributor.joinLookupStrings(item);
|
||||
|
||||
if (commonName != null && !commonName.equals(name)) {
|
||||
return AutoCompletionDecision.SHOW_LOOKUP;
|
||||
|
||||
Reference in New Issue
Block a user