From 53e2c49b27009cb0047b9dd18b7a7d343f41b9c0 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 26 Aug 2014 13:38:46 +0200 Subject: [PATCH] IDEA-128948 Smart type completion should propose generic parameter type --- .../intellij/codeInsight/CodeInsightUtil.java | 42 ++++++++++++++++--- .../completion/JavaCompletionSorting.java | 5 ++- .../completion/JavaInheritorsGetter.java | 5 +-- .../JavaSmartCompletionContributor.java | 3 +- .../com/intellij/psi/JVMElementFactory.java | 1 + ...ggestTypeParametersInTypeArgumentList.java | 8 ++++ .../completion/SmartTypeCompletionTest.java | 5 +++ 7 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/SuggestTypeParametersInTypeArgumentList.java diff --git a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java index 9f2b486164ce..ca7c26dbc811 100644 --- a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java @@ -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 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() { @Override @@ -307,6 +313,30 @@ public class CodeInsightUtil { } + private static void addContextTypeArguments(final PsiElement context, + final PsiClassType baseType, + final Processor inheritorsProcessor) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + Set 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 createInheritorsProcessor(final PsiElement context, final PsiClassType baseType, final int arrayDim, final boolean getRawSubtypes, diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java index d144a67fcb69..5a18a4b42826 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java @@ -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, diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java index 1a14010ec834..a503de4d93a5 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java @@ -229,10 +229,7 @@ public class JavaInheritorsGetter extends CompletionProvider { +} +class Outer { + static class CompletionTest { + private StringEx<> myString; + } +} + diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index 5153f19fe94a..967de28820e8 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -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();