mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IJPL-214795 [java-completion] BringVariableIntoScope locals completion as ModCommands
GitOrigin-RevId: d6750b86a53467d23c7f862bb1ef538ef33677cb
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9786f35b95
commit
c44c7f65d7
@@ -1196,6 +1196,7 @@
|
||||
<modcompletion.completionItemProvider language="JAVA" implementationClass="com.intellij.codeInsight.completion.modcompletion.AnnotationAttributeItemProvider"/>
|
||||
<modcompletion.completionItemProvider language="JAVA" implementationClass="com.intellij.codeInsight.completion.modcompletion.GenerateMemberItemProvider"/>
|
||||
<modcompletion.completionItemProvider language="JAVA" implementationClass="com.intellij.codeInsight.completion.modcompletion.ReferenceItemProvider"/>
|
||||
<modcompletion.completionItemProvider language="JAVA" implementationClass="com.intellij.codeInsight.completion.modcompletion.InnerScopeVariableItemProvider"/>
|
||||
|
||||
<completion.skip implementation="com.intellij.codeInsight.completion.AbstractExpectedTypeSkipper" id="skipAbstract"/>
|
||||
<completion.skip implementation="com.intellij.codeInsight.completion.DeprecatedSkipper" id="skipDeprecated"/>
|
||||
|
||||
+7
-53
@@ -75,8 +75,6 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.psiutils.JavaDeprecationUtils;
|
||||
import com.siyeh.ig.psiutils.TypeUtils;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
|
||||
import one.util.streamex.EntryStream;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.util.*;
|
||||
@@ -897,7 +895,7 @@ public final class JavaCompletionContributor extends CompletionContributor imple
|
||||
}
|
||||
|
||||
if (parameters.getInvocationCount() > 0) {
|
||||
items.addAll(getInnerScopeVariables(parameters, position));
|
||||
items.addAll(getInnerScopeVariables(position));
|
||||
}
|
||||
|
||||
if (ref.getQualifier() instanceof PsiExpression qualifierExpression &&
|
||||
@@ -945,56 +943,12 @@ public final class JavaCompletionContributor extends CompletionContributor imple
|
||||
return null;
|
||||
}
|
||||
|
||||
private static @Unmodifiable Collection<LookupElement> getInnerScopeVariables(CompletionParameters parameters, PsiElement position) {
|
||||
PsiElement container = BringVariableIntoScopeFix.getContainer(position);
|
||||
if (container == null) return Collections.emptyList();
|
||||
Map<String, Optional<PsiLocalVariable>> variableMap =
|
||||
EntryStream.ofTree(container, (depth, element) -> depth > 2 ? null : StreamEx.of(element.getChildren()))
|
||||
.values()
|
||||
.select(PsiCodeBlock.class)
|
||||
.flatArray(PsiCodeBlock::getStatements)
|
||||
.select(PsiDeclarationStatement.class)
|
||||
.flatArray(PsiDeclarationStatement::getDeclaredElements)
|
||||
.select(PsiLocalVariable.class)
|
||||
.remove(var -> PsiTreeUtil.isAncestor(var, position, true))
|
||||
.toMap(PsiLocalVariable::getName, Optional::of, (v1, v2) -> Optional.empty());
|
||||
PsiResolveHelper helper = JavaPsiFacade.getInstance(parameters.getOriginalFile().getProject()).getResolveHelper();
|
||||
variableMap.values().removeAll(Collections.singleton(Optional.<PsiLocalVariable>empty()));
|
||||
variableMap.keySet().removeIf(name -> helper.resolveReferencedVariable(name, position) != null);
|
||||
int offset = position.getTextRange().getStartOffset();
|
||||
variableMap.values().removeIf(v -> v.orElseThrow().getTextRange().getStartOffset() > offset);
|
||||
if (variableMap.isEmpty()) return Collections.emptyList();
|
||||
return ContainerUtil.map(variableMap.values(), optVar -> {
|
||||
assert optVar.isPresent();
|
||||
PsiLocalVariable variable = optVar.get();
|
||||
String place = getPlace(variable);
|
||||
return new VariableLookupItem(variable, JavaBundle.message("completion.inner.scope.tail.text", place)).setPriority(-1);
|
||||
});
|
||||
}
|
||||
|
||||
private static @Nls @NotNull String getPlace(PsiLocalVariable variable) {
|
||||
String place = JavaBundle.message("completion.inner.scope");
|
||||
PsiCodeBlock block = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class);
|
||||
PsiElement statement = block == null ? null : block.getParent();
|
||||
if (statement instanceof PsiTryStatement) {
|
||||
place = ((PsiTryStatement)statement).getFinallyBlock() == block ? JavaKeywords.TRY + "-" + JavaKeywords.FINALLY : JavaKeywords.TRY;
|
||||
}
|
||||
else if (statement instanceof PsiCatchSection) {
|
||||
place = JavaKeywords.CATCH;
|
||||
}
|
||||
else if (statement instanceof PsiSynchronizedStatement) {
|
||||
place = JavaKeywords.SYNCHRONIZED;
|
||||
}
|
||||
else if (statement instanceof PsiBlockStatement) {
|
||||
PsiElement parent = statement.getParent();
|
||||
if (parent instanceof PsiWhileStatement) {
|
||||
place = JavaKeywords.WHILE;
|
||||
}
|
||||
else if (parent instanceof PsiIfStatement) {
|
||||
place = ((PsiIfStatement)parent).getThenBranch() == statement ? JavaKeywords.IF + "-then" : JavaKeywords.IF + "-" + JavaKeywords.ELSE;
|
||||
}
|
||||
}
|
||||
return place;
|
||||
private static @Unmodifiable Collection<LookupElement> getInnerScopeVariables(PsiElement position) {
|
||||
List<PsiLocalVariable> list = BringVariableIntoScopeFix.findInnerScopeVariables(position);
|
||||
return ContainerUtil.map(list, variable ->
|
||||
new VariableLookupItem(
|
||||
variable, JavaBundle.message("completion.inner.scope.tail.text", BringVariableIntoScopeFix.getVariableDeclarationPlace(variable)))
|
||||
.setPriority(-1));
|
||||
}
|
||||
|
||||
private static @NotNull List<LookupElement> completePermitsListReference(@NotNull CompletionParameters parameters,
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.completion.modcompletion;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.BringVariableIntoScopeFix;
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.modcompletion.ModCompletionItem;
|
||||
import com.intellij.modcompletion.ModCompletionItemProvider;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiLocalVariable;
|
||||
import org.jetbrains.annotations.NotNullByDefault;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@NotNullByDefault
|
||||
final class InnerScopeVariableItemProvider implements ModCompletionItemProvider {
|
||||
@Override
|
||||
public void provideItems(CompletionContext context, Consumer<ModCompletionItem> sink) {
|
||||
if (context.invocationCount() < 1) return;
|
||||
PsiElement position = context.getPosition();
|
||||
for (PsiLocalVariable variable : BringVariableIntoScopeFix.findInnerScopeVariables(position)) {
|
||||
sink.accept(new VariableCompletionItem(
|
||||
variable, JavaBundle.message("completion.inner.scope.tail.text", BringVariableIntoScopeFix.getVariableDeclarationPlace(variable))));
|
||||
}
|
||||
}
|
||||
}
|
||||
-4
@@ -150,10 +150,6 @@ final class ReferenceItemProvider implements ModCompletionItemProvider {
|
||||
sink.accept(firstArrayElement);
|
||||
}
|
||||
});
|
||||
|
||||
//if (context.invocationCount() > 0) {
|
||||
// items.addAll(getInnerScopeVariables(parameters, position));
|
||||
//}
|
||||
}
|
||||
|
||||
private static @Nullable CommonCompletionItem accessFirstElement(ModCompletionItem item) {
|
||||
|
||||
+1
-1
@@ -142,12 +142,12 @@ final class VariableCompletionItem extends PsiUpdateCompletionItem<PsiVariable>
|
||||
if (toDelete != null && toDelete.isValid()) {
|
||||
document.deleteString(toDelete.getStartOffset(), toDelete.getEndOffset());
|
||||
}
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document);
|
||||
}
|
||||
else if (VariableLookupItem.shouldQualify(field, file.findReferenceAt(updater.getCaretOffset() - 1))) {
|
||||
qualifyFieldReference(actionContext.offset(), updater, field);
|
||||
}
|
||||
}
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document);
|
||||
|
||||
PsiReferenceExpression ref = PsiTreeUtil.findElementOfClassAtOffset(file, updater.getCaretOffset() - 1, PsiReferenceExpression.class, false);
|
||||
if (ref != null) {
|
||||
|
||||
+63
-2
@@ -5,6 +5,8 @@ import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInsight.intention.PriorityAction;
|
||||
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
|
||||
import com.intellij.codeInspection.util.IntentionName;
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.java.syntax.parser.JavaKeywords;
|
||||
import com.intellij.modcommand.ActionContext;
|
||||
import com.intellij.modcommand.ModCommand;
|
||||
import com.intellij.modcommand.ModCommandAction;
|
||||
@@ -16,11 +18,14 @@ import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.controlFlow.ControlFlowUtil;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import one.util.streamex.EntryStream;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
public final class BringVariableIntoScopeFix implements ModCommandAction {
|
||||
private static final Logger LOG = Logger.getInstance(BringVariableIntoScopeFix.class);
|
||||
@@ -182,4 +187,60 @@ public final class BringVariableIntoScopeFix implements ModCommandAction {
|
||||
PsiExpression initializer = factory.createExpressionFromText(init, variable);
|
||||
variable.setInitializer(initializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param position PSI position to find the inner scope variables
|
||||
* @return list of variables declared in the scopes nested to the position scope
|
||||
*/
|
||||
public static @NotNull List<PsiLocalVariable> findInnerScopeVariables(PsiElement position) {
|
||||
PsiElement container = getContainer(position);
|
||||
Map<String, Optional<PsiLocalVariable>> variableMap = Map.of();
|
||||
if (container != null) {
|
||||
variableMap = EntryStream.ofTree(container, (depth, element) -> depth > 2 ? null : StreamEx.of(element.getChildren()))
|
||||
.values()
|
||||
.select(PsiCodeBlock.class)
|
||||
.flatArray(PsiCodeBlock::getStatements)
|
||||
.select(PsiDeclarationStatement.class)
|
||||
.flatArray(PsiDeclarationStatement::getDeclaredElements)
|
||||
.select(PsiLocalVariable.class)
|
||||
.remove(var -> PsiTreeUtil.isAncestor(var, position, true))
|
||||
.toMap(PsiLocalVariable::getName, Optional::of, (v1, v2) -> Optional.empty());
|
||||
PsiResolveHelper helper = JavaPsiFacade.getInstance(container.getProject()).getResolveHelper();
|
||||
variableMap.values().removeAll(Collections.singleton(Optional.<PsiLocalVariable>empty()));
|
||||
variableMap.keySet().removeIf(name -> helper.resolveReferencedVariable(name, position) != null);
|
||||
int offset = position.getTextRange().getStartOffset();
|
||||
variableMap.values().removeIf(v -> v.orElseThrow().getTextRange().getStartOffset() > offset);
|
||||
}
|
||||
List<PsiLocalVariable> list = ContainerUtil.map(variableMap.values(), Optional::get);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param variable variable to describe its location
|
||||
* @return the human-readable description of variable's declaration place, useful for variable brought into the scope.
|
||||
*/
|
||||
public static @Nls @NotNull String getVariableDeclarationPlace(PsiLocalVariable variable) {
|
||||
String place = JavaBundle.message("completion.inner.scope");
|
||||
PsiCodeBlock block = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class);
|
||||
PsiElement statement = block == null ? null : block.getParent();
|
||||
if (statement instanceof PsiTryStatement) {
|
||||
place = ((PsiTryStatement)statement).getFinallyBlock() == block ? JavaKeywords.TRY + "-" + JavaKeywords.FINALLY : JavaKeywords.TRY;
|
||||
}
|
||||
else if (statement instanceof PsiCatchSection) {
|
||||
place = JavaKeywords.CATCH;
|
||||
}
|
||||
else if (statement instanceof PsiSynchronizedStatement) {
|
||||
place = JavaKeywords.SYNCHRONIZED;
|
||||
}
|
||||
else if (statement instanceof PsiBlockStatement) {
|
||||
PsiElement parent = statement.getParent();
|
||||
if (parent instanceof PsiWhileStatement) {
|
||||
place = JavaKeywords.WHILE;
|
||||
}
|
||||
else if (parent instanceof PsiIfStatement ifStatement) {
|
||||
place = ifStatement.getThenBranch() == statement ? JavaKeywords.IF + "-then" : JavaKeywords.IF + "-" + JavaKeywords.ELSE;
|
||||
}
|
||||
}
|
||||
return place;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user