package org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.jdt.core.NamingConventions;
import org.eclipse.jdt.core.dom.AST;
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.Block;
import org.eclipse.jdt.core.dom.CastExpression;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.ConditionalExpression;
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.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.InfixExpression.Operator;
import org.eclipse.jdt.core.dom.InstanceofExpression;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.ParenthesizedExpression;
import org.eclipse.jdt.core.dom.PostfixExpression;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
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.manipulation.CodeGeneration;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2Core;
import org.eclipse.jdt.internal.core.manipulation.StubUtility;
import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
public abstract class AbstractToStringGenerator {
protected static final String METHODNAME_TO_STRING= "toString";
protected static final String TYPENAME_STRING= "String";
final protected String HELPER_TOSTRING_METHOD_NAME= "toString";
final private String HELPER_ARRAYTOSTRING_METHOD_NAME= "arrayToString";
final private String MAX_LEN_VARIABLE_NAME= "maxLen";
protected String fMaxLenVariableName= MAX_LEN_VARIABLE_NAME;
protected final static String OVERWRITE_METHOD_PROPERTY= "override_method";
public ToStringTemplateParser getTemplateParser() {
return new ToStringTemplateParser();
}
protected ToStringGenerationContext fContext;
protected AST fAst;
protected MethodDeclaration toStringMethod;
protected boolean needMaxLenVariable;
protected boolean needCollectionToStringMethod;
protected List<ITypeBinding> typesThatNeedArrayToStringMethod;
public RefactoringStatus checkConditions() {
return new RefactoringStatus();
}
public MethodDeclaration generateToStringMethod() throws CoreException {
initialize();
String[] stringArray= fContext.getTemplateParser().getBeginning();
for (int i= 0; i < stringArray.length; i++) {
addElement(processElement(stringArray[i], null));
}
stringArray= fContext.getTemplateParser().getBody();
Object[] members= fContext.getSelectedMembers();
for (int i= 0; i < members.length; i++) {
if (!fContext.isSkipNulls() || getMemberType(members[i]).isPrimitive())
addMember(members[i], i != members.length - 1);
else
addMemberCheckNull(members[i], i != members.length - 1);
}
stringArray= fContext.getTemplateParser().getEnding();
for (int i= 0; i < stringArray.length; i++) {
addElement(processElement(stringArray[i], null));
}
complete();
return toStringMethod;
}
public List<MethodDeclaration> generateHelperMethods() {
List<MethodDeclaration> result= new ArrayList<>();
if (needCollectionToStringMethod)
result.add(createHelperToStringMethod(false));
if (!typesThatNeedArrayToStringMethod.isEmpty())
result.add(createHelperToStringMethod(true));
return result;
}
protected void () throws CoreException {
ITypeBinding object= fAst.resolveWellKnownType("java.lang.Object");
IMethodBinding[] objms= object.getDeclaredMethods();
IMethodBinding objectMethod= null;
for (int i= 0; i < objms.length; i++) {
if (objms[i].getName().equals(METHODNAME_TO_STRING) && objms[i].getParameterTypes().length == 0)
objectMethod= objms[i];
}
if (fContext.isCreateComments()) {
String docString= CodeGeneration.getMethodComment(fContext.getCompilationUnit(), fContext.getTypeBinding().getQualifiedName(), toStringMethod, objectMethod, StubUtility
.getLineDelimiterUsed(fContext.getCompilationUnit()));
if (docString != null) {
Javadoc javadoc= (Javadoc)fContext.getASTRewrite().createStringPlaceholder(docString, ASTNode.JAVADOC);
toStringMethod.setJavadoc(javadoc);
}
}
StubUtility2Core.addOverrideAnnotation(fContext.getCodeGenerationSettings(), fContext.getTypeBinding().getJavaElement().getJavaProject(), fContext.getASTRewrite(), fContext.getImportRewrite(), toStringMethod, objectMethod.getDeclaringClass().isInterface(), null);
}
protected MethodDeclaration createHelperToStringMethod(boolean array) {
final String iteratorName= createNameSuggestion("iterator", NamingConventions.VK_LOCAL);
final String appendMethodName= "append";
final String indexName= createNameSuggestion("i", NamingConventions.VK_LOCAL);
final String lengthParamName= createNameSuggestion("len", NamingConventions.VK_PARAMETER);
final String maxLenParamName= createNameSuggestion(MAX_LEN_VARIABLE_NAME, NamingConventions.VK_PARAMETER);
String paramName;
String stringBuilderName;
String stringBuilderTypeName;
if (fContext.is50orHigher()) {
stringBuilderTypeName= "java.lang.StringBuilder";
stringBuilderName= createNameSuggestion("builder", NamingConventions.VK_LOCAL);
} else {
stringBuilderTypeName= "java.lang.StringBuffer";
stringBuilderName= createNameSuggestion("buffer", NamingConventions.VK_LOCAL);
}
MethodDeclaration arrayToStringMethod= fAst.newMethodDeclaration();
arrayToStringMethod.setName(fAst.newSimpleName(array ? HELPER_ARRAYTOSTRING_METHOD_NAME : HELPER_TOSTRING_METHOD_NAME));
arrayToStringMethod.modifiers().add(fAst.newModifier(Modifier.ModifierKeyword.PRIVATE_KEYWORD));
arrayToStringMethod.setReturnType2(fAst.newSimpleType(fAst.newName(TYPENAME_STRING)));
if (array) {
paramName= createNameSuggestion("array", NamingConventions.VK_PARAMETER);
SingleVariableDeclaration param= fAst.newSingleVariableDeclaration();
param.setType(fAst.newSimpleType(addImport("java.lang.Object")));
param.setName(fAst.newSimpleName(paramName));
arrayToStringMethod.parameters().add(param);
param= fAst.newSingleVariableDeclaration();
param.setType(fAst.newPrimitiveType(PrimitiveType.INT));
param.setName(fAst.newSimpleName(lengthParamName));
arrayToStringMethod.parameters().add(param);
} else {
paramName= createNameSuggestion("collection", NamingConventions.VK_PARAMETER);
SingleVariableDeclaration param= fAst.newSingleVariableDeclaration();
Type collectionType= fAst.newSimpleType(addImport("java.util.Collection"));
if (fContext.is50orHigher()) {
ParameterizedType genericType= fAst.newParameterizedType(collectionType);
genericType.typeArguments().add(fAst.newWildcardType());
param.setType(genericType);
} else {
param.setType(collectionType);
}
param.setName(fAst.newSimpleName(paramName));
arrayToStringMethod.parameters().add(param);
}
if (fContext.isLimitItems()) {
SingleVariableDeclaration param= fAst.newSingleVariableDeclaration();
param.setType(fAst.newPrimitiveType(PrimitiveType.INT));
param.setName(fAst.newSimpleName(maxLenParamName));
arrayToStringMethod.parameters().add(param);
}
Block body= fAst.newBlock();
arrayToStringMethod.setBody(body);
VariableDeclarationFragment fragment= fAst.newVariableDeclarationFragment();
fragment.setName(fAst.newSimpleName(stringBuilderName));
ClassInstanceCreation classInstance= fAst.newClassInstanceCreation();
classInstance.setType(fAst.newSimpleType(addImport(stringBuilderTypeName)));
fragment.setInitializer(classInstance);
VariableDeclarationStatement vStatement= fAst.newVariableDeclarationStatement(fragment);
vStatement.setType(fAst.newSimpleType(addImport(stringBuilderTypeName)));
body.statements().add(vStatement);
if (array && fContext.isLimitItems()) {
MethodInvocation minInvocation= createMethodInvocation(addImport("java.lang.Math"), "min", fAst.newSimpleName(lengthParamName));
minInvocation.arguments().add(fAst.newSimpleName(maxLenParamName));
Assignment lengthAssignment= fAst.newAssignment();
lengthAssignment.setLeftHandSide(fAst.newSimpleName(lengthParamName));
lengthAssignment.setRightHandSide(minInvocation);
body.statements().add(fAst.newExpressionStatement(lengthAssignment));
}
StringLiteral literal= fAst.newStringLiteral();
literal.setLiteralValue("[");
body.statements().add(fAst.newExpressionStatement(createMethodInvocation(stringBuilderName, appendMethodName, literal)));
ForStatement forStatement= fAst.newForStatement();
Block forBlock= fAst.newBlock();
forStatement.setBody(forBlock);
VariableDeclarationFragment indexDeclFragment= fAst.newVariableDeclarationFragment();
indexDeclFragment.setName(fAst.newSimpleName(indexName));
indexDeclFragment.setInitializer(fAst.newNumberLiteral("0"));
VariableDeclarationExpression indexDeclExpression= fAst.newVariableDeclarationExpression(indexDeclFragment);
indexDeclExpression.setType(fAst.newPrimitiveType(PrimitiveType.INT));
PostfixExpression postfixExpr= fAst.newPostfixExpression();
postfixExpr.setOperand(fAst.newSimpleName(indexName));
postfixExpr.setOperator(org.eclipse.jdt.core.dom.PostfixExpression.Operator.INCREMENT);
forStatement.updaters().add(postfixExpr);
IfStatement ifStatement= fAst.newIfStatement();
ifStatement.setExpression(createInfixExpression(fAst.newSimpleName(indexName), Operator.GREATER, fAst.newNumberLiteral(String.valueOf(0))));
literal= fAst.newStringLiteral();
literal.setLiteralValue(", ");
ifStatement.setThenStatement(createOneStatementBlock(createMethodInvocation(stringBuilderName, appendMethodName, literal)));
forBlock.statements().add(ifStatement);
if (array) {
forStatement.initializers().add(indexDeclExpression);
forStatement.setExpression(createInfixExpression(fAst.newSimpleName(indexName), Operator.LESS, fAst.newSimpleName(lengthParamName)));
for (Iterator<ITypeBinding> iterator= typesThatNeedArrayToStringMethod.iterator(); iterator.hasNext();) {
ITypeBinding typeBinding= iterator.next();
String typeName= typeBinding.getName();
PrimitiveType.Code code= null;
if (typeName.equals("byte")) code= PrimitiveType.BYTE;
if (typeName.equals("short")) code= PrimitiveType.SHORT;
if (typeName.equals("char")) code= PrimitiveType.CHAR;
if (typeName.equals("int")) code= PrimitiveType.INT;
if (typeName.equals("long")) code= PrimitiveType.LONG;
if (typeName.equals("float")) code= PrimitiveType.FLOAT;
if (typeName.equals("double")) code= PrimitiveType.DOUBLE;
if (typeName.equals("boolean")) code= PrimitiveType.BOOLEAN;
if (code == null && !typeName.equals("Object"))continue;
InstanceofExpression instanceOf= fAst.newInstanceofExpression();
instanceOf.setLeftOperand(fAst.newSimpleName(paramName));
instanceOf.setRightOperand(fAst.newArrayType(code != null ? (Type)fAst.newPrimitiveType(code) : fAst.newSimpleType(addImport("java.lang.Object"))));
ifStatement= fAst.newIfStatement();
ifStatement.setExpression(instanceOf);
CastExpression arrayCast= fAst.newCastExpression();
arrayCast.setExpression(fAst.newSimpleName(paramName));
arrayCast.setType(fAst.newArrayType(code != null ? (Type)fAst.newPrimitiveType(code) : fAst.newSimpleType(addImport("java.lang.Object"))));
ParenthesizedExpression parenthesizedCast= fAst.newParenthesizedExpression();
parenthesizedCast.setExpression(arrayCast);
ArrayAccess arrayAccess= fAst.newArrayAccess();
arrayAccess.setArray(parenthesizedCast);
arrayAccess.setIndex(fAst.newSimpleName(indexName));
ifStatement.setThenStatement(createOneStatementBlock(createMethodInvocation(stringBuilderName, appendMethodName, arrayAccess)));
forBlock.statements().add(ifStatement);
}
} else {
body.statements().add(fAst.newExpressionStatement(indexDeclExpression));
fragment= fAst.newVariableDeclarationFragment();
fragment.setName(fAst.newSimpleName(iteratorName));
fragment.setInitializer(createMethodInvocation(paramName, "iterator", null));
VariableDeclarationExpression vExpression= fAst.newVariableDeclarationExpression(fragment);
SimpleType iteratorType= fAst.newSimpleType(addImport("java.util.Iterator"));
if (fContext.is50orHigher()) {
ParameterizedType pType= fAst.newParameterizedType(iteratorType);
pType.typeArguments().add(fAst.newWildcardType());
vExpression.setType(pType);
} else {
vExpression.setType(iteratorType);
}
forStatement.initializers().add(vExpression);
Expression indexExpression= createInfixExpression(fAst.newSimpleName(indexName), Operator.LESS, fAst.newSimpleName(maxLenParamName));
forStatement.setExpression(createInfixExpression(createMethodInvocation(iteratorName, "hasNext", null), Operator.CONDITIONAL_AND, indexExpression));
MethodInvocation nextInvocation= createMethodInvocation(iteratorName, "next", null);
forBlock.statements().add(fAst.newExpressionStatement(createMethodInvocation(stringBuilderName, appendMethodName, nextInvocation)));
}
body.statements().add(forStatement);
literal= fAst.newStringLiteral();
literal.setLiteralValue("]");
body.statements().add(fAst.newExpressionStatement(createMethodInvocation(stringBuilderName, appendMethodName, literal)));
ReturnStatement returnStatement= fAst.newReturnStatement();
returnStatement.setExpression(createMethodInvocation(stringBuilderName, "toString", null));
body.statements().add(returnStatement);
arrayToStringMethod.setProperty(OVERWRITE_METHOD_PROPERTY, Boolean.valueOf(array));
return arrayToStringMethod;
}
protected void initialize() {
needMaxLenVariable= false;
needCollectionToStringMethod= false;
typesThatNeedArrayToStringMethod= new ArrayList<>();
checkNeedForHelperMethods();
toStringMethod= fAst.newMethodDeclaration();
toStringMethod.modifiers().addAll(ASTNodeFactory.newModifiers(fAst, Modifier.PUBLIC));
toStringMethod.setName(fAst.newSimpleName(METHODNAME_TO_STRING));
toStringMethod.setConstructor(false);
toStringMethod.setReturnType2(fAst.newSimpleType(fAst.newName(TYPENAME_STRING)));
Block body= fAst.newBlock();
toStringMethod.setBody(body);
fMaxLenVariableName= createNameSuggestion(MAX_LEN_VARIABLE_NAME, NamingConventions.VK_LOCAL);
}
protected void complete() throws CoreException {
if (needMaxLenVariable) {
toStringMethod.getBody().statements().add(0, createMaxLenDeclaration());
}
createMethodComment();
toStringMethod.setProperty(OVERWRITE_METHOD_PROPERTY, Boolean.valueOf(true));
}
protected void checkNeedForHelperMethods() {
if ((!fContext.isLimitItems() && !fContext.isCustomArray()) || (fContext.isLimitItems() && fContext.getLimitItemsValue() == 0))
return;
boolean isNonPrimitive= false;
for (int i= 0; i < fContext.getSelectedMembers().length; i++) {
ITypeBinding memberType= getMemberType(fContext.getSelectedMembers()[i]);
boolean[] implementsInterfaces= implementsInterfaces(memberType.getErasure(), new String[] { "java.util.Collection", "java.util.List", "java.util.Map" });
boolean isCollection= implementsInterfaces[0];
boolean isList= implementsInterfaces[1];
boolean isMap= implementsInterfaces[2];
if (fContext.isLimitItems() && (isCollection || isMap) && !isList) {
needCollectionToStringMethod= true;
}
if (fContext.isCustomArray() && memberType.isArray()) {
ITypeBinding componentType= memberType.getComponentType();
if (componentType.isPrimitive() && (!fContext.is50orHigher() || (!fContext.is60orHigher() && fContext.isLimitItems()))) {
if (!typesThatNeedArrayToStringMethod.contains(componentType))
typesThatNeedArrayToStringMethod.add(componentType);
} else if (!componentType.isPrimitive())
isNonPrimitive= true;
}
}
if (!typesThatNeedArrayToStringMethod.isEmpty() && isNonPrimitive)
typesThatNeedArrayToStringMethod.add(fAst.resolveWellKnownType("java.lang.Object"));
}
protected Object processElement(String templateElement, Object member) {
Object result= templateElement;
if (templateElement == ToStringTemplateParser.OBJECT_NAME_VARIABLE) {
result= fContext.getTypeBinding().getName();
}
if (templateElement == ToStringTemplateParser.OBJECT_GET_NAME_VARIABLE) {
MethodInvocation getClassInvocation= fAst.newMethodInvocation();
if (fContext.isKeywordThis())
getClassInvocation.setExpression(fAst.newThisExpression());
getClassInvocation.setName(fAst.newSimpleName("getClass"));
MethodInvocation getNameInvocation= fAst.newMethodInvocation();
getNameInvocation.setExpression(getClassInvocation);
getNameInvocation.setName(fAst.newSimpleName("getName"));
result= getNameInvocation;
}
if (templateElement == ToStringTemplateParser.OBJECT_SUPER_TOSTRING_VARIABLE) {
SuperMethodInvocation superToStringInvocation= fAst.newSuperMethodInvocation();
superToStringInvocation.setName(fAst.newSimpleName(METHODNAME_TO_STRING));
result= superToStringInvocation;
}
if (templateElement == ToStringTemplateParser.OBJECT_HASHCODE_VARIABLE) {
MethodInvocation hashCodeInvocation= fAst.newMethodInvocation();
if (fContext.isKeywordThis())
hashCodeInvocation.setExpression(fAst.newThisExpression());
hashCodeInvocation.setName(fAst.newSimpleName("hashCode"));
result= hashCodeInvocation;
}
if (templateElement == ToStringTemplateParser.OBJECT_SYSTEM_HASHCODE_VARIABLE) {
result= createMethodInvocation(addImport("java.lang.System"), "identityHashCode", fAst.newThisExpression());
}
if (templateElement == ToStringTemplateParser.MEMBER_NAME_VARIABLE || templateElement == ToStringTemplateParser.MEMBER_NAME_PARENTHESIS_VARIABLE) {
result= getMemberName(member, templateElement);
}
if (templateElement == ToStringTemplateParser.MEMBER_VALUE_VARIABLE) {
result= createMemberAccessExpression(member, false, fContext.isSkipNulls());
}
if (result instanceof StringLiteral)
return ((StringLiteral)result).getLiteralValue();
else
return result;
}
protected abstract void addElement(Object element);
protected void addMember(Object member, boolean addSeparator) {
String[] stringArray= fContext.getTemplateParser().getBody();
for (int i= 0; i < stringArray.length; i++) {
addElement(processElement(stringArray[i], member));
}
if (addSeparator)
addElement(fContext.getTemplateParser().getSeparator());
}
protected void addMemberCheckNull(Object member, boolean addSeparator) {
addMember(member, addSeparator);
}
protected MethodInvocation createMethodInvocation(Expression expression, String methodName, Expression argument) {
MethodInvocation invocation= fAst.newMethodInvocation();
invocation.setExpression(expression);
invocation.setName(fAst.newSimpleName(methodName));
if (argument != null)
invocation.arguments().add(argument);
return invocation;
}
protected MethodInvocation createMethodInvocation(String receiver, String methodName, Expression argument) {
return createMethodInvocation(fAst.newName(receiver), methodName, argument);
}
protected Statement createOneStatementBlock(Expression expression) {
if (fContext.isForceBlocks()) {
Block forBlock= fAst.newBlock();
forBlock.statements().add(fAst.newExpressionStatement(expression));
return forBlock;
} else {
return fAst.newExpressionStatement(expression);
}
}
protected InfixExpression createInfixExpression(Expression leftOperand, Operator operator, Expression rightOperand) {
InfixExpression expression= fAst.newInfixExpression();
expression.setLeftOperand(leftOperand);
expression.setOperator(operator);
expression.setRightOperand(rightOperand);
return expression;
}
protected VariableDeclarationStatement createMaxLenDeclaration() {
VariableDeclarationFragment fragment= fAst.newVariableDeclarationFragment();
fragment.setName(fAst.newSimpleName(fMaxLenVariableName));
fragment.setInitializer(fAst.newNumberLiteral(String.valueOf(fContext.getLimitItemsValue())));
VariableDeclarationStatement declExpression= fAst.newVariableDeclarationStatement(fragment);
declExpression.setType(fAst.newPrimitiveType(PrimitiveType.INT));
declExpression.modifiers().add(fAst.newModifier(ModifierKeyword.FINAL_KEYWORD));
return declExpression;
}
protected Expression createMemberAccessExpression(Object member, boolean ignoreArraysCollections, boolean ignoreNulls) {
if (!ignoreArraysCollections) {
ITypeBinding memberType= getMemberType(member);
boolean isArray= memberType.isArray();
boolean[] implementsInterfaces= implementsInterfaces(memberType.getErasure(), new String[] { "java.util.Collection", "java.util.List", "java.util.Map" });
boolean isCollection= implementsInterfaces[0];
boolean isList= implementsInterfaces[1];
boolean isMap= implementsInterfaces[2];
if (isCollection || isMap || (isArray && fContext.isCustomArray())) {
Expression accessExpression= null;
if (fContext.isLimitItems()) {
if (fContext.getLimitItemsValue() == 0) {
accessExpression= fAst.newStringLiteral();
((StringLiteral)accessExpression).setLiteralValue("[]");
} else {
if (isList && !needCollectionToStringMethod) {
MethodInvocation memberSizeInvocation= fAst.newMethodInvocation();
memberSizeInvocation.setExpression(createMemberAccessExpression(member, true, true));
memberSizeInvocation.setName(fAst.newSimpleName("size"));
accessExpression= createSubListInvocation(createMemberAccessExpression(member, true, true), memberSizeInvocation);
needMaxLenVariable= true;
} else if (isCollection || isMap) {
Expression memberAccess= createMemberAccessExpression(member, true, true);
if (isMap) {
MethodInvocation entrySetInvocation= fAst.newMethodInvocation();
entrySetInvocation.setExpression(memberAccess);
entrySetInvocation.setName(fAst.newSimpleName("entrySet"));
memberAccess= entrySetInvocation;
}
MethodInvocation toStringInvocation= fAst.newMethodInvocation();
if (fContext.isKeywordThis())
toStringInvocation.setExpression(fAst.newThisExpression());
toStringInvocation.setName(fAst.newSimpleName(HELPER_TOSTRING_METHOD_NAME));
toStringInvocation.arguments().add(memberAccess);
toStringInvocation.arguments().add(fAst.newSimpleName(fMaxLenVariableName));
needMaxLenVariable= true;
accessExpression= toStringInvocation;
} else if (isArray) {
FieldAccess lengthAccess= fAst.newFieldAccess();
lengthAccess.setExpression(createMemberAccessExpression(member, true, true));
lengthAccess.setName(fAst.newSimpleName("length"));
ITypeBinding arrayComponentType= memberType.getComponentType();
if (!arrayComponentType.isPrimitive() && typesThatNeedArrayToStringMethod.isEmpty()) {
MethodInvocation asListInvocation= createMethodInvocation(addImport("java.util.Arrays"), "asList", createMemberAccessExpression(member, true, true));
accessExpression= createSubListInvocation(asListInvocation, lengthAccess);
} else {
if (fContext.is60orHigher()) {
Name arraysImport= addImport("java.util.Arrays");
MethodInvocation minInvocation= createMethodInvocation(addImport("java.lang.Math"), "min", lengthAccess);
minInvocation.arguments().add(fAst.newSimpleName(fMaxLenVariableName));
needMaxLenVariable= true;
MethodInvocation copyOfInvocation= createMethodInvocation(arraysImport, "copyOf", createMemberAccessExpression(member, true, true));
copyOfInvocation.arguments().add(minInvocation);
Name arraysImportCopy= (Name)ASTNode.copySubtree(fAst, arraysImport);
accessExpression= createMethodInvocation(arraysImportCopy, "toString", copyOfInvocation);
} else {
MethodInvocation arrayToStringInvocation= fAst.newMethodInvocation();
if (fContext.isKeywordThis())
arrayToStringInvocation.setExpression(fAst.newThisExpression());
arrayToStringInvocation.setName(fAst.newSimpleName(HELPER_ARRAYTOSTRING_METHOD_NAME));
arrayToStringInvocation.arguments().add(createMemberAccessExpression(member, true, true));
arrayToStringInvocation.arguments().add(lengthAccess);
arrayToStringInvocation.arguments().add(fAst.newSimpleName(fMaxLenVariableName));
needMaxLenVariable= true;
accessExpression= arrayToStringInvocation;
}
}
}
}
} else {
if (isArray && fContext.isCustomArray()) {
if (fContext.is50orHigher()) {
return createMethodInvocation(addImport("java.util.Arrays"), "toString", createMemberAccessExpression(member, true, true));
} else {
ITypeBinding arrayComponentType= memberType.getComponentType();
if (!arrayComponentType.isPrimitive() && typesThatNeedArrayToStringMethod.isEmpty()) {
accessExpression= createMethodInvocation(addImport("java.util.Arrays"), "asList", createMemberAccessExpression(member, true, true));
} else {
FieldAccess lengthAccess= fAst.newFieldAccess();
lengthAccess.setExpression(createMemberAccessExpression(member, true, true));
lengthAccess.setName(fAst.newSimpleName("length"));
MethodInvocation arrayToStringInvocation= fAst.newMethodInvocation();
if (fContext.isKeywordThis())
arrayToStringInvocation.setExpression(fAst.newThisExpression());
arrayToStringInvocation.setName(fAst.newSimpleName(HELPER_ARRAYTOSTRING_METHOD_NAME));
arrayToStringInvocation.arguments().add(createMemberAccessExpression(member, true, true));
arrayToStringInvocation.arguments().add(lengthAccess);
accessExpression= arrayToStringInvocation;
}
}
}
}
if (accessExpression != null) {
if (!ignoreNulls) {
ConditionalExpression conditional= fAst.newConditionalExpression();
conditional.setExpression(createInfixExpression(createMemberAccessExpression(member, true, true), Operator.NOT_EQUALS, fAst.newNullLiteral()));
conditional.setThenExpression(accessExpression);
conditional.setElseExpression(fAst.newNullLiteral());
return conditional;
}
return accessExpression;
}
}
}
if (member instanceof IVariableBinding) {
if (fContext.isKeywordThis()) {
FieldAccess fa= fAst.newFieldAccess();
fa.setExpression(fAst.newThisExpression());
fa.setName(fAst.newSimpleName(((IVariableBinding)member).getName()));
return fa;
}
return fAst.newSimpleName(((IVariableBinding)member).getName());
}
if (member instanceof IMethodBinding) {
if (((IMethodBinding)member).getName().equals(METHODNAME_TO_STRING)) {
SuperMethodInvocation invocation= fAst.newSuperMethodInvocation();
invocation.setName(fAst.newSimpleName(((IMethodBinding)member).getName()));
return invocation;
}
MethodInvocation invocation= fAst.newMethodInvocation();
if (fContext.isKeywordThis()) {
invocation.setExpression(fAst.newThisExpression());
}
invocation.setName(fAst.newSimpleName(((IMethodBinding)member).getName()));
return invocation;
}
return null;
}
protected Expression createSubListInvocation(Expression memberAccess, Expression sizeAccess) {
MethodInvocation subListInvocation= fAst.newMethodInvocation();
subListInvocation.setExpression(memberAccess);
subListInvocation.setName(fAst.newSimpleName("subList"));
subListInvocation.arguments().add(fAst.newNumberLiteral(String.valueOf(0)));
MethodInvocation minInvocation= createMethodInvocation(addImport("java.lang.Math"), "min", sizeAccess);
minInvocation.arguments().add(fAst.newSimpleName(fMaxLenVariableName));
subListInvocation.arguments().add(minInvocation);
needMaxLenVariable= true;
return subListInvocation;
}
protected Name addImport(String typeName) {
String importedName= fContext.getImportRewrite().addImport(typeName);
return fAst.newName(importedName);
}
private Set<String> excluded;
protected String createNameSuggestion(String baseName, int variableKind) {
if (excluded == null) {
excluded= new HashSet<>();
IVariableBinding[] fields= fContext.getTypeBinding().getDeclaredFields();
for (int i= 0; i < fields.length; i++) {
excluded.add(fields[i].getName());
}
ITypeBinding superType= fContext.getTypeBinding().getSuperclass();
while (superType != null) {
fields= superType.getDeclaredFields();
for (int i= 0; i < fields.length; i++) {
if (!Modifier.isPrivate(fields[i].getModifiers())) {
excluded.add(fields[i].getName());
}
}
superType= superType.getSuperclass();
}
ITypeBinding[] types= fContext.getTypeBinding().getDeclaredTypes();
for (int i= 0; i < types.length; i++) {
excluded.add(types[i].getName());
}
superType= fContext.getTypeBinding().getSuperclass();
while (superType != null) {
types= superType.getDeclaredTypes();
for (int i= 0; i < types.length; i++) {
if (!Modifier.isPrivate(types[i].getModifiers())) {
excluded.add(types[i].getName());
}
}
superType= superType.getSuperclass();
}
}
return StubUtility.getVariableNameSuggestions(variableKind, fContext.getCompilationUnit().getJavaProject(), baseName, 0, excluded, true)[0];
}
protected boolean[] implementsInterfaces(ITypeBinding memberType, String[] interfaceNames) {
boolean[] result= new boolean[interfaceNames.length];
for (int i= 0; i < interfaceNames.length; i++) {
if (memberType.getQualifiedName().equals(interfaceNames[i]))
result[i]= true;
}
ITypeBinding[] interfaces= memberType.getInterfaces();
for (int i= 0; i < interfaces.length; i++) {
boolean[] deeper= implementsInterfaces(interfaces[i].getErasure(), interfaceNames);
for (int j= 0; j < interfaceNames.length; j++) {
result[j]= result[j] || deeper[j];
}
}
return result;
}
protected String getMemberName(Object member, String templateElement) {
if (member instanceof IVariableBinding) {
return ((IVariableBinding)member).getName();
}
if (member instanceof IMethodBinding) {
String result= ((IMethodBinding)member).getName();
if (templateElement == ToStringTemplateParser.MEMBER_NAME_PARENTHESIS_VARIABLE)
result+= "()";
return result;
}
return null;
}
protected ITypeBinding getMemberType(Object member) {
if (member instanceof IVariableBinding) {
return ((IVariableBinding)member).getType();
}
if (member instanceof IMethodBinding) {
return ((IMethodBinding)member).getReturnType();
}
return null;
}
public void setContext(ToStringGenerationContext context) {
fContext= context;
fAst= fContext.getAST();
excluded= null;
}
public ToStringGenerationContext getContext() {
return fContext;
}
}