java completion: suggest same-named fields in scope, add Outer.this. qualifier for instance fields

GitOrigin-RevId: c80f4dc53b13c4851a9c9df9402198f1d1b48c26
This commit is contained in:
Peter Gromov
2020-06-12 15:38:19 +02:00
committed by intellij-monorepo-bot
parent 78c061ce43
commit 10fa53499e
7 changed files with 50 additions and 21 deletions

View File

@@ -563,7 +563,7 @@ public class JavaCompletionUtil {
return Collections.singletonList(item);
}
if (completion instanceof PsiVariable) {
return Collections.singletonList(new VariableLookupItem((PsiVariable)completion).setSubstitutor(substitutor));
return Collections.singletonList(new VariableLookupItem((PsiVariable)completion).setSubstitutor(substitutor).qualifyIfNeeded(reference));
}
if (completion instanceof PsiPackage) {
return Collections.singletonList(new PackageLookupItem((PsiPackage)completion, reference.getElement()));

View File

@@ -8,6 +8,7 @@ import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -18,12 +19,13 @@ import java.util.List;
*/
public class JavaStaticMemberProcessor extends StaticMemberProcessor {
private final PsiElement myOriginalPosition;
private final PsiElement myPosition;
public JavaStaticMemberProcessor(CompletionParameters parameters) {
super(parameters.getPosition());
myOriginalPosition = parameters.getOriginalPosition();
final PsiFile file = parameters.getPosition().getContainingFile();
myPosition = parameters.getPosition();
final PsiFile file = myPosition.getContainingFile();
if (file instanceof PsiJavaFile) {
final PsiImportList importList = ((PsiJavaFile)file).getImportList();
if (importList != null) {
@@ -60,7 +62,7 @@ public class JavaStaticMemberProcessor extends StaticMemberProcessor {
super.handleInsert(context);
}
});
}.qualifyIfNeeded(ObjectUtils.tryCast(myPosition.getParent(), PsiJavaCodeReferenceElement.class)));
}
private PsiReference createReferenceToMemberName(@NotNull PsiMember member) {

View File

@@ -20,6 +20,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ui.ColorIcon;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -35,6 +36,7 @@ public class VariableLookupItem extends LookupItem<PsiVariable> implements Typed
private final Color myColor;
private final String myTailText;
private PsiSubstitutor mySubstitutor = PsiSubstitutor.EMPTY;
private String myForcedQualifier;
public VariableLookupItem(PsiVariable var) {
super(var, var.getName());
@@ -46,15 +48,31 @@ public class VariableLookupItem extends LookupItem<PsiVariable> implements Typed
public VariableLookupItem(PsiField field, boolean shouldImport) {
super(field, field.getName());
myHelper = new MemberLookupHelper(field, field.getContainingClass(), shouldImport, false);
if (!shouldImport) {
for (String s : JavaCompletionUtil.getAllLookupStrings(field)) {
setLookupString(s); //todo set the string that will be inserted
}
}
myColor = getInitializerColor(field);
myTailText = getInitializerText(field);
}
@ApiStatus.Internal
public LookupElement qualifyIfNeeded(@Nullable PsiReference position) {
PsiVariable var = getObject();
if (var instanceof PsiField && !willBeImported() && shouldQualify((PsiField)var, position)) {
boolean isInstanceField = !var.hasModifierProperty(PsiModifier.STATIC);
PsiClass aClass = ((PsiField)var).getContainingClass();
String className = aClass == null ? null : aClass.getName();
if (className != null) {
String infix = isInstanceField ? ".this." : ".";
myForcedQualifier = className + infix;
for (String s : JavaCompletionUtil.getAllLookupStrings(aClass)) {
setLookupString(s + infix + var.getName());
}
if (isInstanceField) {
return PrioritizedLookupElement.withExplicitProximity(this, -1);
}
}
}
return this;
}
@Nullable
private String getInitializerText(PsiVariable var) {
if (myColor != null || !var.hasModifierProperty(PsiModifier.FINAL) || !var.hasModifierProperty(PsiModifier.STATIC)) return null;
@@ -124,12 +142,12 @@ public class VariableLookupItem extends LookupItem<PsiVariable> implements Typed
@Override
public void renderElement(LookupElementPresentation presentation) {
boolean qualify = myHelper != null && !myHelper.willBeImported();
boolean qualify = myHelper != null && !myHelper.willBeImported() || myForcedQualifier != null;
PsiVariable variable = getObject();
String name = variable.getName();
if (qualify && variable instanceof PsiField && ((PsiField)variable).getContainingClass() != null) {
name = ((PsiField)variable).getContainingClass().getName() + "." + name;
name = (myForcedQualifier != null ? myForcedQualifier : ((PsiField)variable).getContainingClass().getName() + ".") + name;
}
presentation.setItemText(name);
@@ -259,10 +277,13 @@ public class VariableLookupItem extends LookupItem<PsiVariable> implements Typed
return true;
}
PsiReference reference = context.getFile().findReferenceAt(context.getStartOffset());
if (reference instanceof PsiReferenceExpression && !((PsiReferenceExpression)reference).isQualified()) {
final PsiVariable target = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper()
.resolveReferencedVariable(field.getName(), (PsiElement)reference);
return shouldQualify(field, context.getFile().findReferenceAt(context.getTailOffset() - 1));
}
private static boolean shouldQualify(@NotNull PsiField field, @Nullable PsiReference context) {
if (context instanceof PsiReferenceExpression && !((PsiReferenceExpression)context).isQualified()) {
PsiVariable target = JavaPsiFacade.getInstance(context.getElement().getProject()).getResolveHelper()
.resolveReferencedVariable(field.getName(), (PsiElement)context);
return !field.getManager().areElementsEquivalent(target, CompletionUtil.getOriginalOrSelf(field));
}
return false;
@@ -278,7 +299,7 @@ public class VariableLookupItem extends LookupItem<PsiVariable> implements Typed
PsiClass containingClass = field.getContainingClass();
if (containingClass != null && containingClass.getName() != null) {
context.getDocument().insertString(context.getStartOffset(), ".");
context.getDocument().insertString(context.getStartOffset(), field.hasModifierProperty(PsiModifier.STATIC) ? "." : ".this.");
JavaCompletionUtil.insertClassReference(containingClass, file, context.getStartOffset());
PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument());
}

View File

@@ -12,6 +12,7 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Consumer;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -133,7 +134,8 @@ public class JavaMembersGetter extends MembersGetter {
return null;
}
return new VariableLookupItem(field, false);
return new VariableLookupItem(field, false)
.qualifyIfNeeded(ObjectUtils.tryCast(myParameters.getPosition().getParent(), PsiJavaCodeReferenceElement.class));
}
@Override

View File

@@ -15,6 +15,7 @@
*/
package com.intellij.codeInsight.completion.scope;
import com.intellij.codeInsight.completion.CompletionUtilCoreImpl;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Trinity;
import com.intellij.psi.*;
@@ -70,7 +71,7 @@ public class CompletionElement{
myQualifierText);
}
if (myElement instanceof PsiVariable) {
return "#" + ((PsiVariable)myElement).getName();
return CompletionUtilCoreImpl.getOriginalOrSelf((PsiElement)myElement);
}
return null;

View File

@@ -5,7 +5,7 @@ public class Beda {
int ffid;
{
ffid<caret>
Beda.this.ffid<caret>
}
}
}

View File

@@ -605,7 +605,7 @@ public class ListUtils {
void testDoubleConstant() throws Throwable {
configure()
assertStringItems("XFOO")
assertStringItems("Intf.XFOO", "XFOO")
}
void testNotOnlyKeywordsInsideSwitch() throws Throwable {
@@ -862,7 +862,10 @@ public class ListUtils {
}
void testSameNamedVariableInNestedClasses() throws Throwable {
doTest()
configure()
myFixture.assertPreferredCompletionItems 0, "ffid", "Beda.this.ffid"
selectItem(myItems[1])
checkResult()
}
void testHonorUnderscoreInPrefix() throws Throwable {