private static boolean polyadicExpressionsAreEquivalent( @NotNull PsiPolyadicExpression polyadicExpression1, @NotNull PsiPolyadicExpression polyadicExpression2) { final IElementType tokenType1 = polyadicExpression1.getOperationTokenType(); final IElementType tokenType2 = polyadicExpression2.getOperationTokenType(); if (!tokenType1.equals(tokenType2)) { return false; } final PsiExpression[] operands1 = polyadicExpression1.getOperands(); final PsiExpression[] operands2 = polyadicExpression2.getOperands(); if (operands1.length != operands2.length) { return false; } for (int i = 0, length = operands1.length; i < length; i++) { if (!expressionsAreEquivalent(operands1[i], operands2[i])) { return false; } } return true; }
@Override public void visitPolyadicExpression(PsiPolyadicExpression expression) { super.visitPolyadicExpression(expression); if (!ExpressionUtils.hasStringType(expression)) { return; } final PsiExpression[] operands = expression.getOperands(); for (PsiExpression operand : operands) { checkExpression(operand); } }
@Nullable private String evaluate(PsiExpression expression, Map<String, Computable<String>> arguments) { if (expression instanceof PsiPolyadicExpression) { PsiPolyadicExpression binaryExpression = (PsiPolyadicExpression) expression; if (binaryExpression.getOperationTokenType() == JavaTokenType.PLUS) { String r = ""; for (PsiExpression op : binaryExpression.getOperands()) { String lhs = evaluate(op, arguments); if (lhs == null) return null; r += lhs; } return r; } } else if (expression instanceof PsiLiteralExpression) { final Object value = ((PsiLiteralExpression) expression).getValue(); if (value instanceof String) { return (String) value; } } else if (expression instanceof PsiReferenceExpression) { final PsiElement result = ((PsiReferenceExpression) expression).resolve(); if (result instanceof PsiParameter) { final String name = ((PsiParameter) result).getName(); final Computable<String> arg = arguments.get(name); return arg == null ? null : arg.compute(); } if (result instanceof PsiVariable) { final PsiExpression initializer = ((PsiVariable) result).getInitializer(); if (initializer != null) { return evaluate(initializer, arguments); } } } else if (expression instanceof PsiMethodCallExpression) { final PsiMethodCallExpression methodCall = (PsiMethodCallExpression) expression; final String callText = methodCall.getMethodExpression().getText(); if (callText.equals("getTestName")) { final PsiExpression[] psiExpressions = methodCall.getArgumentList().getExpressions(); if (psiExpressions.length == 1) { if ("true".equals(psiExpressions[0].getText()) && !StringUtil.isEmpty(myTestName)) { return UsefulTestCase.lowercaseFirstLetter(myTestName, true); } return myTestName; } } } if (expression != null) { myLogMessages.add("Failed to evaluate " + expression.getText()); } return null; }
private static boolean isPartOfLargerExpression(PsiPolyadicExpression expression) { if (expression.getOperands().length > 2) { return true; } final PsiElement containingElement = expression.getParent(); if (containingElement instanceof PsiExpression) { final PsiExpression containingExpression = (PsiExpression) containingElement; if (!PsiUtil.isConstantExpression(containingExpression)) { return false; } } else { return false; } return true; }
@NotNull public List<String> createConversions( @NotNull PsiPolyadicExpression expression, PsiType expectedType) { PsiExpression[] arguments = expression.getOperands(); int length = arguments.length; List<String> conversions = new LinkedList<String>(); List<PsiType> expectedTypes = Collections.nCopies(length, expectedType); List<PsiType> actualTypes = new LinkedList<PsiType>(); for (PsiExpression e : arguments) actualTypes.add(e.getType()); assert actualTypes.size() == expectedTypes.size() : "The type list must have the same length"; for (int i = 0; i < actualTypes.size(); i++) conversions.add(i, createConversionForExpression(arguments[i], expectedTypes.get(i))); return conversions; }
@Nullable static PsiPolyadicExpression getSubexpression( PsiPolyadicExpression expression, PsiJavaToken token) { final PsiExpression[] operands = expression.getOperands(); if (operands.length == 2) { return expression; } for (int i = 1; i < operands.length; i++) { final PsiExpression operand = operands[i]; final PsiJavaToken currentToken = expression.getTokenBeforeOperand(operand); if (currentToken == token) { final String binaryExpressionText = operands[i - 1].getText() + ' ' + token.getText() + ' ' + operand.getText(); final PsiElementFactory factory = JavaPsiFacade.getElementFactory(expression.getProject()); return (PsiPolyadicExpression) factory.createExpressionFromText(binaryExpressionText, expression); } } return null; }
@Override public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { final PsiPolyadicExpression expression = SplitConditionUtil.findCondition(element, true, false); if (expression == null || expression.getOperands().length < 2) return false; PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent()); if (!(parent instanceof PsiLambdaExpression)) return false; if (((PsiLambdaExpression) parent).getParameterList().getParametersCount() != 1) return false; parent = parent.getParent(); if (!(parent instanceof PsiExpressionList)) return false; final PsiElement gParent = parent.getParent(); if (!(gParent instanceof PsiMethodCallExpression)) return false; if (MergeFilterChainAction.isFilterCall((PsiMethodCallExpression) gParent)) { return true; } return false; }
@Nullable private static PsiReferenceExpression getReferenceFromInstanceofExpression( PsiExpression expression) { if (expression instanceof PsiParenthesizedExpression) { final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression) expression; return getReferenceFromInstanceofExpression(parenthesizedExpression.getExpression()); } else if (expression instanceof PsiInstanceOfExpression) { final PsiInstanceOfExpression instanceOfExpression = (PsiInstanceOfExpression) expression; final PsiExpression operand = ParenthesesUtils.stripParentheses(instanceOfExpression.getOperand()); if (!(operand instanceof PsiReferenceExpression)) { return null; } return (PsiReferenceExpression) operand; } else if (expression instanceof PsiPolyadicExpression) { final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression) expression; final IElementType tokenType = polyadicExpression.getOperationTokenType(); if (JavaTokenType.OROR != tokenType) { return null; } final PsiExpression[] operands = polyadicExpression.getOperands(); final PsiReferenceExpression referenceExpression = getReferenceFromInstanceofExpression(operands[0]); if (referenceExpression == null) { return null; } for (int i = 1, operandsLength = operands.length; i < operandsLength; i++) { if (!referencesEqual( referenceExpression, getReferenceFromInstanceofExpression(operands[i]))) { return null; } } return referenceExpression; } else { return null; } }
private boolean checkCondition( @Nullable PsiExpression condition, @NotNull PsiStatement context, List<PsiExpression> notUpdated) { if (condition == null) { return false; } if (PsiUtil.isConstantExpression(condition) || PsiKeyword.NULL.equals(condition.getText())) { return true; } if (condition instanceof PsiInstanceOfExpression) { final PsiInstanceOfExpression instanceOfExpression = (PsiInstanceOfExpression) condition; final PsiExpression operand = instanceOfExpression.getOperand(); return checkCondition(operand, context, notUpdated); } else if (condition instanceof PsiParenthesizedExpression) { // catch stuff like "while ((x)) { ... }" final PsiExpression expression = ((PsiParenthesizedExpression) condition).getExpression(); return checkCondition(expression, context, notUpdated); } else if (condition instanceof PsiPolyadicExpression) { // while (value != x) { ... } // while (value != (x + y)) { ... } // while (b1 && b2) { ... } final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression) condition; for (PsiExpression operand : polyadicExpression.getOperands()) { if (!checkCondition(operand, context, notUpdated)) { return false; } } return true; } else if (condition instanceof PsiReferenceExpression) { final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) condition; final PsiElement element = referenceExpression.resolve(); if (element instanceof PsiField) { final PsiField field = (PsiField) element; final PsiType type = field.getType(); if (field.hasModifierProperty(PsiModifier.FINAL) && type.getArrayDimensions() == 0) { if (field.hasModifierProperty(PsiModifier.STATIC)) { return true; } final PsiExpression qualifier = referenceExpression.getQualifierExpression(); if (qualifier == null) { return true; } else if (checkCondition(qualifier, context, notUpdated)) { return true; } } } else if (element instanceof PsiVariable) { final PsiVariable variable = (PsiVariable) element; if (variable.hasModifierProperty(PsiModifier.FINAL)) { // final variables cannot be updated, don't bother to // flag them return true; } else if (element instanceof PsiLocalVariable || element instanceof PsiParameter) { if (!VariableAccessUtils.variableIsAssigned(variable, context)) { notUpdated.add(referenceExpression); return true; } } } } else if (condition instanceof PsiPrefixExpression) { final PsiPrefixExpression prefixExpression = (PsiPrefixExpression) condition; final IElementType tokenType = prefixExpression.getOperationTokenType(); if (JavaTokenType.EXCL.equals(tokenType) || JavaTokenType.PLUS.equals(tokenType) || JavaTokenType.MINUS.equals(tokenType)) { final PsiExpression operand = prefixExpression.getOperand(); return checkCondition(operand, context, notUpdated); } } else if (condition instanceof PsiArrayAccessExpression) { // Actually the contents of the array could change nevertheless // if it is accessed through a different reference like this: // int[] local_ints = new int[]{1, 2}; // int[] other_ints = local_ints; // while (local_ints[0] > 0) { other_ints[0]--; } // // Keep this check? final PsiArrayAccessExpression accessExpression = (PsiArrayAccessExpression) condition; final PsiExpression indexExpression = accessExpression.getIndexExpression(); return checkCondition(indexExpression, context, notUpdated) && checkCondition(accessExpression.getArrayExpression(), context, notUpdated); } else if (condition instanceof PsiConditionalExpression) { final PsiConditionalExpression conditionalExpression = (PsiConditionalExpression) condition; final PsiExpression thenExpression = conditionalExpression.getThenExpression(); final PsiExpression elseExpression = conditionalExpression.getElseExpression(); if (thenExpression == null || elseExpression == null) { return false; } return checkCondition(conditionalExpression.getCondition(), context, notUpdated) && checkCondition(thenExpression, context, notUpdated) && checkCondition(elseExpression, context, notUpdated); } else if (condition instanceof PsiThisExpression) { return true; } else if (condition instanceof PsiMethodCallExpression && !ignoreIterators) { final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) condition; if (!IteratorUtils.isCallToHasNext(methodCallExpression)) { return false; } final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); if (qualifierExpression instanceof PsiReferenceExpression) { final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) qualifierExpression; final PsiElement element = referenceExpression.resolve(); if (!(element instanceof PsiVariable)) { return false; } final PsiVariable variable = (PsiVariable) element; if (!IteratorUtils.containsCallToScannerNext(context, variable, true)) { notUpdated.add(qualifierExpression); return true; } } else { if (!IteratorUtils.containsCallToScannerNext(context, null, true)) { notUpdated.add(methodCallExpression); return true; } } } return false; }
public static boolean areParenthesesNeeded( PsiExpression expression, PsiExpression parentExpression, boolean ignoreClarifyingParentheses) { if (parentExpression instanceof PsiParenthesizedExpression || parentExpression instanceof PsiArrayInitializerExpression) { return false; } final int parentPrecedence = getPrecedence(parentExpression); final int childPrecedence = getPrecedence(expression); if (parentPrecedence > childPrecedence) { if (ignoreClarifyingParentheses) { if (expression instanceof PsiPolyadicExpression) { if (parentExpression instanceof PsiPolyadicExpression || parentExpression instanceof PsiConditionalExpression || parentExpression instanceof PsiInstanceOfExpression) { return true; } } else if (expression instanceof PsiInstanceOfExpression) { return true; } } return false; } if (parentExpression instanceof PsiPolyadicExpression && expression instanceof PsiPolyadicExpression) { final PsiPolyadicExpression parentPolyadicExpression = (PsiPolyadicExpression) parentExpression; final PsiType parentType = parentPolyadicExpression.getType(); if (parentType == null) { return true; } final PsiPolyadicExpression childPolyadicExpression = (PsiPolyadicExpression) expression; final PsiType childType = childPolyadicExpression.getType(); if (!parentType.equals(childType)) { return true; } if (childType.equalsToText(CommonClassNames.JAVA_LANG_STRING) && !PsiTreeUtil.isAncestor( parentPolyadicExpression.getOperands()[0], childPolyadicExpression, true)) { final PsiExpression[] operands = childPolyadicExpression.getOperands(); for (PsiExpression operand : operands) { if (!childType.equals(operand.getType())) { return true; } } } else if (childType.equals(PsiType.BOOLEAN)) { final PsiExpression[] operands = childPolyadicExpression.getOperands(); for (PsiExpression operand : operands) { if (!PsiType.BOOLEAN.equals(operand.getType())) { return true; } } } final IElementType parentOperator = parentPolyadicExpression.getOperationTokenType(); final IElementType childOperator = childPolyadicExpression.getOperationTokenType(); if (ignoreClarifyingParentheses) { if (!childOperator.equals(parentOperator)) { return true; } } final PsiExpression[] parentOperands = parentPolyadicExpression.getOperands(); if (!PsiTreeUtil.isAncestor(parentOperands[0], expression, false)) { if (!isAssociativeOperation(parentPolyadicExpression) || JavaTokenType.DIV == childOperator || JavaTokenType.PERC == childOperator) { return true; } } } else if (parentExpression instanceof PsiConditionalExpression && expression instanceof PsiConditionalExpression) { final PsiConditionalExpression conditionalExpression = (PsiConditionalExpression) parentExpression; final PsiExpression condition = conditionalExpression.getCondition(); return PsiTreeUtil.isAncestor(condition, expression, true); } return parentPrecedence < childPrecedence; }
private static void removeParensFromPolyadicExpression( @NotNull PsiPolyadicExpression polyadicExpression, boolean ignoreClarifyingParentheses) { for (PsiExpression operand : polyadicExpression.getOperands()) { removeParentheses(operand, ignoreClarifyingParentheses); } }
private static void removeParensFromParenthesizedExpression( @NotNull PsiParenthesizedExpression parenthesizedExpression, boolean ignoreClarifyingParentheses) { final PsiExpression body = parenthesizedExpression.getExpression(); if (body == null) { parenthesizedExpression.delete(); return; } final PsiElement parent = parenthesizedExpression.getParent(); if (!(parent instanceof PsiExpression) || parent instanceof PsiParenthesizedExpression || parent instanceof PsiArrayInitializerExpression) { final PsiExpression newExpression = (PsiExpression) parenthesizedExpression.replace(body); removeParentheses(newExpression, ignoreClarifyingParentheses); return; } else if (parent instanceof PsiArrayAccessExpression) { final PsiArrayAccessExpression arrayAccessExpression = (PsiArrayAccessExpression) parent; if (parenthesizedExpression == arrayAccessExpression.getIndexExpression()) { // use addAfter() + delete() instead of replace() to // workaround automatic insertion of parentheses by psi final PsiExpression newExpression = (PsiExpression) parent.addAfter(body, parenthesizedExpression); parenthesizedExpression.delete(); removeParentheses(newExpression, ignoreClarifyingParentheses); return; } } final PsiExpression parentExpression = (PsiExpression) parent; final int parentPrecedence = getPrecedence(parentExpression); final int childPrecedence = getPrecedence(body); if (parentPrecedence < childPrecedence) { final PsiElement bodyParent = body.getParent(); final PsiParenthesizedExpression newParenthesizedExpression = (PsiParenthesizedExpression) parenthesizedExpression.replace(bodyParent); final PsiExpression expression = newParenthesizedExpression.getExpression(); if (expression != null) { removeParentheses(expression, ignoreClarifyingParentheses); } } else if (parentPrecedence == childPrecedence) { if (parentExpression instanceof PsiPolyadicExpression && body instanceof PsiPolyadicExpression) { final PsiPolyadicExpression parentPolyadicExpression = (PsiPolyadicExpression) parentExpression; final IElementType parentOperator = parentPolyadicExpression.getOperationTokenType(); final PsiPolyadicExpression bodyPolyadicExpression = (PsiPolyadicExpression) body; final IElementType bodyOperator = bodyPolyadicExpression.getOperationTokenType(); final PsiType parentType = parentPolyadicExpression.getType(); final PsiType bodyType = body.getType(); if (parentType != null && parentType.equals(bodyType) && parentOperator.equals(bodyOperator)) { final PsiExpression[] parentOperands = parentPolyadicExpression.getOperands(); if (PsiTreeUtil.isAncestor(parentOperands[0], body, true) || isCommutativeOperator(bodyOperator)) { // use addAfter() + delete() instead of replace() to // workaround automatic insertion of parentheses by psi final PsiExpression newExpression = (PsiExpression) parent.addAfter(body, parenthesizedExpression); parenthesizedExpression.delete(); removeParentheses(newExpression, ignoreClarifyingParentheses); return; } } if (ignoreClarifyingParentheses) { if (parentOperator.equals(bodyOperator)) { removeParentheses(body, ignoreClarifyingParentheses); } } else { final PsiExpression newExpression = (PsiExpression) parenthesizedExpression.replace(body); removeParentheses(newExpression, ignoreClarifyingParentheses); } } else { final PsiExpression newExpression = (PsiExpression) parenthesizedExpression.replace(body); removeParentheses(newExpression, ignoreClarifyingParentheses); } } else { if (ignoreClarifyingParentheses && parent instanceof PsiPolyadicExpression && (body instanceof PsiPolyadicExpression || body instanceof PsiInstanceOfExpression)) { removeParentheses(body, ignoreClarifyingParentheses); } else { final PsiExpression newExpression = (PsiExpression) parenthesizedExpression.replace(body); removeParentheses(newExpression, ignoreClarifyingParentheses); } } }