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.
This commit is contained in:
Mikhail Golubev
2017-07-19 19:28:31 +03:00
parent fa59ae276b
commit 388ee93846
3 changed files with 15 additions and 15 deletions
@@ -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<RatedResolveResult> 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<String> components = new ArrayList<>();
@@ -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<OrderEntry> orderEntries = projectRootManager.getFileIndex().getOrderEntriesForFile(vfile);
@@ -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