From 16d92229b15854a8761711765cabca5950fe1794 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 13 Aug 2015 18:12:49 +0200 Subject: [PATCH] IDEA-143807 Incorrect smart completion inside a cast --- .../completion/JavaCompletionContributor.java | 25 +++++++++++++---- .../completion/SmartCastProvider.java | 28 +++++++++++++++---- .../PreferCastTypesHavingSpecifiedMethod.java | 17 +++++++++++ ...ggestCastReturnTypeByCalledMethod-out.java | 9 ++++++ .../SuggestCastReturnTypeByCalledMethod.java | 9 ++++++ .../NormalCompletionOrderingTest.groovy | 4 +++ .../completion/SmartTypeCompletionTest.java | 2 ++ 7 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/normalSorting/PreferCastTypesHavingSpecifiedMethod.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/SuggestCastReturnTypeByCalledMethod-out.java create mode 100644 java/java-tests/testData/codeInsight/completion/smartType/SuggestCastReturnTypeByCalledMethod.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 2b2c35859f9d..b2ec45cf117e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -238,16 +238,22 @@ public class JavaCompletionContributor extends CompletionContributor { MethodReturnTypeProvider.addProbableReturnTypes(parameters, new Consumer() { @Override public void consume(LookupElement element) { - PsiType type = assertNotNull(element.as(PsiTypeLookupItem.CLASS_CONDITION_KEY)).getPsiType(); - PsiClass aClass = type instanceof PsiClassType && ((PsiClassType)type).getParameterCount() == 0 ? ((PsiClassType)type).resolve() : null; - if (aClass != null) { - inheritors.registerClass(aClass); - } + registerClassFromTypeElement(element, inheritors); result.addElement(element); } }); } + if (SmartCastProvider.shouldSuggestCast(parameters)) { + SmartCastProvider.addCastVariants(parameters, new Consumer() { + @Override + public void consume(LookupElement element) { + registerClassFromTypeElement(element, inheritors); + result.addElement(PrioritizedLookupElement.withPriority(element, 1)); + } + }); + } + PsiElement parent = position.getParent(); if (parent instanceof PsiReferenceExpression) { final List expected = Arrays.asList(ExpectedTypesProvider.getExpectedTypes((PsiExpression)parent, true)); @@ -285,6 +291,15 @@ public class JavaCompletionContributor extends CompletionContributor { result.stopHere(); } + private void registerClassFromTypeElement(LookupElement element, InheritorsHolder inheritors) { + PsiType type = assertNotNull(element.as(PsiTypeLookupItem.CLASS_CONDITION_KEY)).getPsiType(); + PsiClass aClass = + type instanceof PsiClassType && ((PsiClassType)type).getParameterCount() == 0 ? ((PsiClassType)type).resolve() : null; + if (aClass != null) { + inheritors.registerClass(aClass); + } + } + private static void addExpressionVariants(@NotNull CompletionParameters parameters, PsiElement position, CompletionResultSet result) { if (JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(position) && !JavaCompletionData.AFTER_DOT.accepts(position) && !SmartCastProvider.shouldSuggestCast(parameters)) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java index 135f641f229b..5ac5057d8113 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCastProvider.java @@ -1,6 +1,7 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.ExpectedTypeInfo; +import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.completion.simple.RParenthTailType; import com.intellij.codeInsight.lookup.AutoCompletionPolicy; @@ -17,6 +18,7 @@ import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.impl.source.tree.java.PsiEmptyExpressionImpl; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.Consumer; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,12 +48,26 @@ class SmartCastProvider extends CompletionProvider { @Override protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { + addCastVariants(parameters, result); + } + + static void addCastVariants(@NotNull CompletionParameters parameters, @NotNull Consumer result) { if (!shouldSuggestCast(parameters)) return; - + PsiElement position = parameters.getPosition(); PsiElement parenthesisOwner = getParenthesisOwner(position); - final boolean overwrite = parenthesisOwner instanceof PsiTypeCastExpression; - + final boolean insideCast = parenthesisOwner instanceof PsiTypeCastExpression; + + if (insideCast) { + PsiElement parent = parenthesisOwner.getParent(); + if (parent instanceof PsiParenthesizedExpression && parent.getParent() instanceof PsiReferenceExpression) { + for (ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes((PsiParenthesizedExpression)parent, false)) { + result.consume(PsiTypeLookupItem.createLookupItem(info.getType(), parent)); + } + return; + } + } + for (final ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { PsiType type = info.getDefaultType(); if (type instanceof PsiWildcardType) { @@ -71,7 +87,7 @@ class SmartCastProvider extends CompletionProvider { } } } - result.addElement(createSmartCastElement(parameters, overwrite, type)); + result.consume(createSmartCastElement(parameters, insideCast, type)); } } @@ -120,7 +136,9 @@ class SmartCastProvider extends CompletionProvider { context.setTailOffset(TailType.insertChar(editor, context.getTailOffset(), ' ')); } - editor.getCaretModel().moveToOffset(context.getTailOffset()); + if (parameters.getCompletionType() == CompletionType.SMART) { + editor.getCaretModel().moveToOffset(context.getTailOffset()); + } editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } }); diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/PreferCastTypesHavingSpecifiedMethod.java b/java/java-tests/testData/codeInsight/completion/normalSorting/PreferCastTypesHavingSpecifiedMethod.java new file mode 100644 index 000000000000..1de06b4a67b2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/PreferCastTypesHavingSpecifiedMethod.java @@ -0,0 +1,17 @@ +public class MainClass1 { + + public void main(Object o) { + ((Ma) o).zoo(); + } + + void zoo() {} + +} + +class MainClass2 { + void zoo() {} +} + +class Maa { + void zoo2() {} +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SuggestCastReturnTypeByCalledMethod-out.java b/java/java-tests/testData/codeInsight/completion/smartType/SuggestCastReturnTypeByCalledMethod-out.java new file mode 100644 index 000000000000..8bc86ee69f5a --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SuggestCastReturnTypeByCalledMethod-out.java @@ -0,0 +1,9 @@ +public class Main { + + public Object main(Object o) { + return ((Main) o).zoo(); + } + + void zoo() {} + +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SuggestCastReturnTypeByCalledMethod.java b/java/java-tests/testData/codeInsight/completion/smartType/SuggestCastReturnTypeByCalledMethod.java new file mode 100644 index 000000000000..9e8ba00c384a --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SuggestCastReturnTypeByCalledMethod.java @@ -0,0 +1,9 @@ +public class Main { + + public Object main(Object o) { + return (() o).zoo(); + } + + void zoo() {} + +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy index 95e9f505fd8a..5fc141750035 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy @@ -696,4 +696,8 @@ interface TxANotAnno {} assert 'SomeInterface' == LookupElementPresentation.renderElement(myFixture.lookupElements[3]).itemText } + public void testPreferCastTypesHavingSpecifiedMethod() { + checkPreferredItems 0, 'MainClass1', 'MainClass2', 'Maa' + } + } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index bee1fc65e894..c8a518b513c4 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -1153,6 +1153,8 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { myFixture.assertPreferredCompletionItems(0, "Serializable", "CharSequence", "Object"); } + public void testSuggestCastReturnTypeByCalledMethod() { doTest(); } + public void testNonStaticField() throws Exception { doAntiTest(); } private void doActionTest() throws Exception {