diff --git a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/ChainSearcher.java b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/ChainSearcher.java index 70940eced821..cb9c793b9667 100644 --- a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/ChainSearcher.java +++ b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/ChainSearcher.java @@ -150,10 +150,10 @@ public class ChainSearcher { private static boolean addChainIfTerminal(CallChain currentChain, List result, int pathMaximalLength, ChainCompletionContext context) { - RefChainOperation signature = currentChain.getHeadSignature(); - if (!(signature instanceof MethodIncompleteSignature)) return false; + RefChainOperation signature = currentChain.getLastMethodSign(); + RefChainOperation head = currentChain.getHeadSignature(); if (((MethodIncompleteSignature)signature).isStatic() || - context.hasQualifier(context.resolvePsiClass(((MethodIncompleteSignature)signature).getOwnerRef())) || + context.hasQualifier(context.resolvePsiClass(head.getOwnerRef1())) || currentChain.length() >= pathMaximalLength) { addChainIfNotPresent(currentChain, result); return true; diff --git a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/MethodChainLookupRangingHelper.java b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/MethodChainLookupRangingHelper.java index 840e218b9261..a23e3246b0f3 100644 --- a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/MethodChainLookupRangingHelper.java +++ b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/MethodChainLookupRangingHelper.java @@ -35,7 +35,6 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.stream.Collectors; @@ -57,14 +56,16 @@ public class MethodChainLookupRangingHelper { matchedParametersInContext += info.getSecond(); if (chainLookupElement == null) { - LookupElement qualifierLookupElement = createQualifierLookupElement(method, chain.getQualifierClass(), context); + LookupElement qualifierLookupElement = method.hasModifierProperty(PsiModifier.STATIC) ? null : createQualifierLookupElement(chain.getQualifierClass(), context); LookupElement headLookupElement = createMethodLookupElement(method); chainLookupElement = qualifierLookupElement == null ? headLookupElement : new JavaChainLookupElement(qualifierLookupElement, headLookupElement); } else { chainLookupElement = new JavaChainLookupElement(chainLookupElement, new JavaMethodCallElement(method)); } } else { - if (chainLookupElement == null) throw new IllegalStateException(); + if (chainLookupElement == null) { + chainLookupElement = createQualifierLookupElement(chain.getQualifierClass(), context); + } PsiClass castClass = ((ChainOperation.TypeCast)op).getCastClass(); PsiClassType type = JavaPsiFacade.getElementFactory(castClass.getProject()).createType(castClass); chainLookupElement = CastingLookupElementDecorator.createCastingElement(chainLookupElement, type); @@ -109,9 +110,9 @@ public class MethodChainLookupRangingHelper { }; } - @Nullable - private static LookupElement createQualifierLookupElement(@NotNull PsiMethod method, @NotNull PsiClass qualifierClass, @NotNull ChainCompletionContext context) { - if (method.hasModifierProperty(PsiModifier.STATIC)) return null; + @NotNull + private static LookupElement createQualifierLookupElement(@NotNull PsiClass qualifierClass, + @NotNull ChainCompletionContext context) { PsiNamedElement element = context.getQualifiers(qualifierClass).findFirst().orElse(null); if (element == null) { return new ChainCompletionNewVariableLookupElement(qualifierClass, context); diff --git a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/MethodIncompleteSignature.kt b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/MethodIncompleteSignature.kt index a8a56dccd0a8..14762a99f1ef 100644 --- a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/MethodIncompleteSignature.kt +++ b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/MethodIncompleteSignature.kt @@ -28,6 +28,10 @@ import java.util.function.Predicate class MethodIncompleteSignature(val ref: LightRef.JavaLightMethodRef, private val signatureData: SignatureData, private val refService: CompilerReferenceServiceEx): RefChainOperation { + override fun getOwnerRef1(): LightRef.LightClassHierarchyElementDef { + return ownerRef + } + override fun getOwner1(): String { return owner } diff --git a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/RefChainOperation.java b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/RefChainOperation.java index 4338ac3d3579..2f9b381b9f77 100644 --- a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/RefChainOperation.java +++ b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/RefChainOperation.java @@ -19,6 +19,7 @@ import org.jetbrains.jps.backwardRefs.LightRef; public interface RefChainOperation { String getOwner1(); + LightRef.LightClassHierarchyElementDef getOwnerRef1(); LightRef getRef1(); } diff --git a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/TypeCast.kt b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/TypeCast.kt index bd3709623b1c..9fa09601eeae 100644 --- a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/TypeCast.kt +++ b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/TypeCast.kt @@ -22,6 +22,10 @@ class TypeCast(val operandRef: LightRef.LightClassHierarchyElementDef, val castTypeRef: LightRef.LightClassHierarchyElementDef, refService: CompilerReferenceServiceEx, val occurrences: Int): RefChainOperation { + override fun getOwnerRef1(): LightRef.LightClassHierarchyElementDef { + return operandRef + } + override fun getOwner1(): String { return operandName } diff --git a/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnContextVariable/TestCompletion.java b/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnContextVariable/TestCompletion.java new file mode 100644 index 000000000000..bea43a5d5b31 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnContextVariable/TestCompletion.java @@ -0,0 +1,11 @@ +interface Editor {} +interface EditorEx extends Editor { + MarkupModelEx getMarkupModel(); +} +interface MarkupModelEx {} + +class Test { + void m(Editor editor) { + MarkupModelEx m = + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnContextVariable/TestIndex.java b/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnContextVariable/TestIndex.java new file mode 100644 index 000000000000..9e02d9826597 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnContextVariable/TestIndex.java @@ -0,0 +1,19 @@ +interface Editor {} +interface EditorEx extends Editor { + MarkupModelEx getMarkupModel(); +} +interface MarkupModelEx {} + +class Test { + void m(Editor editor) { + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnStaticMethod/TestCompletion.java b/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnStaticMethod/TestCompletion.java new file mode 100644 index 000000000000..762e124f58e4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnStaticMethod/TestCompletion.java @@ -0,0 +1,15 @@ +interface InspectionManager { + static InspectionManager getInstance() { + return null; + } +} +interface InspectionManagerEx extends InspectionManager { + GlobalInspectionContext createContext(); +} +interface GlobalInspectionContext {} + +class Test { + void m() { + GlobalInspectionContext c = + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnStaticMethod/TestIndex.java b/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnStaticMethod/TestIndex.java new file mode 100644 index 000000000000..81fd6179e38c --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnStaticMethod/TestIndex.java @@ -0,0 +1,24 @@ +interface InspectionManager { + static InspectionManager getInstance() { + return null; + } +} +interface InspectionManagerEx extends InspectionManager { + GlobalInspectionContext createContext(); +} +interface GlobalInspectionContext {} + +class Test { + void m() { + ((InspectionManagerEx)InspectionManager.getInstance()).createContext(); + ((InspectionManagerEx)InspectionManager.getInstance()).createContext(); + ((InspectionManagerEx)InspectionManager.getInstance()).createContext(); + ((InspectionManagerEx)InspectionManager.getInstance()).createContext(); + ((InspectionManagerEx)InspectionManager.getInstance()).createContext(); + ((InspectionManagerEx)InspectionManager.getInstance()).createContext(); + ((InspectionManagerEx)InspectionManager.getInstance()).createContext(); + ((InspectionManagerEx)InspectionManager.getInstance()).createContext(); + ((InspectionManagerEx)InspectionManager.getInstance()).createContext(); + ((InspectionManagerEx)InspectionManager.getInstance()).createContext(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnVariableOutsideContext/TestCompletion.java b/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnVariableOutsideContext/TestCompletion.java new file mode 100644 index 000000000000..ffbe7a3383b8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnVariableOutsideContext/TestCompletion.java @@ -0,0 +1,11 @@ +interface Editor {} +interface EditorEx extends Editor { + MarkupModelEx getMarkupModel(); +} +interface MarkupModelEx {} + +class Test { + void m() { + MarkupModelEx m = + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnVariableOutsideContext/TestIndex.java b/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnVariableOutsideContext/TestIndex.java new file mode 100644 index 000000000000..9e02d9826597 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/methodChains/testChainWithCastOnVariableOutsideContext/TestIndex.java @@ -0,0 +1,19 @@ +interface Editor {} +interface EditorEx extends Editor { + MarkupModelEx getMarkupModel(); +} +interface MarkupModelEx {} + +class Test { + void m(Editor editor) { + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + ((EditorEx)editor).getMarkupModel(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/MethodChainsCompletionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/MethodChainsCompletionTest.java index bd4b99d71002..97e8bc884a2f 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/MethodChainsCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/MethodChainsCompletionTest.java @@ -23,7 +23,9 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.compiler.chainsSearch.ChainRelevance; import com.intellij.compiler.chainsSearch.completion.MethodChainCompletionContributor; import com.intellij.compiler.chainsSearch.completion.lookup.JavaRelevantChainLookupElement; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.util.registry.Registry; +import com.intellij.pom.java.LanguageLevel; import com.intellij.testFramework.SkipSlowTestLocally; import com.intellij.util.SmartList; @@ -44,6 +46,7 @@ public class MethodChainsCompletionTest extends AbstractCompilerAwareTest { Registry.get(MethodChainCompletionContributor.REGISTRY_KEY).setValue(true, myFixture.getTestRootDisposable()); myDefaultAutoCompleteOnCodeCompletion = CodeInsightSettings.getInstance().AUTOCOMPLETE_ON_CODE_COMPLETION; CodeInsightSettings.getInstance().AUTOCOMPLETE_ON_SMART_TYPE_COMPLETION = false; + LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_8); } @Override @@ -240,6 +243,20 @@ public class MethodChainsCompletionTest extends AbstractCompilerAwareTest { assertEquals("psiElement.getProject", element.getLookupString()); } + public void testChainWithCastOnContextVariable() { + JavaRelevantChainLookupElement element = assertOneElement(doCompletion()); + assertEquals("(EditorEx)editor.getMarkupModel", element.toString()); + } + + public void testChainWithCastOnVariableOutsideContext() { + assertEmpty(doCompletion()); + } + + public void testChainWithCastOnStaticMethod() { + JavaRelevantChainLookupElement element = assertOneElement(doCompletion()); + assertEquals("(InspectionManagerEx)getInstance().createContext", element.toString()); + } + public void assertAdvisorLookupElementEquals(String lookupText, int unreachableParametersCount, int chainSize,