private static boolean textOfExpressionsIsEquivalent( GrExpression expToCompare1, GrExpression expToCompare2) { final String text1 = expToCompare1.getText(); final String text2 = expToCompare2.getText(); return text1.equals(text2); }
@Nullable public static GrExpression replaceExpression( GrExpression oldExpr, GrExpression newExpr, boolean removeUnnecessaryParentheses) { PsiElement oldParent = oldExpr.getParent(); if (oldParent == null) throw new PsiInvalidElementAccessException(oldExpr); if (!(oldExpr instanceof GrApplicationStatement)) { newExpr = ApplicationStatementUtil.convertToMethodCallExpression(newExpr); } // Remove unnecessary parentheses if (removeUnnecessaryParentheses && oldParent instanceof GrParenthesizedExpression && !(oldParent.getParent() instanceof GrArgumentLabel)) { return ((GrExpression) oldParent) .replaceWithExpression(newExpr, removeUnnecessaryParentheses); } // regexes cannot be after identifier , try to replace it with simple string if (getRegexAtTheBeginning(newExpr) != null && isAfterIdentifier(oldExpr)) { final PsiElement copy = newExpr.copy(); final GrLiteral regex = getRegexAtTheBeginning(copy); LOG.assertTrue(regex != null); final GrLiteral stringLiteral = GrStringUtil.createStringFromRegex(regex); if (regex == copy) { return oldExpr.replaceWithExpression(stringLiteral, removeUnnecessaryParentheses); } else { regex.replace(stringLiteral); return oldExpr.replaceWithExpression((GrExpression) copy, removeUnnecessaryParentheses); } } GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(oldExpr.getProject()); if (oldParent instanceof GrStringInjection) { if (newExpr instanceof GrString || newExpr instanceof GrLiteral && ((GrLiteral) newExpr).getValue() instanceof String) { return GrStringUtil.replaceStringInjectionByLiteral( (GrStringInjection) oldParent, (GrLiteral) newExpr); } else { newExpr = factory.createExpressionFromText("{" + newExpr.getText() + "}"); oldParent.getNode().replaceChild(oldExpr.getNode(), newExpr.getNode()); return newExpr; } } if (PsiTreeUtil.getParentOfType(oldExpr, GrStringInjection.class, false, GrCodeBlock.class) != null) { final PsiElement replaced = oldExpr.replace(newExpr); final GrStringInjection stringInjection = PsiTreeUtil.getParentOfType(replaced, GrStringInjection.class); GrStringUtil.wrapInjection(stringInjection); assert stringInjection != null; return stringInjection.getClosableBlock(); } // check priorities if (oldParent instanceof GrExpression && !(oldParent instanceof GrParenthesizedExpression)) { GrExpression addedParenth = addParenthesesIfNeeded(newExpr, oldExpr, (GrExpression) oldParent); if (newExpr != addedParenth) { return oldExpr.replaceWithExpression(addedParenth, removeUnnecessaryParentheses); } } // if replace closure argument with expression // we should add the expression in arg list if (oldExpr instanceof GrClosableBlock && !(newExpr instanceof GrClosableBlock) && oldParent instanceof GrMethodCallExpression && ArrayUtil.contains( oldExpr, ((GrMethodCallExpression) oldParent).getClosureArguments())) { return ((GrMethodCallExpression) oldParent) .replaceClosureArgument((GrClosableBlock) oldExpr, newExpr); } newExpr = (GrExpression) oldExpr.replace(newExpr); // if newExpr is the first grand child of command argument list we should replace command arg // list with parenthesised arg list. // In other case the code will be broken. So we try to find wrapping command arg list counting // levels. After arg list replace we go inside it // to find target parenthesised expression. if (newExpr instanceof GrParenthesizedExpression && isFirstChild(newExpr)) { int parentCount = 0; PsiElement element = oldParent; while (element != null && !(element instanceof GrCommandArgumentList)) { if (element instanceof GrCodeBlock || element instanceof GrParenthesizedExpression) break; if (element instanceof PsiFile) break; final PsiElement parent = element.getParent(); if (parent == null) break; if (!isFirstChild(element)) break; element = parent; parentCount++; } if (element instanceof GrCommandArgumentList) { final GrCommandArgumentList commandArgList = (GrCommandArgumentList) element; final PsiElement parent = commandArgList.getParent(); LOG.assertTrue(parent instanceof GrApplicationStatement); final GrMethodCall methodCall = factory.createMethodCallByAppCall((GrApplicationStatement) parent); final GrMethodCall newCall = (GrMethodCall) parent.replace(methodCall); PsiElement result = newCall.getArgumentList().getAllArguments()[0]; for (int i = 0; i < parentCount; i++) { result = PsiUtil.skipWhitespacesAndComments(result.getFirstChild(), true); } LOG.assertTrue(result instanceof GrParenthesizedExpression); return (GrExpression) result; } } return newExpr; }
@SuppressWarnings({"ConstantConditions"}) public static boolean expressionsAreEquivalent( @Nullable GrExpression exp1, @Nullable GrExpression exp2) { if (exp1 == null && exp2 == null) { return true; } if (exp1 == null || exp2 == null) { return false; } GrExpression expToCompare1 = (GrExpression) PsiUtil.skipParentheses(exp1, false); GrExpression expToCompare2 = (GrExpression) PsiUtil.skipParentheses(exp2, false); final int type1 = getExpressionType(expToCompare1); final int type2 = getExpressionType(expToCompare2); if (type1 != type2) { return false; } switch (type1) { case THIS_EXPRESSION: case SUPER_EXPRESSION: return true; case LITERAL_EXPRESSION: case REFERENCE_EXPRESSION: final String text1 = expToCompare1.getText(); final String text2 = expToCompare2.getText(); return text1.equals(text2); case CALL_EXPRESSION: return methodCallExpressionsAreEquivalent( (GrMethodCall) expToCompare1, (GrMethodCall) expToCompare2); case NEW_EXPRESSION: return newExpressionsAreEquivalent( (GrNewExpression) expToCompare1, (GrNewExpression) expToCompare2); case ARRAY_LITERAL_EXPRESSION: return arrayDeclarationsAreEquivalent( (GrArrayDeclaration) expToCompare1, (GrArrayDeclaration) expToCompare2); case PREFIX_EXPRESSION: return prefixExpressionsAreEquivalent( (GrUnaryExpression) expToCompare1, (GrUnaryExpression) expToCompare2); case POSTFIX_EXPRESSION: return postfixExpressionsAreEquivalent( (GrUnaryExpression) expToCompare1, (GrUnaryExpression) expToCompare2); case BINARY_EXPRESSION: return binaryExpressionsAreEquivalent( (GrBinaryExpression) expToCompare1, (GrBinaryExpression) expToCompare2); case ASSIGNMENT_EXPRESSION: return assignmentExpressionsAreEquivalent( (GrAssignmentExpression) expToCompare1, (GrAssignmentExpression) expToCompare2); case CONDITIONAL_EXPRESSION: return conditionalExpressionsAreEquivalent( (GrConditionalExpression) expToCompare1, (GrConditionalExpression) expToCompare2); case ELVIS_EXPRESSION: return elvisExpressionsAreEquivalent( (GrElvisExpression) expToCompare1, (GrElvisExpression) expToCompare2); case RANGE_EXPRESSION: return rangeExpressionsAreEquivalent( (GrRangeExpression) expToCompare1, (GrRangeExpression) expToCompare2); case TYPE_CAST_EXPRESSION: return typecastExpressionsAreEquivalent( (GrTypeCastExpression) expToCompare1, (GrTypeCastExpression) expToCompare2); case SAFE_CAST_EXPRESSION: return safecastExpressionsAreEquivalent( (GrSafeCastExpression) expToCompare1, (GrSafeCastExpression) expToCompare2); case INSTANCEOF_EXPRESSION: return instanceofExpressionsAreEquivalent( (GrInstanceOfExpression) expToCompare1, (GrInstanceOfExpression) expToCompare2); case INDEX_EXPRESSION: return indexExpressionsAreEquivalent( (GrIndexProperty) expToCompare1, (GrIndexProperty) expToCompare2); case LIST_OR_MAP_EXPRESSION: return listOrMapExpressionsAreEquivalent( (GrListOrMap) expToCompare1, (GrListOrMap) expToCompare2); case CLOSABLE_BLOCK_EXPRESSION: return closableBlockExpressionsAreEquivalent( (GrClosableBlock) expToCompare1, (GrClosableBlock) expToCompare2); case PROPERTY_SELECTION_EXPRESSION: return textOfExpressionsIsEquivalent(expToCompare1, expToCompare2); // todo default: return false; } }