mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-128948 Smart type completion should propose generic parameter type
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
package com.intellij.codeInsight;
|
||||
|
||||
import com.intellij.codeInsight.completion.AllClassesGetter;
|
||||
import com.intellij.codeInsight.completion.CompletionUtil;
|
||||
import com.intellij.codeInsight.completion.JavaCompletionUtil;
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher;
|
||||
import com.intellij.lang.Language;
|
||||
@@ -33,21 +34,21 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.psi.util.proximity.PsiProximityComparator;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.FilteredQuery;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.Query;
|
||||
import com.intellij.psi.util.FileTypeUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class CodeInsightUtil {
|
||||
@Nullable
|
||||
@@ -283,6 +284,11 @@ public class CodeInsightUtil {
|
||||
|
||||
final Processor<PsiClass> inheritorsProcessor =
|
||||
createInheritorsProcessor(context, baseType, arrayDim, getRawSubtypes, consumer, baseClass, baseSubstitutor);
|
||||
|
||||
addContextTypeArguments(context, baseType, inheritorsProcessor);
|
||||
|
||||
if (baseClass.hasModifierProperty(PsiModifier.FINAL)) return;
|
||||
|
||||
if (matcher.getPrefix().length() > 2) {
|
||||
AllClassesGetter.processJavaClasses(matcher, context.getProject(), scope, new Processor<PsiClass>() {
|
||||
@Override
|
||||
@@ -307,6 +313,30 @@ public class CodeInsightUtil {
|
||||
|
||||
}
|
||||
|
||||
private static void addContextTypeArguments(final PsiElement context,
|
||||
final PsiClassType baseType,
|
||||
final Processor<PsiClass> inheritorsProcessor) {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Set<String> usedNames = ContainerUtil.newHashSet();
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.getProject());
|
||||
PsiElement each = context;
|
||||
while (true) {
|
||||
PsiTypeParameterListOwner typed = PsiTreeUtil.getParentOfType(each, PsiTypeParameterListOwner.class);
|
||||
if (typed == null) break;
|
||||
for (PsiTypeParameter parameter : typed.getTypeParameters()) {
|
||||
if (baseType.isAssignableFrom(factory.createType(parameter)) && usedNames.add(parameter.getName())) {
|
||||
inheritorsProcessor.process(CompletionUtil.getOriginalOrSelf(parameter));
|
||||
}
|
||||
}
|
||||
|
||||
each = typed;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Processor<PsiClass> createInheritorsProcessor(final PsiElement context, final PsiClassType baseType,
|
||||
final int arrayDim,
|
||||
final boolean getRawSubtypes,
|
||||
|
||||
@@ -278,10 +278,12 @@ public class JavaCompletionSorting {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Comparable weigh(@NotNull LookupElement item) {
|
||||
public MyResult weigh(@NotNull LookupElement item) {
|
||||
final Object object = item.getObject();
|
||||
|
||||
if (object instanceof PsiClass) {
|
||||
if (object instanceof PsiTypeParameter) return MyResult.typeParameter;
|
||||
|
||||
if (myTypeParameter != null && object.equals(PsiUtil.resolveClassInType(TypeConversionUtil.typeParameterErasure(myTypeParameter)))) {
|
||||
return MyResult.exactlyExpected;
|
||||
}
|
||||
@@ -340,6 +342,7 @@ public class JavaCompletionSorting {
|
||||
|
||||
private enum MyResult {
|
||||
expectedNoSelect,
|
||||
typeParameter,
|
||||
exactlyDefault,
|
||||
ofDefaultType,
|
||||
exactlyExpected,
|
||||
|
||||
@@ -229,10 +229,7 @@ public class JavaInheritorsGetter extends CompletionProvider<CompletionParameter
|
||||
|
||||
//long
|
||||
for (final PsiClassType type : expectedClassTypes) {
|
||||
final PsiClass psiClass = type.resolve();
|
||||
if (psiClass != null && !psiClass.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
CodeInsightUtil.processSubTypes(type, parameters.getPosition(), false, matcher, consumer);
|
||||
}
|
||||
CodeInsightUtil.processSubTypes(type, parameters.getPosition(), false, matcher, consumer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -158,8 +158,9 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
@Override
|
||||
public void consume(PsiType type) {
|
||||
final PsiClass psiClass = PsiUtil.resolveClassInType(type);
|
||||
if (psiClass == null) return;
|
||||
if (psiClass == null || psiClass instanceof PsiTypeParameter) return;
|
||||
|
||||
//noinspection SuspiciousMethodCalls
|
||||
if (expectedClassTypes.contains(type)) return;
|
||||
|
||||
result.addElement(createInstanceofLookupElement(psiClass, parameterizedTypes));
|
||||
|
||||
@@ -307,3 +307,4 @@ public interface JVMElementFactory {
|
||||
*/
|
||||
boolean isValidLocalVariableName(@NotNull String name);
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class StringEx<T extends String> {
|
||||
}
|
||||
class Outer<T extends String> {
|
||||
static class CompletionTest<T extends String> {
|
||||
private StringEx<<caret>> myString;
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -777,6 +777,11 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase {
|
||||
myFixture.assertPreferredCompletionItems(0, "i", "z", "zz", "i, z, zz");
|
||||
}
|
||||
|
||||
public void testSuggestTypeParametersInTypeArgumentList() {
|
||||
configureByTestName();
|
||||
myFixture.assertPreferredCompletionItems(0, "T", "String");
|
||||
}
|
||||
|
||||
public void testWrongAnonymous() throws Throwable {
|
||||
configureByTestName();
|
||||
select();
|
||||
|
||||
Reference in New Issue
Block a user