mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-389301 [java-completion] JavaReflectionCompletionContributor -> JavaReflectionCompletionItemProvider
(part of) Convert reflection completion to ModCommand API GitOrigin-RevId: b3f9a197512ae7172a0498498cc0f3dd44ba5edb
This commit is contained in:
committed by
intellij-monorepo-bot
parent
13fc9b6b27
commit
177432ea88
+10
@@ -7,6 +7,7 @@ import com.intellij.codeInsight.completion.PrioritizedLookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.java.syntax.parser.JavaKeywords;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
@@ -413,6 +414,15 @@ public final class JavaReflectionReferenceUtil {
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static void shortenArgumentsClassReferences(@NotNull ModPsiUpdater context) {
|
||||
final PsiElement parameter = PsiUtilCore.getElementAtOffset(context.getPsiFile(), context.getCaretOffset());
|
||||
final PsiExpressionList parameterList = PsiTreeUtil.getParentOfType(parameter, PsiExpressionList.class);
|
||||
if (parameterList != null && parameterList.getParent() instanceof PsiMethodCallExpression) {
|
||||
JavaCodeStyleManager.getInstance(context.getProject()).shortenClassReferences(parameterList);
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static @NotNull LookupElement withPriority(@NotNull LookupElement lookupElement, boolean hasPriority) {
|
||||
return hasPriority ? lookupElement : PrioritizedLookupElement.withPriority(lookupElement, -1);
|
||||
|
||||
@@ -1146,8 +1146,8 @@
|
||||
<lookup.charFilter implementation="com.intellij.codeInsight.completion.JavaCharFilter" id="java"/>
|
||||
<completion.contributor language="JAVA" id="javaMethodHandle" order="last, before javaLegacy"
|
||||
implementationClass="com.intellij.psi.impl.source.resolve.reference.impl.JavaMethodHandleCompletionContributor"/>
|
||||
<completion.contributor language="JAVA" id="javaReflection" order="before javaLegacy, before javaClassReference"
|
||||
implementationClass="com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionCompletionContributor"/>
|
||||
<modcompletion.completionItemProvider language="JAVA" id="javaReflection"
|
||||
implementationClass="com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionCompletionItemProvider"/>
|
||||
<completion.contributor language="JAVA" id="javadoc" order="last, before javaLegacy, before wordCompletion"
|
||||
implementationClass="com.intellij.codeInsight.completion.JavaDocCompletionContributor"/>
|
||||
<completion.contributor language="JVM" id="javaClassName" order="last, before default"
|
||||
|
||||
+3
-1
@@ -52,6 +52,7 @@ import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNullByDefault;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -68,8 +69,9 @@ import static com.intellij.patterns.PsiJavaPatterns.psiExpressionStatement;
|
||||
import static com.intellij.patterns.StandardPatterns.or;
|
||||
import static com.intellij.patterns.StandardPatterns.string;
|
||||
|
||||
@ApiStatus.Internal
|
||||
@NotNullByDefault
|
||||
final class NonImportedClassProvider extends JavaModCompletionItemProvider {
|
||||
public final class NonImportedClassProvider extends JavaModCompletionItemProvider {
|
||||
private static final PsiJavaElementPattern.Capture<PsiElement> AFTER_NEW = psiElement().afterLeaf(JavaKeywords.NEW);
|
||||
private static final ElementPattern<PsiElement> IN_PERMITS_LIST = psiElement().afterLeaf(
|
||||
psiElement()
|
||||
|
||||
+72
-70
@@ -2,39 +2,42 @@
|
||||
package com.intellij.psi.impl.source.resolve.reference.impl;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.completion.CompletionContributor;
|
||||
import com.intellij.codeInsight.completion.CompletionParameters;
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet;
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.intellij.codeInsight.completion.InsertionContext;
|
||||
import com.intellij.codeInsight.completion.JavaClassNameCompletionContributor;
|
||||
import com.intellij.codeInsight.completion.JavaLookupElementBuilder;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.codeInsight.completion.JavaClassReferenceCompletionContributor;
|
||||
import com.intellij.java.completion.modcommand.NonImportedClassProvider;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.modcompletion.CommonCompletionItem;
|
||||
import com.intellij.modcompletion.ModCompletionItemPresentation;
|
||||
import com.intellij.modcompletion.ModCompletionItemProvider;
|
||||
import com.intellij.modcompletion.ModCompletionResult;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.MarkupText;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.patterns.PatternCondition;
|
||||
import com.intellij.psi.CommonClassNames;
|
||||
import com.intellij.psi.PsiAnnotation;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiClassObjectAccessExpression;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiExpressionList;
|
||||
import com.intellij.psi.PsiJavaCodeReferenceElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiMethodCallExpression;
|
||||
import com.intellij.psi.PsiPackage;
|
||||
import com.intellij.psi.PsiSubstitutor;
|
||||
import com.intellij.psi.PsiTypeElement;
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReference;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.psi.util.PsiFormatUtilBase;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.NotNullByDefault;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@@ -48,9 +51,9 @@ import static com.intellij.psi.impl.source.resolve.reference.impl.JavaReflection
|
||||
import static com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionReferenceUtil.getReflectiveClass;
|
||||
import static com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionReferenceUtil.isPublic;
|
||||
import static com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionReferenceUtil.shortenArgumentsClassReferences;
|
||||
import static com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionReferenceUtil.withPriority;
|
||||
|
||||
public final class JavaReflectionCompletionContributor extends CompletionContributor implements DumbAware {
|
||||
@NotNullByDefault
|
||||
public final class JavaReflectionCompletionItemProvider implements DumbAware, ModCompletionItemProvider {
|
||||
private static final String CONSTRUCTOR = "getConstructor";
|
||||
private static final String DECLARED_CONSTRUCTOR = "getDeclaredConstructor";
|
||||
private static final String ANNOTATION = "getAnnotation";
|
||||
@@ -86,25 +89,24 @@ public final class JavaReflectionCompletionContributor extends CompletionContrib
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) {
|
||||
if (parameters.getCompletionType() != CompletionType.BASIC) {
|
||||
return;
|
||||
}
|
||||
public void provideItems(CompletionContext parameters, ModCompletionResult sink) {
|
||||
if (parameters.isSmart()) return;
|
||||
|
||||
final PsiElement position = parameters.getPosition();
|
||||
if (!isInJavaContext(position)) {
|
||||
return;
|
||||
}
|
||||
if (!isInJavaContext(position)) return;
|
||||
|
||||
if (BEGINNING_OF_ANNOTATION_ARGUMENTS.accepts(position)) {
|
||||
addVariants(position, (psiClass, isDeclared) -> addAnnotationClasses(psiClass, isDeclared, result));
|
||||
addVariants(position, (psiClass, isDeclared) -> addAnnotationClasses(psiClass, isDeclared, sink));
|
||||
//TODO handle annotations on fields and methods
|
||||
}
|
||||
else if (BEGINNING_OF_CONSTRUCTOR_ARGUMENTS.accepts(position)) {
|
||||
addVariants(position, (psiClass, isDeclared) -> addConstructorParameterTypes(psiClass, isDeclared, result));
|
||||
addVariants(position, (psiClass, isDeclared) -> addConstructorParameterTypes(psiClass, isDeclared, sink));
|
||||
}
|
||||
else if (JavaReflectionReferenceContributor.Holder.CLASS_PATTERN.accepts(position.getParent())) {
|
||||
JavaClassNameCompletionContributor.addAllClasses(parameters, parameters.getInvocationCount() <= 1, result.getPrefixMatcher(), result);
|
||||
JavaClassReference ref = JavaClassReferenceCompletionContributor.findJavaClassReference(position.getContainingFile(), parameters.getOffset());
|
||||
if (ref != null && ref.getCompletionContext() instanceof PsiPackage psiPackage && psiPackage.getName() == null) {
|
||||
NonImportedClassProvider.addAllClasses(parameters, parameters.getInvocationCount() <= 1, parameters.matcher(), sink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,9 +123,9 @@ public final class JavaReflectionCompletionContributor extends CompletionContrib
|
||||
}
|
||||
}
|
||||
|
||||
private static void addAnnotationClasses(@NotNull PsiClass psiClass, boolean isDeclared, @NotNull CompletionResultSet result) {
|
||||
private static void addAnnotationClasses(PsiClass psiClass, boolean isDeclared, ModCompletionResult sink) {
|
||||
Set<PsiAnnotation> declaredAnnotations =
|
||||
isDeclared ? Collections.unmodifiableSet(new HashSet<>(Arrays.asList(AnnotationUtil.getAllAnnotations(psiClass, false, null, false)))) : null;
|
||||
isDeclared ? Set.of(AnnotationUtil.getAllAnnotations(psiClass, false, null, false)) : null;
|
||||
|
||||
PsiAnnotation[] annotations = AnnotationUtil.getAllAnnotations(psiClass, true, null, false);
|
||||
for (PsiAnnotation annotation : annotations) {
|
||||
@@ -132,75 +134,75 @@ public final class JavaReflectionCompletionContributor extends CompletionContrib
|
||||
PsiElement resolved = referenceElement.resolve();
|
||||
if (resolved instanceof PsiClass annotationClass) {
|
||||
String className = annotationClass.getName();
|
||||
if (className != null) {
|
||||
LookupElement lookupElement = LookupElementBuilder.createWithIcon(annotationClass)
|
||||
.withPresentableText(className + ".class")
|
||||
.withInsertHandler(JavaReflectionCompletionContributor::handleAnnotationClassInsertion);
|
||||
if (isDeclared) {
|
||||
lookupElement = withPriority(lookupElement, declaredAnnotations.contains(annotation));
|
||||
}
|
||||
result.addElement(lookupElement);
|
||||
String qualifiedName = annotationClass.getQualifiedName();
|
||||
if (className != null && qualifiedName != null) {
|
||||
CommonCompletionItem item = new CommonCompletionItem(className)
|
||||
.withObject(annotationClass)
|
||||
.withPresentation(new ModCompletionItemPresentation(MarkupText.plainText(className + ".class"))
|
||||
.withMainIcon(() -> annotationClass.getIcon(0)))
|
||||
.withAdditionalUpdater((_, updater) -> {
|
||||
handleParametersInsertion(updater, qualifiedName + ".class");
|
||||
})
|
||||
.withPriority(isDeclared && !declaredAnnotations.contains(annotation) ? -1 : 0);
|
||||
sink.accept(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addConstructorParameterTypes(@NotNull PsiClass psiClass, boolean isDeclared, @NotNull CompletionResultSet result) {
|
||||
private static void addConstructorParameterTypes(PsiClass psiClass, boolean isDeclared, ModCompletionResult result) {
|
||||
PsiMethod[] constructors = psiClass.getConstructors();
|
||||
for (PsiMethod constructor : constructors) {
|
||||
LookupElement lookupElement = JavaLookupElementBuilder.forMethod(constructor, PsiSubstitutor.EMPTY)
|
||||
.withInsertHandler(JavaReflectionCompletionContributor::handleConstructorSignatureInsertion);
|
||||
if (isDeclared) {
|
||||
lookupElement = withPriority(lookupElement, isPublic(constructor));
|
||||
}
|
||||
result.addElement(lookupElement);
|
||||
String lookupString = constructor.getName();
|
||||
String parametersPresentation = PsiFormatUtil.formatMethod(constructor, PsiSubstitutor.EMPTY,
|
||||
PsiFormatUtilBase.SHOW_PARAMETERS,
|
||||
PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_TYPE);
|
||||
String parametersText = getParameterTypesText(constructor);
|
||||
CommonCompletionItem item = new CommonCompletionItem(lookupString)
|
||||
.withObject(constructor)
|
||||
.withPresentation(new ModCompletionItemPresentation(
|
||||
MarkupText.plainText(constructor.getName() + parametersPresentation))
|
||||
.withMainIcon(() -> constructor.getIcon(Iconable.ICON_FLAG_VISIBILITY)))
|
||||
.withPriority(isDeclared && !isPublic(constructor) ? -1 : 0)
|
||||
.withAdditionalUpdater((_, updater) -> {
|
||||
if (parametersText != null) {
|
||||
handleParametersInsertion(updater, parametersText);
|
||||
}
|
||||
});
|
||||
result.accept(item);
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleAnnotationClassInsertion(@NotNull InsertionContext context, @NotNull LookupElement item) {
|
||||
Object object = item.getObject();
|
||||
if (object instanceof PsiClass) {
|
||||
String className = ((PsiClass)object).getQualifiedName();
|
||||
if (className != null) {
|
||||
handleParametersInsertion(context, className + ".class");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleConstructorSignatureInsertion(@NotNull InsertionContext context, @NotNull LookupElement item) {
|
||||
Object object = item.getObject();
|
||||
if (object instanceof PsiMethod) {
|
||||
String text = getParameterTypesText((PsiMethod)object);
|
||||
if (text != null) {
|
||||
handleParametersInsertion(context, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleParametersInsertion(@NotNull InsertionContext context, @NotNull String text) {
|
||||
PsiElement newElement = PsiUtilCore.getElementAtOffset(context.getFile(), context.getStartOffset());
|
||||
private static void handleParametersInsertion(ModPsiUpdater updater, String text) {
|
||||
PsiElement newElement = PsiUtilCore.getElementAtOffset(updater.getPsiFile(), updater.getCaretOffset());
|
||||
PsiExpressionList parameterList = PsiTreeUtil.getParentOfType(newElement, PsiExpressionList.class);
|
||||
if (parameterList != null) {
|
||||
final TextRange range = parameterList.getTextRange();
|
||||
context.getDocument().replaceString(range.getStartOffset(), range.getEndOffset(), "(" + text + ")");
|
||||
context.commitDocument();
|
||||
shortenArgumentsClassReferences(context);
|
||||
TextRange range = parameterList.getTextRange();
|
||||
Document document = updater.getDocument();
|
||||
document.replaceString(range.getStartOffset(), range.getEndOffset(), "(" + text + ")");
|
||||
PsiDocumentManager.getInstance(updater.getProject()).commitDocument(document);
|
||||
shortenArgumentsClassReferences(updater);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MethodDefinedInInterfacePatternCondition extends PatternCondition<PsiMethod> {
|
||||
private final String myInterfaceName;
|
||||
|
||||
MethodDefinedInInterfacePatternCondition(@NotNull String interfaceName) {
|
||||
MethodDefinedInInterfacePatternCondition(String interfaceName) {
|
||||
super("definedInInterface");
|
||||
myInterfaceName = interfaceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accepts(@NotNull PsiMethod method, ProcessingContext context) {
|
||||
public boolean accepts(PsiMethod method, ProcessingContext context) {
|
||||
PsiClass containingClass = method.getContainingClass();
|
||||
return InheritanceUtil.isInheritor(containingClass, false, myInterfaceName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -179,7 +179,7 @@ public class JavaReflectionCompletionTest extends LightFixtureCompletionTestCase
|
||||
public void testClassForNamePackages() {
|
||||
myFixture.addClass("package foo.bar.one; public class FirstClass {}");
|
||||
myFixture.addClass("package foo.bar.two; public class SecondClass {}");
|
||||
doTest(2, "FirstClass", "SecondClass", "one", "two");
|
||||
doTest(0, "one", "two");
|
||||
}
|
||||
|
||||
public void testClassForNameShortName() {
|
||||
|
||||
Reference in New Issue
Block a user