mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
java class reference: search subtypes only on smart completion, work as usual (and fast) on basic (IDEA-92934)
This commit is contained in:
+20
-7
@@ -15,11 +15,15 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiPackage;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReference;
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReferenceSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -31,24 +35,33 @@ public class JavaClassReferenceCompletionContributor extends CompletionContribut
|
||||
public void duringCompletion(@NotNull CompletionInitializationContext context) {
|
||||
JavaClassReference reference = findJavaClassReference(context.getFile(), context.getStartOffset());
|
||||
if (reference != null && reference.getExtendClassNames() != null) {
|
||||
final PsiReference[] references = reference.getJavaClassReferenceSet().getReferences();
|
||||
final PsiReference last = references[references.length - 1];
|
||||
context.setReplacementOffset(last.getRangeInElement().getEndOffset() + last.getElement().getTextRange().getStartOffset());
|
||||
JavaClassReferenceSet set = reference.getJavaClassReferenceSet();
|
||||
context.setReplacementOffset(set.getRangeInElement().getEndOffset() + set.getElement().getTextRange().getStartOffset());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) {
|
||||
if (parameters.getCompletionType() == CompletionType.SMART) {
|
||||
return;
|
||||
}
|
||||
|
||||
PsiElement position = parameters.getPosition();
|
||||
JavaClassReference reference = findJavaClassReference(position.getContainingFile(), parameters.getOffset());
|
||||
if (reference == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] extendClassNames = reference.getExtendClassNames();
|
||||
PsiElement context = reference.getCompletionContext();
|
||||
if (extendClassNames != null && context instanceof PsiPackage) {
|
||||
if (parameters.getCompletionType() == CompletionType.SMART) {
|
||||
JavaClassReferenceSet set = reference.getJavaClassReferenceSet();
|
||||
int setStart = set.getRangeInElement().getStartOffset() + set.getElement().getTextRange().getStartOffset();
|
||||
String fullPrefix = parameters.getPosition().getContainingFile().getText().substring(setStart, parameters.getOffset());
|
||||
reference.processSubclassVariants((PsiPackage)context, extendClassNames, result.withPrefixMatcher(fullPrefix));
|
||||
return;
|
||||
}
|
||||
result.addLookupAdvertisement("Press " + getActionShortcut(IdeActions.ACTION_SMART_TYPE_COMPLETION) + " to see inheritors of " +
|
||||
StringUtil.join(extendClassNames, ", "));
|
||||
}
|
||||
|
||||
if (parameters.getCompletionType() == CompletionType.CLASS_NAME) {
|
||||
JavaClassNameCompletionContributor.addAllClasses(parameters, result);
|
||||
}
|
||||
|
||||
+21
-31
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.source.resolve.reference.impl.providers;
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet;
|
||||
import com.intellij.codeInsight.completion.JavaLookupElementBuilder;
|
||||
import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor;
|
||||
import com.intellij.codeInsight.daemon.QuickFixProvider;
|
||||
@@ -23,6 +24,7 @@ import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixActionRegistrarImpl;
|
||||
import com.intellij.codeInsight.daemon.quickFix.CreateClassOrPackageFix;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.LocalQuickFixProvider;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
@@ -55,7 +57,10 @@ import com.intellij.util.text.CharArrayUtil;
|
||||
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.Map;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
@@ -225,15 +230,8 @@ public class JavaClassReference extends GenericReference implements PsiJavaRefer
|
||||
@Override
|
||||
@NotNull
|
||||
public Object[] getVariants() {
|
||||
PsiElement context = getContext();
|
||||
if (context == null) {
|
||||
context = JavaPsiFacade.getInstance(getElement().getProject()).findPackage("");
|
||||
}
|
||||
PsiElement context = getCompletionContext();
|
||||
if (context instanceof PsiPackage) {
|
||||
final String[] extendClasses = getExtendClassNames();
|
||||
if (extendClasses != null) {
|
||||
return getSubclassVariants((PsiPackage)context, extendClasses);
|
||||
}
|
||||
return processPackage((PsiPackage)context);
|
||||
}
|
||||
if (context instanceof PsiClass) {
|
||||
@@ -257,6 +255,12 @@ public class JavaClassReference extends GenericReference implements PsiJavaRefer
|
||||
return ArrayUtil.EMPTY_OBJECT_ARRAY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiElement getCompletionContext() {
|
||||
PsiElement context = getContext();
|
||||
return context == null ? JavaPsiFacade.getInstance(getElement().getProject()).findPackage("") : context;
|
||||
}
|
||||
|
||||
public String[] getExtendClassNames() {
|
||||
return JavaClassReferenceProvider.EXTEND_CLASS_NAMES.getValue(getOptions());
|
||||
}
|
||||
@@ -508,8 +512,7 @@ public class JavaClassReference extends GenericReference implements PsiJavaRefer
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Object[] getSubclassVariants(@NotNull PsiPackage context, @NotNull String[] extendClasses) {
|
||||
HashSet<Object> lookups = new HashSet<Object>();
|
||||
public void processSubclassVariants(@NotNull PsiPackage context, @NotNull String[] extendClasses, CompletionResultSet result) {
|
||||
GlobalSearchScope packageScope = PackageScope.packageScope(context, true);
|
||||
GlobalSearchScope scope = myJavaClassReferenceSet.getProvider().getScope(getElement().getProject());
|
||||
if (scope != null) {
|
||||
@@ -529,35 +532,22 @@ public class JavaClassReference extends GenericReference implements PsiJavaRefer
|
||||
// add itself
|
||||
if (packageScope.contains(extendClass.getContainingFile().getVirtualFile())) {
|
||||
if (isClassAccepted(extendClass, classKind, instantiatable, concrete, notInterface, notEnum)) {
|
||||
ContainerUtil.addIfNotNull(createSubclassLookupValue(context, extendClass), lookups);
|
||||
result.addElement(createSubclassLookupValue(extendClass, extendClassName));
|
||||
}
|
||||
}
|
||||
for (final PsiClass clazz : ClassInheritorsSearch.search(extendClass, packageScope, true)) {
|
||||
if (isClassAccepted(clazz, classKind, instantiatable, concrete, notInterface, notEnum)) {
|
||||
ContainerUtil.addIfNotNull(createSubclassLookupValue(context, clazz), lookups);
|
||||
String qname = clazz.getQualifiedName();
|
||||
if (qname != null && isClassAccepted(clazz, classKind, instantiatable, concrete, notInterface, notEnum)) {
|
||||
result.addElement(createSubclassLookupValue(clazz, qname));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return lookups.toArray();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Object createSubclassLookupValue(@NotNull final PsiPackage context, @NotNull final PsiClass clazz) {
|
||||
final String qname = clazz.getQualifiedName();
|
||||
if (qname == null) return null;
|
||||
|
||||
String name = qname;
|
||||
final String pack = context.getQualifiedName();
|
||||
if (pack.length() > 0) {
|
||||
if (name.startsWith(pack)) {
|
||||
name = name.substring(pack.length() + 1);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return JavaLookupElementBuilder.forClass(clazz, name, true).withLookupString(qname).withLookupString(clazz.getName());
|
||||
@NotNull
|
||||
private static LookupElementBuilder createSubclassLookupValue(@NotNull final PsiClass clazz, @NotNull String qname) {
|
||||
return JavaLookupElementBuilder.forClass(clazz, qname, true).withPresentableText(StringUtil.getShortName(qname));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
@@ -59,6 +59,11 @@ public class JavaClassReferenceSet {
|
||||
return myProvider;
|
||||
}
|
||||
|
||||
public TextRange getRangeInElement() {
|
||||
PsiReference[] references = getReferences();
|
||||
return new TextRange(references[0].getRangeInElement().getStartOffset(), references[references.length - 1].getRangeInElement().getEndOffset());
|
||||
}
|
||||
|
||||
private void reparse(String str, PsiElement element, final boolean isStaticImport, JavaClassReferenceSet context) {
|
||||
myElement = element;
|
||||
myContext = context;
|
||||
|
||||
@@ -69,4 +69,6 @@ public interface Lookup {
|
||||
PrefixMatcher itemMatcher(@NotNull LookupElement item);
|
||||
|
||||
boolean isSelectionTouched();
|
||||
|
||||
List<String> getAdvertisements();
|
||||
}
|
||||
|
||||
@@ -138,4 +138,7 @@ public class Advertiser {
|
||||
return myComponent;
|
||||
}
|
||||
|
||||
public List<String> getAdvertisements() {
|
||||
return myTexts;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1158,6 +1158,11 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
return mySelectionTouched;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAdvertisements() {
|
||||
return myAdComponent.getAdvertisements();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide(){
|
||||
hideLookup(true);
|
||||
@@ -1290,7 +1295,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
}
|
||||
|
||||
public void addAdvertisement(@NotNull final String text) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!myDisposed) {
|
||||
@@ -1301,7 +1306,12 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
}
|
||||
}
|
||||
}
|
||||
}, myModalityState);
|
||||
};
|
||||
if (ApplicationManager.getApplication().isDispatchThread()) {
|
||||
runnable.run();
|
||||
} else {
|
||||
ApplicationManager.getApplication().invokeLater(runnable, myModalityState);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLookupDisposed() {
|
||||
|
||||
+3
@@ -19,6 +19,7 @@ package com.intellij.testFramework.fixtures;
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.intellij.codeInspection.InspectionToolProvider;
|
||||
@@ -361,6 +362,8 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
|
||||
|
||||
void finishLookup();
|
||||
|
||||
Lookup getLookup();
|
||||
|
||||
@NotNull
|
||||
PsiElement getElementAtCaret();
|
||||
|
||||
|
||||
+1
-1
@@ -1879,7 +1879,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
|
||||
}
|
||||
}
|
||||
|
||||
private LookupImpl getLookup() {
|
||||
public LookupImpl getLookup() {
|
||||
return (LookupImpl)LookupManager.getActiveLookup(myEditor);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<idea-plugin>
|
||||
<actions>
|
||||
<action class="foo.<caret>"/>
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
@@ -0,0 +1,5 @@
|
||||
<idea-plugin>
|
||||
<actions>
|
||||
<action class="foo.<caret>"/>
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
+39
-30
@@ -13,28 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.idea.devkit.codeInsight;
|
||||
|
||||
import com.intellij.codeInsight.TargetElementUtilBase;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.openapi.application.PluginPathManager;
|
||||
import com.intellij.openapi.application.Result;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.psi.ElementDescriptionUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
|
||||
import com.intellij.testFramework.fixtures.TempDirTestFixture;
|
||||
import com.intellij.usageView.UsageViewNodeTextLocation;
|
||||
import com.intellij.usageView.UsageViewTypeLocation;
|
||||
import com.intellij.util.xml.DeprecatedClassUsageInspection;
|
||||
import org.jetbrains.idea.devkit.inspections.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
package org.jetbrains.idea.devkit.codeInsight
|
||||
import com.intellij.codeInsight.TargetElementUtilBase
|
||||
import com.intellij.codeInsight.completion.CompletionType
|
||||
import com.intellij.codeInspection.LocalInspectionTool
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.PluginPathManager
|
||||
import com.intellij.psi.ElementDescriptionUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase
|
||||
import com.intellij.testFramework.fixtures.TempDirTestFixture
|
||||
import com.intellij.usageView.UsageViewNodeTextLocation
|
||||
import com.intellij.usageView.UsageViewTypeLocation
|
||||
import com.intellij.util.xml.DeprecatedClassUsageInspection
|
||||
import org.jetbrains.idea.devkit.inspections.*
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
@@ -124,14 +118,8 @@ public class PluginXmlFunctionalTest extends JavaCodeInsightFixtureTestCase {
|
||||
}
|
||||
|
||||
private void addPluginXml(final String root, final String text) throws IOException {
|
||||
myTempDirFixture.createFile(root +
|
||||
"/META-INF/plugin.xml", text);
|
||||
new WriteCommandAction(getProject()) {
|
||||
@Override
|
||||
protected void run(Result result) throws Throwable {
|
||||
PsiTestUtil.addSourceContentToRoots(myModule, myTempDirFixture.getFile(root));
|
||||
}
|
||||
}.execute();
|
||||
myTempDirFixture.createFile(root + "/META-INF/plugin.xml", text);
|
||||
ApplicationManager.application.runWriteAction { PsiTestUtil.addSourceContentToRoots(myModule, myTempDirFixture.getFile(root)) }
|
||||
}
|
||||
|
||||
public void testNoWordCompletionInClassPlaces() throws Throwable {
|
||||
@@ -152,6 +140,27 @@ public class PluginXmlFunctionalTest extends JavaCodeInsightFixtureTestCase {
|
||||
myFixture.checkResultByFile(getTestName(false) + "_after.xml");
|
||||
}
|
||||
|
||||
public void testShowPackagesInActionClass() {
|
||||
myFixture.addClass("package com.intellij.openapi.actionSystem; public class AnAction { }");
|
||||
myFixture.addClass("package foo.bar; public class BarAction extends com.intellij.openapi.actionSystem.AnAction { }");
|
||||
myFixture.addClass("package foo.goo; public class GooAction extends com.intellij.openapi.actionSystem.AnAction { }");
|
||||
myFixture.configureByFile(getTestName(false) + ".xml");
|
||||
myFixture.completeBasic();
|
||||
assert myFixture.lookupElementStrings == ['bar', 'goo']
|
||||
assert myFixture.lookup.advertisements.find { it.contains('to see inheritors of com.intellij.openapi.actionSystem.AnAction') }
|
||||
}
|
||||
|
||||
public void testShowAnActionInheritorsOnSmartCompletion() {
|
||||
myFixture.addClass("package com.intellij.openapi.actionSystem; public class AnAction { }");
|
||||
myFixture.addClass("package foo.bar; public class BarAction extends com.intellij.openapi.actionSystem.AnAction { }");
|
||||
myFixture.addClass("package foo.goo; public class GooAction extends com.intellij.openapi.actionSystem.AnAction { }");
|
||||
myFixture.addClass("package another.goo; public class AnotherAction extends com.intellij.openapi.actionSystem.AnAction { }");
|
||||
myFixture.configureByFile(getTestName(false) + ".xml");
|
||||
myFixture.complete(CompletionType.SMART);
|
||||
assert myFixture.lookupElementStrings == ['foo.bar.BarAction', 'foo.goo.GooAction']
|
||||
assert !myFixture.lookup.advertisements.find { it.contains('to see inheritors of com.intellij.openapi.actionSystem.AnAction') }
|
||||
}
|
||||
|
||||
public void testDeprecatedExtensionAttribute() {
|
||||
myFixture.enableInspections(DeprecatedClassUsageInspection.class);
|
||||
myFixture.testHighlighting("deprecatedExtensionAttribute.xml", "MyExtBean.java");
|
||||
Reference in New Issue
Block a user