Fixes wrong mapping of subscribed assignment targets (PY-247); adds tests.

This commit is contained in:
Dmitry Cheryasov
2009-12-11 10:01:22 +02:00
parent e3cbb528df
commit 970d8dacbc
10 changed files with 171 additions and 12 deletions
@@ -20,17 +20,14 @@ import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.ResolveState;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.HashMap;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.toolbox.FP;
import com.jetbrains.python.toolbox.RepeatIterable;
import com.jetbrains.python.toolbox.RepeatIterator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -98,21 +95,21 @@ public class PyAssignmentStatementImpl extends PyElementImpl implements PyAssign
private static void mapToValues(PyExpression lhs, PyExpression rhs, List<Pair<PyExpression, PyExpression>> map) {
// cast for convenience
PyTupleExpression lhs_tuple = null;
PyTargetExpression lhs_target = null;
PyExpression lhs_one = null;
if (lhs instanceof PyTupleExpression) lhs_tuple = (PyTupleExpression)lhs;
else if (lhs instanceof PyTargetExpression) lhs_target = (PyTargetExpression)lhs;
else if (lhs != null) lhs_one = lhs;
PyTupleExpression rhs_tuple = null;
PyTargetExpression rhs_target = null;
PyExpression rhs_one = null;
if (rhs instanceof PyTupleExpression) rhs_tuple = (PyTupleExpression)rhs;
else if (rhs instanceof PyTargetExpression) rhs_target = (PyTargetExpression)rhs;
else if (rhs != null) rhs_one = rhs;
//
if (lhs_target != null) { // single LHS, single RHS (direct mapping) or multiple RHS (packing)
map.add(new Pair<PyExpression, PyExpression>(lhs_target, rhs));
if (lhs_one != null) { // single LHS, single RHS (direct mapping) or multiple RHS (packing)
map.add(new Pair<PyExpression, PyExpression>(lhs_one, rhs));
}
else if (lhs_tuple != null && rhs_target != null) { // multiple LHS, single RHS: unpacking
//for (PyExpression tuple_elt : lhs_tuple.getElements()) map.add(new Pair<PyExpression, PyExpression>(tuple_elt, rhs_target));
map.addAll(FP.zipList(lhs_tuple, new RepeatIterable<PyExpression>(rhs_target)));
else if (lhs_tuple != null && rhs_one != null) { // multiple LHS, single RHS: unpacking
//for (PyExpression tuple_elt : lhs_tuple.getElements()) map.add(new Pair<PyExpression, PyExpression>(tuple_elt, rhs_one));
map.addAll(FP.zipList(lhs_tuple, new RepeatIterable<PyExpression>(rhs_one)));
}
else if (lhs_tuple != null && rhs_tuple != null) { // multiple both sides: piecewise mapping
map.addAll(FP.zipList(lhs_tuple, rhs_tuple, null, null));
@@ -0,0 +1 @@
<dst1>a = <dst2>b = <dst3>c = <src>1
+1
View File
@@ -0,0 +1 @@
<dst>a = <src>"foo"
@@ -0,0 +1 @@
<dst>a = <src>foo['bar']
@@ -0,0 +1 @@
<dst>foo['bar'] = <src>1
@@ -0,0 +1 @@
<dst1>a, <dst2>b = <src1>1, <src2>2
@@ -0,0 +1 @@
<dst>some_tuple = <src1>1, <src2>2
@@ -0,0 +1 @@
<dst1>a, <dst2>b = <src>some_tuple
@@ -0,0 +1,154 @@
package com.jetbrains.python;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.psi.PyAssignmentStatement;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyTargetExpression;
import com.jetbrains.python.psi.PySubscriptionExpression;
import java.util.List;
import java.util.Map;
/**
* Tests assignment mapping and tracking.
* User: dcheryasov
* Date: Dec 11, 2009 2:13:51 AM
*/
public class PyAssignmentMappingTest extends MarkedTestCase {
public String getTestDataPath() {
return PythonTestUtil.getTestDataPath() + "/psi/assignment/";
}
public void testSimple() throws Exception {
Map<String, PsiElement> marks = loadTest();
assertEquals(2, marks.size());
PsiElement src = marks.get("<src>").getParent(); // const -> expr;
PsiElement dst = marks.get("<dst>").getParent(); // ident -> target expr
assertTrue(dst instanceof PyTargetExpression);
PyAssignmentStatement stmt = (PyAssignmentStatement)dst.getParent();
List<Pair<PyExpression, PyExpression>> mapping = stmt.getTargetsToValuesMapping();
assertEquals(1, mapping.size());
Pair<PyExpression, PyExpression> pair = mapping.get(0);
assertEquals(dst, pair.getFirst());
assertEquals(src, pair.getSecond());
}
public void testSubscribedSource() throws Exception {
Map<String, PsiElement> marks = loadTest();
assertEquals(2, marks.size());
PsiElement src = marks.get("<src>").getParent().getParent(); // const -> ref foo -> subscr expr;
PsiElement dst = marks.get("<dst>").getParent(); // ident -> target expr
assertTrue(dst instanceof PyTargetExpression);
PyAssignmentStatement stmt = (PyAssignmentStatement)dst.getParent();
List<Pair<PyExpression, PyExpression>> mapping = stmt.getTargetsToValuesMapping();
assertEquals(1, mapping.size());
Pair<PyExpression, PyExpression> pair = mapping.get(0);
assertEquals(dst, pair.getFirst());
assertEquals(src, pair.getSecond());
}
public void testSubscribedTarget() throws Exception {
Map<String, PsiElement> marks = loadTest();
assertEquals(2, marks.size());
PsiElement src = marks.get("<src>").getParent(); // const -> expr;
PsiElement dst = marks.get("<dst>").getParent().getParent(); // ident -> target expr
assertTrue(dst instanceof PySubscriptionExpression);
PyAssignmentStatement stmt = (PyAssignmentStatement)src.getParent();
List<Pair<PyExpression, PyExpression>> mapping = stmt.getTargetsToValuesMapping();
assertEquals(1, mapping.size());
Pair<PyExpression, PyExpression> pair = mapping.get(0);
assertEquals(dst, pair.getFirst());
assertEquals(src, pair.getSecond());
}
public void testMultiple() throws Exception {
Map<String, PsiElement> marks = loadTest();
final int TARGET_NUM = 3;
assertEquals(TARGET_NUM+1, marks.size());
PsiElement src = marks.get("<src>").getParent(); // const -> expr;
PsiElement[] dsts = new PsiElement[TARGET_NUM];
for (int i=0; i<TARGET_NUM; i+=1) {
PsiElement dst = marks.get("<dst" + String.valueOf(i+1) +">").getParent(); // ident -> target expr
assertTrue(dst instanceof PyTargetExpression);
dsts[i] = dst;
}
PyAssignmentStatement stmt = (PyAssignmentStatement)src.getParent();
List<Pair<PyExpression, PyExpression>> mapping = stmt.getTargetsToValuesMapping();
assertEquals(TARGET_NUM, mapping.size());
for (int i=0; i<TARGET_NUM; i+=1) {
Pair<PyExpression, PyExpression> pair = mapping.get(i);
assertEquals(dsts[i], pair.getFirst());
assertEquals(src, pair.getSecond());
}
}
public void testTupleMapped() throws Exception {
Map<String, PsiElement> marks = loadTest();
final int PAIR_NUM = 2;
assertEquals(PAIR_NUM*2, marks.size());
PsiElement[] srcs = new PsiElement[PAIR_NUM];
PsiElement[] dsts = new PsiElement[PAIR_NUM];
for (int i=0; i<PAIR_NUM; i+=1) {
PsiElement dst = marks.get("<dst" + String.valueOf(i+1) +">").getParent(); // ident -> target expr
assertTrue(dst instanceof PyTargetExpression);
dsts[i] = dst;
PsiElement src = marks.get("<src" + String.valueOf(i+1) +">").getParent(); // ident -> target expr
assertTrue(src instanceof PyExpression);
srcs[i] = src;
}
PyAssignmentStatement stmt = (PyAssignmentStatement)srcs[0].getParent().getParent(); // tuple expr -> assignment
List<Pair<PyExpression, PyExpression>> mapping = stmt.getTargetsToValuesMapping();
assertEquals(PAIR_NUM, mapping.size());
for (int i=0; i<PAIR_NUM; i+=1) {
Pair<PyExpression, PyExpression> pair = mapping.get(i);
assertEquals(dsts[i], pair.getFirst());
assertEquals(srcs[i], pair.getSecond());
}
}
public void testTuplePack() throws Exception {
Map<String, PsiElement> marks = loadTest();
final int SRC_NUM = 2;
assertEquals(SRC_NUM+1, marks.size());
PsiElement[] srcs = new PsiElement[SRC_NUM];
for (int i=0; i<SRC_NUM; i+=1) {
PsiElement src = marks.get("<src" + String.valueOf(i+1) +">").getParent(); // ident -> target expr
assertTrue(src instanceof PyExpression);
srcs[i] = src;
}
PsiElement dst = marks.get("<dst>").getParent(); // ident -> target expr
PyAssignmentStatement stmt = (PyAssignmentStatement)dst.getParent();
List<Pair<PyExpression, PyExpression>> mapping = stmt.getTargetsToValuesMapping();
assertEquals(1, mapping.size());
Pair<PyExpression, PyExpression> pair = mapping.get(0);
assertEquals(dst, pair.getFirst());
for (PsiElement src : srcs) {
assertEquals(src.getParent(), pair.getSecond()); // numeric expr -> tuple
}
}
public void testTupleUnpack() throws Exception {
Map<String, PsiElement> marks = loadTest();
final int DST_NUM = 2;
assertEquals(DST_NUM+1, marks.size());
PsiElement[] dsts = new PsiElement[DST_NUM];
for (int i=0; i<DST_NUM; i+=1) {
PsiElement dst = marks.get("<dst" + String.valueOf(i+1) +">").getParent(); // ident -> target expr
assertTrue(dst instanceof PyTargetExpression);
dsts[i] = dst;
}
PsiElement src = marks.get("<src>").getParent(); // ident -> target expr
PyAssignmentStatement stmt = (PyAssignmentStatement)src.getParent();
List<Pair<PyExpression, PyExpression>> mapping = stmt.getTargetsToValuesMapping();
assertEquals(DST_NUM, mapping.size());
for (int i=0; i<DST_NUM; i+=1) {
Pair<PyExpression, PyExpression> pair = mapping.get(i);
assertEquals(dsts[i], pair.getFirst());
assertEquals(src, pair.getSecond());
}
}
}
@@ -20,6 +20,7 @@ public class PythonAllTestsSuite {
PyMultiFileResolveTest.class,
PyResolveCalleeTest.class,
PyToJavaResolveTest.class,
PyAssignmentTrackingTest.class,
PythonCompletionTest.class,
PyInheritorsSearchTest.class,
PyParameterInfoTest.class,