More precise way to determine if expression is True (PY-19856)

This commit is contained in:
Semyon Proshev
2018-02-20 13:56:13 +03:00
parent ebac009906
commit 318a574bff
3 changed files with 49 additions and 7 deletions
@@ -443,7 +443,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
boolean isStaticallyTrue = false;
if (condition != null) {
condition.accept(this);
isStaticallyTrue = PyEvaluator.evaluateBoolean(condition, false);
isStaticallyTrue = PyEvaluator.evaluateAsBoolean(condition, false);
}
final Instruction head = myBuilder.prevInstruction;
final PyElsePart elsePart = node.getElsePart();
@@ -813,7 +813,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
super.visitPyAssertStatement(node);
final PyExpression[] args = node.getArguments();
// assert False
if (args.length >= 1 && !PyEvaluator.evaluateBoolean(args[0], true)) {
if (args.length >= 1 && !PyEvaluator.evaluateAsBoolean(args[0], true)) {
abruptFlow(node);
return;
}
@@ -18,6 +18,7 @@ package com.jetbrains.python.psi.impl;
import com.intellij.psi.PsiElement;
import com.intellij.psi.ResolveResult;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
@@ -341,16 +342,40 @@ public class PyEvaluator {
return PyUtil.as(new PyEvaluator().evaluate(expression), resultType);
}
public static boolean evaluateBoolean(@Nullable PyExpression expr, boolean defaultValue) {
final Object result = new PyEvaluator().evaluate(expr);
/**
* Shortcut that evaluates expression and tries to determine if `bool` will return true for it
*
* @param expression expression to evaluate
* @return true if expression is evaluated to value so `bool` returns true for it
*/
@Nullable
public static Boolean evaluateAsBoolean(@Nullable PyExpression expression) {
final PyEvaluator evaluator = new PyEvaluator();
evaluator.setEvaluateCollectionItems(false);
evaluator.setEvaluateKeys(false);
final Object result = evaluator.evaluate(expression);
if (result instanceof Boolean) {
return (Boolean)result;
}
else if (result instanceof Integer) {
return ((Integer)result) != 0;
return (Integer)result != 0;
}
else {
return defaultValue;
else if (result instanceof String) {
return !((String)result).isEmpty();
}
else if (result instanceof Collection) {
return !((Collection)result).isEmpty();
}
else if (result instanceof Map) {
return !((Map)result).isEmpty();
}
return null;
}
public static boolean evaluateAsBoolean(@Nullable PyExpression expression, boolean defaultValue) {
return ObjectUtils.notNull(evaluateAsBoolean(expression), defaultValue);
}
}
@@ -264,6 +264,23 @@ public class PyEvaluatorTest extends PyTestCase {
assertNull(new PyEvaluator().evaluate(expression));
}
public void testEvaluateAsBoolean() {
assertTrue(PyEvaluator.evaluateAsBoolean(parseExpression("True")));
assertFalse(PyEvaluator.evaluateAsBoolean(parseExpression("False")));
assertTrue(PyEvaluator.evaluateAsBoolean(parseExpression("\'a\'")));
assertFalse(PyEvaluator.evaluateAsBoolean(parseExpression("\'\'")));
assertTrue(PyEvaluator.evaluateAsBoolean(parseExpression("1")));
assertFalse(PyEvaluator.evaluateAsBoolean(parseExpression("0")));
assertTrue(PyEvaluator.evaluateAsBoolean(parseExpression("{1: 0}")));
assertFalse(PyEvaluator.evaluateAsBoolean(parseExpression("{}")));
assertTrue(PyEvaluator.evaluateAsBoolean(parseExpression("[1]")));
assertFalse(PyEvaluator.evaluateAsBoolean(parseExpression("[]")));
}
@NotNull
private <T> T byExpression(@NotNull String expression, @NotNull Class<T> cls) {
final Object value = new PyEvaluator().evaluate(parseExpression(expression));