From 1df8d5baa56164cc08d0c224474693c6d5af981a Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 23 Apr 2013 18:29:43 +0400 Subject: [PATCH 1/2] Pass 'inherited' resolve flag to PyType ancestors --- .../com/jetbrains/python/psi/types/PyImportedModuleType.java | 2 +- python/src/com/jetbrains/python/psi/types/PyUnionType.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java index cfa0d325d2a6..90edfdffd197 100644 --- a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java @@ -42,7 +42,7 @@ public class PyImportedModuleType implements PyType { final PsiElement resolved = myImportedModule.resolve(); if (resolved instanceof PyFile) { final PyFile file = (PyFile)resolved; - return new PyModuleType(file, myImportedModule).resolveMember(name, location, direction, resolveContext, true); + return new PyModuleType(file, myImportedModule).resolveMember(name, location, direction, resolveContext, inherited); } else if (resolved instanceof PsiDirectory) { final List elements = Collections.singletonList(ResolveImportUtil.resolveChild(resolved, name, null, true, true)); diff --git a/python/src/com/jetbrains/python/psi/types/PyUnionType.java b/python/src/com/jetbrains/python/psi/types/PyUnionType.java index ca774a21f61a..01d5ab3e7b86 100644 --- a/python/src/com/jetbrains/python/psi/types/PyUnionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyUnionType.java @@ -32,7 +32,7 @@ public class PyUnionType implements PyType { boolean all_nulls = true; for (PyType member : myMembers) { if (member != null) { - List result = member.resolveMember(name, null, direction, resolveContext, true); + List result = member.resolveMember(name, null, direction, resolveContext, inherited); if (result != null) { all_nulls = false; ret.addAll(result); From 14212790f49ffe0686e624f491127dec2b0fc27c Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 23 Apr 2013 21:08:08 +0400 Subject: [PATCH 2/2] Added 'isinstance' checks for qualified references (PY-5614) --- .../controlflow/InstructionBuilder.java | 5 +- .../psi/impl/PyReferenceExpressionImpl.java | 62 ++++++++++++++----- .../psi/impl/PyTargetExpressionImpl.java | 4 ++ .../python/refactoring/PyDefUseUtil.java | 7 +++ .../com/jetbrains/python/PyTypeTest.java | 39 ++++++++++++ 5 files changed, 101 insertions(+), 16 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/controlflow/InstructionBuilder.java b/python/src/com/jetbrains/python/codeInsight/controlflow/InstructionBuilder.java index 724036f7d11d..0983aa0b1a25 100644 --- a/python/src/com/jetbrains/python/codeInsight/controlflow/InstructionBuilder.java +++ b/python/src/com/jetbrains/python/codeInsight/controlflow/InstructionBuilder.java @@ -4,6 +4,7 @@ import com.google.common.collect.Lists; import com.intellij.codeInsight.controlflow.ControlFlowBuilder; import com.intellij.codeInsight.controlflow.Instruction; import com.jetbrains.python.psi.PyReferenceExpression; +import com.jetbrains.python.psi.impl.PyQualifiedName; import java.util.List; @@ -18,7 +19,9 @@ public class InstructionBuilder { List result = Lists.newArrayList(); for (PyTypeAssertionEvaluator.Assertion def: assertions) { final PyReferenceExpression e = def.getElement(); - result.add(ReadWriteInstruction.assertType(builder, e, e.getName(), def.getTypeEvalFunction())); + final PyQualifiedName qname = e.asQualifiedName(); + final String name = qname != null ? qname.toString() : e.getName(); + result.add(ReadWriteInstruction.assertType(builder, e, name, def.getTypeEvalFunction())); } return result; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index 18614a0007f3..2df5a5830d2b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -16,6 +16,7 @@ import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PythonDialectsTokenSetProvider; import com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; +import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.console.PydevConsoleRunner; import com.jetbrains.python.console.completion.PydevConsoleReference; import com.jetbrains.python.console.pydev.ConsoleCommunication; @@ -204,7 +205,9 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere } } ResolveResult[] targets = getReference(PyResolveContext.noImplicits().withTypeEvalContext(context)).multiResolve(false); - if (targets.length == 0) return null; + if (targets.length == 0) { + return getQualifiedReferenceTypeByControlFlow(context); + } for (ResolveResult resolveResult : targets) { PsiElement target = resolveResult.getElement(); if (target == this || target == null) { @@ -226,6 +229,24 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere } } + @Nullable + public PyType getQualifiedReferenceTypeByControlFlow(@NotNull TypeEvalContext context) { + PyExpression qualifier = getQualifier(); + if (context.allowDataFlow(this) && qualifier != null) { + PyExpression next = qualifier; + while (next != null) { + qualifier = next; + next = qualifier instanceof PyQualifiedExpression ? ((PyQualifiedExpression)qualifier).getQualifier() : null; + } + final ScopeOwner scopeOwner = ScopeUtil.getScopeOwner(this); + final PyQualifiedName qname = asQualifiedName(); + if (qname != null && scopeOwner != null) { + return getTypeByControlFlow(qname.toString(), context, qualifier, scopeOwner); + } + } + return null; + } + @Nullable public Ref getTypeOfProperty(@NotNull TypeEvalContext context) { final PyExpression qualifier = getQualifier(); @@ -309,23 +330,13 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere if ((target instanceof PyTargetExpression || target instanceof PyNamedParameter) && anchor != null && context.allowDataFlow(anchor)) { final ScopeOwner scopeOwner = PsiTreeUtil.getStubOrPsiParentOfType(anchor, ScopeOwner.class); if (scopeOwner != null && scopeOwner == PsiTreeUtil.getStubOrPsiParentOfType(target, ScopeOwner.class)) { - PyAugAssignmentStatement augAssignment = PsiTreeUtil.getParentOfType(anchor, PyAugAssignmentStatement.class); - try { - final List defs = PyDefUseUtil.getLatestDefs(scopeOwner, - ((PyElement)target).getName(), - augAssignment != null ? augAssignment : anchor, - true); - if (!defs.isEmpty()) { - PyType type = defs.get(0).getType(context, anchor); - for (int i = 1; i < defs.size(); i++) { - type = PyUnionType.union(type, defs.get(i).getType(context, anchor)); - } + final String name = ((PyElement)target).getName(); + if (name != null) { + final PyType type = getTypeByControlFlow(name, context, anchor, scopeOwner); + if (type != null) { return type; } } - catch (PyDefUseUtil.InstructionNotFoundException e) { - // ignore - } } } if (target instanceof PyFunction) { @@ -356,6 +367,27 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere return null; } + private static PyType getTypeByControlFlow(@NotNull String name, + @NotNull TypeEvalContext context, + @NotNull PyExpression anchor, + @NotNull ScopeOwner scopeOwner) { + PyAugAssignmentStatement augAssignment = PsiTreeUtil.getParentOfType(anchor, PyAugAssignmentStatement.class); + try { + final PyElement element = augAssignment != null ? augAssignment : anchor; + final List defs = PyDefUseUtil.getLatestDefs(scopeOwner, name, element, true); + if (!defs.isEmpty()) { + PyType type = defs.get(0).getType(context, anchor); + for (int i = 1; i < defs.size(); i++) { + type = PyUnionType.union(type, defs.get(i).getType(context, anchor)); + } + return type; + } + } + catch (PyDefUseUtil.InstructionNotFoundException ignored) { + } + return null; + } + @Nullable public static PyType getReferenceTypeFromProviders(@NotNull final PsiElement target, TypeEvalContext context, diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index 9da2e5cded3b..6ff0197e7662 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -160,6 +160,10 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl