void (@NotNull PsiTryStatement statement) { startElement(statement); PsiCodeBlock[] catchBlocks = statement.getCatchBlocks(); PsiParameter[] catchBlockParameters = statement.getCatchBlockParameters(); int catchNum = Math.min(catchBlocks.length, catchBlockParameters.length); myUnhandledExceptionCatchBlocks.push(null); for (int i = catchNum - 1; i >= 0; i--) { ProgressManager.checkCanceled(); myCatchParameters.push(catchBlockParameters[i]); myCatchBlocks.push(catchBlocks[i]); final PsiType type = catchBlockParameters[i].getType(); // todo cast param if (type instanceof PsiClassType && ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)type)) { myUnhandledExceptionCatchBlocks.push(catchBlocks[i]); } else if (type instanceof PsiDisjunctionType) { final PsiType lub = ((PsiDisjunctionType)type).getLeastUpperBound(); if (lub instanceof PsiClassType && ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)lub)) { myUnhandledExceptionCatchBlocks.push(catchBlocks[i]); } else if (lub instanceof PsiIntersectionType) { for (PsiType conjunct : ((PsiIntersectionType)lub).getConjuncts()) { if (conjunct instanceof PsiClassType && ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)conjunct)) { myUnhandledExceptionCatchBlocks.push(catchBlocks[i]); break; } } } } } PsiCodeBlock finallyBlock = statement.getFinallyBlock(); FinallyBlockSubroutine finallyBlockSubroutine = null; if (finallyBlock != null) { finallyBlockSubroutine = new FinallyBlockSubroutine(finallyBlock); myFinallyBlocks.push(finallyBlockSubroutine); } PsiResourceList resourceList = statement.getResourceList(); if (resourceList != null) { generateCheckedExceptionJumps(resourceList); resourceList.accept(this); } PsiCodeBlock tryBlock = statement.getTryBlock(); if (tryBlock != null) { // javac works as if all checked exceptions can occur at the top of the block generateCheckedExceptionJumps(tryBlock); tryBlock.accept(this); } //noinspection StatementWithEmptyBody while (myUnhandledExceptionCatchBlocks.pop() != null) ; myCurrentFlow.addInstruction(new GoToInstruction(finallyBlock == null ? 0 : -6)); if (finallyBlock == null) { addElementOffsetLater(statement, false); } else { addElementOffsetLater(finallyBlock, true); } for (int i = 0; i < catchNum; i++) { myCatchParameters.pop(); myCatchBlocks.pop(); } for (int i = catchNum - 1; i >= 0; i--) { ProgressManager.checkCanceled(); if (myPolicy.isParameterAccepted(catchBlockParameters[i])) { generateWriteInstruction(catchBlockParameters[i]); } PsiCodeBlock catchBlock = catchBlocks[i]; if (catchBlock != null) { catchBlock.accept(this); } else { LOG.error("Catch body is null (" + i + ") " + statement.getText()); } myCurrentFlow.addInstruction(new GoToInstruction(finallyBlock == null ? 0 : -6)); if (finallyBlock == null) { addElementOffsetLater(statement, false); } else { addElementOffsetLater(finallyBlock, true); } } if (finallyBlock != null) { myFinallyBlocks.pop(); } if (finallyBlock != null) { // normal completion, call finally block and proceed CallInstruction normalCompletion = new CallInstruction(0, 0); finallyBlockSubroutine.addCall(normalCompletion); myCurrentFlow.addInstruction(normalCompletion); addElementOffsetLater(finallyBlock, true); myCurrentFlow.addInstruction(new GoToInstruction(0)); addElementOffsetLater(statement, false); // return completion, call finally block and return CallInstruction returnCompletion = new CallInstruction(0, 0); finallyBlockSubroutine.addCall(returnCompletion); myCurrentFlow.addInstruction(returnCompletion); addElementOffsetLater(finallyBlock, true); addReturnInstruction(statement); // throw exception completion, call finally block and rethrow CallInstruction throwExceptionCompletion = new CallInstruction(0, 0); finallyBlockSubroutine.addCall(throwExceptionCompletion); myCurrentFlow.addInstruction(throwExceptionCompletion); addElementOffsetLater(finallyBlock, true); final GoToInstruction gotoUncheckedRethrow = new GoToInstruction(0); myCurrentFlow.addInstruction(gotoUncheckedRethrow); addElementOffsetLater(finallyBlock, false); finallyBlock.accept(this); final int procStart = myCurrentFlow.getStartOffset(finallyBlock); final int procEnd = myCurrentFlow.getEndOffset(finallyBlock); for (CallInstruction callInstruction : finallyBlockSubroutine.getCalls()) { callInstruction.procBegin = procStart; callInstruction.procEnd = procEnd; } // generate return instructions // first three return instructions are for normal completion, return statement call completion and unchecked exception throwing completion resp. // normal completion myCurrentFlow.addInstruction(new ReturnInstruction(0, normalCompletion)); // return statement call completion myCurrentFlow.addInstruction(new ReturnInstruction(procStart - 3, returnCompletion)); // unchecked exception throwing completion myCurrentFlow.addInstruction(new ReturnInstruction(procStart - 1, throwExceptionCompletion)); // checked exception throwing completion; need to dispatch to the correct catch clause final List<PsiElement> unhandledExceptionCatchBlocks = finallyBlockToUnhandledExceptions.remove(finallyBlock); for (int i = 0; unhandledExceptionCatchBlocks != null && i < unhandledExceptionCatchBlocks.size(); i++) { ProgressManager.checkCanceled(); PsiElement catchBlock = unhandledExceptionCatchBlocks.get(i); final ReturnInstruction returnInstruction = new ReturnInstruction(0, throwExceptionCompletion); returnInstruction.setRethrowFromFinally(); myCurrentFlow.addInstruction(returnInstruction); if (catchBlock == null) { // dispatch to rethrowing exception code returnInstruction.offset = procStart - 1; } else { // dispatch to catch clause returnInstruction.offset--; // -1 for catch block init parameter instruction addElementOffsetLater(catchBlock, true); } } // here generated rethrowing code for unchecked exceptions gotoUncheckedRethrow.offset = myCurrentFlow.getSize(); generateUncheckedExceptionJumps(statement, false); // just in case myCurrentFlow.addInstruction(new ThrowToInstruction(0)); addElementOffsetLater(myCodeFragment, false); } finishElement(statement); }