IDEADEV-40452
[fedora-idea.git] / plugins / InspectionGadgets / src / com / siyeh / ig / psiutils / RecursionUtils.java
blob702ade418dee758bdd8e01472e047d435cbd2858
1 /*
2 * Copyright 2003-2006 Dave Griffith, Bas Leijdekkers
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.siyeh.ig.psiutils;
18 import com.intellij.psi.*;
19 import com.intellij.psi.tree.IElementType;
20 import org.jetbrains.annotations.NotNull;
22 public class RecursionUtils{
24 private RecursionUtils(){
25 super();
28 public static boolean statementMayReturnBeforeRecursing(
29 PsiStatement statement, PsiMethod method){
30 if(statement == null){
31 return true;
33 if(statement instanceof PsiBreakStatement ||
34 statement instanceof PsiContinueStatement ||
35 statement instanceof PsiThrowStatement ||
36 statement instanceof PsiExpressionListStatement ||
37 statement instanceof PsiExpressionStatement ||
38 statement instanceof PsiEmptyStatement ||
39 statement instanceof PsiAssertStatement ||
40 statement instanceof PsiDeclarationStatement){
41 return false;
42 } else if(statement instanceof PsiReturnStatement){
43 final PsiReturnStatement returnStatement =
44 (PsiReturnStatement) statement;
45 final PsiExpression returnValue = returnStatement.getReturnValue();
46 if(returnValue != null){
47 if(expressionDefinitelyRecurses(returnValue, method)){
48 return false;
51 return true;
52 } else if(statement instanceof PsiForStatement){
53 return forStatementMayReturnBeforeRecursing(
54 (PsiForStatement) statement, method);
55 } else if(statement instanceof PsiForeachStatement){
56 return foreachStatementMayReturnBeforeRecursing(
57 (PsiForeachStatement) statement, method);
58 } else if(statement instanceof PsiWhileStatement){
59 return whileStatementMayReturnBeforeRecursing(
60 (PsiWhileStatement) statement, method);
61 } else if(statement instanceof PsiDoWhileStatement){
62 return doWhileStatementMayReturnBeforeRecursing(
63 (PsiDoWhileStatement) statement, method);
64 } else if(statement instanceof PsiSynchronizedStatement){
65 final PsiCodeBlock body = ((PsiSynchronizedStatement) statement)
66 .getBody();
67 return codeBlockMayReturnBeforeRecursing(body, method, false);
68 } else if(statement instanceof PsiBlockStatement){
69 final PsiBlockStatement blockStatement =
70 (PsiBlockStatement)statement;
71 final PsiCodeBlock codeBlock = blockStatement.getCodeBlock();
72 return codeBlockMayReturnBeforeRecursing(codeBlock, method, false);
73 } else if(statement instanceof PsiLabeledStatement){
74 return labeledStatementMayReturnBeforeRecursing(
75 (PsiLabeledStatement) statement, method);
76 } else if(statement instanceof PsiIfStatement){
77 return ifStatementMayReturnBeforeRecursing(
78 (PsiIfStatement) statement, method);
79 } else if(statement instanceof PsiTryStatement){
80 return tryStatementMayReturnBeforeRecursing(
81 (PsiTryStatement) statement, method);
82 } else if(statement instanceof PsiSwitchStatement){
83 return switchStatementMayReturnBeforeRecursing(
84 (PsiSwitchStatement) statement, method);
85 } else {
86 // unknown statement type
87 return true;
91 private static boolean doWhileStatementMayReturnBeforeRecursing(
92 PsiDoWhileStatement loopStatement, PsiMethod method){
93 final PsiStatement body = loopStatement.getBody();
94 return statementMayReturnBeforeRecursing(body, method);
97 private static boolean whileStatementMayReturnBeforeRecursing(
98 PsiWhileStatement loopStatement, PsiMethod method){
99 final PsiExpression test = loopStatement.getCondition();
100 if(expressionDefinitelyRecurses(test, method)){
101 return false;
103 final PsiStatement body = loopStatement.getBody();
104 return statementMayReturnBeforeRecursing(body, method);
107 private static boolean forStatementMayReturnBeforeRecursing(
108 PsiForStatement loopStatement, PsiMethod method){
109 final PsiStatement initialization = loopStatement.getInitialization();
111 if(statementMayReturnBeforeRecursing(initialization, method)){
112 return true;
114 final PsiExpression test = loopStatement.getCondition();
115 if(expressionDefinitelyRecurses(test, method)){
116 return false;
118 final PsiStatement body = loopStatement.getBody();
119 return statementMayReturnBeforeRecursing(body, method);
122 private static boolean foreachStatementMayReturnBeforeRecursing(
123 PsiForeachStatement loopStatement, PsiMethod method){
124 final PsiExpression test = loopStatement.getIteratedValue();
125 if(expressionDefinitelyRecurses(test, method)){
126 return false;
128 final PsiStatement body = loopStatement.getBody();
129 return statementMayReturnBeforeRecursing(body, method);
132 private static boolean switchStatementMayReturnBeforeRecursing(
133 PsiSwitchStatement switchStatement, PsiMethod method){
135 final PsiCodeBlock body = switchStatement.getBody();
136 if(body == null){
137 return true;
139 final PsiStatement[] statements = body.getStatements();
140 for(final PsiStatement statement : statements){
141 if(statementMayReturnBeforeRecursing(statement, method)){
142 return true;
145 return false;
148 private static boolean tryStatementMayReturnBeforeRecursing(
149 PsiTryStatement tryStatement, PsiMethod method){
150 final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
151 if(finallyBlock != null){
152 if (codeBlockMayReturnBeforeRecursing(finallyBlock, method,
153 false)) {
154 return true;
156 if (codeBlockDefinitelyRecurses(finallyBlock, method)) {
157 return false;
160 final PsiCodeBlock tryBlock = tryStatement.getTryBlock();
161 if(codeBlockMayReturnBeforeRecursing(tryBlock, method, false)){
162 return true;
164 final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks();
165 for(final PsiCodeBlock catchBlock : catchBlocks){
166 if(codeBlockMayReturnBeforeRecursing(catchBlock, method, false)){
167 return true;
170 return false;
173 private static boolean ifStatementMayReturnBeforeRecursing(
174 PsiIfStatement ifStatement, PsiMethod method){
175 final PsiExpression test = ifStatement.getCondition();
176 if(expressionDefinitelyRecurses(test, method)){
177 return false;
179 final PsiStatement thenBranch = ifStatement.getThenBranch();
180 if(statementMayReturnBeforeRecursing(thenBranch, method)){
181 return true;
183 final PsiStatement elseBranch = ifStatement.getElseBranch();
184 return elseBranch != null &&
185 statementMayReturnBeforeRecursing(elseBranch, method);
188 private static boolean labeledStatementMayReturnBeforeRecursing(
189 PsiLabeledStatement labeledStatement, PsiMethod method){
190 final PsiStatement statement = labeledStatement.getStatement();
191 return statementMayReturnBeforeRecursing(statement, method);
194 private static boolean codeBlockMayReturnBeforeRecursing(
195 PsiCodeBlock block, PsiMethod method, boolean endsInImplicitReturn){
196 if(block == null){
197 return true;
199 final PsiStatement[] statements = block.getStatements();
200 for(final PsiStatement statement : statements){
201 if(statementMayReturnBeforeRecursing(statement, method)){
202 return true;
204 if(statementDefinitelyRecurses(statement, method)){
205 return false;
208 return endsInImplicitReturn;
211 public static boolean methodMayRecurse(@NotNull PsiMethod method){
212 final RecursionVisitor recursionVisitor = new RecursionVisitor(method);
213 method.accept(recursionVisitor);
214 return recursionVisitor.isRecursive();
217 private static boolean expressionDefinitelyRecurses(PsiExpression exp,
218 PsiMethod method){
219 if(exp == null){
220 return false;
222 if(exp instanceof PsiMethodCallExpression){
223 return methodCallExpressionDefinitelyRecurses(
224 (PsiMethodCallExpression) exp, method);
226 if(exp instanceof PsiNewExpression){
227 return newExpressionDefinitelyRecurses(
228 (PsiNewExpression) exp, method);
230 if(exp instanceof PsiAssignmentExpression){
231 return assignmentExpressionDefinitelyRecurses(
232 (PsiAssignmentExpression) exp, method);
234 if(exp instanceof PsiArrayInitializerExpression){
235 return arrayInitializerExpressionDefinitelyRecurses(
236 (PsiArrayInitializerExpression) exp, method);
238 if(exp instanceof PsiTypeCastExpression){
239 return typeCastExpressionDefinitelyRecurses(
240 (PsiTypeCastExpression) exp, method);
242 if (exp instanceof PsiArrayAccessExpression){
243 return arrayAccessExpressionDefinitelyRecurses(
244 (PsiArrayAccessExpression) exp, method);
246 if(exp instanceof PsiPrefixExpression){
247 return prefixExpressionDefinitelyRecurses(
248 (PsiPrefixExpression) exp, method);
250 if (exp instanceof PsiPostfixExpression){
251 return postfixExpressionDefinitelyRecurses(
252 (PsiPostfixExpression) exp, method);
254 if (exp instanceof PsiBinaryExpression){
255 return binaryExpressionDefinitelyRecurses(
256 (PsiBinaryExpression) exp, method);
258 if (exp instanceof PsiInstanceOfExpression){
259 return instanceOfExpressionDefinitelyRecurses(
260 (PsiInstanceOfExpression) exp, method);
262 if(exp instanceof PsiConditionalExpression){
263 return conditionalExpressionDefinitelyRecurses(
264 (PsiConditionalExpression) exp, method);
266 if(exp instanceof PsiParenthesizedExpression){
267 return parenthesizedExpressionDefinitelyRecurses(
268 (PsiParenthesizedExpression) exp, method);
270 if(exp instanceof PsiReferenceExpression){
271 return referenceExpressionDefinitelyRecurses(
272 (PsiReferenceExpression) exp, method);
274 if (exp instanceof PsiLiteralExpression ||
275 exp instanceof PsiClassObjectAccessExpression ||
276 exp instanceof PsiThisExpression ||
277 exp instanceof PsiSuperExpression){
278 return false;
280 return false;
283 private static boolean conditionalExpressionDefinitelyRecurses(
284 PsiConditionalExpression expression, PsiMethod method){
285 final PsiExpression condExpression = expression.getCondition();
286 if(expressionDefinitelyRecurses(condExpression, method)){
287 return true;
289 final PsiExpression thenExpression = expression.getThenExpression();
290 final PsiExpression elseExpression = expression.getElseExpression();
291 return expressionDefinitelyRecurses(thenExpression, method)
292 && expressionDefinitelyRecurses(elseExpression, method);
295 private static boolean binaryExpressionDefinitelyRecurses(
296 PsiBinaryExpression expression, PsiMethod method){
297 final PsiExpression lhs = expression.getLOperand();
298 if(expressionDefinitelyRecurses(lhs, method)){
299 return true;
301 final PsiJavaToken sign = expression.getOperationSign();
302 final IElementType tokenType = sign.getTokenType();
303 if(tokenType.equals(JavaTokenType.ANDAND) ||
304 tokenType.equals(JavaTokenType.OROR)){
305 return false;
307 final PsiExpression rhs = expression.getROperand();
308 return expressionDefinitelyRecurses(rhs, method);
311 private static boolean arrayAccessExpressionDefinitelyRecurses(
312 PsiArrayAccessExpression expression, PsiMethod method){
313 final PsiExpression arrayExp = expression.getArrayExpression();
314 final PsiExpression indexExp = expression.getIndexExpression();
315 return expressionDefinitelyRecurses(arrayExp, method) ||
316 expressionDefinitelyRecurses(indexExp, method);
319 private static boolean arrayInitializerExpressionDefinitelyRecurses(
320 PsiArrayInitializerExpression expression, PsiMethod method){
321 final PsiExpression[] initializers = expression.getInitializers();
322 for(final PsiExpression initializer : initializers){
323 if(expressionDefinitelyRecurses(initializer, method)){
324 return true;
327 return false;
330 private static boolean prefixExpressionDefinitelyRecurses(
331 PsiPrefixExpression expression, PsiMethod method){
332 final PsiExpression operand = expression.getOperand();
333 return expressionDefinitelyRecurses(operand, method);
336 private static boolean postfixExpressionDefinitelyRecurses(
337 PsiPostfixExpression expression, PsiMethod method){
338 final PsiExpression operand = expression.getOperand();
339 return expressionDefinitelyRecurses(operand, method);
342 private static boolean instanceOfExpressionDefinitelyRecurses(
343 PsiInstanceOfExpression expression, PsiMethod method){
344 final PsiExpression operand = expression.getOperand();
345 return expressionDefinitelyRecurses(operand, method);
348 private static boolean parenthesizedExpressionDefinitelyRecurses(
349 PsiParenthesizedExpression expression, PsiMethod method){
350 final PsiExpression innerExpression = expression.getExpression();
351 return expressionDefinitelyRecurses(innerExpression, method);
354 private static boolean referenceExpressionDefinitelyRecurses(
355 PsiReferenceExpression expression, PsiMethod method){
357 final PsiExpression qualifierExpression =
358 expression.getQualifierExpression();
359 if(qualifierExpression != null){
360 return expressionDefinitelyRecurses(qualifierExpression, method);
362 return false;
365 private static boolean typeCastExpressionDefinitelyRecurses(
366 PsiTypeCastExpression expression, PsiMethod method){
367 final PsiExpression operand = expression.getOperand();
368 return expressionDefinitelyRecurses(operand, method);
371 private static boolean assignmentExpressionDefinitelyRecurses(
372 PsiAssignmentExpression assignmentExpression, PsiMethod method){
373 final PsiExpression rhs = assignmentExpression.getRExpression();
374 final PsiExpression lhs = assignmentExpression.getLExpression();
375 return expressionDefinitelyRecurses(rhs, method) ||
376 expressionDefinitelyRecurses(lhs, method);
379 private static boolean newExpressionDefinitelyRecurses(PsiNewExpression exp,
380 PsiMethod method){
381 final PsiExpression[] arrayDimensions = exp.getArrayDimensions();
382 for(final PsiExpression arrayDimension : arrayDimensions){
383 if(expressionDefinitelyRecurses(arrayDimension, method)){
384 return true;
387 final PsiArrayInitializerExpression arrayInitializer = exp
388 .getArrayInitializer();
389 if(expressionDefinitelyRecurses(arrayInitializer, method)){
390 return true;
392 final PsiExpression qualifier = exp.getQualifier();
393 if(expressionDefinitelyRecurses(qualifier, method)){
394 return true;
396 final PsiExpressionList argumentList = exp.getArgumentList();
397 if(argumentList != null){
398 final PsiExpression[] args = argumentList.getExpressions();
399 for(final PsiExpression arg : args){
400 if(expressionDefinitelyRecurses(arg, method)){
401 return true;
405 return false;
408 private static boolean methodCallExpressionDefinitelyRecurses(
409 PsiMethodCallExpression exp, PsiMethod method){
410 final PsiReferenceExpression methodExpression =
411 exp.getMethodExpression();
412 final PsiMethod referencedMethod = exp.resolveMethod();
413 if(referencedMethod == null){
414 return false;
416 if(referencedMethod.equals(method)){
417 if(method.hasModifierProperty(PsiModifier.STATIC) ||
418 method.hasModifierProperty(PsiModifier.PRIVATE)){
419 return true;
421 final PsiExpression qualifier =
422 methodExpression.getQualifierExpression();
423 if(qualifier == null || qualifier instanceof PsiThisExpression){
424 return true;
427 final PsiExpression qualifier =
428 methodExpression.getQualifierExpression();
429 if(expressionDefinitelyRecurses(qualifier, method)){
430 return true;
432 final PsiExpressionList argumentList = exp.getArgumentList();
433 final PsiExpression[] args = argumentList.getExpressions();
434 for(final PsiExpression arg : args){
435 if(expressionDefinitelyRecurses(arg, method)){
436 return true;
439 return false;
442 private static boolean statementDefinitelyRecurses(PsiStatement statement,
443 PsiMethod method){
444 if(statement == null){
445 return false;
447 if(statement instanceof PsiBreakStatement ||
448 statement instanceof PsiContinueStatement ||
449 statement instanceof PsiThrowStatement ||
450 statement instanceof PsiEmptyStatement ||
451 statement instanceof PsiAssertStatement){
452 return false;
453 } else if(statement instanceof PsiExpressionListStatement){
454 final PsiExpressionListStatement expressionListStatement =
455 (PsiExpressionListStatement)statement;
456 final PsiExpressionList expressionList =
457 expressionListStatement.getExpressionList();
458 if(expressionList == null){
459 return false;
461 final PsiExpression[] expressions = expressionList.getExpressions();
462 for(final PsiExpression expression : expressions){
463 if(expressionDefinitelyRecurses(expression, method)){
464 return true;
467 return false;
468 } else if(statement instanceof PsiExpressionStatement){
469 final PsiExpressionStatement expressionStatement =
470 (PsiExpressionStatement)statement;
471 final PsiExpression expression =
472 expressionStatement.getExpression();
473 return expressionDefinitelyRecurses(expression, method);
474 } else if(statement instanceof PsiDeclarationStatement){
475 final PsiDeclarationStatement declaration =
476 (PsiDeclarationStatement) statement;
477 final PsiElement[] declaredElements =
478 declaration.getDeclaredElements();
479 for(final PsiElement declaredElement : declaredElements){
480 if(declaredElement instanceof PsiLocalVariable){
481 final PsiLocalVariable variable =
482 (PsiLocalVariable) declaredElement;
483 final PsiExpression initializer = variable.getInitializer();
484 if(expressionDefinitelyRecurses(initializer, method)){
485 return true;
489 return false;
490 } else if(statement instanceof PsiReturnStatement){
491 final PsiReturnStatement returnStatement =
492 (PsiReturnStatement) statement;
493 final PsiExpression returnValue = returnStatement.getReturnValue();
494 if(returnValue != null){
495 if(expressionDefinitelyRecurses(returnValue, method)){
496 return true;
499 return false;
500 } else if(statement instanceof PsiForStatement){
501 return forStatementDefinitelyRecurses((PsiForStatement)
502 statement, method);
503 } else if(statement instanceof PsiForeachStatement){
504 return foreachStatementDefinitelyRecurses(
505 (PsiForeachStatement) statement, method);
506 } else if (statement instanceof PsiWhileStatement){
507 return whileStatementDefinitelyRecurses(
508 (PsiWhileStatement) statement, method);
509 } else if (statement instanceof PsiDoWhileStatement){
510 return doWhileStatementDefinitelyRecurses(
511 (PsiDoWhileStatement) statement, method);
512 } else if (statement instanceof PsiSynchronizedStatement){
513 final PsiCodeBlock body = ((PsiSynchronizedStatement) statement)
514 .getBody();
515 return codeBlockDefinitelyRecurses(body, method);
516 } else if(statement instanceof PsiBlockStatement){
517 final PsiCodeBlock codeBlock = ((PsiBlockStatement) statement)
518 .getCodeBlock();
519 return codeBlockDefinitelyRecurses(codeBlock, method);
520 } else if(statement instanceof PsiLabeledStatement){
521 return labeledStatementDefinitelyRecurses(
522 (PsiLabeledStatement) statement, method);
523 } else if (statement instanceof PsiIfStatement){
524 return ifStatementDefinitelyRecurses(
525 (PsiIfStatement) statement, method);
526 } else if(statement instanceof PsiTryStatement){
527 return tryStatementDefinitelyRecurses(
528 (PsiTryStatement) statement, method);
529 } else if(statement instanceof PsiSwitchStatement){
530 return switchStatementDefinitelyRecurses(
531 (PsiSwitchStatement) statement, method);
532 } else {
533 // unknown statement type
534 return false;
538 private static boolean switchStatementDefinitelyRecurses(
539 PsiSwitchStatement switchStatement, PsiMethod method){
540 final PsiExpression switchExpression = switchStatement.getExpression();
541 return expressionDefinitelyRecurses(switchExpression, method);
544 private static boolean tryStatementDefinitelyRecurses(
545 PsiTryStatement tryStatement, PsiMethod method) {
546 final PsiCodeBlock tryBlock = tryStatement.getTryBlock();
547 if(codeBlockDefinitelyRecurses(tryBlock, method)){
548 return true;
550 final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
551 return codeBlockDefinitelyRecurses(finallyBlock, method);
554 private static boolean codeBlockDefinitelyRecurses(PsiCodeBlock block,
555 PsiMethod method){
556 if(block == null){
557 return false;
559 final PsiStatement[] statements = block.getStatements();
560 for(final PsiStatement statement : statements){
561 if(statementDefinitelyRecurses(statement, method)){
562 return true;
565 return false;
568 private static boolean ifStatementDefinitelyRecurses(
569 PsiIfStatement ifStatement, PsiMethod method) {
570 final PsiExpression condition = ifStatement.getCondition();
571 if(expressionDefinitelyRecurses(condition, method)){
572 return true;
574 final PsiStatement thenBranch = ifStatement.getThenBranch();
575 final PsiStatement elseBranch = ifStatement.getElseBranch();
576 if(thenBranch == null || elseBranch == null){
577 return false;
579 return statementDefinitelyRecurses(thenBranch, method) &&
580 statementDefinitelyRecurses(elseBranch, method);
583 private static boolean forStatementDefinitelyRecurses(
584 PsiForStatement forStatement, PsiMethod method) {
585 final PsiStatement initialization = forStatement.getInitialization();
586 if(statementDefinitelyRecurses(initialization, method)){
587 return true;
589 final PsiExpression condition = forStatement.getCondition();
590 if(expressionDefinitelyRecurses(condition, method)){
591 return true;
593 if(BoolUtils.isTrue(condition)){
594 final PsiStatement body = forStatement.getBody();
595 return statementDefinitelyRecurses(body, method);
597 return false;
600 private static boolean foreachStatementDefinitelyRecurses(
601 PsiForeachStatement foreachStatement, PsiMethod method){
602 final PsiExpression iteration = foreachStatement.getIteratedValue();
603 return expressionDefinitelyRecurses(iteration, method);
606 private static boolean whileStatementDefinitelyRecurses(
607 PsiWhileStatement whileStatement, PsiMethod method){
609 final PsiExpression condition = whileStatement.getCondition();
610 if(expressionDefinitelyRecurses(condition, method)){
611 return true;
613 if(BoolUtils.isTrue(condition)){
614 final PsiStatement body = whileStatement.getBody();
615 return statementDefinitelyRecurses(body, method);
617 return false;
620 private static boolean doWhileStatementDefinitelyRecurses(
621 PsiDoWhileStatement doWhileStatement, PsiMethod method){
623 final PsiStatement body = doWhileStatement.getBody();
624 if(statementDefinitelyRecurses(body, method)){
625 return true;
627 final PsiExpression condition = doWhileStatement.getCondition();
628 return expressionDefinitelyRecurses(condition, method);
631 private static boolean labeledStatementDefinitelyRecurses(
632 PsiLabeledStatement labeledStatement, PsiMethod method){
633 final PsiStatement body = labeledStatement.getStatement();
634 return statementDefinitelyRecurses(body, method);
637 public static boolean methodDefinitelyRecurses(
638 @NotNull PsiMethod method){
639 final PsiCodeBlock body = method.getBody();
640 if(body == null){
641 return false;
643 return !codeBlockMayReturnBeforeRecursing(body, method, true);