blob: 88fe69cef124d3a9fe2d58e15d89e2c0743bd9d9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2020 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
* Red Hat Inc. - refactored to jdt.core.manipulation
*******************************************************************************/
/**
*
**/
package org.eclipse.jdt.internal.corext.fix;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
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.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ForStatement;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.manipulation.JavaManipulation;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation;
import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
import org.eclipse.jdt.internal.corext.refactoring.util.TightSourceRangeComputer;
public abstract class ConvertLoopOperation extends CompilationUnitRewriteOperation {
protected static final String FOR_LOOP_ELEMENT_IDENTIFIER= "element"; //$NON-NLS-1$
protected static final IStatus ERROR_STATUS= new Status(IStatus.ERROR, JavaManipulation.ID_PLUGIN, ""); //$NON-NLS-1$
private static final Map<String, String> IRREG_NOUNS= Stream.of(
new AbstractMap.SimpleImmutableEntry<>("Children", "Child"), //$NON-NLS-1$ //$NON-NLS-2$
new AbstractMap.SimpleImmutableEntry<>("Entries", "Entry"), //$NON-NLS-1$ //$NON-NLS-2$
new AbstractMap.SimpleImmutableEntry<>("Proxies", "Proxy"), //$NON-NLS-1$ //$NON-NLS-2$
new AbstractMap.SimpleImmutableEntry<>("Indices", "Index")) //$NON-NLS-1$ //$NON-NLS-2$
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
private static final Set<String> NO_BASE_TYPES = Stream.of(
"integers", //$NON-NLS-1$
"floats", //$NON-NLS-1$
"doubles", //$NON-NLS-1$
"booleans", //$NON-NLS-1$
"bytes", //$NON-NLS-1$
"chars", //$NON-NLS-1$
"shorts", //$NON-NLS-1$
"longs") //$NON-NLS-1$
.collect(Collectors.toSet());
private static final Set<String> CUT_PREFIX= Stream.of("all") //$NON-NLS-1$
.collect(Collectors.toSet());
private static final Set<String> IRREG_ENDINGS= Stream.of(
"xes", //$NON-NLS-1$
"ies", //$NON-NLS-1$
"oes", //$NON-NLS-1$
"ses", //$NON-NLS-1$
"hes", //$NON-NLS-1$
"zes", //$NON-NLS-1$
"ves", //$NON-NLS-1$
"ces", //$NON-NLS-1$
"ss", //$NON-NLS-1$
"is", //$NON-NLS-1$
"us", //$NON-NLS-1$
"os", //$NON-NLS-1$
"as") //$NON-NLS-1$
.collect(Collectors.toSet());
private final ForStatement fStatement;
private ConvertLoopOperation fOperation;
private ConvertLoopOperation fChildLoopOperation;
private final String[] fUsedNames;
public ConvertLoopOperation(ForStatement statement, String[] usedNames) {
fStatement= statement;
fUsedNames= usedNames;
}
public void setBodyConverter(ConvertLoopOperation operation) {
fOperation= operation;
}
public void setChildLoopOperation(ConvertLoopOperation operation) {
fChildLoopOperation= operation;
}
public ConvertLoopOperation getChildLoopOperation() {
return fChildLoopOperation;
}
public abstract String getIntroducedVariableName();
public abstract IStatus satisfiesPreconditions();
protected abstract Statement convert(CompilationUnitRewrite cuRewrite, TextEditGroup group, LinkedProposalModelCore positionGroups) throws CoreException;
protected ForStatement getForStatement() {
return fStatement;
}
protected Statement getBody(CompilationUnitRewrite cuRewrite, TextEditGroup group, LinkedProposalModelCore positionGroups) throws CoreException {
if (fOperation != null) {
return fOperation.convert(cuRewrite, group, positionGroups);
} else {
return (Statement)cuRewrite.getASTRewrite().createMoveTarget(getForStatement().getBody());
}
}
protected String[] getUsedVariableNames() {
final List<String> results= new ArrayList<>();
ForStatement forStatement= getForStatement();
CompilationUnit root= (CompilationUnit)forStatement.getRoot();
Collection<String> variableNames= new ScopeAnalyzer(root).getUsedVariableNames(forStatement.getStartPosition(), forStatement.getLength());
results.addAll(variableNames);
forStatement.accept(new GenericVisitor() {
@Override
public boolean visit(SingleVariableDeclaration node) {
results.add(node.getName().getIdentifier());
return super.visit(node);
}
@Override
public boolean visit(VariableDeclarationFragment fragment) {
results.add(fragment.getName().getIdentifier());
return super.visit(fragment);
}
});
results.addAll(Arrays.asList(fUsedNames));
return results.toArray(new String[results.size()]);
}
@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);
ASTNode node= getForStatement();
ASTNodes.replaceButKeepComment(rewrite, node, statement, group);
}
public static String modifybasename(String suggestedName) {
String name= suggestedName;
for(String prefix : CUT_PREFIX) {
if(prefix.length() >= suggestedName.length()) {
continue;
}
char afterPrefix= suggestedName.charAt(prefix.length());
if(Character.isUpperCase(afterPrefix) || afterPrefix == '_') {
if(suggestedName.toLowerCase().startsWith(prefix)) {
String nameWithoutPrefix= suggestedName.substring(prefix.length());
if(nameWithoutPrefix.startsWith("_") && nameWithoutPrefix.length() > 1) { //$NON-NLS-1$
name= nameWithoutPrefix.substring(1);
} else {
name= nameWithoutPrefix;
}
if(name.length() == 1) {
return name;
}
break;
}
}
}
for(Map.Entry<String, String> entry : IRREG_NOUNS.entrySet()) {
String suffix = entry.getKey();
if(name.toLowerCase().endsWith(suffix.toLowerCase())) {
String firstPart= name.substring(0, name.length() - suffix.length());
return firstPart + entry.getValue();
}
}
for(String varname : NO_BASE_TYPES) {
if(name.equalsIgnoreCase(varname)) {
return FOR_LOOP_ELEMENT_IDENTIFIER;
}
}
for(String suffix : IRREG_ENDINGS) {
if(name.toLowerCase().endsWith(suffix)) {
return FOR_LOOP_ELEMENT_IDENTIFIER;
}
}
if(name.length() > 2 && name.endsWith("s")) { //$NON-NLS-1$
return name.substring(0, name.length() - 1);
}
return FOR_LOOP_ELEMENT_IDENTIFIER;
}
}