From 8a5f55098609ddded8fe34e19b1a0ba0ac273257 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Thu, 3 Aug 2017 18:58:54 +0300 Subject: [PATCH] PY-8132 Fixed: Completion shows function instead of variable if function contains a variable with name equal to function name Update CompletionVariantsProcessor to ignore same name elements from outer scope --- .../psi/resolve/CompletionVariantsProcessor.java | 2 ++ .../python/psi/resolve/VariantsProcessor.java | 8 +++++--- ...pletionVariantDoesNotOverwriteClosestOne.after.py | 3 +++ ...terCompletionVariantDoesNotOverwriteClosestOne.py | 3 +++ .../com/jetbrains/python/PythonCompletionTest.java | 12 +++++------- 5 files changed, 18 insertions(+), 10 deletions(-) create mode 100644 python/testData/completion/outerCompletionVariantDoesNotOverwriteClosestOne.after.py create mode 100644 python/testData/completion/outerCompletionVariantDoesNotOverwriteClosestOne.py diff --git a/python/src/com/jetbrains/python/psi/resolve/CompletionVariantsProcessor.java b/python/src/com/jetbrains/python/psi/resolve/CompletionVariantsProcessor.java index 4be22038fff4..305b76c33dfa 100644 --- a/python/src/com/jetbrains/python/psi/resolve/CompletionVariantsProcessor.java +++ b/python/src/com/jetbrains/python/psi/resolve/CompletionVariantsProcessor.java @@ -161,6 +161,7 @@ public class CompletionVariantsProcessor extends VariantsProcessor { if (PyUtil.isClassPrivateName(name) && !PyUtil.inSameFile(element, myContext)) { return; } + markAsProcessed(name); myVariants.put(name, setupItem(LookupElementBuilder.createWithSmartPointer(name, element).withIcon(element.getIcon(0)))); } @@ -169,6 +170,7 @@ public class CompletionVariantsProcessor extends VariantsProcessor { Icon icon = element.getIcon(0); // things like PyTargetExpression cannot have a general icon, but here we only have variables if (icon == null) icon = PlatformIcons.VARIABLE_ICON; + markAsProcessed(name); myVariants.put(name, setupItem(LookupElementBuilder.createWithSmartPointer(name, element).withIcon(icon))); } } diff --git a/python/src/com/jetbrains/python/psi/resolve/VariantsProcessor.java b/python/src/com/jetbrains/python/psi/resolve/VariantsProcessor.java index 9b04f118fbdb..11de86b66936 100644 --- a/python/src/com/jetbrains/python/psi/resolve/VariantsProcessor.java +++ b/python/src/com/jetbrains/python/psi/resolve/VariantsProcessor.java @@ -121,14 +121,16 @@ public abstract class VariantsProcessor implements PsiScopeProcessor { return false; } - protected void addElement(@NotNull String name, @NotNull PsiElement element) { - mySeenNames.add(name); - } + protected abstract void addElement(@NotNull String name, @NotNull PsiElement element); protected void addImportedElement(@NotNull String name, @NotNull PyElement element) { addElement(name, element); } + protected void markAsProcessed(@NotNull String name) { + mySeenNames.add(name); + } + @Contract("null -> false") private boolean nameIsAcceptable(@Nullable String name) { if (name == null) { diff --git a/python/testData/completion/outerCompletionVariantDoesNotOverwriteClosestOne.after.py b/python/testData/completion/outerCompletionVariantDoesNotOverwriteClosestOne.after.py new file mode 100644 index 000000000000..7af5e8319893 --- /dev/null +++ b/python/testData/completion/outerCompletionVariantDoesNotOverwriteClosestOne.after.py @@ -0,0 +1,3 @@ +def abracadabra(): + abracadabra = "str" + print(abracadabra) \ No newline at end of file diff --git a/python/testData/completion/outerCompletionVariantDoesNotOverwriteClosestOne.py b/python/testData/completion/outerCompletionVariantDoesNotOverwriteClosestOne.py new file mode 100644 index 000000000000..1efca1ca161e --- /dev/null +++ b/python/testData/completion/outerCompletionVariantDoesNotOverwriteClosestOne.py @@ -0,0 +1,3 @@ +def abracadabra(): + abracadabra = "str" + print(abracadab) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java index 2a42a8e6505e..c5e388e54064 100644 --- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java @@ -1138,8 +1138,6 @@ public class PythonCompletionTest extends PyTestCase { // PY-18246 public void testTypingNamedTupleCreatedViaCallInstance() { - myFixture.copyDirectoryToProject("../typing", ""); - final List suggested = doTestByText( "from typing import NamedTuple\n" + "EmployeeRecord = NamedTuple('EmployeeRecord', [\n" + @@ -1157,8 +1155,6 @@ public class PythonCompletionTest extends PyTestCase { // PY-18246 public void testTypingNamedTupleCreatedViaKwargsCallInstance() { - myFixture.copyDirectoryToProject("../typing", ""); - final List suggested = doTestByText( "from typing import NamedTuple\n" + "EmployeeRecord = NamedTuple('EmployeeRecord', name=str, age=int, title=str, department=str)\n" + @@ -1174,8 +1170,6 @@ public class PythonCompletionTest extends PyTestCase { runWithLanguageLevel( LanguageLevel.PYTHON36, () -> { - myFixture.copyDirectoryToProject("../typing", ""); - final List suggested = doTestByText( "from typing import NamedTuple\n" + "class EmployeeRecord(NamedTuple):\n" + @@ -1194,7 +1188,6 @@ public class PythonCompletionTest extends PyTestCase { // PY-21519 public void testTypeComment() { - myFixture.copyDirectoryToProject("../typing", ""); final List variants = doTestByFile(); assertContainsElements(variants, "List", "Union", "Optional"); } @@ -1205,6 +1198,11 @@ public class PythonCompletionTest extends PyTestCase { assertDoesntContain(variants, "illegal"); } + // PY-8132 + public void testOuterCompletionVariantDoesNotOverwriteClosestOne() { + doTest(); + } + @Override protected String getTestDataPath() { return super.getTestDataPath() + "/completion";