| /* |
| * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers |
| * |
| * 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.siyeh.ig.psiutils; |
| |
| import com.intellij.psi.*; |
| import com.intellij.psi.tree.IElementType; |
| import org.jetbrains.annotations.NotNull; |
| |
| public class RecursionUtils { |
| |
| private RecursionUtils() { |
| super(); |
| } |
| |
| public static boolean statementMayReturnBeforeRecursing( |
| PsiStatement statement, PsiMethod method) { |
| if (statement == null) { |
| return true; |
| } |
| if (statement instanceof PsiBreakStatement || |
| statement instanceof PsiContinueStatement || |
| statement instanceof PsiThrowStatement || |
| statement instanceof PsiExpressionListStatement || |
| statement instanceof PsiExpressionStatement || |
| statement instanceof PsiEmptyStatement || |
| statement instanceof PsiAssertStatement || |
| statement instanceof PsiDeclarationStatement) { |
| return false; |
| } |
| else if (statement instanceof PsiReturnStatement) { |
| final PsiReturnStatement returnStatement = |
| (PsiReturnStatement)statement; |
| final PsiExpression returnValue = returnStatement.getReturnValue(); |
| if (returnValue != null) { |
| if (expressionDefinitelyRecurses(returnValue, method)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| else if (statement instanceof PsiForStatement) { |
| return forStatementMayReturnBeforeRecursing( |
| (PsiForStatement)statement, method); |
| } |
| else if (statement instanceof PsiForeachStatement) { |
| return foreachStatementMayReturnBeforeRecursing( |
| (PsiForeachStatement)statement, method); |
| } |
| else if (statement instanceof PsiWhileStatement) { |
| return whileStatementMayReturnBeforeRecursing( |
| (PsiWhileStatement)statement, method); |
| } |
| else if (statement instanceof PsiDoWhileStatement) { |
| return doWhileStatementMayReturnBeforeRecursing( |
| (PsiDoWhileStatement)statement, method); |
| } |
| else if (statement instanceof PsiSynchronizedStatement) { |
| final PsiCodeBlock body = ((PsiSynchronizedStatement)statement) |
| .getBody(); |
| return codeBlockMayReturnBeforeRecursing(body, method, false); |
| } |
| else if (statement instanceof PsiBlockStatement) { |
| final PsiBlockStatement blockStatement = |
| (PsiBlockStatement)statement; |
| final PsiCodeBlock codeBlock = blockStatement.getCodeBlock(); |
| return codeBlockMayReturnBeforeRecursing(codeBlock, method, false); |
| } |
| else if (statement instanceof PsiLabeledStatement) { |
| return labeledStatementMayReturnBeforeRecursing( |
| (PsiLabeledStatement)statement, method); |
| } |
| else if (statement instanceof PsiIfStatement) { |
| return ifStatementMayReturnBeforeRecursing( |
| (PsiIfStatement)statement, method); |
| } |
| else if (statement instanceof PsiTryStatement) { |
| return tryStatementMayReturnBeforeRecursing( |
| (PsiTryStatement)statement, method); |
| } |
| else if (statement instanceof PsiSwitchStatement) { |
| return switchStatementMayReturnBeforeRecursing( |
| (PsiSwitchStatement)statement, method); |
| } |
| else { |
| // unknown statement type |
| return true; |
| } |
| } |
| |
| private static boolean doWhileStatementMayReturnBeforeRecursing( |
| PsiDoWhileStatement loopStatement, PsiMethod method) { |
| final PsiStatement body = loopStatement.getBody(); |
| return statementMayReturnBeforeRecursing(body, method); |
| } |
| |
| private static boolean whileStatementMayReturnBeforeRecursing( |
| PsiWhileStatement loopStatement, PsiMethod method) { |
| final PsiExpression test = loopStatement.getCondition(); |
| if (expressionDefinitelyRecurses(test, method)) { |
| return false; |
| } |
| final PsiStatement body = loopStatement.getBody(); |
| return statementMayReturnBeforeRecursing(body, method); |
| } |
| |
| private static boolean forStatementMayReturnBeforeRecursing( |
| PsiForStatement loopStatement, PsiMethod method) { |
| final PsiStatement initialization = loopStatement.getInitialization(); |
| |
| if (statementMayReturnBeforeRecursing(initialization, method)) { |
| return true; |
| } |
| final PsiExpression test = loopStatement.getCondition(); |
| if (expressionDefinitelyRecurses(test, method)) { |
| return false; |
| } |
| final PsiStatement body = loopStatement.getBody(); |
| return statementMayReturnBeforeRecursing(body, method); |
| } |
| |
| private static boolean foreachStatementMayReturnBeforeRecursing( |
| PsiForeachStatement loopStatement, PsiMethod method) { |
| final PsiExpression test = loopStatement.getIteratedValue(); |
| if (expressionDefinitelyRecurses(test, method)) { |
| return false; |
| } |
| final PsiStatement body = loopStatement.getBody(); |
| return statementMayReturnBeforeRecursing(body, method); |
| } |
| |
| private static boolean switchStatementMayReturnBeforeRecursing( |
| PsiSwitchStatement switchStatement, PsiMethod method) { |
| |
| final PsiCodeBlock body = switchStatement.getBody(); |
| if (body == null) { |
| return true; |
| } |
| final PsiStatement[] statements = body.getStatements(); |
| for (final PsiStatement statement : statements) { |
| if (statementMayReturnBeforeRecursing(statement, method)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static boolean tryStatementMayReturnBeforeRecursing( |
| PsiTryStatement tryStatement, PsiMethod method) { |
| final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); |
| if (finallyBlock != null) { |
| if (codeBlockMayReturnBeforeRecursing(finallyBlock, method, |
| false)) { |
| return true; |
| } |
| if (codeBlockDefinitelyRecurses(finallyBlock, method)) { |
| return false; |
| } |
| } |
| final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); |
| if (codeBlockMayReturnBeforeRecursing(tryBlock, method, false)) { |
| return true; |
| } |
| final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); |
| for (final PsiCodeBlock catchBlock : catchBlocks) { |
| if (codeBlockMayReturnBeforeRecursing(catchBlock, method, false)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static boolean ifStatementMayReturnBeforeRecursing( |
| PsiIfStatement ifStatement, PsiMethod method) { |
| final PsiExpression test = ifStatement.getCondition(); |
| if (expressionDefinitelyRecurses(test, method)) { |
| return false; |
| } |
| final PsiStatement thenBranch = ifStatement.getThenBranch(); |
| if (statementMayReturnBeforeRecursing(thenBranch, method)) { |
| return true; |
| } |
| final PsiStatement elseBranch = ifStatement.getElseBranch(); |
| return elseBranch != null && |
| statementMayReturnBeforeRecursing(elseBranch, method); |
| } |
| |
| private static boolean labeledStatementMayReturnBeforeRecursing( |
| PsiLabeledStatement labeledStatement, PsiMethod method) { |
| final PsiStatement statement = labeledStatement.getStatement(); |
| return statementMayReturnBeforeRecursing(statement, method); |
| } |
| |
| private static boolean codeBlockMayReturnBeforeRecursing( |
| PsiCodeBlock block, PsiMethod method, boolean endsInImplicitReturn) { |
| if (block == null) { |
| return true; |
| } |
| final PsiStatement[] statements = block.getStatements(); |
| for (final PsiStatement statement : statements) { |
| if (statementMayReturnBeforeRecursing(statement, method)) { |
| return true; |
| } |
| if (statementDefinitelyRecurses(statement, method)) { |
| return false; |
| } |
| } |
| return endsInImplicitReturn; |
| } |
| |
| public static boolean methodMayRecurse(@NotNull PsiMethod method) { |
| final RecursionVisitor recursionVisitor = new RecursionVisitor(method); |
| method.accept(recursionVisitor); |
| return recursionVisitor.isRecursive(); |
| } |
| |
| private static boolean expressionDefinitelyRecurses(PsiExpression exp, |
| PsiMethod method) { |
| if (exp == null) { |
| return false; |
| } |
| if (exp instanceof PsiMethodCallExpression) { |
| return methodCallExpressionDefinitelyRecurses( |
| (PsiMethodCallExpression)exp, method); |
| } |
| if (exp instanceof PsiNewExpression) { |
| return newExpressionDefinitelyRecurses( |
| (PsiNewExpression)exp, method); |
| } |
| if (exp instanceof PsiAssignmentExpression) { |
| return assignmentExpressionDefinitelyRecurses( |
| (PsiAssignmentExpression)exp, method); |
| } |
| if (exp instanceof PsiArrayInitializerExpression) { |
| return arrayInitializerExpressionDefinitelyRecurses( |
| (PsiArrayInitializerExpression)exp, method); |
| } |
| if (exp instanceof PsiTypeCastExpression) { |
| return typeCastExpressionDefinitelyRecurses( |
| (PsiTypeCastExpression)exp, method); |
| } |
| if (exp instanceof PsiArrayAccessExpression) { |
| return arrayAccessExpressionDefinitelyRecurses( |
| (PsiArrayAccessExpression)exp, method); |
| } |
| if (exp instanceof PsiPrefixExpression) { |
| return prefixExpressionDefinitelyRecurses( |
| (PsiPrefixExpression)exp, method); |
| } |
| if (exp instanceof PsiPostfixExpression) { |
| return postfixExpressionDefinitelyRecurses( |
| (PsiPostfixExpression)exp, method); |
| } |
| if (exp instanceof PsiBinaryExpression) { |
| return binaryExpressionDefinitelyRecurses( |
| (PsiBinaryExpression)exp, method); |
| } |
| if (exp instanceof PsiInstanceOfExpression) { |
| return instanceOfExpressionDefinitelyRecurses( |
| (PsiInstanceOfExpression)exp, method); |
| } |
| if (exp instanceof PsiConditionalExpression) { |
| return conditionalExpressionDefinitelyRecurses( |
| (PsiConditionalExpression)exp, method); |
| } |
| if (exp instanceof PsiParenthesizedExpression) { |
| return parenthesizedExpressionDefinitelyRecurses( |
| (PsiParenthesizedExpression)exp, method); |
| } |
| if (exp instanceof PsiReferenceExpression) { |
| return referenceExpressionDefinitelyRecurses( |
| (PsiReferenceExpression)exp, method); |
| } |
| if (exp instanceof PsiLiteralExpression || |
| exp instanceof PsiClassObjectAccessExpression || |
| exp instanceof PsiThisExpression || |
| exp instanceof PsiSuperExpression) { |
| return false; |
| } |
| return false; |
| } |
| |
| private static boolean conditionalExpressionDefinitelyRecurses( |
| PsiConditionalExpression expression, PsiMethod method) { |
| final PsiExpression condExpression = expression.getCondition(); |
| if (expressionDefinitelyRecurses(condExpression, method)) { |
| return true; |
| } |
| final PsiExpression thenExpression = expression.getThenExpression(); |
| final PsiExpression elseExpression = expression.getElseExpression(); |
| return expressionDefinitelyRecurses(thenExpression, method) |
| && expressionDefinitelyRecurses(elseExpression, method); |
| } |
| |
| private static boolean binaryExpressionDefinitelyRecurses( |
| PsiBinaryExpression expression, PsiMethod method) { |
| final PsiExpression lhs = expression.getLOperand(); |
| if (expressionDefinitelyRecurses(lhs, method)) { |
| return true; |
| } |
| final IElementType tokenType = expression.getOperationTokenType(); |
| if (tokenType.equals(JavaTokenType.ANDAND) || |
| tokenType.equals(JavaTokenType.OROR)) { |
| return false; |
| } |
| final PsiExpression rhs = expression.getROperand(); |
| return expressionDefinitelyRecurses(rhs, method); |
| } |
| |
| private static boolean arrayAccessExpressionDefinitelyRecurses( |
| PsiArrayAccessExpression expression, PsiMethod method) { |
| final PsiExpression arrayExp = expression.getArrayExpression(); |
| final PsiExpression indexExp = expression.getIndexExpression(); |
| return expressionDefinitelyRecurses(arrayExp, method) || |
| expressionDefinitelyRecurses(indexExp, method); |
| } |
| |
| private static boolean arrayInitializerExpressionDefinitelyRecurses( |
| PsiArrayInitializerExpression expression, PsiMethod method) { |
| final PsiExpression[] initializers = expression.getInitializers(); |
| for (final PsiExpression initializer : initializers) { |
| if (expressionDefinitelyRecurses(initializer, method)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static boolean prefixExpressionDefinitelyRecurses( |
| PsiPrefixExpression expression, PsiMethod method) { |
| final PsiExpression operand = expression.getOperand(); |
| return expressionDefinitelyRecurses(operand, method); |
| } |
| |
| private static boolean postfixExpressionDefinitelyRecurses( |
| PsiPostfixExpression expression, PsiMethod method) { |
| final PsiExpression operand = expression.getOperand(); |
| return expressionDefinitelyRecurses(operand, method); |
| } |
| |
| private static boolean instanceOfExpressionDefinitelyRecurses( |
| PsiInstanceOfExpression expression, PsiMethod method) { |
| final PsiExpression operand = expression.getOperand(); |
| return expressionDefinitelyRecurses(operand, method); |
| } |
| |
| private static boolean parenthesizedExpressionDefinitelyRecurses( |
| PsiParenthesizedExpression expression, PsiMethod method) { |
| final PsiExpression innerExpression = expression.getExpression(); |
| return expressionDefinitelyRecurses(innerExpression, method); |
| } |
| |
| private static boolean referenceExpressionDefinitelyRecurses( |
| PsiReferenceExpression expression, PsiMethod method) { |
| final PsiExpression qualifierExpression = |
| expression.getQualifierExpression(); |
| return qualifierExpression != null && |
| expressionDefinitelyRecurses(qualifierExpression, method); |
| } |
| |
| private static boolean typeCastExpressionDefinitelyRecurses( |
| PsiTypeCastExpression expression, PsiMethod method) { |
| final PsiExpression operand = expression.getOperand(); |
| return expressionDefinitelyRecurses(operand, method); |
| } |
| |
| private static boolean assignmentExpressionDefinitelyRecurses( |
| PsiAssignmentExpression assignmentExpression, PsiMethod method) { |
| final PsiExpression rhs = assignmentExpression.getRExpression(); |
| final PsiExpression lhs = assignmentExpression.getLExpression(); |
| return expressionDefinitelyRecurses(rhs, method) || |
| expressionDefinitelyRecurses(lhs, method); |
| } |
| |
| private static boolean newExpressionDefinitelyRecurses(PsiNewExpression exp, |
| PsiMethod method) { |
| final PsiExpression[] arrayDimensions = exp.getArrayDimensions(); |
| for (final PsiExpression arrayDimension : arrayDimensions) { |
| if (expressionDefinitelyRecurses(arrayDimension, method)) { |
| return true; |
| } |
| } |
| final PsiArrayInitializerExpression arrayInitializer = exp |
| .getArrayInitializer(); |
| if (expressionDefinitelyRecurses(arrayInitializer, method)) { |
| return true; |
| } |
| final PsiExpression qualifier = exp.getQualifier(); |
| if (expressionDefinitelyRecurses(qualifier, method)) { |
| return true; |
| } |
| final PsiExpressionList argumentList = exp.getArgumentList(); |
| if (argumentList != null) { |
| final PsiExpression[] args = argumentList.getExpressions(); |
| for (final PsiExpression arg : args) { |
| if (expressionDefinitelyRecurses(arg, method)) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| private static boolean methodCallExpressionDefinitelyRecurses( |
| PsiMethodCallExpression exp, PsiMethod method) { |
| final PsiReferenceExpression methodExpression = |
| exp.getMethodExpression(); |
| final PsiMethod referencedMethod = exp.resolveMethod(); |
| if (referencedMethod == null) { |
| return false; |
| } |
| if (referencedMethod.equals(method)) { |
| if (method.hasModifierProperty(PsiModifier.STATIC) || |
| method.hasModifierProperty(PsiModifier.PRIVATE)) { |
| return true; |
| } |
| final PsiExpression qualifier = |
| methodExpression.getQualifierExpression(); |
| if (qualifier == null || qualifier instanceof PsiThisExpression) { |
| return true; |
| } |
| } |
| final PsiExpression qualifier = |
| methodExpression.getQualifierExpression(); |
| if (expressionDefinitelyRecurses(qualifier, method)) { |
| return true; |
| } |
| final PsiExpressionList argumentList = exp.getArgumentList(); |
| final PsiExpression[] args = argumentList.getExpressions(); |
| for (final PsiExpression arg : args) { |
| if (expressionDefinitelyRecurses(arg, method)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static boolean statementDefinitelyRecurses(PsiStatement statement, |
| PsiMethod method) { |
| if (statement == null) { |
| return false; |
| } |
| if (statement instanceof PsiBreakStatement || |
| statement instanceof PsiContinueStatement || |
| statement instanceof PsiThrowStatement || |
| statement instanceof PsiEmptyStatement || |
| statement instanceof PsiAssertStatement) { |
| return false; |
| } |
| else if (statement instanceof PsiExpressionListStatement) { |
| final PsiExpressionListStatement expressionListStatement = |
| (PsiExpressionListStatement)statement; |
| final PsiExpressionList expressionList = |
| expressionListStatement.getExpressionList(); |
| if (expressionList == null) { |
| return false; |
| } |
| final PsiExpression[] expressions = expressionList.getExpressions(); |
| for (final PsiExpression expression : expressions) { |
| if (expressionDefinitelyRecurses(expression, method)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| else if (statement instanceof PsiExpressionStatement) { |
| final PsiExpressionStatement expressionStatement = |
| (PsiExpressionStatement)statement; |
| final PsiExpression expression = |
| expressionStatement.getExpression(); |
| return expressionDefinitelyRecurses(expression, method); |
| } |
| else if (statement instanceof PsiDeclarationStatement) { |
| final PsiDeclarationStatement declaration = |
| (PsiDeclarationStatement)statement; |
| final PsiElement[] declaredElements = |
| declaration.getDeclaredElements(); |
| for (final PsiElement declaredElement : declaredElements) { |
| if (declaredElement instanceof PsiLocalVariable) { |
| final PsiLocalVariable variable = |
| (PsiLocalVariable)declaredElement; |
| final PsiExpression initializer = variable.getInitializer(); |
| if (expressionDefinitelyRecurses(initializer, method)) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| else if (statement instanceof PsiReturnStatement) { |
| final PsiReturnStatement returnStatement = |
| (PsiReturnStatement)statement; |
| final PsiExpression returnValue = returnStatement.getReturnValue(); |
| if (returnValue != null) { |
| if (expressionDefinitelyRecurses(returnValue, method)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| else if (statement instanceof PsiForStatement) { |
| return forStatementDefinitelyRecurses((PsiForStatement) |
| statement, method); |
| } |
| else if (statement instanceof PsiForeachStatement) { |
| return foreachStatementDefinitelyRecurses( |
| (PsiForeachStatement)statement, method); |
| } |
| else if (statement instanceof PsiWhileStatement) { |
| return whileStatementDefinitelyRecurses( |
| (PsiWhileStatement)statement, method); |
| } |
| else if (statement instanceof PsiDoWhileStatement) { |
| return doWhileStatementDefinitelyRecurses( |
| (PsiDoWhileStatement)statement, method); |
| } |
| else if (statement instanceof PsiSynchronizedStatement) { |
| final PsiCodeBlock body = ((PsiSynchronizedStatement)statement) |
| .getBody(); |
| return codeBlockDefinitelyRecurses(body, method); |
| } |
| else if (statement instanceof PsiBlockStatement) { |
| final PsiCodeBlock codeBlock = ((PsiBlockStatement)statement) |
| .getCodeBlock(); |
| return codeBlockDefinitelyRecurses(codeBlock, method); |
| } |
| else if (statement instanceof PsiLabeledStatement) { |
| return labeledStatementDefinitelyRecurses( |
| (PsiLabeledStatement)statement, method); |
| } |
| else if (statement instanceof PsiIfStatement) { |
| return ifStatementDefinitelyRecurses( |
| (PsiIfStatement)statement, method); |
| } |
| else if (statement instanceof PsiTryStatement) { |
| return tryStatementDefinitelyRecurses( |
| (PsiTryStatement)statement, method); |
| } |
| else if (statement instanceof PsiSwitchStatement) { |
| return switchStatementDefinitelyRecurses( |
| (PsiSwitchStatement)statement, method); |
| } |
| else { |
| // unknown statement type |
| return false; |
| } |
| } |
| |
| private static boolean switchStatementDefinitelyRecurses( |
| PsiSwitchStatement switchStatement, PsiMethod method) { |
| final PsiExpression switchExpression = switchStatement.getExpression(); |
| return expressionDefinitelyRecurses(switchExpression, method); |
| } |
| |
| private static boolean tryStatementDefinitelyRecurses( |
| PsiTryStatement tryStatement, PsiMethod method) { |
| final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); |
| if (codeBlockDefinitelyRecurses(tryBlock, method)) { |
| return true; |
| } |
| final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); |
| return codeBlockDefinitelyRecurses(finallyBlock, method); |
| } |
| |
| private static boolean codeBlockDefinitelyRecurses(PsiCodeBlock block, |
| PsiMethod method) { |
| if (block == null) { |
| return false; |
| } |
| final PsiStatement[] statements = block.getStatements(); |
| for (final PsiStatement statement : statements) { |
| if (statementDefinitelyRecurses(statement, method)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static boolean ifStatementDefinitelyRecurses( |
| PsiIfStatement ifStatement, PsiMethod method) { |
| final PsiExpression condition = ifStatement.getCondition(); |
| if (expressionDefinitelyRecurses(condition, method)) { |
| return true; |
| } |
| final PsiStatement thenBranch = ifStatement.getThenBranch(); |
| final PsiStatement elseBranch = ifStatement.getElseBranch(); |
| if (thenBranch == null) { |
| return false; |
| } |
| final Object value = |
| ExpressionUtils.computeConstantExpression(condition); |
| if (value == Boolean.TRUE) { |
| return statementDefinitelyRecurses(thenBranch, method); |
| } |
| else if (value == Boolean.FALSE) { |
| return elseBranch != null && |
| statementDefinitelyRecurses(elseBranch, method); |
| } |
| return statementDefinitelyRecurses(thenBranch, method) && |
| statementDefinitelyRecurses(elseBranch, method); |
| } |
| |
| private static boolean forStatementDefinitelyRecurses( |
| PsiForStatement forStatement, PsiMethod method) { |
| final PsiStatement initialization = forStatement.getInitialization(); |
| if (statementDefinitelyRecurses(initialization, method)) { |
| return true; |
| } |
| final PsiExpression condition = forStatement.getCondition(); |
| if (expressionDefinitelyRecurses(condition, method)) { |
| return true; |
| } |
| final Object value = |
| ExpressionUtils.computeConstantExpression(condition); |
| if (value == Boolean.TRUE) { |
| final PsiStatement body = forStatement.getBody(); |
| return statementDefinitelyRecurses(body, method); |
| } |
| return false; |
| } |
| |
| private static boolean foreachStatementDefinitelyRecurses( |
| PsiForeachStatement foreachStatement, PsiMethod method) { |
| final PsiExpression iteration = foreachStatement.getIteratedValue(); |
| return expressionDefinitelyRecurses(iteration, method); |
| } |
| |
| private static boolean whileStatementDefinitelyRecurses( |
| PsiWhileStatement whileStatement, PsiMethod method) { |
| |
| final PsiExpression condition = whileStatement.getCondition(); |
| if (expressionDefinitelyRecurses(condition, method)) { |
| return true; |
| } |
| final Object value = |
| ExpressionUtils.computeConstantExpression(condition); |
| if (value == Boolean.TRUE) { |
| final PsiStatement body = whileStatement.getBody(); |
| return statementDefinitelyRecurses(body, method); |
| } |
| return false; |
| } |
| |
| private static boolean doWhileStatementDefinitelyRecurses( |
| PsiDoWhileStatement doWhileStatement, PsiMethod method) { |
| |
| final PsiStatement body = doWhileStatement.getBody(); |
| if (statementDefinitelyRecurses(body, method)) { |
| return true; |
| } |
| final PsiExpression condition = doWhileStatement.getCondition(); |
| return expressionDefinitelyRecurses(condition, method); |
| } |
| |
| private static boolean labeledStatementDefinitelyRecurses( |
| PsiLabeledStatement labeledStatement, PsiMethod method) { |
| final PsiStatement body = labeledStatement.getStatement(); |
| return statementDefinitelyRecurses(body, method); |
| } |
| |
| public static boolean methodDefinitelyRecurses( |
| @NotNull PsiMethod method) { |
| final PsiCodeBlock body = method.getBody(); |
| return body != null && |
| !codeBlockMayReturnBeforeRecursing(body, method, true); |
| } |
| } |