aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinier Zwitserloot <r.zwitserloot@projectlombok.org>2021-03-22 08:03:42 +0100
committerReinier Zwitserloot <r.zwitserloot@projectlombok.org>2021-03-22 08:03:42 +0100
commitbcd05a01b14705678dfd280989fa5071b627a234 (patch)
tree55f5af9b2b158c37f9d04b7ec27aad048d4e1ffd
parentade900b82b8205bb439ac9d6d99dff0c3af6e10f (diff)
parentfa0b5249cf5fee28d9be13ecdf0225f651f686aa (diff)
downloadlombok-bcd05a01b14705678dfd280989fa5071b627a234.tar.gz
lombok-bcd05a01b14705678dfd280989fa5071b627a234.tar.bz2
lombok-bcd05a01b14705678dfd280989fa5071b627a234.zip
Merge branch 'records'
# Conflicts: # src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java # src/core/lombok/eclipse/handlers/HandleBuilder.java # src/core/lombok/eclipse/handlers/HandleData.java # src/core/lombok/eclipse/handlers/HandleNonNull.java # src/core/lombok/eclipse/handlers/HandleSuperBuilder.java # src/core/lombok/javac/handlers/HandleBuilder.java # src/core/lombok/javac/handlers/HandleNonNull.java # src/core/lombok/javac/handlers/HandleSuperBuilder.java # test/core/src/lombok/RunTestsViaEcj.java
-rw-r--r--src/core/lombok/core/LombokNode.java10
-rw-r--r--src/core/lombok/eclipse/EclipseAST.java22
-rw-r--r--src/core/lombok/eclipse/EclipseNode.java12
-rw-r--r--src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java115
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleBuilder.java17
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleConstructor.java7
-rw-r--r--src/core/lombok/eclipse/handlers/HandleData.java11
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java10
-rw-r--r--src/core/lombok/eclipse/handlers/HandleFieldDefaults.java8
-rw-r--r--src/core/lombok/eclipse/handlers/HandleGetter.java14
-rw-r--r--src/core/lombok/eclipse/handlers/HandleLog.java11
-rw-r--r--src/core/lombok/eclipse/handlers/HandleNonNull.java18
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSetter.java14
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSuperBuilder.java5
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSynchronized.java6
-rw-r--r--src/core/lombok/eclipse/handlers/HandleToString.java10
-rw-r--r--src/core/lombok/eclipse/handlers/HandleUtilityClass.java9
-rw-r--r--src/core/lombok/eclipse/handlers/HandleValue.java9
-rw-r--r--src/core/lombok/javac/JavacNode.java12
-rw-r--r--src/core/lombok/javac/handlers/HandleBuilder.java15
-rw-r--r--src/core/lombok/javac/handlers/HandleConstructor.java7
-rw-r--r--src/core/lombok/javac/handlers/HandleData.java3
-rw-r--r--src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java12
-rw-r--r--src/core/lombok/javac/handlers/HandleFieldDefaults.java7
-rw-r--r--src/core/lombok/javac/handlers/HandleGetter.java14
-rw-r--r--src/core/lombok/javac/handlers/HandleLog.java17
-rw-r--r--src/core/lombok/javac/handlers/HandleNonNull.java12
-rw-r--r--src/core/lombok/javac/handlers/HandleSetter.java13
-rw-r--r--src/core/lombok/javac/handlers/HandleSuperBuilder.java7
-rw-r--r--src/core/lombok/javac/handlers/HandleSynchronized.java8
-rw-r--r--src/core/lombok/javac/handlers/HandleToString.java8
-rw-r--r--src/core/lombok/javac/handlers/HandleUtilityClass.java9
-rw-r--r--src/core/lombok/javac/handlers/HandleWithBy.java3
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java53
-rw-r--r--src/delombok/lombok/delombok/PrettyPrinter.java24
-rw-r--r--src/utils/lombok/eclipse/Eclipse.java18
-rw-r--r--src/utils/lombok/eclipse/Java14Bits.java11
-rw-r--r--src/utils/lombok/javac/Java14Flags.java26
-rw-r--r--src/utils/lombok/javac/Javac.java6
-rw-r--r--test/core/src/lombok/RunTestsViaEcj.java4
-rw-r--r--test/transform/resource/after-delombok/BuilderSimpleOnRecord.java43
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularOnRecord.java136
-rw-r--r--test/transform/resource/after-delombok/ConstructorsOnRecord.java2
-rw-r--r--test/transform/resource/after-delombok/DataOnRecord.java2
-rw-r--r--test/transform/resource/after-delombok/EqualsAndHashCodeOnRecord.java2
-rw-r--r--test/transform/resource/after-delombok/FieldDefaultsOnRecord.java2
-rw-r--r--test/transform/resource/after-delombok/FieldNameConstantsOnRecord.java9
-rw-r--r--test/transform/resource/after-delombok/GetterOnRecord.java2
-rw-r--r--test/transform/resource/after-delombok/LoggerConfigOnRecord.java2
-rw-r--r--test/transform/resource/after-delombok/LoggerSlf4jNonStaticOnRecord.java3
-rw-r--r--test/transform/resource/after-delombok/LoggerSlf4jOnRecord.java3
-rw-r--r--test/transform/resource/after-delombok/NonNullExistingConstructorOnRecord.java22
-rw-r--r--test/transform/resource/after-delombok/NonNullOnRecord.java22
-rw-r--r--test/transform/resource/after-delombok/SetterOnRecord.java2
-rw-r--r--test/transform/resource/after-delombok/SynchronizedInRecord.java6
-rw-r--r--test/transform/resource/after-delombok/ToStringOnRecord.java2
-rw-r--r--test/transform/resource/after-delombok/UtilityClassOnRecord.java2
-rw-r--r--test/transform/resource/after-delombok/ValueOnRecord.java2
-rw-r--r--test/transform/resource/after-delombok/WithByOnRecord.java11
-rw-r--r--test/transform/resource/after-delombok/WithByOnRecordComponent.java6
-rw-r--r--test/transform/resource/after-delombok/WithOnRecord.java11
-rw-r--r--test/transform/resource/after-delombok/WithOnRecordComponent.java6
-rw-r--r--test/transform/resource/after-ecj/BuilderSimpleOnRecord.java34
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularOnRecord.java128
-rw-r--r--test/transform/resource/after-ecj/ConstructorsOnRecord.java12
-rw-r--r--test/transform/resource/after-ecj/DataOnRecord.java10
-rw-r--r--test/transform/resource/after-ecj/EqualsAndHashCodeOnRecord.java10
-rw-r--r--test/transform/resource/after-ecj/FieldDefaultsOnRecord.java9
-rw-r--r--test/transform/resource/after-ecj/FieldNameConstantsOnRecord.java27
-rw-r--r--test/transform/resource/after-ecj/GetterOnRecord.java10
-rw-r--r--test/transform/resource/after-ecj/LoggerConfigOnRecord.java10
-rw-r--r--test/transform/resource/after-ecj/LoggerSlf4jOnRecord.java13
-rw-r--r--test/transform/resource/after-ecj/NonNullExistingConstructorOnRecord.java30
-rw-r--r--test/transform/resource/after-ecj/NonNullOnRecord.java30
-rw-r--r--test/transform/resource/after-ecj/SetterOnRecord.java10
-rw-r--r--test/transform/resource/after-ecj/SynchronizedInRecord.java14
-rw-r--r--test/transform/resource/after-ecj/ToStringOnRecord.java10
-rw-r--r--test/transform/resource/after-ecj/UtilityClassOnRecord.java10
-rw-r--r--test/transform/resource/after-ecj/ValueOnRecord.java10
-rw-r--r--test/transform/resource/after-ecj/WithByOnRecord.java16
-rw-r--r--test/transform/resource/after-ecj/WithByOnRecordComponent.java13
-rw-r--r--test/transform/resource/after-ecj/WithOnRecord.java16
-rw-r--r--test/transform/resource/after-ecj/WithOnRecordComponent.java13
-rw-r--r--test/transform/resource/before/BuilderSimpleOnRecord.java7
-rw-r--r--test/transform/resource/before/BuilderSingularOnRecord.java11
-rw-r--r--test/transform/resource/before/ConstructorsOnRecord.java11
-rw-r--r--test/transform/resource/before/DataOnRecord.java7
-rw-r--r--test/transform/resource/before/EqualsAndHashCodeOnRecord.java7
-rw-r--r--test/transform/resource/before/FieldDefaultsOnRecord.java5
-rw-r--r--test/transform/resource/before/FieldNameConstantsOnRecord.java9
-rw-r--r--test/transform/resource/before/GetterOnRecord.java7
-rw-r--r--test/transform/resource/before/LoggerConfigOnRecord.java8
-rw-r--r--test/transform/resource/before/LoggerSlf4jOnRecord.java7
-rw-r--r--test/transform/resource/before/NonNullExistingConstructorOnRecord.java9
-rw-r--r--test/transform/resource/before/NonNullOnRecord.java9
-rw-r--r--test/transform/resource/before/SetterOnRecord.java7
-rw-r--r--test/transform/resource/before/SuperBuilderOnRecord.java8
-rw-r--r--test/transform/resource/before/SynchronizedInRecord.java10
-rw-r--r--test/transform/resource/before/ToStringOnRecord.java7
-rw-r--r--test/transform/resource/before/UtilityClassOnRecord.java7
-rw-r--r--test/transform/resource/before/ValueOnRecord.java7
-rw-r--r--test/transform/resource/before/WithByOnRecord.java7
-rw-r--r--test/transform/resource/before/WithByOnRecordComponent.java6
-rw-r--r--test/transform/resource/before/WithOnRecord.java7
-rw-r--r--test/transform/resource/before/WithOnRecordComponent.java6
-rw-r--r--test/transform/resource/messages-delombok/ConstructorsOnRecord.java.messages3
-rw-r--r--test/transform/resource/messages-delombok/DataOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-delombok/EqualsAndHashCodeOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-delombok/FieldDefaultsOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-delombok/GetterOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-delombok/LoggerConfigOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-delombok/SetterOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-delombok/SuperBuilderOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-delombok/SynchronizedInRecord.java.messages1
-rw-r--r--test/transform/resource/messages-delombok/ToStringOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-delombok/UtilityClassErrors.java.messages2
-rw-r--r--test/transform/resource/messages-delombok/UtilityClassOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-delombok/ValueOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-ecj/ConstructorsOnRecord.java.messages3
-rw-r--r--test/transform/resource/messages-ecj/DataOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-ecj/EqualsAndHashCodeOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-ecj/FieldDefaultsOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-ecj/GetterOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-ecj/LoggerConfigOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-ecj/SetterOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-ecj/SuperBuilderOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-ecj/SynchronizedInRecord.java.messages1
-rw-r--r--test/transform/resource/messages-ecj/ToStringOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-ecj/UtilityClassErrors.java.messages2
-rw-r--r--test/transform/resource/messages-ecj/UtilityClassOnRecord.java.messages1
-rw-r--r--test/transform/resource/messages-ecj/ValueOnRecord.java.messages1
131 files changed, 1314 insertions, 217 deletions
diff --git a/src/core/lombok/core/LombokNode.java b/src/core/lombok/core/LombokNode.java
index abfc66a6..34273a86 100644
--- a/src/core/lombok/core/LombokNode.java
+++ b/src/core/lombok/core/LombokNode.java
@@ -160,18 +160,16 @@ public abstract class LombokNode<A extends AST<A, L, N>, L extends LombokNode<A,
List<L> fields = new ArrayList<L>();
for (L potentialField : type.down()) {
if (potentialField.getKind() != Kind.FIELD) continue;
- if (fieldContainsAnnotation(potentialField.get(), get())) fields.add(potentialField);
+ for (L child : potentialField.down()) {
+ if (child.getKind() != Kind.ANNOTATION) continue;
+ if (child.get() == get()) fields.add(potentialField);
+ }
}
return fields;
}
/**
- * Return {@code true} if the annotation is attached to the field.
- */
- protected abstract boolean fieldContainsAnnotation(N field, N annotation);
-
- /**
* Returns the direct parent node in the AST tree of this node. For example, a local variable declaration's
* direct parent can be e.g. an If block, but its {@code up()} {@code LombokNode} is the {@code Method} that contains it.
*/
diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java
index 53a6a232..0036ec23 100644
--- a/src/core/lombok/eclipse/EclipseAST.java
+++ b/src/core/lombok/eclipse/EclipseAST.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2018 The Project Lombok Authors.
+ * Copyright (C) 2009-2021 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
@@ -32,7 +32,7 @@ import java.util.List;
import lombok.core.AST;
import lombok.core.LombokImmutableList;
-import lombok.eclipse.handlers.EclipseHandlerUtil;
+import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import lombok.permit.Permit;
import org.eclipse.core.resources.ResourcesPlugin;
@@ -115,7 +115,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
try {
return EclipseWorkspaceBasedFileResolver.resolve(fileName);
} catch (IllegalArgumentException e) {
- EclipseHandlerUtil.warning("Finding 'lombok.config' file failed for '" + fileName + "'", e);
+ warning("Finding 'lombok.config' file failed for '" + fileName + "'", e);
// String msg = e.getMessage();
// if (msg != null && msg.startsWith("Path must include project and resource name")) {
// // We shouldn't throw an exception at all, but we can't reproduce this so we need help from our users to figure this out.
@@ -345,7 +345,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
case TYPE:
return buildType((TypeDeclaration) node);
case FIELD:
- return buildField((FieldDeclaration) node);
+ return buildField((FieldDeclaration) node, null);
case INITIALIZER:
return buildInitializer((Initializer) node);
case METHOD:
@@ -384,16 +384,18 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
private EclipseNode buildType(TypeDeclaration type) {
if (setAndGetAsHandled(type)) return null;
List<EclipseNode> childNodes = new ArrayList<EclipseNode>();
- childNodes.addAll(buildFields(type.fields));
+ childNodes.addAll(buildFields(type.fields, getRecordFieldAnnotations(type)));
childNodes.addAll(buildTypes(type.memberTypes));
childNodes.addAll(buildMethods(type.methods));
childNodes.addAll(buildAnnotations(type.annotations, false));
return putInMap(new EclipseNode(this, type, childNodes, Kind.TYPE));
}
- private Collection<EclipseNode> buildFields(FieldDeclaration[] children) {
+ private Collection<EclipseNode> buildFields(FieldDeclaration[] children, Annotation[][] annotations) {
List<EclipseNode> childNodes = new ArrayList<EclipseNode>();
- if (children != null) for (FieldDeclaration child : children) addIfNotNull(childNodes, buildField(child));
+ if (children != null) for (int i = 0; i < children.length; i++) {
+ addIfNotNull(childNodes, buildField(children[i], annotations[i]));
+ }
return childNodes;
}
@@ -403,13 +405,13 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
return list;
}
- private EclipseNode buildField(FieldDeclaration field) {
- if (field instanceof Initializer) return buildInitializer((Initializer)field);
+ private EclipseNode buildField(FieldDeclaration field, Annotation[] annotations) {
+ if (field instanceof Initializer) return buildInitializer((Initializer) field);
if (setAndGetAsHandled(field)) return null;
List<EclipseNode> childNodes = new ArrayList<EclipseNode>();
addIfNotNull(childNodes, buildTypeUse(field.type));
addIfNotNull(childNodes, buildStatement(field.initialization));
- childNodes.addAll(buildAnnotations(field.annotations, true));
+ childNodes.addAll(buildAnnotations(annotations != null ? annotations : field.annotations, true));
return putInMap(new EclipseNode(this, field, childNodes, Kind.FIELD));
}
diff --git a/src/core/lombok/eclipse/EclipseNode.java b/src/core/lombok/eclipse/EclipseNode.java
index 12e9ccdb..4f86f0a5 100644
--- a/src/core/lombok/eclipse/EclipseNode.java
+++ b/src/core/lombok/eclipse/EclipseNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2020 The Project Lombok Authors.
+ * Copyright (C) 2009-2021 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
@@ -143,16 +143,6 @@ public class EclipseNode extends lombok.core.LombokNode<EclipseAST, EclipseNode,
}
}
- @Override protected boolean fieldContainsAnnotation(ASTNode field, ASTNode annotation) {
- if (!(field instanceof FieldDeclaration)) return false;
- FieldDeclaration f = (FieldDeclaration) field;
- if (f.annotations == null) return false;
- for (Annotation childAnnotation : f.annotations) {
- if (childAnnotation == annotation) return true;
- }
- return false;
- }
-
/** {@inheritDoc} */
@Override public String getName() {
final char[] n;
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index 68ba075b..defe8d34 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2020 The Project Lombok Authors.
+ * Copyright (C) 2009-2021 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
@@ -337,6 +337,7 @@ public class EclipseHandlerUtil {
public static final Field TYPE_REFERENCE__ANNOTATIONS;
public static final Class<?> INTERSECTION_BINDING1, INTERSECTION_BINDING2;
public static final Field INTERSECTION_BINDING_TYPES1, INTERSECTION_BINDING_TYPES2;
+ public static final Field TYPE_DECLARATION_RECORD_COMPONENTS;
static {
STRING_LITERAL__LINE_NUMBER = getField(StringLiteral.class, "lineNumber");
ANNOTATION__MEMBER_VALUE_PAIR_NAME = getField(Annotation.class, "memberValuePairName");
@@ -345,6 +346,7 @@ public class EclipseHandlerUtil {
INTERSECTION_BINDING2 = getClass("org.eclipse.jdt.internal.compiler.lookup.IntersectionCastTypeBinding");
INTERSECTION_BINDING_TYPES1 = INTERSECTION_BINDING1 == null ? null : getField(INTERSECTION_BINDING1, "intersectingTypes");
INTERSECTION_BINDING_TYPES2 = INTERSECTION_BINDING2 == null ? null : getField(INTERSECTION_BINDING2, "intersectingTypes");
+ TYPE_DECLARATION_RECORD_COMPONENTS = getField(TypeDeclaration.class, "recordComponents");
}
public static int reflectInt(Field f, Object o) {
@@ -776,13 +778,10 @@ public class EclipseHandlerUtil {
}
public static boolean hasNonNullAnnotations(EclipseNode node) {
- AbstractVariableDeclaration avd = (AbstractVariableDeclaration) node.get();
- if (avd.annotations == null) return false;
- for (Annotation annotation : avd.annotations) {
- TypeReference typeRef = annotation.type;
- if (typeRef != null && typeRef.getTypeName() != null) {
- for (String bn : NONNULL_ANNOTATIONS) if (typeMatches(bn, node, typeRef)) return true;
- }
+ for (EclipseNode child : node.down()) {
+ if (child.getKind() != Kind.ANNOTATION) continue;
+ Annotation annotation = (Annotation) child.get();
+ for (String bn : NONNULL_ANNOTATIONS) if (typeMatches(bn, node, annotation.type)) return true;
}
return false;
}
@@ -1877,15 +1876,12 @@ public class EclipseHandlerUtil {
public static MemberExistsResult constructorExists(EclipseNode node) {
node = upToTypeNode(node);
if (node != null && node.get() instanceof TypeDeclaration) {
- TypeDeclaration typeDecl = (TypeDeclaration)node.get();
+ TypeDeclaration typeDecl = (TypeDeclaration) node.get();
if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) {
- if (def instanceof ConstructorDeclaration) {
- if ((def.bits & ASTNode.IsDefaultConstructor) != 0) continue;
-
- if (isTolerate(node, def)) continue;
-
- return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK;
- }
+ if (!(def instanceof ConstructorDeclaration)) continue;
+ if ((def.bits & ASTNode.IsDefaultConstructor) != 0) continue;
+ if (isTolerate(node, def)) continue;
+ return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK;
}
}
@@ -1893,6 +1889,26 @@ public class EclipseHandlerUtil {
}
/**
+ * Checks if there is at least one constructor that is generated by lombok.
+ *
+ * @param node Any node that represents the Type (TypeDeclaration) to look in, or any child node thereof.
+ */
+ public static boolean lombokConstructorExists(EclipseNode node) {
+ node = upToTypeNode(node);
+ if (node != null && node.get() instanceof TypeDeclaration) {
+ TypeDeclaration typeDecl = (TypeDeclaration) node.get();
+ if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) {
+ if (!(def instanceof ConstructorDeclaration)) continue;
+ if ((def.bits & ASTNode.IsDefaultConstructor | IsCanonicalConstructor) != 0) continue;
+ if (isTolerate(node, def)) continue;
+ if (getGeneratedBy(def) != null) return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
* Inserts a field into an existing type. The type must represent a {@code TypeDeclaration}.
* The field carries the &#64;{@link SuppressWarnings}("all") annotation.
*/
@@ -2626,6 +2642,73 @@ public class EclipseHandlerUtil {
return generateQualifiedTypeRef(source, fromQualifiedName(typeName));
}
+ /**
+ * Returns {@code true} if the provided node is an actual class and not some other type declaration (so, not an annotation definition, interface, enum, or record).
+ */
+ public static boolean isClass(EclipseNode typeNode) {
+ return isTypeAndDoesNotHaveFlags(typeNode, ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation | AccRecord);
+ }
+
+ /**
+ * Returns {@code true} if the provided node is an actual class or enum and not some other type declaration (so, not an annotation definition, interface, or record).
+ */
+ public static boolean isClassOrEnum(EclipseNode typeNode) {
+ return isTypeAndDoesNotHaveFlags(typeNode, ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | AccRecord);
+ }
+
+ /**
+ * Returns {@code true} if the provided node is a record declaration (so, not an annotation definition, interface, enum, or plain class).
+ */
+ public static boolean isRecord(EclipseNode typeNode) {
+ TypeDeclaration typeDecl = null;
+ if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
+ int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
+ return (modifiers & AccRecord) != 0;
+ }
+
+ /**
+ * Returns {@code true} If the provided node is a field declaration, and represents a field in a {@code record} declaration.
+ */
+ public static boolean isRecordField(EclipseNode fieldNode) {
+ return fieldNode.getKind() == Kind.FIELD && (((FieldDeclaration) fieldNode.get()).modifiers & AccRecord) != 0;
+ }
+
+ /**
+ * Returns {@code true) if the provided node is a type declaration <em>and</em> is <strong>not</strong> of any kind indicated by the flags (the intent is to pass flags usch as `ClassFileConstants.AccEnum`).
+ */
+ static boolean isTypeAndDoesNotHaveFlags(EclipseNode typeNode, long flags) {
+ TypeDeclaration typeDecl = null;
+ if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
+ int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
+ return (modifiers & flags) == 0;
+ }
+
+ public static AbstractVariableDeclaration[] getRecordComponents(TypeDeclaration typeDeclaration) {
+ if (typeDeclaration == null || (typeDeclaration.modifiers & AccRecord) == 0) return null;
+ try {
+ return (AbstractVariableDeclaration[]) TYPE_DECLARATION_RECORD_COMPONENTS.get(typeDeclaration);
+ } catch (Exception e) {
+ // This presumably means this isn't a JDK16 - fall through.
+ }
+ return null;
+ }
+
+ public static Annotation[][] getRecordFieldAnnotations(TypeDeclaration typeDeclaration) {
+ if (typeDeclaration.fields == null) return null;
+ Annotation[][] annotations = new Annotation[typeDeclaration.fields.length][];
+
+ AbstractVariableDeclaration[] recordComponents = getRecordComponents(typeDeclaration);
+ if (recordComponents != null) {
+ int j = 0;
+ for (int i = 0; i < typeDeclaration.fields.length; i++) {
+ if ((typeDeclaration.fields[i].modifiers & AccRecord) != 0) {
+ annotations[i] = recordComponents[j++].annotations;
+ }
+ }
+ }
+ return annotations;
+ }
+
public static String getDocComment(CompilationUnitDeclaration cud, ASTNode node) {
ICompilationUnit compilationUnit = cud.compilationResult.compilationUnit;
if (node instanceof FieldDeclaration) {
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java
index 07297142..c2b73988 100755
--- a/src/core/lombok/eclipse/handlers/HandleBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java
@@ -253,6 +253,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
@Override public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) {
+ final String BUILDER_NODE_NOT_SUPPORTED_ERR = "@Builder is only supported on classes, records, constructors, and methods.";
+
handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
BuilderJob job = new BuilderJob();
job.sourceNode = annotationNode;
@@ -288,6 +290,11 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
List<EclipseNode> nonFinalNonDefaultedFields = null;
if (parent.get() instanceof TypeDeclaration) {
+ if (!isClass(parent) && !isRecord(parent)) {
+ annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR);
+ return;
+ }
+
job.parentType = parent;
TypeDeclaration td = (TypeDeclaration) parent.get();
@@ -336,8 +343,12 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
allFields.add(fieldNode);
}
- handleConstructor.generateConstructor(parent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER,
- Collections.<Annotation>emptyList(), annotationNode);
+ if (!isRecord(parent)) {
+ // Records ship with a canonical constructor that acts as @AllArgsConstructor - just use that one.
+
+ handleConstructor.generateConstructor(parent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER,
+ Collections.<Annotation>emptyList(), annotationNode);
+ }
job.typeParams = job.builderTypeParams = td.typeParameters;
buildMethodReturnType = job.createBuilderParentTypeReference();
@@ -446,7 +457,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
if (!checkName("builderClassName", job.builderClassName, annotationNode)) return;
}
} else {
- annotationNode.addError("@Builder is only supported on types, constructors, and methods.");
+ annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR);
return;
}
diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java
index e7f373a6..e69c3267 100755
--- a/src/core/lombok/eclipse/handlers/HandleConstructor.java
+++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java
@@ -194,12 +194,7 @@ public class HandleConstructor {
}
static boolean checkLegality(EclipseNode typeNode, EclipseNode errorNode, String name) {
- TypeDeclaration typeDecl = null;
- if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
- int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
- boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0;
-
- if (typeDecl == null || notAClass) {
+ if (!isClassOrEnum(typeNode)) {
errorNode.addError(name + " is only supported on a class or an enum.");
return false;
}
diff --git a/src/core/lombok/eclipse/handlers/HandleData.java b/src/core/lombok/eclipse/handlers/HandleData.java
index 67594dab..00e1fd38 100644
--- a/src/core/lombok/eclipse/handlers/HandleData.java
+++ b/src/core/lombok/eclipse/handlers/HandleData.java
@@ -22,6 +22,7 @@
package lombok.eclipse.handlers;
import static lombok.core.handlers.HandlerUtil.*;
+import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.util.Collections;
@@ -35,8 +36,6 @@ import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists;
import lombok.spi.Provides;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
-import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
-import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
/**
* Handles the {@code lombok.Data} annotation for eclipse.
@@ -55,13 +54,7 @@ public class HandleData extends EclipseAnnotationHandler<Data> {
Data ann = annotation.getInstance();
EclipseNode typeNode = annotationNode.up();
- TypeDeclaration typeDecl = null;
- if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
- int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
- boolean notAClass = (modifiers &
- (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) != 0;
-
- if (typeDecl == null || notAClass) {
+ if (!isClass(typeNode)) {
annotationNode.addError("@Data is only supported on a class.");
return;
}
diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
index bf81283b..753c489c 100755
--- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
@@ -144,18 +144,12 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
public void generateMethods(EclipseNode typeNode, EclipseNode errorNode, List<Included<EclipseNode, EqualsAndHashCode.Include>> members,
Boolean callSuper, boolean whineIfExists, boolean cacheHashCode, FieldAccess fieldAccess, List<Annotation> onParam) {
- TypeDeclaration typeDecl = null;
-
- if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
- int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
- boolean notAClass = (modifiers &
- (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) != 0;
-
- if (typeDecl == null || notAClass) {
+ if (!isClass(typeNode)) {
errorNode.addError("@EqualsAndHashCode is only supported on a class.");
return;
}
+ TypeDeclaration typeDecl = (TypeDeclaration) typeNode.get();
boolean implicitCallSuper = callSuper == null;
if (callSuper == null) {
diff --git a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
index ea86505d..5900e7ed 100644
--- a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
+++ b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java
@@ -63,13 +63,7 @@ public class HandleFieldDefaults extends EclipseASTAdapter {
}
}
- TypeDeclaration typeDecl = null;
- if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
- int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
- boolean notAClass = (modifiers &
- (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0;
-
- if (typeDecl == null || notAClass) {
+ if (!isClassOrEnum(typeNode)) {
pos.addError("@FieldDefaults is only supported on a class or an enum.");
return false;
}
diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java
index a9e2c5ba..7f8fdef2 100644
--- a/src/core/lombok/eclipse/handlers/HandleGetter.java
+++ b/src/core/lombok/eclipse/handlers/HandleGetter.java
@@ -81,6 +81,7 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
@Provides
public class HandleGetter extends EclipseAnnotationHandler<Getter> {
private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY = new Annotation[0];
+ private static final String GETTER_NODE_NOT_SUPPORTED_ERR = "@Getter is only supported on a class, an enum, or a field.";
public boolean generateGetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelGetter, List<Annotation> onMethod) {
if (checkForTypeLevelGetter) {
@@ -90,14 +91,8 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> {
}
}
- TypeDeclaration typeDecl = null;
- if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
- int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
- boolean notAClass = (modifiers &
- (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0;
-
- if (typeDecl == null || notAClass) {
- pos.addError("@Getter is only supported on a class, an enum, or a field.");
+ if (!isClassOrEnum(typeNode)) {
+ pos.addError(GETTER_NODE_NOT_SUPPORTED_ERR);
return false;
}
@@ -171,8 +166,9 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> {
public void createGetterForField(AccessLevel level,
EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists, boolean lazy, List<Annotation> onMethod) {
+
if (fieldNode.getKind() != Kind.FIELD) {
- errorNode.addError("@Getter is only supported on a class or a field.");
+ errorNode.addError(GETTER_NODE_NOT_SUPPORTED_ERR);
return;
}
diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java
index bf2b1358..df3989a4 100644
--- a/src/core/lombok/eclipse/handlers/HandleLog.java
+++ b/src/core/lombok/eclipse/handlers/HandleLog.java
@@ -52,7 +52,7 @@ import lombok.spi.Provides;
public class HandleLog {
private static final IdentifierName LOG = IdentifierName.valueOf("log");
-
+
private HandleLog() {
throw new UnsupportedOperationException();
}
@@ -82,10 +82,15 @@ public class HandleLog {
annotationNode.addWarning("Field '" + logFieldName + "' already exists.");
return;
}
-
+
+ if (isRecord(owner) && !useStatic) {
+ annotationNode.addError("Logger fields must be static in records.");
+ return;
+ }
+
Object valueGuess = annotation.getValueGuess("topic");
Expression loggerTopic = (Expression) annotation.getActualExpression("topic");
-
+
if (valueGuess instanceof String && ((String) valueGuess).trim().isEmpty()) loggerTopic = null;
if (framework.getDeclaration().getParametersWithTopic() == null && loggerTopic != null) {
annotationNode.addError(framework.getAnnotationAsString() + " does not allow a topic.");
diff --git a/src/core/lombok/eclipse/handlers/HandleNonNull.java b/src/core/lombok/eclipse/handlers/HandleNonNull.java
index 2fbf2030..27e78d32 100644
--- a/src/core/lombok/eclipse/handlers/HandleNonNull.java
+++ b/src/core/lombok/eclipse/handlers/HandleNonNull.java
@@ -26,6 +26,7 @@ import static lombok.eclipse.Eclipse.isPrimitive;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.util.Arrays;
+import java.util.Collections;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
@@ -47,18 +48,19 @@ import org.eclipse.jdt.internal.compiler.ast.ThrowStatement;
import org.eclipse.jdt.internal.compiler.ast.TryStatement;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import lombok.AccessLevel;
import lombok.ConfigurationKeys;
import lombok.NonNull;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
-import lombok.eclipse.DeferUntilPostDiet;
+import lombok.eclipse.EcjAugments;
import lombok.eclipse.EclipseAST;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
+import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists;
import lombok.spi.Provides;
-@DeferUntilPostDiet
@Provides
@HandlerPriority(value = 512) // 2^9; onParameter=@__(@NonNull) has to run first.
public class HandleNonNull extends EclipseAnnotationHandler<NonNull> {
@@ -66,6 +68,7 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> {
private static final char[] CHECK_NOT_NULL = "checkNotNull".toCharArray();
public static final HandleNonNull INSTANCE = new HandleNonNull();
+ private HandleConstructor handleConstructor = new HandleConstructor();
public void fix(EclipseNode method) {
for (EclipseNode m : method.down()) {
@@ -81,6 +84,17 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> {
}
@Override public void handle(AnnotationValues<NonNull> annotation, Annotation ast, EclipseNode annotationNode) {
+ // Generating new methods is only possible during diet parse but modifying existing methods requires a full parse.
+ // As we need both for @NonNull we reset the handled flag during diet parse.
+ if (!annotationNode.isCompleteParse()) {
+ EclipseNode typeNode = upToTypeNode(annotationNode);
+ if (isRecordField(annotationNode.up()) && !lombokConstructorExists(typeNode)) {
+ handleConstructor.generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, null, SkipIfConstructorExists.NO, Collections.<Annotation>emptyList(), annotationNode);
+ }
+ EcjAugments.ASTNode_handled.clear(ast);
+ return;
+ }
+
handle0(ast, annotationNode, false);
}
diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java
index 8ef40199..ddae21fb 100644
--- a/src/core/lombok/eclipse/handlers/HandleSetter.java
+++ b/src/core/lombok/eclipse/handlers/HandleSetter.java
@@ -63,6 +63,8 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
*/
@Provides
public class HandleSetter extends EclipseAnnotationHandler<Setter> {
+ private static final String SETTER_NODE_NOT_SUPPORTED_ERR = "@Setter is only supported on a class or a field.";
+
public boolean generateSetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelSetter, List<Annotation> onMethod, List<Annotation> onParam) {
if (checkForTypeLevelSetter) {
if (hasAnnotation(Setter.class, typeNode)) {
@@ -71,14 +73,8 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
}
}
- TypeDeclaration typeDecl = null;
- if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
- int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
- boolean notAClass = (modifiers &
- (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) != 0;
-
- if (typeDecl == null || notAClass) {
- pos.addError("@Setter is only supported on a class or a field.");
+ if (!isClass(typeNode)) {
+ pos.addError(SETTER_NODE_NOT_SUPPORTED_ERR);
return false;
}
@@ -148,7 +144,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
ASTNode source = sourceNode.get();
if (fieldNode.getKind() != Kind.FIELD) {
- sourceNode.addError("@Setter is only supported on a class or a field.");
+ sourceNode.addError(SETTER_NODE_NOT_SUPPORTED_ERR);
return;
}
diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
index 3599dbe0..4f4baecd 100644
--- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
@@ -180,10 +180,11 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
List<EclipseNode> nonFinalNonDefaultedFields = null;
- if (!(parent.get() instanceof TypeDeclaration)) {
- annotationNode.addError("@SuperBuilder is only supported on types.");
+ if (!isClass(parent)) {
+ annotationNode.addError("@SuperBuilder is only supported on classes.");
return;
}
+
job.parentType = parent;
TypeDeclaration td = (TypeDeclaration) parent.get();
diff --git a/src/core/lombok/eclipse/handlers/HandleSynchronized.java b/src/core/lombok/eclipse/handlers/HandleSynchronized.java
index 957ce827..18d1e7b7 100644
--- a/src/core/lombok/eclipse/handlers/HandleSynchronized.java
+++ b/src/core/lombok/eclipse/handlers/HandleSynchronized.java
@@ -148,6 +148,11 @@ public class HandleSynchronized extends EclipseAnnotationHandler<Synchronized> {
return;
}
+ EclipseNode typeNode = upToTypeNode(annotationNode);
+ if (!isClassOrEnum(typeNode)) {
+ annotationNode.addError("@Synchronized is legal only on methods in classes and enums.");
+ return;
+ }
boolean[] isStatic = { method.isStatic() };
char[] lockName = createLockField(annotation, annotationNode, isStatic, true);
if (lockName == null) return;
@@ -163,7 +168,6 @@ public class HandleSynchronized extends EclipseAnnotationHandler<Synchronized> {
Expression lockVariable;
if (isStatic[0]) {
- EclipseNode typeNode = upToTypeNode(annotationNode);
char[][] n = getQualifiedInnerName(typeNode, lockName);
long[] ps = new long[n.length];
Arrays.fill(ps, pos);
diff --git a/src/core/lombok/eclipse/handlers/HandleToString.java b/src/core/lombok/eclipse/handlers/HandleToString.java
index 7d70782a..72491277 100644
--- a/src/core/lombok/eclipse/handlers/HandleToString.java
+++ b/src/core/lombok/eclipse/handlers/HandleToString.java
@@ -50,7 +50,6 @@ import org.eclipse.jdt.internal.compiler.ast.SuperReference;
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
-import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import lombok.AccessLevel;
@@ -116,14 +115,7 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> {
public void generateToString(EclipseNode typeNode, EclipseNode errorNode, List<Included<EclipseNode, ToString.Include>> members,
boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) {
- TypeDeclaration typeDecl = null;
-
- if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
- int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
- boolean notAClass = (modifiers &
- (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0;
-
- if (typeDecl == null || notAClass) {
+ if (!isClassOrEnum(typeNode)) {
errorNode.addError("@ToString is only supported on a class or enum.");
return;
}
diff --git a/src/core/lombok/eclipse/handlers/HandleUtilityClass.java b/src/core/lombok/eclipse/handlers/HandleUtilityClass.java
index 8ea8cd12..9a18b20b 100644
--- a/src/core/lombok/eclipse/handlers/HandleUtilityClass.java
+++ b/src/core/lombok/eclipse/handlers/HandleUtilityClass.java
@@ -68,13 +68,8 @@ public class HandleUtilityClass extends EclipseAnnotationHandler<UtilityClass> {
}
private static boolean checkLegality(EclipseNode typeNode, EclipseNode errorNode) {
- TypeDeclaration typeDecl = null;
- if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
- int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
- boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) != 0;
-
- if (typeDecl == null || notAClass) {
- errorNode.addError("@UtilityClass is only supported on a class (can't be an interface, enum, or annotation).");
+ if (!isClass(typeNode)) {
+ errorNode.addError("@UtilityClass is only supported on a class.");
return false;
}
diff --git a/src/core/lombok/eclipse/handlers/HandleValue.java b/src/core/lombok/eclipse/handlers/HandleValue.java
index ce28b38d..7a73e5ed 100644
--- a/src/core/lombok/eclipse/handlers/HandleValue.java
+++ b/src/core/lombok/eclipse/handlers/HandleValue.java
@@ -59,16 +59,11 @@ public class HandleValue extends EclipseAnnotationHandler<Value> {
Value ann = annotation.getInstance();
EclipseNode typeNode = annotationNode.up();
- TypeDeclaration typeDecl = null;
- if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
- int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
- boolean notAClass = (modifiers &
- (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) != 0;
-
- if (typeDecl == null || notAClass) {
+ if (!isClass(typeNode)) {
annotationNode.addError("@Value is only supported on a class.");
return;
}
+ TypeDeclaration typeDecl = (TypeDeclaration) typeNode.get();
// Make class final.
if (!hasAnnotation(NonFinal.class, typeNode)) {
diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java
index 3de3f38b..035f7c53 100644
--- a/src/core/lombok/javac/JavacNode.java
+++ b/src/core/lombok/javac/JavacNode.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2020 The Project Lombok Authors.
+ * Copyright (C) 2009-2021 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
@@ -186,16 +186,6 @@ public class JavacNode extends lombok.core.LombokNode<JavacAST, JavacNode, JCTre
return false;
}
- @Override protected boolean fieldContainsAnnotation(JCTree field, JCTree annotation) {
- if (!(field instanceof JCVariableDecl)) return false;
- JCVariableDecl f = (JCVariableDecl) field;
- if (f.mods.annotations == null) return false;
- for (JCAnnotation childAnnotation : f.mods.annotations) {
- if (childAnnotation == annotation) return true;
- }
- return false;
- }
-
/**
* Convenient shortcut to the owning JavacAST object's getTreeMaker method.
*
diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java
index 911a2e39..a25baeb0 100644
--- a/src/core/lombok/javac/handlers/HandleBuilder.java
+++ b/src/core/lombok/javac/handlers/HandleBuilder.java
@@ -192,6 +192,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
}
@Override public void handle(AnnotationValues<Builder> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ final String BUILDER_NODE_NOT_SUPPORTED_ERR = "@Builder is only supported on classes, records, constructors, and methods.";
+
handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
BuilderJob job = new BuilderJob();
job.sourceNode = annotationNode;
@@ -229,6 +231,11 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
ArrayList<JavacNode> nonFinalNonDefaultedFields = null;
if (parent.get() instanceof JCClassDecl) {
+ if (!isClass(parent) && !isRecord(parent)) {
+ annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR);
+ return;
+ }
+
job.parentType = parent;
JCClassDecl td = (JCClassDecl) parent.get();
@@ -279,7 +286,11 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
allFields.append(fieldNode);
}
- handleConstructor.generateConstructor(parent, AccessLevel.PACKAGE, List.<JCAnnotation>nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, annotationNode);
+ if (!isRecord(parent)) {
+ // Records ship with a canonical constructor that acts as @AllArgsConstructor - just use that one.
+
+ handleConstructor.generateConstructor(parent, AccessLevel.PACKAGE, List.<JCAnnotation>nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, annotationNode);
+ }
buildMethodReturnType = namePlusTypeParamsToTypeReference(parent.getTreeMaker(), parent, td.typarams);
job.typeParams = job.builderTypeParams = td.typarams;
@@ -387,7 +398,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
}
}
} else {
- annotationNode.addError("@Builder is only supported on types, constructors, and methods.");
+ annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR);
return;
}
diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java
index 0defdefd..9c74ca0e 100644
--- a/src/core/lombok/javac/handlers/HandleConstructor.java
+++ b/src/core/lombok/javac/handlers/HandleConstructor.java
@@ -181,12 +181,7 @@ public class HandleConstructor {
}
public static boolean checkLegality(JavacNode typeNode, JavacNode errorNode, String name) {
- JCClassDecl typeDecl = null;
- if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get();
- long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags;
- boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION)) != 0;
-
- if (typeDecl == null || notAClass) {
+ if (!isClassOrEnum(typeNode)) {
errorNode.addError(name + " is only supported on a class or an enum.");
return false;
}
diff --git a/src/core/lombok/javac/handlers/HandleData.java b/src/core/lombok/javac/handlers/HandleData.java
index 5fe1e4fe..06524aa8 100644
--- a/src/core/lombok/javac/handlers/HandleData.java
+++ b/src/core/lombok/javac/handlers/HandleData.java
@@ -51,9 +51,8 @@ public class HandleData extends JavacAnnotationHandler<Data> {
deleteAnnotationIfNeccessary(annotationNode, Data.class);
JavacNode typeNode = annotationNode.up();
- boolean notAClass = !isClass(typeNode);
- if (notAClass) {
+ if (!isClass(typeNode)) {
annotationNode.addError("@Data is only supported on a class.");
return;
}
diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
index a75d551f..ffe882d8 100644
--- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
@@ -95,9 +95,9 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS);
boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
-
+
boolean cacheHashCode = ann.cacheStrategy() == CacheStrategy.LAZY;
-
+
generateMethods(typeNode, annotationNode, members, callSuper, true, cacheHashCode, fieldAccess, onParam);
}
@@ -118,13 +118,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
public void generateMethods(JavacNode typeNode, JavacNode source, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members,
Boolean callSuper, boolean whineIfExists, boolean cacheHashCode, FieldAccess fieldAccess, List<JCAnnotation> onParam) {
- boolean notAClass = true;
- if (typeNode.get() instanceof JCClassDecl) {
- long flags = ((JCClassDecl) typeNode.get()).mods.flags;
- notAClass = (flags & (Flags.INTERFACE | Flags.ANNOTATION | Flags.ENUM)) != 0;
- }
-
- if (notAClass) {
+ if (!isClass(typeNode)) {
source.addError("@EqualsAndHashCode is only supported on a class.");
return;
}
diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java
index 4a87c138..ebab67e3 100644
--- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java
+++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java
@@ -56,12 +56,7 @@ public class HandleFieldDefaults extends JavacASTAdapter {
}
}
- JCClassDecl typeDecl = null;
- if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get();
- long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags;
- boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION)) != 0;
-
- if (typeDecl == null || notAClass) {
+ if (!isClassOrEnum(typeNode)) {
errorNode.addError("@FieldDefaults is only supported on a class or an enum.");
return false;
}
diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java
index 4cfa3276..8f6de9bb 100644
--- a/src/core/lombok/javac/handlers/HandleGetter.java
+++ b/src/core/lombok/javac/handlers/HandleGetter.java
@@ -51,7 +51,6 @@ import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCBinary;
import com.sun.tools.javac.tree.JCTree.JCBlock;
-import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
import com.sun.tools.javac.tree.JCTree.JCIf;
@@ -72,6 +71,8 @@ import com.sun.tools.javac.util.Name;
*/
@Provides
public class HandleGetter extends JavacAnnotationHandler<Getter> {
+ private static final String GETTER_NODE_NOT_SUPPORTED_ERR = "@Getter is only supported on a class, an enum, or a field.";
+
public void generateGetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelGetter, List<JCAnnotation> onMethod) {
if (checkForTypeLevelGetter) {
if (hasAnnotation(Getter.class, typeNode)) {
@@ -80,13 +81,8 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
}
}
- JCClassDecl typeDecl = null;
- if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get();
- long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags;
- boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION)) != 0;
-
- if (typeDecl == null || notAClass) {
- errorNode.addError("@Getter is only supported on a class, an enum, or a field.");
+ if (!isClassOrEnum(typeNode)) {
+ errorNode.addError(GETTER_NODE_NOT_SUPPORTED_ERR);
return;
}
@@ -170,7 +166,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
JavacNode fieldNode, JavacNode source, boolean whineIfExists, boolean lazy, List<JCAnnotation> onMethod) {
if (fieldNode.getKind() != Kind.FIELD) {
- source.addError("@Getter is only supported on a class or a field.");
+ source.addError(GETTER_NODE_NOT_SUPPORTED_ERR);
return;
}
diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java
index 674aa62c..47c4098f 100644
--- a/src/core/lombok/javac/handlers/HandleLog.java
+++ b/src/core/lombok/javac/handlers/HandleLog.java
@@ -31,6 +31,7 @@ import lombok.core.configuration.IdentifierName;
import lombok.core.configuration.LogDeclaration;
import lombok.core.configuration.LogDeclaration.LogFactoryParameter;
import lombok.core.handlers.LoggingFramework;
+import lombok.javac.Javac;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
@@ -74,9 +75,14 @@ public class HandleLog {
return;
}
+ if (isRecord(typeNode) && !useStatic) {
+ annotationNode.addError("Logger fields must be static in records.");
+ return;
+ }
+
Object valueGuess = annotation.getValueGuess("topic");
JCExpression loggerTopic = (JCExpression) annotation.getActualExpression("topic");
-
+
if (valueGuess instanceof String && ((String) valueGuess).trim().isEmpty()) loggerTopic = null;
if (framework.getDeclaration().getParametersWithTopic() == null && loggerTopic != null) {
annotationNode.addError(framework.getAnnotationAsString() + " does not allow a topic.");
@@ -118,7 +124,14 @@ public class HandleLog {
maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (useStatic ? Flags.STATIC : 0)),
typeNode.toName(logFieldName), loggerType, factoryMethodCall), source);
- injectFieldAndMarkGenerated(typeNode, fieldDecl);
+ if (isRecord(typeNode) && Javac.getJavaCompilerVersion() < 16) {
+ // This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8243057
+
+ injectField(typeNode, fieldDecl);
+ } else {
+ injectFieldAndMarkGenerated(typeNode, fieldDecl);
+ }
+
return true;
}
diff --git a/src/core/lombok/javac/handlers/HandleNonNull.java b/src/core/lombok/javac/handlers/HandleNonNull.java
index 174c31de..2f359c0f 100644
--- a/src/core/lombok/javac/handlers/HandleNonNull.java
+++ b/src/core/lombok/javac/handlers/HandleNonNull.java
@@ -49,6 +49,7 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
+import lombok.AccessLevel;
import lombok.ConfigurationKeys;
import lombok.NonNull;
import lombok.core.AST.Kind;
@@ -56,11 +57,14 @@ import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
+import lombok.javac.handlers.HandleConstructor.SkipIfConstructorExists;
import lombok.spi.Provides;
@Provides
@HandlerPriority(value = 512) // 2^9; onParameter=@__(@NonNull) has to run first.
public class HandleNonNull extends JavacAnnotationHandler<NonNull> {
+ private HandleConstructor handleConstructor = new HandleConstructor();
+
@Override public void handle(AnnotationValues<NonNull> annotation, JCAnnotation ast, JavacNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.NON_NULL_FLAG_USAGE, "@NonNull");
@@ -122,6 +126,14 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> {
String expectedName = paramNode.getName();
+ JavacNode typeNode = upToTypeNode(annotationNode);
+
+ if ((declaration.mods.flags & RECORD) != 0) {
+ if (!lombokConstructorExists(typeNode)) {
+ handleConstructor.generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, null, SkipIfConstructorExists.NO, annotationNode);
+ }
+ }
+
/* Abort if the null check is already there, delving into try and synchronized statements */ {
List<JCStatement> stats = statements;
int idx = 0;
diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java
index a4fb1b71..5c34f9f5 100644
--- a/src/core/lombok/javac/handlers/HandleSetter.java
+++ b/src/core/lombok/javac/handlers/HandleSetter.java
@@ -61,6 +61,8 @@ import com.sun.tools.javac.util.Name;
*/
@Provides
public class HandleSetter extends JavacAnnotationHandler<Setter> {
+ private static final String SETTER_NODE_NOT_SUPPORTED_ERR = "@Setter is only supported on a class or a field.";
+
public void generateSetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelSetter, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
if (checkForTypeLevelSetter) {
if (hasAnnotation(Setter.class, typeNode)) {
@@ -69,13 +71,8 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
}
}
- JCClassDecl typeDecl = null;
- if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get();
- long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags;
- boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION | Flags.ENUM)) != 0;
-
- if (typeDecl == null || notAClass) {
- errorNode.addError("@Setter is only supported on a class or a field.");
+ if (!isClass(typeNode)) {
+ errorNode.addError(SETTER_NODE_NOT_SUPPORTED_ERR);
return;
}
@@ -149,7 +146,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
public void createSetterForField(AccessLevel level, JavacNode fieldNode, JavacNode sourceNode, boolean whineIfExists, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
if (fieldNode.getKind() != Kind.FIELD) {
- fieldNode.addError("@Setter is only supported on a class or a field.");
+ fieldNode.addError(SETTER_NODE_NOT_SUPPORTED_ERR);
return;
}
diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java
index 17b54f3c..9185cedf 100644
--- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java
+++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java
@@ -159,14 +159,15 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
List<JCExpression> superclassTypeParams = List.nil();
boolean addCleaning = false;
- if (!(parent.get() instanceof JCClassDecl)) {
- annotationNode.addError("@SuperBuilder is only supported on types.");
+ if (!isClass(parent)) {
+ annotationNode.addError("@SuperBuilder is only supported on classes.");
return;
}
- // Gather all fields of the class that should be set by the builder.
job.parentType = parent;
JCClassDecl td = (JCClassDecl) parent.get();
+
+ // Gather all fields of the class that should be set by the builder.
ArrayList<JavacNode> nonFinalNonDefaultedFields = null;
boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent));
diff --git a/src/core/lombok/javac/handlers/HandleSynchronized.java b/src/core/lombok/javac/handlers/HandleSynchronized.java
index ca4a8293..0bf7cbe8 100644
--- a/src/core/lombok/javac/handlers/HandleSynchronized.java
+++ b/src/core/lombok/javac/handlers/HandleSynchronized.java
@@ -76,6 +76,12 @@ public class HandleSynchronized extends JavacAnnotationHandler<Synchronized> {
return;
}
+ JavacNode typeNode = upToTypeNode(annotationNode);
+ if (!isClassOrEnum(typeNode)) {
+ annotationNode.addError("@Synchronized is legal only on methods in classes and enums.");
+ return;
+ }
+
boolean[] isStatic = new boolean[] {(method.mods.flags & Flags.STATIC) != 0};
String lockName = annotation.getInstance().value();
boolean autoMake = false;
@@ -86,8 +92,6 @@ public class HandleSynchronized extends JavacAnnotationHandler<Synchronized> {
JavacTreeMaker maker = methodNode.getTreeMaker().at(ast.pos);
- JavacNode typeNode = upToTypeNode(annotationNode);
-
MemberExistsResult exists = MemberExistsResult.NOT_EXISTS;
if (typeNode != null && typeNode.get() instanceof JCClassDecl) {
diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java
index 1b76285f..3fc6a4e4 100644
--- a/src/core/lombok/javac/handlers/HandleToString.java
+++ b/src/core/lombok/javac/handlers/HandleToString.java
@@ -105,13 +105,7 @@ public class HandleToString extends JavacAnnotationHandler<ToString> {
public void generateToString(JavacNode typeNode, JavacNode source, java.util.List<Included<JavacNode, ToString.Include>> members,
boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) {
- boolean notAClass = true;
- if (typeNode.get() instanceof JCClassDecl) {
- long flags = ((JCClassDecl) typeNode.get()).mods.flags;
- notAClass = (flags & (Flags.INTERFACE | Flags.ANNOTATION)) != 0;
- }
-
- if (notAClass) {
+ if (!isClassOrEnum(typeNode)) {
source.addError("@ToString is only supported on a class or enum.");
return;
}
diff --git a/src/core/lombok/javac/handlers/HandleUtilityClass.java b/src/core/lombok/javac/handlers/HandleUtilityClass.java
index cb8a72ad..e006cc47 100644
--- a/src/core/lombok/javac/handlers/HandleUtilityClass.java
+++ b/src/core/lombok/javac/handlers/HandleUtilityClass.java
@@ -67,13 +67,8 @@ public class HandleUtilityClass extends JavacAnnotationHandler<UtilityClass> {
}
private static boolean checkLegality(JavacNode typeNode, JavacNode errorNode) {
- JCClassDecl typeDecl = null;
- if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get();
- long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags;
- boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION | Flags.ENUM)) != 0;
-
- if (typeDecl == null || notAClass) {
- errorNode.addError("@UtilityClass is only supported on a class (can't be an interface, enum, or annotation).");
+ if (!isClass(typeNode)) {
+ errorNode.addError("@UtilityClass is only supported on a class.");
return false;
}
diff --git a/src/core/lombok/javac/handlers/HandleWithBy.java b/src/core/lombok/javac/handlers/HandleWithBy.java
index b88f2c14..f1f953b3 100644
--- a/src/core/lombok/javac/handlers/HandleWithBy.java
+++ b/src/core/lombok/javac/handlers/HandleWithBy.java
@@ -125,7 +125,6 @@ public class HandleWithBy extends JavacAnnotationHandler<WithBy> {
@Override public void handle(AnnotationValues<WithBy> annotation, JCAnnotation ast, JavacNode annotationNode) {
handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.WITHBY_FLAG_USAGE, "@WithBy");
- Collection<JavacNode> fields = annotationNode.upFromAnnotationToFields();
deleteAnnotationIfNeccessary(annotationNode, WithBy.class);
deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
JavacNode node = annotationNode.up();
@@ -137,7 +136,7 @@ public class HandleWithBy extends JavacAnnotationHandler<WithBy> {
switch (node.getKind()) {
case FIELD:
- createWithByForFields(level, fields, annotationNode, true, onMethod);
+ createWithByForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, true, onMethod);
break;
case TYPE:
if (!onMethod.isEmpty()) annotationNode.addError("'onMethod' is not supported for @WithBy on a type.");
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index 5cbe08da..b4f2acc4 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2020 The Project Lombok Authors.
+ * Copyright (C) 2009-2021 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
@@ -807,7 +807,7 @@ public class JavacHandlerUtil {
node = upToTypeNode(node);
if (node != null && node.get() instanceof JCClassDecl) {
- for (JCTree def : ((JCClassDecl)node.get()).defs) {
+ for (JCTree def : ((JCClassDecl) node.get()).defs) {
if (def instanceof JCMethodDecl) {
JCMethodDecl md = (JCMethodDecl) def;
if (md.name.contentEquals("<init>")) {
@@ -822,6 +822,30 @@ public class JavacHandlerUtil {
return MemberExistsResult.NOT_EXISTS;
}
+ /**
+ * Checks if there is at least one constructor that is generated by lombok.
+ *
+ * @param node Any node that represents the Type (TypeDeclaration) to look in, or any child node thereof.
+ */
+ public static boolean lombokConstructorExists(JavacNode node) {
+ node = upToTypeNode(node);
+
+ if (node != null && node.get() instanceof JCClassDecl) {
+ for (JCTree def : ((JCClassDecl) node.get()).defs) {
+ if (def instanceof JCMethodDecl) {
+ JCMethodDecl md = (JCMethodDecl) def;
+ if (md.name.contentEquals("<init>")) {
+ if ((md.mods.flags & Flags.GENERATEDCONSTR) != 0) continue;
+ if (isTolerate(node, md)) continue;
+ if (getGeneratedBy(def) != null) return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
public static boolean isConstructorCall(final JCStatement statement) {
if (!(statement instanceof JCExpressionStatement)) return false;
JCExpression expr = ((JCExpressionStatement) statement).expr;
@@ -1924,17 +1948,30 @@ public class JavacHandlerUtil {
return out.toList();
}
- static boolean isClass(JavacNode typeNode) {
- return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ENUM | Flags.ANNOTATION);
+ /**
+ * Returns {@code true} if the provided node is an actual class and not some other type declaration (so, not an annotation definition, interface, enum, or record).
+ */
+ public static boolean isClass(JavacNode typeNode) {
+ return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ENUM | Flags.ANNOTATION | RECORD);
+ }
+
+ /**
+ * Returns {@code true} if the provided node is an actual class or enum and not some other type declaration (so, not an annotation definition, interface, or record).
+ */
+ public static boolean isClassOrEnum(JavacNode typeNode) {
+ return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ANNOTATION | RECORD);
}
- static boolean isClassOrEnum(JavacNode typeNode) {
- return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ANNOTATION);
+ /**
+ * Returns {@code true} if the provided node is a record declaration (so, not an annotation definition, interface, enum, or plain class).
+ */
+ public static boolean isRecord(JavacNode typeNode) {
+ return typeNode.getKind() == Kind.TYPE && (((JCClassDecl) typeNode.get()).mods.flags & RECORD) != 0;
}
- public static boolean isClassAndDoesNotHaveFlags(JavacNode typeNode, int flags) {
+ public static boolean isClassAndDoesNotHaveFlags(JavacNode typeNode, long flags) {
JCClassDecl typeDecl = null;
- if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl)typeNode.get();
+ if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get();
else return false;
long typeDeclflags = typeDecl == null ? 0 : typeDecl.mods.flags;
diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java
index 7531b0b1..05904815 100644
--- a/src/delombok/lombok/delombok/PrettyPrinter.java
+++ b/src/delombok/lombok/delombok/PrettyPrinter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2020 The Project Lombok Authors.
+ * Copyright (C) 2016-2021 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
@@ -514,10 +514,12 @@ public class PrettyPrinter extends JCTree.Visitor {
boolean isInterface = (tree.mods.flags & INTERFACE) != 0;
boolean isAnnotationInterface = isInterface && (tree.mods.flags & ANNOTATION) != 0;
boolean isEnum = (tree.mods.flags & ENUM) != 0;
+ boolean isRecord = (tree.mods.flags & RECORD) != 0;
if (isAnnotationInterface) print("@interface ");
else if (isInterface) print("interface ");
else if (isEnum) print("enum ");
+ else if (isRecord) print("record ");
else print("class ");
print(tree.name);
@@ -540,6 +542,8 @@ public class PrettyPrinter extends JCTree.Visitor {
print(tree.implementing, ", ");
}
+ if (isRecord) printRecordConstructor(tree.defs);
+
println(" {");
indent++;
printClassMembers(tree.defs, isEnum, isInterface);
@@ -549,6 +553,23 @@ public class PrettyPrinter extends JCTree.Visitor {
currentTypeName = prevTypeName;
}
+ private void printRecordConstructor(List<JCTree> members) {
+ boolean first = true;
+ print("(");
+ for (JCTree member : members) {
+ if (member instanceof JCVariableDecl) {
+ JCVariableDecl variableDecl = (JCVariableDecl) member;
+ if ((variableDecl.mods.flags & GENERATED_MEMBER) != 0) {
+ if (!first) print(", ");
+ first = false;
+ printAnnotations(variableDecl.mods.annotations, false);
+ printVarDef0(variableDecl);
+ }
+ }
+ }
+ print(")");
+ }
+
private void printClassMembers(List<JCTree> members, boolean isEnum, boolean isInterface) {
Class<?> prefType = null;
int typeOfPrevEnumMember = isEnum ? 3 : 0; // 1 = normal, 2 = with body, 3 = no enum field yet.
@@ -578,6 +599,7 @@ public class PrettyPrinter extends JCTree.Visitor {
JCTree init = ((JCVariableDecl) member).init;
typeOfPrevEnumMember = init instanceof JCNewClass && ((JCNewClass) init).def != null ? 2 : 1;
} else if (member instanceof JCVariableDecl) {
+ if ((((JCVariableDecl) member).mods.flags & GENERATED_MEMBER) != 0) continue;
if (prefType != null && prefType != JCVariableDecl.class) println();
if (isInterface) flagMod = -1L & ~(PUBLIC | STATIC | FINAL);
print(member);
diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java
index 31979955..ac15f90b 100644
--- a/src/utils/lombok/eclipse/Eclipse.java
+++ b/src/utils/lombok/eclipse/Eclipse.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2019 The Project Lombok Authors.
+ * Copyright (C) 2009-2021 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
@@ -60,6 +60,11 @@ public class Eclipse {
*/
public static final int ECLIPSE_DO_NOT_TOUCH_FLAG = ASTNode.Bit24;
+ /* This section includes flags that would ordinarily be in ClassFileConstants, but which are 'too new' (we don't compile against older versions of ecj/eclipse for compatibility). */
+ public static final int AccRecord = ASTNode.Bit25;
+ public static final int IsCanonicalConstructor = ASTNode.Bit10; // For record declarations, and presumably later on any constructor matching the destructor.
+ public static final int IsImplicit = ASTNode.Bit11; // the generated statements in the compact constructor of a record.
+
private static final Pattern SPLIT_AT_DOT = Pattern.compile("\\.");
private Eclipse() {
@@ -239,9 +244,14 @@ public class Eclipse {
for (Field f : CompilerOptions.class.getDeclaredFields()) {
try {
- if (f.getName().startsWith("VERSION_1_")) {
- ecjCompilerVersionCached = Math.max(ecjCompilerVersionCached, Integer.parseInt(f.getName().substring("VERSION_1_".length())));
- }
+ String fName = f.getName();
+ String versionNumber = null;
+ if (fName.startsWith("VERSION_1_")) {
+ versionNumber = fName.substring("VERSION_1_".length());
+ } else if (fName.startsWith("VERSION_")) {
+ versionNumber = fName.substring("VERSION_".length());
+ } else continue;
+ ecjCompilerVersionCached = Math.max(ecjCompilerVersionCached, Integer.parseInt(versionNumber));
} catch (Exception ignore) {}
}
diff --git a/src/utils/lombok/eclipse/Java14Bits.java b/src/utils/lombok/eclipse/Java14Bits.java
new file mode 100644
index 00000000..c7e00c39
--- /dev/null
+++ b/src/utils/lombok/eclipse/Java14Bits.java
@@ -0,0 +1,11 @@
+package lombok.eclipse;
+
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+
+public class Java14Bits {
+ private Java14Bits() { }
+
+ public static final int AccRecord = ASTNode.Bit25;
+ public static final int IsCanonicalConstructor = ASTNode.Bit10; // record declaration
+ public static final int IsImplicit = ASTNode.Bit11; // record declaration / generated statements in compact constructor
+}
diff --git a/src/utils/lombok/javac/Java14Flags.java b/src/utils/lombok/javac/Java14Flags.java
new file mode 100644
index 00000000..0d565dca
--- /dev/null
+++ b/src/utils/lombok/javac/Java14Flags.java
@@ -0,0 +1,26 @@
+package lombok.javac;
+
+public class Java14Flags {
+ private Java14Flags() { }
+
+ /**
+ * Flag to indicate that a class is a record. The flag is also used to mark fields that are
+ * part of the state vector of a record and to mark the canonical constructor
+ */
+ public static final long RECORD = 1L<<61; // ClassSymbols, MethodSymbols and VarSymbols
+
+ /**
+ * Flag to mark a record constructor as a compact one
+ */
+ public static final long COMPACT_RECORD_CONSTRUCTOR = 1L<<51; // MethodSymbols only
+
+ /**
+ * Flag to mark a record field that was not initialized in the compact constructor
+ */
+ public static final long UNINITIALIZED_FIELD= 1L<<51; // VarSymbols only
+
+ /** Flag is set for compiler-generated record members, it could be appplied to
+ * accessors and fields
+ */
+ public static final int GENERATED_MEMBER = 1<<24; // MethodSymbols and VarSymbols
+}
diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java
index 27926507..c0bda93c 100644
--- a/src/utils/lombok/javac/Javac.java
+++ b/src/utils/lombok/javac/Javac.java
@@ -75,6 +75,12 @@ public class Javac {
private static final AtomicInteger compilerVersion = new AtomicInteger(-1);
+ /* This section includes flags that would ordinarily be in Flags, but which are 'too new' (we don't compile against older versions of javac for compatibility). */
+ public static final long RECORD = 1L << 61; // ClassSymbols, MethodSymbols, VarSymbols (Marks types as being records, as well as the 'fields' in the compact declaration, and the canonical constructor)
+ public static final long COMPACT_RECORD_CONSTRUCTOR = 1L << 51; // MethodSymbols (the 'implicit' many-args constructor that records have)
+ public static final long UNINITIALIZED_FIELD = 1L << 51; // VarSymbols (To identify fields that the compact record constructor won't initialize)
+ public static final long GENERATED_MEMBER = 1L << 24; // MethodSymbols, VarSymbols (marks methods and the constructor generated in records)
+
/**
* Returns the version of this java compiler, i.e. the JDK that it shipped in. For example, for javac v1.7, this returns {@code 7}.
*/
diff --git a/test/core/src/lombok/RunTestsViaEcj.java b/test/core/src/lombok/RunTestsViaEcj.java
index 995f4a69..1c2be160 100644
--- a/test/core/src/lombok/RunTestsViaEcj.java
+++ b/test/core/src/lombok/RunTestsViaEcj.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2020 The Project Lombok Authors.
+ * Copyright (C) 2010-2021 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
@@ -85,6 +85,8 @@ public class RunTestsViaEcj extends AbstractRunTests {
warnings.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, "ignore");
warnings.put(CompilerOptions.OPTION_ReportIndirectStaticAccess, "warning");
warnings.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, "warning");
+ warnings.put("org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures", "enabled");
+ warnings.put("org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures", "ignore");
int ecjVersion = Eclipse.getEcjCompilerVersion();
warnings.put(CompilerOptions.OPTION_Source, (ecjVersion < 9 ? "1." : "") + ecjVersion);
options.set(warnings);
diff --git a/test/transform/resource/after-delombok/BuilderSimpleOnRecord.java b/test/transform/resource/after-delombok/BuilderSimpleOnRecord.java
new file mode 100644
index 00000000..03aca3aa
--- /dev/null
+++ b/test/transform/resource/after-delombok/BuilderSimpleOnRecord.java
@@ -0,0 +1,43 @@
+import java.util.List;
+
+record BuilderSimpleOnRecord<T>(List<T> l, String a) {
+ @java.lang.SuppressWarnings("all")
+ protected static class BuilderSimpleOnRecordBuilder<T> {
+ @java.lang.SuppressWarnings("all")
+ private List<T> l;
+ @java.lang.SuppressWarnings("all")
+ private String a;
+
+ @java.lang.SuppressWarnings("all")
+ BuilderSimpleOnRecordBuilder() {
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSimpleOnRecord.BuilderSimpleOnRecordBuilder<T> l(final List<T> l) {
+ this.l = l;
+ return this;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSimpleOnRecord.BuilderSimpleOnRecordBuilder<T> a(final String a) {
+ this.a = a;
+ return this;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSimpleOnRecord<T> build() {
+ return new BuilderSimpleOnRecord<T>(this.l, this.a);
+ }
+
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public java.lang.String toString() {
+ return "BuilderSimpleOnRecord.BuilderSimpleOnRecordBuilder(l=" + this.l + ", a=" + this.a + ")";
+ }
+ }
+
+ @java.lang.SuppressWarnings("all")
+ protected static <T> BuilderSimpleOnRecord.BuilderSimpleOnRecordBuilder<T> builder() {
+ return new BuilderSimpleOnRecord.BuilderSimpleOnRecordBuilder<T>();
+ }
+}
diff --git a/test/transform/resource/after-delombok/BuilderSingularOnRecord.java b/test/transform/resource/after-delombok/BuilderSingularOnRecord.java
new file mode 100644
index 00000000..32b37865
--- /dev/null
+++ b/test/transform/resource/after-delombok/BuilderSingularOnRecord.java
@@ -0,0 +1,136 @@
+import java.util.Collection;
+import java.util.List;
+
+record BuilderSingularOnRecord<T>(List<T> children, Collection<? extends Number> scarves, @SuppressWarnings("all") List rawList) {
+ @java.lang.SuppressWarnings("all")
+ public static class BuilderSingularOnRecordBuilder<T> {
+ @java.lang.SuppressWarnings("all")
+ private java.util.ArrayList<T> children;
+ @java.lang.SuppressWarnings("all")
+ private java.util.ArrayList<Number> scarves;
+ @java.lang.SuppressWarnings("all")
+ private java.util.ArrayList<java.lang.Object> rawList;
+
+ @java.lang.SuppressWarnings("all")
+ BuilderSingularOnRecordBuilder() {
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> child(final T child) {
+ if (this.children == null) this.children = new java.util.ArrayList<T>();
+ this.children.add(child);
+ return this;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> children(final java.util.Collection<? extends T> children) {
+ if (children == null) {
+ throw new java.lang.NullPointerException("children cannot be null");
+ }
+ if (this.children == null) this.children = new java.util.ArrayList<T>();
+ this.children.addAll(children);
+ return this;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> clearChildren() {
+ if (this.children != null) this.children.clear();
+ return this;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> scarf(final Number scarf) {
+ if (this.scarves == null) this.scarves = new java.util.ArrayList<Number>();
+ this.scarves.add(scarf);
+ return this;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> scarves(final java.util.Collection<? extends Number> scarves) {
+ if (scarves == null) {
+ throw new java.lang.NullPointerException("scarves cannot be null");
+ }
+ if (this.scarves == null) this.scarves = new java.util.ArrayList<Number>();
+ this.scarves.addAll(scarves);
+ return this;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> clearScarves() {
+ if (this.scarves != null) this.scarves.clear();
+ return this;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> rawList(final java.lang.Object rawList) {
+ if (this.rawList == null) this.rawList = new java.util.ArrayList<java.lang.Object>();
+ this.rawList.add(rawList);
+ return this;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> rawList(final java.util.Collection<?> rawList) {
+ if (rawList == null) {
+ throw new java.lang.NullPointerException("rawList cannot be null");
+ }
+ if (this.rawList == null) this.rawList = new java.util.ArrayList<java.lang.Object>();
+ this.rawList.addAll(rawList);
+ return this;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> clearRawList() {
+ if (this.rawList != null) this.rawList.clear();
+ return this;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public BuilderSingularOnRecord<T> build() {
+ java.util.List<T> children;
+ switch (this.children == null ? 0 : this.children.size()) {
+ case 0:
+ children = java.util.Collections.emptyList();
+ break;
+ case 1:
+ children = java.util.Collections.singletonList(this.children.get(0));
+ break;
+ default:
+ children = java.util.Collections.unmodifiableList(new java.util.ArrayList<T>(this.children));
+ }
+ java.util.Collection<Number> scarves;
+ switch (this.scarves == null ? 0 : this.scarves.size()) {
+ case 0:
+ scarves = java.util.Collections.emptyList();
+ break;
+ case 1:
+ scarves = java.util.Collections.singletonList(this.scarves.get(0));
+ break;
+ default:
+ scarves = java.util.Collections.unmodifiableList(new java.util.ArrayList<Number>(this.scarves));
+ }
+ java.util.List<java.lang.Object> rawList;
+ switch (this.rawList == null ? 0 : this.rawList.size()) {
+ case 0:
+ rawList = java.util.Collections.emptyList();
+ break;
+ case 1:
+ rawList = java.util.Collections.singletonList(this.rawList.get(0));
+ break;
+ default:
+ rawList = java.util.Collections.unmodifiableList(new java.util.ArrayList<java.lang.Object>(this.rawList));
+ }
+ return new BuilderSingularOnRecord<T>(children, scarves, rawList);
+ }
+
+ @java.lang.Override
+ @java.lang.SuppressWarnings("all")
+ public java.lang.String toString() {
+ return "BuilderSingularOnRecord.BuilderSingularOnRecordBuilder(children=" + this.children + ", scarves=" + this.scarves + ", rawList=" + this.rawList + ")";
+ }
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public static <T> BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> builder() {
+ return new BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T>();
+ }
+}
diff --git a/test/transform/resource/after-delombok/ConstructorsOnRecord.java b/test/transform/resource/after-delombok/ConstructorsOnRecord.java
new file mode 100644
index 00000000..8cef8809
--- /dev/null
+++ b/test/transform/resource/after-delombok/ConstructorsOnRecord.java
@@ -0,0 +1,2 @@
+record ConstructorsOnRecord(String a, String b) {
+}
diff --git a/test/transform/resource/after-delombok/DataOnRecord.java b/test/transform/resource/after-delombok/DataOnRecord.java
new file mode 100644
index 00000000..b4384dce
--- /dev/null
+++ b/test/transform/resource/after-delombok/DataOnRecord.java
@@ -0,0 +1,2 @@
+record DataOnRecord(String a, String b) {
+}
diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeOnRecord.java b/test/transform/resource/after-delombok/EqualsAndHashCodeOnRecord.java
new file mode 100644
index 00000000..949cdec6
--- /dev/null
+++ b/test/transform/resource/after-delombok/EqualsAndHashCodeOnRecord.java
@@ -0,0 +1,2 @@
+record EqualsAndHashCodeOnRecord(String a, String b) {
+}
diff --git a/test/transform/resource/after-delombok/FieldDefaultsOnRecord.java b/test/transform/resource/after-delombok/FieldDefaultsOnRecord.java
new file mode 100644
index 00000000..1287dcb0
--- /dev/null
+++ b/test/transform/resource/after-delombok/FieldDefaultsOnRecord.java
@@ -0,0 +1,2 @@
+record FieldDefaultsOnRecord(String a, String b) {
+}
diff --git a/test/transform/resource/after-delombok/FieldNameConstantsOnRecord.java b/test/transform/resource/after-delombok/FieldNameConstantsOnRecord.java
new file mode 100644
index 00000000..2e3339fa
--- /dev/null
+++ b/test/transform/resource/after-delombok/FieldNameConstantsOnRecord.java
@@ -0,0 +1,9 @@
+record FieldNameConstantsOnRecord(String iAmADvdPlayer, int $skipMe, int andMe, String butPrintMePlease) {
+ static double skipMeToo;
+
+ @java.lang.SuppressWarnings("all")
+ static final class Fields {
+ public static final java.lang.String iAmADvdPlayer = "iAmADvdPlayer";
+ public static final java.lang.String butPrintMePlease = "butPrintMePlease";
+ }
+}
diff --git a/test/transform/resource/after-delombok/GetterOnRecord.java b/test/transform/resource/after-delombok/GetterOnRecord.java
new file mode 100644
index 00000000..5090e92d
--- /dev/null
+++ b/test/transform/resource/after-delombok/GetterOnRecord.java
@@ -0,0 +1,2 @@
+record GetterOnRecord(String a, String b) {
+}
diff --git a/test/transform/resource/after-delombok/LoggerConfigOnRecord.java b/test/transform/resource/after-delombok/LoggerConfigOnRecord.java
new file mode 100644
index 00000000..5b43f24e
--- /dev/null
+++ b/test/transform/resource/after-delombok/LoggerConfigOnRecord.java
@@ -0,0 +1,2 @@
+record LoggerConfigOnRecord(String a, String b) {
+}
diff --git a/test/transform/resource/after-delombok/LoggerSlf4jNonStaticOnRecord.java b/test/transform/resource/after-delombok/LoggerSlf4jNonStaticOnRecord.java
new file mode 100644
index 00000000..e59ed6d3
--- /dev/null
+++ b/test/transform/resource/after-delombok/LoggerSlf4jNonStaticOnRecord.java
@@ -0,0 +1,3 @@
+record LoggerSlf4jOnRecord(String a, String b) {
+ private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jOnRecord.class);
+}
diff --git a/test/transform/resource/after-delombok/LoggerSlf4jOnRecord.java b/test/transform/resource/after-delombok/LoggerSlf4jOnRecord.java
new file mode 100644
index 00000000..e59ed6d3
--- /dev/null
+++ b/test/transform/resource/after-delombok/LoggerSlf4jOnRecord.java
@@ -0,0 +1,3 @@
+record LoggerSlf4jOnRecord(String a, String b) {
+ private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jOnRecord.class);
+}
diff --git a/test/transform/resource/after-delombok/NonNullExistingConstructorOnRecord.java b/test/transform/resource/after-delombok/NonNullExistingConstructorOnRecord.java
new file mode 100644
index 00000000..de2757ee
--- /dev/null
+++ b/test/transform/resource/after-delombok/NonNullExistingConstructorOnRecord.java
@@ -0,0 +1,22 @@
+import lombok.NonNull;
+
+record NonNullOnRecord(@NonNull String a, @NonNull String b) {
+ public NonNullOnRecord(@NonNull String b) {
+ this("default", b);
+ if (b == null) {
+ throw new java.lang.NullPointerException("b is marked non-null but is null");
+ }
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public NonNullOnRecord(@NonNull final String a, @NonNull final String b) {
+ if (a == null) {
+ throw new java.lang.NullPointerException("a is marked non-null but is null");
+ }
+ if (b == null) {
+ throw new java.lang.NullPointerException("b is marked non-null but is null");
+ }
+ this.a = a;
+ this.b = b;
+ }
+}
diff --git a/test/transform/resource/after-delombok/NonNullOnRecord.java b/test/transform/resource/after-delombok/NonNullOnRecord.java
new file mode 100644
index 00000000..7147f49c
--- /dev/null
+++ b/test/transform/resource/after-delombok/NonNullOnRecord.java
@@ -0,0 +1,22 @@
+import lombok.NonNull;
+
+record NonNullOnRecord(@NonNull String a, @NonNull String b) {
+ public void method(@NonNull String param) {
+ if (param == null) {
+ throw new java.lang.NullPointerException("param is marked non-null but is null");
+ }
+ String asd = "a";
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public NonNullOnRecord(@NonNull final String a, @NonNull final String b) {
+ if (a == null) {
+ throw new java.lang.NullPointerException("a is marked non-null but is null");
+ }
+ if (b == null) {
+ throw new java.lang.NullPointerException("b is marked non-null but is null");
+ }
+ this.a = a;
+ this.b = b;
+ }
+}
diff --git a/test/transform/resource/after-delombok/SetterOnRecord.java b/test/transform/resource/after-delombok/SetterOnRecord.java
new file mode 100644
index 00000000..39a911ca
--- /dev/null
+++ b/test/transform/resource/after-delombok/SetterOnRecord.java
@@ -0,0 +1,2 @@
+record SetterOnRecord(String a, String b) {
+}
diff --git a/test/transform/resource/after-delombok/SynchronizedInRecord.java b/test/transform/resource/after-delombok/SynchronizedInRecord.java
new file mode 100644
index 00000000..67ca868a
--- /dev/null
+++ b/test/transform/resource/after-delombok/SynchronizedInRecord.java
@@ -0,0 +1,6 @@
+// version 14:
+record SynchronizedInRecord(String a, String b) {
+ public void foo() {
+ String foo = "bar";
+ }
+}
diff --git a/test/transform/resource/after-delombok/ToStringOnRecord.java b/test/transform/resource/after-delombok/ToStringOnRecord.java
new file mode 100644
index 00000000..84db33be
--- /dev/null
+++ b/test/transform/resource/after-delombok/ToStringOnRecord.java
@@ -0,0 +1,2 @@
+record ToStringOnRecord(String a, String b) {
+}
diff --git a/test/transform/resource/after-delombok/UtilityClassOnRecord.java b/test/transform/resource/after-delombok/UtilityClassOnRecord.java
new file mode 100644
index 00000000..fbe27370
--- /dev/null
+++ b/test/transform/resource/after-delombok/UtilityClassOnRecord.java
@@ -0,0 +1,2 @@
+record UtilityClassOnRecord(String a, String b) {
+}
diff --git a/test/transform/resource/after-delombok/ValueOnRecord.java b/test/transform/resource/after-delombok/ValueOnRecord.java
new file mode 100644
index 00000000..d3d0e6db
--- /dev/null
+++ b/test/transform/resource/after-delombok/ValueOnRecord.java
@@ -0,0 +1,2 @@
+record ValueOnRecord(String a, String b) {
+}
diff --git a/test/transform/resource/after-delombok/WithByOnRecord.java b/test/transform/resource/after-delombok/WithByOnRecord.java
new file mode 100644
index 00000000..d6a24a9a
--- /dev/null
+++ b/test/transform/resource/after-delombok/WithByOnRecord.java
@@ -0,0 +1,11 @@
+record WithByOnRecord(String a, String b) {
+ @java.lang.SuppressWarnings("all")
+ public WithByOnRecord withABy(final java.util.function.Function<? super String, ? extends String> transformer) {
+ return new WithByOnRecord(transformer.apply(this.a), this.b);
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public WithByOnRecord withBBy(final java.util.function.Function<? super String, ? extends String> transformer) {
+ return new WithByOnRecord(this.a, transformer.apply(this.b));
+ }
+}
diff --git a/test/transform/resource/after-delombok/WithByOnRecordComponent.java b/test/transform/resource/after-delombok/WithByOnRecordComponent.java
new file mode 100644
index 00000000..5af50625
--- /dev/null
+++ b/test/transform/resource/after-delombok/WithByOnRecordComponent.java
@@ -0,0 +1,6 @@
+record WithByOnRecordComponent(String a, String b) {
+ @java.lang.SuppressWarnings("all")
+ public WithByOnRecordComponent withABy(final java.util.function.Function<? super String, ? extends String> transformer) {
+ return new WithByOnRecordComponent(transformer.apply(this.a), this.b);
+ }
+}
diff --git a/test/transform/resource/after-delombok/WithOnRecord.java b/test/transform/resource/after-delombok/WithOnRecord.java
new file mode 100644
index 00000000..bfb123bc
--- /dev/null
+++ b/test/transform/resource/after-delombok/WithOnRecord.java
@@ -0,0 +1,11 @@
+record WithOnRecord(String a, String b) {
+ @java.lang.SuppressWarnings("all")
+ public WithOnRecord withA(final String a) {
+ return this.a == a ? this : new WithOnRecord(a, this.b);
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public WithOnRecord withB(final String b) {
+ return this.b == b ? this : new WithOnRecord(this.a, b);
+ }
+}
diff --git a/test/transform/resource/after-delombok/WithOnRecordComponent.java b/test/transform/resource/after-delombok/WithOnRecordComponent.java
new file mode 100644
index 00000000..a5f4ec36
--- /dev/null
+++ b/test/transform/resource/after-delombok/WithOnRecordComponent.java
@@ -0,0 +1,6 @@
+record WithOnRecordComponent(String a, String b) {
+ @java.lang.SuppressWarnings("all")
+ public WithOnRecordComponent withA(final String a) {
+ return this.a == a ? this : new WithOnRecordComponent(a, this.b);
+ }
+}
diff --git a/test/transform/resource/after-ecj/BuilderSimpleOnRecord.java b/test/transform/resource/after-ecj/BuilderSimpleOnRecord.java
new file mode 100644
index 00000000..e73ed92e
--- /dev/null
+++ b/test/transform/resource/after-ecj/BuilderSimpleOnRecord.java
@@ -0,0 +1,34 @@
+import java.util.List;
+@lombok.Builder(access = lombok.AccessLevel.PROTECTED) record BuilderSimpleOnRecord(List l, String a)<T> {
+ protected static @java.lang.SuppressWarnings("all") class BuilderSimpleOnRecordBuilder<T> {
+ private @java.lang.SuppressWarnings("all") List<T> l;
+ private @java.lang.SuppressWarnings("all") String a;
+ @java.lang.SuppressWarnings("all") BuilderSimpleOnRecordBuilder() {
+ super();
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSimpleOnRecord.BuilderSimpleOnRecordBuilder<T> l(final List<T> l) {
+ this.l = l;
+ return this;
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSimpleOnRecord.BuilderSimpleOnRecordBuilder<T> a(final String a) {
+ this.a = a;
+ return this;
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSimpleOnRecord<T> build() {
+ return new BuilderSimpleOnRecord<T>(this.l, this.a);
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
+ return (((("BuilderSimpleOnRecord.BuilderSimpleOnRecordBuilder(l=" + this.l) + ", a=") + this.a) + ")");
+ }
+ }
+/* Implicit */ private final List<T> l;
+/* Implicit */ private final String a;
+ public BuilderSimpleOnRecord(List<T> l, String a) {
+ super();
+ .l = l;
+ .a = a;
+ }
+ protected static @java.lang.SuppressWarnings("all") <T>BuilderSimpleOnRecord.BuilderSimpleOnRecordBuilder<T> builder() {
+ return new BuilderSimpleOnRecord.BuilderSimpleOnRecordBuilder<T>();
+ }
+}
diff --git a/test/transform/resource/after-ecj/BuilderSingularOnRecord.java b/test/transform/resource/after-ecj/BuilderSingularOnRecord.java
new file mode 100644
index 00000000..b1d9cf39
--- /dev/null
+++ b/test/transform/resource/after-ecj/BuilderSingularOnRecord.java
@@ -0,0 +1,128 @@
+import java.util.Collection;
+import java.util.List;
+import lombok.Builder;
+import lombok.Singular;
+@Builder record BuilderSingularOnRecord(List children, Collection scarves, List rawList)<T> {
+ public static @java.lang.SuppressWarnings("all") class BuilderSingularOnRecordBuilder<T> {
+ private @java.lang.SuppressWarnings("all") java.util.ArrayList<T> children;
+ private @java.lang.SuppressWarnings("all") java.util.ArrayList<Number> scarves;
+ private @java.lang.SuppressWarnings("all") java.util.ArrayList<java.lang.Object> rawList;
+ @java.lang.SuppressWarnings("all") BuilderSingularOnRecordBuilder() {
+ super();
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> child(final T child) {
+ if ((this.children == null))
+ this.children = new java.util.ArrayList<T>();
+ this.children.add(child);
+ return this;
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> children(final java.util.Collection<? extends T> children) {
+ if ((children == null))
+ {
+ throw new java.lang.NullPointerException("children cannot be null");
+ }
+ if ((this.children == null))
+ this.children = new java.util.ArrayList<T>();
+ this.children.addAll(children);
+ return this;
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> clearChildren() {
+ if ((this.children != null))
+ this.children.clear();
+ return this;
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> scarf(final Number scarf) {
+ if ((this.scarves == null))
+ this.scarves = new java.util.ArrayList<Number>();
+ this.scarves.add(scarf);
+ return this;
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> scarves(final java.util.Collection<? extends Number> scarves) {
+ if ((scarves == null))
+ {
+ throw new java.lang.NullPointerException("scarves cannot be null");
+ }
+ if ((this.scarves == null))
+ this.scarves = new java.util.ArrayList<Number>();
+ this.scarves.addAll(scarves);
+ return this;
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> clearScarves() {
+ if ((this.scarves != null))
+ this.scarves.clear();
+ return this;
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> rawList(final java.lang.Object rawList) {
+ if ((this.rawList == null))
+ this.rawList = new java.util.ArrayList<java.lang.Object>();
+ this.rawList.add(rawList);
+ return this;
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> rawList(final java.util.Collection<?> rawList) {
+ if ((rawList == null))
+ {
+ throw new java.lang.NullPointerException("rawList cannot be null");
+ }
+ if ((this.rawList == null))
+ this.rawList = new java.util.ArrayList<java.lang.Object>();
+ this.rawList.addAll(rawList);
+ return this;
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> clearRawList() {
+ if ((this.rawList != null))
+ this.rawList.clear();
+ return this;
+ }
+ public @java.lang.SuppressWarnings("all") BuilderSingularOnRecord<T> build() {
+ java.util.List<T> children;
+ switch (((this.children == null) ? 0 : this.children.size())) {
+ case 0 :
+ children = java.util.Collections.emptyList();
+ break;
+ case 1 :
+ children = java.util.Collections.singletonList(this.children.get(0));
+ break;
+ default :
+ children = java.util.Collections.unmodifiableList(new java.util.ArrayList<T>(this.children));
+ }
+ java.util.Collection<Number> scarves;
+ switch (((this.scarves == null) ? 0 : this.scarves.size())) {
+ case 0 :
+ scarves = java.util.Collections.emptyList();
+ break;
+ case 1 :
+ scarves = java.util.Collections.singletonList(this.scarves.get(0));
+ break;
+ default :
+ scarves = java.util.Collections.unmodifiableList(new java.util.ArrayList<Number>(this.scarves));
+ }
+ java.util.List<java.lang.Object> rawList;
+ switch (((this.rawList == null) ? 0 : this.rawList.size())) {
+ case 0 :
+ rawList = java.util.Collections.emptyList();
+ break;
+ case 1 :
+ rawList = java.util.Collections.singletonList(this.rawList.get(0));
+ break;
+ default :
+ rawList = java.util.Collections.unmodifiableList(new java.util.ArrayList<java.lang.Object>(this.rawList));
+ }
+ return new BuilderSingularOnRecord<T>(children, scarves, rawList);
+ }
+ public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
+ return (((((("BuilderSingularOnRecord.BuilderSingularOnRecordBuilder(children=" + this.children) + ", scarves=") + this.scarves) + ", rawList=") + this.rawList) + ")");
+ }
+ }
+/* Implicit */ private final List<T> children;
+/* Implicit */ private final Collection<? extends Number> scarves;
+/* Implicit */ private final List rawList;
+ public BuilderSingularOnRecord(@Singular List<T> children, @Singular Collection<? extends Number> scarves, @SuppressWarnings("all") @Singular("rawList") List rawList) {
+ super();
+ .children = children;
+ .scarves = scarves;
+ .rawList = rawList;
+ }
+ public static @java.lang.SuppressWarnings("all") <T>BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T> builder() {
+ return new BuilderSingularOnRecord.BuilderSingularOnRecordBuilder<T>();
+ }
+}
diff --git a/test/transform/resource/after-ecj/ConstructorsOnRecord.java b/test/transform/resource/after-ecj/ConstructorsOnRecord.java
new file mode 100644
index 00000000..bfd9618f
--- /dev/null
+++ b/test/transform/resource/after-ecj/ConstructorsOnRecord.java
@@ -0,0 +1,12 @@
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
+@AllArgsConstructor @RequiredArgsConstructor @NoArgsConstructor record ConstructorsOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public ConstructorsOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/DataOnRecord.java b/test/transform/resource/after-ecj/DataOnRecord.java
new file mode 100644
index 00000000..48783330
--- /dev/null
+++ b/test/transform/resource/after-ecj/DataOnRecord.java
@@ -0,0 +1,10 @@
+import lombok.Data;
+@Data record DataOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public DataOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/EqualsAndHashCodeOnRecord.java b/test/transform/resource/after-ecj/EqualsAndHashCodeOnRecord.java
new file mode 100644
index 00000000..60285186
--- /dev/null
+++ b/test/transform/resource/after-ecj/EqualsAndHashCodeOnRecord.java
@@ -0,0 +1,10 @@
+import lombok.EqualsAndHashCode;
+@EqualsAndHashCode record EqualsAndHashCodeOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public EqualsAndHashCodeOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/FieldDefaultsOnRecord.java b/test/transform/resource/after-ecj/FieldDefaultsOnRecord.java
new file mode 100644
index 00000000..95c49a42
--- /dev/null
+++ b/test/transform/resource/after-ecj/FieldDefaultsOnRecord.java
@@ -0,0 +1,9 @@
+@lombok.experimental.FieldDefaults(makeFinal = true) record FieldDefaultsOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public FieldDefaultsOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/FieldNameConstantsOnRecord.java b/test/transform/resource/after-ecj/FieldNameConstantsOnRecord.java
new file mode 100644
index 00000000..b25fd6b3
--- /dev/null
+++ b/test/transform/resource/after-ecj/FieldNameConstantsOnRecord.java
@@ -0,0 +1,27 @@
+import lombok.experimental.FieldNameConstants;
+import lombok.AccessLevel;
+@FieldNameConstants(level = AccessLevel.PACKAGE) record FieldNameConstantsOnRecord(String iAmADvdPlayer, int $skipMe, int andMe, String butPrintMePlease) {
+ static final @java.lang.SuppressWarnings("all") class Fields {
+ public static final java.lang.String iAmADvdPlayer = "iAmADvdPlayer";
+ public static final java.lang.String butPrintMePlease = "butPrintMePlease";
+ <clinit>() {
+ }
+ private @java.lang.SuppressWarnings("all") Fields() {
+ super();
+ }
+ }
+/* Implicit */ private final String iAmADvdPlayer;
+/* Implicit */ private final int $skipMe;
+/* Implicit */ private final int andMe;
+/* Implicit */ private final String butPrintMePlease;
+ static double skipMeToo;
+ <clinit>() {
+ }
+ public FieldNameConstantsOnRecord(String iAmADvdPlayer, int $skipMe, int andMe, String butPrintMePlease) {
+ super();
+ .iAmADvdPlayer = iAmADvdPlayer;
+ .$skipMe = $skipMe;
+ .andMe = andMe;
+ .butPrintMePlease = butPrintMePlease;
+ }
+}
diff --git a/test/transform/resource/after-ecj/GetterOnRecord.java b/test/transform/resource/after-ecj/GetterOnRecord.java
new file mode 100644
index 00000000..2cb61dba
--- /dev/null
+++ b/test/transform/resource/after-ecj/GetterOnRecord.java
@@ -0,0 +1,10 @@
+import lombok.Getter;
+@Getter record GetterOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public GetterOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/LoggerConfigOnRecord.java b/test/transform/resource/after-ecj/LoggerConfigOnRecord.java
new file mode 100644
index 00000000..ca572860
--- /dev/null
+++ b/test/transform/resource/after-ecj/LoggerConfigOnRecord.java
@@ -0,0 +1,10 @@
+import lombok.extern.slf4j.Slf4j;
+@Slf4j record LoggerConfigOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public LoggerConfigOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/LoggerSlf4jOnRecord.java b/test/transform/resource/after-ecj/LoggerSlf4jOnRecord.java
new file mode 100644
index 00000000..804c8582
--- /dev/null
+++ b/test/transform/resource/after-ecj/LoggerSlf4jOnRecord.java
@@ -0,0 +1,13 @@
+import lombok.extern.slf4j.Slf4j;
+@Slf4j record LoggerSlf4jOnRecord(org log, String a) {
+ private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jOnRecord.class);
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ <clinit>() {
+ }
+ public LoggerSlf4jOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/NonNullExistingConstructorOnRecord.java b/test/transform/resource/after-ecj/NonNullExistingConstructorOnRecord.java
new file mode 100644
index 00000000..82bc6ffd
--- /dev/null
+++ b/test/transform/resource/after-ecj/NonNullExistingConstructorOnRecord.java
@@ -0,0 +1,30 @@
+import lombok.NonNull;
+record NonNullOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public NonNullOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+ public NonNullOnRecord(@NonNull String b) {
+ this("default", b);
+ if ((b == null))
+ {
+ throw new java.lang.NullPointerException("b is marked non-null but is null");
+ }
+ }
+ public @java.lang.SuppressWarnings("all") NonNullOnRecord(final String a, final String b) {
+ super();
+ if ((a == null))
+ {
+ throw new java.lang.NullPointerException("a is marked non-null but is null");
+ }
+ if ((b == null))
+ {
+ throw new java.lang.NullPointerException("b is marked non-null but is null");
+ }
+ this.a = a;
+ this.b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/NonNullOnRecord.java b/test/transform/resource/after-ecj/NonNullOnRecord.java
new file mode 100644
index 00000000..7d71d9cc
--- /dev/null
+++ b/test/transform/resource/after-ecj/NonNullOnRecord.java
@@ -0,0 +1,30 @@
+import lombok.NonNull;
+record NonNullOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public NonNullOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+ public void method(@NonNull String param) {
+ if ((param == null))
+ {
+ throw new java.lang.NullPointerException("param is marked non-null but is null");
+ }
+ String asd = "a";
+ }
+ public @java.lang.SuppressWarnings("all") NonNullOnRecord(final String a, final String b) {
+ super();
+ if ((a == null))
+ {
+ throw new java.lang.NullPointerException("a is marked non-null but is null");
+ }
+ if ((b == null))
+ {
+ throw new java.lang.NullPointerException("b is marked non-null but is null");
+ }
+ this.a = a;
+ this.b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/SetterOnRecord.java b/test/transform/resource/after-ecj/SetterOnRecord.java
new file mode 100644
index 00000000..c9d3764f
--- /dev/null
+++ b/test/transform/resource/after-ecj/SetterOnRecord.java
@@ -0,0 +1,10 @@
+import lombok.Setter;
+@Setter record SetterOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public SetterOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/SynchronizedInRecord.java b/test/transform/resource/after-ecj/SynchronizedInRecord.java
new file mode 100644
index 00000000..f90a85e2
--- /dev/null
+++ b/test/transform/resource/after-ecj/SynchronizedInRecord.java
@@ -0,0 +1,14 @@
+import lombok.Synchronized;
+record SynchronizedInRecord(java $lock, String a) {
+ private final java.lang.Object $lock = new java.lang.Object[0];
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public SynchronizedInRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+ public @Synchronized void foo() {
+ String foo = "bar";
+ }
+}
diff --git a/test/transform/resource/after-ecj/ToStringOnRecord.java b/test/transform/resource/after-ecj/ToStringOnRecord.java
new file mode 100644
index 00000000..8decb8d1
--- /dev/null
+++ b/test/transform/resource/after-ecj/ToStringOnRecord.java
@@ -0,0 +1,10 @@
+import lombok.ToString;
+@ToString record ToStringOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public ToStringOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/UtilityClassOnRecord.java b/test/transform/resource/after-ecj/UtilityClassOnRecord.java
new file mode 100644
index 00000000..036c0f86
--- /dev/null
+++ b/test/transform/resource/after-ecj/UtilityClassOnRecord.java
@@ -0,0 +1,10 @@
+import lombok.experimental.UtilityClass;
+@UtilityClass record UtilityClassOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public UtilityClassOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/ValueOnRecord.java b/test/transform/resource/after-ecj/ValueOnRecord.java
new file mode 100644
index 00000000..5b505c76
--- /dev/null
+++ b/test/transform/resource/after-ecj/ValueOnRecord.java
@@ -0,0 +1,10 @@
+import lombok.Value;
+@Value record ValueOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public ValueOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+}
diff --git a/test/transform/resource/after-ecj/WithByOnRecord.java b/test/transform/resource/after-ecj/WithByOnRecord.java
new file mode 100644
index 00000000..c40841c8
--- /dev/null
+++ b/test/transform/resource/after-ecj/WithByOnRecord.java
@@ -0,0 +1,16 @@
+import lombok.experimental.WithBy;
+@WithBy record WithByOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public WithByOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+ public @java.lang.SuppressWarnings("all") WithByOnRecord withABy(final java.util.function.Function<? super String, ? extends String> transformer) {
+ return new WithByOnRecord(transformer.apply(this.a), this.b);
+ }
+ public @java.lang.SuppressWarnings("all") WithByOnRecord withBBy(final java.util.function.Function<? super String, ? extends String> transformer) {
+ return new WithByOnRecord(this.a, transformer.apply(this.b));
+ }
+}
diff --git a/test/transform/resource/after-ecj/WithByOnRecordComponent.java b/test/transform/resource/after-ecj/WithByOnRecordComponent.java
new file mode 100644
index 00000000..19fe508c
--- /dev/null
+++ b/test/transform/resource/after-ecj/WithByOnRecordComponent.java
@@ -0,0 +1,13 @@
+import lombok.experimental.WithBy;
+record WithByOnRecordComponent(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public WithByOnRecordComponent( String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+ public @java.lang.SuppressWarnings("all") WithByOnRecordComponent withABy(final java.util.function.Function<? super String, ? extends String> transformer) {
+ return new WithByOnRecordComponent(transformer.apply(this.a), this.b);
+ }
+}
diff --git a/test/transform/resource/after-ecj/WithOnRecord.java b/test/transform/resource/after-ecj/WithOnRecord.java
new file mode 100644
index 00000000..5ab8d6ac
--- /dev/null
+++ b/test/transform/resource/after-ecj/WithOnRecord.java
@@ -0,0 +1,16 @@
+import lombok.With;
+@With record WithOnRecord(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public WithOnRecord(String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+ public @java.lang.SuppressWarnings("all") WithOnRecord withA(final String a) {
+ return ((this.a == a) ? this : new WithOnRecord(a, this.b));
+ }
+ public @java.lang.SuppressWarnings("all") WithOnRecord withB(final String b) {
+ return ((this.b == b) ? this : new WithOnRecord(this.a, b));
+ }
+}
diff --git a/test/transform/resource/after-ecj/WithOnRecordComponent.java b/test/transform/resource/after-ecj/WithOnRecordComponent.java
new file mode 100644
index 00000000..42028f81
--- /dev/null
+++ b/test/transform/resource/after-ecj/WithOnRecordComponent.java
@@ -0,0 +1,13 @@
+import lombok.With;
+record WithOnRecordComponent(String a, String b) {
+/* Implicit */ private final String a;
+/* Implicit */ private final String b;
+ public WithOnRecordComponent( String a, String b) {
+ super();
+ .a = a;
+ .b = b;
+ }
+ public @java.lang.SuppressWarnings("all") WithOnRecordComponent withA(final String a) {
+ return ((this.a == a) ? this : new WithOnRecordComponent(a, this.b));
+ }
+}
diff --git a/test/transform/resource/before/BuilderSimpleOnRecord.java b/test/transform/resource/before/BuilderSimpleOnRecord.java
new file mode 100644
index 00000000..7968db64
--- /dev/null
+++ b/test/transform/resource/before/BuilderSimpleOnRecord.java
@@ -0,0 +1,7 @@
+// version 14:
+
+import java.util.List;
+
+@lombok.Builder(access = lombok.AccessLevel.PROTECTED)
+record BuilderSimpleOnRecord<T>(List<T> l, String a) {
+}
diff --git a/test/transform/resource/before/BuilderSingularOnRecord.java b/test/transform/resource/before/BuilderSingularOnRecord.java
new file mode 100644
index 00000000..0ffd80be
--- /dev/null
+++ b/test/transform/resource/before/BuilderSingularOnRecord.java
@@ -0,0 +1,11 @@
+// version 14:
+
+import java.util.Collection;
+import java.util.List;
+
+import lombok.Builder;
+import lombok.Singular;
+
+@Builder
+record BuilderSingularOnRecord<T>(@Singular List<T> children, @Singular Collection<? extends Number> scarves, @SuppressWarnings("all") @Singular("rawList") List rawList) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/ConstructorsOnRecord.java b/test/transform/resource/before/ConstructorsOnRecord.java
new file mode 100644
index 00000000..d45495c8
--- /dev/null
+++ b/test/transform/resource/before/ConstructorsOnRecord.java
@@ -0,0 +1,11 @@
+// version 14:
+
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
+
+@AllArgsConstructor
+@RequiredArgsConstructor
+@NoArgsConstructor
+record ConstructorsOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/DataOnRecord.java b/test/transform/resource/before/DataOnRecord.java
new file mode 100644
index 00000000..ed32c337
--- /dev/null
+++ b/test/transform/resource/before/DataOnRecord.java
@@ -0,0 +1,7 @@
+// version 14:
+
+import lombok.Data;
+
+@Data
+record DataOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/EqualsAndHashCodeOnRecord.java b/test/transform/resource/before/EqualsAndHashCodeOnRecord.java
new file mode 100644
index 00000000..5c295b3d
--- /dev/null
+++ b/test/transform/resource/before/EqualsAndHashCodeOnRecord.java
@@ -0,0 +1,7 @@
+// version 14:
+
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode
+record EqualsAndHashCodeOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/FieldDefaultsOnRecord.java b/test/transform/resource/before/FieldDefaultsOnRecord.java
new file mode 100644
index 00000000..cf74508d
--- /dev/null
+++ b/test/transform/resource/before/FieldDefaultsOnRecord.java
@@ -0,0 +1,5 @@
+// version 14:
+
+@lombok.experimental.FieldDefaults(makeFinal = true)
+record FieldDefaultsOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/FieldNameConstantsOnRecord.java b/test/transform/resource/before/FieldNameConstantsOnRecord.java
new file mode 100644
index 00000000..0905e082
--- /dev/null
+++ b/test/transform/resource/before/FieldNameConstantsOnRecord.java
@@ -0,0 +1,9 @@
+// version 14:
+
+import lombok.experimental.FieldNameConstants;
+import lombok.AccessLevel;
+
+@FieldNameConstants(level = AccessLevel.PACKAGE)
+record FieldNameConstantsOnRecord(String iAmADvdPlayer, int $skipMe, @FieldNameConstants.Exclude int andMe, String butPrintMePlease) {
+ static double skipMeToo;
+} \ No newline at end of file
diff --git a/test/transform/resource/before/GetterOnRecord.java b/test/transform/resource/before/GetterOnRecord.java
new file mode 100644
index 00000000..5a56a6d4
--- /dev/null
+++ b/test/transform/resource/before/GetterOnRecord.java
@@ -0,0 +1,7 @@
+// version 14:
+
+import lombok.Getter;
+
+@Getter
+record GetterOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/LoggerConfigOnRecord.java b/test/transform/resource/before/LoggerConfigOnRecord.java
new file mode 100644
index 00000000..c5f5a05a
--- /dev/null
+++ b/test/transform/resource/before/LoggerConfigOnRecord.java
@@ -0,0 +1,8 @@
+// CONF: lombok.log.fieldIsStatic = false
+// version 14:
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+record LoggerConfigOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/LoggerSlf4jOnRecord.java b/test/transform/resource/before/LoggerSlf4jOnRecord.java
new file mode 100644
index 00000000..f3402742
--- /dev/null
+++ b/test/transform/resource/before/LoggerSlf4jOnRecord.java
@@ -0,0 +1,7 @@
+// version 14:
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+record LoggerSlf4jOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/NonNullExistingConstructorOnRecord.java b/test/transform/resource/before/NonNullExistingConstructorOnRecord.java
new file mode 100644
index 00000000..1faf7d69
--- /dev/null
+++ b/test/transform/resource/before/NonNullExistingConstructorOnRecord.java
@@ -0,0 +1,9 @@
+// version 14:
+
+import lombok.NonNull;
+
+record NonNullOnRecord(@NonNull String a, @NonNull String b) {
+ public NonNullOnRecord(@NonNull String b) {
+ this("default", b);
+ }
+} \ No newline at end of file
diff --git a/test/transform/resource/before/NonNullOnRecord.java b/test/transform/resource/before/NonNullOnRecord.java
new file mode 100644
index 00000000..223f8cbb
--- /dev/null
+++ b/test/transform/resource/before/NonNullOnRecord.java
@@ -0,0 +1,9 @@
+// version 14:
+
+import lombok.NonNull;
+
+record NonNullOnRecord(@NonNull String a, @NonNull String b) {
+ public void method(@NonNull String param) {
+ String asd = "a";
+ }
+} \ No newline at end of file
diff --git a/test/transform/resource/before/SetterOnRecord.java b/test/transform/resource/before/SetterOnRecord.java
new file mode 100644
index 00000000..c91e06cd
--- /dev/null
+++ b/test/transform/resource/before/SetterOnRecord.java
@@ -0,0 +1,7 @@
+// version 14:
+
+import lombok.Setter;
+
+@Setter
+record SetterOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/SuperBuilderOnRecord.java b/test/transform/resource/before/SuperBuilderOnRecord.java
new file mode 100644
index 00000000..8925176e
--- /dev/null
+++ b/test/transform/resource/before/SuperBuilderOnRecord.java
@@ -0,0 +1,8 @@
+// skip compare content
+// version 14:
+
+import lombok.experimental.SuperBuilder;
+
+@SuperBuilder
+record SupeBuilderOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/SynchronizedInRecord.java b/test/transform/resource/before/SynchronizedInRecord.java
new file mode 100644
index 00000000..99f87543
--- /dev/null
+++ b/test/transform/resource/before/SynchronizedInRecord.java
@@ -0,0 +1,10 @@
+// version 14:
+
+import lombok.Synchronized;
+
+record SynchronizedInRecord(String a, String b) {
+ @Synchronized
+ public void foo() {
+ String foo = "bar";
+ }
+} \ No newline at end of file
diff --git a/test/transform/resource/before/ToStringOnRecord.java b/test/transform/resource/before/ToStringOnRecord.java
new file mode 100644
index 00000000..279c6f6c
--- /dev/null
+++ b/test/transform/resource/before/ToStringOnRecord.java
@@ -0,0 +1,7 @@
+// version 14:
+
+import lombok.ToString;
+
+@ToString
+record ToStringOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/UtilityClassOnRecord.java b/test/transform/resource/before/UtilityClassOnRecord.java
new file mode 100644
index 00000000..1e3ebb38
--- /dev/null
+++ b/test/transform/resource/before/UtilityClassOnRecord.java
@@ -0,0 +1,7 @@
+// version 14:
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+record UtilityClassOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/ValueOnRecord.java b/test/transform/resource/before/ValueOnRecord.java
new file mode 100644
index 00000000..e1e49595
--- /dev/null
+++ b/test/transform/resource/before/ValueOnRecord.java
@@ -0,0 +1,7 @@
+// version 14:
+
+import lombok.Value;
+
+@Value
+record ValueOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/WithByOnRecord.java b/test/transform/resource/before/WithByOnRecord.java
new file mode 100644
index 00000000..6c7b8e2d
--- /dev/null
+++ b/test/transform/resource/before/WithByOnRecord.java
@@ -0,0 +1,7 @@
+// version 14:
+
+import lombok.experimental.WithBy;
+
+@WithBy
+record WithByOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/WithByOnRecordComponent.java b/test/transform/resource/before/WithByOnRecordComponent.java
new file mode 100644
index 00000000..7e0f0f19
--- /dev/null
+++ b/test/transform/resource/before/WithByOnRecordComponent.java
@@ -0,0 +1,6 @@
+// version 14:
+
+import lombok.experimental.WithBy;
+
+record WithByOnRecordComponent(@WithBy String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/WithOnRecord.java b/test/transform/resource/before/WithOnRecord.java
new file mode 100644
index 00000000..211da3c8
--- /dev/null
+++ b/test/transform/resource/before/WithOnRecord.java
@@ -0,0 +1,7 @@
+// version 14:
+
+import lombok.With;
+
+@With
+record WithOnRecord(String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/before/WithOnRecordComponent.java b/test/transform/resource/before/WithOnRecordComponent.java
new file mode 100644
index 00000000..6f827851
--- /dev/null
+++ b/test/transform/resource/before/WithOnRecordComponent.java
@@ -0,0 +1,6 @@
+// version 14:
+
+import lombok.With;
+
+record WithOnRecordComponent(@With String a, String b) {
+} \ No newline at end of file
diff --git a/test/transform/resource/messages-delombok/ConstructorsOnRecord.java.messages b/test/transform/resource/messages-delombok/ConstructorsOnRecord.java.messages
new file mode 100644
index 00000000..d1732a8c
--- /dev/null
+++ b/test/transform/resource/messages-delombok/ConstructorsOnRecord.java.messages
@@ -0,0 +1,3 @@
+7 AllArgsConstructor is only supported on a class or an enum.
+8 RequiredArgsConstructor is only supported on a class or an enum.
+9 NoArgsConstructor is only supported on a class or an enum.
diff --git a/test/transform/resource/messages-delombok/DataOnRecord.java.messages b/test/transform/resource/messages-delombok/DataOnRecord.java.messages
new file mode 100644
index 00000000..42a9625b
--- /dev/null
+++ b/test/transform/resource/messages-delombok/DataOnRecord.java.messages
@@ -0,0 +1 @@
+5 @Data is only supported on a class.
diff --git a/test/transform/resource/messages-delombok/EqualsAndHashCodeOnRecord.java.messages b/test/transform/resource/messages-delombok/EqualsAndHashCodeOnRecord.java.messages
new file mode 100644
index 00000000..daa53bcd
--- /dev/null
+++ b/test/transform/resource/messages-delombok/EqualsAndHashCodeOnRecord.java.messages
@@ -0,0 +1 @@
+5 @EqualsAndHashCode is only supported on a class.
diff --git a/test/transform/resource/messages-delombok/FieldDefaultsOnRecord.java.messages b/test/transform/resource/messages-delombok/FieldDefaultsOnRecord.java.messages
new file mode 100644
index 00000000..1afb1bdf
--- /dev/null
+++ b/test/transform/resource/messages-delombok/FieldDefaultsOnRecord.java.messages
@@ -0,0 +1 @@
+3 @FieldDefaults is only supported on a class or an enum.
diff --git a/test/transform/resource/messages-delombok/GetterOnRecord.java.messages b/test/transform/resource/messages-delombok/GetterOnRecord.java.messages
new file mode 100644
index 00000000..0830c585
--- /dev/null
+++ b/test/transform/resource/messages-delombok/GetterOnRecord.java.messages
@@ -0,0 +1 @@
+5 @Getter is only supported on a class, an enum, or a field.
diff --git a/test/transform/resource/messages-delombok/LoggerConfigOnRecord.java.messages b/test/transform/resource/messages-delombok/LoggerConfigOnRecord.java.messages
new file mode 100644
index 00000000..7dd3294e
--- /dev/null
+++ b/test/transform/resource/messages-delombok/LoggerConfigOnRecord.java.messages
@@ -0,0 +1 @@
+6 Logger fields must be static in records.
diff --git a/test/transform/resource/messages-delombok/SetterOnRecord.java.messages b/test/transform/resource/messages-delombok/SetterOnRecord.java.messages
new file mode 100644
index 00000000..1913765c
--- /dev/null
+++ b/test/transform/resource/messages-delombok/SetterOnRecord.java.messages
@@ -0,0 +1 @@
+5 @Setter is only supported on a class or a field.
diff --git a/test/transform/resource/messages-delombok/SuperBuilderOnRecord.java.messages b/test/transform/resource/messages-delombok/SuperBuilderOnRecord.java.messages
new file mode 100644
index 00000000..25b474ab
--- /dev/null
+++ b/test/transform/resource/messages-delombok/SuperBuilderOnRecord.java.messages
@@ -0,0 +1 @@
+6 @SuperBuilder is only supported on types.
diff --git a/test/transform/resource/messages-delombok/SynchronizedInRecord.java.messages b/test/transform/resource/messages-delombok/SynchronizedInRecord.java.messages
new file mode 100644
index 00000000..d40e68b3
--- /dev/null
+++ b/test/transform/resource/messages-delombok/SynchronizedInRecord.java.messages
@@ -0,0 +1 @@
+5 @Synchronized is legal only on methods in classes and enums.
diff --git a/test/transform/resource/messages-delombok/ToStringOnRecord.java.messages b/test/transform/resource/messages-delombok/ToStringOnRecord.java.messages
new file mode 100644
index 00000000..0299664b
--- /dev/null
+++ b/test/transform/resource/messages-delombok/ToStringOnRecord.java.messages
@@ -0,0 +1 @@
+5 @ToString is only supported on a class or enum.
diff --git a/test/transform/resource/messages-delombok/UtilityClassErrors.java.messages b/test/transform/resource/messages-delombok/UtilityClassErrors.java.messages
index 4afa12ec..21e23ed5 100644
--- a/test/transform/resource/messages-delombok/UtilityClassErrors.java.messages
+++ b/test/transform/resource/messages-delombok/UtilityClassErrors.java.messages
@@ -1,4 +1,4 @@
4 @UtilityClasses cannot have declared constructors.
7 @UtilityClass cannot be placed on a method local or anonymous inner class, or any class nested in such a class.
-12 @UtilityClass is only supported on a class (can't be an interface, enum, or annotation).
+12 @UtilityClass is only supported on a class.
17 @UtilityClass automatically makes the class static, however, this class cannot be made static. \ No newline at end of file
diff --git a/test/transform/resource/messages-delombok/UtilityClassOnRecord.java.messages b/test/transform/resource/messages-delombok/UtilityClassOnRecord.java.messages
new file mode 100644
index 00000000..9de73ebd
--- /dev/null
+++ b/test/transform/resource/messages-delombok/UtilityClassOnRecord.java.messages
@@ -0,0 +1 @@
+5 @UtilityClass is only supported on a class (can't be an interface, enum, annotation, or record).
diff --git a/test/transform/resource/messages-delombok/ValueOnRecord.java.messages b/test/transform/resource/messages-delombok/ValueOnRecord.java.messages
new file mode 100644
index 00000000..ebb71090
--- /dev/null
+++ b/test/transform/resource/messages-delombok/ValueOnRecord.java.messages
@@ -0,0 +1 @@
+5 @Value is only supported on a class.
diff --git a/test/transform/resource/messages-ecj/ConstructorsOnRecord.java.messages b/test/transform/resource/messages-ecj/ConstructorsOnRecord.java.messages
new file mode 100644
index 00000000..d1732a8c
--- /dev/null
+++ b/test/transform/resource/messages-ecj/ConstructorsOnRecord.java.messages
@@ -0,0 +1,3 @@
+7 AllArgsConstructor is only supported on a class or an enum.
+8 RequiredArgsConstructor is only supported on a class or an enum.
+9 NoArgsConstructor is only supported on a class or an enum.
diff --git a/test/transform/resource/messages-ecj/DataOnRecord.java.messages b/test/transform/resource/messages-ecj/DataOnRecord.java.messages
new file mode 100644
index 00000000..42a9625b
--- /dev/null
+++ b/test/transform/resource/messages-ecj/DataOnRecord.java.messages
@@ -0,0 +1 @@
+5 @Data is only supported on a class.
diff --git a/test/transform/resource/messages-ecj/EqualsAndHashCodeOnRecord.java.messages b/test/transform/resource/messages-ecj/EqualsAndHashCodeOnRecord.java.messages
new file mode 100644
index 00000000..daa53bcd
--- /dev/null
+++ b/test/transform/resource/messages-ecj/EqualsAndHashCodeOnRecord.java.messages
@@ -0,0 +1 @@
+5 @EqualsAndHashCode is only supported on a class.
diff --git a/test/transform/resource/messages-ecj/FieldDefaultsOnRecord.java.messages b/test/transform/resource/messages-ecj/FieldDefaultsOnRecord.java.messages
new file mode 100644
index 00000000..1afb1bdf
--- /dev/null
+++ b/test/transform/resource/messages-ecj/FieldDefaultsOnRecord.java.messages
@@ -0,0 +1 @@
+3 @FieldDefaults is only supported on a class or an enum.
diff --git a/test/transform/resource/messages-ecj/GetterOnRecord.java.messages b/test/transform/resource/messages-ecj/GetterOnRecord.java.messages
new file mode 100644
index 00000000..0830c585
--- /dev/null
+++ b/test/transform/resource/messages-ecj/GetterOnRecord.java.messages
@@ -0,0 +1 @@
+5 @Getter is only supported on a class, an enum, or a field.
diff --git a/test/transform/resource/messages-ecj/LoggerConfigOnRecord.java.messages b/test/transform/resource/messages-ecj/LoggerConfigOnRecord.java.messages
new file mode 100644
index 00000000..7dd3294e
--- /dev/null
+++ b/test/transform/resource/messages-ecj/LoggerConfigOnRecord.java.messages
@@ -0,0 +1 @@
+6 Logger fields must be static in records.
diff --git a/test/transform/resource/messages-ecj/SetterOnRecord.java.messages b/test/transform/resource/messages-ecj/SetterOnRecord.java.messages
new file mode 100644
index 00000000..1913765c
--- /dev/null
+++ b/test/transform/resource/messages-ecj/SetterOnRecord.java.messages
@@ -0,0 +1 @@
+5 @Setter is only supported on a class or a field.
diff --git a/test/transform/resource/messages-ecj/SuperBuilderOnRecord.java.messages b/test/transform/resource/messages-ecj/SuperBuilderOnRecord.java.messages
new file mode 100644
index 00000000..25b474ab
--- /dev/null
+++ b/test/transform/resource/messages-ecj/SuperBuilderOnRecord.java.messages
@@ -0,0 +1 @@
+6 @SuperBuilder is only supported on types.
diff --git a/test/transform/resource/messages-ecj/SynchronizedInRecord.java.messages b/test/transform/resource/messages-ecj/SynchronizedInRecord.java.messages
new file mode 100644
index 00000000..af4b11f8
--- /dev/null
+++ b/test/transform/resource/messages-ecj/SynchronizedInRecord.java.messages
@@ -0,0 +1 @@
+6 @Synchronized is legal only on methods in classes and enums.
diff --git a/test/transform/resource/messages-ecj/ToStringOnRecord.java.messages b/test/transform/resource/messages-ecj/ToStringOnRecord.java.messages
new file mode 100644
index 00000000..0299664b
--- /dev/null
+++ b/test/transform/resource/messages-ecj/ToStringOnRecord.java.messages
@@ -0,0 +1 @@
+5 @ToString is only supported on a class or enum.
diff --git a/test/transform/resource/messages-ecj/UtilityClassErrors.java.messages b/test/transform/resource/messages-ecj/UtilityClassErrors.java.messages
index 15c9b10f..21e23ed5 100644
--- a/test/transform/resource/messages-ecj/UtilityClassErrors.java.messages
+++ b/test/transform/resource/messages-ecj/UtilityClassErrors.java.messages
@@ -1,4 +1,4 @@
4 @UtilityClasses cannot have declared constructors.
7 @UtilityClass cannot be placed on a method local or anonymous inner class, or any class nested in such a class.
-12 @UtilityClass is only supported on a class (can't be an interface, enum, or annotation)
+12 @UtilityClass is only supported on a class.
17 @UtilityClass automatically makes the class static, however, this class cannot be made static. \ No newline at end of file
diff --git a/test/transform/resource/messages-ecj/UtilityClassOnRecord.java.messages b/test/transform/resource/messages-ecj/UtilityClassOnRecord.java.messages
new file mode 100644
index 00000000..9de73ebd
--- /dev/null
+++ b/test/transform/resource/messages-ecj/UtilityClassOnRecord.java.messages
@@ -0,0 +1 @@
+5 @UtilityClass is only supported on a class (can't be an interface, enum, annotation, or record).
diff --git a/test/transform/resource/messages-ecj/ValueOnRecord.java.messages b/test/transform/resource/messages-ecj/ValueOnRecord.java.messages
new file mode 100644
index 00000000..ebb71090
--- /dev/null
+++ b/test/transform/resource/messages-ecj/ValueOnRecord.java.messages
@@ -0,0 +1 @@
+5 @Value is only supported on a class.