protected PsiType processParameterDeclaration(PsiElement parentDeclarationScope) { PsiType result = null; if (parentDeclarationScope instanceof PsiForeachStatement) { final PsiForeachStatement foreachStatement = (PsiForeachStatement) parentDeclarationScope; final PsiExpression iteratedValue = foreachStatement.getIteratedValue(); if (iteratedValue != null) { result = JavaGenericsUtil.getCollectionItemType(iteratedValue); } } return result; }
@NotNull static ElementFilter getReferenceFilter(PsiElement element, boolean allowRecursion) { // throw foo if (psiElement() .withParent(psiElement(PsiReferenceExpression.class).withParent(PsiThrowStatement.class)) .accepts(element)) { return TrueFilter.INSTANCE; } if (psiElement() .inside( StandardPatterns.or( psiElement(PsiAnnotationParameterList.class), psiElement(PsiSwitchLabelStatement.class))) .accepts(element)) { return new ElementExtractorFilter( new AndFilter( new ClassFilter(PsiField.class), new ModifierFilter(PsiKeyword.STATIC, PsiKeyword.FINAL))); } final PsiForeachStatement foreach = PsiTreeUtil.getParentOfType(element, PsiForeachStatement.class); if (foreach != null && !PsiTreeUtil.isAncestor(foreach.getBody(), element, false)) { return new ElementExtractorFilter( new ElementFilter() { @Override public boolean isAcceptable(Object element, @Nullable PsiElement context) { return element != foreach.getIterationParameter(); } @Override public boolean isClassAcceptable(Class hintClass) { return true; } }); } if (!allowRecursion) { final ElementFilter filter = RecursionWeigher.recursionFilter(element); if (filter != null) { return new ElementExtractorFilter(filter); } } return TrueFilter.INSTANCE; }
private static boolean isAddAllCall(PsiForeachStatement statement, PsiStatement body) { final PsiIfStatement ifStatement = extractIfStatement(body); if (ifStatement == null) { final PsiParameter parameter = statement.getIterationParameter(); final PsiMethodCallExpression methodCallExpression = extractAddCall(body, null); LOG.assertTrue(methodCallExpression != null); return isIdentityMapping( parameter, methodCallExpression.getArgumentList().getExpressions()[0]); } return false; }
private static boolean forEachStatementsAreEquivalent( @NotNull PsiForeachStatement statement1, @NotNull PsiForeachStatement statement2) { final PsiExpression value1 = statement1.getIteratedValue(); final PsiExpression value2 = statement2.getIteratedValue(); if (!expressionsAreEquivalent(value1, value2)) { return false; } final PsiParameter parameter1 = statement1.getIterationParameter(); final PsiParameter parameter2 = statement1.getIterationParameter(); final String name1 = parameter1.getName(); final String name2 = parameter2.getName(); if (!name1.equals(name2)) { return false; } final PsiType type1 = parameter1.getType(); if (!type1.equals(parameter2.getType())) { return false; } final PsiStatement body1 = statement1.getBody(); final PsiStatement body2 = statement2.getBody(); return statementsAreEquivalent(body1, body2); }
@Override public void visitForeachStatement(PsiForeachStatement statement) { super.visitForeachStatement(statement); final PsiExpression iteratedValue = statement.getIteratedValue(); if (iteratedValue == null) { return; } final PsiType type = iteratedValue.getType(); if (!(type instanceof PsiArrayType)) { return; } final PsiArrayType arrayType = (PsiArrayType) type; final PsiType componentType = arrayType.getComponentType(); if (componentType instanceof PsiPrimitiveType) { return; } final PsiParameter parameter = statement.getIterationParameter(); final PsiStatement body = statement.getBody(); if (!bodyIsArrayToCollectionCopy(body, parameter, false)) { return; } registerStatementError(statement); }
@Nullable private static String getCollectionsAddAllText(PsiForeachStatement foreachStatement) throws IncorrectOperationException { final PsiStatement body = getBody(foreachStatement); if (!(body instanceof PsiExpressionStatement)) { return null; } final PsiExpressionStatement expressionStatement = (PsiExpressionStatement) body; final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) expressionStatement.getExpression(); final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); final PsiElement collection = methodExpression.getQualifier(); if (collection == null) { // fixme for when the array is added to 'this' return null; } final String collectionText = collection.getText(); final PsiExpression iteratedValue = foreachStatement.getIteratedValue(); if (iteratedValue == null) { return null; } final String arrayText = iteratedValue.getText(); @NonNls final StringBuilder buffer = new StringBuilder(); if (PsiUtil.isLanguageLevel5OrHigher(foreachStatement)) { buffer.append("java.util.Collections.addAll("); buffer.append(collectionText); buffer.append(','); buffer.append(arrayText); buffer.append(");"); } else { buffer.append(collectionText); buffer.append(".addAll(java.util.Arrays.asList("); buffer.append(arrayText); 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; } }
private static void restoreComments(PsiForeachStatement foreachStatement, PsiStatement body) { final PsiElement parent = foreachStatement.getParent(); for (PsiElement comment : PsiTreeUtil.findChildrenOfType(body, PsiComment.class)) { parent.addBefore(comment, foreachStatement); } }
@Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { final PsiForeachStatement foreachStatement = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiForeachStatement.class); if (foreachStatement != null) { if (!FileModificationService.getInstance().preparePsiElementForWrite(foreachStatement)) return; final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); PsiStatement body = foreachStatement.getBody(); final PsiExpression iteratedValue = foreachStatement.getIteratedValue(); if (body != null && iteratedValue != null) { final PsiParameter parameter = foreachStatement.getIterationParameter(); final PsiIfStatement ifStatement = extractIfStatement(body); final PsiMethodCallExpression methodCallExpression = extractAddCall(body, ifStatement); if (methodCallExpression == null) return; if (isAddAllCall(foreachStatement, body)) { restoreComments(foreachStatement, body); final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression(); final String qualifierText = qualifierExpression != null ? qualifierExpression.getText() : ""; final String callText = StringUtil.getQualifiedName( qualifierText, "addAll(" + getIteratedValueText(iteratedValue) + ");"); PsiElement result = foreachStatement.replace( elementFactory.createStatementFromText(callText, foreachStatement)); reformatWhenNeeded(project, result); return; } final StringBuilder builder = new StringBuilder(getIteratedValueText(iteratedValue) + ".stream()"); builder.append(createFiltersChainText(body, parameter, ifStatement)); builder.append( createMapperFunctionalExpressionText( parameter, methodCallExpression.getArgumentList().getExpressions()[0])); builder.append(".collect(java.util.stream.Collectors."); PsiElement result = null; try { final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression(); if (qualifierExpression instanceof PsiReferenceExpression) { final PsiElement resolve = ((PsiReferenceExpression) qualifierExpression).resolve(); if (resolve instanceof PsiVariable) { if (resolve instanceof PsiLocalVariable && foreachStatement.equals( PsiTreeUtil.skipSiblingsForward( resolve.getParent(), PsiWhiteSpace.class))) { final PsiExpression initializer = ((PsiVariable) resolve).getInitializer(); if (initializer instanceof PsiNewExpression) { final PsiExpressionList argumentList = ((PsiNewExpression) initializer).getArgumentList(); if (argumentList != null && argumentList.getExpressions().length == 0) { restoreComments(foreachStatement, body); final String callText = builder.toString() + createInitializerReplacementText( ((PsiVariable) resolve).getType(), initializer) + ")"; result = initializer.replace( elementFactory.createExpressionFromText(callText, null)); simplifyRedundantCast(result); foreachStatement.delete(); return; } } } } } restoreComments(foreachStatement, body); final String qualifierText = qualifierExpression != null ? qualifierExpression.getText() : ""; final String callText = StringUtil.getQualifiedName( qualifierText, "addAll(" + builder.toString() + "toList()));"); result = foreachStatement.replace( elementFactory.createStatementFromText(callText, foreachStatement)); simplifyRedundantCast(result); } finally { reformatWhenNeeded(project, result); } } } }
@Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { final PsiForeachStatement foreachStatement = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiForeachStatement.class); if (foreachStatement != null) { if (!FileModificationService.getInstance().preparePsiElementForWrite(foreachStatement)) return; PsiStatement body = foreachStatement.getBody(); final PsiExpression iteratedValue = foreachStatement.getIteratedValue(); if (body != null && iteratedValue != null) { restoreComments(foreachStatement, body); final PsiParameter parameter = foreachStatement.getIterationParameter(); final PsiIfStatement ifStmt = extractIfStatement(body); StringBuilder buffer = new StringBuilder(getIteratedValueText(iteratedValue)); if (ifStmt != null) { final PsiStatement thenBranch = ifStmt.getThenBranch(); LOG.assertTrue(thenBranch != null); buffer.append(".stream()"); buffer.append(createFiltersChainText(body, parameter, ifStmt)); body = thenBranch; } buffer.append(".").append(getForEachMethodName()).append("("); final String functionalExpressionText = createForEachFunctionalExpressionText(project, body, parameter); final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); PsiExpressionStatement callStatement = (PsiExpressionStatement) elementFactory.createStatementFromText( buffer.toString() + functionalExpressionText + ");", foreachStatement); callStatement = (PsiExpressionStatement) foreachStatement.replace(callStatement); final PsiExpressionList argumentList = ((PsiCallExpression) callStatement.getExpression()).getArgumentList(); LOG.assertTrue(argumentList != null, callStatement.getText()); final PsiExpression[] expressions = argumentList.getExpressions(); LOG.assertTrue(expressions.length == 1); if (expressions[0] instanceof PsiFunctionalExpression && ((PsiFunctionalExpression) expressions[0]).getFunctionalInterfaceType() == null) { callStatement = (PsiExpressionStatement) callStatement.replace( elementFactory.createStatementFromText( buffer.toString() + "(" + parameter.getText() + ") -> " + wrapInBlock(body) + ");", callStatement)); } simplifyRedundantCast(callStatement); CodeStyleManager.getInstance(project) .reformat( JavaCodeStyleManager.getInstance(project).shortenClassReferences(callStatement)); } } }