/* * Copyright 2005, Sixth and Red River Software * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.sixrr.stockmetrics.utils; import com.intellij.psi.*; public class ControlFlowUtils { private ControlFlowUtils() { super(); } public static boolean statementMayCompleteNormally(PsiStatement statement) { if (statement == null) { return true; } if (statement instanceof PsiBreakStatement || statement instanceof PsiContinueStatement || statement instanceof PsiReturnStatement || statement instanceof PsiThrowStatement) { return false; } else if (statement instanceof PsiExpressionListStatement || statement instanceof PsiExpressionStatement || statement instanceof PsiEmptyStatement || statement instanceof PsiAssertStatement || statement instanceof PsiDeclarationStatement) { return true; } else if (statement instanceof PsiForStatement) { return forStatementMayReturnNormally((PsiForStatement) statement); } else if (statement instanceof PsiForeachStatement) { return true; } else if (statement instanceof PsiWhileStatement) { return whileStatementMayReturnNormally((PsiWhileStatement) statement); } else if (statement instanceof PsiDoWhileStatement) { return doWhileStatementMayReturnNormally((PsiDoWhileStatement) statement); } else if (statement instanceof PsiSynchronizedStatement) { final PsiCodeBlock body = ((PsiSynchronizedStatement) statement).getBody(); return codeBlockMayCompleteNormally(body); } else if (statement instanceof PsiBlockStatement) { final PsiCodeBlock codeBlock = ((PsiBlockStatement) statement).getCodeBlock(); return codeBlockMayCompleteNormally(codeBlock); } else if (statement instanceof PsiLabeledStatement) { return labeledStatementMayCompleteNormally((PsiLabeledStatement) statement); } else if (statement instanceof PsiIfStatement) { return ifStatementMayReturnNormally((PsiIfStatement) statement); } else if (statement instanceof PsiTryStatement) { return tryStatementMayReturnNormally((PsiTryStatement) statement); } else if (statement instanceof PsiSwitchStatement) { return switchStatementMayReturnNormally((PsiSwitchStatement) statement); } else // unknown statement type { return true; } } private static boolean doWhileStatementMayReturnNormally(PsiDoWhileStatement loopStatement) { final PsiExpression test = loopStatement.getCondition(); final PsiStatement body = loopStatement.getBody(); return statementMayCompleteNormally(body) && !BoolUtils.isTrue(test) || statementIsBreakTarget(loopStatement); } private static boolean whileStatementMayReturnNormally(PsiWhileStatement loopStatement) { final PsiExpression test = loopStatement.getCondition(); return !BoolUtils.isTrue(test) || statementIsBreakTarget(loopStatement); } private static boolean forStatementMayReturnNormally(PsiForStatement loopStatement) { final PsiExpression test = loopStatement.getCondition(); if (statementIsBreakTarget(loopStatement)) { return true; } if (test == null) { return false; } return !BoolUtils.isTrue(test); } private static boolean switchStatementMayReturnNormally(PsiSwitchStatement switchStatement) { if (statementIsBreakTarget(switchStatement)) { return true; } final PsiCodeBlock body = switchStatement.getBody(); if (body == null) { return true; } final PsiStatement[] statements = body.getStatements(); return statementMayCompleteNormally(statements[statements.length - 1]); } private static boolean tryStatementMayReturnNormally(PsiTryStatement tryStatement) { final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); if (finallyBlock != null) { if (!codeBlockMayCompleteNormally(finallyBlock)) { return false; } } final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); if (codeBlockMayCompleteNormally(tryBlock)) { return true; } final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); for (final PsiCodeBlock catchBlock : catchBlocks) { if (codeBlockMayCompleteNormally(catchBlock)) { return true; } } return false; } private static boolean ifStatementMayReturnNormally(PsiIfStatement ifStatement) { final PsiStatement thenBranch = ifStatement.getThenBranch(); if (statementMayCompleteNormally(thenBranch)) { return true; } final PsiStatement elseBranch = ifStatement.getElseBranch(); return elseBranch == null || statementMayCompleteNormally(elseBranch); } private static boolean labeledStatementMayCompleteNormally(PsiLabeledStatement labeledStatement) { final PsiStatement statement = labeledStatement.getStatement(); return statementMayCompleteNormally(statement) || statementIsBreakTarget(statement); } private static boolean codeBlockMayCompleteNormally(PsiCodeBlock block) { if (block == null) { return true; } final PsiStatement[] statements = block.getStatements(); for (final PsiStatement statement : statements) { if (!statementMayCompleteNormally(statement)) { return false; } } return true; } private static boolean statementIsBreakTarget(PsiStatement statement) { final BreakFinder breakFinder = new BreakFinder(statement); statement.accept(breakFinder); return breakFinder.breakFound(); } private static class BreakFinder extends JavaRecursiveElementVisitor { private boolean m_found = false; private final PsiStatement m_target; private BreakFinder(PsiStatement target) { super(); m_target = target; } private boolean breakFound() { return m_found; } @Override public void visitBreakStatement(PsiBreakStatement breakStatement) { super.visitBreakStatement(breakStatement); final PsiStatement exitedStatement = breakStatement.findExitedStatement(); if (m_target.equals(exitedStatement)) { m_found = true; } } } }