IDEADEV-40452
[fedora-idea.git] / plugins / InspectionGadgets / src / com / siyeh / ig / psiutils / InitializationUtils.java
blob4523804496e8d6f65c712abc986d612e601c56a9
1 /*
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;
24 import java.util.Set;
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,
38 boolean strict) {
39 if (method == null) {
40 return false;
42 final PsiCodeBlock body = method.getBody();
43 return body != null && blockAssignsVariableOrFails(body, variable,
44 strict);
47 public static boolean classInitializerAssignsVariableOrFails(
48 @Nullable PsiClassInitializer initializer,
49 @NotNull PsiVariable variable, boolean strict) {
50 if (initializer == null) {
51 return false;
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,
64 boolean strict) {
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){
72 if(block == null){
73 return false;
75 final PsiStatement[] statements = block.getStatements();
76 int assignmentCount = 0;
77 for(final PsiStatement statement : statements){
78 if(statementAssignsVariableOrFails(statement, variable,
79 checkedMethods, strict)){
80 if (strict) {
81 assignmentCount++;
82 } else {
83 return true;
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){
94 return false;
96 if(ExceptionUtils.statementThrowsException(statement)){
97 return true;
99 if(statement instanceof PsiBreakStatement ||
100 statement instanceof PsiContinueStatement ||
101 statement instanceof PsiAssertStatement ||
102 statement instanceof PsiEmptyStatement){
103 return false;
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)){
124 return true;
127 return false;
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,
143 variable,
144 checkedMethods, strict);
145 } else if(statement instanceof PsiForeachStatement){
146 final PsiForeachStatement foreachStatement =
147 (PsiForeachStatement)statement;
148 return foreachStatementAssignsVariableOrFails(variable,
149 foreachStatement);
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);
192 } else {
193 // unknown statement type
194 return false;
198 public static boolean switchStatementAssignsVariableOrFails(
199 @NotNull PsiSwitchStatement switchStatement,
200 @NotNull PsiVariable variable,
201 boolean strict) {
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)) {
213 return true;
215 final PsiCodeBlock body = switchStatement.getBody();
216 if (body == null) {
217 return false;
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) {
228 return false;
230 if (labelStatement.isDefaultCase()) {
231 containsDefault = true;
233 assigns = false;
234 } else if (statement instanceof PsiBreakStatement) {
235 final PsiBreakStatement breakStatement
236 = (PsiBreakStatement) statement;
237 if (breakStatement.getLabelIdentifier() != null) {
238 return false;
240 if (!assigns) {
241 return false;
243 assigns = false;
244 } else {
245 assigns |= statementAssignsVariableOrFails(statement, variable,
246 checkedMethods, strict);
247 if (i == statements.length - 1 && !assigns) {
248 return false;
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)){
267 return true;
271 return false;
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){
283 if (strict) {
284 initializedInTryAndCatch &=
285 ExceptionUtils.blockThrowsException(catchBlock);
286 } else {
287 initializedInTryAndCatch &= blockAssignsVariableOrFails(
288 catchBlock, variable,
289 checkedMethods, strict);
292 if(initializedInTryAndCatch){
293 return true;
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,
304 boolean strict){
305 final PsiExpression condition = ifStatement.getCondition();
306 if(expressionAssignsVariableOrFails(condition, variable,
307 checkedMethods, strict)){
308 return true;
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,
329 boolean strict){
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,
335 strict);
338 private static boolean whileStatementAssignsVariableOrFails(
339 @NotNull PsiWhileStatement whileStatement, PsiVariable variable,
340 @NotNull Set<MethodSignature> checkedMethods,
341 boolean strict){
342 final PsiExpression condition = whileStatement.getCondition();
343 if(expressionAssignsVariableOrFails(condition, variable,
344 checkedMethods, strict)){
345 return true;
347 if(BoolUtils.isTrue(condition)){
348 final PsiStatement body = whileStatement.getBody();
349 if(statementAssignsVariableOrFails(body, variable, checkedMethods,
350 strict)){
351 return true;
354 return false;
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)){
363 return true;
365 final PsiExpression test = forStatement.getCondition();
366 if(expressionAssignsVariableOrFails(test, variable, checkedMethods,
367 strict)){
368 return true;
370 if(BoolUtils.isTrue(test)){
371 final PsiStatement body = forStatement.getBody();
372 if(statementAssignsVariableOrFails(body, variable, checkedMethods,
373 strict)){
374 return true;
376 final PsiStatement update = forStatement.getUpdate();
377 if(statementAssignsVariableOrFails(update, variable,
378 checkedMethods, strict)){
379 return true;
382 return false;
385 private static boolean foreachStatementAssignsVariableOrFails(
386 PsiVariable field, PsiForeachStatement forStatement){
387 return false;
390 private static boolean expressionAssignsVariableOrFails(
391 @Nullable PsiExpression expression,
392 PsiVariable variable,
393 @NotNull Set<MethodSignature> checkedMethods, boolean strict){
394 if(expression == null){
395 return false;
397 if(expression instanceof PsiThisExpression ||
398 expression instanceof PsiLiteralExpression ||
399 expression instanceof PsiSuperExpression ||
400 expression instanceof PsiClassObjectAccessExpression){
401 return false;
402 } else if(expression instanceof PsiReferenceExpression){
403 return false;
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)){
420 return true;
423 return false;
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)){
468 return true;
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,
483 strict)){
484 return true;
486 final PsiExpression rhs = assignment.getRExpression();
487 if(expressionAssignsVariableOrFails(rhs, variable, checkedMethods,
488 strict)){
489 return true;
491 if(lhs instanceof PsiReferenceExpression){
492 final PsiElement element = ((PsiReference) lhs).resolve();
493 if(element != null && element.equals(variable)){
494 return true;
497 return false;
498 } else{
499 return false;
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)){
512 return true;
516 final PsiArrayInitializerExpression arrayInitializer =
517 newExpression.getArrayInitializer();
518 if(expressionAssignsVariableOrFails(arrayInitializer, variable,
519 checkedMethods, strict)){
520 return true;
522 final PsiExpression[] arrayDimensions =
523 newExpression.getArrayDimensions();
524 for(final PsiExpression dim : arrayDimensions){
525 if(expressionAssignsVariableOrFails(dim, variable,
526 checkedMethods, strict)){
527 return true;
530 return false;
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,
541 strict)){
542 return true;
545 final PsiReferenceExpression methodExpression =
546 callExpression.getMethodExpression();
547 if(expressionAssignsVariableOrFails(methodExpression, variable,
548 checkedMethods, strict)){
549 return true;
551 final PsiMethod method = callExpression.resolveMethod();
552 if(method == null){
553 return false;
555 final MethodSignature methodSignature =
556 method.getSignature(PsiSubstitutor.EMPTY);
557 if(!checkedMethods.add(methodSignature)){
558 return false;
560 final PsiClass containingClass =
561 ClassUtils.getContainingClass(callExpression);
562 final PsiClass calledClass = method.getContainingClass();
563 if(calledClass == null || !calledClass.equals(containingClass)){
564 return false;
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);
575 return false;