[java-completion] JavaNoVariantsDelegator: avoid redundant chains of nested classes

Fixes IDEA-334398 Code completion of nested types suggests confusing levels of nesting

GitOrigin-RevId: 206fc2b9f4a6501720b7bc95e79d981b20450823
This commit is contained in:
Tagir Valeev
2023-10-18 12:18:35 +02:00
committed by intellij-monorepo-bot
parent 3f492d6bec
commit db535a5a08
4 changed files with 42 additions and 1 deletions

View File

@@ -28,6 +28,7 @@ public class JavaChainLookupElement extends LookupElementDecorator<LookupElement
public JavaChainLookupElement(LookupElement qualifier, LookupElement main) {
this(qualifier, main, ".");
}
public JavaChainLookupElement(LookupElement qualifier, LookupElement main, String separator) {
super(main);
myQualifier = qualifier;
@@ -186,4 +187,22 @@ public class JavaChainLookupElement extends LookupElementDecorator<LookupElement
}
return ((PsiVariable) object).getType();
}
/**
* @param base base item to create a chain
* @param item nested item
* @return false if the chain looks redundant, and it's better not to suggest it.
*/
static boolean isReasonableChain(LookupElement base, LookupElement item) {
PsiElement baseElement = base.getPsiElement();
PsiElement itemElement = item.getPsiElement();
if (baseElement == null || itemElement == null) return true;
if (baseElement.equals(itemElement)) return false;
if (itemElement instanceof PsiMember member) {
PsiClass itemClass = member.getContainingClass();
if (itemClass == null || itemClass.equals(baseElement)) return true;
if (PsiTreeUtil.isAncestor(itemClass, baseElement, true)) return false;
}
return true;
}
}

View File

@@ -203,7 +203,9 @@ public class JavaNoVariantsDelegator extends CompletionContributor implements Du
if (ref != null) {
for (LookupElement item : JavaSmartCompletionContributor.completeReference(position, ref, filter, true, true, parameters,
result.getPrefixMatcher())) {
LookupElement chain = highlighter.highlightIfNeeded(null, new JavaChainLookupElement(base, item, separator), item.getObject());
if (!JavaChainLookupElement.isReasonableChain(base, item)) continue;
JavaChainLookupElement chainedElement = new JavaChainLookupElement(base, item, separator);
LookupElement chain = highlighter.highlightIfNeeded(null, chainedElement, item.getObject());
if (JavaCompletionContributor.shouldInsertSemicolon(position)) {
chain = TailTypeDecorator.withTail(chain, TailTypes.semicolonType());
}

View File

@@ -0,0 +1,13 @@
sealed interface AddUserError {
final class NameIsEmpty implements AddUserError {}
final class NameIsTooLong implements AddUserError {}
}
class Test {
public static AddUserError TryAddUser() {
return new AUE.<caret>
}
}

View File

@@ -36,4 +36,11 @@ public class NormalSealedCompletionTest extends NormalCompletionTestCase {
@NeedsIndex.Full(reason = "AllClassesGetter.processJavaClasses uses indices, see 0a72bf3a7baa7dc1550e8e4308431d78eb753eb6 commit")
public void testSealedPermitsInner() { doTest("\n"); }
@NeedsIndex.Full
public void testNestedClassCompletion() {
configure();
myFixture.completeBasic();
myFixture.assertPreferredCompletionItems(0, "AddUserError.NameIsEmpty", "AddUserError.NameIsTooLong");
}
}