mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
copletion in case of null in dataflow now works, also fixed case with isinstance with tuple (PY-1175)
This commit is contained in:
@@ -35,12 +35,34 @@ public class PyAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
PyExpression[] args = node.getArguments();
|
||||
if (args.length == 2 && args[0] instanceof PyReferenceExpression) {
|
||||
PyReferenceExpression target = (PyReferenceExpression)args[0];
|
||||
Assertion o = new Assertion(target.getName(), args[1]);
|
||||
myStack.push(o);
|
||||
PyExpression typeElement = args[1];
|
||||
|
||||
if (!processTuple(target, typeElement)) {
|
||||
pushTypeElement(target, typeElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processTuple(PyReferenceExpression target, PyExpression typeElement) {
|
||||
boolean pushed = false;
|
||||
if (typeElement instanceof PyParenthesizedExpression) {
|
||||
PyExpression contained = ((PyParenthesizedExpression)typeElement).getContainedExpression();
|
||||
if (contained instanceof PyTupleExpression) {
|
||||
for (PyExpression e : ((PyTupleExpression)contained).getElements()) {
|
||||
pushTypeElement(target, e);
|
||||
pushed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pushed;
|
||||
}
|
||||
|
||||
private void pushTypeElement(PyReferenceExpression target, PyExpression typeElement) {
|
||||
Assertion o = new Assertion(target.getName(), typeElement);
|
||||
myStack.push(o);
|
||||
}
|
||||
|
||||
class Assertion {
|
||||
private final String name;
|
||||
private final PyElement element;
|
||||
@@ -57,6 +79,7 @@ public class PyAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
public PyElement getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<Assertion> getDefinitions() {
|
||||
|
||||
@@ -17,8 +17,8 @@ public class ReadWriteInstruction extends InstructionImpl {
|
||||
private final boolean isRead;
|
||||
|
||||
ACCESS(boolean read, boolean write) {
|
||||
isWrite = write;
|
||||
isRead = read;
|
||||
isWrite = write;
|
||||
}
|
||||
public boolean isWriteAccess(){
|
||||
return isWrite;
|
||||
|
||||
@@ -133,7 +133,7 @@ public class PyQualifiedReferenceImpl extends PyReferenceImpl {
|
||||
PyExpression qualifier = myElement.getQualifier();
|
||||
assert qualifier != null;
|
||||
|
||||
PyType qualifierType = qualifier.getType(TypeEvalContext.slow());
|
||||
PyType qualifierType = qualifier.getType(TypeEvalContext.variants());
|
||||
ProcessingContext ctx = new ProcessingContext();
|
||||
final Set<String> namesAlready = new HashSet<String>();
|
||||
ctx.put(PyType.CTX_NAMES, namesAlready);
|
||||
|
||||
@@ -18,7 +18,6 @@ import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.resolve.*;
|
||||
import com.jetbrains.python.psi.types.*;
|
||||
import com.jetbrains.python.refactoring.PyDefUseUtil;
|
||||
import com.jetbrains.python.toolbox.Maybe;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -281,7 +280,7 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
|
||||
if (defs.length > 0) {
|
||||
PyType type = getTypeIfExpr(defs[0], context);
|
||||
for (int i = 1; i < defs.length; i++) {
|
||||
type = PyUnionType.union(type, getTypeIfExpr(defs[i], context));
|
||||
type = PyUnionType.union(type, getTypeIfExpr(defs[i], context), context.allowNulls());
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -55,6 +55,19 @@ public class PyUnionType implements PyType {
|
||||
}, ", ") + ")";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PyType union(PyType type1, PyType type2, boolean allowNulls) {
|
||||
if (allowNulls) {
|
||||
if (type1 == null) {
|
||||
return type2;
|
||||
}
|
||||
if (type2 == null) {
|
||||
return type1;
|
||||
}
|
||||
}
|
||||
return union(type1, type2);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PyType union(PyType type1, PyType type2) {
|
||||
if (type1 instanceof PyTupleType && type2 instanceof PyTupleType) {
|
||||
@@ -64,20 +77,20 @@ public class PyUnionType implements PyType {
|
||||
int count = tupleType1.getElementCount();
|
||||
PyType[] members = new PyType[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
members [i] = union(tupleType1.getElementType(i), tupleType2.getElementType(i));
|
||||
members[i] = union(tupleType1.getElementType(i), tupleType2.getElementType(i));
|
||||
}
|
||||
return new PyTupleType(tupleType1, members);
|
||||
}
|
||||
}
|
||||
Set<PyType> members = new HashSet<PyType>();
|
||||
if (type1 instanceof PyUnionType) {
|
||||
members.addAll(((PyUnionType) type1).myMembers);
|
||||
members.addAll(((PyUnionType)type1).myMembers);
|
||||
}
|
||||
else {
|
||||
members.add(type1);
|
||||
}
|
||||
if (type2 instanceof PyUnionType) {
|
||||
members.addAll(((PyUnionType) type2).myMembers);
|
||||
members.addAll(((PyUnionType)type2).myMembers);
|
||||
}
|
||||
else {
|
||||
members.add(type2);
|
||||
|
||||
@@ -11,6 +11,8 @@ import java.util.Map;
|
||||
*/
|
||||
public class TypeEvalContext {
|
||||
private boolean myAllowDataFlow;
|
||||
private boolean allowNulls = false;
|
||||
|
||||
private Map<PyExpression, PyType> myEvaluated = new HashMap<PyExpression, PyType>();
|
||||
|
||||
private TypeEvalContext(boolean allowDataFlow) {
|
||||
@@ -25,6 +27,15 @@ public class TypeEvalContext {
|
||||
return myAllowDataFlow;
|
||||
}
|
||||
|
||||
|
||||
public static TypeEvalContext variants() {
|
||||
TypeEvalContext context = slow();
|
||||
context.allowNulls = true;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
public static TypeEvalContext slow() {
|
||||
return new TypeEvalContext(true);
|
||||
}
|
||||
@@ -42,4 +53,8 @@ public class TypeEvalContext {
|
||||
myEvaluated.put(expr, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean allowNulls() {
|
||||
return allowNulls;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ import java.util.HashSet;
|
||||
* @author Dennis.Ushakov
|
||||
*/
|
||||
public class PyDefUseUtil {
|
||||
private PyDefUseUtil() {}
|
||||
private PyDefUseUtil() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PyElement[] getLatestDefs(ScopeOwner block, PyElement var, PsiElement anchor) {
|
||||
@@ -50,8 +51,10 @@ public class PyDefUseUtil {
|
||||
name = instruction.getName();
|
||||
}
|
||||
if (access.isWriteAccess() && Comparing.strEqual(name, var.getName())) {
|
||||
result.add((PyElement) instruction.getElement());
|
||||
return;
|
||||
result.add((PyElement)instruction.getElement());
|
||||
if (access != ReadWriteInstruction.ACCESS.WRITETYPE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Instruction instruction : instructions[instr].allPred()) {
|
||||
@@ -73,7 +76,11 @@ public class PyDefUseUtil {
|
||||
return result.toArray(new PyElement[result.size()]);
|
||||
}
|
||||
|
||||
private static void getPostRefs(PyTargetExpression var, Instruction[] instructions, int instr, boolean[] visited, Collection<PyElement> result) {
|
||||
private static void getPostRefs(PyTargetExpression var,
|
||||
Instruction[] instructions,
|
||||
int instr,
|
||||
boolean[] visited,
|
||||
Collection<PyElement> result) {
|
||||
if (visited[instr]) return;
|
||||
visited[instr] = true;
|
||||
if (instructions[instr] instanceof ReadWriteInstruction) {
|
||||
|
||||
9
python/testData/completion/isInstanceTuple.after.py
Normal file
9
python/testData/completion/isInstanceTuple.after.py
Normal file
@@ -0,0 +1,9 @@
|
||||
class Foo:
|
||||
def test(self): pass
|
||||
|
||||
class Foo2:
|
||||
def test(self): pass
|
||||
|
||||
def x(p):
|
||||
if isinstance(p, (Foo, Foo2)):
|
||||
p.test()
|
||||
9
python/testData/completion/isInstanceTuple.py
Normal file
9
python/testData/completion/isInstanceTuple.py
Normal file
@@ -0,0 +1,9 @@
|
||||
class Foo:
|
||||
def test(self): pass
|
||||
|
||||
class Foo2:
|
||||
def test(self): pass
|
||||
|
||||
def x(p):
|
||||
if isinstance(p, (Foo, Foo2)):
|
||||
p.te<caret>
|
||||
@@ -110,6 +110,10 @@ public class PythonCompletionTest extends PyLightFixtureTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIsInstanceTuple() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testPropertyParens() throws Exception { // PY-1037
|
||||
doTest();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user