[python] CFG support logical expressions in if/while conditions

GitOrigin-RevId: 274b3271dccc93be64830374c8047a8f6552033e
This commit is contained in:
Petr
2024-12-19 19:51:11 +00:00
committed by intellij-monorepo-bot
parent 94aaceafb6
commit 3f8f4f40c3
52 changed files with 975 additions and 862 deletions
@@ -4,6 +4,7 @@ package com.jetbrains.python.codeInsight.codeFragment;
import com.intellij.codeInsight.codeFragment.CannotCreateCodeFragmentException;
import com.intellij.codeInsight.codeFragment.CodeFragmentUtil;
import com.intellij.codeInsight.codeFragment.Position;
import com.intellij.codeInsight.controlflow.ConditionalInstruction;
import com.intellij.codeInsight.controlflow.ControlFlow;
import com.intellij.codeInsight.controlflow.Instruction;
import com.intellij.openapi.util.Pair;
@@ -133,7 +134,13 @@ public final class PyCodeFragmentUtil {
private static List<Instruction> getFragmentSubGraph(@NotNull List<Instruction> graph, int start, int end) {
List<Instruction> instructions = new ArrayList<>();
for (Instruction instruction : graph) {
final PsiElement element = instruction.getElement();
final PsiElement element;
if (instruction instanceof ConditionalInstruction conditionalInstruction) {
element = conditionalInstruction.getCondition();
}
else {
element = instruction.getElement();
}
if (element != null) {
if (CodeFragmentUtil.getPosition(element, start, end) == Position.INSIDE) {
instructions.add(instruction);
@@ -16,33 +16,24 @@
package com.jetbrains.python.codeInsight.controlflow;
import com.google.common.collect.ImmutableSet;
import com.intellij.codeInsight.controlflow.ConditionalInstruction;
import com.intellij.codeInsight.controlflow.ControlFlow;
import com.intellij.codeInsight.controlflow.ControlFlowBuilder;
import com.intellij.codeInsight.controlflow.Instruction;
import com.google.common.collect.Lists;
import com.intellij.codeInsight.controlflow.*;
import com.intellij.codeInsight.controlflow.impl.ConditionalInstructionImpl;
import com.intellij.codeInsight.controlflow.impl.TransparentInstructionImpl;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.QualifiedName;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.ParamHelper;
import com.jetbrains.python.psi.impl.PyAugAssignmentStatementNavigator;
import com.jetbrains.python.psi.impl.PyEvaluator;
import com.jetbrains.python.psi.impl.PyImportStatementNavigator;
import kotlin.Triple;
import com.jetbrains.python.psi.impl.*;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.*;
public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
@@ -51,6 +42,10 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
private final ControlFlowBuilder myBuilder = new ControlFlowBuilder();
private @Nullable TrueFalseNodes myTrueFalseNodes;
private record TrueFalseNodes(@NotNull Instruction trueNode, @NotNull Instruction falseNode) {}
public ControlFlow buildControlFlow(@NotNull final ScopeOwner owner) {
return myBuilder.build(this, owner);
}
@@ -145,9 +140,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
myBuilder.addNodeAndCheckPending(callInstruction);
if (node.isCalleeText(PyNames.ASSERT_IS_INSTANCE)) {
final PyTypeAssertionEvaluator assertionEvaluator = new PyTypeAssertionEvaluator();
node.accept(assertionEvaluator);
addAssertInstructions(assertionEvaluator);
addTypeAssertionNodes(node, true);
}
}
@@ -310,45 +303,24 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
}
}
@NotNull
private List<Pair<PsiElement, Instruction>> getBranchingPoints(@Nullable PyExpression condition) {
final List<Pair<PsiElement, Instruction>> result = new ArrayList<>();
if (!isConjunctionOrDisjunction(condition)) {
// make previous instruction to be considered as a negative branching point
result.add(Pair.create(condition, myBuilder.prevInstruction));
}
myBuilder.processPending((pendingScope, instruction) -> {
if (pendingScope != null && PsiTreeUtil.isAncestor(condition, pendingScope, false)) {
result.add(Pair.create(pendingScope, instruction));
}
else {
myBuilder.addPendingEdge(pendingScope, instruction);
}
});
return result;
}
@Override
public void visitPyConditionalExpression(@NotNull PyConditionalExpression node) {
myBuilder.startNode(node);
TransparentInstruction trueNode = addTransparentInstruction();
TransparentInstruction falseNode = addTransparentInstruction();
final PyExpression condition = node.getCondition();
final PyTypeAssertionEvaluator assertionEvaluator = new PyTypeAssertionEvaluator();
if (condition != null) {
condition.accept(this);
condition.accept(assertionEvaluator);
visitCondition(condition, trueNode, falseNode);
}
final Instruction branchingPoint = myBuilder.prevInstruction;
final PyExpression truePart = node.getTruePart();
final PyExpression falsePart = node.getFalsePart();
if (truePart != null) {
addAssertInstructions(assertionEvaluator);
myBuilder.prevInstruction = trueNode;
truePart.accept(this);
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
}
if (falsePart != null) {
myBuilder.prevInstruction = branchingPoint;
myBuilder.prevInstruction = falseNode;
falsePart.accept(this);
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
}
@@ -363,154 +335,92 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
public void visitPyIfStatement(final @NotNull PyIfStatement node) {
myBuilder.startNode(node);
PyExpression lastCondition = null; // last visited condition
List<Pair<PsiElement, Instruction>> lastBranchingPoints = Collections.emptyList(); // outcoming negative edges from the last condition
final List<Boolean> conditionResults = new ArrayList<>(); // visited conditions results
List<Instruction> exitInstructions = new ArrayList<>();
boolean unreachable = false;
for (PyIfPart ifPart : StreamEx.of(node.getIfPart()).append(node.getElifParts())) {
TransparentInstruction thenNode = addTransparentInstruction();
TransparentInstruction elseNode = addTransparentInstruction();
PyExpression condition = ifPart.getCondition();
if (condition != null) {
visitCondition(condition, thenNode, elseNode);
}
PyIfPart prevIfPart = null;
Boolean conditionResult = PyEvaluator.evaluateAsBooleanNoResolve(condition);
myBuilder.prevInstruction = unreachable || Boolean.FALSE.equals(conditionResult) ? null : thenNode;
if (Boolean.TRUE.equals(conditionResult)) {
unreachable = true;
}
for (PyIfPart part : StreamEx.of(node.getIfPart()).append(node.getElifParts())) {
if (prevIfPart != null) {
// first `if` could not be considered as some `if` inheritor
if (!ContainerUtil.exists(conditionResults, Boolean.TRUE::equals)) {
// edges to `if` would be created below if there were no conditions evaluated to `True` earlier
lastBranchingPoints.forEach(pair -> myBuilder.addPendingEdge(pair.getFirst(), pair.getSecond()));
}
visitPyStatementPart(ifPart);
exitInstructions.add(myBuilder.prevInstruction);
myBuilder.prevInstruction = elseNode;
}
final PyElsePart elsePart = node.getElsePart();
if (elsePart != null) {
if (unreachable) {
myBuilder.prevInstruction = null;
myBuilder.startConditionalNode(part, lastCondition, false);
addAssertInstructions(getNegativeTypeAssertions(prevIfPart));
}
prevIfPart = part;
final Triple<PyExpression, List<Pair<PsiElement, Instruction>>, Boolean> currentPartResults = visitPyConditionalPart(part, node);
lastCondition = currentPartResults.getFirst();
lastBranchingPoints = currentPartResults.getSecond();
conditionResults.add(currentPartResults.getThird());
visitPyStatementPart(elsePart);
}
assert prevIfPart != null;
final PyTypeAssertionEvaluator negativeAssertionEvaluator = getNegativeTypeAssertions(prevIfPart);
exitInstructions.add(myBuilder.prevInstruction);
myBuilder.prevInstruction = addTransparentInstruction();
final PyElsePart elseBranch = node.getElsePart();
if (elseBranch != null) {
if (!ContainerUtil.exists(conditionResults, Boolean.TRUE::equals)) {
// edges to `else` would be created below if there were no conditions evaluated to `True` earlier
lastBranchingPoints.forEach(pair -> myBuilder.addPendingEdge(pair.getFirst(), pair.getSecond()));
}
myBuilder.prevInstruction = null;
final PyStatementList statements = elseBranch.getStatementList();
myBuilder.startConditionalNode(statements, lastCondition, false);
addAssertInstructions(negativeAssertionEvaluator);
statements.accept(this);
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
}
else if (ContainerUtil.getLastItem(conditionResults) != Boolean.TRUE) {
// if last condition was evaluated to `True`, all outcoming `if` statement edges were correctly processed in the last `if`
myBuilder.prevInstruction = null;
final Instruction instruction = ContainerUtil.getFirstItem(addAssertInstructions(negativeAssertionEvaluator));
if (instruction != null) {
lastBranchingPoints.forEach(p -> myBuilder.addEdge(p.getSecond(), instruction));
}
else {
lastBranchingPoints.forEach(pair -> myBuilder.addPendingEdge(pair.getFirst(), pair.getSecond()));
}
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
for (Instruction exitInstruction : Lists.reverse(exitInstructions)) {
myBuilder.addEdge(exitInstruction, myBuilder.prevInstruction);
}
}
private static @NotNull PyTypeAssertionEvaluator getNegativeTypeAssertions(@NotNull PyIfPart ifPart) {
final PyTypeAssertionEvaluator negativeAssertionEvaluator = new PyTypeAssertionEvaluator(false);
final PyExpression firstIfPartCondition = ifPart.getCondition();
if (firstIfPartCondition != null) {
firstIfPartCondition.accept(negativeAssertionEvaluator);
@Override
public void visitPyPrefixExpression(@NotNull PyPrefixExpression node) {
if (myTrueFalseNodes != null && node.getOperator() == PyTokenTypes.NOT_KEYWORD) {
PyExpression operand = node.getOperand();
if (operand != null) {
visitCondition(operand, myTrueFalseNodes.falseNode, myTrueFalseNodes.trueNode);
}
}
return negativeAssertionEvaluator;
}
@NotNull
private Triple<PyExpression, List<Pair<PsiElement, Instruction>>, Boolean> visitPyConditionalPart(@NotNull PyConditionalStatementPart part,
@NotNull PyStatement node) {
final PyExpression condition = part.getCondition();
final PyTypeAssertionEvaluator assertionEvaluator = new PyTypeAssertionEvaluator();
final Boolean conditionResult = PyEvaluator.evaluateAsBooleanNoResolve(condition);
if (condition != null) {
condition.accept(this);
condition.accept(assertionEvaluator);
}
final List<Pair<PsiElement, Instruction>> branchingPoints = getBranchingPoints(condition);
if (conditionResult == Boolean.FALSE) {
myBuilder.flowAbrupted();
}
else if (isConjunctionOrDisjunction(condition)) {
// to make edges between positive sub-conditions inside and the statement below
final var shortCircuitPositivePoints = selectShortCircuitPositivePoints(branchingPoints);
branchingPoints.removeAll(shortCircuitPositivePoints);
shortCircuitPositivePoints.forEach(pair -> myBuilder.addPendingEdge(pair.getFirst(), pair.getSecond()));
}
visitPyConditionalPartStatements(part, assertionEvaluator, node);
return new Triple<>(condition, branchingPoints, conditionResult);
}
private static @NotNull List<Pair<PsiElement, Instruction>> selectShortCircuitPositivePoints(@NotNull List<Pair<PsiElement, Instruction>> branchingPoints) {
return ContainerUtil.filter(
branchingPoints,
it -> it.getSecond() instanceof ConditionalInstruction && ((ConditionalInstruction)it.getSecond()).getResult()
);
}
private void visitPyConditionalPartStatements(@NotNull PyConditionalStatementPart part,
@NotNull PyTypeAssertionEvaluator assertionEvaluator,
@NotNull PyStatement node) {
final PyStatementList statements = part.getStatementList();
myBuilder.startConditionalNode(statements, part.getCondition(), true);
addAssertInstructions(assertionEvaluator);
statements.accept(this);
if (!(node instanceof PyLoopStatement)) { // outcoming edges will be looped
myBuilder.processPending(
(pendingScope, instruction) -> {
if (pendingScope != null && PsiTreeUtil.isAncestor(statements, pendingScope, false)) {
myBuilder.addPendingEdge(node, instruction);
}
else {
myBuilder.addPendingEdge(pendingScope, instruction);
}
}
);
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
else {
super.visitPyPrefixExpression(node);
}
}
@Override
public void visitPyBinaryExpression(@NotNull PyBinaryExpression node) {
if (isConjunctionOrDisjunction(node)) {
final boolean conjunction = node.getOperator() == PyTokenTypes.AND_KEYWORD;
PyElementType operator = node.getOperator();
if (operator == PyTokenTypes.AND_KEYWORD || operator == PyTokenTypes.OR_KEYWORD) {
final PyExpression left = node.getLeftExpression();
final PyExpression right = node.getRightExpression();
if (left == null || right == null) return;
myBuilder.startNode(node);
final PyTypeAssertionEvaluator assertionEvaluator = new PyTypeAssertionEvaluator(conjunction);
final PyExpression left = node.getLeftExpression();
if (left != null) {
visitConjunctOrDisjunct(node, left, null, assertionEvaluator, conjunction);
Instruction trueNode;
Instruction falseNode;
Instruction exitNode;
if (myTrueFalseNodes == null) {
trueNode = falseNode = exitNode = addTransparentInstruction();
}
else {
trueNode = myTrueFalseNodes.trueNode;
falseNode = myTrueFalseNodes.falseNode;
exitNode = null;
}
final PyExpression right = node.getRightExpression();
if (right != null) {
visitConjunctOrDisjunct(node, right, assertionEvaluator, null, true);
Instruction rightNode = addTransparentInstruction();
if (operator == PyTokenTypes.AND_KEYWORD) {
visitCondition(left, rightNode, falseNode);
}
else {
visitCondition(left, trueNode, rightNode);
}
myBuilder.prevInstruction = rightNode;
visitCondition(right, trueNode, falseNode);
if (exitNode != null) {
myBuilder.prevInstruction = exitNode;
}
}
else {
@@ -518,79 +428,32 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
}
}
static boolean isConjunctionOrDisjunction(@Nullable PyExpression node) {
if (node instanceof PyBinaryExpression) {
final var operator = ((PyBinaryExpression)node).getOperator();
return operator == PyTokenTypes.AND_KEYWORD || operator == PyTokenTypes.OR_KEYWORD;
}
return false;
}
private void visitConjunctOrDisjunct(@NotNull PyBinaryExpression node,
@NotNull PyExpression subExpression,
@Nullable PyTypeAssertionEvaluator previousAssertionEvaluator,
@Nullable PyTypeAssertionEvaluator assertionEvaluator,
boolean conditionResultToContinue) {
if (previousAssertionEvaluator != null) {
addAssertInstructions(previousAssertionEvaluator);
}
subExpression.accept(this);
if (assertionEvaluator != null) {
subExpression.accept(assertionEvaluator);
}
final var branchingPoint = myBuilder.prevInstruction;
final var outside = new ConditionalInstructionImpl(myBuilder, null, subExpression, !conditionResultToContinue);
myBuilder.addNode(outside);
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
myBuilder.prevInstruction = branchingPoint;
final var toTheNext = new ConditionalInstructionImpl(myBuilder, null, subExpression, conditionResultToContinue);
myBuilder.addNode(toTheNext);
}
@Override
public void visitPyWhileStatement(final @NotNull PyWhileStatement node) {
final Instruction instruction = myBuilder.startNode(node);
Instruction entryNode = myBuilder.startNode(node);
final var mainPartResults = visitPyConditionalPart(node.getWhilePart(), node);
final var branchingPoints = mainPartResults.getSecond();
TransparentInstruction thenNode = addTransparentInstruction();
TransparentInstruction elseNode = addTransparentInstruction();
// Loop edges
if (myBuilder.prevInstruction != null) {
myBuilder.addEdge(myBuilder.prevInstruction, instruction);
}
myBuilder.checkPending(instruction);
final var isStaticallyTrue = mainPartResults.getThird() == Boolean.TRUE;
final var elsePart = node.getElsePart();
if (elsePart == null) {
if (!isStaticallyTrue) {
for (Pair<PsiElement, Instruction> pair : branchingPoints) {
myBuilder.addPendingEdge(node, pair.getSecond());
}
}
}
else {
final var elsePartInstruction = new ConditionalInstructionImpl(myBuilder, elsePart, mainPartResults.getFirst(), false);
myBuilder.prevInstruction = null;
myBuilder.addNode(elsePartInstruction);
if (!isStaticallyTrue) {
for (Pair<PsiElement, Instruction> pair : branchingPoints) {
myBuilder.addEdge(pair.getSecond(), elsePartInstruction);
}
}
elsePart.accept(this);
myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
final PyConditionalStatementPart whilePart = node.getWhilePart();
final PyExpression condition = whilePart.getCondition();
if (condition != null) {
visitCondition(condition, thenNode, elseNode);
}
myBuilder.flowAbrupted();
final Boolean conditionResult = PyEvaluator.evaluateAsBooleanNoResolve(condition);
myBuilder.prevInstruction = Boolean.FALSE.equals(conditionResult) ? null : thenNode;
visitPyStatementPart(whilePart);
myBuilder.checkPending(entryNode);
myBuilder.addEdge(myBuilder.prevInstruction, entryNode);
myBuilder.prevInstruction = Boolean.TRUE.equals(conditionResult) ? null : elseNode;
PyElsePart elsePart = node.getElsePart();
if (elsePart != null) {
visitPyStatementPart(elsePart);
}
}
@Override
@@ -916,10 +779,8 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
else {
myBuilder.startNode(condition);
}
final PyTypeAssertionEvaluator assertionEvaluator = new PyTypeAssertionEvaluator();
condition.accept(this);
condition.accept(assertionEvaluator);
addAssertInstructions(assertionEvaluator);
addTypeAssertionNodes(condition, true);
// Condition is true for nested "for" and "if" constructs, next startNode() should create a conditional node
prevCondition = condition;
@@ -969,9 +830,12 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
myBuilder.flowAbrupted();
return;
}
PyTypeAssertionEvaluator evaluator = new PyTypeAssertionEvaluator();
node.acceptChildren(evaluator);
addAssertInstructions(evaluator);
TransparentInstruction trueNode = addTransparentInstruction();
TransparentInstruction falseNode = addTransparentInstruction();
visitCondition(args[0], trueNode, falseNode);
myBuilder.addPendingEdge(null, falseNode);
myBuilder.prevInstruction = trueNode;
}
@Override
@@ -1023,6 +887,43 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
myBuilder.addNodeAndCheckPending(instruction);
}
private void visitCondition(@NotNull PyExpression expression, @NotNull Instruction trueNode, @NotNull Instruction falseNode) {
TrueFalseNodes prevTrueFalseNodes = myTrueFalseNodes;
myTrueFalseNodes = new TrueFalseNodes(trueNode, falseNode);
expression.accept(this);
myTrueFalseNodes = prevTrueFalseNodes;
if (!isLogicalExpression(Objects.requireNonNull(PyPsiUtils.flattenParens(expression)))) {
addConditionalNode(expression, false, falseNode);
addConditionalNode(expression, true, trueNode);
}
}
private static boolean isLogicalExpression(@NotNull PyExpression expression) {
if (expression instanceof PyBinaryExpression binaryExpression) {
PyElementType operator = binaryExpression.getOperator();
return operator == PyTokenTypes.AND_KEYWORD || operator == PyTokenTypes.OR_KEYWORD;
}
if (expression instanceof PyPrefixExpression prefixExpression) {
return prefixExpression.getOperator() == PyTokenTypes.NOT_KEYWORD;
}
return false;
}
private void addConditionalNode(@NotNull PyExpression condition, boolean result, @NotNull Instruction target) {
Instruction prevInstruction = myBuilder.prevInstruction;
myBuilder.addNode(new ConditionalInstructionImpl(myBuilder, null, condition, result));
addTypeAssertionNodes(condition, result);
myBuilder.addEdge(myBuilder.prevInstruction, target);
myBuilder.prevInstruction = prevInstruction;
}
private void visitPyStatementPart(@NotNull PyStatementPart statementPart) {
PyStatementList statementList = statementPart.getStatementList();
myBuilder.startNode(statementList);
statementList.accept(this);
}
private void abruptFlow(final PsiElement node) {
// Here we process pending instructions!!!
myBuilder.processPending((pendingScope, instruction) -> {
@@ -1045,17 +946,20 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
PyStatementList.class);
}
@NotNull
private List<Instruction> addAssertInstructions(@NotNull PyTypeAssertionEvaluator assertionEvaluator) {
final List<Instruction> result = new ArrayList<>();
for (PyTypeAssertionEvaluator.Assertion def : assertionEvaluator.getDefinitions()) {
private void addTypeAssertionNodes(@NotNull PyExpression condition, boolean positive) {
final PyTypeAssertionEvaluator evaluator = new PyTypeAssertionEvaluator(positive);
condition.accept(evaluator);
for (PyTypeAssertionEvaluator.Assertion def : evaluator.getDefinitions()) {
final PyReferenceExpression e = def.getElement();
final QualifiedName qname = e.asQualifiedName();
final String name = qname != null ? qname.toString() : e.getName();
ReadWriteInstruction instr = ReadWriteInstruction.assertType(myBuilder, e, name, def.getTypeEvalFunction());
myBuilder.addNode(instr);
result.add(instr);
myBuilder.addNode(ReadWriteInstruction.assertType(myBuilder, e, name, def.getTypeEvalFunction()));
}
return result;
}
private TransparentInstruction addTransparentInstruction() {
TransparentInstructionImpl instruction = new TransparentInstructionImpl(myBuilder, null, "");
myBuilder.instructions.add(instruction);
return instruction;
}
}
@@ -6,14 +6,14 @@ import com.intellij.codeInsight.controlflow.Instruction;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.function.BiFunction;
import static com.jetbrains.python.codeInsight.controlflow.PyControlFlowBuilder.isConjunctionOrDisjunction;
public final class PyMatchStatementControlFlowBuilder {
private final ControlFlowBuilder myBuilder;
private final PyElementVisitor myBaseVisitor;
@@ -153,4 +153,13 @@ public final class PyMatchStatementControlFlowBuilder {
return pendingScope;
});
}
private static boolean isConjunctionOrDisjunction(@Nullable PyExpression node) {
if (node instanceof PyBinaryExpression) {
final var operator = ((PyBinaryExpression)node).getOperator();
return operator == PyTokenTypes.AND_KEYWORD || operator == PyTokenTypes.OR_KEYWORD;
}
return false;
}
}
@@ -24,10 +24,6 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
private final Stack<Assertion> myStack = new Stack<>();
private boolean myPositive;
public PyTypeAssertionEvaluator() {
this(true);
}
public PyTypeAssertionEvaluator(boolean positive) {
myPositive = positive;
}
@@ -36,18 +32,6 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
return myStack;
}
@Override
public void visitPyPrefixExpression(@NotNull PyPrefixExpression node) {
if (node.getOperator() == PyTokenTypes.NOT_KEYWORD) {
myPositive = !myPositive;
super.visitPyPrefixExpression(node);
myPositive = !myPositive;
}
else {
super.visitPyPrefixExpression(node);
}
}
@Override
public void visitPyCallExpression(@NotNull PyCallExpression node) {
if (node.isCalleeText(PyNames.ISINSTANCE, PyNames.ASSERT_IS_INSTANCE)) {
@@ -89,6 +73,8 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
@Override
public void visitPyBinaryExpression(@NotNull PyBinaryExpression node) {
if (node.isOperator(PyNames.AND) || node.isOperator(PyNames.OR)) return;
final PyExpression lhs = node.getLeftExpression();
final PyExpression rhs = node.getRightExpression();
@@ -279,7 +279,8 @@ class PyInvertIfConditionIntention : PsiUpdateModCommandAction<PsiElement>(PsiEl
when {
instruction == currentInstruction -> ControlFlowUtil.Operation.NEXT
instruction is ReadWriteInstruction -> ControlFlowUtil.Operation.NEXT
instruction.element == null || !instruction.element!!.parents(false).contains(currentElement) -> {
instruction.element == null -> ControlFlowUtil.Operation.NEXT
!instruction.element!!.parents(false).contains(currentElement) -> {
result = false
ControlFlowUtil.Operation.BREAK
}
@@ -167,6 +167,15 @@ public final class PyRedeclarationInspection extends PyInspection {
}
private static boolean possiblyFalseCondition(@NotNull Instruction instruction) {
if (instruction instanceof ConditionalInstruction conditionalInstruction) {
if (conditionalInstruction.getCondition() instanceof PyExpression condition) {
return conditionalInstruction.getResult()
? !PyEvaluator.evaluateAsBoolean(condition, false)
: PyEvaluator.evaluateAsBoolean(condition, true);
}
return false;
}
final PsiElement element = instruction.getElement();
if (element == null) return false;
@@ -177,15 +186,6 @@ public final class PyRedeclarationInspection extends PyInspection {
return !PyEvaluator.evaluateAsBoolean(forPart.getSource(), false);
}
if (instruction instanceof ConditionalInstruction conditionalInstruction) {
final PsiElement condition = conditionalInstruction.getCondition();
if (condition instanceof PyExpression) {
return conditionalInstruction.getResult()
? !PyEvaluator.evaluateAsBoolean((PyExpression)condition, false)
: PyEvaluator.evaluateAsBoolean((PyExpression)condition, true);
}
}
return false;
}
@@ -8,6 +8,12 @@
7(8) READ ACCESS: x
8(9) READ ACCESS: int
9(10) element: PyCallExpression: isinstance
10(11) ASSERTTYPE ACCESS: s
11(12) ASSERTTYPE ACCESS: x
12() element: null
10(11) READ ACCESS: isinstance
11(12) READ ACCESS: s
12(13) READ ACCESS: basestring
13(14,16) element: PyCallExpression: isinstance
14(15) element: null. Condition: isinstance(s, basestring):false
15(18) ASSERTTYPE ACCESS: s
16(17) element: null. Condition: isinstance(s, basestring):true
17(18) ASSERTTYPE ACCESS: s
18() element: null
@@ -2,10 +2,12 @@
1(2) element: PyAssignmentStatement
2(3) WRITE ACCESS: sibling
3(4) element: PyIfStatement
4(5,10) READ ACCESS: sibling
5(6) element: PyStatementList. Condition: sibling:true
6(7) ASSERTTYPE ACCESS: sibling
7(8) element: PyAssignmentStatement
8(9) element: PySubscriptionExpression
9(10) READ ACCESS: sibling
10() element: null
4(5,6) READ ACCESS: sibling
5(12) element: null. Condition: sibling:false
6(7) element: null. Condition: sibling:true
7(8) ASSERTTYPE ACCESS: sibling
8(9) element: PyStatementList
9(10) element: PyAssignmentStatement
10(11) element: PySubscriptionExpression
11(12) READ ACCESS: sibling
12() element: null
@@ -9,20 +9,20 @@
8(9,10) WRITE ACCESS: r
9(14) element: null. Condition: (r := undefined2()):false
10(11) element: null. Condition: (r := undefined2()):true
11(12) element: PyStatementList. Condition: undefined1 and (r := undefined2()):true
11(12) element: PyStatementList
12(13) element: PyPrintStatement
13(1) READ ACCESS: r
14(15) element: PyWhileStatement
15(16) element: PyBinaryExpression
16(17,18) READ ACCESS: undefined3
17(24) element: null. Condition: undefined3:true
18(19) element: null. Condition: undefined3:false
17(19) element: null. Condition: undefined3:false
18(24) element: null. Condition: undefined3:true
19(20) READ ACCESS: undefined4
20(21) element: PyCallExpression: undefined4
21(22,23) WRITE ACCESS: r2
22(27) element: null. Condition: (r2 := undefined4()):false
23(24) element: null. Condition: (r2 := undefined4()):true
24(25) element: PyStatementList. Condition: undefined3 or (r2 := undefined4()):true
24(25) element: PyStatementList
25(26) element: PyPrintStatement
26(14) READ ACCESS: r2
27() element: null
@@ -9,24 +9,24 @@
8(9,10) WRITE ACCESS: r
9(14) element: null. Condition: (r := undefined2()):false
10(11) element: null. Condition: (r := undefined2()):true
11(12) element: PyStatementList. Condition: undefined1 and (r := undefined2()):true
11(12) element: PyStatementList
12(13) element: PyPrintStatement
13(1) READ ACCESS: r
14(15) element: PyElsePart. Condition: undefined1 and (r := undefined2()):false
14(15) element: PyStatementList
15(16) element: PyPrintStatement
16(17) element: PyWhileStatement
17(18) element: PyBinaryExpression
18(19,20) READ ACCESS: undefined3
19(26) element: null. Condition: undefined3:true
20(21) element: null. Condition: undefined3:false
19(21) element: null. Condition: undefined3:false
20(26) element: null. Condition: undefined3:true
21(22) READ ACCESS: undefined4
22(23) element: PyCallExpression: undefined4
23(24,25) WRITE ACCESS: r2
24(29) element: null. Condition: (r2 := undefined4()):false
25(26) element: null. Condition: (r2 := undefined4()):true
26(27) element: PyStatementList. Condition: undefined3 or (r2 := undefined4()):true
26(27) element: PyStatementList
27(28) element: PyPrintStatement
28(16) READ ACCESS: r2
29(30) element: PyElsePart. Condition: undefined3 or (r2 := undefined4()):false
29(30) element: PyStatementList
30(31) element: PyPrintStatement
31() element: null
@@ -1,11 +1,15 @@
0(1) element: null
1(2) element: PyWhileStatement
2(3,10) READ ACCESS: foo
3(4) element: PyStatementList. Condition: foo:true
4(5) element: PyIfStatement
5(6,9) READ ACCESS: condition
6(7) element: PyStatementList. Condition: condition:true
7(8) ASSERTTYPE ACCESS: condition
8(10) element: PyBreakStatement
9(1) element: PyPrintStatement
10() element: null
2(3,4) READ ACCESS: foo
3(14) element: null. Condition: foo:false
4(5) element: null. Condition: foo:true
5(6) element: PyStatementList
6(7) element: PyIfStatement
7(8,9) READ ACCESS: condition
8(13) element: null. Condition: condition:false
9(10) element: null. Condition: condition:true
10(11) ASSERTTYPE ACCESS: condition
11(12) element: PyStatementList
12(14) element: PyBreakStatement
13(1) element: PyPrintStatement
14() element: null
@@ -8,9 +8,11 @@
7(8) WRITE ACCESS: c
8(9) element: PyAssignmentStatement
9(10) element: PyConditionalExpression
10(11,13) READ ACCESS: c
11(12) ASSERTTYPE ACCESS: c
12(14) READ ACCESS: x
13(14) READ ACCESS: y
14(15) WRITE ACCESS: z
15() element: null
10(11,12) READ ACCESS: c
11(15) element: null. Condition: c:false
12(13) element: null. Condition: c:true
13(14) ASSERTTYPE ACCESS: c
14(16) READ ACCESS: x
15(16) READ ACCESS: y
16(17) WRITE ACCESS: z
17() element: null
@@ -1,11 +1,15 @@
0(1) element: null
1(2) element: PyWhileStatement
2(3,10) READ ACCESS: foo
3(4) element: PyStatementList. Condition: foo:true
4(5) element: PyIfStatement
5(6,9) READ ACCESS: condition
6(7) element: PyStatementList. Condition: condition:true
7(8) ASSERTTYPE ACCESS: condition
8(1) element: PyContinueStatement
9(1) element: PyPrintStatement
10() element: null
2(3,4) READ ACCESS: foo
3(14) element: null. Condition: foo:false
4(5) element: null. Condition: foo:true
5(6) element: PyStatementList
6(7) element: PyIfStatement
7(8,9) READ ACCESS: condition
8(13) element: null. Condition: condition:false
9(10) element: null. Condition: condition:true
10(11) ASSERTTYPE ACCESS: condition
11(12) element: PyStatementList
12(1) element: PyContinueStatement
13(1) element: PyPrintStatement
14() element: null
@@ -7,13 +7,15 @@
6(7) element: PyIfStatement
7(8) READ ACCESS: len
8(9) READ ACCESS: s
9(10,12) element: PyCallExpression: len
10(11) element: PyStatementList. Condition: len(s) == 1:true
11(3,15) element: PyContinueStatement
12(13) element: PyExpressionStatement
13(14) READ ACCESS: sys
14(4,15) element: PyCallExpression: sys.exit
15(16) element: PyRaiseStatement
16(17) READ ACCESS: Exception
17(18) element: PyCallExpression: Exception
18() element: null
9(10,11) element: PyCallExpression: len
10(14) element: null. Condition: len(s) == 1:false
11(12) element: null. Condition: len(s) == 1:true
12(13) element: PyStatementList
13(3,17) element: PyContinueStatement
14(15) element: PyExpressionStatement
15(16) READ ACCESS: sys
16(4,17) element: PyCallExpression: sys.exit
17(18) element: PyRaiseStatement
18(19) READ ACCESS: Exception
19(20) element: PyCallExpression: Exception
20() element: null
@@ -8,16 +8,18 @@
7(8) READ ACCESS: isinstance
8(9) READ ACCESS: str
9(10) READ ACCESS: int
10(11,17) element: PyCallExpression: isinstance
11(12) element: PyStatementList. Condition: isinstance(str, int):true
12(13) ASSERTTYPE ACCESS: str
13(14) element: PyExpressionStatement
14(15) READ ACCESS: self
15(16) element: PyCallExpression: self.fail
16(18) element: PyPrintStatement
17(18) ASSERTTYPE ACCESS: str
18(19) element: PyExpressionStatement
19(20) READ ACCESS: self
20(21) READ ACCESS: str
21(22) element: PyCallExpression: self.assert_
22() element: null
10(11,13) element: PyCallExpression: isinstance
11(12) element: null. Condition: isinstance(str, int):false
12(20) ASSERTTYPE ACCESS: str
13(14) element: null. Condition: isinstance(str, int):true
14(15) ASSERTTYPE ACCESS: str
15(16) element: PyStatementList
16(17) element: PyExpressionStatement
17(18) READ ACCESS: self
18(19) element: PyCallExpression: self.fail
19(20) element: PyPrintStatement
20(21) element: PyExpressionStatement
21(22) READ ACCESS: self
22(23) READ ACCESS: str
23(24) element: PyCallExpression: self.assert_
24() element: null
@@ -1,11 +1,13 @@
0(1) element: null
1(2) element: PyForStatement
2(3,10) READ ACCESS: lines
2(3,12) READ ACCESS: lines
3(4) element: PyTargetExpression: line
4(5) WRITE ACCESS: line
5(6) element: PyIfStatement
6(7,3,10) READ ACCESS: line
7(8) element: PyStatementList. Condition: line == '@':true
8(9) element: PyAssignmentStatement
9(3,10) WRITE ACCESS: head
10() element: null
6(7,8) READ ACCESS: line
7(3,12) element: null. Condition: line == '@':false
8(9) element: null. Condition: line == '@':true
9(10) element: PyStatementList
10(11) element: PyAssignmentStatement
11(3,12) WRITE ACCESS: head
12() element: null
@@ -15,7 +15,7 @@
14(15,16) READ ACCESS: end
15(3,20) element: null. Condition: hour < end:false
16(17) element: null. Condition: hour < end:true
17(18) element: PyStatementList. Condition: hour >= start and hour < end:true
17(18) element: PyStatementList
18(19) element: PyReturnStatement
19(20) READ ACCESS: name
20() element: null
@@ -25,34 +25,32 @@
24(25) element: PyBinaryExpression
25(26) element: PyBinaryExpression
26(27,28) READ ACCESS: collapse
27(34) element: null. Condition: collapse:false
27(32) element: null. Condition: collapse:false
28(29) element: null. Condition: collapse:true
29(30,31) element: PyLambdaExpression
30(34) element: null. Condition: (lambda s: " ".join(s.split())):false
31(32,33) element: null. Condition: (lambda s: " ".join(s.split())):true
32(37) element: null. Condition: collapse and (lambda s: " ".join(s.split())):true
33(34) element: null. Condition: collapse and (lambda s: " ".join(s.split())):false
34(35,36) element: PyLambdaExpression
35(37) element: null. Condition: (lambda s: s):false
36(37) element: null. Condition: (lambda s: s):true
37(38) WRITE ACCESS: processFunc
38(39) element: PyPrintStatement
39(40) element: PyListCompExpression
40(41) element: PyReferenceExpression: methodList
41(42,56) READ ACCESS: methodList
42(43) element: PyTargetExpression: method
43(44) WRITE ACCESS: method
44(45) element: PyBinaryExpression
45(46) READ ACCESS: method
46(47) READ ACCESS: spacing
47(48) element: PyCallExpression: method.ljust
48(49) READ ACCESS: processFunc
49(50) READ ACCESS: str
50(51) READ ACCESS: getattr
51(52) READ ACCESS: object
52(53) READ ACCESS: method
53(54) element: PyCallExpression: getattr
54(55) element: PyCallExpression: str
55(42,56) element: PyCallExpression: processFunc
56(57) element: PyCallExpression: "\n".join
57() element: null
30(32) element: null. Condition: (lambda s: " ".join(s.split())):false
31(35) element: null. Condition: (lambda s: " ".join(s.split())):true
32(33,34) element: PyLambdaExpression
33(35) element: null. Condition: (lambda s: s):false
34(35) element: null. Condition: (lambda s: s):true
35(36) WRITE ACCESS: processFunc
36(37) element: PyPrintStatement
37(38) element: PyListCompExpression
38(39) element: PyReferenceExpression: methodList
39(40,54) READ ACCESS: methodList
40(41) element: PyTargetExpression: method
41(42) WRITE ACCESS: method
42(43) element: PyBinaryExpression
43(44) READ ACCESS: method
44(45) READ ACCESS: spacing
45(46) element: PyCallExpression: method.ljust
46(47) READ ACCESS: processFunc
47(48) READ ACCESS: str
48(49) READ ACCESS: getattr
49(50) READ ACCESS: object
50(51) READ ACCESS: method
51(52) element: PyCallExpression: getattr
52(53) element: PyCallExpression: str
53(40,54) element: PyCallExpression: processFunc
54(55) element: PyCallExpression: "\n".join
55() element: null
+33 -23
View File
@@ -1,24 +1,34 @@
0(1) element: null
1(2,4) element: PyIfStatement
2(3) element: PyStatementList. Condition: 0j:true
3(4) element: PyPassStatement
4(5,7) element: PyIfStatement
5(6) element: PyStatementList. Condition: 1j:true
6(9) element: PyPassStatement
7(8) element: PyStatementList. Condition: 1j:false
8(9) element: PyPassStatement
9(10,12) element: PyIfStatement
10(11) element: PyStatementList. Condition: 2j:true
11(15) element: PyPassStatement
12(13,15) element: PyIfPartElif. Condition: 2j:false
13(14) element: PyStatementList. Condition: 3j:true
14(15) element: PyPassStatement
15(16,18) element: PyIfStatement
16(17) element: PyStatementList. Condition: 4j:true
17(23) element: PyPassStatement
18(19,21) element: PyIfPartElif. Condition: 4j:false
19(20) element: PyStatementList. Condition: 5j:true
20(23) element: PyPassStatement
21(22) element: PyStatementList. Condition: 5j:false
22(23) element: PyExpressionStatement
23() element: null
1(2,3) element: PyIfStatement
2(6) element: null. Condition: 0j:false
3(4) element: null. Condition: 0j:true
4(5) element: PyStatementList
5(6) element: PyPassStatement
6(7,8) element: PyIfStatement
7(11) element: null. Condition: 1j:false
8(9) element: null. Condition: 1j:true
9(10) element: PyStatementList
10(13) element: PyPassStatement
11(12) element: PyStatementList
12(13) element: PyPassStatement
13(14,15) element: PyIfStatement
14(18,19) element: null. Condition: 2j:false
15(16) element: null. Condition: 2j:true
16(17) element: PyStatementList
17(22) element: PyPassStatement
18(22) element: null. Condition: 3j:false
19(20) element: null. Condition: 3j:true
20(21) element: PyStatementList
21(22) element: PyPassStatement
22(23,24) element: PyIfStatement
23(27,28) element: null. Condition: 4j:false
24(25) element: null. Condition: 4j:true
25(26) element: PyStatementList
26(33) element: PyPassStatement
27(31) element: null. Condition: 5j:false
28(29) element: null. Condition: 5j:true
29(30) element: PyStatementList
30(33) element: PyPassStatement
31(32) element: PyStatementList
32(33) element: PyExpressionStatement
33() element: null
@@ -1,26 +1,32 @@
0(1) element: null
1(2) element: PyIfStatement
2(3,6) READ ACCESS: c
3(4) element: PyStatementList. Condition: c:true
4(5) ASSERTTYPE ACCESS: c
5(12) element: PyPassStatement
6(7) element: PyIfPartElif. Condition: c:false
7(12) READ ACCESS: False
8(9) element: PyStatementList. Condition: False:true
9(10) ASSERTTYPE ACCESS: False
10(11) element: PyAssignmentStatement
11(12) WRITE ACCESS: a
12(13) element: PyIfStatement
13(14,17) READ ACCESS: d
14(15) element: PyStatementList. Condition: d:true
15(16) ASSERTTYPE ACCESS: d
16(25) element: PyPassStatement
17(18) element: PyIfPartElif. Condition: d:false
18(23) READ ACCESS: False
19(20) element: PyStatementList. Condition: False:true
20(21) ASSERTTYPE ACCESS: False
21(22) element: PyAssignmentStatement
22(25) WRITE ACCESS: b
23(24) element: PyStatementList. Condition: False:false
24(25) element: PyPassStatement
25() element: null
2(3,4) READ ACCESS: c
3(8) element: null. Condition: c:false
4(5) element: null. Condition: c:true
5(6) ASSERTTYPE ACCESS: c
6(7) element: PyStatementList
7(15) element: PyPassStatement
8(9,10) READ ACCESS: False
9(15) element: null. Condition: False:false
10(11) element: null. Condition: False:true
11() ASSERTTYPE ACCESS: False
12(13) element: PyStatementList
13(14) element: PyAssignmentStatement
14(15) WRITE ACCESS: a
15(16) element: PyIfStatement
16(17,18) READ ACCESS: d
17(22) element: null. Condition: d:false
18(19) element: null. Condition: d:true
19(20) ASSERTTYPE ACCESS: d
20(21) element: PyStatementList
21(31) element: PyPassStatement
22(23,24) READ ACCESS: False
23(29) element: null. Condition: False:false
24(25) element: null. Condition: False:true
25() ASSERTTYPE ACCESS: False
26(27) element: PyStatementList
27(28) element: PyAssignmentStatement
28(31) WRITE ACCESS: b
29(30) element: PyStatementList
30(31) element: PyPassStatement
31() element: null
@@ -1,25 +1,31 @@
0(1) element: null
1(2) element: PyIfStatement
2(3,6) READ ACCESS: c
3(4) element: PyStatementList. Condition: c:true
4(5) ASSERTTYPE ACCESS: c
5(11) element: PyPassStatement
6(7) element: PyIfPartElif. Condition: c:false
7(8) READ ACCESS: True
8(9) element: PyStatementList. Condition: True:true
9(10) ASSERTTYPE ACCESS: True
10(11) element: PyPassStatement
11(12) element: PyIfStatement
12(13,16) READ ACCESS: d
13(14) element: PyStatementList. Condition: d:true
14(15) ASSERTTYPE ACCESS: d
15(24) element: PyPassStatement
16(17) element: PyIfPartElif. Condition: d:false
17(18) READ ACCESS: True
18(19) element: PyStatementList. Condition: True:true
19(20) ASSERTTYPE ACCESS: True
20(24) element: PyPassStatement
21(22) element: PyStatementList. Condition: True:false
22(23) element: PyAssignmentStatement
23(24) WRITE ACCESS: e
24() element: null
2(3,4) READ ACCESS: c
3(8) element: null. Condition: c:false
4(5) element: null. Condition: c:true
5(6) ASSERTTYPE ACCESS: c
6(7) element: PyStatementList
7(14) element: PyPassStatement
8(9,10) READ ACCESS: True
9(14) element: null. Condition: True:false
10(11) element: null. Condition: True:true
11(12) ASSERTTYPE ACCESS: True
12(13) element: PyStatementList
13(14) element: PyPassStatement
14(15) element: PyIfStatement
15(16,17) READ ACCESS: d
16(21) element: null. Condition: d:false
17(18) element: null. Condition: d:true
18(19) ASSERTTYPE ACCESS: d
19(20) element: PyStatementList
20(30) element: PyPassStatement
21(22,23) READ ACCESS: True
22() element: null. Condition: True:false
23(24) element: null. Condition: True:true
24(25) ASSERTTYPE ACCESS: True
25(26) element: PyStatementList
26(30) element: PyPassStatement
27(28) element: PyStatementList
28(29) element: PyAssignmentStatement
29(30) WRITE ACCESS: e
30() element: null
@@ -1,17 +1,19 @@
0(1) element: null
1(2) element: PyIfStatement
2(3,13) READ ACCESS: markup
3(4) element: PyStatementList. Condition: markup:true
4(5) ASSERTTYPE ACCESS: markup
5(6) element: PyTryExceptStatement
6(7,9) element: PyTryPart
7(8,9) element: PyReturnStatement
8(9,16) READ ACCESS: renderer
9(10) element: PyExceptPart
10(11) READ ACCESS: KeyError
11(12) element: PyRaiseStatement
12(16) READ ACCESS: Error
13(14) element: PyStatementList. Condition: markup:false
14(15) element: PyReturnStatement
15(16) READ ACCESS: body
16() element: null
2(3,4) READ ACCESS: markup
3(15) element: null. Condition: markup:false
4(5) element: null. Condition: markup:true
5(6) ASSERTTYPE ACCESS: markup
6(7) element: PyStatementList
7(8) element: PyTryExceptStatement
8(9,11) element: PyTryPart
9(10,11) element: PyReturnStatement
10(11,18) READ ACCESS: renderer
11(12) element: PyExceptPart
12(13) READ ACCESS: KeyError
13(14) element: PyRaiseStatement
14(18) READ ACCESS: Error
15(16) element: PyStatementList
16(17) element: PyReturnStatement
17(18) READ ACCESS: body
18() element: null
@@ -1,29 +1,36 @@
0(1) element: null
1(2) element: PyIfStatement
2(7) READ ACCESS: False
3(4) element: PyStatementList. Condition: False:true
4(5) ASSERTTYPE ACCESS: False
5(6) element: PyAssignmentStatement
6(7) WRITE ACCESS: a
7(8) element: PyIfStatement
8(13) READ ACCESS: False
9(10) element: PyStatementList. Condition: False:true
10(11) ASSERTTYPE ACCESS: False
11(12) element: PyAssignmentStatement
12(15) WRITE ACCESS: b
13(14) element: PyStatementList. Condition: False:false
14(15) element: PyPassStatement
15(16) element: PyIfStatement
16(21) READ ACCESS: False
17(18) element: PyStatementList. Condition: False:true
18(19) ASSERTTYPE ACCESS: False
19(20) element: PyAssignmentStatement
20(28) WRITE ACCESS: c
21(22) element: PyIfPartElif. Condition: False:false
22(23,26) READ ACCESS: d
23(24) element: PyStatementList. Condition: d:true
24(25) ASSERTTYPE ACCESS: d
25(28) element: PyPassStatement
26(27) element: PyStatementList. Condition: d:false
27(28) element: PyPassStatement
28() element: null
2(3,4) READ ACCESS: False
3(9) element: null. Condition: False:false
4(5) element: null. Condition: False:true
5() ASSERTTYPE ACCESS: False
6(7) element: PyStatementList
7(8) element: PyAssignmentStatement
8(9) WRITE ACCESS: a
9(10) element: PyIfStatement
10(11,12) READ ACCESS: False
11(17) element: null. Condition: False:false
12(13) element: null. Condition: False:true
13() ASSERTTYPE ACCESS: False
14(15) element: PyStatementList
15(16) element: PyAssignmentStatement
16(19) WRITE ACCESS: b
17(18) element: PyStatementList
18(19) element: PyPassStatement
19(20) element: PyIfStatement
20(21,22) READ ACCESS: False
21(27) element: null. Condition: False:false
22(23) element: null. Condition: False:true
23() ASSERTTYPE ACCESS: False
24(25) element: PyStatementList
25(26) element: PyAssignmentStatement
26(35) WRITE ACCESS: c
27(28,29) READ ACCESS: d
28(33) element: null. Condition: d:false
29(30) element: null. Condition: d:true
30(31) ASSERTTYPE ACCESS: d
31(32) element: PyStatementList
32(35) element: PyPassStatement
33(34) element: PyStatementList
34(35) element: PyPassStatement
35() element: null
@@ -1,29 +1,36 @@
0(1) element: null
1(2) element: PyIfStatement
2(3) READ ACCESS: True
3(4) element: PyStatementList. Condition: True:true
4(5) ASSERTTYPE ACCESS: True
5(6) element: PyPassStatement
6(7) element: PyIfStatement
7(8) READ ACCESS: True
8(9) element: PyStatementList. Condition: True:true
9(10) ASSERTTYPE ACCESS: True
10(14) element: PyPassStatement
11(12) element: PyStatementList. Condition: True:false
12(13) element: PyAssignmentStatement
13(14) WRITE ACCESS: b
14(15) element: PyIfStatement
15(16) READ ACCESS: True
16(17) element: PyStatementList. Condition: True:true
17(18) ASSERTTYPE ACCESS: True
18(28) element: PyPassStatement
19(20) element: PyIfPartElif. Condition: True:false
20(21) READ ACCESS: c
21(22) element: PyStatementList. Condition: c:true
22(23) ASSERTTYPE ACCESS: c
23(24) element: PyAssignmentStatement
24(28) WRITE ACCESS: d
25(26) element: PyStatementList. Condition: c:false
26(27) element: PyAssignmentStatement
27(28) WRITE ACCESS: e
28() element: null
2(3,4) READ ACCESS: True
3(8) element: null. Condition: True:false
4(5) element: null. Condition: True:true
5(6) ASSERTTYPE ACCESS: True
6(7) element: PyStatementList
7(8) element: PyPassStatement
8(9) element: PyIfStatement
9(10,11) READ ACCESS: True
10() element: null. Condition: True:false
11(12) element: null. Condition: True:true
12(13) ASSERTTYPE ACCESS: True
13(14) element: PyStatementList
14(18) element: PyPassStatement
15(16) element: PyStatementList
16(17) element: PyAssignmentStatement
17(18) WRITE ACCESS: b
18(19) element: PyIfStatement
19(20,21) READ ACCESS: True
20(25) element: null. Condition: True:false
21(22) element: null. Condition: True:true
22(23) ASSERTTYPE ACCESS: True
23(24) element: PyStatementList
24(35) element: PyPassStatement
25(26,27) READ ACCESS: c
26() element: null. Condition: c:false
27(28) element: null. Condition: c:true
28() ASSERTTYPE ACCESS: c
29(30) element: PyStatementList
30(31) element: PyAssignmentStatement
31(35) WRITE ACCESS: d
32(33) element: PyStatementList
33(34) element: PyAssignmentStatement
34(35) WRITE ACCESS: e
35() element: null
@@ -1,12 +1,14 @@
0(1) element: null
1(2) element: PyIfStatement
2(3) READ ACCESS: xs
3(4,8) READ ACCESS: None
4(5) element: PyStatementList. Condition: xs is None:true
5(6) ASSERTTYPE ACCESS: xs
6(7) element: PyAssignmentStatement
7(9) WRITE ACCESS: xs
8(9) ASSERTTYPE ACCESS: xs
9(10) element: PyPrintStatement
10(11) READ ACCESS: xs
11() element: null
3(4,6) READ ACCESS: None
4(5) element: null. Condition: xs is None:false
5(11) ASSERTTYPE ACCESS: xs
6(7) element: null. Condition: xs is None:true
7(8) ASSERTTYPE ACCESS: xs
8(9) element: PyStatementList
9(10) element: PyAssignmentStatement
10(11) WRITE ACCESS: xs
11(12) element: PyPrintStatement
12(13) READ ACCESS: xs
13() element: null
@@ -3,20 +3,24 @@
2(3) READ ACCESS: isinstance
3(4) READ ACCESS: x
4(5) READ ACCESS: str
5(6,18) element: PyCallExpression: isinstance
6(7) element: PyStatementList. Condition: not isinstance(x, str):true
7(8) ASSERTTYPE ACCESS: x
8(9) element: PyIfStatement
9(10) READ ACCESS: x
10(11,15) READ ACCESS: None
11(12) element: PyStatementList. Condition: x is None:true
12(13) ASSERTTYPE ACCESS: x
13(14) element: PyPrintStatement
14(16) READ ACCESS: x
15(16) ASSERTTYPE ACCESS: x
16(17) element: PyPrintStatement
17(19) READ ACCESS: x
18(19) ASSERTTYPE ACCESS: x
5(6,8) element: PyCallExpression: isinstance
6(7) element: null. Condition: isinstance(x, str):false
7(10) ASSERTTYPE ACCESS: x
8(9) element: null. Condition: isinstance(x, str):true
9(23) ASSERTTYPE ACCESS: x
10(11) element: PyStatementList
11(12) element: PyIfStatement
12(13) READ ACCESS: x
13(14,16) READ ACCESS: None
14(15) element: null. Condition: x is None:false
15(21) ASSERTTYPE ACCESS: x
16(17) element: null. Condition: x is None:true
17(18) ASSERTTYPE ACCESS: x
18(19) element: PyStatementList
19(20) element: PyPrintStatement
20(21) READ ACCESS: x
21() element: null
21(22) element: PyPrintStatement
22(23) READ ACCESS: x
23(24) element: PyPrintStatement
24(25) READ ACCESS: x
25() element: null
@@ -5,16 +5,18 @@
4(5) READ ACCESS: isinstance
5(6) READ ACCESS: s
6(7) READ ACCESS: basestring
7(8,14) element: PyCallExpression: isinstance
8(9) element: PyStatementList. Condition: (isinstance(s, basestring)):true
9(10) ASSERTTYPE ACCESS: s
10(11) element: PyAssignmentStatement
11(12) READ ACCESS: s
12(13) element: PyCallExpression: s.split
13(19) WRITE ACCESS: s2
14(15) element: PyStatementList. Condition: (isinstance(s, basestring)):false
15(16) ASSERTTYPE ACCESS: s
16(17) element: PyAssignmentStatement
17(18) READ ACCESS: s
18(19) WRITE ACCESS: x
19() element: null
7(8,10) element: PyCallExpression: isinstance
8(9) element: null. Condition: (isinstance(s, basestring)):false
9(17) ASSERTTYPE ACCESS: s
10(11) element: null. Condition: (isinstance(s, basestring)):true
11(12) ASSERTTYPE ACCESS: s
12(13) element: PyStatementList
13(14) element: PyAssignmentStatement
14(15) READ ACCESS: s
15(16) element: PyCallExpression: s.split
16(21) WRITE ACCESS: s2
17(18) element: PyStatementList
18(19) element: PyAssignmentStatement
19(20) READ ACCESS: s
20(21) WRITE ACCESS: x
21() element: null
@@ -3,26 +3,31 @@
2(3) WRITE ACCESS: var
3(4) element: PyIfStatement
4(5) READ ACCESS: a
5(6,9) READ ACCESS: b
6(7) element: PyStatementList. Condition: a == b:true
7(8) element: PyAssignmentStatement
8(25) WRITE ACCESS: var
9(10) element: PyIfPartElif. Condition: a == b:false
10(11) READ ACCESS: aa
11(12,22) READ ACCESS: bb
12(13) element: PyStatementList. Condition: aa == bb:true
13(14) element: PyAssignmentStatement
14(15) READ ACCESS: same_changet_expression
15(16) WRITE ACCESS: bbb
16(17) element: PyIfStatement
17(18,25) READ ACCESS: bbb
18(19) element: PyStatementList. Condition: bbb:true
19(20) ASSERTTYPE ACCESS: bbb
20(21) element: PyAssignmentStatement
21(25) WRITE ACCESS: var
22(23) element: PyStatementList. Condition: aa == bb:false
23(24) element: PyAssignmentStatement
24(25) WRITE ACCESS: var
25(26) element: PyReturnStatement
26(27) READ ACCESS: var
27() element: null
5(6,7) READ ACCESS: b
6(11) element: null. Condition: a == b:false
7(8) element: null. Condition: a == b:true
8(9) element: PyStatementList
9(10) element: PyAssignmentStatement
10(30) WRITE ACCESS: var
11(12) READ ACCESS: aa
12(13,14) READ ACCESS: bb
13(27) element: null. Condition: aa == bb:false
14(15) element: null. Condition: aa == bb:true
15(16) element: PyStatementList
16(17) element: PyAssignmentStatement
17(18) READ ACCESS: same_changet_expression
18(19) WRITE ACCESS: bbb
19(20) element: PyIfStatement
20(21,22) READ ACCESS: bbb
21(30) element: null. Condition: bbb:false
22(23) element: null. Condition: bbb:true
23(24) ASSERTTYPE ACCESS: bbb
24(25) element: PyStatementList
25(26) element: PyAssignmentStatement
26(30) WRITE ACCESS: var
27(28) element: PyStatementList
28(29) element: PyAssignmentStatement
29(30) WRITE ACCESS: var
30(31) element: PyReturnStatement
31(32) READ ACCESS: var
32() element: null
@@ -1,14 +1,16 @@
0(1) element: null
1(2) element: PyWhileStatement
2(3,11) READ ACCESS: x
3(4) element: PyStatementList. Condition: x:true
4(5) element: PyMatchStatement
5(6) READ ACCESS: x
6(7,9) refutable pattern: 42
7(8) matched pattern: 42
8(11) element: PyBreakStatement
9(10) element: PyExpressionStatement
10(1) READ ACCESS: y
2(3,4) READ ACCESS: x
3(13) element: null. Condition: x:false
4(5) element: null. Condition: x:true
5(6) element: PyStatementList
6(7) element: PyMatchStatement
7(8) READ ACCESS: x
8(9,11) refutable pattern: 42
9(10) matched pattern: 42
10(13) element: PyBreakStatement
11(12) element: PyExpressionStatement
12(13) READ ACCESS: z
13() element: null
12(1) READ ACCESS: y
13(14) element: PyExpressionStatement
14(15) READ ACCESS: z
15() element: null
@@ -1,14 +1,16 @@
0(1) element: null
1(2) element: PyWhileStatement
2(3,11) READ ACCESS: x
3(4) element: PyStatementList. Condition: x:true
4(5) element: PyMatchStatement
5(6) READ ACCESS: x
6(7,9) refutable pattern: 42
7(8) matched pattern: 42
8(1) element: PyContinueStatement
9(10) element: PyExpressionStatement
10(1) READ ACCESS: y
2(3,4) READ ACCESS: x
3(13) element: null. Condition: x:false
4(5) element: null. Condition: x:true
5(6) element: PyStatementList
6(7) element: PyMatchStatement
7(8) READ ACCESS: x
8(9,11) refutable pattern: 42
9(10) matched pattern: 42
10(1) element: PyContinueStatement
11(12) element: PyExpressionStatement
12(13) READ ACCESS: z
13() element: null
12(1) READ ACCESS: y
13(14) element: PyExpressionStatement
14(15) READ ACCESS: z
15() element: null
@@ -3,10 +3,10 @@
2(3) WRITE ACCESS: x
3(4) element: PyBinaryExpression
4(5,6) READ ACCESS: x
5(13) element: null. Condition: x > 0:false
5(10) element: null. Condition: x > 0:false
6(7) element: null. Condition: x > 0:true
7(8,9) READ ACCESS: x
8(13) element: null. Condition: x < 10:false
8(10) element: null. Condition: x < 10:false
9(10) element: null. Condition: x < 10:true
10(11) element: PyStatementList. Condition: x > 0 and x < 10:true
11(12) element: PyExpressionStatement
@@ -3,20 +3,18 @@
2(3) WRITE ACCESS: x
3(4) element: PyBinaryExpression
4(5,6) READ ACCESS: x
5(19) element: null. Condition: x % 4 == 0:false
5(14) element: null. Condition: x % 4 == 0:false
6(7) element: null. Condition: x % 4 == 0:true
7(8) element: PyBinaryExpression
8(9,10) READ ACCESS: x
9(16) element: null. Condition: x % 400 == 0:true
10(11) element: null. Condition: x % 400 == 0:false
9(11) element: null. Condition: x % 400 == 0:false
10(14) element: null. Condition: x % 400 == 0:true
11(12,13) READ ACCESS: x
12(19) element: null. Condition: x % 100 != 0:false
13(14,15) element: null. Condition: x % 100 != 0:true
14(19) element: null. Condition: (x % 400 == 0 or x % 100 != 0):false
15(16) element: null. Condition: (x % 400 == 0 or x % 100 != 0):true
16(17) element: PyStatementList. Condition: x % 4 == 0 and (x % 400 == 0 or x % 100 != 0):true
12(14) element: null. Condition: x % 100 != 0:false
13(14) element: null. Condition: x % 100 != 0:true
14(15) element: PyStatementList. Condition: x % 4 == 0 and (x % 400 == 0 or x % 100 != 0):true
15(16) element: PyExpressionStatement
16(17) READ ACCESS: y
17(18) element: PyExpressionStatement
18(19) READ ACCESS: y
19(20) element: PyExpressionStatement
20(21) READ ACCESS: z
21() element: null
18(19) READ ACCESS: z
19() element: null
@@ -3,10 +3,10 @@
2(3) WRITE ACCESS: x
3(4) element: PyBinaryExpression
4(5,6) READ ACCESS: x
5(10) element: null. Condition: x > 0:true
6(7) element: null. Condition: x > 0:false
5(7) element: null. Condition: x > 0:false
6(10) element: null. Condition: x > 0:true
7(8,9) READ ACCESS: x
8(13) element: null. Condition: x < 0:false
8(10) element: null. Condition: x < 0:false
9(10) element: null. Condition: x < 0:true
10(11) element: PyStatementList. Condition: x > 0 or x < 0:true
11(12) element: PyExpressionStatement
@@ -7,8 +7,8 @@
6(7) matched pattern: [x1, x2, x3]
7(8) element: PyBinaryExpression
8(9,10) READ ACCESS: x1
9(14) element: null. Condition: x1:true
10(11) element: null. Condition: x1:false
9(11) element: null. Condition: x1:false
10(14) element: null. Condition: x1:true
11(12,13) READ ACCESS: x2
12(14) element: null. Condition: x2:false
13(14) element: null. Condition: x2:true
@@ -5,10 +5,10 @@
4(5) matched pattern: [x]
5(6) element: PyBinaryExpression
6(7,8) READ ACCESS: x
7(15) element: null. Condition: x > 0:false
7(12) element: null. Condition: x > 0:false
8(9) element: null. Condition: x > 0:true
9(10,11) READ ACCESS: x
10(15) element: null. Condition: x % 2 == 0:false
10(12) element: null. Condition: x % 2 == 0:false
11(12) element: null. Condition: x % 2 == 0:true
12(13) element: PyStatementList. Condition: x > 0 and x % 2 == 0:true
13(14) element: PyExpressionStatement
@@ -2,8 +2,8 @@
1(2) element: PyAssignmentStatement
2(3) element: PyBinaryExpression
3(4,5) READ ACCESS: bar
4(9) element: null. Condition: bar:true
5(6) element: null. Condition: bar:false
4(6) element: null. Condition: bar:false
5(9) element: null. Condition: bar:true
6(7,8) READ ACCESS: baz
7(9) element: null. Condition: baz:false
8(9) element: null. Condition: baz:true
@@ -1,11 +1,15 @@
0(1) element: null
1(2) element: PyWhileStatement
2(3,10) READ ACCESS: foo
3(4) element: PyStatementList. Condition: foo:true
4(5) element: PyIfStatement
5(6,9) READ ACCESS: condition
6(7) element: PyStatementList. Condition: condition:true
7(8) ASSERTTYPE ACCESS: condition
8(10) element: PyReturnStatement
9(1) element: PyPrintStatement
10() element: null
2(3,4) READ ACCESS: foo
3(14) element: null. Condition: foo:false
4(5) element: null. Condition: foo:true
5(6) element: PyStatementList
6(7) element: PyIfStatement
7(8,9) READ ACCESS: condition
8(13) element: null. Condition: condition:false
9(10) element: null. Condition: condition:true
10(11) ASSERTTYPE ACCESS: condition
11(12) element: PyStatementList
12(14) element: PyReturnStatement
13(1) element: PyPrintStatement
14() element: null
@@ -2,10 +2,12 @@
1(2) element: PyAssignmentStatement
2(3) WRITE ACCESS: sibling
3(4) element: PyIfStatement
4(5,10) READ ACCESS: sibling
5(6) element: PyStatementList. Condition: sibling:true
6(7) ASSERTTYPE ACCESS: sibling
7(8) element: PyAssignmentStatement
8(9) element: PySubscriptionExpression
9(10) READ ACCESS: sibling
10() element: null
4(5,6) READ ACCESS: sibling
5(12) element: null. Condition: sibling:false
6(7) element: null. Condition: sibling:true
7(8) ASSERTTYPE ACCESS: sibling
8(9) element: PyStatementList
9(10) element: PyAssignmentStatement
10(11) element: PySubscriptionExpression
11(12) READ ACCESS: sibling
12() element: null
@@ -7,26 +7,30 @@
6(7,10) element: PyAssignmentStatement
7(8,10) READ ACCESS: open
8(9,10) element: PyCallExpression: open
9(10,19) WRITE ACCESS: status
9(10,21) WRITE ACCESS: status
10(11) element: PyFinallyPart
11(12) element: PyIfStatement
12(13) READ ACCESS: status
13(14,18) READ ACCESS: None
14(15) element: PyStatementList. Condition: status is not None:true
15(16) ASSERTTYPE ACCESS: status
16(17) element: PyPrintStatement
17(31) READ ACCESS: status
18(31) ASSERTTYPE ACCESS: status
19(20) element: PyFinallyPart
20(21) element: PyIfStatement
21(22) READ ACCESS: status
22(23,27) READ ACCESS: None
23(24) element: PyStatementList. Condition: status is not None:true
24(25) ASSERTTYPE ACCESS: status
25(26) element: PyPrintStatement
26(28) READ ACCESS: status
27(28) ASSERTTYPE ACCESS: status
28(29) element: PyExpressionStatement
29(30) READ ACCESS: status
30(31) element: PyCallExpression: status.close
31() element: null
13(14,16) READ ACCESS: None
14(15) element: null. Condition: status is not None:false
15() ASSERTTYPE ACCESS: status
16(17) element: null. Condition: status is not None:true
17(18) ASSERTTYPE ACCESS: status
18(19) element: PyStatementList
19(20) element: PyPrintStatement
20() READ ACCESS: status
21(22) element: PyFinallyPart
22(23) element: PyIfStatement
23(24) READ ACCESS: status
24(25,27) READ ACCESS: None
25(26) element: null. Condition: status is not None:false
26(32) ASSERTTYPE ACCESS: status
27(28) element: null. Condition: status is not None:true
28(29) ASSERTTYPE ACCESS: status
29(30) element: PyStatementList
30(31) element: PyPrintStatement
31(32) READ ACCESS: status
32(33) element: PyExpressionStatement
33(34) READ ACCESS: status
34(35) element: PyCallExpression: status.close
35() element: null
@@ -2,64 +2,69 @@
1(2) element: PyAssignmentStatement
2(3) WRITE ACCESS: a
3(4) element: PyTryExceptStatement
4(5,56) element: PyTryPart
5(6,56) element: PyAssignmentStatement
6(7,56) WRITE ACCESS: b
7(8,56) element: PyForStatement
8(9,56) element: PyTargetExpression: x
9(10,56) WRITE ACCESS: x
10(11,56) element: PyTryExceptStatement
11(12,46) element: PyTryPart
12(13,46) element: PyAssignmentStatement
13(14,46) WRITE ACCESS: c
14(15,46) element: PyTryExceptStatement
15(16,38) element: PyTryPart
16(17,38) element: PyAssignmentStatement
17(18,38) WRITE ACCESS: d
18(19,38) element: PyIfStatement
19(20,22,38) READ ACCESS: x
20(21) element: PyStatementList. Condition: x == 0:true
21(38,41) element: PyBreakStatement
22(23,38) element: PyIfPartElif. Condition: x == 0:false
23(24,26,38) READ ACCESS: x
24(25) element: PyStatementList. Condition: x == 1:true
25(7,38,41) element: PyContinueStatement
26(27,38) element: PyIfPartElif. Condition: x == 1:false
27(28,32,38) READ ACCESS: x
28(29) element: PyStatementList. Condition: x == 2:true
29(30,38) element: PyRaiseStatement
30(31,38) READ ACCESS: Exception
31(38) element: PyCallExpression: Exception
32(33,38) element: PyIfPartElif. Condition: x == 2:false
33(34,36,38) READ ACCESS: x
34(35) element: PyStatementList. Condition: x == 3:true
35(38) element: PyReturnStatement
36(37,38) element: PyAssignmentStatement
37(38,41) WRITE ACCESS: e
38(39,46) element: PyFinallyPart
39(40,46) element: PyAssignmentStatement
40(46) WRITE ACCESS: f
41(42,46) element: PyFinallyPart
42(43,46) element: PyAssignmentStatement
43(44,46,49) WRITE ACCESS: f
44(45,46) element: PyAssignmentStatement
45(46,49) WRITE ACCESS: g
46(47,56) element: PyFinallyPart
47(48,56) element: PyAssignmentStatement
48(56) WRITE ACCESS: h
49(50,56) element: PyFinallyPart
50(51,56) element: PyAssignmentStatement
51(52,54,56) WRITE ACCESS: h
52(53,56) element: PyAssignmentStatement
53(8,54,56) WRITE ACCESS: i
54(55,56) element: PyAssignmentStatement
55(56,59) WRITE ACCESS: j
56(57) element: PyFinallyPart
57(58) element: PyAssignmentStatement
58(64) WRITE ACCESS: k
59(60) element: PyFinallyPart
60(61) element: PyAssignmentStatement
61(62) WRITE ACCESS: k
4(5,61) element: PyTryPart
5(6,61) element: PyAssignmentStatement
6(7,61) WRITE ACCESS: b
7(8,61) element: PyForStatement
8(9,61) element: PyTargetExpression: x
9(10,61) WRITE ACCESS: x
10(11,61) element: PyTryExceptStatement
11(12,51) element: PyTryPart
12(13,51) element: PyAssignmentStatement
13(14,51) WRITE ACCESS: c
14(15,51) element: PyTryExceptStatement
15(16,43) element: PyTryPart
16(17,43) element: PyAssignmentStatement
17(18,43) WRITE ACCESS: d
18(19,43) element: PyIfStatement
19(20,21,43) READ ACCESS: x
20(24) element: null. Condition: x == 0:false
21(22) element: null. Condition: x == 0:true
22(23) element: PyStatementList
23(43,46) element: PyBreakStatement
24(25,26,43) READ ACCESS: x
25(29) element: null. Condition: x == 1:false
26(27) element: null. Condition: x == 1:true
27(28) element: PyStatementList
28(7,43,46) element: PyContinueStatement
29(30,31,43) READ ACCESS: x
30(36) element: null. Condition: x == 2:false
31(32) element: null. Condition: x == 2:true
32(33) element: PyStatementList
33(34,43) element: PyRaiseStatement
34(35,43) READ ACCESS: Exception
35(43) element: PyCallExpression: Exception
36(37,38,43) READ ACCESS: x
37(41) element: null. Condition: x == 3:false
38(39) element: null. Condition: x == 3:true
39(40) element: PyStatementList
40(43) element: PyReturnStatement
41(42,43) element: PyAssignmentStatement
42(43,46) WRITE ACCESS: e
43(44,51) element: PyFinallyPart
44(45,51) element: PyAssignmentStatement
45(51) WRITE ACCESS: f
46(47,51) element: PyFinallyPart
47(48,51) element: PyAssignmentStatement
48(49,51,54) WRITE ACCESS: f
49(50,51) element: PyAssignmentStatement
50(51,54) WRITE ACCESS: g
51(52,61) element: PyFinallyPart
52(53,61) element: PyAssignmentStatement
53(61) WRITE ACCESS: h
54(55,61) element: PyFinallyPart
55(56,61) element: PyAssignmentStatement
56(57,59,61) WRITE ACCESS: h
57(58,61) element: PyAssignmentStatement
58(8,59,61) WRITE ACCESS: i
59(60,61) element: PyAssignmentStatement
60(61,64) WRITE ACCESS: j
61(62) element: PyFinallyPart
62(63) element: PyAssignmentStatement
63(64) WRITE ACCESS: l
64() element: null
63(69) WRITE ACCESS: k
64(65) element: PyFinallyPart
65(66) element: PyAssignmentStatement
66(67) WRITE ACCESS: k
67(68) element: PyAssignmentStatement
68(69) WRITE ACCESS: l
69() element: null
@@ -22,10 +22,12 @@
21(22) element: PyIfStatement
22(23) READ ACCESS: checkit
23(24) READ ACCESS: x
24(25,28) element: PyCallExpression: checkit
25(26) element: PyStatementList. Condition: checkit(x):true
26(27) element: PyPrintStatement
27(30) READ ACCESS: x
28(29) element: PyStatementList. Condition: checkit(x):false
29(30) element: PyPassStatement
30() element: null
24(25,26) element: PyCallExpression: checkit
25(30) element: null. Condition: checkit(x):false
26(27) element: null. Condition: checkit(x):true
27(28) element: PyStatementList
28(29) element: PyPrintStatement
29(32) READ ACCESS: x
30(31) element: PyStatementList
31(32) element: PyPassStatement
32() element: null
@@ -22,10 +22,12 @@
21(22) element: PyWhileStatement
22(23) READ ACCESS: checkit
23(24) READ ACCESS: x
24(25,30) element: PyCallExpression: checkit
25(26) element: PyStatementList. Condition: checkit(x):true
26(27) element: PyAssignmentStatement
27(28) READ ACCESS: foo
28(29) element: PyCallExpression: foo.bar
29(21) WRITE ACCESS: x
30() element: null
24(25,26) element: PyCallExpression: checkit
25(32) element: null. Condition: checkit(x):false
26(27) element: null. Condition: checkit(x):true
27(28) element: PyStatementList
28(29) element: PyAssignmentStatement
29(30) READ ACCESS: foo
30(31) element: PyCallExpression: foo.bar
31(21) WRITE ACCESS: x
32() element: null
@@ -10,15 +10,14 @@
9(10) READ ACCESS: isinstance
10(11) READ ACCESS: var
11(12) READ ACCESS: A
12(13,14) element: PyCallExpression: isinstance
13(22) element: null. Condition: isinstance(var, A):false
14(15) element: null. Condition: isinstance(var, A):true
15(16) ASSERTTYPE ACCESS: var
16(17,18) READ ACCESS: var
17(22) element: null. Condition: var:false
18(19) element: null. Condition: var:true
19(20) element: PyStatementList. Condition: isinstance(var, A) and var:true
20(21) ASSERTTYPE ACCESS: var
21(23) element: PyPassStatement
22(23) ASSERTTYPE ACCESS: var
23() element: null
12(13,15) element: PyCallExpression: isinstance
13(14) element: null. Condition: isinstance(var, A):false
14(22) ASSERTTYPE ACCESS: var
15(16) element: null. Condition: isinstance(var, A):true
16(17) ASSERTTYPE ACCESS: var
17(18,19) READ ACCESS: var
18(22) element: null. Condition: var:false
19(20) element: null. Condition: var:true
20(21) element: PyStatementList
21(22) element: PyPassStatement
22() element: null
@@ -7,24 +7,25 @@
6(7) READ ACCESS: isinstance
7(8) READ ACCESS: var
8(9) READ ACCESS: A
9(10,28) element: PyCallExpression: isinstance
10(11) element: PyStatementList. Condition: isinstance(var, A):true
11(12) ASSERTTYPE ACCESS: var
12(13) element: PyIfStatement
13(14) element: PyBinaryExpression
14(15) READ ACCESS: isinstance
15(16) READ ACCESS: var
16(17) READ ACCESS: B
17(18,19) element: PyCallExpression: isinstance
18(24) element: null. Condition: isinstance(var, B):true
19(20) element: null. Condition: isinstance(var, B):false
20(21) ASSERTTYPE ACCESS: var
21(22,23) READ ACCESS: var
22(27) element: null. Condition: var:false
23(24) element: null. Condition: var:true
24(25) element: PyStatementList. Condition: isinstance(var, B) or var:true
25(26) ASSERTTYPE ACCESS: var
26(29) element: PyPassStatement
27(29) ASSERTTYPE ACCESS: var
28(29) ASSERTTYPE ACCESS: var
29() element: null
9(10,12) element: PyCallExpression: isinstance
10(11) element: null. Condition: isinstance(var, A):false
11(30) ASSERTTYPE ACCESS: var
12(13) element: null. Condition: isinstance(var, A):true
13(14) ASSERTTYPE ACCESS: var
14(15) element: PyStatementList
15(16) element: PyIfStatement
16(17) element: PyBinaryExpression
17(18) READ ACCESS: isinstance
18(19) READ ACCESS: var
19(20) READ ACCESS: B
20(21,23) element: PyCallExpression: isinstance
21(22) element: null. Condition: isinstance(var, B):false
22(25) ASSERTTYPE ACCESS: var
23(24) element: null. Condition: isinstance(var, B):true
24(28) ASSERTTYPE ACCESS: var
25(26,27) READ ACCESS: var
26(30) element: null. Condition: var:false
27(28) element: null. Condition: var:true
28(29) element: PyStatementList
29(30) element: PyPassStatement
30() element: null
@@ -1,46 +1,58 @@
0(1) element: null
1(2) element: PyWhileStatement
2(3,6) READ ACCESS: c1
3(4) element: PyStatementList. Condition: c1:true
4(5) element: PyAssignmentStatement
5(1) WRITE ACCESS: x
6(7) element: PyElsePart. Condition: c1:false
7(8) element: PyAssignmentStatement
8(9) WRITE ACCESS: y
9(10) element: PyWhileStatement
10(11,17) READ ACCESS: c2
11(12) element: PyStatementList. Condition: c2:true
12(13) element: PyAssignmentStatement
13(14) WRITE ACCESS: a
14(20) element: PyBreakStatement
15(16) element: PyAssignmentStatement
16(9) WRITE ACCESS: b
17(18) element: PyElsePart. Condition: c2:false
18(19) element: PyAssignmentStatement
19(20) WRITE ACCESS: c
20(21) element: PyWhileStatement
21(22,32) READ ACCESS: c3
22(23) element: PyStatementList. Condition: c3:true
23(24) element: PyAssignmentStatement
24(25) WRITE ACCESS: m
25(26) element: PyIfStatement
26(27,30) READ ACCESS: m
27(28) element: PyStatementList. Condition: m:true
28(29) ASSERTTYPE ACCESS: m
29(35) element: PyBreakStatement
30(31) element: PyAssignmentStatement
31(20) WRITE ACCESS: n
32(33) element: PyElsePart. Condition: c3:false
33(34) element: PyAssignmentStatement
34(35) WRITE ACCESS: o
35(36) element: PyWhileStatement
36(37,45) READ ACCESS: c4
37(38) element: PyStatementList. Condition: c4:true
2(3,4) READ ACCESS: c1
3(8) element: null. Condition: c1:false
4(5) element: null. Condition: c1:true
5(6) element: PyStatementList
6(7) element: PyAssignmentStatement
7(1) WRITE ACCESS: x
8(9) element: PyStatementList
9(10) element: PyAssignmentStatement
10(11) WRITE ACCESS: y
11(12) element: PyWhileStatement
12(13,14) READ ACCESS: c2
13(21) element: null. Condition: c2:false
14(15) element: null. Condition: c2:true
15(16) element: PyStatementList
16(17) element: PyAssignmentStatement
17(18) WRITE ACCESS: a
18(24) element: PyBreakStatement
19(20) element: PyAssignmentStatement
20(11) WRITE ACCESS: b
21(22) element: PyStatementList
22(23) element: PyAssignmentStatement
23(24) WRITE ACCESS: c
24(25) element: PyWhileStatement
25(26,27) READ ACCESS: c3
26(40) element: null. Condition: c3:false
27(28) element: null. Condition: c3:true
28(29) element: PyStatementList
29(30) element: PyAssignmentStatement
30(31) WRITE ACCESS: m
31(32) element: PyIfStatement
32(33,34) READ ACCESS: m
33(38) element: null. Condition: m:false
34(35) element: null. Condition: m:true
35(36) ASSERTTYPE ACCESS: m
36(37) element: PyStatementList
37(43) element: PyBreakStatement
38(39) element: PyAssignmentStatement
39(40) WRITE ACCESS: m
40(41) element: PyIfStatement
41(42,35) READ ACCESS: m
42(43) element: PyStatementList. Condition: m:true
43(44) ASSERTTYPE ACCESS: m
44(45) element: PyBreakStatement
45() element: null
39(24) WRITE ACCESS: n
40(41) element: PyStatementList
41(42) element: PyAssignmentStatement
42(43) WRITE ACCESS: o
43(44) element: PyWhileStatement
44(45,46) READ ACCESS: c4
45(57) element: null. Condition: c4:false
46(47) element: null. Condition: c4:true
47(48) element: PyStatementList
48(49) element: PyAssignmentStatement
49(50) WRITE ACCESS: m
50(51) element: PyIfStatement
51(52,53) READ ACCESS: m
52(43) element: null. Condition: m:false
53(54) element: null. Condition: m:true
54(55) ASSERTTYPE ACCESS: m
55(56) element: PyStatementList
56(57) element: PyBreakStatement
57() element: null
@@ -1,8 +1,10 @@
0(1) element: null
1(2) element: PyWhileStatement
2(3) READ ACCESS: True
3(4) element: PyStatementList. Condition: True:true
4(1) element: PyPassStatement
5(6) element: PyElsePart. Condition: True:false
6(7) element: PyPrintStatement
7() element: null
2(3,4) READ ACCESS: True
3() element: null. Condition: True:false
4(5) element: null. Condition: True:true
5(6) element: PyStatementList
6(1) element: PyPassStatement
7(8) element: PyStatementList
8(9) element: PyPrintStatement
9() element: null
@@ -5,6 +5,9 @@
4(5) READ ACCESS: True
5(6) READ ACCESS: f
6(7) element: PyCallExpression: f
7(8) element: PyPrintStatement
8(9) element: PyPrintStatement
9() element: null
7(8,9) READ ACCESS: True
8(12) element: null. Condition: True:false
9(10) element: null. Condition: True:true
10(11) element: PyPrintStatement
11(12) element: PyPrintStatement
12() element: null
@@ -2,14 +2,16 @@
1(2) element: PyWithStatement
2(3) READ ACCESS: context_manager
3(4) element: PyIfStatement
4(5,9) READ ACCESS: c
5(6) element: PyStatementList. Condition: c:true
6(7) ASSERTTYPE ACCESS: c
7(8) element: PyRaiseStatement
8(12,14) READ ACCESS: ValueError
9(10) element: PyAssignmentStatement
10(11) READ ACCESS: c
11(12) WRITE ACCESS: val
12(13) element: PyPrintStatement
13(14) READ ACCESS: val
14() element: null
4(5,6) READ ACCESS: c
5(11) element: null. Condition: c:false
6(7) element: null. Condition: c:true
7(8) ASSERTTYPE ACCESS: c
8(9) element: PyStatementList
9(10) element: PyRaiseStatement
10(14,16) READ ACCESS: ValueError
11(12) element: PyAssignmentStatement
12(13) READ ACCESS: c
13(14) WRITE ACCESS: val
14(15) element: PyPrintStatement
15(16) READ ACCESS: val
16() element: null
@@ -17,7 +17,7 @@ def test(c):
"""
x1 = f1(c)
f2(x1) # Weaker union types
f3(<warning descr="Expected type 'int', got 'Union[list, str, None]' instead">x1</warning>)
f3(<warning descr="Expected type 'int', got 'Union[str, list, None]' instead">x1</warning>)
f2(<warning descr="Expected type 'str', got 'int' instead">x1.count('')</warning>)
f3(x1.count(''))
@@ -2175,7 +2175,7 @@ public class Py3TypeTest extends PyTestCase {
public void testTypeGuardResultIsAssignedButValIsReassignedSometimes() {
doTest("int | list[str]",
doTest("list[str] | int",
"""
from typing import List
from typing import TypeGuard
@@ -287,6 +287,74 @@ public class PyTypeTest extends PyTestCase {
""");
}
public void testIfIsInstanceOr1() {
doTest("Union[str, int]",
"""
def foo(a):
if isinstance(a, int) or isinstance(a, str):
expr = a
""");
}
public void testIfIsInstanceOr2() {
doTest("Union[B, A, int, str]",
"""
class A:
pass
class B:
pass
def f(a: object):
if isinstance(a, str) or isinstance(a, int) or isinstance(a, A) or isinstance(a, B):
expr = a
else:
pass
""");
}
public void testIfIsInstanceAnd1() {
doTest("A",
"""
class A:
pass
def f(a):
if isinstance(a, (str, A)) and isinstance(a, (A, int)):
expr = a
""");
}
public void testIfIsInstanceAnd2() {
doTest("A",
"""
class A:
pass
class B:
pass
def f(a):
if isinstance(a, (str, A)) and isinstance(a, (A, int)) and isinstance(a, (B, A)):
expr = a
""");
}
public void testIfIsInstanceLogicalExpressions() {
doTest("Union[B, str]",
"""
class A:
pass
class B:
pass
def f(a):
if isinstance(a, (str, A, int)) and not isinstance(a, (A, int)) or isinstance(a, B):
expr = a
""");
}
// PY-4383
public void testAssertIsInstance() {
doTest("int",
@@ -3335,7 +3403,7 @@ public class PyTypeTest extends PyTestCase {
// PY-9634
public void testAfterIsInstanceAndAttributeUsage() {
doTest("Union[int, {bar}]",
doTest("Union[{bar}, int]",
"""
def bar(y):
if isinstance(y, int):
@@ -4108,28 +4176,34 @@ public class PyTypeTest extends PyTestCase {
doTest("int", "((expr)) = 42");
}
public void testElif() {
doTest("float",
public void testElif1() {
doTest("str",
"""
def foo(a: int | str | float):
if isinstance(a, int):
pass
elif isinstance(a, str):
pass
else:
expr = a
""");
class A:
pass
def foo(a: int | str | A):
if isinstance(a, A):
pass
elif isinstance(a, int):
pass
else:
expr = a
""");
}
public void testElif2() {
doTest("float",
doTest("A",
"""
def foo(a: int | str | float):
if isinstance(a, int):
pass
elif not isinstance(a, str):
expr = a
""");
class A:
pass
def foo(a: int | str | A):
if isinstance(a, int):
pass
elif not isinstance(a, str):
expr = a
""");
}
private static List<TypeEvalContext> getTypeEvalContexts(@NotNull PyExpression element) {
@@ -66,6 +66,16 @@ public class PyUnreachableCodeInspectionTest extends PyInspectionTestCase {
doTest();
}
public void testWhileTrue() {
doTestByText(
"""
while True:
pass
<warning descr="This code is unreachable">print()</warning>
"""
);
}
// PY-22184
public void testWhileTrueTryBreakFinally() {
doTest();
@@ -76,15 +86,18 @@ public class PyUnreachableCodeInspectionTest extends PyInspectionTestCase {
doTestByText(
"""
if False:
<warning descr="This code is unreachable">a = 1</warning>
<warning descr="This code is unreachable">a = 1
a1 = 1</warning>
if False:
<warning descr="This code is unreachable">b = 1</warning>
<warning descr="This code is unreachable">b = 1
b1 = 1</warning>
else:
pass
if False:
<warning descr="This code is unreachable">c = 1</warning>
<warning descr="This code is unreachable">c = 1
c1 = 1</warning>
elif d:
pass
else:
@@ -103,14 +116,17 @@ public class PyUnreachableCodeInspectionTest extends PyInspectionTestCase {
if True:
pass
else:
<warning descr="This code is unreachable">b = 1</warning>
<warning descr="This code is unreachable">b = 1
b1 = 1</warning>
if True:
pass
elif c:
<warning descr="This code is unreachable">d = 1</warning>
<warning descr="This code is unreachable">d = 1
d1 = 1</warning>
else:
<warning descr="This code is unreachable">e = 1</warning>
<warning descr="This code is unreachable">e = 1
e1 = 1</warning>
"""
);
}
@@ -129,7 +145,8 @@ public class PyUnreachableCodeInspectionTest extends PyInspectionTestCase {
elif True:
pass
else:
<warning descr="This code is unreachable">e = 1</warning>
<warning descr="This code is unreachable">e = 1
f = 2</warning>
"""
);
}
@@ -141,12 +158,14 @@ public class PyUnreachableCodeInspectionTest extends PyInspectionTestCase {
if c:
pass
elif False:
<warning descr="This code is unreachable">a = 1</warning>
<warning descr="This code is unreachable">a = 1
a1 = 1</warning>
if d:
pass
elif False:
<warning descr="This code is unreachable">b = 1</warning>
<warning descr="This code is unreachable">b = 1
b1 = 1</warning>
else:
pass"""
);