mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Don't use resolve while evaluating expressions for CFG
This commit is contained in:
@@ -448,7 +448,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
boolean isStaticallyTrue = false;
|
||||
if (condition != null) {
|
||||
condition.accept(this);
|
||||
isStaticallyTrue = PyEvaluator.evaluateAsBoolean(condition, false);
|
||||
isStaticallyTrue = PyEvaluator.evaluateAsBooleanNoResolve(condition, false);
|
||||
}
|
||||
final Instruction head = myBuilder.prevInstruction;
|
||||
final PyElsePart elsePart = node.getElsePart();
|
||||
@@ -481,7 +481,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
}
|
||||
final Instruction head = myBuilder.prevInstruction;
|
||||
final PyElsePart elsePart = node.getElsePart();
|
||||
if (elsePart == null && !PyEvaluator.evaluateAsBoolean(source, false)) {
|
||||
if (elsePart == null && !PyEvaluator.evaluateAsBooleanNoResolve(source, false)) {
|
||||
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
|
||||
}
|
||||
final PyStatementList list = forPart.getStatementList();
|
||||
@@ -816,7 +816,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
super.visitPyAssertStatement(node);
|
||||
final PyExpression[] args = node.getArguments();
|
||||
// assert False
|
||||
if (args.length >= 1 && !PyEvaluator.evaluateAsBoolean(args[0], true)) {
|
||||
if (args.length >= 1 && !PyEvaluator.evaluateAsBooleanNoResolve(args[0], true)) {
|
||||
abruptFlow(node);
|
||||
return;
|
||||
}
|
||||
|
||||
+2
-2
@@ -120,8 +120,8 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
final Object leftValue = new PyEvaluator().evaluate(lhs);
|
||||
final Object rightValue = new PyEvaluator().evaluate(rhs);
|
||||
final Object leftValue = PyEvaluator.evaluateNoResolve(lhs, Object.class);
|
||||
final Object rightValue = PyEvaluator.evaluateNoResolve(rhs, Object.class);
|
||||
|
||||
if (leftValue instanceof Boolean && rightValue instanceof Boolean) {
|
||||
return;
|
||||
|
||||
@@ -55,6 +55,11 @@ public class PyEvaluator {
|
||||
*/
|
||||
private boolean myEvaluateKeys = true;
|
||||
|
||||
/**
|
||||
* if true, references will be resolved
|
||||
*/
|
||||
private boolean myEnableResolve = true;
|
||||
|
||||
public void setNamespace(@Nullable Map<String, Object> namespace) {
|
||||
myNamespace = namespace;
|
||||
}
|
||||
@@ -67,6 +72,10 @@ public class PyEvaluator {
|
||||
myEvaluateKeys = evaluateKeys;
|
||||
}
|
||||
|
||||
public void enableResolve(boolean enableResolve) {
|
||||
myEnableResolve = enableResolve;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Contract("null -> null")
|
||||
public Object evaluate(@Nullable PyExpression expression) {
|
||||
@@ -242,6 +251,9 @@ public class PyEvaluator {
|
||||
if (myNamespace != null) {
|
||||
return myNamespace.get(expression.getReferencedName());
|
||||
}
|
||||
if (!myEnableResolve) {
|
||||
return null;
|
||||
}
|
||||
final ResolveResult[] results = expression.getReference(PyResolveContext.noImplicits()).multiResolve(false);
|
||||
if (results.length != 1) {
|
||||
return null;
|
||||
@@ -332,9 +344,9 @@ public class PyEvaluator {
|
||||
/**
|
||||
* Shortcut that evaluates expression with default params and casts it to particular type (if possible)
|
||||
*
|
||||
* @param <T> expected type
|
||||
* @param expression expression to evaluate
|
||||
* @param resultType expected type
|
||||
* @param <T> expected type
|
||||
* @return value if expression is evaluated to this type, null otherwise
|
||||
*/
|
||||
@Nullable
|
||||
@@ -342,6 +354,21 @@ public class PyEvaluator {
|
||||
return PyUtil.as(new PyEvaluator().evaluate(expression), resultType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut that evaluates expression with default params and disabled resolve and casts it to particular type (if possible)
|
||||
*
|
||||
* @param <T> expected type
|
||||
* @param expression expression to evaluate
|
||||
* @param resultType expected type
|
||||
* @return value if expression is evaluated to this type, null otherwise
|
||||
*/
|
||||
@Nullable
|
||||
public static <T> T evaluateNoResolve(@Nullable PyExpression expression, @NotNull Class<T> resultType) {
|
||||
final PyEvaluator evaluator = new PyEvaluator();
|
||||
evaluator.enableResolve(false);
|
||||
return PyUtil.as(evaluator.evaluate(expression), resultType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut that evaluates expression and tries to determine if `bool` will return true for it
|
||||
*
|
||||
@@ -350,10 +377,39 @@ public class PyEvaluator {
|
||||
*/
|
||||
@Nullable
|
||||
public static Boolean evaluateAsBoolean(@Nullable PyExpression expression) {
|
||||
return evaluateAsBoolean(prepareEvaluatorForBoolean(true), expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 evaluateAsBooleanNoResolve(@Nullable PyExpression expression) {
|
||||
return evaluateAsBoolean(prepareEvaluatorForBoolean(false), expression);
|
||||
}
|
||||
|
||||
public static boolean evaluateAsBoolean(@Nullable PyExpression expression, boolean defaultValue) {
|
||||
return ObjectUtils.notNull(evaluateAsBoolean(expression), defaultValue);
|
||||
}
|
||||
|
||||
public static boolean evaluateAsBooleanNoResolve(@Nullable PyExpression expression, boolean defaultValue) {
|
||||
return ObjectUtils.notNull(evaluateAsBooleanNoResolve(expression), defaultValue);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PyEvaluator prepareEvaluatorForBoolean(boolean enableResolve) {
|
||||
final PyEvaluator evaluator = new PyEvaluator();
|
||||
evaluator.setEvaluateCollectionItems(false);
|
||||
evaluator.setEvaluateKeys(false);
|
||||
evaluator.enableResolve(enableResolve);
|
||||
return evaluator;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Boolean evaluateAsBoolean(@NotNull PyEvaluator evaluator, @Nullable PyExpression expression) {
|
||||
final Object result = evaluator.evaluate(expression);
|
||||
|
||||
if (result instanceof Boolean) {
|
||||
@@ -374,8 +430,4 @@ public class PyEvaluator {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean evaluateAsBoolean(@Nullable PyExpression expression, boolean defaultValue) {
|
||||
return ObjectUtils.notNull(evaluateAsBoolean(expression), defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
1(2) element: PyAssignmentStatement
|
||||
2(3) WRITE ACCESS: tests
|
||||
3(4) element: PyForStatement
|
||||
4(5) READ ACCESS: tests
|
||||
4(5,17) READ ACCESS: tests
|
||||
5(6) element: PyTargetExpression: t
|
||||
6(7) WRITE ACCESS: t
|
||||
7(8) element: PyTryExceptStatement
|
||||
|
||||
@@ -281,6 +281,38 @@ public class PyEvaluatorTest extends PyTestCase {
|
||||
assertFalse(PyEvaluator.evaluateAsBoolean(parseExpression("[]")));
|
||||
}
|
||||
|
||||
public void testEvaluateAsBooleanNoResolve() {
|
||||
assertTrue(PyEvaluator.evaluateAsBooleanNoResolve(parseExpression("True")));
|
||||
assertFalse(PyEvaluator.evaluateAsBooleanNoResolve(parseExpression("False")));
|
||||
|
||||
assertTrue(PyEvaluator.evaluateAsBooleanNoResolve(parseExpression("\'a\'")));
|
||||
assertFalse(PyEvaluator.evaluateAsBooleanNoResolve(parseExpression("\'\'")));
|
||||
|
||||
assertTrue(PyEvaluator.evaluateAsBooleanNoResolve(parseExpression("1")));
|
||||
assertFalse(PyEvaluator.evaluateAsBooleanNoResolve(parseExpression("0")));
|
||||
|
||||
assertTrue(PyEvaluator.evaluateAsBooleanNoResolve(parseExpression("{1: 0}")));
|
||||
assertFalse(PyEvaluator.evaluateAsBooleanNoResolve(parseExpression("{}")));
|
||||
|
||||
assertTrue(PyEvaluator.evaluateAsBooleanNoResolve(parseExpression("[1]")));
|
||||
assertFalse(PyEvaluator.evaluateAsBooleanNoResolve(parseExpression("[]")));
|
||||
|
||||
assertNull(PyEvaluator.evaluateAsBooleanNoResolve(parseText("a = True\nexpr = a")));
|
||||
assertNull(PyEvaluator.evaluateAsBooleanNoResolve(parseText("a = False\nexpr = a")));
|
||||
|
||||
assertNull(PyEvaluator.evaluateAsBooleanNoResolve(parseText("a = \'a\'\nexpr = a")));
|
||||
assertNull(PyEvaluator.evaluateAsBooleanNoResolve(parseText("a = \'\'\nexpr = a")));
|
||||
|
||||
assertNull(PyEvaluator.evaluateAsBooleanNoResolve(parseText("a = 1\nexpr = a")));
|
||||
assertNull(PyEvaluator.evaluateAsBooleanNoResolve(parseText("a = 0\nexpr = a")));
|
||||
|
||||
assertNull(PyEvaluator.evaluateAsBooleanNoResolve(parseText("a = {1: 0}\nexpr = a")));
|
||||
assertNull(PyEvaluator.evaluateAsBooleanNoResolve(parseText("a = {}\nexpr = a")));
|
||||
|
||||
assertNull(PyEvaluator.evaluateAsBooleanNoResolve(parseText("a = [1]\nexpr = a")));
|
||||
assertNull(PyEvaluator.evaluateAsBooleanNoResolve(parseText("a = []\nexpr = a")));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private <T> T byExpression(@NotNull String expression, @NotNull Class<T> cls) {
|
||||
final Object value = new PyEvaluator().evaluate(parseExpression(expression));
|
||||
|
||||
Reference in New Issue
Block a user