From f9d156ca8a529e5fdde472eed520166525a1bede Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Mon, 6 Jul 2015 19:41:54 +0300 Subject: [PATCH] Resolve only explicitly imported submodules of imported packages (follow-up for PY-14454) Now we try to filter resolve results for members of an imported module by only explicitly imported results as we used to do for directories only. The difference is we do it now for both directories and __init__.py files and only if we're resolving a member in the same file where the import for the module is located. --- .../psi/types/PyImportedModuleType.java | 24 +++++++++++++++---- .../python/psi/types/PyModuleType.java | 9 +++---- .../ImplicitlyImportedSubModule/a.py | 5 ---- .../pkg1/__init__.py | 1 - .../ImplicitlyImportedSubModule/pkg1/m1.py | 1 - .../ImplicitlyImportedSubModule/pkg1/m2.py | 1 - .../main.py | 5 ++++ .../nspkg1/m2.py | 0 .../nspkg1/m3.py | 0 .../nspkg1/nssubpkg1/m1.py | 0 .../unusedSubmodule/p1/__init__.py | 0 .../unusedImport/unusedSubmodule/p1/m1.py | 1 + .../unusedImport/unusedSubmodule/p1/m2.py | 1 + .../unusedImport/unusedSubmodule/test1.py | 3 +++ ...Py3UnresolvedReferencesInspectionTest.java | 5 ++++ .../PyUnresolvedReferencesInspectionTest.java | 5 +--- .../inspections/PyUnusedImportTest.java | 5 ++++ 17 files changed, 46 insertions(+), 20 deletions(-) delete mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/a.py delete mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/__init__.py delete mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m1.py delete mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m2.py create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/main.py create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/m2.py create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/m3.py create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/nssubpkg1/m1.py create mode 100644 python/testData/inspections/unusedImport/unusedSubmodule/p1/__init__.py create mode 100644 python/testData/inspections/unusedImport/unusedSubmodule/p1/m1.py create mode 100644 python/testData/inspections/unusedImport/unusedSubmodule/p1/m2.py create mode 100644 python/testData/inspections/unusedImport/unusedSubmodule/test1.py diff --git a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java index 19f247d4a4bf..0aaa054c8b6c 100644 --- a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java @@ -15,16 +15,17 @@ */ package com.jetbrains.python.psi.types; +import com.google.common.collect.Sets; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.openapi.util.Condition; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiFileSystemItem; import com.intellij.util.ArrayUtil; import com.intellij.util.ProcessingContext; -import com.jetbrains.python.psi.AccessDirection; -import com.jetbrains.python.psi.PyExpression; -import com.jetbrains.python.psi.PyFile; -import com.jetbrains.python.psi.PyUtil; +import com.intellij.util.containers.ContainerUtil; +import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyImportedModule; import com.jetbrains.python.psi.resolve.PointInImport; import com.jetbrains.python.psi.resolve.PyResolveContext; @@ -36,6 +37,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; /** * @author yole @@ -57,6 +59,20 @@ public class PyImportedModuleType implements PyType { if (resolved != null) { final PsiFile containingFile = location != null ? location.getContainingFile() : null; List elements = Collections.singletonList(ResolveImportUtil.resolveChild(resolved, name, containingFile, false, true)); + final PyImportElement importElement = myImportedModule.getImportElement(); + if (location != null && importElement != null && PyUtil.inSameFile(location, importElement) && + ResolveImportUtil.getPointInImport(location) == PointInImport.NONE && resolved instanceof PsiFileSystemItem) { + final List importedSubmodules = PyModuleType.collectImportedSubmodules((PsiFileSystemItem)resolved, location); + if (importedSubmodules != null) { + final Set imported = Sets.newHashSet(importedSubmodules); + elements = ContainerUtil.filter(elements, new Condition() { + @Override + public boolean value(PsiElement element) { + return imported.contains(element); + } + }); + } + } return ResolveImportUtil.rateResults(elements); } return null; diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index cd642a6910cf..d057b70c6ed3 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -388,7 +388,8 @@ public class PyModuleType implements PyType { // Modules don't descend from obje @NotNull PsiElement location, @Nullable final Set existingNames) { - return ContainerUtil.mapNotNull(collectImportedSubmodules(pyPackage, location), + final List elements = collectImportedSubmodules(pyPackage, location); + return elements != null ? ContainerUtil.mapNotNull(elements, new Function() { @Override public LookupElement fun(PsiElement element) { @@ -400,10 +401,10 @@ public class PyModuleType implements PyType { // Modules don't descend from obje } return null; } - }); + }) : Collections.emptyList(); } - @NotNull + @Nullable public static List collectImportedSubmodules(@NotNull PsiFileSystemItem pyPackage, @NotNull PsiElement location) { final PsiElement parentAnchor; if (pyPackage instanceof PyFile && PyUtil.isPackage(((PyFile)pyPackage))) { @@ -413,7 +414,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje parentAnchor = pyPackage; } else { - throw new IllegalArgumentException("Package argument should be either standard Python package or namespace package"); + return null; } final ScopeOwner scopeOwner = ScopeUtil.getScopeOwner(location); diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/a.py deleted file mode 100644 index 6de874dee44a..000000000000 --- a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/a.py +++ /dev/null @@ -1,5 +0,0 @@ -import pkg1.m1 - -print(pkg1.m2) -print(pkg1.nonexistent) - diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/__init__.py b/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/__init__.py deleted file mode 100644 index 8b137891791f..000000000000 --- a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m1.py b/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m1.py deleted file mode 100644 index 123f7cbbfd9d..000000000000 --- a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m1.py +++ /dev/null @@ -1 +0,0 @@ -import pkg1.m2 diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m2.py b/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m2.py deleted file mode 100644 index 8b137891791f..000000000000 --- a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m2.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/main.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/main.py new file mode 100644 index 000000000000..54e2273f4550 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/main.py @@ -0,0 +1,5 @@ +import nspkg1.m2 + +print(nspkg1.m2) +print(nspkg1.m3) +print(nspkg1.nssubpkg1) diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/m2.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/m2.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/m3.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/m3.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/nssubpkg1/m1.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/nssubpkg1/m1.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/unusedImport/unusedSubmodule/p1/__init__.py b/python/testData/inspections/unusedImport/unusedSubmodule/p1/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/unusedImport/unusedSubmodule/p1/m1.py b/python/testData/inspections/unusedImport/unusedSubmodule/p1/m1.py new file mode 100644 index 000000000000..a43e3eb876c1 --- /dev/null +++ b/python/testData/inspections/unusedImport/unusedSubmodule/p1/m1.py @@ -0,0 +1 @@ +a1 = 42 \ No newline at end of file diff --git a/python/testData/inspections/unusedImport/unusedSubmodule/p1/m2.py b/python/testData/inspections/unusedImport/unusedSubmodule/p1/m2.py new file mode 100644 index 000000000000..97f0eb4ade34 --- /dev/null +++ b/python/testData/inspections/unusedImport/unusedSubmodule/p1/m2.py @@ -0,0 +1 @@ +a2 = -1 \ No newline at end of file diff --git a/python/testData/inspections/unusedImport/unusedSubmodule/test1.py b/python/testData/inspections/unusedImport/unusedSubmodule/test1.py new file mode 100644 index 000000000000..40e9e79d3ac1 --- /dev/null +++ b/python/testData/inspections/unusedImport/unusedSubmodule/test1.py @@ -0,0 +1,3 @@ +import p1.m1 + +print(p1.m2.a2) diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java index 9cdac1dd034b..1a29300f947d 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java @@ -112,6 +112,11 @@ public class Py3UnresolvedReferencesInspectionTest extends PyTestCase { doTest(); } + // PY-14385 + public void testNotImportedSubmodulesOfNamespacePackage() { + doMultiFileTest("main.py"); + } + // PY-15017 public void testClassLevelReferenceInMethodAnnotation() { doTest(); diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 6e0c1b333f7a..59a93465d995 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -510,10 +510,7 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { doTest(); } - // PY-14615 - public void testImplicitlyImportedSubModule() { - doMultiFileTest(); - } + @NotNull @Override diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnusedImportTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnusedImportTest.java index 1ce20f386adf..018d75e8fbde 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnusedImportTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnusedImportTest.java @@ -38,6 +38,11 @@ public class PyUnusedImportTest extends PyTestCase { doTest("test1.py"); } + // PY-5621 + public void testUnusedSubmodule() { + doTest("test1.py"); + } + // PY-6380 public void testUnusedAfterStarImport() { doTest("test1.py");