From c49b372edd1a6b372b5fb483cde1e2bdd0b50c3e Mon Sep 17 00:00:00 2001 From: "andrey.matveev" Date: Tue, 22 Dec 2020 17:01:51 +0700 Subject: [PATCH] PY-46056 Fix wrong same directory and library elements prioritization in completion (cherry picked from commit 0189cf588066af3c0f133caa599d1f1bc50caec0) IJ-MR-4895 GitOrigin-RevId: d8918a1530c612138c80850e41ad140d61300f4b --- .../impl/references/PyImportReference.java | 46 +++++++++++++------ .../ordinaryPackage/__init__.py | 0 .../ordinaryPackage/logging.py | 0 .../ordinaryPackage/logging1.py | 0 .../ordinaryPackage/sample.py | 1 + .../plainDirectory/logging.py | 0 .../plainDirectory/logging1.py | 0 .../plainDirectory/sample.py | 1 + .../ordinaryPackage/__init__.py | 0 .../ordinaryPackage/logging.py | 0 .../ordinaryPackage/logging1.py | 0 .../ordinaryPackage/sample.py | 1 + .../plainDirectory/logging.py | 0 .../plainDirectory/logging1.py | 0 .../plainDirectory/sample.py | 1 + .../jetbrains/python/Py3CompletionTest.java | 33 +++++++++++++ 16 files changed, 68 insertions(+), 15 deletions(-) create mode 100644 python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/__init__.py create mode 100644 python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging.py create mode 100644 python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging1.py create mode 100644 python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py create mode 100644 python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging.py create mode 100644 python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging1.py create mode 100644 python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py create mode 100644 python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/__init__.py create mode 100644 python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging.py create mode 100644 python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging1.py create mode 100644 python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py create mode 100644 python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging.py create mode 100644 python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging1.py create mode 100644 python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/references/PyImportReference.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/references/PyImportReference.java index b7f3b1814325..af275c2a81a4 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/references/PyImportReference.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/references/PyImportReference.java @@ -215,6 +215,7 @@ public class PyImportReference extends PyReferenceImpl { } } } + fillFromRootsIfNotRelative(relativeLevel, insertHandler); } else { // in "import _" or "from _ import" PsiElement prevElem = PyPsiUtils.getPrevNonWhitespaceSibling(myElement); @@ -235,28 +236,43 @@ public class PyImportReference extends PyReferenceImpl { addImportedNames(importStatement.getImportElements()); } } + final PsiDirectory containingDirectory = myCurrentFile.getContainingDirectory(); // look at dir by level - if ((relativeLevel >= 0 || !ResolveImportUtil.isAbsoluteImportEnabledFor(myCurrentFile))) { - final PsiDirectory containingDirectory = myCurrentFile.getContainingDirectory(); - if (containingDirectory != null) { - QualifiedName thisQName = QualifiedNameFinder.findShortestImportableQName(containingDirectory); - if (thisQName == null || thisQName.getComponentCount() == relativeLevel) { - fillFromDir(ResolveImportUtil.stepBackFrom(myCurrentFile, relativeLevel), insertHandler); - } - else if (thisQName.getComponentCount() > relativeLevel) { - thisQName = thisQName.removeTail(relativeLevel); - fillFromQName(thisQName, insertHandler); - } - } + if (LanguageLevel.forElement(myCurrentFile).isPy3K() && containingDirectory != null && + PyUtil.isExplicitPackage(containingDirectory)) { + fillFromRootsIfNotRelative(relativeLevel, insertHandler); + fillFromSameDirectoryOrRelative(relativeLevel, insertHandler); + } + else { + fillFromSameDirectoryOrRelative(relativeLevel, insertHandler); + fillFromRootsIfNotRelative(relativeLevel, insertHandler); } - } - if (relativeLevel == -1) { - fillFromQName(QualifiedName.fromComponents(), insertHandler); } return ArrayUtil.toObjectArray(myObjects); } + private void fillFromRootsIfNotRelative(int relativeLevel, @Nullable InsertHandler insertHandler) { + if (relativeLevel == -1) { + fillFromQName(QualifiedName.fromComponents(), insertHandler); + } + } + + private void fillFromSameDirectoryOrRelative(int relativeLevel, @Nullable InsertHandler insertHandler) { + if (relativeLevel < 0 && ResolveImportUtil.isAbsoluteImportEnabledFor(myCurrentFile)) return; + final PsiDirectory containingDirectory = myCurrentFile.getContainingDirectory(); + if (containingDirectory != null) { + QualifiedName thisQName = QualifiedNameFinder.findShortestImportableQName(containingDirectory); + if (thisQName == null || thisQName.getComponentCount() == relativeLevel) { + fillFromDir(ResolveImportUtil.stepBackFrom(myCurrentFile, relativeLevel), insertHandler); + } + else if (thisQName.getComponentCount() > relativeLevel) { + thisQName = thisQName.removeTail(relativeLevel); + fillFromQName(thisQName, insertHandler); + } + } + } + private void fillFromQName(QualifiedName thisQName, InsertHandler insertHandler) { StreamEx.of(PyResolveImportUtil.resolveQualifiedName(thisQName, PyResolveImportUtil.fromFoothold(myCurrentFile))) .select(PsiDirectory.class) diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/__init__.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging1.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging1.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py new file mode 100644 index 000000000000..75970a773ebb --- /dev/null +++ b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py @@ -0,0 +1 @@ +from log \ No newline at end of file diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging1.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging1.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py new file mode 100644 index 000000000000..75970a773ebb --- /dev/null +++ b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py @@ -0,0 +1 @@ +from log \ No newline at end of file diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/__init__.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging1.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging1.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py new file mode 100644 index 000000000000..d722805d37f3 --- /dev/null +++ b/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py @@ -0,0 +1 @@ +import log \ No newline at end of file diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging1.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging1.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py new file mode 100644 index 000000000000..d722805d37f3 --- /dev/null +++ b/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py @@ -0,0 +1 @@ +import log \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java index f044730c75c0..360dea053df3 100644 --- a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java +++ b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java @@ -7,6 +7,7 @@ import com.intellij.openapi.module.Module; import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.TestDataPath; +import com.intellij.testFramework.fixtures.TestLookupElementPresentation; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.codeInsight.completion.PyModuleNameCompletionContributor; import com.jetbrains.python.fixtures.PyTestCase; @@ -491,6 +492,38 @@ public class Py3CompletionTest extends PyTestCase { }); } + // PY-46056 + public void testImportCompletionHintForSameDirectoryModuleInOrdinaryPackage() { + doTestVariantTailText("ordinaryPackage/sample.py", "logging", null); + } + + // PY-46056 + public void testImportCompletionHintForSameDirectoryModuleInPlainDirectory() { + doTestVariantTailText("plainDirectory/sample.py", "logging", " (plainDirectory)"); + } + + // PY-46056 + public void testFromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage() { + doTestVariantTailText("ordinaryPackage/sample.py", "logging", null); + } + + // PY-46056 + public void testFromImportCompletionHintForSameDirectoryModuleInPlainDirectory() { + doTestVariantTailText("plainDirectory/sample.py", "logging", " (plainDirectory)"); + } + + private void doTestVariantTailText(@NotNull String entryFilePath, @NotNull String variantName, @Nullable String tailText) { + runWithLanguageLevel(LanguageLevel.getLatest(), () -> { + myFixture.copyDirectoryToProject(getTestName(true), ""); + myFixture.configureByFile(entryFilePath); + LookupElement[] variants = myFixture.completeBasic(); + assertNotNull(variants); + LookupElement lookupElement = ContainerUtil.find(variants, v -> v.getLookupString().equals(variantName)); + assertNotNull(lookupElement); + assertEquals(tailText, TestLookupElementPresentation.renderElement(lookupElement).getTailText()); + }); + } + // PY-46054 public void testFromImportFromSameDirectoryModule() { runWithLanguageLevel(LanguageLevel.getLatest(), () -> {