mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'python-fixes'
This commit is contained in:
@@ -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<Instruction> 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;
|
||||
}
|
||||
|
||||
@@ -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<PyType> 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<ReadWriteInstruction> 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<ReadWriteInstruction> 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,
|
||||
|
||||
@@ -160,6 +160,10 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
|
||||
if (typeOfProperty != null) {
|
||||
return typeOfProperty.get();
|
||||
}
|
||||
final PyType cfgType = refex.getQualifiedReferenceTypeByControlFlow(context);
|
||||
if (cfgType != null) {
|
||||
return cfgType;
|
||||
}
|
||||
return typeFromTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<PsiElement> elements = Collections.singletonList(ResolveImportUtil.resolveChild(resolved, name, null, true, true));
|
||||
|
||||
@@ -32,7 +32,7 @@ public class PyUnionType implements PyType {
|
||||
boolean all_nulls = true;
|
||||
for (PyType member : myMembers) {
|
||||
if (member != null) {
|
||||
List<? extends RatedResolveResult> result = member.resolveMember(name, null, direction, resolveContext, true);
|
||||
List<? extends RatedResolveResult> result = member.resolveMember(name, null, direction, resolveContext, inherited);
|
||||
if (result != null) {
|
||||
all_nulls = false;
|
||||
ret.addAll(result);
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyAugAssignmentStatementNavigator;
|
||||
import com.jetbrains.python.psi.impl.PyQualifiedName;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -75,6 +76,12 @@ public class PyDefUseUtil {
|
||||
if (element instanceof PyImportElement) {
|
||||
return ((PyImportElement) element).getVisibleName();
|
||||
}
|
||||
if (element instanceof PyReferenceExpression) {
|
||||
final PyQualifiedName qname = ((PyReferenceExpression)element).asQualifiedName();
|
||||
if (qname != null) {
|
||||
return qname.toString();
|
||||
}
|
||||
}
|
||||
return element instanceof PyElement ? ((PyElement)element).getName() : null;
|
||||
}
|
||||
|
||||
|
||||
@@ -497,6 +497,45 @@ public class PyTypeTest extends PyTestCase {
|
||||
" expr = x\n");
|
||||
}
|
||||
|
||||
// PY-5614
|
||||
public void testUnknownReferenceTypeAttribute() {
|
||||
doTest("str",
|
||||
"def f(x):\n" +
|
||||
" if isinstance(x.foo, str):\n" +
|
||||
" expr = x.foo\n");
|
||||
}
|
||||
|
||||
// PY-5614
|
||||
public void testUnknownTypeAttribute() {
|
||||
doTest("str",
|
||||
"class C(object):\n" +
|
||||
" def __init__(self, foo):\n" +
|
||||
" self.foo = foo\n" +
|
||||
" def f(self):\n" +
|
||||
" if isinstance(self.foo, str):\n" +
|
||||
" expr = self.foo\n");
|
||||
}
|
||||
|
||||
// PY-5614
|
||||
public void testKnownTypeAttribute() {
|
||||
doTest("str",
|
||||
"class C(object):\n" +
|
||||
" def __init__(self):\n" +
|
||||
" self.foo = 42\n" +
|
||||
" def f(self):\n" +
|
||||
" if isinstance(self.foo, str):\n" +
|
||||
" expr = self.foo\n");
|
||||
}
|
||||
|
||||
// PY-5614
|
||||
public void testNestedUnknownReferenceTypeAttribute() {
|
||||
doTest("str",
|
||||
"def f(x):\n" +
|
||||
" if isinstance(x.foo.bar, str):\n" +
|
||||
" expr = x.foo.bar\n");
|
||||
|
||||
}
|
||||
|
||||
private PyExpression parseExpr(String text) {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, text);
|
||||
return myFixture.findElementByText("expr", PyExpression.class);
|
||||
|
||||
Reference in New Issue
Block a user