From f5b93393fc834575e62e521eebd4aa76cac5498c Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Tue, 11 Nov 2014 17:57:59 +0300 Subject: [PATCH] Do not ignore import element completely if qualifier was resolved to namespace package Consider the case when we are trying to invoke auto completion in "import foo.bar.". Previously (mistakenly) type of qualifier "foo.bar" was PyImportedModuleType(bar), which could not be successfully resolved unless there is some other top-level "bar" module under project roots. Now it's correct PyImportModuleType(foo.bar). --- .../python/psi/impl/PyImportedModule.java | 7 +++++++ .../psi/impl/PyReferenceExpressionImpl.java | 19 ++++++++++++++++--- .../a.after.py | 1 + .../a.py | 1 + .../nspkg1/nspkg2/bar.py | 0 .../nspkg1/nspkg2/foo.py | 0 .../jetbrains/python/Py3CompletionTest.java | 4 ++++ 7 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 python/testData/completion/importNestedQualifiedNamespacePackage/a.after.py create mode 100644 python/testData/completion/importNestedQualifiedNamespacePackage/a.py create mode 100644 python/testData/completion/importNestedQualifiedNamespacePackage/nspkg1/nspkg2/bar.py create mode 100644 python/testData/completion/importNestedQualifiedNamespacePackage/nspkg1/nspkg2/foo.py diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java b/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java index 317bede9385f..61cdf56fcef1 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java +++ b/python/src/com/jetbrains/python/psi/impl/PyImportedModule.java @@ -37,6 +37,13 @@ public class PyImportedModule extends LightElement implements NameDefiner { @NotNull private final PyFile myContainingFile; @NotNull private final QualifiedName myImportedPrefix; + /** + * @param importElement parental import element, may be {@code null} if we're resolving {@code module} part in {@code from module import ...} statement + * @param containingFile file to be used as anchor e.g. to determine relative import position + * @param importedPrefix qualified name to resolve + * + * @see com.jetbrains.python.psi.resolve.ResolveImportUtil + */ public PyImportedModule(@Nullable PyImportElement importElement, @NotNull PyFile containingFile, @NotNull QualifiedName importedPrefix) { super(containingFile.getManager(), PythonLanguage.getInstance()); myImportElement = importElement; diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index fd1126e64a2f..6cfdbe15cce8 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -36,7 +36,10 @@ import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.references.PyImportReference; import com.jetbrains.python.psi.impl.references.PyQualifiedReference; import com.jetbrains.python.psi.impl.references.PyReferenceImpl; -import com.jetbrains.python.psi.resolve.*; +import com.jetbrains.python.psi.resolve.ImplicitResolveResult; +import com.jetbrains.python.psi.resolve.PyResolveContext; +import com.jetbrains.python.psi.resolve.QualifiedResolveResult; +import com.jetbrains.python.psi.resolve.RatedResolveResult; import com.jetbrains.python.psi.types.*; import com.jetbrains.python.refactoring.PyDefUseUtil; import org.jetbrains.annotations.NotNull; @@ -382,8 +385,18 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere if (PyUtil.isPackage(dir, anchor)) { final PsiFile containingFile = anchor.getContainingFile(); if (containingFile instanceof PyFile) { - final QualifiedName qualifiedName = QualifiedName.fromComponents(dir.getName()); - final PyImportedModule module = new PyImportedModule(null, (PyFile)containingFile, qualifiedName); + final PyImportElement importElement = PsiTreeUtil.getParentOfType(anchor, PyImportElement.class); + final QualifiedName qualifiedName; + if (importElement != null) { + qualifiedName = anchor.asQualifiedName(); + } + else { + qualifiedName = QualifiedName.fromComponents(dir.getName()); + } + if (qualifiedName == null) { + return null; + } + final PyImportedModule module = new PyImportedModule(importElement, (PyFile)containingFile, qualifiedName); return new PyImportedModuleType(module); } } diff --git a/python/testData/completion/importNestedQualifiedNamespacePackage/a.after.py b/python/testData/completion/importNestedQualifiedNamespacePackage/a.after.py new file mode 100644 index 000000000000..eb8080426891 --- /dev/null +++ b/python/testData/completion/importNestedQualifiedNamespacePackage/a.after.py @@ -0,0 +1 @@ +import nspkg1.nspkg2.foo \ No newline at end of file diff --git a/python/testData/completion/importNestedQualifiedNamespacePackage/a.py b/python/testData/completion/importNestedQualifiedNamespacePackage/a.py new file mode 100644 index 000000000000..fa2789326e4c --- /dev/null +++ b/python/testData/completion/importNestedQualifiedNamespacePackage/a.py @@ -0,0 +1 @@ +import nspkg1.nspkg2.f \ No newline at end of file diff --git a/python/testData/completion/importNestedQualifiedNamespacePackage/nspkg1/nspkg2/bar.py b/python/testData/completion/importNestedQualifiedNamespacePackage/nspkg1/nspkg2/bar.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importNestedQualifiedNamespacePackage/nspkg1/nspkg2/foo.py b/python/testData/completion/importNestedQualifiedNamespacePackage/nspkg1/nspkg2/foo.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java index 9c87e473dd56..5fe31bdedeb3 100644 --- a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java +++ b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java @@ -115,4 +115,8 @@ public class Py3CompletionTest extends PyTestCase { public void testFromQualifiedNamespacePackageImport() { doMultiFileTest(); } + + public void testImportNestedQualifiedNamespacePackage() { + doMultiFileTest(); + } }