From 45317ba63496fcd44ddafe5ef3317b76cc476367 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Mon, 2 Apr 2018 19:56:50 +0300 Subject: [PATCH] Check if import source is located in the same package or above (PY-26139) --- .../PyProtectedMemberInspection.java | 25 ++++++++++++++----- .../my_package/__init__.py | 0 .../my_package/_module1.py | 2 ++ .../my_package/my_subpackage/__init__.py | 0 .../my_package/my_subpackage/module2.py | 3 +++ .../my_package/__init__.py | 0 .../my_package/_module1.py | 2 ++ .../my_package/module2.py | 3 +++ .../PyProtectedMemberInspectionTest.java | 10 ++++++++ 9 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/__init__.py create mode 100644 python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/_module1.py create mode 100644 python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/my_subpackage/__init__.py create mode 100644 python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/my_subpackage/module2.py create mode 100644 python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInSamePackage/my_package/__init__.py create mode 100644 python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInSamePackage/my_package/_module1.py create mode 100644 python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInSamePackage/my_package/module2.py diff --git a/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java b/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java index 777cc117bf4d..efc3609c43bd 100644 --- a/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java @@ -7,6 +7,7 @@ import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; @@ -16,7 +17,6 @@ import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; -import com.jetbrains.python.codeInsight.stdlib.PyNamedTupleType; import com.jetbrains.python.inspections.quickfix.PyAddPropertyForFieldQuickFix; import com.jetbrains.python.inspections.quickfix.PyMakePublicQuickFix; import com.jetbrains.python.inspections.quickfix.PyRenameElementQuickFix; @@ -73,12 +73,24 @@ public class PyProtectedMemberInspection extends PyInspection { } } - private boolean isImportFromTheSamePackage(PyReferenceExpression importSource) { - PsiDirectory directory = importSource.getContainingFile().getContainingDirectory(); - if (directory != null && PyUtil.isPackage(directory, true, importSource.getContainingFile()) && - directory.getName().equals(importSource.getName())) { - return true; + private boolean isImportFromTheSamePackage(@NotNull PyReferenceExpression importSource) { + final PsiDirectory currentFileDirectory = importSource.getContainingFile().getContainingDirectory(); + + if (currentFileDirectory != null && PyUtil.isPackage(currentFileDirectory, true, importSource)) { + final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(myTypeEvalContext); + + return StreamEx + .of(importSource.getReference(resolveContext).multiResolve(false)) + .map(ResolveResult::getElement) + .nonNull() + .map(PsiElement::getContainingFile) + .nonNull() + .map(PsiFile::getContainingDirectory) + .nonNull() + .map(PsiDirectory::getVirtualFile) + .anyMatch(importedSourceDir -> VfsUtilCore.isAncestor(importedSourceDir, currentFileDirectory.getVirtualFile(), false)); } + return false; } @@ -87,6 +99,7 @@ public class PyProtectedMemberInspection extends PyInspection { final PyExpression qualifier = node.getQualifier(); if (ignoreAnnotations && PsiTreeUtil.getParentOfType(node, PyAnnotation.class) != null) return; if (qualifier == null || ArrayUtil.contains(qualifier.getText(), PyNames.CANONICAL_SELF, PyNames.CANONICAL_CLS)) return; + if (isImportFromTheSamePackage(node)) return; checkReference(node, qualifier); } diff --git a/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/__init__.py b/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/_module1.py b/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/_module1.py new file mode 100644 index 000000000000..7b3f59d68f68 --- /dev/null +++ b/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/_module1.py @@ -0,0 +1,2 @@ +class A: + pass \ No newline at end of file diff --git a/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/my_subpackage/__init__.py b/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/my_subpackage/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/my_subpackage/module2.py b/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/my_subpackage/module2.py new file mode 100644 index 000000000000..a1953e7f1989 --- /dev/null +++ b/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInPackageAbove/my_package/my_subpackage/module2.py @@ -0,0 +1,3 @@ +from my_package._module1 import A + +print(A) \ No newline at end of file diff --git a/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInSamePackage/my_package/__init__.py b/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInSamePackage/my_package/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInSamePackage/my_package/_module1.py b/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInSamePackage/my_package/_module1.py new file mode 100644 index 000000000000..7b3f59d68f68 --- /dev/null +++ b/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInSamePackage/my_package/_module1.py @@ -0,0 +1,2 @@ +class A: + pass \ No newline at end of file diff --git a/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInSamePackage/my_package/module2.py b/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInSamePackage/my_package/module2.py new file mode 100644 index 000000000000..a1953e7f1989 --- /dev/null +++ b/python/testData/inspections/PyProtectedMemberInspection/ProtectedModuleInSamePackage/my_package/module2.py @@ -0,0 +1,3 @@ +from my_package._module1 import A + +print(A) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyProtectedMemberInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyProtectedMemberInspectionTest.java index 5292e09b2118..05b3386f936e 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyProtectedMemberInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyProtectedMemberInspectionTest.java @@ -84,6 +84,16 @@ public class PyProtectedMemberInspectionTest extends PyInspectionTestCase { runWithLanguageLevel(LanguageLevel.PYTHON36, this::doTest); } + // PY-26139 + public void testProtectedModuleInSamePackage() { + doMultiFileTest("my_package/module2.py"); + } + + // PY-26139 + public void testProtectedModuleInPackageAbove() { + doMultiFileTest("my_package/my_subpackage/module2.py"); + } + @NotNull @Override protected Class getInspectionClass() {