From 140b91e13a991c25297fbf365c6e8d11e1038965 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 12 Dec 2013 16:50:13 +0400 Subject: [PATCH] method references: smart completion to filter by return type --- .../JavaSmartCompletionContributor.java | 11 ++++ .../MethodReferenceCompletionProvider.java | 61 +++++++++++++++++++ .../FilteredMethodReference-out.java | 13 ++++ .../smartType/FilteredMethodReference.java | 13 ++++ ...ailableInLambdaPositionAfterQualifier.java | 2 +- .../completion/SmartType18CompletionTest.java | 4 ++ 6 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/completion/MethodReferenceCompletionProvider.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/FilteredMethodReference-out.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/FilteredMethodReference.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index a72a49c46168..bcfa4f0d55cd 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -100,6 +100,16 @@ public class JavaSmartCompletionContributor extends CompletionContributor { LambdaUtil.isValidLambdaContext(rulezzRef.getParent()); }}); + static final PsiElementPattern.Capture METHOD_REFERENCE = psiElement().with(new PatternCondition("METHOD_REFERENCE_CONTEXT") { + @Override + public boolean accepts(@NotNull PsiElement element, ProcessingContext context) { + final PsiElement rulezzRef = element.getParent(); + return rulezzRef != null && + rulezzRef instanceof PsiMethodReferenceExpression && + ((PsiReferenceExpression)rulezzRef).getQualifier() != element && + LambdaUtil.isValidLambdaContext(rulezzRef.getParent()); + }}); + @Nullable private static ElementFilter getReferenceFilter(PsiElement element) { //throw new foo @@ -322,6 +332,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { }); extend(CompletionType.SMART, LAMBDA, new LambdaCompletionProvider()); + extend(CompletionType.SMART, METHOD_REFERENCE, new MethodReferenceCompletionProvider()); } private static void addExpectedTypeMembers(CompletionParameters params, diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/MethodReferenceCompletionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/MethodReferenceCompletionProvider.java new file mode 100644 index 000000000000..dbd2fc8ef3c6 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/MethodReferenceCompletionProvider.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2013 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. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.ExpectedTypeInfo; +import com.intellij.codeInsight.ExpectedTypeInfoImpl; +import com.intellij.codeInsight.TailType; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.psi.*; +import com.intellij.psi.filters.ElementFilter; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.Consumer; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; + +public class MethodReferenceCompletionProvider extends CompletionProvider { + @Override + protected void addCompletions(@NotNull CompletionParameters parameters, + ProcessingContext context, + @NotNull final CompletionResultSet result) { + if (!PsiUtil.isLanguageLevel8OrHigher(parameters.getOriginalFile())) return; + final ExpectedTypeInfo[] expectedTypes = JavaSmartCompletionContributor.getExpectedTypes(parameters); + for (ExpectedTypeInfo expectedType : expectedTypes) { + final PsiType defaultType = expectedType.getDefaultType(); + if (LambdaHighlightingUtil.checkInterfaceFunctional(defaultType) == null) { + final PsiType returnType = LambdaUtil.getFunctionalInterfaceReturnType(defaultType); + if (returnType != null) { + final ExpectedTypeInfoImpl typeInfo = + new ExpectedTypeInfoImpl(returnType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, returnType, TailType.UNKNOWN, null, + ExpectedTypeInfoImpl.NULL); + Consumer noTypeCheck = new Consumer() { + @Override + public void consume(final LookupElement lookupElement) { + result.addElement(lookupElement); + } + }; + + final Runnable runnable = ReferenceExpressionCompletionContributor + .fillCompletionVariants(new JavaSmartCompletionParameters(parameters, typeInfo), noTypeCheck); + if (runnable != null) { + runnable.run(); + } + } + } + } + } +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/FilteredMethodReference-out.java b/java/java-tests/testData/codeInsight/completion/smartType/FilteredMethodReference-out.java new file mode 100644 index 000000000000..2086ad1bbf39 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/FilteredMethodReference-out.java @@ -0,0 +1,13 @@ +class Test { + interface I { + int foo(); + } + + static int aa() { + return 0; + } + + { + I i = Test::aa + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/FilteredMethodReference.java b/java/java-tests/testData/codeInsight/completion/smartType/FilteredMethodReference.java new file mode 100644 index 000000000000..f49bb50c7bbb --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/FilteredMethodReference.java @@ -0,0 +1,13 @@ +class Test { + interface I { + int foo(); + } + + static int aa() { + return 0; + } + + { + I i = Test:: + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NotAvailableInLambdaPositionAfterQualifier.java b/java/java-tests/testData/codeInsight/completion/smartType/NotAvailableInLambdaPositionAfterQualifier.java index 261bf0a7ddba..f7523c61078d 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/NotAvailableInLambdaPositionAfterQualifier.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/NotAvailableInLambdaPositionAfterQualifier.java @@ -4,6 +4,6 @@ class Test { } { - I i = Test:: + I i = Unknown:: } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java index 24b2d43ed22b..72840250b795 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java @@ -73,6 +73,10 @@ public class SmartType18CompletionTest extends LightFixtureCompletionTestCase { doTest(); } + public void testFilteredMethodReference() throws Exception { + doTest(); + } + public void testNotAvailableInLambdaPositionAfterQualifier() throws Exception { configureByFile("/" + getTestName(false) + ".java"); assertNotNull(myItems);