diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/GenerateToStringHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/GenerateToStringHandler.java index acc710b339..9191f457b9 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/GenerateToStringHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/GenerateToStringHandler.java @@ -13,18 +13,28 @@ package org.eclipse.jdt.ls.core.internal.handlers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + import org.apache.commons.lang3.StringUtils; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; +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.Modifier; import org.eclipse.jdt.core.dom.NodeFinder; import org.eclipse.jdt.core.manipulation.CoreASTProvider; import org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.GenerateToStringOperation; @@ -34,6 +44,7 @@ import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; import org.eclipse.jdt.ls.core.internal.corrections.DiagnosticsHelper; +import org.eclipse.jdt.ls.core.internal.handlers.JdtDomModels.BindingComparator; import org.eclipse.jdt.ls.core.internal.handlers.JdtDomModels.LspVariableBinding; import org.eclipse.jdt.ls.core.internal.preferences.Preferences; import org.eclipse.jdt.ls.core.internal.text.correction.CodeActionUtility; @@ -67,23 +78,89 @@ public static CheckToStringResponse checkToStringStatus(IType type, IProgressMon if (type == null) { return response; } - try { CompilationUnit astRoot = CoreASTProvider.getInstance().getAST(type.getCompilationUnit(), CoreASTProvider.WAIT_YES, monitor); if (astRoot == null) { return response; } - ITypeBinding typeBinding = ASTNodes.getTypeBinding(astRoot, type); if (typeBinding != null) { response.type = type.getTypeQualifiedName(); - response.fields = JdtDomModels.getDeclaredFields(typeBinding, false); + IVariableBinding[] fields = typeBinding.getDeclaredFields(); + HashMap fieldsToBindingsMap = new HashMap<>(); + HashMap selectedFieldsToBindingsMap = new HashMap<>(); + for (IVariableBinding variableBinding : fields) { + if (!Modifier.isStatic(variableBinding.getModifiers())) { + fieldsToBindingsMap.put(variableBinding.getJavaElement(), variableBinding); + if (!Modifier.isTransient(variableBinding.getModifiers())) { + selectedFieldsToBindingsMap.put(variableBinding.getJavaElement(), variableBinding); + } + } + } + final IField[] allFields; + if (type.isRecord()) { + allFields = type.getRecordComponents(); + } else { + allFields = type.getFields(); + } + List fieldsToBindings = new ArrayList<>(); + List selectedFieldsToBindings = new ArrayList<>(); + for (IMember member : allFields) { + IVariableBinding memberBinding = selectedFieldsToBindingsMap.remove(member); + if (memberBinding != null) { + selectedFieldsToBindings.add(memberBinding); + fieldsToBindingsMap.remove(member); + } + } + for (IMember member : allFields) { + IVariableBinding memberBinding = fieldsToBindingsMap.remove(member); + if (memberBinding != null) { + fieldsToBindings.add(memberBinding); + } + } + selectedFieldsToBindings.sort(new BindingComparator()); + fieldsToBindings.sort(new BindingComparator()); + List inheritedFieldsToBindings = new ArrayList<>(); + ITypeBinding superTypeBinding = typeBinding; + while ((superTypeBinding = superTypeBinding.getSuperclass()) != null) { + for (IVariableBinding candidateField : superTypeBinding.getDeclaredFields()) { + if (!Modifier.isPrivate(candidateField.getModifiers()) && !Modifier.isStatic(candidateField.getModifiers()) && !JdtDomModels.contains(fieldsToBindings, candidateField)) { + inheritedFieldsToBindings.add(candidateField); + } + } + } + inheritedFieldsToBindings.sort(new BindingComparator()); + List methodsToBindings = new ArrayList<>(); + for (IMethodBinding candidateMethod : typeBinding.getDeclaredMethods()) { + if (!Modifier.isStatic(candidateMethod.getModifiers()) && candidateMethod.getParameterTypes().length == 0 && !"void".equals(candidateMethod.getReturnType().getName()) && !"toString".equals(candidateMethod.getName()) //$NON-NLS-1$//$NON-NLS-2$ + && !"clone".equals(candidateMethod.getName())) { //$NON-NLS-1$ + methodsToBindings.add(candidateMethod); + } + } + methodsToBindings.sort(new BindingComparator()); + superTypeBinding = typeBinding; + List inheritedMethodsToBindings = new ArrayList<>(); + while ((superTypeBinding = superTypeBinding.getSuperclass()) != null) { + for (IMethodBinding candidateMethod : superTypeBinding.getDeclaredMethods()) { + if (!Modifier.isPrivate(candidateMethod.getModifiers()) && !Modifier.isStatic(candidateMethod.getModifiers()) && candidateMethod.getParameterTypes().length == 0 + && !"void".equals(candidateMethod.getReturnType().getName()) && !JdtDomModels.contains(methodsToBindings, candidateMethod) && !"clone".equals(candidateMethod.getName())) { //$NON-NLS-1$ //$NON-NLS-2$ + inheritedMethodsToBindings.add(candidateMethod); + } + } + } + inheritedMethodsToBindings.sort(new BindingComparator()); + List result = new LinkedList<>(); + result.addAll(selectedFieldsToBindings.stream().map(f -> new LspVariableBinding(f, true)).toList()); + result.addAll(fieldsToBindings.stream().map(f -> new LspVariableBinding(f)).toList()); + result.addAll(inheritedFieldsToBindings.stream().map(f -> new LspVariableBinding(f)).toList()); + result.addAll(methodsToBindings.stream().map(f -> new LspVariableBinding(f)).toList()); + result.addAll(inheritedMethodsToBindings.stream().map(f -> new LspVariableBinding(f)).toList()); + response.fields = result.toArray(new LspVariableBinding[0]); response.exists = CodeActionUtility.hasMethod(type, METHODNAME_TOSTRING); } } catch (JavaModelException e) { JavaLanguageServerPlugin.logException("Failed to check toString status", e); } - return response; } @@ -144,7 +221,7 @@ public static TextEdit generateToString(IType type, LspVariableBinding[] fields, ITypeBinding typeBinding = ASTNodes.getTypeBinding(astRoot, type); if (typeBinding != null) { - IVariableBinding[] selectedFields = JdtDomModels.convertToVariableBindings(typeBinding, fields); + IBinding[] selectedFields = JdtDomModels.convertToBindings(typeBinding, fields); GenerateToStringOperation operation = GenerateToStringOperation.createOperation(typeBinding, selectedFields, astRoot, insertPosition, settings, false, false); operation.run(null); return operation.getResultingEdit(); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JdtDomModels.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JdtDomModels.java index 7efb3ee7ff..d58ccb135a 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JdtDomModels.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JdtDomModels.java @@ -13,13 +13,17 @@ package org.eclipse.jdt.ls.core.internal.handlers; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.List; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.JavaModelException; +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; @@ -34,20 +38,30 @@ public static class LspVariableBinding { public String type; public boolean isField; public boolean isSelected; + public String[] parameters; public LspVariableBinding(IVariableBinding binding) { + this(binding, false); + } + + public LspVariableBinding(IVariableBinding binding, boolean isSelected) { this.bindingKey = binding.getKey(); this.name = binding.getName(); this.type = binding.getType().getName(); this.isField = binding.isField(); - this.isSelected = false; + this.isSelected = isSelected; } - public LspVariableBinding(IVariableBinding binding, boolean isSelected) { + public LspVariableBinding(IMethodBinding binding) { + this(binding, false); + } + + public LspVariableBinding(IMethodBinding binding, boolean isSelected) { this.bindingKey = binding.getKey(); this.name = binding.getName(); - this.type = binding.getType().getName(); - this.isField = binding.isField(); + this.type = binding.getReturnType().getName(); + this.isField = false; + this.parameters = Stream.of(binding.getParameterTypes()).map(type -> type.getName()).toArray(String[]::new); this.isSelected = isSelected; } } @@ -64,23 +78,101 @@ public LspMethodBinding(IMethodBinding binding) { } } + public static IBinding[] convertToBindings(ITypeBinding typeBinding, LspVariableBinding[] fields) { + Set bindingKeys = Stream.of(fields).map((field) -> field.bindingKey).collect(Collectors.toSet()); + IVariableBinding[] bindings = typeBinding.getDeclaredFields(); + List fieldsToBindings = new ArrayList<>(); + for (IVariableBinding variableBinding : bindings) { + if (!Modifier.isStatic(variableBinding.getModifiers())) { + fieldsToBindings.add(variableBinding); + } + } + ITypeBinding superTypeBinding = typeBinding; + while ((superTypeBinding = superTypeBinding.getSuperclass()) != null) { + for (IVariableBinding candidateField : superTypeBinding.getDeclaredFields()) { + if (!Modifier.isPrivate(candidateField.getModifiers()) && !Modifier.isStatic(candidateField.getModifiers()) && !contains(fieldsToBindings, candidateField)) { + fieldsToBindings.add(candidateField); + } + } + } + List methodsToBindings = new ArrayList<>(); + for (IMethodBinding candidateMethod : typeBinding.getDeclaredMethods()) { + if (!Modifier.isStatic(candidateMethod.getModifiers()) && candidateMethod.getParameterTypes().length == 0 && !"void".equals(candidateMethod.getReturnType().getName()) && !"toString".equals(candidateMethod.getName()) //$NON-NLS-1$//$NON-NLS-2$ + && !"clone".equals(candidateMethod.getName())) { //$NON-NLS-1$ + methodsToBindings.add(candidateMethod); + } + } + superTypeBinding = typeBinding; + while ((superTypeBinding = superTypeBinding.getSuperclass()) != null) { + for (IMethodBinding candidateMethod : superTypeBinding.getDeclaredMethods()) { + if (!Modifier.isPrivate(candidateMethod.getModifiers()) && !Modifier.isStatic(candidateMethod.getModifiers()) && candidateMethod.getParameterTypes().length == 0 && !"void".equals(candidateMethod.getReturnType().getName()) //$NON-NLS-1$ + && !JdtDomModels.contains(methodsToBindings, candidateMethod) && !"clone".equals(candidateMethod.getName())) { //$NON-NLS-1$ + methodsToBindings.add(candidateMethod); + } + } + } + IBinding[] fieldsMembers = fieldsToBindings.stream().sorted(new BindingComparator()).filter(f -> bindingKeys.contains(f.getKey())).toArray(IVariableBinding[]::new); + IBinding[] methodsMembers = methodsToBindings.stream().sorted(new BindingComparator()).filter(f -> bindingKeys.contains(f.getKey())).toArray(IMethodBinding[]::new); + IBinding[] result; + if (methodsMembers.length == 0) { + result = fieldsMembers; + } else if (fieldsMembers.length == 0) { + result = methodsMembers; + } else { + result = new IBinding[fieldsMembers.length + methodsMembers.length]; + System.arraycopy(fieldsMembers, 0, result, 0, fieldsMembers.length); + System.arraycopy(methodsMembers, 0, result, fieldsMembers.length, methodsMembers.length); + } + return result; + } + public static IVariableBinding[] convertToVariableBindings(ITypeBinding typeBinding, LspVariableBinding[] fields) { Set bindingKeys = Stream.of(fields).map((field) -> field.bindingKey).collect(Collectors.toSet()); - return Arrays.stream(typeBinding.getDeclaredFields()).sorted(new VariableBindingComparator()).filter(f -> bindingKeys.contains(f.getKey())).toArray(IVariableBinding[]::new); + IVariableBinding[] bindings = typeBinding.getDeclaredFields(); + List members = new ArrayList<>(); + for (IVariableBinding variableBinding : bindings) { + if (!Modifier.isStatic(variableBinding.getModifiers())) { + members.add(variableBinding); + } + } + return members.stream().sorted(new BindingComparator()).filter(f -> bindingKeys.contains(f.getKey())).toArray(IVariableBinding[]::new); + } + + public static boolean contains(List inheritedFields, T member) { + for (T object : inheritedFields) { + if (object instanceof IVariableBinding && member instanceof IVariableBinding) { + if (((IVariableBinding) object).getName().equals(((IVariableBinding) member).getName())) { + return true; + } + } + if (object instanceof IMethodBinding && member instanceof IMethodBinding) { + if (((IMethodBinding) object).getName().equals(((IMethodBinding) member).getName())) { + return true; + } + } + } + return false; } public static LspVariableBinding[] getDeclaredFields(ITypeBinding typeBinding, boolean includeStatic) { - return Arrays.stream(typeBinding.getDeclaredFields()).sorted(new VariableBindingComparator()).filter(f -> includeStatic || !Modifier.isStatic(f.getModifiers())).map(f -> new LspVariableBinding(f)).toArray(LspVariableBinding[]::new); + return Arrays.stream(typeBinding.getDeclaredFields()).sorted(new BindingComparator()).filter(f -> includeStatic || !Modifier.isStatic(f.getModifiers())).map(f -> new LspVariableBinding(f)).toArray(LspVariableBinding[]::new); } - public static class VariableBindingComparator implements Comparator { + public static class BindingComparator implements Comparator { @Override - public int compare(IVariableBinding a, IVariableBinding b) { + public int compare(IBinding a, IBinding b) { try { - return JDTUtils.getNameRange(a.getJavaElement()).getOffset() - JDTUtils.getNameRange(b.getJavaElement()).getOffset(); + ISourceRange nameRangeA = a.getJavaElement() == null ? null : JDTUtils.getNameRange(a.getJavaElement()); + ISourceRange nameRangeB = b.getJavaElement() == null ? null : JDTUtils.getNameRange(b.getJavaElement()); + if (nameRangeA != null && nameRangeB != null) { + return nameRangeA.getOffset() - nameRangeB.getOffset(); + } else { + return 0; + } } catch (JavaModelException e) { return 0; } } } + } diff --git a/org.eclipse.jdt.ls.tests/projects/eclipse/hello/src/org/sample/Child.java b/org.eclipse.jdt.ls.tests/projects/eclipse/hello/src/org/sample/Child.java new file mode 100644 index 0000000000..fa700f202f --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/eclipse/hello/src/org/sample/Child.java @@ -0,0 +1,5 @@ +package org.sample; + +public class Child extends Parent { + protected String name; +} diff --git a/org.eclipse.jdt.ls.tests/projects/eclipse/hello/src/org/sample/Parent.java b/org.eclipse.jdt.ls.tests/projects/eclipse/hello/src/org/sample/Parent.java new file mode 100644 index 0000000000..d295238944 --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/eclipse/hello/src/org/sample/Parent.java @@ -0,0 +1,5 @@ +package org.sample; + +public class Parent { + protected String parentName; +} diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/GenerateToStringHandlerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/GenerateToStringHandlerTest.java index 8eb3e40716..2394c3ad97 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/GenerateToStringHandlerTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/GenerateToStringHandlerTest.java @@ -13,6 +13,7 @@ package org.eclipse.jdt.ls.core.internal.handlers; +import static org.eclipse.jdt.ls.core.internal.WorkspaceHelper.getProject; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -20,11 +21,14 @@ import java.io.IOException; +import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.GenerateToStringOperation; import org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.ToStringGenerationSettingsCore; @@ -34,6 +38,7 @@ import org.eclipse.jdt.ls.core.internal.CodeActionUtil; import org.eclipse.jdt.ls.core.internal.codemanipulation.AbstractSourceTestCase; import org.eclipse.jdt.ls.core.internal.handlers.GenerateToStringHandler.CheckToStringResponse; +import org.eclipse.jdt.ls.core.internal.handlers.JdtDomModels.LspVariableBinding; import org.eclipse.lsp4j.CodeActionParams; import org.eclipse.lsp4j.Range; import org.eclipse.text.edits.TextEdit; @@ -56,7 +61,7 @@ public void testGenerateToStringStatus() throws JavaModelException { CheckToStringResponse response = GenerateToStringHandler.checkToStringStatus(params); assertEquals("B", response.type); assertNotNull(response.fields); - assertEquals(2, response.fields.length); + assertEquals(5, response.fields.length); assertFalse(response.exists); } @@ -79,7 +84,7 @@ public void testCheckToStringStatus_methodsExist() throws JavaModelException { CheckToStringResponse response = GenerateToStringHandler.checkToStringStatus(params); assertEquals("B", response.type); assertNotNull(response.fields); - assertEquals(2, response.fields.length); + assertEquals(5, response.fields.length); assertTrue(response.exists); } @@ -112,22 +117,22 @@ public void testGenerateToString() throws ValidateEditException, CoreException, generateToString(unit.findPrimaryType(), settings); /* @formatter:off */ - String expected = "package p;\r\n" + - "\r\n" + - "import java.util.Arrays;\r\n" + - "import java.util.List;\r\n" + - "\r\n" + - "public class B {\r\n" + - " private static String UUID = \"23434343\";\r\n" + - " String name;\r\n" + - " int id;\r\n" + - " List aList;\r\n" + - " String[] arrays;\r\n" + - " @Override\r\n" + - " public String toString() {\r\n" + - " return \"B [name=\" + name + \", id=\" + id + \", aList=\" + aList + \", arrays=\" + (arrays != null ? Arrays.asList(arrays) : null) + \"]\";\r\n" + - " }\r\n" + - "}"; + String expected = "package p;\r\n" + + "\r\n" + + "import java.util.Arrays;\r\n" + + "import java.util.List;\r\n" + + "\r\n" + + "public class B {\r\n" + + " private static String UUID = \"23434343\";\r\n" + + " String name;\r\n" + + " int id;\r\n" + + " List aList;\r\n" + + " String[] arrays;\r\n" + + " @Override\r\n" + + " public String toString() {\r\n" + + " return \"B [name=\" + name + \", id=\" + id + \", aList=\" + aList + \", arrays=\" + (arrays != null ? Arrays.asList(arrays) : null) + \", getClass()=\" + getClass() + \", hashCode()=\" + hashCode() + \", toString()=\" + super.toString() + \"]\";\r\n" + + " }\r\n" + + "}"; /* @formatter:on */ compareSource(expected, unit.getSource()); @@ -150,7 +155,7 @@ public void testGenerateToStringOrder() throws ValidateEditException, CoreExcept CheckToStringResponse response = GenerateToStringHandler.checkToStringStatus(params); assertEquals("B", response.type); assertNotNull(response.fields); - assertEquals(3, response.fields.length); + assertEquals(6, response.fields.length); assertFalse(response.exists); assertEquals("stringField", response.fields[0].name); assertEquals("intField", response.fields[1].name); @@ -169,18 +174,18 @@ public void testGenerateToStringOrder() throws ValidateEditException, CoreExcept generateToString(unit.findPrimaryType(), settings); /* @formatter:off */ - String expected = "package p;\r\n" + - "\r\n" + - "public class B {\r\n" + - " public String stringField;\r\n" + - " public int intField;\r\n" + - " public static int staticIntField;\r\n" + - " public boolean booleanField;\r\n" + - " @Override\r\n" + - " public String toString() {\r\n" + - " return \"B [stringField=\" + stringField + \", intField=\" + intField + \", booleanField=\" + booleanField + \"]\";\r\n" + - " }\r\n" + - "}"; + String expected = "package p;\r\n" + + "\r\n" + + "public class B {\r\n" + + " public String stringField;\r\n" + + " public int intField;\r\n" + + " public static int staticIntField;\r\n" + + " public boolean booleanField;\r\n" + + " @Override\r\n" + + " public String toString() {\r\n" + + " return \"B [stringField=\" + stringField + \", intField=\" + intField + \", booleanField=\" + booleanField + \", getClass()=\" + getClass() + \", hashCode()=\" + hashCode() + \", toString()=\" + super.toString() + \"]\";\r\n" + + " }\r\n" + + "}"; /* @formatter:on */ compareSource(expected, unit.getSource()); @@ -218,35 +223,42 @@ public void testGenerateToString_customizedSettings() throws ValidateEditExcepti generateToString(unit.findPrimaryType(), settings); /* @formatter:off */ - String expected = "package p;\r\n" + - "\r\n" + - "import java.util.List;\r\n" + - "\r\n" + - "public class B {\r\n" + - " private static String UUID = \"23434343\";\r\n" + - " String name;\r\n" + - " int id;\r\n" + - " List aList;\r\n" + - " String[] arrays;\r\n" + - " @Override\r\n" + - " public String toString() {\r\n" + - " final int maxLen = 10;\r\n" + - " StringBuilder builder = new StringBuilder();\r\n" + - " builder.append(\"B [\");\r\n" + - " if (name != null) {\r\n" + - " builder.append(\"name=\").append(name).append(\", \");\r\n" + - " }\r\n" + - " builder.append(\"id=\").append(id).append(\", \");\r\n" + - " if (aList != null) {\r\n" + - " builder.append(\"aList=\").append(aList.subList(0, Math.min(aList.size(), maxLen))).append(\", \");\r\n" + - " }\r\n" + - " if (arrays != null) {\r\n" + - " builder.append(\"arrays=\").append(arrays);\r\n" + - " }\r\n" + - " builder.append(\"]\");\r\n" + - " return builder.toString();\r\n" + - " }\r\n" + - "}"; + String expected = "package p;\r\n" + + "\r\n" + + "import java.util.List;\r\n" + + "\r\n" + + "public class B {\r\n" + + " private static String UUID = \"23434343\";\r\n" + + " String name;\r\n" + + " int id;\r\n" + + " List aList;\r\n" + + " String[] arrays;\r\n" + + " @Override\r\n" + + " public String toString() {\r\n" + + " final int maxLen = 10;\r\n" + + " StringBuilder builder = new StringBuilder();\r\n" + + " builder.append(\"B [\");\r\n" + + " if (name != null) {\r\n" + + " builder.append(\"name=\").append(name).append(\", \");\r\n" + + " }\r\n" + + " builder.append(\"id=\").append(id).append(\", \");\r\n" + + " if (aList != null) {\r\n" + + " builder.append(\"aList=\").append(aList.subList(0, Math.min(aList.size(), maxLen))).append(\", \");\r\n" + + " }\r\n" + + " if (arrays != null) {\r\n" + + " builder.append(\"arrays=\").append(arrays).append(\", \");\r\n" + + " }\r\n" + + " if (getClass() != null) {\r\n" + + " builder.append(\"getClass()=\").append(getClass()).append(\", \");\r\n" + + " }\r\n" + + " builder.append(\"hashCode()=\").append(hashCode()).append(\", \");\r\n" + + " if (super.toString() != null) {\r\n" + + " builder.append(\"toString()=\").append(super.toString());\r\n" + + " }\r\n" + + " builder.append(\"]\");\r\n" + + " return builder.toString();\r\n" + + " }\r\n" + + "}"; /* @formatter:on */ compareSource(expected, unit.getSource()); @@ -285,22 +297,22 @@ public void testGenerateToStringAfterCursorPosition() throws ValidateEditExcepti generateToString(unit.findPrimaryType(), settings, cursor); /* @formatter:off */ - String expected = "package p;\r\n" + - "\r\n" + - "import java.util.Arrays;\r\n" + - "import java.util.List;\r\n" + - "\r\n" + - "public class B {\r\n" + - " private static String UUID = \"23434343\";\r\n" + - " String name;\r\n" + - " int id;\r\n" + - " List aList;/*|*/\r\n" + - " @Override\r\n" + - " public String toString() {\r\n" + - " return \"B [name=\" + name + \", id=\" + id + \", aList=\" + aList + \", arrays=\" + (arrays != null ? Arrays.asList(arrays) : null) + \"]\";\r\n" + - " }\r\n" + - " String[] arrays;\r\n" + - "}"; + String expected = "package p;\r\n" + + "\r\n" + + "import java.util.Arrays;\r\n" + + "import java.util.List;\r\n" + + "\r\n" + + "public class B {\r\n" + + " private static String UUID = \"23434343\";\r\n" + + " String name;\r\n" + + " int id;\r\n" + + " List aList;/*|*/\r\n" + + " @Override\r\n" + + " public String toString() {\r\n" + + " return \"B [name=\" + name + \", id=\" + id + \", aList=\" + aList + \", arrays=\" + (arrays != null ? Arrays.asList(arrays) : null) + \", getClass()=\" + getClass() + \", hashCode()=\" + hashCode() + \", toString()=\" + super.toString() + \"]\";\r\n" + + " }\r\n" + + " String[] arrays;\r\n" + + "}"; /* @formatter:on */ compareSource(expected, unit.getSource()); @@ -342,22 +354,22 @@ public void testGenerateToStringBeforeCursorPosition() throws ValidateEditExcept generateToString(unit.findPrimaryType(), settings, cursor); /* @formatter:off */ - String expected = "package p;\r\n" + - "\r\n" + - "import java.util.Arrays;\r\n" + - "import java.util.List;\r\n" + - "\r\n" + - "public class B {\r\n" + - " private static String UUID = \"23434343\";\r\n" + - " String name;\r\n" + - " int id;\r\n" + - " @Override\r\n" + - " public String toString() {\r\n" + - " return \"B [name=\" + name + \", id=\" + id + \", aList=\" + aList + \", arrays=\" + (arrays != null ? Arrays.asList(arrays) : null) + \"]\";\r\n" + - " }\r\n" + - " List aList;/*|*/\r\n" + - " String[] arrays;\r\n" + - "}"; + String expected = "package p;\r\n" + + "\r\n" + + "import java.util.Arrays;\r\n" + + "import java.util.List;\r\n" + + "\r\n" + + "public class B {\r\n" + + " private static String UUID = \"23434343\";\r\n" + + " String name;\r\n" + + " int id;\r\n" + + " @Override\r\n" + + " public String toString() {\r\n" + + " return \"B [name=\" + name + \", id=\" + id + \", aList=\" + aList + \", arrays=\" + (arrays != null ? Arrays.asList(arrays) : null) + \", getClass()=\" + getClass() + \", hashCode()=\" + hashCode() + \", toString()=\" + super.toString() + \"]\";\r\n" + + " }\r\n" + + " List aList;/*|*/\r\n" + + " String[] arrays;\r\n" + + "}"; /* @formatter:on */ compareSource(expected, unit.getSource()); @@ -366,6 +378,42 @@ public void testGenerateToStringBeforeCursorPosition() throws ValidateEditExcept } } + @Test + public void testInheritedFieldsAndMethods() throws Exception { + importProjects("eclipse/hello"); + IProject project = getProject("hello"); + IJavaProject javaProject = JavaCore.create(project); + ToStringGenerationSettingsCore settings = new ToStringGenerationSettingsCore(); + settings.overrideAnnotation = true; + settings.createComments = false; + settings.useBlocks = false; + settings.stringFormatTemplate = GenerateToStringHandler.DEFAULT_TEMPLATE; + settings.toStringStyle = GenerateToStringOperation.STRING_CONCATENATION; + settings.skipNulls = false; + settings.customArrayToString = true; + settings.limitElements = false; + settings.customBuilderSettings = new CustomBuilderSettings(); + IType type = javaProject.findType("org.sample.Child"); + CheckToStringResponse response = GenerateToStringHandler.checkToStringStatus(type); + assertNotNull(response); + assertEquals(5, response.fields.length); + LspVariableBinding name = response.fields[0]; + // Child.name, field, selected + assertEquals("name", name.name); + assertTrue(name.isField); + assertTrue(name.isSelected); + // Parent.parentName, field, not selected + LspVariableBinding parentName = response.fields[1]; + assertEquals("parentName", parentName.name); + assertTrue(parentName.isField); + assertFalse(parentName.isSelected); + // Object.getClass, method, not selected + LspVariableBinding getClass = response.fields[2]; + assertEquals("getClass", getClass.name); + assertFalse(getClass.isField); + assertFalse(parentName.isSelected); + } + private void generateToString(IType type, ToStringGenerationSettingsCore settings) throws ValidateEditException, CoreException { generateToString(type, settings, null); }