private static boolean tryStatementsAreEquivalent( @NotNull GrTryCatchStatement statement1, @NotNull GrTryCatchStatement statement2) { final GrOpenBlock tryBlock1 = statement1.getTryBlock(); final GrOpenBlock tryBlock2 = statement2.getTryBlock(); if (!openBlocksAreEquivalent(tryBlock1, tryBlock2)) { return false; } final GrFinallyClause finallyBlock1 = statement1.getFinallyClause(); final GrFinallyClause finallyBlock2 = statement2.getFinallyClause(); if (finallyBlock1 != null) { if (finallyBlock2 == null || !openBlocksAreEquivalent(finallyBlock1.getBody(), finallyBlock2.getBody())) { return false; } } else if (finallyBlock2 != null) { return false; } final GrCatchClause[] catchBlocks1 = statement1.getCatchClauses(); final GrCatchClause[] catchBlocks2 = statement2.getCatchClauses(); if (catchBlocks1.length != catchBlocks2.length) { return false; } for (int i = 0; i < catchBlocks2.length; i++) { if (!catchClausesAreEquivalent(catchBlocks1[i], catchBlocks2[i])) { return false; } } return true; }
public void visitTryStatement(GrTryCatchStatement tryCatchStatement) { final GrOpenBlock tryBlock = tryCatchStatement.getTryBlock(); final GrCatchClause[] catchClauses = tryCatchStatement.getCatchClauses(); final GrFinallyClause finallyClause = tryCatchStatement.getFinallyClause(); for (int i = catchClauses.length - 1; i >= 0; i--) { myCaughtExceptionInfos.push(new ExceptionInfo(catchClauses[i])); } if (finallyClause != null) myFinallyCount++; List<Pair<InstructionImpl, GroovyPsiElement>> oldPending = null; if (finallyClause != null) { oldPending = myPending; myPending = new ArrayList<Pair<InstructionImpl, GroovyPsiElement>>(); } InstructionImpl tryBegin = startNode(tryBlock); tryBlock.accept(this); InstructionImpl tryEnd = myHead; finishNode(tryBegin); Set<Pair<InstructionImpl, GroovyPsiElement>> pendingAfterTry = new LinkedHashSet<Pair<InstructionImpl, GroovyPsiElement>>(myPending); @SuppressWarnings("unchecked") List<InstructionImpl>[] throwers = new List[catchClauses.length]; for (int i = 0; i < catchClauses.length; i++) { throwers[i] = myCaughtExceptionInfos.pop().myThrowers; } InstructionImpl[] catches = new InstructionImpl[catchClauses.length]; for (int i = 0; i < catchClauses.length; i++) { interruptFlow(); final InstructionImpl catchBeg = startNode(catchClauses[i]); for (InstructionImpl thrower : throwers[i]) { addEdge(thrower, catchBeg); } final GrParameter parameter = catchClauses[i].getParameter(); if (parameter != null && myPolicy.isVariableInitialized(parameter)) { addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, WRITE)); } catchClauses[i].accept(this); catches[i] = myHead; finishNode(catchBeg); } pendingAfterTry.addAll(myPending); myPending = new ArrayList<Pair<InstructionImpl, GroovyPsiElement>>(pendingAfterTry); if (finallyClause != null) { myFinallyCount--; interruptFlow(); final InstructionImpl finallyInstruction = startNode(finallyClause, false); Set<AfterCallInstruction> postCalls = new LinkedHashSet<AfterCallInstruction>(); final List<Pair<InstructionImpl, GroovyPsiElement>> copy = myPending; myPending = new ArrayList<Pair<InstructionImpl, GroovyPsiElement>>(); for (Pair<InstructionImpl, GroovyPsiElement> pair : copy) { postCalls.add(addCallNode(finallyInstruction, pair.getSecond(), pair.getFirst())); } if (tryEnd != null) { postCalls.add(addCallNode(finallyInstruction, tryCatchStatement, tryEnd)); } for (InstructionImpl catchEnd : catches) { if (catchEnd != null) { postCalls.add(addCallNode(finallyInstruction, tryCatchStatement, catchEnd)); } } // save added postcalls into separate list because we don't want returnInstruction grabbed // their pending edges List<Pair<InstructionImpl, GroovyPsiElement>> pendingPostCalls = myPending; myPending = new ArrayList<Pair<InstructionImpl, GroovyPsiElement>>(); myHead = finallyInstruction; finallyClause.accept(this); final ReturnInstruction returnInstruction = new ReturnInstruction(finallyClause); for (AfterCallInstruction postCall : postCalls) { postCall.setReturnInstruction(returnInstruction); addEdge(returnInstruction, postCall); } addNodeAndCheckPending(returnInstruction); interruptFlow(); finishNode(finallyInstruction); if (oldPending == null) { error(); } oldPending.addAll(pendingPostCalls); myPending = oldPending; } else { if (tryEnd != null) { addPendingEdge(tryCatchStatement, tryEnd); } for (InstructionImpl catchEnd : catches) { addPendingEdge(tryBlock, catchEnd); } } }