mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[python] CFG support logical expressions in if/while conditions
GitOrigin-RevId: 274b3271dccc93be64830374c8047a8f6552033e
This commit is contained in:
committed by
intellij-monorepo-bot
parent
94aaceafb6
commit
3f8f4f40c3
+8
-1
@@ -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);
|
||||
|
||||
+155
-251
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-2
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-16
@@ -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();
|
||||
|
||||
|
||||
+2
-1
@@ -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
|
||||
}
|
||||
|
||||
+9
-9
@@ -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
|
||||
+6
-6
@@ -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
|
||||
@@ -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
|
||||
+19
-15
@@ -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
|
||||
+2
-2
@@ -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
|
||||
|
||||
+10
-12
@@ -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
-3
@@ -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
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+2
-2
@@ -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) {
|
||||
|
||||
+28
-9
@@ -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"""
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user