Search in sources :

Example 16 with Instruction

use of com.intellij.codeInsight.controlflow.Instruction in project intellij-community by JetBrains.

the class DFAEngine method join.

private E join(final Instruction instruction, final List<E> info) {
    final Iterable<? extends Instruction> prev = myDfa.isForward() ? instruction.allPred() : instruction.allSucc();
    final ArrayList<E> prevInfos = new ArrayList<>();
    for (Instruction i : prev) {
        prevInfos.add(info.get(i.num()));
    }
    return mySemilattice.join(prevInfos);
}
Also used : Instruction(com.intellij.codeInsight.controlflow.Instruction)

Example 17 with Instruction

use of com.intellij.codeInsight.controlflow.Instruction in project intellij-community by JetBrains.

the class PyReferenceExpressionImpl method getTypeByControlFlow.

private static PyType getTypeByControlFlow(@NotNull String name, @NotNull TypeEvalContext context, @NotNull PyExpression anchor, @NotNull ScopeOwner scopeOwner) {
    final PyAugAssignmentStatement augAssignment = PsiTreeUtil.getParentOfType(anchor, PyAugAssignmentStatement.class);
    final PyElement element = augAssignment != null ? augAssignment : anchor;
    try {
        final List<Instruction> defs = PyDefUseUtil.getLatestDefs(scopeOwner, name, element, true, false);
        if (!defs.isEmpty()) {
            final ReadWriteInstruction firstInstruction = PyUtil.as(defs.get(0), ReadWriteInstruction.class);
            PyType type = firstInstruction != null ? firstInstruction.getType(context, anchor) : null;
            for (int i = 1; i < defs.size(); i++) {
                final ReadWriteInstruction instruction = PyUtil.as(defs.get(i), ReadWriteInstruction.class);
                type = PyUnionType.union(type, instruction != null ? instruction.getType(context, anchor) : null);
            }
            return type;
        }
    } catch (PyDefUseUtil.InstructionNotFoundException ignored) {
    }
    return null;
}
Also used : PyDefUseUtil(com.jetbrains.python.refactoring.PyDefUseUtil) ReadWriteInstruction(com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction) ReadWriteInstruction(com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction) Instruction(com.intellij.codeInsight.controlflow.Instruction)

Example 18 with Instruction

use of com.intellij.codeInsight.controlflow.Instruction in project intellij-community by JetBrains.

the class ScopeImpl method getDeclaredVariable.

public ScopeVariable getDeclaredVariable(@NotNull final PsiElement anchorElement, @NotNull final String name) throws DFALimitExceededException {
    computeScopeVariables();
    for (int i = 0; i < myFlow.length; i++) {
        Instruction instruction = myFlow[i];
        final PsiElement element = instruction.getElement();
        if (element == anchorElement) {
            return myCachedScopeVariables.get(i).get(name);
        }
    }
    return null;
}
Also used : Instruction(com.intellij.codeInsight.controlflow.Instruction) PsiElement(com.intellij.psi.PsiElement)

Example 19 with Instruction

use of com.intellij.codeInsight.controlflow.Instruction in project intellij-community by JetBrains.

the class PyCodeFragmentUtil method createCodeFragment.

@NotNull
public static PyCodeFragment createCodeFragment(@NotNull final ScopeOwner owner, @NotNull final PsiElement startInScope, @NotNull final PsiElement endInScope) throws CannotCreateCodeFragmentException {
    final int start = startInScope.getTextOffset();
    final int end = endInScope.getTextOffset() + endInScope.getTextLength();
    final ControlFlow flow = ControlFlowCache.getControlFlow(owner);
    if (flow == null) {
        throw new CannotCreateCodeFragmentException(PyBundle.message("refactoring.extract.method.error.undetermined.execution.flow"));
    }
    final List<Instruction> graph = Arrays.asList(flow.getInstructions());
    final List<Instruction> subGraph = getFragmentSubGraph(graph, start, end);
    final AnalysisResult subGraphAnalysis = analyseSubGraph(subGraph, start, end);
    if ((subGraphAnalysis.regularExits > 0 && subGraphAnalysis.returns > 0) || subGraphAnalysis.targetInstructions > 1 || subGraphAnalysis.outerLoopBreaks > 0) {
        throw new CannotCreateCodeFragmentException(PyBundle.message("refactoring.extract.method.error.interrupted.execution.flow"));
    }
    if (subGraphAnalysis.starImports > 0) {
        throw new CannotCreateCodeFragmentException(PyBundle.message("refactoring.extract.method.error.star.import"));
    }
    final Set<String> globalWrites = getGlobalWrites(subGraph, owner);
    final Set<String> nonlocalWrites = getNonlocalWrites(subGraph, owner);
    final Set<String> inputNames = new HashSet<>();
    for (PsiElement element : filterElementsInScope(getInputElements(subGraph, graph), owner)) {
        final String name = getName(element);
        if (name != null) {
            // Ignore "self" and "cls", they are generated automatically when extracting any method fragment
            if (resolvesToBoundMethodParameter(element)) {
                continue;
            }
            if (globalWrites.contains(name) || nonlocalWrites.contains(name)) {
                continue;
            }
            inputNames.add(name);
        }
    }
    final Set<String> outputNames = new HashSet<>();
    for (PsiElement element : getOutputElements(subGraph, graph)) {
        final String name = getName(element);
        if (name != null) {
            if (globalWrites.contains(name) || nonlocalWrites.contains(name)) {
                continue;
            }
            outputNames.add(name);
        }
    }
    final boolean yieldsFound = subGraphAnalysis.yieldExpressions > 0;
    if (yieldsFound && LanguageLevel.forElement(owner).isOlderThan(LanguageLevel.PYTHON33)) {
        throw new CannotCreateCodeFragmentException(PyBundle.message("refactoring.extract.method.error.yield"));
    }
    final boolean isAsync = owner instanceof PyFunction && ((PyFunction) owner).isAsync();
    return new PyCodeFragment(inputNames, outputNames, globalWrites, nonlocalWrites, subGraphAnalysis.returns > 0, yieldsFound, isAsync);
}
Also used : CannotCreateCodeFragmentException(com.intellij.codeInsight.codeFragment.CannotCreateCodeFragmentException) ReadWriteInstruction(com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction) Instruction(com.intellij.codeInsight.controlflow.Instruction) ControlFlow(com.intellij.codeInsight.controlflow.ControlFlow) NotNull(org.jetbrains.annotations.NotNull)

Example 20 with Instruction

use of com.intellij.codeInsight.controlflow.Instruction in project intellij-community by JetBrains.

the class PyControlFlowBuilder method visitPyTryExceptStatement.

@Override
public void visitPyTryExceptStatement(final PyTryExceptStatement node) {
    myBuilder.startNode(node);
    // Process try part
    final PyTryPart tryPart = node.getTryPart();
    myBuilder.startNode(tryPart);
    tryPart.accept(this);
    // Goto else part after execution, or exit
    final PyElsePart elsePart = node.getElsePart();
    if (elsePart != null) {
        myBuilder.startNode(elsePart);
        elsePart.accept(this);
    }
    myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
    // Process except parts
    final List<Instruction> exceptInstructions = emptyMutableList();
    List<Pair<PsiElement, Instruction>> pendingBackup = emptyMutableList();
    for (PyExceptPart exceptPart : node.getExceptParts()) {
        pendingBackup.addAll(myBuilder.pending);
        myBuilder.pending = emptyMutableList();
        myBuilder.flowAbrupted();
        final Instruction exceptInstruction = myBuilder.startNode(exceptPart);
        exceptPart.accept(this);
        myBuilder.addPendingEdge(node, myBuilder.prevInstruction);
        exceptInstructions.add(exceptInstruction);
    }
    for (Pair<PsiElement, Instruction> pair : pendingBackup) {
        myBuilder.addPendingEdge(pair.first, pair.second);
    }
    final List<Instruction> normalExits = new ArrayList<>();
    final PyFinallyPart finallyPart = node.getFinallyPart();
    final Instruction finallyFailInstruction;
    // Store pending normal exit instructions from try-except-else parts
    if (finallyPart != null) {
        myBuilder.processPending((pendingScope, instruction) -> {
            final PsiElement pendingElement = instruction.getElement();
            if (pendingElement != null) {
                final boolean isPending = PsiTreeUtil.isAncestor(node, pendingElement, false) && !PsiTreeUtil.isAncestor(finallyPart, pendingElement, false);
                if (isPending && pendingScope != null) {
                    normalExits.add(instruction);
                } else {
                    myBuilder.addPendingEdge(pendingScope, instruction);
                }
            }
        });
    }
    // Finally-fail part handling
    if (finallyPart != null) {
        myBuilder.flowAbrupted();
        finallyFailInstruction = myBuilder.startNode(finallyPart);
        finallyPart.accept(this);
        myBuilder.addPendingEdge(null, myBuilder.prevInstruction);
        myBuilder.flowAbrupted();
    } else {
        finallyFailInstruction = null;
    }
    // Create exception edges
    for (Instruction instruction : myBuilder.instructions) {
        final PsiElement e = instruction.getElement();
        if (e == null || !canRaiseExceptions(instruction)) {
            continue;
        }
        // All instructions inside the try part have edges to except and finally parts
        if (PsiTreeUtil.getParentOfType(e, PyTryPart.class, false) == tryPart) {
            for (Instruction inst : exceptInstructions) {
                myBuilder.addEdge(instruction, inst);
            }
            if (finallyPart != null) {
                myBuilder.addEdge(instruction, finallyFailInstruction);
            }
        }
        if (finallyPart != null) {
            // All instructions inside except parts have edges to the finally part
            for (PyExceptPart exceptPart : node.getExceptParts()) {
                if (PsiTreeUtil.isAncestor(exceptPart, e, false)) {
                    myBuilder.addEdge(instruction, finallyFailInstruction);
                }
            }
            // All instructions inside the else part have edges to the finally part
            if (PsiTreeUtil.isAncestor(elsePart, e, false)) {
                myBuilder.addEdge(instruction, finallyFailInstruction);
            }
        }
    }
    if (finallyPart != null) {
        myBuilder.processPending((pendingScope, instruction) -> {
            final PsiElement e = instruction.getElement();
            if (e != null) {
                // Change the scope of pending edges from finally-fail part to point to the last instruction
                if (PsiTreeUtil.isAncestor(finallyPart, e, false)) {
                    myBuilder.addPendingEdge(null, instruction);
                } else // Connect pending fail edges to the finally-fail part
                if (pendingScope == null && PsiTreeUtil.isAncestor(node, e, false)) {
                    myBuilder.addEdge(instruction, finallyFailInstruction);
                } else {
                    myBuilder.addPendingEdge(pendingScope, instruction);
                }
            }
        });
        // Duplicate CFG for finally (-fail and -success) only if there are some successfull exits from the
        // try part. Otherwise a single CFG for finally provides the correct control flow
        final Instruction finallyInstruction;
        if (!normalExits.isEmpty()) {
            // Finally-success part handling
            pendingBackup = emptyMutableList();
            pendingBackup.addAll(myBuilder.pending);
            myBuilder.pending = emptyMutableList();
            myBuilder.flowAbrupted();
            Instruction finallySuccessInstruction = myBuilder.startNode(finallyPart);
            finallyPart.accept(this);
            for (Pair<PsiElement, Instruction> pair : pendingBackup) {
                myBuilder.addPendingEdge(pair.first, pair.second);
            }
            finallyInstruction = finallySuccessInstruction;
        } else {
            finallyInstruction = finallyFailInstruction;
        }
        // Connect normal exits from try and else parts to the finally part
        for (Instruction instr : normalExits) {
            myBuilder.addEdge(instr, finallyInstruction);
        }
    }
}
Also used : ArrayList(java.util.ArrayList) Instruction(com.intellij.codeInsight.controlflow.Instruction) PsiElement(com.intellij.psi.PsiElement) Pair(com.intellij.openapi.util.Pair)

Aggregations

Instruction (com.intellij.codeInsight.controlflow.Instruction)33 ReadWriteInstruction (com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction)15 NotNull (org.jetbrains.annotations.NotNull)12 PsiElement (com.intellij.psi.PsiElement)10 ControlFlow (com.intellij.codeInsight.controlflow.ControlFlow)7 ArrayList (java.util.ArrayList)5 ScopeOwner (com.jetbrains.python.codeInsight.controlflow.ScopeOwner)4 Pair (com.intellij.openapi.util.Pair)3 Scope (com.jetbrains.python.codeInsight.dataflow.scope.Scope)3 Project (com.intellij.openapi.project.Project)2 TextRange (com.intellij.openapi.util.TextRange)2 PyDefUseUtil (com.jetbrains.python.refactoring.PyDefUseUtil)2 TargetElementUtil (com.intellij.codeInsight.TargetElementUtil)1 CannotCreateCodeFragmentException (com.intellij.codeInsight.codeFragment.CannotCreateCodeFragmentException)1 HighlightManager (com.intellij.codeInsight.highlighting.HighlightManager)1 Language (com.intellij.lang.Language)1 InlineActionHandler (com.intellij.lang.refactoring.InlineActionHandler)1 ApplicationManager (com.intellij.openapi.application.ApplicationManager)1 CommandProcessor (com.intellij.openapi.command.CommandProcessor)1 Logger (com.intellij.openapi.diagnostic.Logger)1