diff options
author | Rawi01 <Rawi01@users.noreply.github.com> | 2020-09-10 10:20:12 +0200 |
---|---|---|
committer | Rawi01 <Rawi01@users.noreply.github.com> | 2020-09-10 10:32:14 +0200 |
commit | 0064c534273d9fb877f7e570f7a430060c88a5fb (patch) | |
tree | ee7089c1fbe948127aaea4c3317dd7dc18b0ee39 /src/core | |
parent | 9148294f78a8e646ee131ca182a9b692bc028fdb (diff) | |
download | lombok-0064c534273d9fb877f7e570f7a430060c88a5fb.tar.gz lombok-0064c534273d9fb877f7e570f7a430060c88a5fb.tar.bz2 lombok-0064c534273d9fb877f7e570f7a430060c88a5fb.zip |
Add record support
Diffstat (limited to 'src/core')
30 files changed, 220 insertions, 137 deletions
diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java index d53856af..2c860e14 100644 --- a/src/core/lombok/eclipse/EclipseAST.java +++ b/src/core/lombok/eclipse/EclipseAST.java @@ -21,6 +21,8 @@ */ package lombok.eclipse; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -34,7 +36,6 @@ import java.util.List; import lombok.Lombok; import lombok.core.AST; import lombok.core.LombokImmutableList; -import lombok.eclipse.handlers.EclipseHandlerUtil; import lombok.permit.Permit; import org.eclipse.core.resources.ResourcesPlugin; @@ -117,7 +118,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. @@ -362,7 +363,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: @@ -401,16 +402,16 @@ 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; } @@ -420,13 +421,13 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { return list; } - private EclipseNode buildField(FieldDeclaration 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/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 6bfcf16e..c70e4e5c 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -124,6 +124,7 @@ import lombok.core.handlers.HandlerUtil.FieldAccess; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAST; import lombok.eclipse.EclipseNode; +import lombok.eclipse.Java14Bits; import lombok.experimental.Accessors; import lombok.experimental.Tolerate; import lombok.permit.Permit; @@ -332,6 +333,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"); @@ -340,6 +342,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) { @@ -771,12 +774,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) { + Annotation annotation = (Annotation) child.get(); + for (String bn : NONNULL_ANNOTATIONS) if (typeMatches(bn, node, annotation.type)) return true; } } return false; @@ -1888,6 +1889,31 @@ public class EclipseHandlerUtil { } /** + * Checks if there is a constructor 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) { + if ((def.bits & (ASTNode.IsDefaultConstructor | Java14Bits.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 @{@link SuppressWarnings}("all") annotation. */ @@ -2635,4 +2661,57 @@ public class EclipseHandlerUtil { setGeneratedBy(ref, source); return ref; } + + static boolean isClass(EclipseNode typeNode) { + return isClassAndDoesNotHaveFlags(typeNode, ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation | Java14Bits.AccRecord); + } + + static boolean isClassOrEnum(EclipseNode typeNode) { + return isClassAndDoesNotHaveFlags(typeNode, ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | Java14Bits.AccRecord); + } + + public static boolean isClassAndDoesNotHaveFlags(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 boolean isRecord(EclipseNode typeNode) { + return typeNode.getKind() == Kind.TYPE && isRecord((TypeDeclaration) typeNode.get()); + } + + public static boolean isRecord(TypeDeclaration typeDeclaration) { + return (typeDeclaration.modifiers & Java14Bits.AccRecord) != 0; + } + + public static boolean isRecordField(EclipseNode fieldNode) { + return fieldNode.getKind() == Kind.FIELD && (((FieldDeclaration) fieldNode.get()).modifiers & Java14Bits.AccRecord) != 0; + } + + public static AbstractVariableDeclaration[] getRecordComponents(TypeDeclaration typeDeclaration) { + if (!isRecord(typeDeclaration)) return null; + try { + return (AbstractVariableDeclaration[]) TYPE_DECLARATION_RECORD_COMPONENTS.get(typeDeclaration); + } catch (Exception e) { + // Ignore + } + 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 & Java14Bits.AccRecord) != 0) { + annotations[i] = recordComponents[j++].annotations; + } + } + } + return annotations; + } } diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 801fe7e7..5054703a 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -272,8 +272,10 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { allFields.add(fieldNode); } - handleConstructor.generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER, - Collections.<Annotation>emptyList(), annotationNode); + if (!isRecord(tdParent)) { + handleConstructor.generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER, + Collections.<Annotation>emptyList(), annotationNode); + } returnType = namePlusTypeParamsToTypeReference(tdParent, td.typeParameters, p); typeParams = td.typeParameters; diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index 06c9ecd9..ff81b763 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 4011890d..6663d7d0 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.isClass; import java.util.Collections; @@ -34,8 +35,6 @@ import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists; import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.mangosdk.spi.ProviderFor; /** @@ -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 7147343e..83e6de61 100755 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -137,13 +137,9 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH Boolean callSuper, boolean whineIfExists, 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; } diff --git a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java index 702713fe..4927a8fb 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 9cd1e2a1..755311b1 100644 --- a/src/core/lombok/eclipse/handlers/HandleGetter.java +++ b/src/core/lombok/eclipse/handlers/HandleGetter.java @@ -90,13 +90,7 @@ 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) { + if (!isClassOrEnum(typeNode)) { pos.addError("@Getter is only supported on a class, an enum, or a field."); return false; } diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java index a0e431e5..9eae601b 100644 --- a/src/core/lombok/eclipse/handlers/HandleLog.java +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -85,6 +85,10 @@ 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"); diff --git a/src/core/lombok/eclipse/handlers/HandleNonNull.java b/src/core/lombok/eclipse/handlers/HandleNonNull.java index 903d098b..8dc4f4f7 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; @@ -48,17 +49,18 @@ import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.mangosdk.spi.ProviderFor; +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.EclipseAST; import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseAugments; import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists; -@DeferUntilPostDiet @ProviderFor(EclipseAnnotationHandler.class) @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); + } + EclipseAugments.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 cb2ca3bf..9ebbde6d 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -71,13 +71,7 @@ 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) { + if (!isClass(typeNode)) { pos.addError("@Setter is only supported on a class or a field."); return false; } diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index b1e7c419..89c27fe3 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -156,7 +156,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { boolean addCleaning = false; - if (!(tdParent.get() instanceof TypeDeclaration)) { + if (!isClass(tdParent)) { annotationNode.addError("@SuperBuilder is only supported on types."); return; } diff --git a/src/core/lombok/eclipse/handlers/HandleSynchronized.java b/src/core/lombok/eclipse/handlers/HandleSynchronized.java index 08d00d91..37d6755c 100644 --- a/src/core/lombok/eclipse/handlers/HandleSynchronized.java +++ b/src/core/lombok/eclipse/handlers/HandleSynchronized.java @@ -148,6 +148,12 @@ 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 +169,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 a6bcb24f..9b58474c 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 org.mangosdk.spi.ProviderFor; @@ -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 2349f839..338aab0d 100644 --- a/src/core/lombok/eclipse/handlers/HandleUtilityClass.java +++ b/src/core/lombok/eclipse/handlers/HandleUtilityClass.java @@ -70,13 +70,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 (can't be an interface, enum, annotation, or record)."); return false; } diff --git a/src/core/lombok/eclipse/handlers/HandleValue.java b/src/core/lombok/eclipse/handlers/HandleValue.java index 2e0338a8..abea5603 100644 --- a/src/core/lombok/eclipse/handlers/HandleValue.java +++ b/src/core/lombok/eclipse/handlers/HandleValue.java @@ -61,11 +61,8 @@ public class HandleValue extends EclipseAnnotationHandler<Value> { 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; } diff --git a/src/core/lombok/eclipse/handlers/HandleWithBy.java b/src/core/lombok/eclipse/handlers/HandleWithBy.java index 5f229aaf..40e2d524 100644 --- a/src/core/lombok/eclipse/handlers/HandleWithBy.java +++ b/src/core/lombok/eclipse/handlers/HandleWithBy.java @@ -29,7 +29,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; @@ -136,7 +138,10 @@ public class HandleWithBy extends EclipseAnnotationHandler<WithBy> { switch (node.getKind()) { case FIELD: - createWithByForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, true, onMethod); + Set<EclipseNode> fields = new LinkedHashSet<EclipseNode>(); + fields.add(node); + fields.addAll(annotationNode.upFromAnnotationToFields()); + createWithByForFields(level, fields, annotationNode, true, onMethod); break; case TYPE: if (!onMethod.isEmpty()) { diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 7e87ce11..f9675813 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -223,7 +223,9 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { allFields.append(fieldNode); } - handleConstructor.generateConstructor(tdParent, AccessLevel.PACKAGE, List.<JCAnnotation>nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, annotationNode); + if (!isRecord(tdParent)) { + handleConstructor.generateConstructor(tdParent, AccessLevel.PACKAGE, List.<JCAnnotation>nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, annotationNode); + } returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), tdParent, td.typarams); typeParams = td.typarams; diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index 2a683767..54a9f821 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -184,12 +184,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/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index d490738e..e35deb5b 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -113,13 +113,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, 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 aa381c0d..c974bdb9 100644 --- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java @@ -57,12 +57,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 110941d6..1b4d404b 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -52,7 +52,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; @@ -81,12 +80,7 @@ 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) { + if (!isClassOrEnum(typeNode)) { errorNode.addError("@Getter is only supported on a class, an enum, or a field."); return; } diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java index 3173b3ba..1ff10ad1 100644 --- a/src/core/lombok/javac/handlers/HandleLog.java +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -75,6 +75,10 @@ public class HandleLog { annotationNode.addWarning("Field '" + logFieldName + "' already exists."); 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"); @@ -120,10 +124,15 @@ public class HandleLog { maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (useStatic ? Flags.STATIC : 0)), typeNode.toName(logFieldName), loggerType, factoryMethodCall), source, typeNode.getContext()); - injectFieldAndMarkGenerated(typeNode, fieldDecl); + // This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8243057 + if (isRecord(typeNode)) { + injectField(typeNode, fieldDecl); + } else { + injectFieldAndMarkGenerated(typeNode, fieldDecl); + } return true; } - + private static JCExpression[] createFactoryParameters(JavacNode typeNode, JCFieldAccess loggingType, java.util.List<LogFactoryParameter> parameters, JCExpression loggerTopic) { JCExpression[] expressions = new JCExpression[parameters.size()]; JavacTreeMaker maker = typeNode.getTreeMaker(); diff --git a/src/core/lombok/javac/handlers/HandleNonNull.java b/src/core/lombok/javac/handlers/HandleNonNull.java index 079d5b04..6b6b7efa 100644 --- a/src/core/lombok/javac/handlers/HandleNonNull.java +++ b/src/core/lombok/javac/handlers/HandleNonNull.java @@ -51,17 +51,23 @@ 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; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; + +import lombok.javac.Java14Flags; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.handlers.HandleConstructor.SkipIfConstructorExists; @ProviderFor(JavacAnnotationHandler.class) @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"); @@ -119,6 +125,15 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> { return; } + JavacNode typeNode = upToTypeNode(annotationNode); + + if ((declaration.mods.flags & Java14Flags.RECORD) != 0) { + if (!lombokConstructorExists(typeNode)) { + handleConstructor.generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, null, SkipIfConstructorExists.NO, annotationNode); + } + return; + } + List<JCStatement> statements = declaration.body.stats; String expectedName = paramNode.getName(); diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index 82c95719..b51574b7 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -70,12 +70,7 @@ 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) { + if (!isClass(typeNode)) { errorNode.addError("@Setter is only supported on a class or a field."); return; } diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index f6bf9e1f..be6ddae2 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -128,7 +128,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { boolean addCleaning = false; - if (!(tdParent.get() instanceof JCClassDecl)) { + if (!isClass(tdParent)) { annotationNode.addError("@SuperBuilder is only supported on types."); return; } diff --git a/src/core/lombok/javac/handlers/HandleSynchronized.java b/src/core/lombok/javac/handlers/HandleSynchronized.java index b6f1e47f..85dc7e80 100644 --- a/src/core/lombok/javac/handlers/HandleSynchronized.java +++ b/src/core/lombok/javac/handlers/HandleSynchronized.java @@ -78,6 +78,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; @@ -89,8 +95,6 @@ public class HandleSynchronized extends JavacAnnotationHandler<Synchronized> { JavacTreeMaker maker = methodNode.getTreeMaker().at(ast.pos); Context context = methodNode.getContext(); - 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 0a950f7c..ff0016e4 100644 --- a/src/core/lombok/javac/handlers/HandleToString.java +++ b/src/core/lombok/javac/handlers/HandleToString.java @@ -107,13 +107,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 5d651689..9ff33684 100644 --- a/src/core/lombok/javac/handlers/HandleUtilityClass.java +++ b/src/core/lombok/javac/handlers/HandleUtilityClass.java @@ -68,13 +68,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 (can't be an interface, enum, annotation, or record)."); return false; } diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index efc4bf61..cd4bc70a 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -103,6 +103,7 @@ import lombok.core.handlers.HandlerUtil.FieldAccess; import lombok.delombok.LombokOptionsFactory; import lombok.experimental.Accessors; import lombok.experimental.Tolerate; +import lombok.javac.Java14Flags; import lombok.javac.Javac; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; @@ -814,6 +815,32 @@ public class JavacHandlerUtil { return MemberExistsResult.NOT_EXISTS; } + /** + * Checks if there is a constructor generated by lombok. + * + * @param node Any node that represents the Type (JCClassDecl) 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; @@ -1900,14 +1927,14 @@ public class JavacHandlerUtil { } static boolean isClass(JavacNode typeNode) { - return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ENUM | Flags.ANNOTATION); + return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ENUM | Flags.ANNOTATION | Java14Flags.RECORD); } static boolean isClassOrEnum(JavacNode typeNode) { - return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ANNOTATION); + return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ANNOTATION | Java14Flags.RECORD); } - 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(); else return false; @@ -2260,4 +2287,8 @@ public class JavacHandlerUtil { arg.mods.annotations = arg.mods.annotations == null ? List.of(m) : arg.mods.annotations.prepend(m); } } + + public static boolean isRecord(JavacNode typeNode) { + return typeNode.getKind() == Kind.TYPE && (((JCClassDecl) typeNode.get()).mods.flags & Java14Flags.RECORD) != 0; + } } |