2 * Copyright 2003-2009 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
.util
.MethodSignature
;
20 import org
.jetbrains
.annotations
.NotNull
;
21 import org
.jetbrains
.annotations
.Nullable
;
23 import java
.util
.HashSet
;
26 public class InitializationUtils
{
28 private InitializationUtils(){
31 public static boolean methodAssignsVariableOrFails(
32 @Nullable PsiMethod method
, @NotNull PsiVariable variable
) {
33 return methodAssignsVariableOrFails(method
, variable
, false);
36 public static boolean methodAssignsVariableOrFails(
37 @Nullable PsiMethod method
, @NotNull PsiVariable variable
,
42 final PsiCodeBlock body
= method
.getBody();
43 return body
!= null && blockAssignsVariableOrFails(body
, variable
,
47 public static boolean classInitializerAssignsVariableOrFails(
48 @Nullable PsiClassInitializer initializer
,
49 @NotNull PsiVariable variable
, boolean strict
) {
50 if (initializer
== null) {
53 final PsiCodeBlock body
= initializer
.getBody();
54 return blockAssignsVariableOrFails(body
, variable
, strict
);
57 public static boolean blockAssignsVariableOrFails(
58 @Nullable PsiCodeBlock block
, @NotNull PsiVariable variable
) {
59 return blockAssignsVariableOrFails(block
, variable
, false);
62 public static boolean blockAssignsVariableOrFails(
63 @Nullable PsiCodeBlock block
, @NotNull PsiVariable variable
,
65 return blockAssignsVariableOrFails(block
, variable
,
66 new HashSet
<MethodSignature
>(), strict
);
69 private static boolean blockAssignsVariableOrFails(
70 @Nullable PsiCodeBlock block
, @NotNull PsiVariable variable
,
71 @NotNull Set
<MethodSignature
> checkedMethods
, boolean strict
){
75 final PsiStatement
[] statements
= block
.getStatements();
76 int assignmentCount
= 0;
77 for(final PsiStatement statement
: statements
){
78 if(statementAssignsVariableOrFails(statement
, variable
,
79 checkedMethods
, strict
)){
87 return assignmentCount
== 1;
90 private static boolean statementAssignsVariableOrFails(
91 @Nullable PsiStatement statement
, PsiVariable variable
,
92 @NotNull Set
<MethodSignature
> checkedMethods
, boolean strict
){
93 if(statement
== null){
96 if(ExceptionUtils
.statementThrowsException(statement
)){
99 if(statement
instanceof PsiBreakStatement
||
100 statement
instanceof PsiContinueStatement
||
101 statement
instanceof PsiAssertStatement
||
102 statement
instanceof PsiEmptyStatement
){
104 } else if(statement
instanceof PsiReturnStatement
){
105 final PsiReturnStatement returnStatement
=
106 (PsiReturnStatement
) statement
;
107 final PsiExpression returnValue
= returnStatement
.getReturnValue();
108 return expressionAssignsVariableOrFails(returnValue
, variable
,
109 checkedMethods
, strict
);
110 } else if(statement
instanceof PsiThrowStatement
){
111 final PsiThrowStatement throwStatement
=
112 (PsiThrowStatement
) statement
;
113 final PsiExpression exception
= throwStatement
.getException();
114 return expressionAssignsVariableOrFails(exception
, variable
,
115 checkedMethods
, strict
);
116 } else if(statement
instanceof PsiExpressionListStatement
){
117 final PsiExpressionListStatement list
=
118 (PsiExpressionListStatement
) statement
;
119 final PsiExpressionList expressionList
= list
.getExpressionList();
120 final PsiExpression
[] expressions
= expressionList
.getExpressions();
121 for(final PsiExpression expression
: expressions
){
122 if(expressionAssignsVariableOrFails(expression
, variable
,
123 checkedMethods
, strict
)){
128 } else if(statement
instanceof PsiExpressionStatement
){
129 final PsiExpressionStatement expressionStatement
=
130 (PsiExpressionStatement
) statement
;
131 final PsiExpression expression
=
132 expressionStatement
.getExpression();
133 return expressionAssignsVariableOrFails(expression
, variable
,
134 checkedMethods
, strict
);
135 } else if(statement
instanceof PsiDeclarationStatement
){
136 final PsiDeclarationStatement declarationStatement
=
137 (PsiDeclarationStatement
)statement
;
138 return declarationStatementAssignsVariableOrFails(
139 declarationStatement
, variable
, checkedMethods
, strict
);
140 } else if(statement
instanceof PsiForStatement
){
141 final PsiForStatement forStatement
= (PsiForStatement
)statement
;
142 return forStatementAssignsVariableOrFails(forStatement
,
144 checkedMethods
, strict
);
145 } else if(statement
instanceof PsiForeachStatement
){
146 final PsiForeachStatement foreachStatement
=
147 (PsiForeachStatement
)statement
;
148 return foreachStatementAssignsVariableOrFails(variable
,
150 } else if(statement
instanceof PsiWhileStatement
){
151 final PsiWhileStatement whileStatement
=
152 (PsiWhileStatement
)statement
;
153 return whileStatementAssignsVariableOrFails(whileStatement
,
154 variable
, checkedMethods
, strict
);
155 } else if(statement
instanceof PsiDoWhileStatement
){
156 final PsiDoWhileStatement doWhileStatement
=
157 (PsiDoWhileStatement
)statement
;
158 return doWhileAssignsVariableOrFails(doWhileStatement
, variable
,
159 checkedMethods
, strict
);
160 } else if(statement
instanceof PsiSynchronizedStatement
){
161 final PsiSynchronizedStatement synchronizedStatement
=
162 (PsiSynchronizedStatement
)statement
;
163 final PsiCodeBlock body
= synchronizedStatement
.getBody();
164 return blockAssignsVariableOrFails(body
, variable
,
165 checkedMethods
, strict
);
166 } else if(statement
instanceof PsiBlockStatement
){
167 final PsiBlockStatement blockStatement
=
168 (PsiBlockStatement
)statement
;
169 final PsiCodeBlock codeBlock
= blockStatement
.getCodeBlock();
170 return blockAssignsVariableOrFails(codeBlock
, variable
,
171 checkedMethods
, strict
);
172 } else if(statement
instanceof PsiLabeledStatement
){
173 final PsiLabeledStatement labeledStatement
=
174 (PsiLabeledStatement
) statement
;
175 final PsiStatement statementLabeled
=
176 labeledStatement
.getStatement();
177 return statementAssignsVariableOrFails(statementLabeled
, variable
,
178 checkedMethods
, strict
);
179 } else if(statement
instanceof PsiIfStatement
){
180 final PsiIfStatement ifStatement
= (PsiIfStatement
)statement
;
181 return ifStatementAssignsVariableOrFails(ifStatement
, variable
,
182 checkedMethods
, strict
);
183 } else if(statement
instanceof PsiTryStatement
){
184 final PsiTryStatement tryStatement
= (PsiTryStatement
)statement
;
185 return tryStatementAssignsVariableOrFails(tryStatement
, variable
,
186 checkedMethods
, strict
);
187 } else if(statement
instanceof PsiSwitchStatement
){
188 final PsiSwitchStatement switchStatement
=
189 (PsiSwitchStatement
)statement
;
190 return switchStatementAssignsVariableOrFails(switchStatement
,
191 variable
, checkedMethods
, strict
);
193 // unknown statement type
198 public static boolean switchStatementAssignsVariableOrFails(
199 @NotNull PsiSwitchStatement switchStatement
,
200 @NotNull PsiVariable variable
,
202 return switchStatementAssignsVariableOrFails(switchStatement
, variable
,
203 new HashSet(), strict
);
206 private static boolean switchStatementAssignsVariableOrFails(
207 @NotNull PsiSwitchStatement switchStatement
,
208 @NotNull PsiVariable variable
,
209 @NotNull Set
<MethodSignature
> checkedMethods
, boolean strict
) {
210 final PsiExpression expression
= switchStatement
.getExpression();
211 if (expressionAssignsVariableOrFails(expression
, variable
,
212 checkedMethods
, strict
)) {
215 final PsiCodeBlock body
= switchStatement
.getBody();
219 final PsiStatement
[] statements
= body
.getStatements();
220 boolean containsDefault
= false;
221 boolean assigns
= false;
222 for (int i
= 0; i
< statements
.length
; i
++) {
223 final PsiStatement statement
= statements
[i
];
224 if (statement
instanceof PsiSwitchLabelStatement
) {
225 final PsiSwitchLabelStatement labelStatement
226 = (PsiSwitchLabelStatement
) statement
;
227 if (i
== statements
.length
- 1) {
230 if (labelStatement
.isDefaultCase()) {
231 containsDefault
= true;
234 } else if (statement
instanceof PsiBreakStatement
) {
235 final PsiBreakStatement breakStatement
236 = (PsiBreakStatement
) statement
;
237 if (breakStatement
.getLabelIdentifier() != null) {
245 assigns
|= statementAssignsVariableOrFails(statement
, variable
,
246 checkedMethods
, strict
);
247 if (i
== statements
.length
- 1 && !assigns
) {
252 return containsDefault
;
255 private static boolean declarationStatementAssignsVariableOrFails(
256 PsiDeclarationStatement declarationStatement
, PsiVariable variable
,
257 Set
<MethodSignature
> checkedMethods
, boolean strict
){
258 final PsiElement
[] elements
=
259 declarationStatement
.getDeclaredElements();
260 for(PsiElement element
: elements
){
261 if (element
instanceof PsiVariable
) {
262 final PsiVariable declaredVariable
= (PsiVariable
) element
;
263 final PsiExpression initializer
=
264 declaredVariable
.getInitializer();
265 if(expressionAssignsVariableOrFails(initializer
, variable
,
266 checkedMethods
, strict
)){
274 private static boolean tryStatementAssignsVariableOrFails(
275 @NotNull PsiTryStatement tryStatement
, PsiVariable variable
,
276 @NotNull Set
<MethodSignature
> checkedMethods
, boolean strict
){
277 final PsiCodeBlock tryBlock
= tryStatement
.getTryBlock();
278 boolean initializedInTryAndCatch
=
279 blockAssignsVariableOrFails(tryBlock
, variable
,
280 checkedMethods
, strict
);
281 final PsiCodeBlock
[] catchBlocks
= tryStatement
.getCatchBlocks();
282 for(final PsiCodeBlock catchBlock
: catchBlocks
){
284 initializedInTryAndCatch
&=
285 ExceptionUtils
.blockThrowsException(catchBlock
);
287 initializedInTryAndCatch
&= blockAssignsVariableOrFails(
288 catchBlock
, variable
,
289 checkedMethods
, strict
);
292 if(initializedInTryAndCatch
){
295 final PsiCodeBlock finallyBlock
= tryStatement
.getFinallyBlock();
296 return blockAssignsVariableOrFails(finallyBlock
, variable
,
297 checkedMethods
, strict
);
300 private static boolean ifStatementAssignsVariableOrFails(
301 @NotNull PsiIfStatement ifStatement
,
302 PsiVariable variable
,
303 @NotNull Set
<MethodSignature
> checkedMethods
,
305 final PsiExpression condition
= ifStatement
.getCondition();
306 if(expressionAssignsVariableOrFails(condition
, variable
,
307 checkedMethods
, strict
)){
310 final PsiStatement thenBranch
= ifStatement
.getThenBranch();
311 final PsiStatement elseBranch
= ifStatement
.getElseBranch();
312 if (BoolUtils
.isTrue(condition
)) {
313 return statementAssignsVariableOrFails(thenBranch
, variable
,
314 checkedMethods
, strict
);
315 } else if (BoolUtils
.isFalse(condition
)) {
316 return statementAssignsVariableOrFails(elseBranch
, variable
,
317 checkedMethods
, strict
);
319 return statementAssignsVariableOrFails(thenBranch
, variable
,
320 checkedMethods
, strict
) &&
321 statementAssignsVariableOrFails(elseBranch
, variable
,
322 checkedMethods
, strict
);
325 private static boolean doWhileAssignsVariableOrFails(
326 @NotNull PsiDoWhileStatement doWhileStatement
,
327 PsiVariable variable
,
328 @NotNull Set
<MethodSignature
> checkedMethods
,
330 final PsiExpression condition
= doWhileStatement
.getCondition();
331 final PsiStatement body
= doWhileStatement
.getBody();
332 return expressionAssignsVariableOrFails(condition
, variable
,
333 checkedMethods
, strict
) ||
334 statementAssignsVariableOrFails(body
, variable
, checkedMethods
,
338 private static boolean whileStatementAssignsVariableOrFails(
339 @NotNull PsiWhileStatement whileStatement
, PsiVariable variable
,
340 @NotNull Set
<MethodSignature
> checkedMethods
,
342 final PsiExpression condition
= whileStatement
.getCondition();
343 if(expressionAssignsVariableOrFails(condition
, variable
,
344 checkedMethods
, strict
)){
347 if(BoolUtils
.isTrue(condition
)){
348 final PsiStatement body
= whileStatement
.getBody();
349 if(statementAssignsVariableOrFails(body
, variable
, checkedMethods
,
357 private static boolean forStatementAssignsVariableOrFails(
358 @NotNull PsiForStatement forStatement
, PsiVariable variable
,
359 @NotNull Set
<MethodSignature
> checkedMethods
, boolean strict
){
360 final PsiStatement initialization
= forStatement
.getInitialization();
361 if(statementAssignsVariableOrFails(initialization
, variable
,
362 checkedMethods
, strict
)){
365 final PsiExpression test
= forStatement
.getCondition();
366 if(expressionAssignsVariableOrFails(test
, variable
, checkedMethods
,
370 if(BoolUtils
.isTrue(test
)){
371 final PsiStatement body
= forStatement
.getBody();
372 if(statementAssignsVariableOrFails(body
, variable
, checkedMethods
,
376 final PsiStatement update
= forStatement
.getUpdate();
377 if(statementAssignsVariableOrFails(update
, variable
,
378 checkedMethods
, strict
)){
385 private static boolean foreachStatementAssignsVariableOrFails(
386 PsiVariable field
, PsiForeachStatement forStatement
){
390 private static boolean expressionAssignsVariableOrFails(
391 @Nullable PsiExpression expression
,
392 PsiVariable variable
,
393 @NotNull Set
<MethodSignature
> checkedMethods
, boolean strict
){
394 if(expression
== null){
397 if(expression
instanceof PsiThisExpression
||
398 expression
instanceof PsiLiteralExpression
||
399 expression
instanceof PsiSuperExpression
||
400 expression
instanceof PsiClassObjectAccessExpression
){
402 } else if(expression
instanceof PsiReferenceExpression
){
404 } else if(expression
instanceof PsiMethodCallExpression
){
405 final PsiMethodCallExpression methodCallExpression
=
406 (PsiMethodCallExpression
)expression
;
407 return methodCallAssignsVariableOrFails(methodCallExpression
,
408 variable
, checkedMethods
, strict
);
409 } else if (expression
instanceof PsiNewExpression
){
410 final PsiNewExpression newExpression
= (PsiNewExpression
)expression
;
411 return newExpressionAssignsVariableOrFails(newExpression
, variable
,
412 checkedMethods
, strict
);
413 } else if(expression
instanceof PsiArrayInitializerExpression
){
414 final PsiArrayInitializerExpression array
=
415 (PsiArrayInitializerExpression
) expression
;
416 final PsiExpression
[] initializers
= array
.getInitializers();
417 for(final PsiExpression initializer
: initializers
){
418 if(expressionAssignsVariableOrFails(initializer
, variable
,
419 checkedMethods
, strict
)){
424 } else if(expression
instanceof PsiTypeCastExpression
){
425 final PsiTypeCastExpression typeCast
=
426 (PsiTypeCastExpression
) expression
;
427 final PsiExpression operand
= typeCast
.getOperand();
428 return expressionAssignsVariableOrFails(operand
, variable
,
429 checkedMethods
, strict
);
430 } else if(expression
instanceof PsiArrayAccessExpression
){
431 final PsiArrayAccessExpression accessExpression
=
432 (PsiArrayAccessExpression
) expression
;
433 final PsiExpression arrayExpression
=
434 accessExpression
.getArrayExpression();
435 final PsiExpression indexExpression
=
436 accessExpression
.getIndexExpression();
437 return expressionAssignsVariableOrFails(arrayExpression
, variable
,
438 checkedMethods
, strict
) ||
439 expressionAssignsVariableOrFails(indexExpression
, variable
,
440 checkedMethods
, strict
);
441 } else if(expression
instanceof PsiPrefixExpression
){
442 final PsiPrefixExpression prefixExpression
=
443 (PsiPrefixExpression
) expression
;
444 final PsiExpression operand
= prefixExpression
.getOperand();
445 return expressionAssignsVariableOrFails(operand
, variable
,
446 checkedMethods
, strict
);
447 } else if(expression
instanceof PsiPostfixExpression
){
448 final PsiPostfixExpression postfixExpression
=
449 (PsiPostfixExpression
) expression
;
450 final PsiExpression operand
= postfixExpression
.getOperand();
451 return expressionAssignsVariableOrFails(operand
, variable
,
452 checkedMethods
, strict
);
453 } else if(expression
instanceof PsiBinaryExpression
){
454 final PsiBinaryExpression binaryExpression
=
455 (PsiBinaryExpression
) expression
;
456 final PsiExpression lhs
= binaryExpression
.getLOperand();
457 final PsiExpression rhs
= binaryExpression
.getROperand();
458 return expressionAssignsVariableOrFails(lhs
, variable
,
459 checkedMethods
, strict
) ||
460 expressionAssignsVariableOrFails(rhs
, variable
,
461 checkedMethods
, strict
);
462 } else if(expression
instanceof PsiConditionalExpression
){
463 final PsiConditionalExpression conditional
=
464 (PsiConditionalExpression
) expression
;
465 final PsiExpression condition
= conditional
.getCondition();
466 if(expressionAssignsVariableOrFails(condition
, variable
,
467 checkedMethods
, strict
)){
470 final PsiExpression thenExpression
=
471 conditional
.getThenExpression();
472 final PsiExpression elseExpression
=
473 conditional
.getElseExpression();
474 return expressionAssignsVariableOrFails(thenExpression
, variable
,
475 checkedMethods
, strict
) &&
476 expressionAssignsVariableOrFails(elseExpression
, variable
,
477 checkedMethods
, strict
);
478 } else if(expression
instanceof PsiAssignmentExpression
){
479 final PsiAssignmentExpression assignment
=
480 (PsiAssignmentExpression
) expression
;
481 final PsiExpression lhs
= assignment
.getLExpression();
482 if(expressionAssignsVariableOrFails(lhs
, variable
, checkedMethods
,
486 final PsiExpression rhs
= assignment
.getRExpression();
487 if(expressionAssignsVariableOrFails(rhs
, variable
, checkedMethods
,
491 if(lhs
instanceof PsiReferenceExpression
){
492 final PsiElement element
= ((PsiReference
) lhs
).resolve();
493 if(element
!= null && element
.equals(variable
)){
503 private static boolean newExpressionAssignsVariableOrFails(
504 @NotNull PsiNewExpression newExpression
, PsiVariable variable
,
505 @NotNull Set
<MethodSignature
> checkedMethods
, boolean strict
){
506 final PsiExpressionList argumentList
= newExpression
.getArgumentList();
507 if(argumentList
!= null){
508 final PsiExpression
[] args
= argumentList
.getExpressions();
509 for(final PsiExpression arg
: args
){
510 if(expressionAssignsVariableOrFails(arg
, variable
,
511 checkedMethods
, strict
)){
516 final PsiArrayInitializerExpression arrayInitializer
=
517 newExpression
.getArrayInitializer();
518 if(expressionAssignsVariableOrFails(arrayInitializer
, variable
,
519 checkedMethods
, strict
)){
522 final PsiExpression
[] arrayDimensions
=
523 newExpression
.getArrayDimensions();
524 for(final PsiExpression dim
: arrayDimensions
){
525 if(expressionAssignsVariableOrFails(dim
, variable
,
526 checkedMethods
, strict
)){
533 private static boolean methodCallAssignsVariableOrFails(
534 @NotNull PsiMethodCallExpression callExpression
,
535 PsiVariable variable
,
536 @NotNull Set
<MethodSignature
> checkedMethods
, boolean strict
){
537 final PsiExpressionList argList
= callExpression
.getArgumentList();
538 final PsiExpression
[] args
= argList
.getExpressions();
539 for(final PsiExpression arg
: args
){
540 if(expressionAssignsVariableOrFails(arg
, variable
, checkedMethods
,
545 final PsiReferenceExpression methodExpression
=
546 callExpression
.getMethodExpression();
547 if(expressionAssignsVariableOrFails(methodExpression
, variable
,
548 checkedMethods
, strict
)){
551 final PsiMethod method
= callExpression
.resolveMethod();
555 final MethodSignature methodSignature
=
556 method
.getSignature(PsiSubstitutor
.EMPTY
);
557 if(!checkedMethods
.add(methodSignature
)){
560 final PsiClass containingClass
=
561 ClassUtils
.getContainingClass(callExpression
);
562 final PsiClass calledClass
= method
.getContainingClass();
563 if(calledClass
== null || !calledClass
.equals(containingClass
)){
566 if(method
.hasModifierProperty(PsiModifier
.STATIC
)
567 || method
.isConstructor()
568 || method
.hasModifierProperty(PsiModifier
.PRIVATE
)
569 || method
.hasModifierProperty(PsiModifier
.FINAL
)
570 || calledClass
.hasModifierProperty(PsiModifier
.FINAL
)){
571 final PsiCodeBlock body
= method
.getBody();
572 return blockAssignsVariableOrFails(body
, variable
,
573 checkedMethods
, strict
);