java method reference completion: don't show both ::Object and ::new, consistently process class and array types

GitOrigin-RevId: c9483bf7e47db78792a02856bd6988d5f63467f5
This commit is contained in:
Peter Gromov
2020-06-12 21:32:07 +03:00
committed by intellij-monorepo-bot
parent 8c31a5c569
commit faca9a8b19
8 changed files with 92 additions and 20 deletions
@@ -78,11 +78,11 @@ public class LambdaHighlightingUtil {
}
public static boolean insertSemicolonAfter(@NotNull PsiLambdaExpression lambdaExpression) {
return lambdaExpression.getBody() instanceof PsiCodeBlock || !insertSemicolon(lambdaExpression.getParent());
return lambdaExpression.getBody() instanceof PsiCodeBlock || insertSemicolon(lambdaExpression.getParent());
}
public static boolean insertSemicolon(PsiElement parent) {
return parent instanceof PsiExpressionList || parent instanceof PsiExpression;
return !(parent instanceof PsiExpressionList) && !(parent instanceof PsiExpression);
}
public static String checkInterfaceFunctional(@NotNull PsiType functionalInterfaceType) {
@@ -543,7 +543,7 @@ public class JavaCompletionUtil {
}
if (reference instanceof PsiMethodReferenceExpression && completion instanceof PsiMethod && ((PsiMethod)completion).isConstructor()) {
return Collections.singletonList(JavaLookupElementBuilder.forMethod((PsiMethod)completion, "new", PsiSubstitutor.EMPTY, null));
return Collections.singletonList(createConstructorReferenceItem((PsiMethod)completion, (PsiMethodReferenceExpression)reference));
}
PsiSubstitutor substitutor = completionElement.getSubstitutor();
@@ -572,6 +572,15 @@ public class JavaCompletionUtil {
return Collections.singletonList(LookupItemUtil.objectToLookupItem(completion));
}
@NotNull
private static LookupElement createConstructorReferenceItem(@NotNull PsiMethod completion, @NotNull PsiMethodReferenceExpression context) {
LookupElementBuilder item = JavaLookupElementBuilder
.forMethod(completion, "new", PsiSubstitutor.EMPTY, null)
.withPresentableText("new")
.bold();
return LambdaHighlightingUtil.insertSemicolon(context.getParent()) ? TailTypeDecorator.withTail(item, TailType.SEMICOLON) : item;
}
public static boolean hasAccessibleConstructor(@NotNull PsiType type, @NotNull PsiElement place) {
if (type instanceof PsiArrayType) return true;
@@ -825,7 +834,7 @@ public class JavaCompletionUtil {
boolean insertAdditionalSemicolon = true;
PsiElement leaf = context.getFile().findElementAt(context.getStartOffset());
PsiElement composite = leaf == null ? null : leaf.getParent();
if (composite instanceof PsiMethodReferenceExpression && LambdaHighlightingUtil.insertSemicolon(composite.getParent())) {
if (composite instanceof PsiMethodReferenceExpression && !LambdaHighlightingUtil.insertSemicolon(composite.getParent())) {
insertAdditionalSemicolon = false;
}
else if (composite instanceof PsiReferenceExpression) {
@@ -836,7 +845,7 @@ public class JavaCompletionUtil {
if (parent instanceof PsiLambdaExpression && !LambdaHighlightingUtil.insertSemicolonAfter((PsiLambdaExpression)parent)) {
insertAdditionalSemicolon = false;
}
if (parent instanceof PsiMethodReferenceExpression && LambdaHighlightingUtil.insertSemicolon(parent.getParent())) {
if (parent instanceof PsiMethodReferenceExpression && !LambdaHighlightingUtil.insertSemicolon(parent.getParent())) {
insertAdditionalSemicolon = false;
}
}
@@ -7,7 +7,6 @@ import com.intellij.codeInsight.TailTypes;
import com.intellij.codeInsight.completion.util.CompletionStyleUtil;
import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingFeature;
import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil;
import com.intellij.codeInsight.lookup.*;
import com.intellij.openapi.util.Conditions;
import com.intellij.patterns.ElementPattern;
@@ -36,7 +35,6 @@ import static com.intellij.psi.SyntaxTraverser.psiApi;
public class JavaKeywordCompletion {
public static final ElementPattern<PsiElement> AFTER_DOT = psiElement().afterLeaf(".");
private static final ElementPattern<PsiElement> AFTER_DOUBLE_COLON = psiElement().afterLeaf("::");
static final ElementPattern<PsiElement> VARIABLE_AFTER_FINAL = psiElement().afterLeaf(PsiKeyword.FINAL).inside(PsiDeclarationStatement.class);
@@ -228,6 +226,10 @@ public class JavaKeywordCompletion {
return;
}
if (psiElement().afterLeaf("::").accepts(myPosition)) {
return;
}
PsiFile file = myPosition.getContainingFile();
if (PsiJavaModule.MODULE_INFO_FILE.equals(file.getName()) && PsiUtil.isLanguageLevel9OrHigher(file)) {
addModuleKeywords();
@@ -427,15 +429,6 @@ public class JavaKeywordCompletion {
}
private void addExpressionKeywords(boolean statementPosition) {
if (AFTER_DOUBLE_COLON.accepts(myPosition)) {
PsiMethodReferenceExpression parent = PsiTreeUtil.getParentOfType(myPosition, PsiMethodReferenceExpression.class);
if (parent != null && canUseConstructorReference(parent)) {
TailType tail = !LambdaHighlightingUtil.insertSemicolon(parent.getParent()) ? TailType.SEMICOLON : TailType.NONE;
addKeyword(new OverridableSpace(createKeyword(PsiKeyword.NEW), tail));
}
return;
}
if (isExpressionPosition(myPosition)) {
PsiElement parent = myPosition.getParent();
PsiElement grandParent = parent == null ? null : parent.getParent();
@@ -709,7 +702,6 @@ public class JavaKeywordCompletion {
static void addPrimitiveTypes(Consumer<? super LookupElement> result, PsiElement position, JavaCompletionSession session) {
if (AFTER_DOT.accepts(position) ||
AFTER_DOUBLE_COLON.accepts(position) ||
psiElement().inside(psiAnnotation()).accepts(position) && !expectsClassLiteral(position)) {
return;
}
@@ -211,7 +211,12 @@ public class JavaCompletionProcessor implements PsiScopeProcessor, ElementClassH
}
public boolean satisfies(@NotNull PsiElement element, @NotNull ResolveState state) {
final String name = PsiUtilCore.getName(element);
String name = PsiUtilCore.getName(element);
if (element instanceof PsiMethod &&
((PsiMethod)element).isConstructor() &&
myElement.getParent() instanceof PsiMethodReferenceExpression) {
name = PsiKeyword.NEW;
}
if (name != null && StringUtil.isNotEmpty(name) && myMatcher.value(name)) {
if (myFilter.isClassAcceptable(element.getClass()) && myFilter.isAcceptable(new CandidateInfo(element, state.get(PsiSubstitutor.KEY)), myElement)) {
return true;
@@ -161,13 +161,17 @@ public class PsiScopesUtil {
// Composite expression
PsiElement target = null;
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
if (qualifier instanceof PsiExpression || qualifier instanceof PsiJavaCodeReferenceElement) {
if (qualifier instanceof PsiExpression || qualifier instanceof PsiJavaCodeReferenceElement || qualifier instanceof PsiTypeElement) {
PsiType type = null;
if (qualifier instanceof PsiExpression) {
type = ((PsiExpression)qualifier).getType();
assert type == null || type.isValid() : type.getClass() + "; " + qualifier;
processTypeDeclarations(type, ref, processor);
}
else if (qualifier instanceof PsiTypeElement) {
type = ((PsiTypeElement)qualifier).getType();
processTypeDeclarations(type, ref, processor);
}
if (type == null && qualifier instanceof PsiJavaCodeReferenceElement) {
// In case of class qualifier
@@ -0,0 +1,23 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class Foo {
interface I { Object m(); }
void test() {
I i = Foo[]::n<caret>
}
}
@@ -0,0 +1,23 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class Foo {
interface I { Object m(); }
void test() {
I i = Foo[]::new;<caret>
}
}
@@ -4,8 +4,10 @@ package com.intellij.java.codeInsight.completion;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.completion.LightCompletionTestCase;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import org.jetbrains.annotations.NotNull;
@@ -93,7 +95,21 @@ public class KeywordCompletionTest extends LightCompletionTestCase {
public void testDefaultInAnno() { doTest(); }
public void testNullInMethodCall() { doTest(); }
public void testNullInMethodCall2() { doTest(); }
public void testNewInMethodRefs() { doTest(1, "new", "null", "true", "false"); }
public void testNewInMethodRefs() {
doTest(1, "new", "null", "true", "false");
assertEquals("new", LookupElementPresentation.renderElement(myItems[0]).getItemText());
selectItem(myItems[0]);
checkResultByTestName();
}
public void testNewInMethodRefsArray() {
doTest(1, "new", "null", "true", "false");
assertEquals("Object", assertInstanceOf(myItems[0].getPsiElement(), PsiMethod.class).getName());
selectItem(myItems[0]);
checkResultByTestName();
}
public void testNewInCast() { doTest(2, "new", "null", "true", "false"); }
public void testNewInNegation() { doTest(1, "new", "null", "true", "false"); }
public void testSpaceAfterInstanceof() { doTest(); }