copletion in case of null in dataflow now works, also fixed case with isinstance with tuple (PY-1175)

This commit is contained in:
Dmitry Trofimov
2010-07-08 12:44:10 +04:00
parent 772b040978
commit a8be80684e
10 changed files with 92 additions and 13 deletions

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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) {

View 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()

View 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>

View File

@@ -110,6 +110,10 @@ public class PythonCompletionTest extends PyLightFixtureTestCase {
doTest();
}
public void testIsInstanceTuple() throws Exception {
doTest();
}
public void testPropertyParens() throws Exception { // PY-1037
doTest();
}