private static boolean isFixApplicable(PsiExpression location) { // conservative check to see if the result value of the postfix // expression is used later in the same expression statement. // Applying the quick fix in such a case would break the code // because the explicit unboxing code would split the expression in // multiple statements. final PsiElement parent = location.getParent(); if (!(parent instanceof PsiPostfixExpression)) { return true; } final PsiReferenceExpression reference; if (location instanceof PsiReferenceExpression) { reference = (PsiReferenceExpression) location; } else if (location instanceof PsiArrayAccessExpression) { final PsiArrayAccessExpression arrayAccessExpression = (PsiArrayAccessExpression) location; final PsiExpression expression = arrayAccessExpression.getArrayExpression(); if (!(expression instanceof PsiReferenceExpression)) { return true; } reference = (PsiReferenceExpression) expression; } else { return true; } final PsiElement element = reference.resolve(); if (element == null) { return true; } final PsiStatement statement = PsiTreeUtil.getParentOfType(parent, PsiStatement.class); final LocalSearchScope scope = new LocalSearchScope(statement); final Query<PsiReference> query = ReferencesSearch.search(element, scope); final Collection<PsiReference> references = query.findAll(); return references.size() <= 1; }
private boolean isArrayLookup(PsiElement element, String indexName, PsiVariable arrayVariable) { if (element == null) { return false; } if (!(element instanceof PsiArrayAccessExpression)) { return false; } final PsiArrayAccessExpression arrayAccess = (PsiArrayAccessExpression) element; final PsiExpression indexExpression = arrayAccess.getIndexExpression(); if (indexExpression == null) { return false; } if (!indexName.equals(indexExpression.getText())) { return false; } final PsiExpression arrayExpression = arrayAccess.getArrayExpression(); if (!(arrayExpression instanceof PsiReferenceExpression)) { return false; } final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) arrayExpression; final PsiExpression qualifier = referenceExpression.getQualifierExpression(); if (qualifier != null && !(qualifier instanceof PsiThisExpression) && !(qualifier instanceof PsiSuperExpression)) { return false; } final PsiElement target = referenceExpression.resolve(); return arrayVariable.equals(target); }
public static @NotNull PsiType indexSet(PsiArrayAccessExpression paa, PsiExpression value) { if (paa == null) return NoType; for (String method : OOMethods.indexSet) { PsiType res = resolveMethod(paa.getArrayExpression(), method, paa.getIndexExpression(), value); if (res != null) return res; } return NoType; }
private static boolean arrayAccessExpressionsAreEquivalent( @NotNull PsiArrayAccessExpression arrayAccessExpression1, @NotNull PsiArrayAccessExpression arrayAccessExpression2) { final PsiExpression arrayExpression2 = arrayAccessExpression1.getArrayExpression(); final PsiExpression arrayExpression1 = arrayAccessExpression2.getArrayExpression(); final PsiExpression indexExpression2 = arrayAccessExpression1.getIndexExpression(); final PsiExpression indexExpression1 = arrayAccessExpression2.getIndexExpression(); return expressionsAreEquivalent(arrayExpression2, arrayExpression1) && expressionsAreEquivalent(indexExpression2, indexExpression1); }
private static void removeParensFromArrayAccessExpression( @NotNull PsiArrayAccessExpression arrayAccessExpression, boolean ignoreClarifyingParentheses) { final PsiExpression arrayExpression = arrayAccessExpression.getArrayExpression(); removeParentheses(arrayExpression, ignoreClarifyingParentheses); final PsiExpression indexExpression = arrayAccessExpression.getIndexExpression(); if (indexExpression != null) { removeParentheses(indexExpression, ignoreClarifyingParentheses); } }
@Override public void visitForStatement(@NotNull PsiForStatement statement) { super.visitForStatement(statement); final PsiStatement initialization = statement.getInitialization(); if (!(initialization instanceof PsiDeclarationStatement)) { return; } final PsiDeclarationStatement declaration = (PsiDeclarationStatement) initialization; final PsiElement[] declaredElements = declaration.getDeclaredElements(); if (declaredElements.length != 1) { return; } final PsiElement declaredElement = declaredElements[0]; if (!(declaredElement instanceof PsiLocalVariable)) { return; } final PsiLocalVariable variable = (PsiLocalVariable) declaredElement; final PsiExpression initialValue = variable.getInitializer(); if (initialValue == null) { return; } final PsiExpression condition = statement.getCondition(); if (!ExpressionUtils.isVariableLessThanComparison(condition, variable)) { return; } final PsiStatement update = statement.getUpdate(); if (!VariableAccessUtils.variableIsIncremented(variable, update)) { return; } final PsiArrayAccessExpression arrayAccessExpression = getArrayAccessExpression(statement); if (arrayAccessExpression == null) { return; } final PsiExpression arrayExpression = arrayAccessExpression.getArrayExpression(); final PsiType type = arrayExpression.getType(); if (!(type instanceof PsiArrayType) || type.getDeepComponentType() instanceof PsiPrimitiveType) { return; } final PsiStatement body = statement.getBody(); if (!bodyIsArrayToCollectionCopy(body, variable, true)) { return; } registerStatementError(statement); }
public static boolean areParenthesesNeeded( PsiParenthesizedExpression expression, boolean ignoreClarifyingParentheses) { final PsiElement parent = expression.getParent(); if (!(parent instanceof PsiExpression)) { return false; } final PsiExpression child = expression.getExpression(); if (child == null) { return true; } if (parent instanceof PsiArrayAccessExpression) { final PsiArrayAccessExpression arrayAccessExpression = (PsiArrayAccessExpression) parent; final PsiExpression indexExpression = arrayAccessExpression.getIndexExpression(); if (expression == indexExpression) { return false; } } return areParenthesesNeeded(child, (PsiExpression) parent, ignoreClarifyingParentheses); }
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; }
@Nullable private static String getCollectionsAddAllText(PsiForStatement forStatement) throws IncorrectOperationException { final PsiExpression expression = forStatement.getCondition(); final PsiBinaryExpression condition = (PsiBinaryExpression) ParenthesesUtils.stripParentheses(expression); if (condition == null) { return null; } final PsiStatement initialization = forStatement.getInitialization(); if (initialization == null) { return null; } if (!(initialization instanceof PsiDeclarationStatement)) { return null; } final PsiDeclarationStatement declaration = (PsiDeclarationStatement) initialization; final PsiElement[] declaredElements = declaration.getDeclaredElements(); if (declaredElements.length != 1) { return null; } final PsiElement declaredElement = declaredElements[0]; if (!(declaredElement instanceof PsiLocalVariable)) { return null; } final PsiLocalVariable variable = (PsiLocalVariable) declaredElement; final String collectionText = buildCollectionText(forStatement); final PsiArrayAccessExpression arrayAccessExpression = getArrayAccessExpression(forStatement); if (arrayAccessExpression == null) { return null; } final PsiExpression arrayExpression = arrayAccessExpression.getArrayExpression(); final String arrayText = arrayExpression.getText(); final PsiExpression indexExpression = arrayAccessExpression.getIndexExpression(); final String fromOffsetText = buildFromOffsetText(indexExpression, variable); if (fromOffsetText == null) { return null; } final PsiExpression limit; final IElementType tokenType = condition.getOperationTokenType(); if (tokenType == JavaTokenType.LT || tokenType == JavaTokenType.LE) { limit = condition.getROperand(); } else { limit = condition.getLOperand(); } @NonNls final String toOffsetText = buildToOffsetText(limit, tokenType == JavaTokenType.LE || tokenType == JavaTokenType.GE); if (toOffsetText == null) { return null; } if (fromOffsetText.equals("0") && toOffsetText.equals(arrayText + ".length") && PsiUtil.isLanguageLevel5OrHigher(forStatement)) { return "java.util.Collections.addAll(" + collectionText + ',' + arrayText + ");"; } else { @NonNls final StringBuilder buffer = new StringBuilder(); buffer.append(collectionText); buffer.append('.'); buffer.append("addAll(java.util.Arrays.asList("); buffer.append(arrayText); buffer.append(')'); if (!fromOffsetText.equals("0") || !toOffsetText.equals(arrayText + ".length")) { buffer.append(".subList("); buffer.append(fromOffsetText); buffer.append(", "); buffer.append(toOffsetText); buffer.append(')'); } buffer.append(");"); return buffer.toString(); } }
@Override public void visitReferenceExpression(PsiReferenceExpression expression) { if (myWritten && myRead) { return; } super.visitReferenceExpression(expression); final PsiElement target = expression.resolve(); if (target != myVariable) { return; } if (PsiUtil.isAccessedForWriting(expression)) { final PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class); if (parent instanceof PsiAssignmentExpression) { final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression) parent; final PsiExpression rhs = assignmentExpression.getRExpression(); if (isComplexArrayExpression(rhs)) { myWritten = true; myRead = true; } else if (!isSimpleArrayExpression(rhs)) { myWritten = true; } } return; } myIsReferenced = true; PsiElement parent = getParent(expression); if (parent instanceof PsiArrayAccessExpression) { PsiArrayAccessExpression arrayAccessExpression = (PsiArrayAccessExpression) parent; parent = getParent(parent); while (parent instanceof PsiArrayAccessExpression) { arrayAccessExpression = (PsiArrayAccessExpression) parent; parent = getParent(parent); } final PsiType type = arrayAccessExpression.getType(); if (type != null) { final int dimensions = type.getArrayDimensions(); if (dimensions > 0 && dimensions != myVariable.getType().getArrayDimensions()) { myWritten = true; } } if (PsiUtil.isAccessedForWriting(arrayAccessExpression)) { myWritten = true; } if (PsiUtil.isAccessedForReading(arrayAccessExpression)) { myRead = true; } } else if (parent instanceof PsiReferenceExpression) { final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) parent; final String name = referenceExpression.getReferenceName(); if ("length".equals(name) || ("clone".equals(name) && referenceExpression.getParent() instanceof PsiMethodCallExpression)) { myRead = true; } } else if (parent instanceof PsiForeachStatement) { final PsiForeachStatement foreachStatement = (PsiForeachStatement) parent; final PsiExpression iteratedValue = foreachStatement.getIteratedValue(); if (PsiTreeUtil.isAncestor(iteratedValue, expression, false)) { myRead = true; } } else if (parent instanceof PsiExpressionList) { final PsiExpressionList expressionList = (PsiExpressionList) parent; parent = parent.getParent(); if (parent instanceof PsiMethodCallExpression) { final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) parent; final PsiMethod method = methodCallExpression.resolveMethod(); if (method != null) { final PsiClass aClass = method.getContainingClass(); if (aClass != null) { final String methodName = method.getName(); final String qualifiedName = aClass.getQualifiedName(); if ("java.lang.System".equals(qualifiedName)) { if ("arraycopy".equals(methodName)) { final PsiExpression[] expressions = expressionList.getExpressions(); if (expressions.length == 5) { if (PsiTreeUtil.isAncestor(expressions[0], expression, false)) { myRead = true; return; } else if (PsiTreeUtil.isAncestor(expressions[2], expression, false)) { myWritten = true; return; } } } } else if (CommonClassNames.JAVA_UTIL_ARRAYS.equals(qualifiedName)) { if ("fill".equals(methodName) || "parallelPrefix".equals(methodName) || "parallelSetAll".equals(methodName) || "parallelSort".equals(methodName) || "setAll".equals(methodName) || "sort".equals(methodName)) { myWritten = true; } else { myRead = true; } return; } } } } myRead = true; myWritten = true; } else { myWritten = true; myRead = true; } }
public static @NotNull PsiType indexGet(PsiArrayAccessExpression e) { if (e == null || e.getIndexExpression() == null) return NoType; PsiType res = resolveMethod(e.getArrayExpression(), OOMethods.indexGet, e.getIndexExpression()); return res != null ? res : NoType; }
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); } } }