diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyClassNameCompletionContributor.java b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyClassNameCompletionContributor.java index 63ee2f36d55c..f17f1a435b4a 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyClassNameCompletionContributor.java +++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyClassNameCompletionContributor.java @@ -21,6 +21,7 @@ import com.intellij.psi.util.QualifiedName; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; +import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.QualifiedNameFinder; import com.jetbrains.python.psi.search.PySearchUtilBase; @@ -114,7 +115,8 @@ public class PyClassNameCompletionContributor extends PyExtendedCompletionContri @NotNull Class elementClass, @NotNull Function elementHandler) { final Project project = targetFile.getProject(); - final GlobalSearchScope scope = PySearchUtilBase.excludeSdkTestsScope(targetFile); + final GlobalSearchScope scope = PySearchUtilBase.excludeSdkTestsScope(targetFile) + .intersectWith(GlobalSearchScope.notScope(PyUserSkeletonsUtil.getUserSkeletonsDirectoryScope(project))); final Set alreadySuggested = new HashSet<>(); StubIndex stubIndex = StubIndex.getInstance(); diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java index c5cbfcdf824c..4c27d9e18825 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java +++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java @@ -29,6 +29,8 @@ import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.GlobalSearchScopesCore; import com.intellij.psi.util.QualifiedName; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PythonHelpersLocator; @@ -115,6 +117,17 @@ public class PyUserSkeletonsUtil { return skeletonsDir != null && VfsUtilCore.isAncestor(skeletonsDir, virtualFile, false); } + @NotNull + public static GlobalSearchScope getUserSkeletonsDirectoryScope(@NotNull Project project) { + VirtualFile userSkeletonsDirectory = getUserSkeletonsDirectory(); + if (userSkeletonsDirectory != null) { + return new GlobalSearchScopesCore.DirectoryScope(project, userSkeletonsDirectory, true); + } + else { + return GlobalSearchScope.EMPTY_SCOPE; + } + } + public static boolean isStandardLibrarySkeleton(@NotNull VirtualFile virtualFile) { final VirtualFile skeletonsDir = getUserSkeletonsDirectory(); if (skeletonsDir == null) { diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java b/python/python-psi-impl/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java index 3afc605dea2a..0eea3886b58d 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/stubs/PyModuleNameIndex.java @@ -86,16 +86,16 @@ public class PyModuleNameIndex extends ScalarIndexExtension { @NotNull public static List find(@NotNull String name, @NotNull Project project, boolean includeNonProjectItems) { final List results = new ArrayList<>(); - final GlobalSearchScope scope = includeNonProjectItems + final GlobalSearchScope baseScope = includeNonProjectItems ? PySearchUtilBase.excludeSdkTestsScope(project) : GlobalSearchScope.projectScope(project); + final GlobalSearchScope scope = baseScope + .intersectWith(GlobalSearchScope.notScope(PyUserSkeletonsUtil.getUserSkeletonsDirectoryScope(project))); final Collection files = FileBasedIndex.getInstance().getContainingFiles(NAME, name, scope); for (VirtualFile virtualFile : files) { final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile); if (psiFile instanceof PyFile) { - if (!PyUserSkeletonsUtil.isUnderUserSkeletonsDirectory(psiFile)) { - results.add((PyFile)psiFile); - } + results.add((PyFile)psiFile); } } return results; diff --git a/python/testData/completion/className/pythonSkeletonsVariantsNotSuggested/pythonSkeletonsVariantsNotSuggested.py b/python/testData/completion/className/pythonSkeletonsVariantsNotSuggested/pythonSkeletonsVariantsNotSuggested.py new file mode 100644 index 000000000000..eb7e25cb8d1a --- /dev/null +++ b/python/testData/completion/className/pythonSkeletonsVariantsNotSuggested/pythonSkeletonsVariantsNotSuggested.py @@ -0,0 +1 @@ +nd diff --git a/python/testSrc/com/jetbrains/python/PyClassNameCompletionTest.java b/python/testSrc/com/jetbrains/python/PyClassNameCompletionTest.java index 2ee54383f31e..221fe1022f96 100644 --- a/python/testSrc/com/jetbrains/python/PyClassNameCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PyClassNameCompletionTest.java @@ -11,10 +11,13 @@ import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.testFramework.fixtures.TestLookupElementPresentation; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.codeInsight.PyCodeInsightSettings; +import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil; import com.jetbrains.python.fixtures.PyTestCase; import com.jetbrains.python.formatter.PyCodeStyleSettings; +import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyQualifiedNameOwner; import com.jetbrains.python.psi.resolve.QualifiedNameFinder; +import com.jetbrains.python.psi.stubs.PyClassNameIndex; import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -180,6 +183,18 @@ public class PyClassNameCompletionTest extends PyTestCase { assertEquals(" (pkg.mod)", varPresentation.getTailText()); } + // PY-45566 + public void testPythonSkeletonsVariantsNotSuggested() { + LookupElement[] lookupElements = doExtendedCompletion(); + + LookupElement ndarray = ContainerUtil.find(lookupElements, variant -> variant.getLookupString().equals("ndarray")); + assertNull(ndarray); + + PyClass ndarrayUserSkeleton = PyClassNameIndex.findClass("numpy.core.multiarray.ndarray", myFixture.getProject()); + assertNotNull(ndarrayUserSkeleton); + assertTrue(PyUserSkeletonsUtil.isUnderUserSkeletonsDirectory(ndarrayUserSkeleton.getContainingFile())); + } + private void doTest() { LookupElement[] lookupElements = doExtendedCompletion(); if (lookupElements != null) {