@Override public void visitUnaryExpression(GrUnaryExpression expression) { final GrExpression operand = expression.getOperand(); if (operand == null) return; if (expression.getOperationTokenType() != mLNOT) { operand.accept(this); visitCall(expression); return; } ConditionInstruction cond = new ConditionInstruction(expression); addNodeAndCheckPending(cond); registerCondition(cond); operand.accept(this); visitCall(expression); myConditions.removeFirstOccurrence(cond); List<GotoInstruction> negations = collectAndRemoveAllPendingNegations(expression); InstructionImpl head = myHead; addNodeAndCheckPending(new PositiveGotoInstruction(expression, cond)); handlePossibleReturn(expression); addPendingEdge(expression, myHead); if (negations.isEmpty()) { myHead = head; } else { myHead = reduceAllNegationsIntoInstruction(expression, negations); } }
public void visitAssertStatement(GrAssertStatement assertStatement) { final InstructionImpl assertInstruction = startNode(assertStatement); final GrExpression assertion = assertStatement.getAssertion(); if (assertion != null) { assertion.accept(this); InstructionImpl positiveHead = myHead; List<GotoInstruction> negations = collectAndRemoveAllPendingNegations(assertStatement); if (!negations.isEmpty()) { interruptFlow(); reduceAllNegationsIntoInstruction(assertStatement, negations); } GrExpression errorMessage = assertStatement.getErrorMessage(); if (errorMessage != null) { errorMessage.accept(this); } addNode(new ThrowingInstruction(assertStatement)); final PsiType type = TypesUtil.createTypeByFQClassName( CommonClassNames.JAVA_LANG_ASSERTION_ERROR, assertStatement); ExceptionInfo info = findCatch(type); if (info != null) { info.myThrowers.add(myHead); } else { addPendingEdge(null, myHead); } myHead = positiveHead; } finishNode(assertInstruction); }
private List<GotoInstruction> collectAndRemoveAllPendingNegations(GroovyPsiElement currentScope) { List<GotoInstruction> negations = new ArrayList<GotoInstruction>(); for (Iterator<Pair<InstructionImpl, GroovyPsiElement>> iterator = myPending.iterator(); iterator.hasNext(); ) { Pair<InstructionImpl, GroovyPsiElement> pair = iterator.next(); InstructionImpl instruction = pair.first; GroovyPsiElement scope = pair.second; if (!PsiTreeUtil.isAncestor(scope, currentScope, true) && instruction instanceof GotoInstruction) { negations.add((GotoInstruction) instruction); iterator.remove(); } } return negations; }
@Nullable private InstructionImpl reduceAllNegationsIntoInstruction( GroovyPsiElement currentScope, List<? extends GotoInstruction> negations) { if (negations.size() > 1) { InstructionImpl instruction = addNode(new InstructionImpl(currentScope)); for (GotoInstruction negation : negations) { addEdge(negation, instruction); } return instruction; } else if (negations.size() == 1) { GotoInstruction instruction = negations.get(0); myHead = instruction; return instruction; } return null; }
private <T extends InstructionImpl> T addNode(T instruction) { instruction.setNumber(myInstructionNumber++); myInstructions.add(instruction); if (myHead != null) { addEdge(myHead, instruction); } myHead = instruction; return instruction; }
public Instruction[] buildControlFlow(GroovyPsiElement scope) { myInstructions = new ArrayList<InstructionImpl>(); myProcessingStack = new ArrayDeque<InstructionImpl>(); myCaughtExceptionInfos = new ArrayDeque<ExceptionInfo>(); myConditions = new ArrayDeque<ConditionInstruction>(); myFinallyCount = 0; myPending = new ArrayList<Pair<InstructionImpl, GroovyPsiElement>>(); myInstructionNumber = 0; myScope = scope; startNode(null); if (scope instanceof GrClosableBlock) { buildFlowForClosure((GrClosableBlock) scope); } else { scope.accept(this); } final InstructionImpl end = startNode(null); checkPending(end); // collect return edges return assertValidPsi(myInstructions.toArray(new Instruction[myInstructions.size()])); }
@Override public void visitBinaryExpression(GrBinaryExpression expression) { final GrExpression left = expression.getLeftOperand(); final GrExpression right = expression.getRightOperand(); final IElementType opType = expression.getOperationTokenType(); if (ControlFlowBuilderUtil.isInstanceOfBinary(expression)) { expression.getLeftOperand().accept(this); processInstanceOf(expression); return; } if (opType != mLOR && opType != mLAND && opType != kIN) { left.accept(this); if (right != null) { right.accept(this); } visitCall(expression); return; } ConditionInstruction condition = new ConditionInstruction(expression); addNodeAndCheckPending(condition); registerCondition(condition); left.accept(this); if (right == null) return; final List<GotoInstruction> negations = collectAndRemoveAllPendingNegations(expression); visitCall(expression); if (opType == mLAND) { InstructionImpl head = myHead; if (negations.isEmpty()) { addNode(new NegatingGotoInstruction(expression, condition)); handlePossibleReturn(expression); addPendingEdge(expression, myHead); } else { for (GotoInstruction negation : negations) { myHead = negation; handlePossibleReturn(expression); addPendingEdge(expression, myHead); } } myHead = head; } else /*if (opType == mLOR)*/ { final InstructionImpl instruction = addNodeAndCheckPending( new InstructionImpl(expression)); // collect all pending edges from left argument handlePossibleReturn(expression); addPendingEdge(expression, myHead); myHead = instruction; InstructionImpl head = reduceAllNegationsIntoInstruction(expression, negations); if (head != null) myHead = head; // addNode(new NegatingGotoInstruction(expression, myInstructionNumber++, condition)); } myConditions.removeFirstOccurrence(condition); right.accept(this); }