[fixes #788] lombok generated equals method plus a non-null-by-default annotation no longer clash.

This commit is contained in:
Reinier Zwitserloot committed 2020-01-08 01:06:35 +01:00
1 parent 0b0656ae3c
commit 9ad2bd563b
13 files changed
+160 -6

No files matched your search

@@ -745,6 +745,20 @@ public class EclipseHandlerUtil {
}
}
public static String scanForNearestAnnotation(EclipseNode node, String... anns) {
while (node != null) {
for (EclipseNode ann : node.down()) {
if (ann.getKind() != Kind.ANNOTATION) continue;
Annotation a = (Annotation) ann.get();
TypeReference aType = a.type;
for (String annToFind : anns) if (typeMatches(annToFind, node, aType)) return annToFind;
}
node = node.up();
}
return null;
}
public static boolean hasNonNullAnnotations(EclipseNode node) {
AbstractVariableDeclaration avd = (AbstractVariableDeclaration) node.get();
if (avd.annotations == null) return false;
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2019 The Project Lombok Authors.
* Copyright (C) 2009-2020 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -63,6 +63,7 @@ import org.eclipse.jdt.internal.compiler.ast.IfStatement;
import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression;
import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.NameReference;
@@ -504,9 +505,33 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
return arr == null ? 0 : arr.length;
}
/*
* scan method, then class, then enclosing classes, then package for the first of:
* javax.annotation.ParametersAreNonnullByDefault or javax.annotation.ParametersAreNullableByDefault. If it's the NN variant, generate javax.annotation.Nullable _on the type_.
* org.eclipse.jdt.annotation.NonNullByDefault -> org.eclipse.jdt.annotation.Nullable
*/
private static final char[][] JAVAX_ANNOTATION_NULLABLE = Eclipse.fromQualifiedName("javax.annotation.Nullable");
private static final char[][] ORG_ECLIPSE_JDT_ANNOTATION_NULLABLE = Eclipse.fromQualifiedName("org.eclipse.jdt.annotation.Nullable");
public MethodDeclaration createEquals(EclipseNode type, Collection<Included<EclipseNode, EqualsAndHashCode.Include>> members, boolean callSuper, ASTNode source, FieldAccess fieldAccess, boolean needsCanEqual, List<Annotation> onParam) {
int pS = source.sourceStart; int pE = source.sourceEnd;
long p = (long)pS << 32 | pE;
long p = (long) pS << 32 | pE;
Annotation[] onParamType = null;
String nearest = scanForNearestAnnotation(type, "javax.annotation.ParametersAreNullableByDefault", "javax.annotation.ParametersAreNonnullByDefault");
if ("javax.annotation.ParametersAreNonnullByDefault".equals(nearest)) {
onParamType = new Annotation[1];
onParamType[0] = new MarkerAnnotation(generateQualifiedTypeRef(source, JAVAX_ANNOTATION_NULLABLE), 0);
}
nearest = scanForNearestAnnotation(type, "org.eclipse.jdt.annotation.NonNullByDefault");
if (nearest != null) {
Annotation a = new MarkerAnnotation(generateQualifiedTypeRef(source, ORG_ECLIPSE_JDT_ANNOTATION_NULLABLE), 0);
if (onParamType != null) onParamType = new Annotation[] {onParamType[0], a};
else onParamType = new Annotation[] {a};
}
MethodDeclaration method = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
setGeneratedBy(method, source);
@@ -526,7 +551,8 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart;
method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd;
TypeReference objectRef = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] { p, p, p });
QualifiedTypeReference objectRef = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] { p, p, p });
if (onParamType != null) objectRef.annotations = new Annotation[][] {null, null, onParamType};
setGeneratedBy(objectRef, source);
method.arguments = new Argument[] {new Argument(new char[] { 'o' }, 0, objectRef, Modifier.FINAL)};
method.arguments[0].sourceStart = pS; method.arguments[0].sourceEnd = pE;
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2019 The Project Lombok Authors.
* Copyright (C) 2009-2020 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -381,6 +381,20 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
Name otherName = typeNode.toName("other");
Name thisName = typeNode.toName("this");
List<JCAnnotation> annsOnParamOnMethod = List.nil();
String nearest = scanForNearestAnnotation(typeNode, "org.eclipse.jdt.annotation.NonNullByDefault");
if (nearest != null) {
JCAnnotation m = maker.Annotation(genTypeRef(typeNode, "org.eclipse.jdt.annotation.Nullable"), List.<JCExpression>nil());
annsOnParamOnMethod = annsOnParamOnMethod.prepend(m);
}
nearest = scanForNearestAnnotation(typeNode, "javax.annotation.ParametersAreNullableByDefault", "javax.annotation.ParametersAreNonnullByDefault");
if ("javax.annotation.ParametersAreNonnullByDefault".equals(nearest)) {
JCAnnotation m = maker.Annotation(genTypeRef(typeNode, "javax.annotation.Nullable"), List.<JCExpression>nil());
annsOnParamOnMethod = annsOnParamOnMethod.prepend(m);
}
JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil());
List<JCAnnotation> annsOnMethod = List.of(overrideAnnotation);
CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(typeNode);
@@ -388,7 +402,14 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil()));
}
JCModifiers mods = maker.Modifiers(Flags.PUBLIC, annsOnMethod);
JCExpression objectType = genJavaLangTypeRef(typeNode, "Object");
JCExpression objectType;
if (annsOnParamOnMethod.isEmpty()) {
objectType = genJavaLangTypeRef(typeNode, "Object");
} else {
objectType = chainDots(typeNode, "java", "lang", "Object");
objectType = maker.AnnotatedType(annsOnParamOnMethod, objectType);
}
JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN);
long finalFlag = JavacHandlerUtil.addFinalIfNeeded(0L, typeNode.getContext());
@@ -1400,6 +1400,19 @@ public class JavacHandlerUtil {
return result.toList();
}
public static String scanForNearestAnnotation(JavacNode node, String... anns) {
while (node != null) {
for (JavacNode ann : node.down()) {
if (ann.getKind() != Kind.ANNOTATION) continue;
JCAnnotation a = (JCAnnotation) ann.get();
for (String annToFind : anns) if (typeMatches(annToFind, node, a.annotationType)) return annToFind;
}
node = node.up();
}
return null;
}
public static boolean hasNonNullAnnotations(JavacNode node) {
for (JavacNode child : node.down()) {
if (child.getKind() == Kind.ANNOTATION) {
+7 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2018 The Project Lombok Authors.
* Copyright (C) 2013-2020 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -864,6 +864,12 @@ public class JavacTreeMaker {
return invoke(TypeAnnotationWithAttributeOnly, a);
}
//javac versions: 8
private static final MethodId<JCExpression> AnnotatedType = MethodId("AnnotatedType", JCExpression.class, List.class, JCExpression.class);
public JCExpression AnnotatedType(List<JCAnnotation> annotations, JCExpression underlyingType) {
return invoke(AnnotatedType, annotations, underlyingType);
}
//javac versions: 6-8
private static final MethodId<JCStatement> Call = MethodId("Call");
public JCStatement Call(JCExpression apply) {