mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Include type inference for tuple multiplication in PyStdlibTypeProvider
Removed related logic from overly convoluted PyStringFormatInspection.
This commit is contained in:
@@ -135,7 +135,40 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
}
|
||||
else if ("__builtin__.tuple.__add__".equals(qname) && callSite instanceof PyBinaryExpression) {
|
||||
return getTupleConcatenationResultType(((PyBinaryExpression)callSite), context);
|
||||
return getTupleConcatenationResultType((PyBinaryExpression)callSite, context);
|
||||
}
|
||||
else if ("__builtin__.tuple.__mul__".equals(qname) && callSite instanceof PyBinaryExpression) {
|
||||
return getTupleMultiplicationResultType((PyBinaryExpression)callSite, context);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyType getTupleMultiplicationResultType(@NotNull PyBinaryExpression multiplication, @NotNull TypeEvalContext context) {
|
||||
final PyTupleType leftTupleType = as(context.getType(multiplication.getLeftExpression()), PyTupleType.class);
|
||||
if (leftTupleType == null) {
|
||||
return null;
|
||||
}
|
||||
PyExpression rightExpression = multiplication.getRightExpression();
|
||||
if (rightExpression instanceof PyReferenceExpression) {
|
||||
final PsiElement target = ((PyReferenceExpression)rightExpression).getReference().resolve();
|
||||
if (target instanceof PyTargetExpression) {
|
||||
rightExpression = ((PyTargetExpression)target).findAssignedValue();
|
||||
}
|
||||
}
|
||||
if (rightExpression instanceof PyNumericLiteralExpression && ((PyNumericLiteralExpression)rightExpression).isIntegerLiteral()) {
|
||||
final int multiplier = ((PyNumericLiteralExpression)rightExpression).getBigIntegerValue().intValue();
|
||||
final int originalSize = leftTupleType.getElementCount();
|
||||
// Heuristic
|
||||
if (originalSize * multiplier <= 20) {
|
||||
final PyType[] elementTypes = new PyType[leftTupleType.getElementCount() * multiplier];
|
||||
for (int i = 0; i < multiplier; i++) {
|
||||
for (int j = 0; j < originalSize; j++) {
|
||||
elementTypes[i * originalSize + j] = leftTupleType.getElementType(j);
|
||||
}
|
||||
}
|
||||
return PyTupleType.create(multiplication, elementTypes);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -102,39 +102,25 @@ public class PyStringFormatInspection extends PyInspection {
|
||||
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(problemTarget);
|
||||
final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(myTypeEvalContext);
|
||||
|
||||
//in case tuple multiplies integer PY-4647
|
||||
if (rightExpression instanceof PyBinaryExpression) {
|
||||
PyBinaryExpression binaryExpression = (PyBinaryExpression)rightExpression;
|
||||
if (binaryExpression.getOperator() == PyTokenTypes.MULT && binaryExpression.getLeftExpression() instanceof PyParenthesizedExpression
|
||||
&& binaryExpression.getRightExpression() instanceof PyNumericLiteralExpression) {
|
||||
PyParenthesizedExpression parenthesizedExpression = (PyParenthesizedExpression)binaryExpression.getLeftExpression();
|
||||
if (parenthesizedExpression.getContainedExpression() instanceof PyTupleExpression) {
|
||||
PyExpression[] tupleElements = ((PyTupleExpression)parenthesizedExpression.getContainedExpression()).getElements();
|
||||
final PyExpression expression = ((PyBinaryExpression)rightExpression).getRightExpression();
|
||||
if (expression != null) {
|
||||
return ((PyNumericLiteralExpression)expression).getBigIntegerValue().intValue() * tupleElements.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final String s = myFormatSpec.get("1");
|
||||
if (PyUtil.instanceOf(rightExpression, SIMPLE_RHS_EXPRESSIONS)) {
|
||||
if (s != null) {
|
||||
assert rightExpression != null;
|
||||
PyType right_type = myTypeEvalContext.getType(rightExpression);
|
||||
if (right_type instanceof PySubscriptableType) {
|
||||
PySubscriptableType tuple_type = (PySubscriptableType)right_type;
|
||||
for (int i=0; i <= tuple_type.getElementCount(); i += 1) {
|
||||
PyType elementType = tuple_type.getElementType(i);
|
||||
final PyType rightType = myTypeEvalContext.getType(rightExpression);
|
||||
if (rightType instanceof PySubscriptableType) {
|
||||
final PySubscriptableType tupleType = (PySubscriptableType)rightType;
|
||||
for (int i = 0; i <= tupleType.getElementCount(); i += 1) {
|
||||
final PyType elementType = tupleType.getElementType(i);
|
||||
if (elementType != null) {
|
||||
final String typeName = myFormatSpec.get(String.valueOf(i + 1));
|
||||
final PyType type = typeName != null ? PyTypeParser.getTypeByName(problemTarget, typeName) : null;
|
||||
checkTypeCompatible(problemTarget, elementType, type);
|
||||
}
|
||||
}
|
||||
return tuple_type.getElementCount();
|
||||
return tupleType.getElementCount();
|
||||
}
|
||||
else {
|
||||
checkExpressionType(rightExpression, s, problemTarget);
|
||||
}
|
||||
else checkExpressionType(rightExpression, s, problemTarget);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -10,4 +10,7 @@ my_dict['tmp'] = 'classes %(claz)s' % <warning descr="Key 'claz' has no followin
|
||||
|
||||
#PY-4647
|
||||
argument_pattern = re.compile(r'(%s)\s*(\(\s*(%s)\s*\)\s*)?$'
|
||||
% ((states.Inliner.simplename,) * 2))
|
||||
% ((states.Inliner.simplename,) * 2))
|
||||
|
||||
t, num = ('foo',), 2
|
||||
res = '%d %d' % (<warning descr="Unexpected type str"><warning descr="Unexpected type str">t * num</warning></warning>)
|
||||
@@ -848,6 +848,11 @@ public class PyTypeTest extends PyTestCase {
|
||||
"expr = (1,) + (True, 'spam') + ()");
|
||||
}
|
||||
|
||||
public void testTupleMultiplication() {
|
||||
doTest("(int, bool, int, bool)",
|
||||
"expr = (1, False) * 2");
|
||||
}
|
||||
|
||||
public void testConstructorUnification() {
|
||||
doTest("C[int]",
|
||||
"class C(object):\n" +
|
||||
|
||||
Reference in New Issue
Block a user