Copyright (c) 2000, 2019 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation
/******************************************************************************* * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/
package org.eclipse.jdt.internal.corext.fix; import java.util.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.text.edits.TextEditGroup; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTMatcher; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ArrayAccess; import org.eclipse.jdt.core.dom.Assignment; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ContinueStatement; import org.eclipse.jdt.core.dom.EnhancedForStatement; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.FieldAccess; import org.eclipse.jdt.core.dom.ForStatement; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.InfixExpression; import org.eclipse.jdt.core.dom.InfixExpression.Operator; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.NumberLiteral; import org.eclipse.jdt.core.dom.PostfixExpression; import org.eclipse.jdt.core.dom.PrefixExpression; import org.eclipse.jdt.core.dom.PrimitiveType; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.Statement; import org.eclipse.jdt.core.dom.ThisExpression; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.VariableDeclarationExpression; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.TypeLocation; import org.eclipse.jdt.core.dom.rewrite.ListRewrite; import org.eclipse.jdt.internal.core.manipulation.StubUtility; import org.eclipse.jdt.internal.corext.dom.ASTNodes; import org.eclipse.jdt.internal.corext.dom.GenericVisitor; import org.eclipse.jdt.internal.corext.dom.JdtASTMatcher; import org.eclipse.jdt.internal.corext.dom.ModifierRewrite; import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; import org.eclipse.jdt.internal.corext.refactoring.util.TightSourceRangeComputer; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; public class ConvertForLoopOperation extends ConvertLoopOperation { private static final String LENGTH_QUERY= "length"; //$NON-NLS-1$ private static final String SIZE_QUERY= "size"; //$NON-NLS-1$ private static final String GET_QUERY= "get"; //$NON-NLS-1$ private static final String ISEMPTY_QUERY= "isEmpty"; //$NON-NLS-1$ private static final String LITERAL_0= "0"; //$NON-NLS-1$ private static final String LITERAL_1= "1"; //$NON-NLS-1$ private static final class InvalidBodyError extends Error { private static final long serialVersionUID= 1L; } private IVariableBinding fIndexBinding; private IVariableBinding fLengthBinding; private IBinding fArrayBinding; private Expression fArrayAccess; private VariableDeclarationFragment fElementDeclaration; private boolean fMakeFinal; private boolean fIsCollection; private IMethodBinding fSizeMethodBinding; private IMethodBinding fGetMethodBinding; private MethodInvocation fSizeMethodAccess; public ConvertForLoopOperation(ForStatement forStatement) { this(forStatement, new String[0], false); } public ConvertForLoopOperation(ForStatement forStatement, String[] usedNames, boolean makeFinal) { super(forStatement, usedNames); fMakeFinal= makeFinal; } @Override public IStatus satisfiesPreconditions() { ForStatement statement= getForStatement(); CompilationUnit ast= (CompilationUnit)statement.getRoot(); IJavaElement javaElement= ast.getJavaElement(); if (javaElement == null) return ERROR_STATUS; if (!JavaModelUtil.is50OrHigher(javaElement.getJavaProject())) return ERROR_STATUS; if (!validateInitializers(statement)) return ERROR_STATUS; if (!validateExpression(statement)) return ERROR_STATUS; if (!validateUpdaters(statement)) return ERROR_STATUS; if (!validateBody(statement)) return ERROR_STATUS; return Status.OK_STATUS; } /* * Must be one of: * <ul> * <li>int [result]= 0;</li> * <li>int [result]= 0, [lengthBinding]= [arrayBinding].length;</li> * <li>int , [result]= 0;</li> * </ul> */ private boolean validateInitializers(ForStatement statement) { List<Expression> initializers= statement.initializers(); if (initializers.size() != 1) return false; Expression expression= initializers.get(0); if (!(expression instanceof VariableDeclarationExpression)) return false; VariableDeclarationExpression declaration= (VariableDeclarationExpression)expression; ITypeBinding declarationBinding= declaration.resolveTypeBinding(); if (declarationBinding == null) return false; if (!declarationBinding.isPrimitive()) return false; if (!PrimitiveType.INT.toString().equals(declarationBinding.getQualifiedName())) return false; List<VariableDeclarationFragment> fragments= declaration.fragments(); if (fragments.size() == 1) { IVariableBinding indexBinding= getIndexBindingFromFragment(fragments.get(0)); if (indexBinding == null) return false; fIndexBinding= indexBinding; return true; } else if (fragments.size() == 2) { IVariableBinding indexBinding= getIndexBindingFromFragment(fragments.get(0)); if (indexBinding == null) { indexBinding= getIndexBindingFromFragment(fragments.get(1)); if (indexBinding == null) return false; if (!validateLengthFragment(fragments.get(0))) return false; } else { if (!validateLengthFragment(fragments.get(1))) return false; } fIndexBinding= indexBinding; return true; } return false; } /* * [lengthBinding]= [arrayBinding].length */ private boolean validateLengthFragment(VariableDeclarationFragment fragment) { Expression initializer= fragment.getInitializer(); if (initializer == null) return false; if (!validateLengthQuery(initializer)) return false; IVariableBinding lengthBinding= (IVariableBinding)fragment.getName().resolveBinding(); if (lengthBinding == null) return false; fLengthBinding= lengthBinding; return true; } /* * Must be one of: * <ul> * <li>[result]= 0</li> * </ul> */ private IVariableBinding getIndexBindingFromFragment(VariableDeclarationFragment fragment) { Expression initializer= fragment.getInitializer(); if (!(initializer instanceof NumberLiteral)) return null; NumberLiteral number= (NumberLiteral)initializer; if (!LITERAL_0.equals(number.getToken())) return null; return (IVariableBinding)fragment.getName().resolveBinding(); } /* * Must be one of: * <ul> * <li>[indexBinding] < [result].length;</li> * <li>[result].length > [indexBinding];</li> * <li>[indexBinding] < [lengthBinding];</li> * <li>[lengthBinding] > [indexBinding];</li> * </ul> */ private boolean validateExpression(ForStatement statement) { Expression expression= statement.getExpression(); if (!(expression instanceof InfixExpression)) return false; InfixExpression infix= (InfixExpression)expression; Expression left= infix.getLeftOperand(); Expression right= infix.getRightOperand(); if (left instanceof SimpleName && right instanceof SimpleName) { IVariableBinding lengthBinding= fLengthBinding; if (lengthBinding == null) return false; IBinding leftBinding= ((SimpleName)left).resolveBinding(); IBinding righBinding= ((SimpleName)right).resolveBinding(); if (fIndexBinding.equals(leftBinding)) { return lengthBinding.equals(righBinding); } else if (fIndexBinding.equals(righBinding)) { return lengthBinding.equals(leftBinding); } return false; } else if (left instanceof SimpleName) { if (!fIndexBinding.equals(((SimpleName)left).resolveBinding())) return false; if (!Operator.LESS.equals(infix.getOperator())) return false; return validateLengthQuery(right); } else if (right instanceof SimpleName) { if (!fIndexBinding.equals(((SimpleName)right).resolveBinding())) return false; if (!Operator.GREATER.equals(infix.getOperator())) return false; return validateLengthQuery(left); } return false; } /* * Must be one of: * <ul> * <li>[result].length</li> * <li>[result].size()</li> * </ul> */ private boolean validateLengthQuery(Expression lengthQuery) { if (lengthQuery instanceof QualifiedName) { QualifiedName qualifiedName= (QualifiedName)lengthQuery; SimpleName name= qualifiedName.getName(); if (!LENGTH_QUERY.equals(name.getIdentifier())) return false; Name arrayAccess= qualifiedName.getQualifier(); ITypeBinding accessType= arrayAccess.resolveTypeBinding(); if (accessType == null) return false; if (!accessType.isArray()) return false; IBinding arrayBinding= arrayAccess.resolveBinding(); if (arrayBinding == null) return false; fArrayBinding= arrayBinding; fArrayAccess= arrayAccess; return true; } else if (lengthQuery instanceof FieldAccess) { FieldAccess fieldAccess= (FieldAccess)lengthQuery; SimpleName name= fieldAccess.getName(); if (!LENGTH_QUERY.equals(name.getIdentifier())) return false; Expression arrayAccess= fieldAccess.getExpression(); ITypeBinding accessType= arrayAccess.resolveTypeBinding(); if (accessType == null) return false; if (!accessType.isArray()) return false; IBinding arrayBinding= getBinding(arrayAccess); if (arrayBinding == null) return false; fArrayBinding= arrayBinding; fArrayAccess= arrayAccess; return true; } else if (lengthQuery instanceof MethodInvocation) { MethodInvocation methodCall= (MethodInvocation)lengthQuery; SimpleName name= methodCall.getName(); if (!SIZE_QUERY.equals(name.getIdentifier()) || !methodCall.arguments().isEmpty()) { return false; } IMethodBinding methodBinding= methodCall.resolveMethodBinding(); if (methodBinding == null) { return false; } ITypeBinding classBinding= methodBinding.getDeclaringClass(); if (isCollection(classBinding)) { fIsCollection= true; fSizeMethodBinding= methodBinding; fSizeMethodAccess= methodCall; return true; } } return false; } private boolean isCollection(ITypeBinding classBinding) { ITypeBinding[] interfaces= classBinding.getInterfaces(); for (ITypeBinding binding : interfaces) { if (binding.getErasure().getQualifiedName().startsWith("java.util.Collection")) { //$NON-NLS-1$ return true; } } ITypeBinding superClass= classBinding.getSuperclass(); if (superClass != null && isCollection(superClass)) { return true; } for (ITypeBinding binding : interfaces) { if (isCollection(binding)) { return true; } } return false; } /* * Must be one of: * <ul> * <li>[indexBinding]++</li> * <li>++[indexBinding]</li> * <li>[indexBinding]+= 1</li> * <li>[indexBinding]= [indexBinding] + 1</li> * <li>[indexBinding]= 1 + [indexBinding]</li> * <ul> */ private boolean validateUpdaters(ForStatement statement) { List<Expression> updaters= statement.updaters(); if (updaters.size() != 1) return false; Expression updater= updaters.get(0); if (updater instanceof PostfixExpression) { PostfixExpression postfix= (PostfixExpression)updater; if (!PostfixExpression.Operator.INCREMENT.equals(postfix.getOperator())) return false; IBinding binding= getBinding(postfix.getOperand()); if (!fIndexBinding.equals(binding)) return false; return true; } else if (updater instanceof PrefixExpression) { PrefixExpression prefix= (PrefixExpression) updater; if (!PrefixExpression.Operator.INCREMENT.equals(prefix.getOperator())) return false; IBinding binding= getBinding(prefix.getOperand()); if (!fIndexBinding.equals(binding)) return false; return true; } else if (updater instanceof Assignment) { Assignment assignment= (Assignment)updater; Expression left= assignment.getLeftHandSide(); IBinding binding= getBinding(left); if (!fIndexBinding.equals(binding)) return false; if (Assignment.Operator.PLUS_ASSIGN.equals(assignment.getOperator())) { return isOneLiteral(assignment.getRightHandSide()); } else if (Assignment.Operator.ASSIGN.equals(assignment.getOperator())) { Expression right= assignment.getRightHandSide(); if (!(right instanceof InfixExpression)) return false; InfixExpression infixExpression= (InfixExpression)right; Expression leftOperand= infixExpression.getLeftOperand(); IBinding leftBinding= getBinding(leftOperand); Expression rightOperand= infixExpression.getRightOperand(); IBinding rightBinding= getBinding(rightOperand); if (fIndexBinding.equals(leftBinding)) { return isOneLiteral(rightOperand); } else if (fIndexBinding.equals(rightBinding)) { return isOneLiteral(leftOperand); } } } return false; } private boolean isOneLiteral(Expression expression) { if (!(expression instanceof NumberLiteral)) return false; NumberLiteral literal= (NumberLiteral)expression; return LITERAL_1.equals(literal.getToken()); } /* * returns false iff * <ul> * <li><code>indexBinding</code> is used for anything else then accessing * an element of <code>arrayBinding</code></li> or as a parameter to <code>getBinding</code> * <li><code>arrayBinding</code> is assigned</li> * <li>an element of <code>arrayBinding</code> is assigned</li> * <li><code>lengthBinding</code> is referenced</li> * <li>a method call is made to anything but get(<code>indexBinding</code>) or size() or isEmpty() * </ul> * within <code>body</code> */ private boolean validateBody(ForStatement statement) { Statement body= statement.getBody(); try { body.accept(new GenericVisitor() { @Override protected boolean visitNode(ASTNode node) { if (node instanceof ContinueStatement) { return false; } if (node instanceof Name) { Name name= (Name)node; IBinding nameBinding= name.resolveBinding(); if (nameBinding == null) throw new InvalidBodyError(); if (nameBinding.equals(fIndexBinding)) { if (node.getLocationInParent() == ArrayAccess.INDEX_PROPERTY) { if (fIsCollection) throw new InvalidBodyError(); ArrayAccess arrayAccess= (ArrayAccess)node.getParent(); Expression array= arrayAccess.getArray(); if (array instanceof QualifiedName) { if (!(fArrayAccess instanceof QualifiedName)) throw new InvalidBodyError(); IBinding varBinding1= ((QualifiedName) array).getQualifier().resolveBinding(); if (varBinding1 == null) throw new InvalidBodyError(); IBinding varBinding2= ((QualifiedName) fArrayAccess).getQualifier().resolveBinding(); if (!varBinding1.equals(varBinding2)) throw new InvalidBodyError(); } else if (array instanceof FieldAccess) { Expression arrayExpression= ((FieldAccess) array).getExpression(); if (arrayExpression instanceof ThisExpression) { if (fArrayAccess instanceof FieldAccess) { Expression arrayAccessExpression= ((FieldAccess) fArrayAccess).getExpression(); if (!(arrayAccessExpression instanceof ThisExpression)) throw new InvalidBodyError(); } else if (fArrayAccess instanceof QualifiedName) { throw new InvalidBodyError(); } } else { if (!(fArrayAccess instanceof FieldAccess)) throw new InvalidBodyError(); Expression arrayAccessExpression= ((FieldAccess) fArrayAccess).getExpression(); if (!arrayExpression.subtreeMatch(new JdtASTMatcher(), arrayAccessExpression)) { throw new InvalidBodyError(); } } } else { if (fArrayAccess instanceof QualifiedName) { throw new InvalidBodyError(); } if (fArrayAccess instanceof FieldAccess) { Expression arrayAccessExpression= ((FieldAccess) fArrayAccess).getExpression(); if (!(arrayAccessExpression instanceof ThisExpression)) throw new InvalidBodyError(); } } IBinding binding= getBinding(array); if (binding == null) throw new InvalidBodyError(); if (!fArrayBinding.equals(binding)) throw new InvalidBodyError(); } else if (node.getLocationInParent() == MethodInvocation.ARGUMENTS_PROPERTY) { MethodInvocation method= (MethodInvocation)node.getParent(); IMethodBinding methodBinding= method.resolveMethodBinding(); if (methodBinding == null) throw new InvalidBodyError(); ITypeBinding[] parms= methodBinding.getParameterTypes(); if (!fIsCollection || !GET_QUERY.equals(method.getName().getFullyQualifiedName()) || parms.length != 1 || !parms[0].getName().equals("int") || //$NON-NLS-1$ !fSizeMethodBinding.getDeclaringClass().equals(methodBinding.getDeclaringClass()) || fSizeMethodAccess.getExpression() == null || !fSizeMethodAccess.getExpression().subtreeMatch(new ASTMatcher(), method.getExpression())) throw new InvalidBodyError(); fGetMethodBinding= methodBinding; } else { throw new InvalidBodyError(); } } else if (nameBinding.equals(fArrayBinding)) { if (isAssigned(node)) throw new InvalidBodyError(); } else if (nameBinding.equals(fLengthBinding)) { throw new InvalidBodyError(); } else if (fElementDeclaration != null && nameBinding.equals(fElementDeclaration.getName().resolveBinding())) { if (isAssigned(node)) fElementDeclaration= null; } } else if (fIsCollection && node instanceof MethodInvocation) { MethodInvocation method= (MethodInvocation)node; IMethodBinding binding= method.resolveMethodBinding(); if (binding == null) { throw new InvalidBodyError(); } if (fSizeMethodBinding.getDeclaringClass().equals(binding.getDeclaringClass())) { String methodName= method.getName().getFullyQualifiedName(); if (!SIZE_QUERY.equals(methodName) && !GET_QUERY.equals(methodName) && !ISEMPTY_QUERY.equals(methodName)) { throw new InvalidBodyError(); } } } return true; } private boolean isAssigned(ASTNode current) { while (current != null && !(current instanceof Statement)) { if (current.getLocationInParent() == Assignment.LEFT_HAND_SIDE_PROPERTY) return true; if (current instanceof PrefixExpression && !(((PrefixExpression) current).getOperand() instanceof MethodInvocation && ((PrefixExpression) current).getOperator().equals(PrefixExpression.Operator.NOT))) return true; if (current instanceof PostfixExpression) return true; current= current.getParent(); } return false; } @Override public boolean visit(ArrayAccess node) { if (fElementDeclaration != null) return super.visit(node); IBinding binding= getBinding(node.getArray()); if (!fIsCollection && fArrayBinding.equals(binding)) { IBinding index= getBinding(node.getIndex()); if (fIndexBinding.equals(index)) { if (node.getLocationInParent() == VariableDeclarationFragment.INITIALIZER_PROPERTY) { fElementDeclaration= (VariableDeclarationFragment)node.getParent(); } } } return super.visit(node); } @Override public boolean visit(MethodInvocation node) { if (fElementDeclaration != null || !fIsCollection) return super.visit(node); IMethodBinding nodeBinding= node.resolveMethodBinding(); if (nodeBinding == null) { return super.visit(node); } ITypeBinding[] args= nodeBinding.getParameterTypes(); if (GET_QUERY.equals(nodeBinding.getName()) && args.length == 1 && args[0].getName().equals("int") && //$NON-NLS-1$ nodeBinding.getDeclaringClass().equals(fSizeMethodBinding.getDeclaringClass())) { IBinding index= getBinding((Expression)node.arguments().get(0)); if (fIndexBinding.equals(index)) { if (node.getLocationInParent() == VariableDeclarationFragment.INITIALIZER_PROPERTY) { fElementDeclaration= (VariableDeclarationFragment)node.getParent(); } } } return super.visit(node); } }); } catch (InvalidBodyError e) { return false; } return true; } private static IBinding getBinding(Expression expression) { if (expression instanceof FieldAccess) { return ((FieldAccess)expression).resolveFieldBinding(); } else if (expression instanceof Name) { return ((Name)expression).resolveBinding(); } return null; } @Override public String getIntroducedVariableName() { if (fElementDeclaration != null) { return fElementDeclaration.getName().getIdentifier(); } else { ForStatement forStatement= getForStatement(); IJavaProject javaProject= ((CompilationUnit)forStatement.getRoot()).getJavaElement().getJavaProject(); String[] proposals= null; if (this.fIsCollection) { proposals= getVariableNameProposalsCollection(fSizeMethodAccess, javaProject); } else { proposals= getVariableNameProposals(fArrayAccess.resolveTypeBinding(), javaProject); } return proposals[0]; } } @Override public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModelCore positionGroups) throws CoreException { TextEditGroup group= createTextEditGroup(FixMessages.Java50Fix_ConvertToEnhancedForLoop_description, cuRewrite); ASTRewrite rewrite= cuRewrite.getASTRewrite(); TightSourceRangeComputer rangeComputer; if (rewrite.getExtendedSourceRangeComputer() instanceof TightSourceRangeComputer) { rangeComputer= (TightSourceRangeComputer)rewrite.getExtendedSourceRangeComputer(); } else { rangeComputer= new TightSourceRangeComputer(); } rangeComputer.addTightSourceNode(getForStatement()); rewrite.setTargetSourceRangeComputer(rangeComputer); Statement statement= convert(cuRewrite, group, positionGroups); rewrite.replace(getForStatement(), statement, group); } @Override protected Statement convert(CompilationUnitRewrite cuRewrite, TextEditGroup group, LinkedProposalModelCore positionGroups) throws CoreException { ASTRewrite rewrite= cuRewrite.getASTRewrite(); ImportRewrite importRewrite= cuRewrite.getImportRewrite(); ForStatement forStatement= getForStatement(); IJavaProject javaProject= ((CompilationUnit)forStatement.getRoot()).getJavaElement().getJavaProject(); String[] proposals= null; if (this.fIsCollection) { proposals= getVariableNameProposalsCollection(fSizeMethodAccess, javaProject); } else { proposals= getVariableNameProposals(fArrayAccess.resolveTypeBinding(), javaProject); } String parameterName; if (fElementDeclaration != null) { parameterName= fElementDeclaration.getName().getIdentifier(); } else { parameterName= proposals[0]; } LinkedProposalPositionGroupCore pg= positionGroups.getPositionGroup(parameterName, true); if (fElementDeclaration != null) pg.addProposal(parameterName, 10); for (int i= 0; i < proposals.length; i++) { pg.addProposal(proposals[i], 10); } AST ast= forStatement.getAST(); EnhancedForStatement result= ast.newEnhancedForStatement(); SingleVariableDeclaration parameterDeclaration= null; Expression parameterExpression= null; if (this.fIsCollection) { parameterExpression= fSizeMethodAccess.getExpression(); parameterDeclaration= createParameterDeclarationCollection(parameterName, fElementDeclaration, fSizeMethodAccess, forStatement, importRewrite, rewrite, group, pg, fMakeFinal); } else { parameterExpression= fArrayAccess; parameterDeclaration= createParameterDeclaration(parameterName, fElementDeclaration, fArrayAccess, forStatement, importRewrite, rewrite, group, pg, fMakeFinal); } result.setParameter(parameterDeclaration); result.setExpression((Expression)rewrite.createCopyTarget(parameterExpression)); if (this.fIsCollection) { convertBodyCollection(forStatement.getBody(), fIndexBinding, fGetMethodBinding, parameterName, rewrite, group, pg); } else { convertBody(forStatement.getBody(), fIndexBinding, fArrayBinding, parameterName, rewrite, group, pg); } result.setBody(getBody(cuRewrite, group, positionGroups)); positionGroups.setEndPosition(rewrite.track(result)); return result; } private void convertBody(Statement body, final IBinding indexBinding, final IBinding arrayBinding, final String parameterName, final ASTRewrite rewrite, final TextEditGroup editGroup, final LinkedProposalPositionGroupCore pg) { final AST ast= body.getAST(); body.accept(new GenericVisitor() { @Override public boolean visit(ArrayAccess node) { IBinding binding= getBinding(node.getArray()); if (arrayBinding.equals(binding)) { IBinding index= getBinding(node.getIndex()); if (indexBinding.equals(index)) { replaceAccess(node); } } return super.visit(node); } private void replaceAccess(ASTNode node) { if (fElementDeclaration != null && node.getLocationInParent() == VariableDeclarationFragment.INITIALIZER_PROPERTY) { VariableDeclarationFragment fragment= (VariableDeclarationFragment)node.getParent(); IBinding targetBinding= fragment.getName().resolveBinding(); if (targetBinding != null) { VariableDeclarationStatement statement= (VariableDeclarationStatement)fragment.getParent(); if (statement.fragments().size() == 1) { rewrite.remove(statement, editGroup); } else { ListRewrite listRewrite= rewrite.getListRewrite(statement, VariableDeclarationStatement.FRAGMENTS_PROPERTY); listRewrite.remove(fragment, editGroup); } } else { SimpleName name= ast.newSimpleName(parameterName); rewrite.replace(node, name, editGroup); pg.addPosition(rewrite.track(name), true); } } else { SimpleName name= ast.newSimpleName(parameterName); rewrite.replace(node, name, editGroup); pg.addPosition(rewrite.track(name), true); } } }); } private SingleVariableDeclaration createParameterDeclaration(String parameterName, VariableDeclarationFragment fragement, Expression arrayAccess, ForStatement statement, ImportRewrite importRewrite, ASTRewrite rewrite, TextEditGroup group, LinkedProposalPositionGroupCore pg, boolean makeFinal) { CompilationUnit compilationUnit= (CompilationUnit)arrayAccess.getRoot(); AST ast= compilationUnit.getAST(); SingleVariableDeclaration result= ast.newSingleVariableDeclaration(); SimpleName name= ast.newSimpleName(parameterName); pg.addPosition(rewrite.track(name), true); result.setName(name); ITypeBinding arrayTypeBinding= arrayAccess.resolveTypeBinding(); Type type= importType(arrayTypeBinding.getElementType(), statement, importRewrite, compilationUnit, arrayTypeBinding.getDimensions() == 1 ? TypeLocation.LOCAL_VARIABLE : TypeLocation.ARRAY_CONTENTS); if (arrayTypeBinding.getDimensions() != 1) { type= ast.newArrayType(type, arrayTypeBinding.getDimensions() - 1); } result.setType(type); if (fragement != null) { VariableDeclarationStatement declaration= (VariableDeclarationStatement)fragement.getParent(); ModifierRewrite.create(rewrite, result).copyAllModifiers(declaration, group); } if (makeFinal && (fragement == null || ASTNodes.findModifierNode(Modifier.FINAL, ASTNodes.getModifiers(fragement)) == null)) { ModifierRewrite.create(rewrite, result).setModifiers(Modifier.FINAL, 0, group); } return result; } private String[] getVariableNameProposals(ITypeBinding arrayTypeBinding, IJavaProject project) { String[] variableNames= getUsedVariableNames(); String baseName= FOR_LOOP_ELEMENT_IDENTIFIER; String name= fArrayBinding.getName(); if (name.length() > 2 && name.charAt(name.length() - 1) == 's') { baseName= name.substring(0, name.length() - 1); } String[] elementSuggestions= StubUtility.getLocalNameSuggestions(project, baseName, 0, variableNames); String type= arrayTypeBinding.getElementType().getName(); String[] typeSuggestions= StubUtility.getLocalNameSuggestions(project, type, arrayTypeBinding.getDimensions() - 1, variableNames); String[] result= new String[elementSuggestions.length + typeSuggestions.length]; System.arraycopy(elementSuggestions, 0, result, 0, elementSuggestions.length); System.arraycopy(typeSuggestions, 0, result, elementSuggestions.length, typeSuggestions.length); return result; } private String[] getVariableNameProposalsCollection(MethodInvocation sizeMethodAccess, IJavaProject project) { String[] variableNames= getUsedVariableNames(); String baseName= FOR_LOOP_ELEMENT_IDENTIFIER; Expression exp= sizeMethodAccess.getExpression(); String name= exp instanceof SimpleName ? ((SimpleName)exp).getFullyQualifiedName() : ""; //$NON-NLS-1$ if (name.length() > 2 && name.charAt(name.length() - 1) == 's') { baseName= name.substring(0, name.length() - 1); } String[] elementSuggestions= StubUtility.getLocalNameSuggestions(project, baseName, 0, variableNames); ITypeBinding[] typeArgs= fSizeMethodBinding.getDeclaringClass().getTypeArguments(); String type= "Object"; //$NON-NLS-1$ if (typeArgs != null && typeArgs.length > 0) { type= typeArgs[0].getName(); } String[] typeSuggestions= StubUtility.getLocalNameSuggestions(project, type, 0, variableNames); String[] result= new String[elementSuggestions.length + typeSuggestions.length]; System.arraycopy(elementSuggestions, 0, result, 0, elementSuggestions.length); System.arraycopy(typeSuggestions, 0, result, elementSuggestions.length, typeSuggestions.length); return result; } private void convertBodyCollection(Statement body, final IBinding indexBinding, final IBinding getBinding, final String parameterName, final ASTRewrite rewrite, final TextEditGroup editGroup, final LinkedProposalPositionGroupCore pg) { final AST ast= body.getAST(); body.accept(new GenericVisitor() { @Override public boolean visit(MethodInvocation node) { IBinding binding= node.resolveMethodBinding(); if (binding != null && binding.equals(getBinding)) { List<Expression> args = node.arguments(); if (args.size() == 1 && args.get(0) instanceof SimpleName && indexBinding.equals(((SimpleName)args.get(0)).resolveBinding())) { replaceAccess(node); } } return super.visit(node); } private void replaceAccess(ASTNode node) { if (fElementDeclaration != null && node.getLocationInParent() == VariableDeclarationFragment.INITIALIZER_PROPERTY) { VariableDeclarationFragment fragment= (VariableDeclarationFragment)node.getParent(); IBinding targetBinding= fragment.getName().resolveBinding(); if (targetBinding != null) { VariableDeclarationStatement statement= (VariableDeclarationStatement)fragment.getParent(); if (statement.fragments().size() == 1) { rewrite.remove(statement, editGroup); } else { ListRewrite listRewrite= rewrite.getListRewrite(statement, VariableDeclarationStatement.FRAGMENTS_PROPERTY); listRewrite.remove(fragment, editGroup); } } else { SimpleName name= ast.newSimpleName(parameterName); rewrite.replace(node, name, editGroup); pg.addPosition(rewrite.track(name), true); } } else { SimpleName name= ast.newSimpleName(parameterName); rewrite.replace(node, name, editGroup); pg.addPosition(rewrite.track(name), true); } } }); } private SingleVariableDeclaration createParameterDeclarationCollection(String parameterName, VariableDeclarationFragment fragement, Expression sizeAccess, ForStatement statement, ImportRewrite importRewrite, ASTRewrite rewrite, TextEditGroup group, LinkedProposalPositionGroupCore pg, boolean makeFinal) { CompilationUnit compilationUnit= (CompilationUnit)sizeAccess.getRoot(); AST ast= compilationUnit.getAST(); SingleVariableDeclaration result= ast.newSingleVariableDeclaration(); SimpleName name= ast.newSimpleName(parameterName); pg.addPosition(rewrite.track(name), true); result.setName(name); IMethodBinding sizeTypeBinding= ((MethodInvocation)sizeAccess).resolveMethodBinding(); ITypeBinding[] sizeTypeArguments= sizeTypeBinding.getDeclaringClass().getTypeArguments(); Type type= importType(sizeTypeArguments != null && sizeTypeArguments.length > 0 ? sizeTypeArguments[0] : fSizeMethodAccess.getAST().resolveWellKnownType("java.lang.Object"), //$NON-NLS-1$ statement, importRewrite, compilationUnit, TypeLocation.LOCAL_VARIABLE); result.setType(type); if (fragement != null) { VariableDeclarationStatement declaration= (VariableDeclarationStatement)fragement.getParent(); ModifierRewrite.create(rewrite, result).copyAllModifiers(declaration, group); } if (makeFinal && (fragement == null || ASTNodes.findModifierNode(Modifier.FINAL, ASTNodes.getModifiers(fragement)) == null)) { ModifierRewrite.create(rewrite, result).setModifiers(Modifier.FINAL, 0, group); } return result; } }