From 1b8eb3cff64a312f2ed4e14b7130218b307dd4fd Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Thu, 20 Jul 2017 17:50:25 +0300 Subject: [PATCH] PY-18816 In PyReferenceExpressionImpl require switch to AST permission only for fragments that, presumably, contain type hints stored in PSI stubs. Previous attempt to require passing an explicit instance of type eval context with the origin PSI file together with the resolve context, instead of just PyResolveContext#defaultContext() or PyResolveContext#noImplicits(), caused multiple test failures, since it turned out that there is much more code relying on the fact that if we were able to get hold of PyReferenceExpression, we're already in a file that was parsed, and, thus, we can safely perform reference multiresolve there. Changing all these existing usages is, first, cumbersome and, second, doesn't protect us from breakage in other subsystems not covered by tests. This workaround helps us to avoid unstubbing due to presence of code fragments needed to parse type annotations in stubs preserving the legacy behavior for the rest of the code. Additionally, I've reverted 0aa8039a3a70e4a16354c844def31157e6e73a86 where I explicitly set type eval context in several places as described. --- .../hierarchy/call/PyStaticCallHierarchyUtil.java | 3 +-- .../jetbrains/python/highlighting/PyRainbowVisitor.kt | 5 +---- .../inspections/PyGlobalUndefinedInspection.java | 4 +--- .../python/psi/impl/PyCallExpressionHelper.java | 3 ++- .../python/psi/impl/PyNamedParameterImpl.java | 3 +-- .../python/psi/impl/PyReferenceExpressionImpl.java | 4 +++- .../classes/membersManager/InstanceFieldsManager.java | 6 +----- .../classes/membersManager/PropertiesManager.java | 11 +---------- python/testSrc/com/jetbrains/python/PyTypingTest.java | 11 +++++++++++ 9 files changed, 22 insertions(+), 28 deletions(-) diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java b/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java index 3e061a0e84d8..e5f3276b5ed0 100644 --- a/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java +++ b/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java @@ -66,9 +66,8 @@ public class PyStaticCallHierarchyUtil { public void visitPyCallExpression(PyCallExpression node) { super.visitPyCallExpression(node); - final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(element.getProject(), null); StreamEx - .of(node.multiResolveCalleeFunction(PyResolveContext.defaultContext().withTypeEvalContext(typeEvalContext))) + .of(node.multiResolveCalleeFunction(PyResolveContext.defaultContext())) .select(PyFunction.class) .forEach(callees::add); } diff --git a/python/src/com/jetbrains/python/highlighting/PyRainbowVisitor.kt b/python/src/com/jetbrains/python/highlighting/PyRainbowVisitor.kt index 3f7ab5a2f368..a65651449e27 100644 --- a/python/src/com/jetbrains/python/highlighting/PyRainbowVisitor.kt +++ b/python/src/com/jetbrains/python/highlighting/PyRainbowVisitor.kt @@ -25,7 +25,6 @@ import com.jetbrains.python.codeInsight.controlflow.ScopeOwner import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil import com.jetbrains.python.psi.* import com.jetbrains.python.psi.resolve.PyResolveContext -import com.jetbrains.python.psi.types.TypeEvalContext class PyRainbowVisitor : RainbowVisitor() { @@ -90,9 +89,7 @@ class PyRainbowVisitor : RainbowVisitor() { val parent = targetExpression.parent if (parent is PyGlobalStatement) return targetExpression.containingFile if (parent is PyNonlocalStatement) { - val typeEvalContext = TypeEvalContext.codeAnalysis(targetExpression.project, targetExpression.containingFile) - val resolveContext = PyResolveContext.defaultContext().withTypeEvalContext(typeEvalContext) - val outerResolved = targetExpression.getReference(resolveContext).resolve() + val outerResolved = targetExpression.reference.resolve() return if (outerResolved is PyTargetExpression) getTargetContext(outerResolved) else null } diff --git a/python/src/com/jetbrains/python/inspections/PyGlobalUndefinedInspection.java b/python/src/com/jetbrains/python/inspections/PyGlobalUndefinedInspection.java index 1e9ca7c4c624..aa9bd97ced39 100644 --- a/python/src/com/jetbrains/python/inspections/PyGlobalUndefinedInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyGlobalUndefinedInspection.java @@ -21,7 +21,6 @@ import com.intellij.psi.PsiElementVisitor; import com.jetbrains.python.PyBundle; import com.jetbrains.python.psi.PyGlobalStatement; import com.jetbrains.python.psi.PyTargetExpression; -import com.jetbrains.python.psi.resolve.PyResolveContext; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -58,8 +57,7 @@ public class PyGlobalUndefinedInspection extends PyInspection { final PyTargetExpression[] globals = node.getGlobals(); for (PyTargetExpression global : globals) { - final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(myTypeEvalContext); - if (global.getReference(resolveContext).resolve() == global) { + if (global.getReference().resolve() == global) { registerProblem(global, PyBundle.message("INSP.NAME.global.$0.undefined", global.getName())); } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index 4703a00ec7d1..8289ae7d3bae 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -97,7 +97,8 @@ public class PyCallExpressionHelper { if (callee instanceof PyReferenceExpression) { // dereference PyReferenceExpression ref = (PyReferenceExpression)callee; - resolveResult = ref.followAssignmentsChain(PyResolveContext.noImplicits()); + final TypeEvalContext context = TypeEvalContext.codeAnalysis(us.getProject(), us.getContainingFile()); + resolveResult = ref.followAssignmentsChain(PyResolveContext.noImplicits().withTypeEvalContext(context)); resolved = resolveResult.getElement(); } else { diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index 1fbadf144c6f..976161e54c95 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -398,8 +398,7 @@ public class PyNamedParameterImpl extends PyBaseElementImpl members = new ArrayList<>(); - if (context.maySwitchToAST(this)) { + final PsiFile realFile = FileContextUtil.getContextFile(this); + if (!(getContainingFile() instanceof PyExpressionCodeFragment) || (realFile != null && context.maySwitchToAST(realFile))) { for (PsiElement target : PyUtil.multiResolveTopPriority(getReference(resolveContext))) { if (target == this || target == null) { continue; diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java index 681a86b02a83..dfc8b3fecb8b 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/InstanceFieldsManager.java @@ -21,8 +21,6 @@ import com.jetbrains.NotNullPredicate; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyFunctionBuilder; -import com.jetbrains.python.psi.resolve.PyResolveContext; -import com.jetbrains.python.psi.types.TypeEvalContext; import com.jetbrains.python.refactoring.classes.PyClassRefactoringUtil; import org.jetbrains.annotations.NotNull; @@ -135,9 +133,7 @@ class InstanceFieldsManager extends FieldsManager { private static class FieldsOnly extends NotNullPredicate { @Override protected boolean applyNotNull(@NotNull final PyTargetExpression input) { - final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(input.getProject(), null); - final PyResolveContext context = PyResolveContext.noImplicits().withTypeEvalContext(typeEvalContext); - return input.getReference(context).resolve() instanceof PyTargetExpression; + return input.getReference().resolve() instanceof PyTargetExpression; } } } diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/PropertiesManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/PropertiesManager.java index 26ac0985db43..84b0566885ec 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/PropertiesManager.java +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/PropertiesManager.java @@ -20,8 +20,6 @@ import com.intellij.psi.PsiReference; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.MultiMap; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.resolve.PyResolveContext; -import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -187,14 +185,7 @@ class PropertiesManager extends MembersManager { @Override public void visitPyExpression(final PyExpression node) { - final PsiReference reference; - if (node instanceof PyReferenceOwner) { - final TypeEvalContext context = TypeEvalContext.userInitiated(node.getProject(), null); - reference = ((PyReferenceOwner)node).getReference(PyResolveContext.noImplicits().withTypeEvalContext(context)); - } - else { - reference = node.getReference(); - } + final PsiReference reference = node.getReference(); if (reference == null) { return; } diff --git a/python/testSrc/com/jetbrains/python/PyTypingTest.java b/python/testSrc/com/jetbrains/python/PyTypingTest.java index fc168974c6ef..d9fc1aba9db3 100644 --- a/python/testSrc/com/jetbrains/python/PyTypingTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypingTest.java @@ -974,6 +974,17 @@ public class PyTypingTest extends PyTestCase { " expr: Alias = g()"); } + // TODO same test for variable type comments + // PY-18816 + public void testLocalTypeAliasInFunctionTypeComment() { + doTest("int", + "def func():\n" + + " Alias = int\n" + + " def g(x):\n" + + " # type: (Alias) -> None\n" + + " expr = x\n"); + } + private void doTestNoInjectedText(@NotNull String text) { myFixture.configureByText(PythonFileType.INSTANCE, text); final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject());