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);
}
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;
}
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;
}
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);
}
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);
}
}
}
Aggregations