From 388ee9384675221bc693e76cfd77f4cc24b93e30 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Tue, 20 Jun 2017 18:15:54 +0300 Subject: [PATCH] PY-18816 PyBuiltinCache#findSdkForNonModuleFile() handles code fragments Otherwise, a few tests kept failing because it was impossible to find the standard "tuple" class using an expression from an annotation (like "Tuple[T1, T2]") in .pyi stub as the anchor. Note that ModuleUtilCore#findModuleForPsiElement(), used in PyBuiltinCache#findSdkForFile(), already does that internally. Also, use the standard FileContextUtil.getContextFile() method from the platform wherever possible in PyTypingTypeProvider. --- .../codeInsight/typing/PyTypingTypeProvider.java | 13 +++---------- .../jetbrains/python/psi/impl/PyBuiltinCache.java | 15 +++++++++++---- .../python/psi/resolve/PyResolveImportUtil.kt | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java index e38294faa892..70fd41182bee 100644 --- a/python/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java @@ -22,11 +22,11 @@ import com.google.common.collect.Sets; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; +import com.intellij.psi.impl.source.resolve.FileContextUtil; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; -import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; @@ -614,7 +614,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { @Nullable private static PyExpression createExpressionFromFragment(@NotNull String contents, @NotNull PsiElement anchor) { final PyExpressionCodeFragmentImpl codeFragment = new PyExpressionCodeFragmentImpl(anchor.getProject(), "dummy.py", contents, false); - codeFragment.setContext(getFragmentContainingFile(anchor)); + codeFragment.setContext(FileContextUtil.getContextFile(anchor)); final PyExpressionStatement statement = as(codeFragment.getFirstChild(), PyExpressionStatement.class); return statement != null ? statement.getExpression() : null; } @@ -816,7 +816,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { // PyPsiUtils.asQualifiedName() also takes into account subscription and prefix expressions final QualifiedName qualifiedName = makeQualifiedNameFromReferenceExpression(expression); - final PyFile pyFile = getFragmentContainingFile(expression); + final PyFile pyFile = as(FileContextUtil.getContextFile(expression), PyFile.class); if (pyFile != null && qualifiedName != null && qualifiedName.getComponentCount() > 0) { List results = new ArrayList<>(); @@ -855,13 +855,6 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { return Collections.singletonList(expression); } - @Nullable - private static PyFile getFragmentContainingFile(@NotNull PsiElement anchor) { - // PyExpressionCodeFragment#getContext() should return not-null value for expression fragments - final PsiElement contextElement = ObjectUtils.chooseNotNull(anchor.getContainingFile().getContext(), anchor); - return as(contextElement.getContainingFile(), PyFile.class); - } - @Nullable private static QualifiedName makeQualifiedNameFromReferenceExpression(@NotNull PyExpression expression) { final List components = new ArrayList<>(); diff --git a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java index fe853ee5e3f5..8e02c32cb1b8 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java @@ -26,6 +26,7 @@ import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.impl.ModuleLibraryOrderEntryImpl; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.FileContextUtil; import com.intellij.psi.util.QualifiedName; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.psi.*; @@ -104,12 +105,18 @@ public class PyBuiltinCache { } @Nullable - public static Sdk findSdkForNonModuleFile(PsiFileSystemItem psiFile) { - Project project = psiFile.getProject(); + public static Sdk findSdkForNonModuleFile(@NotNull PsiFileSystemItem psiFile) { + final VirtualFile vfile; + if (psiFile instanceof PsiFile) { + final PsiFile contextFile = FileContextUtil.getContextFile(psiFile); + vfile = contextFile != null ? contextFile.getOriginalFile().getVirtualFile() : null; + } + else { + vfile = psiFile.getVirtualFile(); + } Sdk sdk = null; - final VirtualFile vfile = psiFile instanceof PsiFile ? ((PsiFile) psiFile).getOriginalFile().getVirtualFile() : psiFile.getVirtualFile(); if (vfile != null) { // reality - final ProjectRootManager projectRootManager = ProjectRootManager.getInstance(project); + final ProjectRootManager projectRootManager = ProjectRootManager.getInstance(psiFile.getProject()); sdk = projectRootManager.getProjectSdk(); if (sdk == null) { final List orderEntries = projectRootManager.getFileIndex().getOrderEntriesForFile(vfile); diff --git a/python/src/com/jetbrains/python/psi/resolve/PyResolveImportUtil.kt b/python/src/com/jetbrains/python/psi/resolve/PyResolveImportUtil.kt index 2888c0c52445..5f44afd649f8 100644 --- a/python/src/com/jetbrains/python/psi/resolve/PyResolveImportUtil.kt +++ b/python/src/com/jetbrains/python/psi/resolve/PyResolveImportUtil.kt @@ -314,7 +314,7 @@ private fun findCache(context: PyQualifiedNameResolveContext): PythonPathCache? context.module != null -> if (context.effectiveSdk != context.sdk) null else PythonModulePathCache.getInstance(context.module) context.footholdFile != null -> { - val sdk = PyBuiltinCache.findSdkForNonModuleFile(context.footholdFile) + val sdk = PyBuiltinCache.findSdkForNonModuleFile(context.footholdFile!!) if (sdk != null) PythonSdkPathCache.getInstance(context.project, sdk) else null } else -> null