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(){
28 public static boolean statementMayReturnBeforeRecursing(
29 PsiStatement statement
, PsiMethod method
){
30 if(statement
== null){
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
){
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
)){
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
)
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
);
86 // unknown statement type
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
)){
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
)){
114 final PsiExpression test
= loopStatement
.getCondition();
115 if(expressionDefinitelyRecurses(test
, method
)){
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
)){
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();
139 final PsiStatement
[] statements
= body
.getStatements();
140 for(final PsiStatement statement
: statements
){
141 if(statementMayReturnBeforeRecursing(statement
, method
)){
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
,
156 if (codeBlockDefinitelyRecurses(finallyBlock
, method
)) {
160 final PsiCodeBlock tryBlock
= tryStatement
.getTryBlock();
161 if(codeBlockMayReturnBeforeRecursing(tryBlock
, method
, false)){
164 final PsiCodeBlock
[] catchBlocks
= tryStatement
.getCatchBlocks();
165 for(final PsiCodeBlock catchBlock
: catchBlocks
){
166 if(codeBlockMayReturnBeforeRecursing(catchBlock
, method
, false)){
173 private static boolean ifStatementMayReturnBeforeRecursing(
174 PsiIfStatement ifStatement
, PsiMethod method
){
175 final PsiExpression test
= ifStatement
.getCondition();
176 if(expressionDefinitelyRecurses(test
, method
)){
179 final PsiStatement thenBranch
= ifStatement
.getThenBranch();
180 if(statementMayReturnBeforeRecursing(thenBranch
, method
)){
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
){
199 final PsiStatement
[] statements
= block
.getStatements();
200 for(final PsiStatement statement
: statements
){
201 if(statementMayReturnBeforeRecursing(statement
, method
)){
204 if(statementDefinitelyRecurses(statement
, method
)){
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
,
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
){
283 private static boolean conditionalExpressionDefinitelyRecurses(
284 PsiConditionalExpression expression
, PsiMethod method
){
285 final PsiExpression condExpression
= expression
.getCondition();
286 if(expressionDefinitelyRecurses(condExpression
, method
)){
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
)){
301 final PsiJavaToken sign
= expression
.getOperationSign();
302 final IElementType tokenType
= sign
.getTokenType();
303 if(tokenType
.equals(JavaTokenType
.ANDAND
) ||
304 tokenType
.equals(JavaTokenType
.OROR
)){
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
)){
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
);
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
,
381 final PsiExpression
[] arrayDimensions
= exp
.getArrayDimensions();
382 for(final PsiExpression arrayDimension
: arrayDimensions
){
383 if(expressionDefinitelyRecurses(arrayDimension
, method
)){
387 final PsiArrayInitializerExpression arrayInitializer
= exp
388 .getArrayInitializer();
389 if(expressionDefinitelyRecurses(arrayInitializer
, method
)){
392 final PsiExpression qualifier
= exp
.getQualifier();
393 if(expressionDefinitelyRecurses(qualifier
, method
)){
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
)){
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){
416 if(referencedMethod
.equals(method
)){
417 if(method
.hasModifierProperty(PsiModifier
.STATIC
) ||
418 method
.hasModifierProperty(PsiModifier
.PRIVATE
)){
421 final PsiExpression qualifier
=
422 methodExpression
.getQualifierExpression();
423 if(qualifier
== null || qualifier
instanceof PsiThisExpression
){
427 final PsiExpression qualifier
=
428 methodExpression
.getQualifierExpression();
429 if(expressionDefinitelyRecurses(qualifier
, method
)){
432 final PsiExpressionList argumentList
= exp
.getArgumentList();
433 final PsiExpression
[] args
= argumentList
.getExpressions();
434 for(final PsiExpression arg
: args
){
435 if(expressionDefinitelyRecurses(arg
, method
)){
442 private static boolean statementDefinitelyRecurses(PsiStatement statement
,
444 if(statement
== null){
447 if(statement
instanceof PsiBreakStatement
||
448 statement
instanceof PsiContinueStatement
||
449 statement
instanceof PsiThrowStatement
||
450 statement
instanceof PsiEmptyStatement
||
451 statement
instanceof PsiAssertStatement
){
453 } else if(statement
instanceof PsiExpressionListStatement
){
454 final PsiExpressionListStatement expressionListStatement
=
455 (PsiExpressionListStatement
)statement
;
456 final PsiExpressionList expressionList
=
457 expressionListStatement
.getExpressionList();
458 if(expressionList
== null){
461 final PsiExpression
[] expressions
= expressionList
.getExpressions();
462 for(final PsiExpression expression
: expressions
){
463 if(expressionDefinitelyRecurses(expression
, method
)){
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
)){
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
)){
500 } else if(statement
instanceof PsiForStatement
){
501 return forStatementDefinitelyRecurses((PsiForStatement
)
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
)
515 return codeBlockDefinitelyRecurses(body
, method
);
516 } else if(statement
instanceof PsiBlockStatement
){
517 final PsiCodeBlock codeBlock
= ((PsiBlockStatement
) statement
)
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
);
533 // unknown statement type
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
)){
550 final PsiCodeBlock finallyBlock
= tryStatement
.getFinallyBlock();
551 return codeBlockDefinitelyRecurses(finallyBlock
, method
);
554 private static boolean codeBlockDefinitelyRecurses(PsiCodeBlock block
,
559 final PsiStatement
[] statements
= block
.getStatements();
560 for(final PsiStatement statement
: statements
){
561 if(statementDefinitelyRecurses(statement
, method
)){
568 private static boolean ifStatementDefinitelyRecurses(
569 PsiIfStatement ifStatement
, PsiMethod method
) {
570 final PsiExpression condition
= ifStatement
.getCondition();
571 if(expressionDefinitelyRecurses(condition
, method
)){
574 final PsiStatement thenBranch
= ifStatement
.getThenBranch();
575 final PsiStatement elseBranch
= ifStatement
.getElseBranch();
576 if(thenBranch
== null || elseBranch
== null){
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
)){
589 final PsiExpression condition
= forStatement
.getCondition();
590 if(expressionDefinitelyRecurses(condition
, method
)){
593 if(BoolUtils
.isTrue(condition
)){
594 final PsiStatement body
= forStatement
.getBody();
595 return statementDefinitelyRecurses(body
, method
);
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
)){
613 if(BoolUtils
.isTrue(condition
)){
614 final PsiStatement body
= whileStatement
.getBody();
615 return statementDefinitelyRecurses(body
, method
);
620 private static boolean doWhileStatementDefinitelyRecurses(
621 PsiDoWhileStatement doWhileStatement
, PsiMethod method
){
623 final PsiStatement body
= doWhileStatement
.getBody();
624 if(statementDefinitelyRecurses(body
, method
)){
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();
643 return !codeBlockMayReturnBeforeRecursing(body
, method
, true);