IDEADEV-31824 (Incorrect "manual array copy" warning)
[fedora-idea.git] / plugins / InspectionGadgets / src / com / siyeh / ig / psiutils / EquivalenceChecker.java
blob11224d550dac2115b2d5e43eba9a17e0f7cf5a8d
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 com.intellij.psi.util.PsiTreeUtil;
21 import org.jetbrains.annotations.NotNull;
22 import org.jetbrains.annotations.Nullable;
24 import java.util.ArrayList;
25 import java.util.List;
27 public class EquivalenceChecker{
29 private EquivalenceChecker(){
30 super();
33 public static boolean modifierListsAreEquivalent(
34 @Nullable PsiModifierList list1, @Nullable PsiModifierList list2) {
35 if (list1 == null) {
36 return list2 == null;
37 } else if (list2 == null) {
38 return false;
40 final PsiAnnotation[] annotations = list1.getAnnotations();
41 for (PsiAnnotation annotation : annotations) {
42 final String qualifiedName = annotation.getQualifiedName();
43 if (qualifiedName == null) {
44 return false;
46 if (list2.findAnnotation(qualifiedName) == null) {
47 return false;
50 if (list1.hasModifierProperty(PsiModifier.ABSTRACT) &&
51 !list2.hasModifierProperty(PsiModifier.ABSTRACT)) {
52 return false;
54 if (list1.hasModifierProperty(PsiModifier.FINAL) &&
55 !list2.hasModifierProperty(PsiModifier.FINAL)) {
56 return false;
58 if (list1.hasModifierProperty(PsiModifier.NATIVE) &&
59 !list2.hasModifierProperty(PsiModifier.NATIVE)) {
60 return false;
62 if (list1.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) &&
63 !list2.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
64 return false;
66 if (list1.hasModifierProperty(PsiModifier.PRIVATE) &&
67 !list2.hasModifierProperty(PsiModifier.PRIVATE)) {
68 return false;
70 if (list1.hasModifierProperty(PsiModifier.PROTECTED) &&
71 !list2.hasModifierProperty(PsiModifier.PROTECTED)) {
72 return false;
74 if (list1.hasModifierProperty(PsiModifier.PUBLIC) &&
75 !list2.hasModifierProperty(PsiModifier.PUBLIC)) {
76 return false;
78 if (list1.hasModifierProperty(PsiModifier.STATIC) &&
79 !list2.hasModifierProperty(PsiModifier.STATIC)) {
80 return false;
82 if (list1.hasModifierProperty(PsiModifier.STRICTFP) &&
83 !list2.hasModifierProperty(PsiModifier.STRICTFP)) {
84 return false;
86 if (list1.hasModifierProperty(PsiModifier.SYNCHRONIZED) &&
87 !list2.hasModifierProperty(PsiModifier.SYNCHRONIZED)) {
88 return false;
90 if (list1.hasModifierProperty(PsiModifier.TRANSIENT) &&
91 !list2.hasModifierProperty(PsiModifier.TRANSIENT)) {
92 return false;
94 return !(list1.hasModifierProperty(PsiModifier.VOLATILE) &&
95 !list2.hasModifierProperty(PsiModifier.VOLATILE));
98 public static boolean statementsAreEquivalent(
99 @Nullable PsiStatement statement1,
100 @Nullable PsiStatement statement2) {
101 if(statement1 == null && statement2 == null){
102 return true;
104 if(statement1 == null || statement2 == null){
105 return false;
107 if(statement1.getClass() != statement2.getClass()){
108 return false;
110 if(statement1 instanceof PsiAssertStatement){
111 final PsiAssertStatement assertStatement1 =
112 (PsiAssertStatement)statement1;
113 final PsiAssertStatement assertStatement2 =
114 (PsiAssertStatement)statement2;
115 return assertStatementsAreEquivalent(assertStatement1,
116 assertStatement2);
118 if(statement1 instanceof PsiBlockStatement){
119 final PsiBlockStatement blockStatement1 =
120 (PsiBlockStatement)statement1;
121 final PsiBlockStatement blockStatement2 =
122 (PsiBlockStatement)statement2;
123 return blockStatementsAreEquivalent(blockStatement1,
124 blockStatement2);
126 if(statement1 instanceof PsiBreakStatement){
127 final PsiBreakStatement breakStatement1 =
128 (PsiBreakStatement)statement1;
129 final PsiBreakStatement breakStatement2 =
130 (PsiBreakStatement)statement2;
131 return breakStatementsAreEquivalent(breakStatement1,
132 breakStatement2);
134 if(statement1 instanceof PsiContinueStatement){
135 final PsiContinueStatement continueStatement1 =
136 (PsiContinueStatement)statement1;
137 final PsiContinueStatement continueStatement2 =
138 (PsiContinueStatement)statement2;
139 return continueStatementsAreEquivalent(continueStatement1,
140 continueStatement2);
142 if(statement1 instanceof PsiDeclarationStatement){
143 final PsiDeclarationStatement declarationStatement1 =
144 (PsiDeclarationStatement)statement1;
145 final PsiDeclarationStatement declarationStatement2 =
146 (PsiDeclarationStatement)statement2;
147 return declarationStatementsAreEquivalent(declarationStatement1,
148 declarationStatement2);
150 if(statement1 instanceof PsiDoWhileStatement){
151 final PsiDoWhileStatement doWhileStatement1 =
152 (PsiDoWhileStatement)statement1;
153 final PsiDoWhileStatement doWhileStatement2 =
154 (PsiDoWhileStatement)statement2;
155 return doWhileStatementsAreEquivalent(
156 doWhileStatement1, doWhileStatement2);
158 if(statement1 instanceof PsiEmptyStatement){
159 return true;
161 if(statement1 instanceof PsiExpressionListStatement){
162 final PsiExpressionListStatement expressionListStatement1 =
163 (PsiExpressionListStatement)statement1;
164 final PsiExpressionListStatement expressionListStatement2 =
165 (PsiExpressionListStatement)statement2;
166 return expressionListStatementsAreEquivalent(
167 expressionListStatement1,
168 expressionListStatement2);
170 if(statement1 instanceof PsiExpressionStatement){
171 final PsiExpressionStatement expressionStatement1 =
172 (PsiExpressionStatement)statement1;
173 final PsiExpressionStatement expressionStatement2 =
174 (PsiExpressionStatement)statement2;
175 return expressionStatementsAreEquivalent(
176 expressionStatement1,
177 expressionStatement2);
179 if(statement1 instanceof PsiForStatement){
180 final PsiForStatement forStatement1 =
181 (PsiForStatement)statement1;
182 final PsiForStatement forStatement2 =
183 (PsiForStatement)statement2;
184 return forStatementsAreEquivalent(forStatement1, forStatement2);
186 if(statement1 instanceof PsiForeachStatement){
187 final PsiForeachStatement forEachStatement1 =
188 (PsiForeachStatement)statement1;
189 final PsiForeachStatement forEachStatement2 =
190 (PsiForeachStatement)statement2;
191 return forEachStatementsAreEquivalent(forEachStatement1,
192 forEachStatement2);
194 if(statement1 instanceof PsiIfStatement){
195 return ifStatementsAreEquivalent(
196 (PsiIfStatement) statement1,
197 (PsiIfStatement) statement2);
199 if(statement1 instanceof PsiLabeledStatement){
200 final PsiLabeledStatement labeledStatement1 =
201 (PsiLabeledStatement)statement1;
202 final PsiLabeledStatement labeledStatement2 =
203 (PsiLabeledStatement)statement2;
204 return labeledStatementsAreEquivalent(labeledStatement1,
205 labeledStatement2);
207 if(statement1 instanceof PsiReturnStatement){
208 final PsiReturnStatement returnStatement1 =
209 (PsiReturnStatement)statement1;
210 final PsiReturnStatement returnStatement2 =
211 (PsiReturnStatement)statement2;
212 return returnStatementsAreEquivalent(returnStatement1,
213 returnStatement2);
215 if(statement1 instanceof PsiSwitchStatement){
216 final PsiSwitchStatement switchStatement1 =
217 (PsiSwitchStatement)statement1;
218 final PsiSwitchStatement switchStatement2 =
219 (PsiSwitchStatement)statement2;
220 return switchStatementsAreEquivalent(switchStatement1,
221 switchStatement2);
223 if(statement1 instanceof PsiSwitchLabelStatement){
224 final PsiSwitchLabelStatement switchLabelStatement1 =
225 (PsiSwitchLabelStatement)statement1;
226 final PsiSwitchLabelStatement switchLabelStatement2 =
227 (PsiSwitchLabelStatement)statement2;
228 return switchLabelStatementsAreEquivalent(switchLabelStatement1,
229 switchLabelStatement2);
231 if(statement1 instanceof PsiSynchronizedStatement){
232 final PsiSynchronizedStatement synchronizedStatement1 =
233 (PsiSynchronizedStatement)statement1;
234 final PsiSynchronizedStatement synchronizedStatement2 =
235 (PsiSynchronizedStatement)statement2;
236 return synchronizedStatementsAreEquivalent(
237 synchronizedStatement1, synchronizedStatement2);
239 if(statement1 instanceof PsiThrowStatement){
240 final PsiThrowStatement throwStatement1 =
241 (PsiThrowStatement)statement1;
242 final PsiThrowStatement throwStatement2 =
243 (PsiThrowStatement)statement2;
244 return throwStatementsAreEquivalent(throwStatement1,
245 throwStatement2);
247 if(statement1 instanceof PsiTryStatement){
248 final PsiTryStatement tryStatement1 =
249 (PsiTryStatement)statement1;
250 final PsiTryStatement tryStatement2 =
251 (PsiTryStatement)statement2;
252 return tryStatementsAreEquivalent(tryStatement1,
253 tryStatement2);
255 if(statement1 instanceof PsiWhileStatement){
256 final PsiWhileStatement whileStatement1 =
257 (PsiWhileStatement)statement1;
258 final PsiWhileStatement whileStatement2 =
259 (PsiWhileStatement)statement2;
260 return whileStatementsAreEquivalent(whileStatement1,
261 whileStatement2);
263 final String text1 = statement1.getText();
264 final String text2 = statement2.getText();
265 return text1.equals(text2);
268 private static boolean declarationStatementsAreEquivalent(
269 @NotNull PsiDeclarationStatement statement1,
270 @NotNull PsiDeclarationStatement statement2){
271 final PsiElement[] elements1 = statement1.getDeclaredElements();
272 final List<PsiLocalVariable> vars1 =
273 new ArrayList<PsiLocalVariable>(elements1.length);
274 for(PsiElement anElement : elements1){
275 if(anElement instanceof PsiLocalVariable){
276 vars1.add((PsiLocalVariable) anElement);
279 final PsiElement[] elements2 = statement2.getDeclaredElements();
280 final List<PsiLocalVariable> vars2 =
281 new ArrayList<PsiLocalVariable>(elements2.length);
282 for(PsiElement anElement : elements2){
283 if(anElement instanceof PsiLocalVariable){
284 vars2.add((PsiLocalVariable) anElement);
287 final int size = vars1.size();
288 if(size != vars2.size()){
289 return false;
291 for(int i = 0; i < size; i++){
292 final PsiLocalVariable var1 = vars1.get(i);
293 final PsiLocalVariable var2 = vars2.get(i);
294 if(!localVariableAreEquivalent(var1, var2)){
295 return false;
298 return true;
301 private static boolean localVariableAreEquivalent(
302 @NotNull PsiLocalVariable var1, @NotNull PsiLocalVariable var2) {
303 final PsiType type1 = var1.getType();
304 final PsiType type2 = var2.getType();
305 if(!typesAreEquivalent(type1, type2)){
306 return false;
308 final String name1 = var1.getName();
309 final String name2 = var2.getName();
310 if(name1 == null){
311 if (name2 != null) {
312 return false;
314 } else if (name2 == null) {
315 return false;
316 } else if (!name1.equals(name2)) {
317 return false;
319 final PsiExpression initializer1 = var1.getInitializer();
320 final PsiExpression initializer2 = var2.getInitializer();
321 return expressionsAreEquivalent(initializer1, initializer2);
324 private static boolean tryStatementsAreEquivalent(
325 @NotNull PsiTryStatement statement1,
326 @NotNull PsiTryStatement statement2) {
327 final PsiCodeBlock tryBlock1 = statement1.getTryBlock();
328 final PsiCodeBlock tryBlock2 = statement2.getTryBlock();
329 if(!codeBlocksAreEquivalent(tryBlock1, tryBlock2)){
330 return false;
332 final PsiCodeBlock finallyBlock1 = statement1.getFinallyBlock();
333 final PsiCodeBlock finallyBlock2 = statement2.getFinallyBlock();
334 if(!codeBlocksAreEquivalent(finallyBlock1, finallyBlock2)){
335 return false;
337 final PsiCodeBlock[] catchBlocks1 = statement1.getCatchBlocks();
338 final PsiCodeBlock[] catchBlocks2 = statement2.getCatchBlocks();
339 if(catchBlocks1.length != catchBlocks2.length){
340 return false;
342 for(int i = 0; i < catchBlocks2.length; i++){
343 if(!codeBlocksAreEquivalent(catchBlocks1[i], catchBlocks2[i])){
344 return false;
347 final PsiParameter[] catchParameters1 =
348 statement1.getCatchBlockParameters();
349 final PsiParameter[] catchParameters2 =
350 statement2.getCatchBlockParameters();
351 if(catchParameters1.length != catchParameters2.length){
352 return false;
354 for(int i = 0; i < catchParameters2.length; i++){
355 if(!parametersAreEquivalent(catchParameters2[i],
356 catchParameters1[i])){
357 return false;
360 return true;
363 private static boolean parametersAreEquivalent(
364 @NotNull PsiParameter parameter1,
365 @NotNull PsiParameter parameter2) {
366 final PsiType type1 = parameter1.getType();
367 final PsiType type2 = parameter2.getType();
368 if(!typesAreEquivalent(type1, type2)){
369 return false;
371 final String name1 = parameter1.getName();
372 final String name2 = parameter2.getName();
373 if(name1 == null){
374 return name2 == null;
376 return name1.equals(name2);
379 public static boolean typesAreEquivalent(
380 @Nullable PsiType type1, @Nullable PsiType type2){
381 if(type1 == null){
382 return type2 == null;
384 if(type2 == null){
385 return false;
387 final String type1Text = type1.getCanonicalText();
388 final String type2Text = type2.getCanonicalText();
389 return type1Text.equals(type2Text);
392 private static boolean whileStatementsAreEquivalent(
393 @NotNull PsiWhileStatement statement1,
394 @NotNull PsiWhileStatement statement2){
395 final PsiExpression condition1 = statement1.getCondition();
396 final PsiExpression condition2 = statement2.getCondition();
397 final PsiStatement body1 = statement1.getBody();
398 final PsiStatement body2 = statement2.getBody();
399 return expressionsAreEquivalent(condition1, condition2) &&
400 statementsAreEquivalent(body1, body2);
403 private static boolean forStatementsAreEquivalent(
404 @NotNull PsiForStatement statement1,
405 @NotNull PsiForStatement statement2) {
406 final PsiExpression condition1 = statement1.getCondition();
407 final PsiExpression condition2 = statement2.getCondition();
408 if(!expressionsAreEquivalent(condition1, condition2)){
409 return false;
411 final PsiStatement initialization1 = statement1.getInitialization();
412 final PsiStatement initialization2 = statement2.getInitialization();
413 if(!statementsAreEquivalent(initialization1, initialization2)){
414 return false;
416 final PsiStatement update1 = statement1.getUpdate();
417 final PsiStatement update2 = statement2.getUpdate();
418 if(!statementsAreEquivalent(update1, update2)){
419 return false;
421 final PsiStatement body1 = statement1.getBody();
422 final PsiStatement body2 = statement2.getBody();
423 return statementsAreEquivalent(body1, body2);
426 private static boolean forEachStatementsAreEquivalent(
427 @NotNull PsiForeachStatement statement1,
428 @NotNull PsiForeachStatement statement2) {
429 final PsiExpression value1 = statement1.getIteratedValue();
430 final PsiExpression value2 = statement2.getIteratedValue();
431 if(!expressionsAreEquivalent(value1, value2)){
432 return false;
434 final PsiParameter parameter1 = statement1.getIterationParameter();
435 final PsiParameter parameter2 = statement1.getIterationParameter();
436 final String name1 = parameter1.getName();
437 final String name2 = parameter2.getName();
438 if(name1 == null) {
439 if(name2 != null){
440 return false;
442 } else if (name2 == null) {
443 return false;
444 } else if (!name1.equals(name2)){
445 return false;
447 final PsiType type1 = parameter1.getType();
448 if(!type1.equals(parameter2.getType())){
449 return false;
451 final PsiStatement body1 = statement1.getBody();
452 final PsiStatement body2 = statement2.getBody();
453 return statementsAreEquivalent(body1, body2);
456 private static boolean switchStatementsAreEquivalent(
457 @NotNull PsiSwitchStatement statement1,
458 @NotNull PsiSwitchStatement statement2) {
459 final PsiExpression switchExpression1 = statement1.getExpression();
460 final PsiExpression swithcExpression2 = statement2.getExpression();
461 final PsiCodeBlock body1 = statement1.getBody();
462 final PsiCodeBlock body2 = statement2.getBody();
463 return expressionsAreEquivalent(switchExpression1, swithcExpression2) &&
464 codeBlocksAreEquivalent(body1, body2);
467 private static boolean doWhileStatementsAreEquivalent(
468 @NotNull PsiDoWhileStatement statement1,
469 @NotNull PsiDoWhileStatement statement2) {
470 final PsiExpression condition1 = statement1.getCondition();
471 final PsiExpression condition2 = statement2.getCondition();
472 final PsiStatement body1 = statement1.getBody();
473 final PsiStatement body2 = statement2.getBody();
474 return expressionsAreEquivalent(condition1, condition2) &&
475 statementsAreEquivalent(body1, body2);
478 private static boolean assertStatementsAreEquivalent(
479 @NotNull PsiAssertStatement statement1,
480 @NotNull PsiAssertStatement statement2) {
481 final PsiExpression condition1 = statement1.getAssertCondition();
482 final PsiExpression condition2 = statement2.getAssertCondition();
483 final PsiExpression description1 = statement1.getAssertDescription();
484 final PsiExpression description2 = statement2.getAssertDescription();
485 return expressionsAreEquivalent(condition1, condition2) &&
486 expressionsAreEquivalent(description1, description2);
489 private static boolean synchronizedStatementsAreEquivalent(
490 @NotNull PsiSynchronizedStatement statement1,
491 @NotNull PsiSynchronizedStatement statement2) {
492 final PsiExpression lock1 = statement1.getLockExpression();
493 final PsiExpression lock2 = statement2.getLockExpression();
494 final PsiCodeBlock body1 = statement1.getBody();
495 final PsiCodeBlock body2 = statement2.getBody();
496 return expressionsAreEquivalent(lock1, lock2) &&
497 codeBlocksAreEquivalent(body1, body2);
500 private static boolean blockStatementsAreEquivalent(
501 @NotNull PsiBlockStatement statement1,
502 @NotNull PsiBlockStatement statement2){
503 final PsiCodeBlock block1 = statement1.getCodeBlock();
504 final PsiCodeBlock block2 = statement2.getCodeBlock();
505 return codeBlocksAreEquivalent(block1, block2);
508 private static boolean breakStatementsAreEquivalent(
509 @NotNull PsiBreakStatement statement1,
510 @NotNull PsiBreakStatement statement2) {
511 final PsiIdentifier identifier1 = statement1.getLabelIdentifier();
512 final PsiIdentifier identifier2 = statement2.getLabelIdentifier();
513 if(identifier1 == null){
514 return identifier2 == null;
516 if(identifier2 == null){
517 return false;
519 final String text1 = identifier1.getText();
520 final String text2 = identifier2.getText();
521 return text1.equals(text2);
524 private static boolean continueStatementsAreEquivalent(
525 @NotNull PsiContinueStatement statement1,
526 @NotNull PsiContinueStatement statement2) {
527 final PsiIdentifier identifier1 = statement1.getLabelIdentifier();
528 final PsiIdentifier identifier2 = statement2.getLabelIdentifier();
529 if(identifier1 == null){
530 return identifier2 == null;
532 if(identifier2 == null){
533 return false;
535 final String text1 = identifier1.getText();
536 final String text2 = identifier2.getText();
537 return text1.equals(text2);
540 private static boolean switchLabelStatementsAreEquivalent(
541 @NotNull PsiSwitchLabelStatement statement1,
542 @NotNull PsiSwitchLabelStatement statement2) {
543 if (statement1.isDefaultCase()){
544 return statement2.isDefaultCase();
546 if(statement2.isDefaultCase()){
547 return false;
549 final PsiExpression caseExpression1 = statement1.getCaseValue();
550 final PsiExpression caseExpression2 = statement2.getCaseValue();
551 return expressionsAreEquivalent(caseExpression1, caseExpression2);
554 private static boolean labeledStatementsAreEquivalent(
555 @NotNull PsiLabeledStatement statement1,
556 @NotNull PsiLabeledStatement statement2) {
557 final PsiIdentifier identifier1 = statement1.getLabelIdentifier();
558 final PsiIdentifier identifier2 = statement2.getLabelIdentifier();
559 final String text1 = identifier1.getText();
560 final String text2 = identifier2.getText();
561 return text1.equals(text2);
564 public static boolean codeBlocksAreEquivalent(
565 @Nullable PsiCodeBlock block1, @Nullable PsiCodeBlock block2) {
566 if (block1 == null && block2 == null){
567 return true;
569 if(block1 == null || block2 == null){
570 return false;
572 final PsiStatement[] statements1 = block1.getStatements();
573 final PsiStatement[] statements2 = block2.getStatements();
574 if(statements2.length != statements1.length){
575 return false;
577 for(int i = 0; i < statements2.length; i++){
578 if(!statementsAreEquivalent(statements2[i], statements1[i])){
579 return false;
582 return true;
585 private static boolean ifStatementsAreEquivalent(
586 @NotNull PsiIfStatement statement1,
587 @NotNull PsiIfStatement statement2) {
588 final PsiExpression condition1 = statement1.getCondition();
589 final PsiExpression condition2 = statement2.getCondition();
590 final PsiStatement thenBranch1 = statement1.getThenBranch();
591 final PsiStatement thenBranch2 = statement2.getThenBranch();
592 final PsiStatement elseBranch1 = statement1.getElseBranch();
593 final PsiStatement elseBranch2 = statement2.getElseBranch();
594 return expressionsAreEquivalent(condition1, condition2) &&
595 statementsAreEquivalent(thenBranch1, thenBranch2) &&
596 statementsAreEquivalent(elseBranch1, elseBranch2);
599 private static boolean expressionStatementsAreEquivalent(
600 @NotNull PsiExpressionStatement statement1,
601 @NotNull PsiExpressionStatement statement2) {
602 final PsiExpression expression1 = statement1.getExpression();
603 final PsiExpression expression2 = statement2.getExpression();
604 return expressionsAreEquivalent(expression1, expression2);
607 private static boolean returnStatementsAreEquivalent(
608 @NotNull PsiReturnStatement statement1,
609 @NotNull PsiReturnStatement statement2) {
610 final PsiExpression returnValue1 = statement1.getReturnValue();
611 final PsiExpression returnValue2 = statement2.getReturnValue();
612 return expressionsAreEquivalent(returnValue1, returnValue2);
615 private static boolean throwStatementsAreEquivalent(
616 @NotNull PsiThrowStatement statement1,
617 @NotNull PsiThrowStatement statement2) {
618 final PsiExpression exception1 = statement1.getException();
619 final PsiExpression exception2 = statement2.getException();
620 return expressionsAreEquivalent(exception1, exception2);
623 private static boolean expressionListStatementsAreEquivalent(
624 @NotNull PsiExpressionListStatement statement1,
625 @NotNull PsiExpressionListStatement statement2) {
626 final PsiExpressionList expressionList1 =
627 statement1.getExpressionList();
628 final PsiExpression[] expressions1 = expressionList1.getExpressions();
629 final PsiExpressionList expressionList2 =
630 statement2.getExpressionList();
631 final PsiExpression[] expressions2 = expressionList2.getExpressions();
632 return expressionListsAreEquivalent(expressions1, expressions2);
635 public static boolean expressionsAreEquivalent(
636 @Nullable PsiExpression exp1, @Nullable PsiExpression exp2) {
637 if (exp1 == null && exp2 == null){
638 return true;
640 if(exp1 == null || exp2 == null){
641 return false;
643 PsiExpression expToCompare1 = exp1;
644 while(expToCompare1 instanceof PsiParenthesizedExpression){
645 final PsiParenthesizedExpression parenthesizedExpression =
646 (PsiParenthesizedExpression)expToCompare1;
647 expToCompare1 = parenthesizedExpression.getExpression();
649 PsiExpression expToCompare2 = exp2;
650 while(expToCompare2 instanceof PsiParenthesizedExpression){
651 final PsiParenthesizedExpression parenthesizedExpression =
652 (PsiParenthesizedExpression)expToCompare2;
653 expToCompare2 = parenthesizedExpression.getExpression();
655 if (expToCompare1 == null && expToCompare2 == null){
656 return true;
658 if(expToCompare1 == null || expToCompare2 == null){
659 return false;
661 if (expToCompare1.getClass() != expToCompare2.getClass()) {
662 return false;
664 if (expToCompare1 instanceof PsiThisExpression) {
665 return true;
666 } else if (expToCompare1 instanceof PsiSuperExpression) {
667 return true;
668 } else if (expToCompare1 instanceof PsiLiteralExpression) {
669 final String text1 = expToCompare1.getText();
670 final String text2 = expToCompare2.getText();
671 return text1.equals(text2);
672 } else if (expToCompare1 instanceof PsiClassObjectAccessExpression) {
673 final String text1 = expToCompare1.getText();
674 final String text2 = expToCompare2.getText();
675 return text1.equals(text2);
676 } else if (expToCompare1 instanceof PsiReferenceExpression) {
677 return referenceExpressionsAreEquivalent(
678 (PsiReferenceExpression) expToCompare1,
679 (PsiReferenceExpression) expToCompare2);
680 } else if (expToCompare1 instanceof PsiMethodCallExpression) {
681 return methodCallExpressionsAreEquivalent(
682 (PsiMethodCallExpression) expToCompare1,
683 (PsiMethodCallExpression) expToCompare2);
684 } else if (expToCompare1 instanceof PsiNewExpression) {
685 return newExpressionsAreEquivalent(
686 (PsiNewExpression) expToCompare1,
687 (PsiNewExpression) expToCompare2);
688 } else if (expToCompare1 instanceof PsiArrayInitializerExpression) {
689 return arrayInitializerExpressionsAreEquivalent(
690 (PsiArrayInitializerExpression) expToCompare1,
691 (PsiArrayInitializerExpression) expToCompare2);
692 } else if (expToCompare1 instanceof PsiTypeCastExpression) {
693 return typecastExpressionsAreEquivalent(
694 (PsiTypeCastExpression) expToCompare1,
695 (PsiTypeCastExpression) expToCompare2);
696 } else if (expToCompare1 instanceof PsiArrayAccessExpression) {
697 return arrayAccessExpressionsAreEquivalent(
698 (PsiArrayAccessExpression) expToCompare2,
699 (PsiArrayAccessExpression) expToCompare1);
700 } else if (expToCompare1 instanceof PsiPrefixExpression) {
701 return prefixExpressionsAreEquivalent(
702 (PsiPrefixExpression) expToCompare1,
703 (PsiPrefixExpression) expToCompare2);
704 } else if (expToCompare1 instanceof PsiPostfixExpression) {
705 return postfixExpressionsAreEquivalent(
706 (PsiPostfixExpression) expToCompare1,
707 (PsiPostfixExpression) expToCompare2);
708 } else if (expToCompare1 instanceof PsiBinaryExpression) {
709 return binaryExpressionsAreEquivalent(
710 (PsiBinaryExpression) expToCompare1,
711 (PsiBinaryExpression) expToCompare2);
712 } else if (expToCompare1 instanceof PsiAssignmentExpression) {
713 return assignmentExpressionsAreEquivalent(
714 (PsiAssignmentExpression) expToCompare1,
715 (PsiAssignmentExpression) expToCompare2);
716 } else if (expToCompare1 instanceof PsiConditionalExpression) {
717 return conditionalExpressionsAreEquivalent(
718 (PsiConditionalExpression) expToCompare1,
719 (PsiConditionalExpression) expToCompare2);
720 } else if (expToCompare1 instanceof PsiInstanceOfExpression) {
721 return instanceofExpressionsAreEquivalent(
722 (PsiInstanceOfExpression) expToCompare1,
723 (PsiInstanceOfExpression) expToCompare2);
725 return false;
728 private static boolean referenceExpressionsAreEquivalent(
729 PsiReferenceExpression referenceExpression1,
730 PsiReferenceExpression referenceExpression2) {
731 final PsiElement element1 = referenceExpression1.resolve();
732 final PsiElement element2 = referenceExpression2.resolve();
733 if (element1 != null) {
734 if (!element1.equals(element2)) {
735 return false;
737 } else {
738 return element2 == null;
740 if (element1 instanceof PsiMember ) {
741 final PsiMember member1 = (PsiMember)element1;
742 if (member1.hasModifierProperty(PsiModifier.STATIC)) {
743 return true;
744 } else if (member1 instanceof PsiClass) {
745 return true;
747 } else {
748 return true;
750 final PsiExpression qualifier1 =
751 referenceExpression1.getQualifierExpression();
752 final PsiExpression qualifier2 =
753 referenceExpression2.getQualifierExpression();
754 if (qualifier1 != null &&
755 !(qualifier1 instanceof PsiThisExpression ||
756 qualifier1 instanceof PsiSuperExpression)) {
757 if (qualifier2 == null) {
758 return false;
759 } else if (!expressionsAreEquivalent(qualifier1, qualifier2)) {
760 return false;
762 } else {
763 if (qualifier2 != null &&
764 !(qualifier2 instanceof PsiThisExpression ||
765 qualifier2 instanceof PsiSuperExpression)) {
766 return false;
769 final String text1 = referenceExpression1.getText();
770 final String text2 = referenceExpression2.getText();
771 return text1.equals(text2);
774 private static boolean instanceofExpressionsAreEquivalent(
775 PsiInstanceOfExpression instanceOfExpression1,
776 PsiInstanceOfExpression instanceOfExpression2) {
777 final PsiExpression operand1 = instanceOfExpression1.getOperand();
778 final PsiExpression operand2 = instanceOfExpression2.getOperand();
779 if (!expressionsAreEquivalent(operand1, operand2)) {
780 return false;
782 final PsiTypeElement typeElement1 =
783 instanceOfExpression1.getCheckType();
784 final PsiTypeElement typeElement2 =
785 instanceOfExpression2.getCheckType();
786 if (typeElement1 == null) {
787 return typeElement2 == null;
788 } else if (typeElement2 == null) {
789 return false;
791 final PsiType type1 = typeElement1.getType();
792 final PsiType type2 = typeElement2.getType();
793 return typesAreEquivalent(type1, type2);
796 private static boolean methodCallExpressionsAreEquivalent(
797 @NotNull PsiMethodCallExpression methodExp1,
798 @NotNull PsiMethodCallExpression methodExp2){
799 final PsiReferenceExpression methodExpression1 =
800 methodExp1.getMethodExpression();
801 final PsiReferenceExpression methodExpression2 =
802 methodExp2.getMethodExpression();
803 if(!expressionsAreEquivalent(methodExpression1, methodExpression2)){
804 return false;
806 final PsiExpressionList argumentList1 = methodExp1.getArgumentList();
807 final PsiExpression[] args1 = argumentList1.getExpressions();
808 final PsiExpressionList argumentList2 = methodExp2.getArgumentList();
809 final PsiExpression[] args2 = argumentList2.getExpressions();
810 return expressionListsAreEquivalent(args1, args2);
813 private static boolean newExpressionsAreEquivalent(
814 @NotNull PsiNewExpression newExp1,
815 @NotNull PsiNewExpression newExp2) {
816 final PsiJavaCodeReferenceElement classRef1 =
817 newExp1.getClassReference();
818 final PsiJavaCodeReferenceElement classRef2 =
819 newExp2.getClassReference();
820 if (classRef1 == null || classRef2 == null) {
821 return false;
823 final String text = classRef1.getText();
824 if (!text.equals(classRef2.getText())) {
825 return false;
827 final PsiExpression[] arrayDimensions1 = newExp1.getArrayDimensions();
828 final PsiExpression[] arrayDimensions2 = newExp2.getArrayDimensions();
829 if (!expressionListsAreEquivalent(arrayDimensions1, arrayDimensions2)) {
830 return false;
832 final PsiArrayInitializerExpression arrayInitializer1 =
833 newExp1.getArrayInitializer();
834 final PsiArrayInitializerExpression arrayInitializer2 =
835 newExp2.getArrayInitializer();
836 if (!expressionsAreEquivalent(arrayInitializer1, arrayInitializer2)) {
837 return false;
839 final PsiExpression qualifier1 = newExp1.getQualifier();
840 final PsiExpression qualifier2 = newExp2.getQualifier();
841 if (!expressionsAreEquivalent(qualifier1, qualifier2)) {
842 return false;
844 final PsiExpressionList argumentList1 = newExp1.getArgumentList();
845 final PsiExpression[] args1;
846 if (argumentList1 == null) {
847 args1 = null;
848 } else {
849 args1 = argumentList1.getExpressions();
851 final PsiExpressionList argumentList2 = newExp2.getArgumentList();
852 final PsiExpression[] args2;
853 if (argumentList2 == null) {
854 args2 = null;
855 } else {
856 args2 = argumentList2.getExpressions();
858 return expressionListsAreEquivalent(args1, args2);
861 private static boolean arrayInitializerExpressionsAreEquivalent(
862 @NotNull PsiArrayInitializerExpression arrInitExp1,
863 @NotNull PsiArrayInitializerExpression arrInitExp2){
864 final PsiExpression[] initializers1 = arrInitExp1.getInitializers();
865 final PsiExpression[] initializers2 = arrInitExp2.getInitializers();
866 return expressionListsAreEquivalent(initializers1, initializers2);
869 private static boolean typecastExpressionsAreEquivalent(
870 @NotNull PsiTypeCastExpression typecastExp1,
871 @NotNull PsiTypeCastExpression typecastExp2) {
872 final PsiTypeElement typeElement1 = typecastExp1.getCastType();
873 final PsiTypeElement typeElement2 = typecastExp2.getCastType();
874 if (typeElement1 == null && typeElement2 == null) {
875 return true;
877 if (typeElement1 == null || typeElement2 == null) {
878 return false;
880 final PsiType type1 = typeElement1.getType();
881 final PsiType type2 = typeElement2.getType();
882 if(!typesAreEquivalent(type1, type2)) {
883 return false;
885 final PsiExpression operand1 = typecastExp1.getOperand();
886 final PsiExpression operand2 = typecastExp2.getOperand();
887 return expressionsAreEquivalent(operand1, operand2);
890 private static boolean arrayAccessExpressionsAreEquivalent(
891 @NotNull PsiArrayAccessExpression arrAccessExp2,
892 @NotNull PsiArrayAccessExpression arrAccessExp1){
893 final PsiExpression arrayExpression2 =
894 arrAccessExp2.getArrayExpression();
895 final PsiExpression arrayExpression1 =
896 arrAccessExp1.getArrayExpression();
897 final PsiExpression indexExpression2 =
898 arrAccessExp2.getIndexExpression();
899 final PsiExpression indexExpression1 =
900 arrAccessExp1.getIndexExpression();
901 return expressionsAreEquivalent(arrayExpression2, arrayExpression1)
902 && expressionsAreEquivalent(indexExpression2, indexExpression1);
905 private static boolean prefixExpressionsAreEquivalent(
906 @NotNull PsiPrefixExpression prefixExp1,
907 @NotNull PsiPrefixExpression prefixExp2){
908 final PsiJavaToken sign1 = prefixExp1.getOperationSign();
909 final PsiJavaToken sign2 = prefixExp2.getOperationSign();
910 final IElementType tokenType1 = sign1.getTokenType();
911 if(!tokenType1.equals(sign2.getTokenType())){
912 return false;
914 final PsiExpression operand1 = prefixExp1.getOperand();
915 final PsiExpression operand2 = prefixExp2.getOperand();
916 return expressionsAreEquivalent(operand1, operand2);
919 private static boolean postfixExpressionsAreEquivalent(
920 @NotNull PsiPostfixExpression postfixExp1,
921 @NotNull PsiPostfixExpression postfixExp2){
922 final PsiJavaToken sign1 = postfixExp1.getOperationSign();
923 final PsiJavaToken sign2 = postfixExp2.getOperationSign();
924 final IElementType tokenType1 = sign1.getTokenType();
925 if(!tokenType1.equals(sign2.getTokenType())){
926 return false;
928 final PsiExpression operand1 = postfixExp1.getOperand();
929 final PsiExpression operand2 = postfixExp2.getOperand();
930 return expressionsAreEquivalent(operand1, operand2);
933 private static boolean binaryExpressionsAreEquivalent(
934 @NotNull PsiBinaryExpression binaryExp1,
935 @NotNull PsiBinaryExpression binaryExp2){
936 final PsiJavaToken sign1 = binaryExp1.getOperationSign();
937 final PsiJavaToken sign2 = binaryExp2.getOperationSign();
938 final IElementType tokenType1 = sign1.getTokenType();
939 if(!tokenType1.equals(sign2.getTokenType())){
940 return false;
942 final PsiExpression lhs1 = binaryExp1.getLOperand();
943 final PsiExpression lhs2 = binaryExp2.getLOperand();
944 final PsiExpression rhs1 = binaryExp1.getROperand();
945 final PsiExpression rhs2 = binaryExp2.getROperand();
946 return expressionsAreEquivalent(lhs1, lhs2)
947 && expressionsAreEquivalent(rhs1, rhs2);
950 private static boolean assignmentExpressionsAreEquivalent(
951 @NotNull PsiAssignmentExpression assignExp1,
952 @NotNull PsiAssignmentExpression assignExp2){
953 final PsiJavaToken sign1 = assignExp1.getOperationSign();
954 final PsiJavaToken sign2 = assignExp2.getOperationSign();
955 final IElementType tokenType1 = sign1.getTokenType();
956 if(!tokenType1.equals(sign2.getTokenType())){
957 return false;
959 final PsiExpression lhs1 = assignExp1.getLExpression();
960 final PsiExpression lhs2 = assignExp2.getLExpression();
961 final PsiExpression rhs1 = assignExp1.getRExpression();
962 final PsiExpression rhs2 = assignExp2.getRExpression();
963 return expressionsAreEquivalent(lhs1, lhs2)
964 && expressionsAreEquivalent(rhs1, rhs2);
967 private static boolean conditionalExpressionsAreEquivalent(
968 @NotNull PsiConditionalExpression condExp1,
969 @NotNull PsiConditionalExpression condExp2){
970 final PsiExpression condition1 = condExp1.getCondition();
971 final PsiExpression condition2 = condExp2.getCondition();
972 final PsiExpression thenExpression1 = condExp1.getThenExpression();
973 final PsiExpression thenExpression2 = condExp2.getThenExpression();
974 final PsiExpression elseExpression1 = condExp1.getElseExpression();
975 final PsiExpression elseExpression2 = condExp2.getElseExpression();
976 return expressionsAreEquivalent(condition1, condition2)
977 && expressionsAreEquivalent(thenExpression1, thenExpression2)
978 && expressionsAreEquivalent(elseExpression1, elseExpression2);
981 private static boolean expressionListsAreEquivalent(
982 @Nullable PsiExpression[] expressions1,
983 @Nullable PsiExpression[] expressions2){
984 if(expressions1 == null && expressions2 == null){
985 return true;
987 if(expressions1 == null || expressions2 == null){
988 return false;
990 if(expressions1.length != expressions2.length){
991 return false;
993 for(int i = 0; i < expressions1.length; i++){
994 if(!expressionsAreEquivalent(expressions1[i], expressions2[i])){
995 return false;
998 return true;