package org.eclipse.jdt.internal.corext.refactoring.rename;
import java.util.ArrayList;
import java.util.List;
import com.ibm.icu.text.BreakIterator;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.ui.text.JavaWordIterator;
public class RenamingNameSuggestor {
public static final int STRATEGY_EXACT= 1;
public static final int STRATEGY_EMBEDDED= 2;
public static final int STRATEGY_SUFFIX= 3;
private static final String PLURAL_S= "s";
private static final String PLURAL_IES= "ies";
private static final String SINGULAR_Y= "y";
private int fStrategy;
private String[] fFieldPrefixes;
private String[] fFieldSuffixes;
private String[] fStaticFieldPrefixes;
private String[] fStaticFieldSuffixes;
private String[] fLocalPrefixes;
private String[] fLocalSuffixes;
private String[] fArgumentPrefixes;
private String[] fArgumentSuffixes;
private boolean fExtendedInterfaceNameMatching;
private boolean fExtendedAllUpperCaseHunkMatching;
private boolean fExtendedPluralMatching;
public RenamingNameSuggestor() {
this(STRATEGY_SUFFIX);
}
public RenamingNameSuggestor(int strategy) {
Assert.isTrue(strategy >= 1 && strategy <= 3);
fStrategy= strategy;
fExtendedInterfaceNameMatching= true;
fExtendedAllUpperCaseHunkMatching= true;
fExtendedPluralMatching= true;
resetPrefixes();
}
public String suggestNewFieldName(IJavaProject project, String oldFieldName, boolean isStatic, String oldTypeName, String newTypeName) {
initializePrefixesAndSuffixes(project);
if (isStatic)
return suggestNewVariableName(fStaticFieldPrefixes, fStaticFieldSuffixes, oldFieldName, oldTypeName, newTypeName);
else
return suggestNewVariableName(fFieldPrefixes, fFieldSuffixes, oldFieldName, oldTypeName, newTypeName);
}
public String suggestNewLocalName(IJavaProject project, String oldLocalName, boolean isArgument, String oldTypeName, String newTypeName) {
initializePrefixesAndSuffixes(project);
if (isArgument)
return suggestNewVariableName(fArgumentPrefixes, fArgumentSuffixes, oldLocalName, oldTypeName, newTypeName);
else
return suggestNewVariableName(fLocalPrefixes, fLocalSuffixes, oldLocalName, oldTypeName, newTypeName);
}
public String suggestNewMethodName(String oldMethodName, String oldTypeName, String newTypeName) {
Assert.isNotNull(oldMethodName);
Assert.isNotNull(oldTypeName);
Assert.isNotNull(newTypeName);
Assert.isTrue(oldMethodName.length() > 0);
Assert.isTrue(oldTypeName.length() > 0);
Assert.isTrue(newTypeName.length() > 0);
resetPrefixes();
return match(oldTypeName, newTypeName, oldMethodName);
}
public String suggestNewVariableName(String[] prefixes, String[] suffixes, String oldVariableName, String oldTypeName, String newTypeName) {
Assert.isNotNull(prefixes);
Assert.isNotNull(suffixes);
Assert.isNotNull(oldVariableName);
Assert.isNotNull(oldTypeName);
Assert.isNotNull(newTypeName);
Assert.isTrue(oldVariableName.length() > 0);
Assert.isTrue(oldTypeName.length() > 0);
Assert.isTrue(newTypeName.length() > 0);
final String usedPrefix= findLongestPrefix(oldVariableName, prefixes);
final String usedSuffix= findLongestSuffix(oldVariableName, suffixes);
final String strippedVariableName= oldVariableName.substring(usedPrefix.length(), oldVariableName.length() - usedSuffix.length());
String newVariableName= match(oldTypeName, newTypeName, strippedVariableName);
return (newVariableName != null) ? usedPrefix + newVariableName + usedSuffix : null;
}
private String match(final String oldTypeName, final String newTypeName, final String strippedVariableName) {
String oldType= oldTypeName;
String newType= newTypeName;
if (fExtendedInterfaceNameMatching && isInterfaceName(oldType) && isInterfaceName(newType)) {
oldType= getInterfaceName(oldType);
newType= getInterfaceName(newType);
}
String newVariableName= matchDirect(oldType, newType, strippedVariableName);
if (fExtendedPluralMatching && newVariableName == null && canPluralize(oldType))
newVariableName= matchDirect(pluralize(oldType), pluralize(newType), strippedVariableName);
return newVariableName;
}
private String matchDirect(String oldType, String newType, final String strippedVariableName) {
String newVariableName= exactMatch(oldType, newType, strippedVariableName);
if (newVariableName == null && fStrategy >= STRATEGY_EMBEDDED)
newVariableName= embeddedMatch(oldType, newType, strippedVariableName);
if (newVariableName == null && fStrategy >= STRATEGY_SUFFIX)
newVariableName= suffixMatch(oldType, newType, strippedVariableName);
return newVariableName;
}
private String exactMatch(final String oldTypeName, final String newTypeName, final String strippedVariableName) {
String newName= exactDirectMatch(oldTypeName, newTypeName, strippedVariableName);
if (newName != null)
return newName;
if (fExtendedAllUpperCaseHunkMatching && isUpperCaseCamelCaseHunk(oldTypeName)) {
String oldTN= getFirstUpperRestLowerCased(oldTypeName);
String newTN= isUpperCaseCamelCaseHunk(newTypeName) ? getFirstUpperRestLowerCased(newTypeName) : newTypeName;
newName= exactDirectMatch(oldTN, newTN, strippedVariableName);
}
return newName;
}
private String exactDirectMatch(final String oldTypeName, final String newTypeName, final String strippedVariableName) {
if (strippedVariableName.equals(oldTypeName))
return newTypeName;
if (strippedVariableName.equals(getLowerCased(oldTypeName)))
return getLowerCased(newTypeName);
return null;
}
private String embeddedMatch(String oldTypeName, String newTypeName, String strippedVariableName) {
final String lowerCaseVariable= strippedVariableName.toLowerCase();
final String lowerCaseOldTypeName= oldTypeName.toLowerCase();
int presumedIndex= lowerCaseVariable.indexOf(lowerCaseOldTypeName);
while (presumedIndex != -1) {
final String presumedTypeName= strippedVariableName.substring(presumedIndex, presumedIndex + oldTypeName.length());
final String prefix= strippedVariableName.substring(0, presumedIndex);
final String suffix= strippedVariableName.substring(presumedIndex + oldTypeName.length());
if (startsNewHunk(suffix)) {
String name= exactMatch(oldTypeName, newTypeName, presumedTypeName);
if (name != null)
return prefix + name + suffix;
}
presumedIndex= lowerCaseVariable.indexOf(lowerCaseOldTypeName, presumedIndex + 1);
}
return null;
}
private String suffixMatch(final String oldType, final String newType, final String strippedVariableName) {
String[] suffixesOld= getSuffixes(oldType);
String[] suffixesNew= getSuffixes(newType);
String[] suffixesVar= getSuffixes(strippedVariableName);
int min= Math.min(suffixesOld.length, suffixesNew.length);
String[] suffixesOldEqual= new String[min];
String[] suffixesNewEqual= new String[min];
System.arraycopy(suffixesOld, suffixesOld.length - min, suffixesOldEqual, 0, min);
System.arraycopy(suffixesNew, suffixesNew.length - min, suffixesNewEqual, 0, min);
int endIndex= -1;
for (int j= suffixesVar.length - 1; j >= 0; j--) {
String newHunkName= exactMatch(suffixesOldEqual[suffixesOldEqual.length - 1], suffixesNewEqual[suffixesNewEqual.length - 1], suffixesVar[j]);
if (newHunkName != null) {
endIndex= j;
break;
}
}
if (endIndex == -1)
return null;
int stepBack= 0;
int lastSuffixMatched= -1;
int hunkInVarName= -1;
for (int i= suffixesOldEqual.length - 1; i >= 0; i--) {
hunkInVarName= endIndex - stepBack;
stepBack++;
if (hunkInVarName < 0) {
break;
}
String newHunkName= exactMatch(suffixesOldEqual[i], suffixesNewEqual[i], suffixesVar[hunkInVarName]);
if (newHunkName == null)
break;
suffixesVar[hunkInVarName]= newHunkName;
lastSuffixMatched= i;
}
if (lastSuffixMatched == 0) {
int newPrefixes= suffixesNew.length - suffixesNewEqual.length;
if (newPrefixes > 0) {
if (Character.isLowerCase(suffixesVar[hunkInVarName].charAt(0)) && Character.isUpperCase(suffixesOldEqual[lastSuffixMatched].charAt(0))) {
suffixesVar[hunkInVarName]= getUpperCased(suffixesVar[hunkInVarName]);
suffixesNew[0]= getLowerCased(suffixesNew[0]);
}
String[] newVariableName= new String[suffixesVar.length + newPrefixes];
System.arraycopy(suffixesVar, 0, newVariableName, 0, hunkInVarName);
System.arraycopy(suffixesNew, 0, newVariableName, hunkInVarName, newPrefixes);
System.arraycopy(suffixesVar, hunkInVarName, newVariableName, hunkInVarName + newPrefixes, suffixesVar.length - hunkInVarName);
suffixesVar= newVariableName;
}
}
String varName= concat(suffixesVar);
if (varName.equals(strippedVariableName))
return null;
else
return varName;
}
private boolean startsNewHunk(String string) {
if (string.length() == 0)
return true;
return isLegalChar(string.charAt(0));
}
private boolean isUpperCaseCamelCaseHunk(String hunk) {
if (hunk.length() < 2)
return false;
for (int i= 0; i < hunk.length(); i++) {
if (!isLegalChar(hunk.charAt(i)))
return false;
}
return true;
}
private boolean isLegalChar(char c) {
if (Character.isLetter(c))
return Character.isUpperCase(c);
return true;
}
private String[] getSuffixes(String typeName) {
List<String> suffixes= new ArrayList<>();
JavaWordIterator iterator= new JavaWordIterator();
iterator.setText(typeName);
int lastmatch= 0;
int match;
while ( (match= iterator.next()) != BreakIterator.DONE) {
suffixes.add(typeName.substring(lastmatch, match));
lastmatch= match;
}
return suffixes.toArray(new String[0]);
}
private String concat(String[] suffixesNewEqual) {
StringBuilder returner= new StringBuilder();
for (int j= 0; j < suffixesNewEqual.length; j++) {
returner.append(suffixesNewEqual[j]);
}
return returner.toString();
}
private String getLowerCased(String name) {
if (name.length() > 1)
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
else
return name.toLowerCase();
}
private String getUpperCased(String name) {
if (name.length() > 1)
return Character.toUpperCase(name.charAt(0)) + name.substring(1);
else
return name.toLowerCase();
}
private String getFirstUpperRestLowerCased(String name) {
if (name.length() > 1)
return Character.toUpperCase(name.charAt(0)) + name.substring(1).toLowerCase();
else
return name.toLowerCase();
}
private boolean isInterfaceName(String typeName) {
return ( (typeName.length() >= 2) && typeName.charAt(0) == 'I' && Character.isUpperCase(typeName.charAt(1)));
}
private String getInterfaceName(String typeName) {
return typeName.substring(1);
}
private String findLongestPrefix(String name, String[] prefixes) {
String usedPrefix= "";
int bestLen= 0;
for (int i= 0; i < prefixes.length; i++) {
if (name.startsWith(prefixes[i])) {
if (prefixes[i].length() > bestLen) {
bestLen= prefixes[i].length();
usedPrefix= prefixes[i];
}
}
}
return usedPrefix;
}
private String findLongestSuffix(String name, String[] suffixes) {
String usedPrefix= "";
int bestLen= 0;
for (int i= 0; i < suffixes.length; i++) {
if (name.endsWith(suffixes[i])) {
if (suffixes[i].length() > bestLen) {
bestLen= suffixes[i].length();
usedPrefix= suffixes[i];
}
}
}
return usedPrefix;
}
private boolean canPluralize(String typeName) {
return !typeName.endsWith(PLURAL_S);
}
private String pluralize(String typeName) {
if (typeName.endsWith(SINGULAR_Y))
typeName= typeName.substring(0, typeName.length() - 1).concat(PLURAL_IES);
else if (!typeName.endsWith(PLURAL_S))
typeName= typeName.concat(PLURAL_S);
return typeName;
}
private void resetPrefixes() {
String[] empty= new String[0];
fFieldPrefixes= empty;
fFieldSuffixes= empty;
fStaticFieldPrefixes= empty;
fStaticFieldSuffixes= empty;
fLocalPrefixes= empty;
fLocalSuffixes= empty;
fArgumentPrefixes= empty;
fArgumentSuffixes= empty;
}
private void initializePrefixesAndSuffixes(IJavaProject project) {
fFieldPrefixes= readCommaSeparatedPreference(project, JavaCore.CODEASSIST_FIELD_PREFIXES);
fFieldSuffixes= readCommaSeparatedPreference(project, JavaCore.CODEASSIST_FIELD_SUFFIXES);
fStaticFieldPrefixes= readCommaSeparatedPreference(project, JavaCore.CODEASSIST_STATIC_FIELD_PREFIXES);
fStaticFieldSuffixes= readCommaSeparatedPreference(project, JavaCore.CODEASSIST_STATIC_FIELD_SUFFIXES);
fLocalPrefixes= readCommaSeparatedPreference(project, JavaCore.CODEASSIST_LOCAL_PREFIXES);
fLocalSuffixes= readCommaSeparatedPreference(project, JavaCore.CODEASSIST_LOCAL_SUFFIXES);
fArgumentPrefixes= readCommaSeparatedPreference(project, JavaCore.CODEASSIST_ARGUMENT_PREFIXES);
fArgumentSuffixes= readCommaSeparatedPreference(project, JavaCore.CODEASSIST_ARGUMENT_SUFFIXES);
}
private String[] readCommaSeparatedPreference(IJavaProject project, String option) {
String list= project.getOption(option, true);
return list == null ? new String[0] : list.split(",");
}
}