Merge pull request #3420 from Rawi01/tostring-array

Ignore annotations during array detection
This commit is contained in:
Reinier Zwitserloot authored and GitHub committed 2023-08-04 01:59:52 +02:00
commit fe663a5cea
10 files changed
+138 -65

No files matched your search

@@ -25,7 +25,6 @@ import static lombok.core.handlers.HandlerUtil.handleFlagUsage;
import static lombok.javac.Javac.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -269,7 +268,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
for (Included<JavacNode, EqualsAndHashCode.Include> member : members) {
JavacNode memberNode = member.getNode();
JCExpression fType = unnotate(getFieldType(memberNode, fieldAccess));
JCExpression fType = removeTypeUseAnnotations(getFieldType(memberNode, fieldAccess));
boolean isMethod = memberNode.getKind() == Kind.METHOD;
JCExpression fieldAccessor = isMethod ? createMethodAccessor(maker, memberNode) : createFieldAccessor(maker, memberNode, fieldAccess);
@@ -316,8 +315,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
} else if (fType instanceof JCArrayTypeTree) {
JCArrayTypeTree array = (JCArrayTypeTree) fType;
/* java.util.Arrays.deepHashCode(this.fieldName) //use just hashCode() for primitive arrays. */
boolean multiDim = unnotate(array.elemtype) instanceof JCArrayTypeTree;
boolean primitiveArray = unnotate(array.elemtype) instanceof JCPrimitiveTypeTree;
boolean multiDim = removeTypeUseAnnotations(array.elemtype) instanceof JCArrayTypeTree;
boolean primitiveArray = removeTypeUseAnnotations(array.elemtype) instanceof JCPrimitiveTypeTree;
boolean useDeepHC = multiDim || !primitiveArray;
JCExpression hcMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepHC ? "deepHashCode" : "hashCode");
@@ -503,7 +502,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
JavacNode memberNode = member.getNode();
boolean isMethod = memberNode.getKind() == Kind.METHOD;
JCExpression fType = unnotate(getFieldType(memberNode, fieldAccess));
JCExpression fType = removeTypeUseAnnotations(getFieldType(memberNode, fieldAccess));
JCExpression thisFieldAccessor = isMethod ? createMethodAccessor(maker, memberNode) : createFieldAccessor(maker, memberNode, fieldAccess);
JCExpression otherFieldAccessor = isMethod ? createMethodAccessor(maker, memberNode, maker.Ident(otherName)) : createFieldAccessor(maker, memberNode, fieldAccess, maker.Ident(otherName));
if (fType instanceof JCPrimitiveTypeTree) {
@@ -525,8 +524,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
} else if (fType instanceof JCArrayTypeTree) {
JCArrayTypeTree array = (JCArrayTypeTree) fType;
/* if (!java.util.Arrays.deepEquals(this.fieldName, other.fieldName)) return false; //use equals for primitive arrays. */
boolean multiDim = unnotate(array.elemtype) instanceof JCArrayTypeTree;
boolean primitiveArray = unnotate(array.elemtype) instanceof JCPrimitiveTypeTree;
boolean multiDim = removeTypeUseAnnotations(array.elemtype) instanceof JCArrayTypeTree;
boolean primitiveArray = removeTypeUseAnnotations(array.elemtype) instanceof JCPrimitiveTypeTree;
boolean useDeepEquals = multiDim || !primitiveArray;
JCExpression eqMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepEquals ? "deepEquals" : "equals");
@@ -603,30 +602,4 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
public JCStatement returnBool(JavacTreeMaker maker, boolean bool) {
return maker.Return(maker.Literal(CTC_BOOLEAN, bool ? 1 : 0));
}
private boolean jcAnnotatedTypeInit;
private Class<?> jcAnnotatedTypeClass = null;
private Field jcAnnotatedTypeUnderlyingTypeField = null;
private JCExpression unnotate(JCExpression type) {
if (!isJcAnnotatedType(type)) return type;
if (jcAnnotatedTypeUnderlyingTypeField == null) return type;
try {
return (JCExpression) jcAnnotatedTypeUnderlyingTypeField.get(type);
} catch (Exception ignore) {}
return type;
}
private boolean isJcAnnotatedType(JCExpression o) {
if (o == null) return false;
if (!jcAnnotatedTypeInit) {
try {
jcAnnotatedTypeClass = Class.forName("com.sun.tools.javac.tree.JCTree$JCAnnotatedType", false, o.getClass().getClassLoader());
jcAnnotatedTypeUnderlyingTypeField = jcAnnotatedTypeClass.getDeclaredField("underlyingType");
}
catch (Exception ignore) {}
jcAnnotatedTypeInit = true;
}
return jcAnnotatedTypeClass == o.getClass();
}
}
@@ -206,7 +206,7 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
memberAccessor = createFieldAccessor(maker, memberNode, fieldAccess);
}
JCExpression memberType = getFieldType(memberNode, fieldAccess);
JCExpression memberType = removeTypeUseAnnotations(getFieldType(memberNode, fieldAccess));
// The distinction between primitive and object will be useful if we ever add a 'hideNulls' option.
@SuppressWarnings("unused")
@@ -586,29 +586,40 @@ public class JavacHandlerUtil {
static class RecordComponentReflect {
private static final Field astField;
private static final Field originalAnnos;
private static final Method findRecordComponentToRemove;
static {
Field a = null;
Field o = null;
Method m = null;
try {
Class<?> forName = Class.forName("com.sun.tools.javac.code.Symbol$RecordComponent");
a = Permit.permissiveGetField(forName, "ast");
o = Permit.permissiveGetField(forName, "originalAnnos");
m = Permit.permissiveGetMethod(ClassSymbol.class, "findRecordComponentToRemove", JCVariableDecl.class);
} catch (Throwable e) {
// Ignore
}
astField = a;
originalAnnos = o;
findRecordComponentToRemove = m;
}
static void deleteAnnotation(JCClassDecl record, JCVariableDecl component, JCTree annotation) {
if (astField == null || findRecordComponentToRemove == null) return;
if ((astField == null && originalAnnos == null) || findRecordComponentToRemove == null) return;
try {
Object toRemove = Permit.invokeSneaky(findRecordComponentToRemove, record.sym, component);
JCVariableDecl variable = (JCVariableDecl) Permit.get(astField, toRemove);
variable.mods.annotations = filterListByPos(variable.mods.annotations, annotation);
if (astField != null) {
// OpenJDK
JCVariableDecl variable = Permit.get(astField, toRemove);
variable.mods.annotations = filterListByPos(variable.mods.annotations, annotation);
} else {
// Zulu JDK 17
List<JCAnnotation> annotations = Permit.get(originalAnnos, toRemove);
Permit.set(originalAnnos, toRemove, filterListByPos(annotations, annotation));
}
} catch (Throwable e) {
// Ignore
}
@@ -1212,41 +1223,39 @@ public class JavacHandlerUtil {
}
static class JCAnnotatedTypeReflect {
private static Class<?> TYPE;
private static Constructor<?> CONSTRUCTOR;
private static Field ANNOTATIONS, UNDERLYING_TYPE;
private static final Class<?> TYPE;
private static final Constructor<?> CONSTRUCTOR;
private static final Field ANNOTATIONS, UNDERLYING_TYPE;
private static void initByLoader(ClassLoader classLoader) {
if (TYPE != null) return;
Class<?> c;
static {
Class<?> t = null;
Constructor<?> c = null;
Field a = null;
Field u = null;
try {
c = classLoader.loadClass("com.sun.tools.javac.tree.JCTree$JCAnnotatedType");
t = Class.forName("com.sun.tools.javac.tree.JCTree$JCAnnotatedType");
c = Permit.getConstructor(t, List.class, JCExpression.class);
a = Permit.permissiveGetField(t, "annotations");
u = Permit.permissiveGetField(t, "underlyingType");
} catch (Exception e) {
return;
// Ignore
}
init(c);
}
private static void init(Class<?> in) {
if (TYPE != null) return;
if (!in.getName().equals("com.sun.tools.javac.tree.JCTree$JCAnnotatedType")) return;
try {
CONSTRUCTOR = Permit.getConstructor(in, List.class, JCExpression.class);
ANNOTATIONS = Permit.getField(in, "annotations");
UNDERLYING_TYPE = Permit.getField(in, "underlyingType");
TYPE = in;
} catch (Exception ignore) {}
TYPE = t;
CONSTRUCTOR = c;
ANNOTATIONS = a;
UNDERLYING_TYPE = u;
}
static boolean is(JCTree obj) {
if (obj == null) return false;
init(obj.getClass());
return obj.getClass() == TYPE;
}
@SuppressWarnings("unchecked")
static List<JCAnnotation> getAnnotations(JCTree obj) {
init(obj.getClass());
if (ANNOTATIONS == null) return List.nil();
try {
return (List<JCAnnotation>) ANNOTATIONS.get(obj);
} catch (Exception e) {
@@ -1255,14 +1264,16 @@ public class JavacHandlerUtil {
}
static void setAnnotations(JCTree obj, List<JCAnnotation> anns) {
init(obj.getClass());
if (ANNOTATIONS == null) return;
try {
ANNOTATIONS.set(obj, anns);
} catch (Exception e) {}
} catch (Exception e) {
// Ignore
}
}
static JCExpression getUnderlyingType(JCTree obj) {
init(obj.getClass());
if (UNDERLYING_TYPE == null) return null;
try {
return (JCExpression) UNDERLYING_TYPE.get(obj);
} catch (Exception e) {
@@ -1271,7 +1282,7 @@ public class JavacHandlerUtil {
}
static JCExpression create(List<JCAnnotation> annotations, JCExpression underlyingType) {
initByLoader(underlyingType.getClass().getClassLoader());
if (CONSTRUCTOR == null) return underlyingType;
try {
return (JCExpression) CONSTRUCTOR.newInstance(annotations, underlyingType);
} catch (Exception e) {
+2 -2
View File
@@ -297,9 +297,9 @@ public class Permit {
}
}
public static Object get(Field f, Object receiver) throws IllegalAccessException {
public static <T> T get(Field f, Object receiver) throws IllegalAccessException {
try {
return f.get(receiver);
return (T) f.get(receiver);
} catch (IllegalAccessException e) {
handleReflectionDebug(e, null);
throw e;
@@ -0,0 +1,13 @@
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
public class ToStringArray {
int[] primitiveArray;
Object[] objectArray;
@java.lang.Override
@java.lang.SuppressWarnings("all")
public java.lang.String toString() {
return "ToStringArray(primitiveArray=" + java.util.Arrays.toString(this.primitiveArray) + ", objectArray=" + java.util.Arrays.deepToString(this.objectArray) + ")";
}
}
@@ -0,0 +1,23 @@
//version 8:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
public class ToStringArrayTypeAnnotations {
@TA
int[] primitiveArray1;
int @TA [] primitiveArray2;
@TA
Object[] objectArray1;
Object @TA [] objectArray2;
@Target({ElementType.TYPE_USE})
@interface TA {
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
public java.lang.String toString() {
return "ToStringArrayTypeAnnotations(primitiveArray1=" + java.util.Arrays.toString(this.primitiveArray1) + ", primitiveArray2=" + java.util.Arrays.toString(this.primitiveArray2) + ", objectArray1=" + java.util.Arrays.deepToString(this.objectArray1) + ", objectArray2=" + java.util.Arrays.deepToString(this.objectArray2) + ")";
}
}
@@ -0,0 +1,12 @@
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
public @lombok.ToString class ToStringArray {
int[] primitiveArray;
Object[] objectArray;
public ToStringArray() {
super();
}
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
return (((("ToStringArray(primitiveArray=" + java.util.Arrays.toString(this.primitiveArray)) + ", objectArray=") + java.util.Arrays.deepToString(this.objectArray)) + ")");
}
}
@@ -0,0 +1,16 @@
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
public @lombok.ToString class ToStringArrayTypeAnnotations {
@Target({ElementType.TYPE_USE}) @interface TA {
}
@TA int[] primitiveArray1;
int @TA [] primitiveArray2;
@TA Object[] objectArray1;
Object @TA [] objectArray2;
public ToStringArrayTypeAnnotations() {
super();
}
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
return (((((((("ToStringArrayTypeAnnotations(primitiveArray1=" + java.util.Arrays.toString(this.primitiveArray1)) + ", primitiveArray2=") + java.util.Arrays.toString(this.primitiveArray2)) + ", objectArray1=") + java.util.Arrays.deepToString(this.objectArray1)) + ", objectArray2=") + java.util.Arrays.deepToString(this.objectArray2)) + ")");
}
}
@@ -0,0 +1,9 @@
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@lombok.ToString
public class ToStringArray {
int[] primitiveArray;
Object[] objectArray;
}
@@ -0,0 +1,16 @@
//version 8:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@lombok.ToString
public class ToStringArrayTypeAnnotations {
@TA int[] primitiveArray1;
int @TA [] primitiveArray2;
@TA Object[] objectArray1;
Object @TA [] objectArray2;
@Target({ElementType.TYPE_USE})
@interface TA {
}
}