diff --git a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/context/ChainCompletionContext.java b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/context/ChainCompletionContext.java index 715b76f9c25d..43b66f10df3a 100644 --- a/java/compiler/impl/src/com/intellij/compiler/chainsSearch/context/ChainCompletionContext.java +++ b/java/compiler/impl/src/com/intellij/compiler/chainsSearch/context/ChainCompletionContext.java @@ -28,10 +28,12 @@ import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.ClassUtil; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.FactoryMap; +import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.backwardRefs.LightRef; @@ -183,25 +185,44 @@ public class ChainCompletionContext { target = target.toIterators(); } - ContextProcessor processor = new ContextProcessor(null, containingElement.getProject(), containingElement); + Set excludedVariables = getEnclosingLocalVariables(containingElement); + ContextProcessor processor = new ContextProcessor(null, containingElement.getProject(), containingElement, excludedVariables); PsiScopesUtil.treeWalkUp(processor, containingElement, containingElement.getContainingFile()); List contextElements = processor.getContextElements(); return new ChainCompletionContext(target, contextElements, containingElement); } + @NotNull + private static Set getEnclosingLocalVariables(@NotNull PsiElement place) { + Set result = new THashSet<>(); + if (place instanceof PsiLocalVariable) result.add((PsiLocalVariable)place); + PsiElement parent = place.getParent(); + while (parent != null) { + if (parent instanceof PsiFileSystemItem) break; + if (parent instanceof PsiLocalVariable && PsiTreeUtil.isAncestor(((PsiLocalVariable)parent).getInitializer(), place, false)) { + result.add((PsiLocalVariable)parent); + } + parent = parent.getParent(); + } + return result; + } + private static class ContextProcessor extends BaseScopeProcessor implements ElementClassHint { private final List myContextElements = new SmartList<>(); private final PsiVariable myCompletionVariable; private final PsiResolveHelper myResolveHelper; private final PsiElement myPlace; + private final Set myExcludedVariables; private ContextProcessor(@Nullable PsiVariable variable, @NotNull Project project, - @NotNull PsiElement place) { + @NotNull PsiElement place, + @NotNull Set excludedVariables) { myCompletionVariable = variable; myResolveHelper = PsiResolveHelper.SERVICE.getInstance(project); myPlace = place; + myExcludedVariables = excludedVariables; } @Override @@ -215,6 +236,7 @@ public class ChainCompletionContext { @Override public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) { if ((!(element instanceof PsiMethod) || PropertyUtil.isSimplePropertyAccessor((PsiMethod)element)) && + (!(element instanceof PsiVariable) || !myExcludedVariables.contains(element)) && (!(element instanceof PsiMember) || myResolveHelper.isAccessible((PsiMember)element, myPlace, null))) { PsiType type = getType(element); if (type == null) { diff --git a/java/java-tests/testData/codeInsight/completion/methodChains/testDoNotSuggestUninitializedVariable/TestCompletion.java b/java/java-tests/testData/codeInsight/completion/methodChains/testDoNotSuggestUninitializedVariable/TestCompletion.java new file mode 100644 index 000000000000..8a8286899eb8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/methodChains/testDoNotSuggestUninitializedVariable/TestCompletion.java @@ -0,0 +1,16 @@ +public class TestCompletion { + void m() { + PsiElement someVar = get(); + } + + static PsiElement get(Project project) { + return null; + } +} + +interface Project { +} + +interface PsiElement { + Project getProject(); +} diff --git a/java/java-tests/testData/codeInsight/completion/methodChains/testDoNotSuggestUninitializedVariable/TestIndex.java b/java/java-tests/testData/codeInsight/completion/methodChains/testDoNotSuggestUninitializedVariable/TestIndex.java new file mode 100644 index 000000000000..e4266096bf89 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/methodChains/testDoNotSuggestUninitializedVariable/TestIndex.java @@ -0,0 +1,18 @@ +public class TestIndex { + public void statMethod(PsiElement e) { + e.getProject(); + e.getProject(); + e.getProject(); + e.getProject(); + e.getProject(); + e.getProject(); + e.getProject(); + e.getProject(); + } +} + +interface Project {} + +interface PsiElement { + Project getProject(); +} 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 abe47ffca614..bd4b99d71002 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 @@ -235,6 +235,11 @@ public class MethodChainsCompletionTest extends AbstractCompilerAwareTest { doTestRendering(); } + public void testDoNotSuggestUninitializedVariable() { + JavaRelevantChainLookupElement element = assertOneElement(doCompletion()); + assertEquals("psiElement.getProject", element.getLookupString()); + } + public void assertAdvisorLookupElementEquals(String lookupText, int unreachableParametersCount, int chainSize,