Skip to content

Commit

Permalink
Add methods,inherited fields,inherited methods to Generate toString()
Browse files Browse the repository at this point in the history
Signed-off-by: Snjezana Peco <[email protected]>
  • Loading branch information
snjeza committed Feb 28, 2024
1 parent 6c16211 commit 2682123
Show file tree
Hide file tree
Showing 5 changed files with 333 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<IJavaElement, IVariableBinding> fieldsToBindingsMap = new HashMap<>();
HashMap<IJavaElement, IVariableBinding> 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<IVariableBinding> fieldsToBindings = new ArrayList<>();
List<IVariableBinding> 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<IVariableBinding> 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<IMethodBinding> 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<IMethodBinding> 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<LspVariableBinding> 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;
}

Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
}
Expand All @@ -64,23 +78,101 @@ public LspMethodBinding(IMethodBinding binding) {
}
}

public static IBinding[] convertToBindings(ITypeBinding typeBinding, LspVariableBinding[] fields) {
Set<String> bindingKeys = Stream.of(fields).map((field) -> field.bindingKey).collect(Collectors.toSet());
IVariableBinding[] bindings = typeBinding.getDeclaredFields();
List<IVariableBinding> 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<IMethodBinding> 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<String> 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<IVariableBinding> 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 <T extends IBinding> boolean contains(List<T> 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<IVariableBinding> {
public static class BindingComparator implements Comparator<IBinding> {
@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;
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.sample;

public class Child extends Parent {
protected String name;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.sample;

public class Parent {
protected String parentName;
}
Loading

0 comments on commit 2682123

Please sign in to comment.