diff options
Diffstat (limited to 'src/core')
102 files changed, 1665 insertions, 749 deletions
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index ba66649b..b8cd442a 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -695,4 +695,10 @@ public class ConfigurationKeys { */ public static final ConfigurationKey<CheckerFrameworkVersion> CHECKER_FRAMEWORK = new ConfigurationKey<CheckerFrameworkVersion>("checkerframework", "If set with the version of checkerframework.org (in major.minor, or just 'true' for the latest supported version), create relevant checkerframework.org annotations for code lombok generates (default: false).") {}; + /** + * lombok configuration: {@code lombok.standardException.flagUsage} = {@code WARNING} | {@code ERROR}. + * + * If set, <em>any</em> usage of {@code @StandardException} results in a warning / error. + */ + public static final ConfigurationKey<FlagUsageType> STANDARD_EXCEPTION_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.standardException.flagUsage", "Emit a warning or error if @StandardException is used.") {}; } diff --git a/src/core/lombok/bytecode/AsmUtil.java b/src/core/lombok/bytecode/AsmUtil.java index 42bf9700..fc2533e5 100644 --- a/src/core/lombok/bytecode/AsmUtil.java +++ b/src/core/lombok/bytecode/AsmUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 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 @@ -37,7 +37,7 @@ class AsmUtil { ClassReader reader = new ClassReader(byteCode); ClassWriter writer = new FixedClassWriter(reader, 0); - ClassVisitor visitor = new ClassVisitor(Opcodes.ASM7, writer) { + ClassVisitor visitor = new ClassVisitor(Opcodes.ASM9, writer) { @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { return new JSRInlinerAdapter(super.visitMethod(access, name, desc, signature, exceptions), access, name, desc, signature, exceptions); } diff --git a/src/core/lombok/bytecode/PoolConstantsApp.java b/src/core/lombok/bytecode/PoolConstantsApp.java index c2120cc0..65b51f17 100644 --- a/src/core/lombok/bytecode/PoolConstantsApp.java +++ b/src/core/lombok/bytecode/PoolConstantsApp.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -26,8 +26,7 @@ import java.util.ArrayList; import java.util.List; import lombok.core.LombokApp; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.zwitserloot.cmdreader.CmdReader; import com.zwitserloot.cmdreader.Description; @@ -36,9 +35,8 @@ import com.zwitserloot.cmdreader.Mandatory; import com.zwitserloot.cmdreader.Sequential; import com.zwitserloot.cmdreader.Shorthand; -@ProviderFor(LombokApp.class) +@Provides public class PoolConstantsApp extends LombokApp { - @Override public String getAppName() { return "Xprintpool"; } diff --git a/src/core/lombok/bytecode/PostCompilerApp.java b/src/core/lombok/bytecode/PostCompilerApp.java index 5f49bd81..7f2237c0 100644 --- a/src/core/lombok/bytecode/PostCompilerApp.java +++ b/src/core/lombok/bytecode/PostCompilerApp.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 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 @@ -33,8 +33,7 @@ import java.util.List; import lombok.core.DiagnosticsReceiver; import lombok.core.LombokApp; import lombok.core.PostCompiler; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.zwitserloot.cmdreader.CmdReader; import com.zwitserloot.cmdreader.Description; @@ -43,7 +42,7 @@ import com.zwitserloot.cmdreader.Mandatory; import com.zwitserloot.cmdreader.Sequential; import com.zwitserloot.cmdreader.Shorthand; -@ProviderFor(LombokApp.class) +@Provides public class PostCompilerApp extends LombokApp { @Override public List<String> getAppAliases() { return Arrays.asList("post", "postcompile"); diff --git a/src/core/lombok/bytecode/PreventNullAnalysisRemover.java b/src/core/lombok/bytecode/PreventNullAnalysisRemover.java index 20572e22..8ae7af5b 100644 --- a/src/core/lombok/bytecode/PreventNullAnalysisRemover.java +++ b/src/core/lombok/bytecode/PreventNullAnalysisRemover.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 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 @@ -27,15 +27,15 @@ import java.util.concurrent.atomic.AtomicBoolean; import lombok.core.DiagnosticsReceiver; import lombok.core.PostCompilerTransformation; +import lombok.spi.Provides; -import org.mangosdk.spi.ProviderFor; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -@ProviderFor(PostCompilerTransformation.class) +@Provides public class PreventNullAnalysisRemover implements PostCompilerTransformation { @Override public byte[] applyTransformations(byte[] original, String fileName, DiagnosticsReceiver diagnostics) { @@ -50,7 +50,7 @@ public class PreventNullAnalysisRemover implements PostCompilerTransformation { class PreventNullAnalysisVisitor extends MethodVisitor { PreventNullAnalysisVisitor(MethodVisitor mv) { - super(Opcodes.ASM7, mv); + super(Opcodes.ASM9, mv); } @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { @@ -68,7 +68,7 @@ public class PreventNullAnalysisRemover implements PostCompilerTransformation { } } - reader.accept(new ClassVisitor(Opcodes.ASM7, writer) { + reader.accept(new ClassVisitor(Opcodes.ASM9, writer) { @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { return new PreventNullAnalysisVisitor(super.visitMethod(access, name, desc, signature, exceptions)); } diff --git a/src/core/lombok/bytecode/SneakyThrowsRemover.java b/src/core/lombok/bytecode/SneakyThrowsRemover.java index 037cb109..ea1c3cec 100644 --- a/src/core/lombok/bytecode/SneakyThrowsRemover.java +++ b/src/core/lombok/bytecode/SneakyThrowsRemover.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 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 @@ -27,8 +27,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import lombok.core.DiagnosticsReceiver; import lombok.core.PostCompilerTransformation; +import lombok.spi.Provides; -import org.mangosdk.spi.ProviderFor; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; @@ -37,7 +37,7 @@ import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -@ProviderFor(PostCompilerTransformation.class) +@Provides public class SneakyThrowsRemover implements PostCompilerTransformation { @Override public byte[] applyTransformations(byte[] original, String fileName, final DiagnosticsReceiver diagnostics) { @@ -52,7 +52,7 @@ public class SneakyThrowsRemover implements PostCompilerTransformation { class SneakyThrowsRemoverVisitor extends MethodVisitor { SneakyThrowsRemoverVisitor(MethodVisitor mv) { - super(Opcodes.ASM7, mv); + super(Opcodes.ASM9, mv); } private boolean methodInsnQueued = false; @@ -177,7 +177,7 @@ public class SneakyThrowsRemover implements PostCompilerTransformation { } } - reader.accept(new ClassVisitor(Opcodes.ASM7, writer) { + reader.accept(new ClassVisitor(Opcodes.ASM9, writer) { @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { return new SneakyThrowsRemoverVisitor(super.visitMethod(access, name, desc, signature, exceptions)); } diff --git a/src/core/lombok/core/AnnotationProcessor.java b/src/core/lombok/core/AnnotationProcessor.java index 3fef46b8..28d16298 100644 --- a/src/core/lombok/core/AnnotationProcessor.java +++ b/src/core/lombok/core/AnnotationProcessor.java @@ -219,8 +219,12 @@ public class AnnotationProcessor extends AbstractProcessor { if (supported.length() > 0) supported.append(", "); supported.append(proc.getName()); } - procEnv.getMessager().printMessage(Kind.WARNING, String.format("You aren't using a compiler supported by lombok, so lombok will not work and has been disabled.\n" + + if (procEnv.getClass().getName().equals("com.google.turbine.processing.TurbineProcessingEnvironment")) { + procEnv.getMessager().printMessage(Kind.ERROR, String.format("Turbine is not currently supported by lombok.")); + } else { + procEnv.getMessager().printMessage(Kind.WARNING, String.format("You aren't using a compiler supported by lombok, so lombok will not work and has been disabled.\n" + "Your processor is: %s\nLombok supports: %s", procEnv.getClass().getName(), supported)); + } } } 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/core/Main.java b/src/core/lombok/core/Main.java index 47afaefd..7be9e2ea 100644 --- a/src/core/lombok/core/Main.java +++ b/src/core/lombok/core/Main.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 @@ -30,7 +30,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; public class Main { private static final Collection<?> HELP_SWITCHES = Collections.unmodifiableList(Arrays.asList( @@ -46,7 +46,7 @@ public class Main { } } - @ProviderFor(LombokApp.class) + @Provides public static class VersionApp extends LombokApp { @Override public String getAppName() { return "version"; @@ -66,7 +66,7 @@ public class Main { } } - @ProviderFor(LombokApp.class) + @Provides public static class LicenseApp extends LombokApp { @Override public String getAppName() { return "license"; @@ -145,7 +145,7 @@ public class Main { out.println("------------------------------"); } out.println("projectlombok.org " + Version.getFullVersion()); - out.println("Copyright (C) 2009-2018 The Project Lombok Authors."); + out.println("Copyright (C) 2009-2021 The Project Lombok Authors."); out.println("Run 'lombok license' to see the lombok license agreement."); out.println(); out.println("Run lombok without any parameters to start the graphical installer."); diff --git a/src/core/lombok/core/PublicApiCreatorApp.java b/src/core/lombok/core/PublicApiCreatorApp.java index c1430c24..f45808fe 100644 --- a/src/core/lombok/core/PublicApiCreatorApp.java +++ b/src/core/lombok/core/PublicApiCreatorApp.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -36,10 +36,9 @@ import java.util.zip.ZipEntry; import lombok.Lombok; import lombok.patcher.ClassRootFinder; +import lombok.spi.Provides; -import org.mangosdk.spi.ProviderFor; - -@ProviderFor(LombokApp.class) +@Provides public class PublicApiCreatorApp extends LombokApp { @Override public String getAppName() { return "publicApi"; diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index af0941bb..eb8ed6e7 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.java @@ -30,7 +30,7 @@ public class Version { // ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries). // Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example. // Official builds always end in an even number. (Since 0.10.2). - private static final String VERSION = "1.18.19"; + private static final String VERSION = "1.18.21"; private static final String RELEASE_NAME = "Edgy Guinea Pig"; // private static final String RELEASE_NAME = "Envious Ferret"; diff --git a/src/core/lombok/core/configuration/ConfigurationApp.java b/src/core/lombok/core/configuration/ConfigurationApp.java index 9c225fdb..8d794c8a 100644 --- a/src/core/lombok/core/configuration/ConfigurationApp.java +++ b/src/core/lombok/core/configuration/ConfigurationApp.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2020 The Project Lombok Authors. + * Copyright (C) 2014-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 @@ -41,8 +41,6 @@ import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; -import org.mangosdk.spi.ProviderFor; - import com.zwitserloot.cmdreader.CmdReader; import com.zwitserloot.cmdreader.Description; import com.zwitserloot.cmdreader.Excludes; @@ -56,8 +54,9 @@ import com.zwitserloot.cmdreader.Shorthand; import lombok.ConfigurationKeys; import lombok.core.LombokApp; import lombok.core.configuration.ConfigurationParser.Collector; +import lombok.spi.Provides; -@ProviderFor(LombokApp.class) +@Provides public class ConfigurationApp extends LombokApp { private static final URI NO_CONFIG = URI.create(""); diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index 14c2d66c..19cc5a9e 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -325,7 +325,9 @@ public class HandlerUtil { "com.fasterxml.jackson.annotation.JsonTypeInfo", "com.fasterxml.jackson.annotation.JsonView", "com.fasterxml.jackson.databind.annotation.JsonDeserialize", + "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper", "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty", + "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText", })); COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] { "com.fasterxml.jackson.annotation.JsonAnySetter", diff --git a/src/core/lombok/core/handlers/SneakyThrowsAndCleanupDependencyInfo.java b/src/core/lombok/core/handlers/SneakyThrowsAndCleanupDependencyInfo.java index 3b6f8974..482c166b 100644 --- a/src/core/lombok/core/handlers/SneakyThrowsAndCleanupDependencyInfo.java +++ b/src/core/lombok/core/handlers/SneakyThrowsAndCleanupDependencyInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 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 @@ -25,10 +25,9 @@ import java.util.Arrays; import java.util.List; import lombok.core.runtimeDependencies.RuntimeDependencyInfo; +import lombok.spi.Provides; -import org.mangosdk.spi.ProviderFor; - -@ProviderFor(RuntimeDependencyInfo.class) +@Provides public class SneakyThrowsAndCleanupDependencyInfo implements RuntimeDependencyInfo { @Override public List<String> getRuntimeDependencies() { return Arrays.asList( diff --git a/src/core/lombok/core/runtimeDependencies/CreateLombokRuntimeApp.java b/src/core/lombok/core/runtimeDependencies/CreateLombokRuntimeApp.java index 4d5988af..21f097d7 100644 --- a/src/core/lombok/core/runtimeDependencies/CreateLombokRuntimeApp.java +++ b/src/core/lombok/core/runtimeDependencies/CreateLombokRuntimeApp.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 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 @@ -38,8 +38,7 @@ import java.util.zip.ZipEntry; import lombok.core.LombokApp; import lombok.core.SpiLoadUtil; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.zwitserloot.cmdreader.CmdReader; import com.zwitserloot.cmdreader.Description; @@ -48,7 +47,7 @@ import com.zwitserloot.cmdreader.Mandatory; import com.zwitserloot.cmdreader.Requires; import com.zwitserloot.cmdreader.Shorthand; -@ProviderFor(LombokApp.class) +@Provides public class CreateLombokRuntimeApp extends LombokApp { private List<RuntimeDependencyInfo> infoObjects; diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java index 73114c6c..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 @@ -23,7 +23,6 @@ package lombok.eclipse; import java.io.File; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.util.ArrayList; @@ -31,10 +30,9 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import lombok.Lombok; 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; @@ -117,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. @@ -347,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: @@ -386,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; } @@ -405,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..70d98cc6 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; } } @@ -2626,6 +2622,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/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java index 760f5282..d099cab2 100755 --- a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java +++ b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -451,7 +451,17 @@ public class EclipseSingularsRecipes { statements.add(0, nullCheck); } + protected abstract int getTypeArgumentsCount(); + protected abstract char[][] getEmptyMakerReceiver(String targetFqn); protected abstract char[] getEmptyMakerSelector(String targetFqn); + + public MessageSend getEmptyExpression(String targetFqn, SingularData data, EclipseNode typeNode, ASTNode source) { + MessageSend send = new MessageSend(); + send.receiver = generateQualifiedNameRef(source, getEmptyMakerReceiver(targetFqn)); + send.selector = getEmptyMakerSelector(targetFqn); + send.typeArguments = createTypeArgs(getTypeArgumentsCount(), false, typeNode, data.getTypeArgs()); + return send; + } } } diff --git a/src/core/lombok/eclipse/handlers/HandleAccessors.java b/src/core/lombok/eclipse/handlers/HandleAccessors.java index 864ff50b..6a92dee2 100644 --- a/src/core/lombok/eclipse/handlers/HandleAccessors.java +++ b/src/core/lombok/eclipse/handlers/HandleAccessors.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Project Lombok Authors. + * Copyright (C) 2014-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 @@ -28,11 +28,11 @@ import lombok.core.HandlerPriority; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.experimental.Accessors; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.mangosdk.spi.ProviderFor; -@ProviderFor(EclipseAnnotationHandler.class) +@Provides @HandlerPriority(65536) public class HandleAccessors extends EclipseAnnotationHandler<Accessors> { @Override public void handle(AnnotationValues<Accessors> annotation, Annotation ast, EclipseNode annotationNode) { diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 189c5a69..c002c4ca 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2020 The Project Lombok Authors. + * Copyright (C) 2013-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 @@ -74,7 +74,6 @@ import org.eclipse.jdt.internal.compiler.lookup.ClassScope; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.mangosdk.spi.ProviderFor; import lombok.AccessLevel; import lombok.Builder; @@ -98,8 +97,9 @@ import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists; import lombok.experimental.NonFinal; +import lombok.spi.Provides; -@ProviderFor(EclipseAnnotationHandler.class) +@Provides @HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes. public class HandleBuilder extends EclipseAnnotationHandler<Builder> { private HandleConstructor handleConstructor = new HandleConstructor(); @@ -183,14 +183,14 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { builderMethodName = ann.builderMethodName(); buildMethodName = ann.buildMethodName(); - setBuilderClassName(fixBuilderClassName(node, ann.builderClassName())); + setBuilderClassName(getBuilderClassNameTemplate(node, ann.builderClassName())); toBuilder = ann.toBuilder(); if (builderMethodName == null) builderMethodName = "builder"; if (buildMethodName == null) buildMethodName = "build"; } - static String fixBuilderClassName(EclipseNode node, String override) { + static String getBuilderClassNameTemplate(EclipseNode node, String override) { if (override != null && !override.isEmpty()) return override; override = node.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME); if (override != null && !override.isEmpty()) return override; @@ -202,8 +202,12 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } String replaceBuilderClassName(char[] name) { - if (builderClassName.indexOf('*') == -1) return builderClassName; - return builderClassName.replace("*", new String(name)); + return replaceBuilderClassName(name, builderClassName); + } + + String replaceBuilderClassName(char[] name, String template) { + if (template.indexOf('*') == -1) return template; + return template.replace("*", new String(name)); } String replaceBuilderClassName(String name) { @@ -253,6 +257,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 +294,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 +347,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 +461,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/HandleBuilderDefault.java b/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java index d0c597fd..464a0efd 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 The Project Lombok Authors. + * Copyright (C) 2017-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 @@ -23,7 +23,6 @@ package lombok.eclipse.handlers; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.mangosdk.spi.ProviderFor; import lombok.Builder; import lombok.core.AST.Kind; @@ -32,8 +31,9 @@ import lombok.core.HandlerPriority; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.experimental.SuperBuilder; +import lombok.spi.Provides; -@ProviderFor(EclipseAnnotationHandler.class) +@Provides @HandlerPriority(-1025) //HandleBuilder's level, minus one. public class HandleBuilderDefault extends EclipseAnnotationHandler<Builder.Default> { @Override public void handle(AnnotationValues<Builder.Default> annotation, Annotation ast, EclipseNode annotationNode) { diff --git a/src/core/lombok/eclipse/handlers/HandleCleanup.java b/src/core/lombok/eclipse/handlers/HandleCleanup.java index dde7cd08..3ce41763 100644 --- a/src/core/lombok/eclipse/handlers/HandleCleanup.java +++ b/src/core/lombok/eclipse/handlers/HandleCleanup.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 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,6 +32,7 @@ import lombok.core.AnnotationValues; import lombok.core.AST.Kind; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; @@ -52,12 +53,11 @@ import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.SwitchStatement; import org.eclipse.jdt.internal.compiler.ast.TryStatement; -import org.mangosdk.spi.ProviderFor; /** * Handles the {@code lombok.Cleanup} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) +@Provides public class HandleCleanup extends EclipseAnnotationHandler<Cleanup> { public void handle(AnnotationValues<Cleanup> annotation, Annotation ast, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.CLEANUP_FLAG_USAGE, "@Cleanup"); diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index 3233a8c6..e69c3267 100755 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.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 @@ -44,6 +44,7 @@ import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; @@ -79,10 +80,9 @@ 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; public class HandleConstructor { - @ProviderFor(EclipseAnnotationHandler.class) + @Provides public static class HandleNoArgsConstructor extends EclipseAnnotationHandler<NoArgsConstructor> { private static final String NAME = NoArgsConstructor.class.getSimpleName(); private HandleConstructor handleConstructor = new HandleConstructor(); @@ -105,7 +105,7 @@ public class HandleConstructor { } } - @ProviderFor(EclipseAnnotationHandler.class) + @Provides public static class HandleRequiredArgsConstructor extends EclipseAnnotationHandler<RequiredArgsConstructor> { private static final String NAME = RequiredArgsConstructor.class.getSimpleName(); private HandleConstructor handleConstructor = new HandleConstructor(); @@ -166,7 +166,7 @@ public class HandleConstructor { return fields; } - @ProviderFor(EclipseAnnotationHandler.class) + @Provides public static class HandleAllArgsConstructor extends EclipseAnnotationHandler<AllArgsConstructor> { private static final String NAME = AllArgsConstructor.class.getSimpleName(); @@ -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..00e1fd38 100644 --- a/src/core/lombok/eclipse/handlers/HandleData.java +++ b/src/core/lombok/eclipse/handlers/HandleData.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 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 @@ -22,6 +22,7 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.*; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.util.Collections; @@ -32,16 +33,14 @@ import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; 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; -import org.mangosdk.spi.ProviderFor; /** * Handles the {@code lombok.Data} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) +@Provides public class HandleData extends EclipseAnnotationHandler<Data> { private HandleGetter handleGetter = new HandleGetter(); private HandleSetter handleSetter = new HandleSetter(); @@ -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/HandleDelegate.java b/src/core/lombok/eclipse/handlers/HandleDelegate.java index 9d352558..0e3eab66 100644 --- a/src/core/lombok/eclipse/handlers/HandleDelegate.java +++ b/src/core/lombok/eclipse/handlers/HandleDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Project Lombok Authors. + * Copyright (C) 2014-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 @@ -27,14 +27,14 @@ import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.experimental.Delegate; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.mangosdk.spi.ProviderFor; /** * This class just handles basic error cases. The real meat of eclipse '@Delegate' support is in {@code PatchDelegate}. */ -@ProviderFor(EclipseAnnotationHandler.class) +@Provides public class HandleDelegate extends EclipseAnnotationHandler<Delegate> { public void handle(AnnotationValues<Delegate> annotation, Annotation ast, EclipseNode annotationNode) { handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.DELEGATE_FLAG_USAGE, "@Delegate"); diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index deb19c00..12a3c315 100755 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.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 @@ -48,6 +48,7 @@ import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -89,12 +90,11 @@ import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.mangosdk.spi.ProviderFor; /** * Handles the {@code EqualsAndHashCode} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) +@Provides public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndHashCode> { private static final String HASH_CODE_CACHE_NAME = "$hashCodeCache"; @@ -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) { @@ -168,30 +162,6 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH boolean isDirectDescendantOfObject = isDirectDescendantOfObject(typeNode); - if (isDirectDescendantOfObject && callSuper) { - errorNode.addError("Generating equals/hashCode with a supercall to java.lang.Object is pointless."); - return; - } - - if (implicitCallSuper && !isDirectDescendantOfObject) { - CallSuperType cst = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_CALL_SUPER); - if (cst == null) cst = CallSuperType.WARN; - - switch (cst) { - default: - case WARN: - errorNode.addWarning("Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type."); - callSuper = false; - break; - case SKIP: - callSuper = false; - break; - case CALL: - callSuper = true; - break; - } - } - boolean isFinal = (typeDecl.modifiers & ClassFileConstants.AccFinal) != 0; boolean needsCanEqual = !isFinal || !isDirectDescendantOfObject; MemberExistsResult equalsExists = methodExists("equals", typeNode, 1); @@ -220,6 +190,30 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH //fallthrough } + if (isDirectDescendantOfObject && callSuper) { + errorNode.addError("Generating equals/hashCode with a supercall to java.lang.Object is pointless."); + return; + } + + if (implicitCallSuper && !isDirectDescendantOfObject) { + CallSuperType cst = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_CALL_SUPER); + if (cst == null) cst = CallSuperType.WARN; + + switch (cst) { + default: + case WARN: + errorNode.addWarning("Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type."); + callSuper = false; + break; + case SKIP: + callSuper = false; + break; + case CALL: + callSuper = true; + break; + } + } + MethodDeclaration equalsMethod = createEquals(typeNode, members, callSuper, errorNode.get(), fieldAccess, needsCanEqual, onParam); equalsMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration)typeNode.get()).scope); injectMethod(typeNode, equalsMethod); @@ -256,6 +250,8 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH setGeneratedBy(hashCodeCacheDecl.type, source); } + private static final char[] HASH_CODE = "hashCode".toCharArray(), FLOAT_TO_INT_BITS = "floatToIntBits".toCharArray(), DOUBLE_TO_LONG_BITS = "doubleToLongBits".toCharArray(); + public MethodDeclaration createHashCode(EclipseNode type, Collection<Included<EclipseNode, EqualsAndHashCode.Include>> members, boolean callSuper, boolean cacheHashCode, ASTNode source, FieldAccess fieldAccess) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long) pS << 32 | pE; @@ -379,7 +375,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH floatToIntBits.sourceStart = pS; floatToIntBits.sourceEnd = pE; setGeneratedBy(floatToIntBits, source); floatToIntBits.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_FLOAT); - floatToIntBits.selector = "floatToIntBits".toCharArray(); + floatToIntBits.selector = FLOAT_TO_INT_BITS; floatToIntBits.arguments = new Expression[] { fieldAccessor }; statements.add(createResultCalculation(source, floatToIntBits)); } else if (Arrays.equals(TypeConstants.DOUBLE, token)) { @@ -388,7 +384,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH doubleToLongBits.sourceStart = pS; doubleToLongBits.sourceEnd = pE; setGeneratedBy(doubleToLongBits, source); doubleToLongBits.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_DOUBLE); - doubleToLongBits.selector = "doubleToLongBits".toCharArray(); + doubleToLongBits.selector = DOUBLE_TO_LONG_BITS; doubleToLongBits.arguments = new Expression[] { fieldAccessor }; statements.add(createLocalDeclaration(source, dollarFieldName, TypeReference.baseTypeReference(TypeIds.T_long, 0), doubleToLongBits)); SingleNameReference copy1 = new SingleNameReference(dollarFieldName, p); @@ -412,7 +408,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH hashCodeCall.sourceStart = pS; hashCodeCall.sourceEnd = pE; setGeneratedBy(hashCodeCall, source); hashCodeCall.receiver = copy1; - hashCodeCall.selector = "hashCode".toCharArray(); + hashCodeCall.selector = HASH_CODE; NullLiteral nullLiteral = new NullLiteral(pS, pE); setGeneratedBy(nullLiteral, source); EqualExpression objIsNull = new EqualExpression(copy2, nullLiteral, OperatorIds.EQUAL_EQUAL); diff --git a/src/core/lombok/eclipse/handlers/HandleExtensionMethod.java b/src/core/lombok/eclipse/handlers/HandleExtensionMethod.java index 8e53d873..5857780c 100644 --- a/src/core/lombok/eclipse/handlers/HandleExtensionMethod.java +++ b/src/core/lombok/eclipse/handlers/HandleExtensionMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -28,7 +28,6 @@ import java.util.List; 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; import lombok.ConfigurationKeys; import lombok.core.AnnotationValues; @@ -36,9 +35,10 @@ import lombok.core.HandlerPriority; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.experimental.ExtensionMethod; +import lombok.spi.Provides; // This handler just does some additional error checking; the real work is done in the agent. -@ProviderFor(EclipseAnnotationHandler.class) +@Provides @HandlerPriority(66560) // 2^16 + 2^10; we must run AFTER HandleVal which is at 2^16 public class HandleExtensionMethod extends EclipseAnnotationHandler<ExtensionMethod> { @Override public void handle(AnnotationValues<ExtensionMethod> annotation, Annotation ast, EclipseNode annotationNode) { diff --git a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java index 702713fe..5900e7ed 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2016 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -38,6 +38,7 @@ import lombok.eclipse.EclipseNode; import lombok.experimental.FieldDefaults; import lombok.experimental.NonFinal; import lombok.experimental.PackagePrivate; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -47,12 +48,11 @@ import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; 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.mangosdk.spi.ProviderFor; /** * Handles the {@code lombok.FieldDefaults} annotation for eclipse. */ -@ProviderFor(EclipseASTVisitor.class) +@Provides(EclipseASTVisitor.class) @HandlerPriority(-2048) //-2^11; to ensure @Value picks up on messing with the fields' 'final' state, run earlier. public class HandleFieldDefaults extends EclipseASTAdapter { public boolean generateFieldDefaultsForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean makeFinal, boolean checkForTypeLevelFieldDefaults) { @@ -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/HandleFieldNameConstants.java b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java index cee3912c..cc1a5c3f 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2019 The Project Lombok Authors. + * Copyright (C) 2014-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 @@ -41,7 +41,6 @@ import org.eclipse.jdt.internal.compiler.ast.StringLiteral; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.mangosdk.spi.ProviderFor; import lombok.AccessLevel; import lombok.ConfigurationKeys; @@ -54,8 +53,9 @@ import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; import lombok.experimental.FieldNameConstants; +import lombok.spi.Provides; -@ProviderFor(EclipseAnnotationHandler.class) +@Provides public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldNameConstants> { private static final IdentifierName FIELDS = IdentifierName.valueOf("Fields"); diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java index 4d7d84ce..7f8fdef2 100644 --- a/src/core/lombok/eclipse/handlers/HandleGetter.java +++ b/src/core/lombok/eclipse/handlers/HandleGetter.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 @@ -35,6 +35,7 @@ import java.util.Map; import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.experimental.Delegate; +import lombok.spi.Provides; import lombok.Getter; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; @@ -73,14 +74,14 @@ 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; /** * Handles the {@code lombok.Getter} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) +@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/HandleHelper.java b/src/core/lombok/eclipse/handlers/HandleHelper.java index 36f53813..7977c507 100755 --- a/src/core/lombok/eclipse/handlers/HandleHelper.java +++ b/src/core/lombok/eclipse/handlers/HandleHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2016 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -45,7 +45,6 @@ import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.mangosdk.spi.ProviderFor; import lombok.ConfigurationKeys; import lombok.core.AST.Kind; @@ -53,11 +52,12 @@ import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.experimental.Helper; +import lombok.spi.Provides; /** * Handles the {@code lombok.Cleanup} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) +@Provides public class HandleHelper extends EclipseAnnotationHandler<Helper> { private Statement[] getStatementsFromAstNode(ASTNode node) { if (node instanceof Block) return ((Block) node).statements; diff --git a/src/core/lombok/eclipse/handlers/HandleJacksonized.java b/src/core/lombok/eclipse/handlers/HandleJacksonized.java index 90ee7582..466cc338 100644 --- a/src/core/lombok/eclipse/handlers/HandleJacksonized.java +++ b/src/core/lombok/eclipse/handlers/HandleJacksonized.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2020 The Project Lombok Authors. + * Copyright (C) 2013-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 @@ -37,7 +37,6 @@ import org.eclipse.jdt.internal.compiler.ast.StringLiteral; 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.mangosdk.spi.ProviderFor; import lombok.Builder; import lombok.ConfigurationKeys; @@ -50,13 +49,15 @@ import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.experimental.SuperBuilder; import lombok.extern.jackson.Jacksonized; +import lombok.spi.Provides; /** * This (ecj) handler deals with {@code @Jacksonized} modifying the (already * generated) {@code @Builder} or {@code @SuperBuilder} to conform to Jackson's * needs for builders. */ -@ProviderFor(EclipseAnnotationHandler.class) @HandlerPriority(-512) // Above Handle(Super)Builder's level (builders must be already generated). +@Provides +@HandlerPriority(-512) // Above Handle(Super)Builder's level (builders must be already generated). public class HandleJacksonized extends EclipseAnnotationHandler<Jacksonized> { private static final char[][] JSON_POJO_BUILDER_ANNOTATION = Eclipse.fromQualifiedName("com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder"); diff --git a/src/core/lombok/eclipse/handlers/HandleLog.java b/src/core/lombok/eclipse/handlers/HandleLog.java index 8297426d..df3989a4 100644 --- a/src/core/lombok/eclipse/handlers/HandleLog.java +++ b/src/core/lombok/eclipse/handlers/HandleLog.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2019 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 @@ -38,7 +38,6 @@ import org.eclipse.jdt.internal.compiler.ast.StringLiteral; 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.mangosdk.spi.ProviderFor; import lombok.ConfigurationKeys; import lombok.core.AnnotationValues; @@ -49,10 +48,11 @@ import lombok.core.handlers.LoggingFramework; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; +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."); @@ -203,7 +208,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.apachecommons.CommonsLog} annotation for Eclipse. */ - @ProviderFor(EclipseAnnotationHandler.class) + @Provides public static class HandleCommonsLog extends EclipseAnnotationHandler<lombok.extern.apachecommons.CommonsLog> { @Override public void handle(AnnotationValues<lombok.extern.apachecommons.CommonsLog> annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_COMMONS_FLAG_USAGE, "@apachecommons.CommonsLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -214,7 +219,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.java.Log} annotation for Eclipse. */ - @ProviderFor(EclipseAnnotationHandler.class) + @Provides public static class HandleJulLog extends EclipseAnnotationHandler<lombok.extern.java.Log> { @Override public void handle(AnnotationValues<lombok.extern.java.Log> annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_JUL_FLAG_USAGE, "@java.Log", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -225,7 +230,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.log4j.Log4j} annotation for Eclipse. */ - @ProviderFor(EclipseAnnotationHandler.class) + @Provides public static class HandleLog4jLog extends EclipseAnnotationHandler<lombok.extern.log4j.Log4j> { @Override public void handle(AnnotationValues<lombok.extern.log4j.Log4j> annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_LOG4J_FLAG_USAGE, "@Log4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -236,7 +241,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.log4j.Log4j2} annotation for Eclipse. */ - @ProviderFor(EclipseAnnotationHandler.class) + @Provides public static class HandleLog4j2Log extends EclipseAnnotationHandler<lombok.extern.log4j.Log4j2> { @Override public void handle(AnnotationValues<lombok.extern.log4j.Log4j2> annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_LOG4J2_FLAG_USAGE, "@Log4j2", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -247,7 +252,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.slf4j.Slf4j} annotation for Eclipse. */ - @ProviderFor(EclipseAnnotationHandler.class) + @Provides public static class HandleSlf4jLog extends EclipseAnnotationHandler<lombok.extern.slf4j.Slf4j> { @Override public void handle(AnnotationValues<lombok.extern.slf4j.Slf4j> annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_SLF4J_FLAG_USAGE, "@Slf4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -258,7 +263,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.slf4j.XSlf4j} annotation for Eclipse. */ - @ProviderFor(EclipseAnnotationHandler.class) + @Provides public static class HandleXSlf4jLog extends EclipseAnnotationHandler<lombok.extern.slf4j.XSlf4j> { @Override public void handle(AnnotationValues<lombok.extern.slf4j.XSlf4j> annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_XSLF4J_FLAG_USAGE, "@XSlf4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -269,7 +274,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.jbosslog.JBossLog} annotation for Eclipse. */ - @ProviderFor(EclipseAnnotationHandler.class) + @Provides public static class HandleJBossLog extends EclipseAnnotationHandler<lombok.extern.jbosslog.JBossLog> { @Override public void handle(AnnotationValues<lombok.extern.jbosslog.JBossLog> annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_JBOSSLOG_FLAG_USAGE, "@JBossLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -280,7 +285,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.flogger.Flogger} annotation for Eclipse. */ - @ProviderFor(EclipseAnnotationHandler.class) + @Provides public static class HandleFloggerLog extends EclipseAnnotationHandler<lombok.extern.flogger.Flogger> { @Override public void handle(AnnotationValues<lombok.extern.flogger.Flogger> annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_FLOGGER_FLAG_USAGE, "@Flogger", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -291,7 +296,7 @@ public class HandleLog { /** * Handles the {@link lombok.CustomLog} annotation for Eclipse. */ - @ProviderFor(EclipseAnnotationHandler.class) + @Provides public static class HandleCustomLog extends EclipseAnnotationHandler<lombok.CustomLog> { @Override public void handle(AnnotationValues<lombok.CustomLog> annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_CUSTOM_FLAG_USAGE, "@CustomLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); diff --git a/src/core/lombok/eclipse/handlers/HandleNonNull.java b/src/core/lombok/eclipse/handlers/HandleNonNull.java index 903d098b..365eef33 100644 --- a/src/core/lombok/eclipse/handlers/HandleNonNull.java +++ b/src/core/lombok/eclipse/handlers/HandleNonNull.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2019 The Project Lombok Authors. + * Copyright (C) 2013-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 @@ -22,10 +22,12 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.handleFlagUsage; -import static lombok.eclipse.Eclipse.isPrimitive; +import static lombok.eclipse.Eclipse.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; @@ -35,31 +37,40 @@ import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.AssertStatement; import org.eclipse.jdt.internal.compiler.ast.Assignment; import org.eclipse.jdt.internal.compiler.ast.Block; +import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; import org.eclipse.jdt.internal.compiler.ast.EqualExpression; +import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.FieldReference; import org.eclipse.jdt.internal.compiler.ast.IfStatement; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; +import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement; +import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.ThrowStatement; import org.eclipse.jdt.internal.compiler.ast.TryStatement; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; -import org.mangosdk.spi.ProviderFor; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; 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.spi.Provides; -@DeferUntilPostDiet -@ProviderFor(EclipseAnnotationHandler.class) +@Provides @HandlerPriority(value = 512) // 2^9; onParameter=@__(@NonNull) has to run first. public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { private static final char[] REQUIRE_NON_NULL = "requireNonNull".toCharArray(); @@ -80,10 +91,163 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { } } + private List<FieldDeclaration> getRecordComponents(EclipseNode typeNode) { + List<FieldDeclaration> list = new ArrayList<FieldDeclaration>(); + + for (EclipseNode child : typeNode.down()) { + if (child.getKind() == Kind.FIELD) { + FieldDeclaration fd = (FieldDeclaration) child.get(); + if ((fd.modifiers & AccRecord) != 0) list.add(fd); + } + } + + return list; + } + + private EclipseNode addCompactConstructorIfNeeded(EclipseNode typeNode, EclipseNode annotationNode) { + // explicit Compact Constructor has bits set: Bit32, IsCanonicalConstructor (10). + // implicit Compact Constructor has bits set: Bit32, IsCanonicalConstructor (10), and IsImplicit (11). + // explicit constructor with long-form shows up as a normal constructor (Bit32 set, that's all), but the + // implicit CC is then also present and will presumably be stripped out in some later phase. + + EclipseNode toRemove = null; + EclipseNode existingCompactConstructor = null; + List<FieldDeclaration> recordComponents = null; + for (EclipseNode child : typeNode.down()) { + if (!(child.get() instanceof ConstructorDeclaration)) continue; + ConstructorDeclaration cd = (ConstructorDeclaration) child.get(); + if ((cd.bits & IsCanonicalConstructor) != 0) { + if ((cd.bits & IsImplicit) != 0) { + toRemove = child; + } else { + existingCompactConstructor = child; + } + } else { + // If this constructor has exact matching types vs. the record components, + // this is the canonical constructor in long form and we should not generate one. + + if (recordComponents == null) recordComponents = getRecordComponents(typeNode); + int argLength = cd.arguments == null ? 0 : cd.arguments.length; + int compLength = recordComponents.size(); + boolean isCanonical = argLength == compLength; + if (isCanonical) top: for (int i = 0; i < argLength; i++) { + TypeReference a = recordComponents.get(i).type; + TypeReference b = cd.arguments[i] == null ? null : cd.arguments[i].type; + // technically this won't match e.g. `java.lang.String` to just `String`; + // to use this feature you'll need to use the same way to write it, which seems + // like a fair requirement. + char[][] ta = getRawTypeName(a); + char[][] tb = getRawTypeName(b); + if (ta == null || tb == null || ta.length != tb.length) { + isCanonical = false; + break top; + } + for (int j = 0; j < ta.length; j++) { + if (!Arrays.equals(ta[j], tb[j])) { + isCanonical = false; + break top; + } + } + } + if (isCanonical) { + return null; + } + } + } + if (existingCompactConstructor != null) return existingCompactConstructor; + int posToInsert = -1; + TypeDeclaration td = (TypeDeclaration) typeNode.get(); + if (toRemove != null) { + int idxToRemove = -1; + for (int i = 0; i < td.methods.length; i++) { + if (td.methods[i] == toRemove.get()) idxToRemove = i; + } + if (idxToRemove != -1) { + System.arraycopy(td.methods, idxToRemove + 1, td.methods, idxToRemove, td.methods.length - idxToRemove - 1); + posToInsert = td.methods.length - 1; + typeNode.removeChild(toRemove); + } + } + if (posToInsert == -1) { + AbstractMethodDeclaration[] na = new AbstractMethodDeclaration[td.methods.length + 1]; + posToInsert = td.methods.length; + System.arraycopy(td.methods, 0, na, 0, posToInsert); + td.methods = na; + } + + ConstructorDeclaration cd = new ConstructorDeclaration(((CompilationUnitDeclaration) typeNode.top().get()).compilationResult); + cd.modifiers = ClassFileConstants.AccPublic; + cd.bits = ASTNode.Bit32 | ECLIPSE_DO_NOT_TOUCH_FLAG | IsCanonicalConstructor; + cd.selector = td.name; + cd.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + if (recordComponents == null) recordComponents = getRecordComponents(typeNode); + cd.arguments = new Argument[recordComponents.size()]; + cd.statements = new Statement[recordComponents.size()]; + cd.bits = IsCanonicalConstructor; + + for (int i = 0; i < cd.arguments.length; i++) { + FieldDeclaration cmp = recordComponents.get(i); + cd.arguments[i] = new Argument(cmp.name, cmp.sourceStart, cmp.type, 0); + cd.arguments[i].bits = ASTNode.IsArgument | ASTNode.IgnoreRawTypeCheck | ASTNode.IsReachable; + FieldReference lhs = new FieldReference(cmp.name, 0); + lhs.receiver = new ThisReference(0, 0); + SingleNameReference rhs = new SingleNameReference(cmp.name, 0); + cd.statements[i] = new Assignment(lhs, rhs, cmp.sourceEnd); + } + + setGeneratedBy(cd, annotationNode.get()); + for (int i = 0; i < cd.arguments.length; i++) { + FieldDeclaration cmp = recordComponents.get(i); + cd.arguments[i].sourceStart = cmp.sourceStart; + cd.arguments[i].sourceEnd = cmp.sourceStart; + cd.arguments[i].declarationSourceEnd = cmp.sourceStart; + cd.arguments[i].declarationEnd = cmp.sourceStart; + } + + td.methods[posToInsert] = cd; + cd.annotations = addSuppressWarningsAll(typeNode, cd, cd.annotations); + cd.annotations = addGenerated(typeNode, cd, cd.annotations); + return typeNode.add(cd, Kind.METHOD); + } + + private static char[][] getRawTypeName(TypeReference a) { + if (a instanceof QualifiedTypeReference) return ((QualifiedTypeReference) a).tokens; + if (a instanceof SingleTypeReference) return new char[][] {((SingleTypeReference) a).token}; + return null; + } + @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()) { + if (annotationNode.up().getKind() == Kind.FIELD) { + //Check if this is a record and we need to generate the compact form constructor. + EclipseNode typeNode = annotationNode.up().up(); + if (typeNode.getKind() == Kind.TYPE) { + if (isRecord(typeNode)) { + addCompactConstructorIfNeeded(typeNode, annotationNode); + } + } + } + + EcjAugments.ASTNode_handled.clear(ast); + return; + } + handle0(ast, annotationNode, false); } + private EclipseNode findCompactConstructor(EclipseNode typeNode) { + for (EclipseNode child : typeNode.down()) { + if (!(child.get() instanceof ConstructorDeclaration)) continue; + ConstructorDeclaration cd = (ConstructorDeclaration) child.get(); + if ((cd.bits & IsCanonicalConstructor) != 0 && (cd.bits & IsImplicit) == 0) return child; + } + + return null; + } + private void handle0(Annotation ast, EclipseNode annotationNode, boolean force) { handleFlagUsage(annotationNode, ConfigurationKeys.NON_NULL_FLAG_USAGE, "@NonNull"); @@ -92,13 +256,26 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { // but in that case those handlers will take care of it. However, we DO check if the annotation is applied to // a primitive, because those handlers trigger on any annotation named @NonNull and we only want the warning // behaviour on _OUR_ 'lombok.NonNull'. + EclipseNode fieldNode = annotationNode.up(); + EclipseNode typeNode = fieldNode.up(); try { if (isPrimitive(((AbstractVariableDeclaration) annotationNode.up().get()).type)) { annotationNode.addWarning("@NonNull is meaningless on a primitive."); + return; } } catch (Exception ignore) {} + if (isRecord(typeNode)) { + // well, these kinda double as parameters (of the compact constructor), so we do some work here. + // NB:Tthe diet parse run already added an explicit compact constructor if we need to take any actions. + EclipseNode compactConstructor = findCompactConstructor(typeNode); + + if (compactConstructor != null) { + addNullCheckIfNeeded((AbstractMethodDeclaration) compactConstructor.get(), (AbstractVariableDeclaration) fieldNode.get(), annotationNode); + } + } + return; } @@ -140,6 +317,11 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { return; } + addNullCheckIfNeeded(declaration, param, annotationNode); + paramNode.up().rebuild(); + } + + private void addNullCheckIfNeeded(AbstractMethodDeclaration declaration, AbstractVariableDeclaration param, EclipseNode annotationNode) { // Possibly, if 'declaration instanceof ConstructorDeclaration', fetch declaration.constructorCall, search it for any references to our parameter, // and if they exist, create a new method in the class: 'private static <T> T lombok$nullCheck(T expr, String msg) {if (expr == null) throw NPE; return expr;}' and // wrap all references to it in the super/this to a call to this method. @@ -188,7 +370,6 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { newStatements[skipOver] = nullCheck; declaration.statements = newStatements; } - paramNode.up().rebuild(); } public boolean isNullCheck(Statement stat) { diff --git a/src/core/lombok/eclipse/handlers/HandlePrintAST.java b/src/core/lombok/eclipse/handlers/HandlePrintAST.java index 234e29b8..9cc3e1ae 100644 --- a/src/core/lombok/eclipse/handlers/HandlePrintAST.java +++ b/src/core/lombok/eclipse/handlers/HandlePrintAST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 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 @@ -26,7 +26,6 @@ import java.io.FileNotFoundException; import java.io.PrintStream; import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.mangosdk.spi.ProviderFor; import lombok.Lombok; import lombok.core.AnnotationValues; @@ -36,11 +35,12 @@ import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseASTVisitor; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.spi.Provides; /** * Handles the {@code lombok.core.PrintAST} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) +@Provides @DeferUntilPostDiet @HandlerPriority(536870912) // 2^29; this handler is customarily run at the very end. public class HandlePrintAST extends EclipseAnnotationHandler<PrintAST> { diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index 83c6eef2..ddae21fb 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.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 @@ -38,6 +38,7 @@ import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -56,13 +57,14 @@ 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.TypeIds; -import org.mangosdk.spi.ProviderFor; /** * Handles the {@code lombok.Setter} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) +@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/HandleSneakyThrows.java b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java index 481dbcde..5f0ca3fb 100644 --- a/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java +++ b/src/core/lombok/eclipse/handlers/HandleSneakyThrows.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 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 @@ -36,6 +36,7 @@ import lombok.core.HandlerPriority; import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; @@ -56,12 +57,11 @@ import org.eclipse.jdt.internal.compiler.ast.Statement; 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 org.mangosdk.spi.ProviderFor; /** * Handles the {@code lombok.HandleSneakyThrows} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) +@Provides @DeferUntilPostDiet @HandlerPriority(value = 1024) // 2^10; @NonNull must have run first, so that we wrap around the statements generated by it. public class HandleSneakyThrows extends EclipseAnnotationHandler<SneakyThrows> { diff --git a/src/core/lombok/eclipse/handlers/HandleStandardException.java b/src/core/lombok/eclipse/handlers/HandleStandardException.java new file mode 100755 index 00000000..def6e495 --- /dev/null +++ b/src/core/lombok/eclipse/handlers/HandleStandardException.java @@ -0,0 +1,253 @@ +/* + * Copyright (C) 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.handlers; + +import lombok.AccessLevel; +import lombok.ConfigurationKeys; +import lombok.experimental.StandardException; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseHandlerUtil.*; +import lombok.spi.Provides; +import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; + +import java.lang.reflect.Modifier; +import java.util.*; + +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; +import static lombok.eclipse.Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +@Provides +public class HandleStandardException extends EclipseAnnotationHandler<StandardException> { + @Override + public void handle(AnnotationValues<StandardException> annotation, Annotation ast, EclipseNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.STANDARD_EXCEPTION_FLAG_USAGE, "@StandardException"); + + EclipseNode typeNode = annotationNode.up(); + if (!isClass(typeNode)) { + annotationNode.addError("@StandardException is only supported on a class"); + return; + } + + TypeDeclaration classDef = (TypeDeclaration) typeNode.get(); + if (classDef.superclass == null) { + annotationNode.addError("@StandardException requires that you extend a Throwable type"); + return; + } + + AccessLevel access = annotation.getInstance().access(); + + generateNoArgsConstructor(typeNode, access, annotationNode); + generateMsgOnlyConstructor(typeNode, access, annotationNode); + generateCauseOnlyConstructor(typeNode, access, annotationNode); + generateFullConstructor(typeNode, access, annotationNode); + } + + private void generateNoArgsConstructor(EclipseNode typeNode, AccessLevel level, EclipseNode source) { + if (hasConstructor(typeNode) != MemberExistsResult.NOT_EXISTS) return; + int pS = source.get().sourceStart, pE = source.get().sourceEnd; + + ExplicitConstructorCall explicitCall = new ExplicitConstructorCall(ExplicitConstructorCall.This); + explicitCall.arguments = new Expression[] {new NullLiteral(pS, pE), new NullLiteral(pS, pE)}; + ConstructorDeclaration constructor = createConstructor(level, typeNode, false, false, source, explicitCall, null); + injectMethod(typeNode, constructor); + } + + private void generateMsgOnlyConstructor(EclipseNode typeNode, AccessLevel level, EclipseNode source) { + if (hasConstructor(typeNode, String.class) != MemberExistsResult.NOT_EXISTS) return; + int pS = source.get().sourceStart, pE = source.get().sourceEnd; + long p = (long) pS << 32 | pE; + + ExplicitConstructorCall explicitCall = new ExplicitConstructorCall(ExplicitConstructorCall.This); + explicitCall.arguments = new Expression[] {new SingleNameReference(MESSAGE, p), new NullLiteral(pS, pE)}; + ConstructorDeclaration constructor = createConstructor(level, typeNode, true, false, source, explicitCall, null); + injectMethod(typeNode, constructor); + } + + private void generateCauseOnlyConstructor(EclipseNode typeNode, AccessLevel level, EclipseNode source) { + if (hasConstructor(typeNode, Throwable.class) != MemberExistsResult.NOT_EXISTS) return; + int pS = source.get().sourceStart, pE = source.get().sourceEnd; + long p = (long) pS << 32 | pE; + + ExplicitConstructorCall explicitCall = new ExplicitConstructorCall(ExplicitConstructorCall.This); + Expression causeNotNull = new EqualExpression(new SingleNameReference(CAUSE, p), new NullLiteral(pS, pE), OperatorIds.NOT_EQUAL); + MessageSend causeDotGetMessage = new MessageSend(); + causeDotGetMessage.sourceStart = pS; causeDotGetMessage.sourceEnd = pE; + causeDotGetMessage.receiver = new SingleNameReference(CAUSE, p); + causeDotGetMessage.selector = GET_MESSAGE; + Expression messageExpr = new ConditionalExpression(causeNotNull, causeDotGetMessage, new NullLiteral(pS, pE)); + explicitCall.arguments = new Expression[] {messageExpr, new SingleNameReference(CAUSE, p)}; + ConstructorDeclaration constructor = createConstructor(level, typeNode, false, true, source, explicitCall, null); + injectMethod(typeNode, constructor); + } + + private void generateFullConstructor(EclipseNode typeNode, AccessLevel level, EclipseNode source) { + if (hasConstructor(typeNode, String.class, Throwable.class) != MemberExistsResult.NOT_EXISTS) return; + int pS = source.get().sourceStart, pE = source.get().sourceEnd; + long p = (long) pS << 32 | pE; + + ExplicitConstructorCall explicitCall = new ExplicitConstructorCall(ExplicitConstructorCall.Super); + explicitCall.arguments = new Expression[] {new SingleNameReference(MESSAGE, p)}; + Expression causeNotNull = new EqualExpression(new SingleNameReference(CAUSE, p), new NullLiteral(pS, pE), OperatorIds.NOT_EQUAL); + MessageSend causeDotInitCause = new MessageSend(); + causeDotInitCause.sourceStart = pS; causeDotInitCause.sourceEnd = pE; + causeDotInitCause.receiver = new SuperReference(pS, pE); + causeDotInitCause.selector = INIT_CAUSE; + causeDotInitCause.arguments = new Expression[] {new SingleNameReference(CAUSE, p)}; + IfStatement ifs = new IfStatement(causeNotNull, causeDotInitCause, pS, pE); + ConstructorDeclaration constructor = createConstructor(level, typeNode, true, true, source, explicitCall, ifs); + injectMethod(typeNode, constructor); + } + + /** + * Checks if a constructor with the provided parameters exists under the type node. + */ + public static MemberExistsResult hasConstructor(EclipseNode node, Class<?>... paramTypes) { + 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) != 0) continue; + if (!paramsMatch(node, def.arguments, paramTypes)) continue; + return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; + } + } + } + + return MemberExistsResult.NOT_EXISTS; + } + + private static boolean paramsMatch(EclipseNode node, Argument[] a, Class<?>[] b) { + if (a == null) return b == null || b.length == 0; + if (b == null) return a.length == 0; + if (a.length != b.length) return false; + + for (int i = 0; i < a.length; i++) { + if (!typeMatches(b[i], node, a[i].type)) return false; + } + return true; + } + + private static final char[][] JAVA_BEANS_CONSTRUCTORPROPERTIES = new char[][] { "java".toCharArray(), "beans".toCharArray(), "ConstructorProperties".toCharArray() }; + private static final char[] MESSAGE = "message".toCharArray(), CAUSE = "cause".toCharArray(), GET_MESSAGE = "getMessage".toCharArray(), INIT_CAUSE = "initCause".toCharArray(); + + public static Annotation[] createConstructorProperties(ASTNode source, boolean msgParam, boolean causeParam) { + if (!msgParam && !causeParam) return null; + + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long) pS << 32 | pE; + long[] poss = new long[3]; + Arrays.fill(poss, p); + + QualifiedTypeReference constructorPropertiesType = new QualifiedTypeReference(JAVA_BEANS_CONSTRUCTORPROPERTIES, poss); + setGeneratedBy(constructorPropertiesType, source); + SingleMemberAnnotation ann = new SingleMemberAnnotation(constructorPropertiesType, pS); + ann.declarationSourceEnd = pE; + + ArrayInitializer fieldNames = new ArrayInitializer(); + fieldNames.sourceStart = pS; + fieldNames.sourceEnd = pE; + fieldNames.expressions = new Expression[(msgParam && causeParam) ? 2 : 1]; + + int ctr = 0; + if (msgParam) { + fieldNames.expressions[ctr] = new StringLiteral(MESSAGE, pS, pE, 0); + setGeneratedBy(fieldNames.expressions[ctr], source); + ctr++; + } + if (causeParam) { + fieldNames.expressions[ctr] = new StringLiteral(CAUSE, pS, pE, 0); + setGeneratedBy(fieldNames.expressions[ctr], source); + ctr++; + } + + ann.memberValue = fieldNames; + setGeneratedBy(ann, source); + setGeneratedBy(ann.memberValue, source); + return new Annotation[] { ann }; + } + + @SuppressWarnings("deprecation") public static ConstructorDeclaration createConstructor(AccessLevel level, EclipseNode typeNode, boolean msgParam, boolean causeParam, EclipseNode sourceNode, ExplicitConstructorCall explicitCall, Statement extra) { + ASTNode source = sourceNode.get(); + TypeDeclaration typeDeclaration = ((TypeDeclaration) typeNode.get()); + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long) pS << 32 | pE; + + boolean addConstructorProperties; + if ((!msgParam && !causeParam) || isLocalType(typeNode)) { + addConstructorProperties = false; + } else { + Boolean v = typeNode.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_ADD_CONSTRUCTOR_PROPERTIES); + addConstructorProperties = v != null ? v.booleanValue() : + Boolean.FALSE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_SUPPRESS_CONSTRUCTOR_PROPERTIES)); + } + + ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) typeNode.top().get()).compilationResult); + + constructor.modifiers = toEclipseModifier(level); + constructor.selector = typeDeclaration.name; + constructor.thrownExceptions = null; + constructor.typeParameters = null; + constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; + constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = pS; + constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = pE; + constructor.arguments = null; + + List<Argument> params = new ArrayList<Argument>(); + + if (msgParam) { + TypeReference typeRef = new QualifiedTypeReference(TypeConstants.JAVA_LANG_STRING, new long[] {p, p, p}); + Argument parameter = new Argument(MESSAGE, p, typeRef, Modifier.FINAL); + params.add(parameter); + } + if (causeParam) { + TypeReference typeRef = new QualifiedTypeReference(TypeConstants.JAVA_LANG_THROWABLE, new long[] {p, p, p}); + Argument parameter = new Argument(CAUSE, p, typeRef, Modifier.FINAL); + params.add(parameter); + } + + explicitCall.sourceStart = pS; + explicitCall.sourceEnd = pE; + constructor.constructorCall = explicitCall; + constructor.statements = extra != null ? new Statement[] {extra} : null; + constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[0]); + + Annotation[] constructorProperties = null; + if (addConstructorProperties) constructorProperties = createConstructorProperties(source, msgParam, causeParam); + constructor.annotations = copyAnnotations(source, constructorProperties); + constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope); + return constructor; + } + + public static boolean isLocalType(EclipseNode type) { + Kind kind = type.up().getKind(); + if (kind == Kind.COMPILATION_UNIT) return false; + if (kind == Kind.TYPE) return isLocalType(type.up()); + return true; + } +} diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 8fdfd315..4d5d2448 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2020 The Project Lombok Authors. + * Copyright (C) 2013-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 @@ -50,6 +50,7 @@ import org.eclipse.jdt.internal.compiler.ast.FalseLiteral; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldReference; import org.eclipse.jdt.internal.compiler.ast.IfStatement; +import org.eclipse.jdt.internal.compiler.ast.Initializer; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; @@ -74,7 +75,6 @@ import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.mangosdk.spi.ProviderFor; import lombok.AccessLevel; import lombok.Builder; @@ -100,8 +100,9 @@ import lombok.eclipse.handlers.HandleBuilder.BuilderFieldData; import lombok.eclipse.handlers.HandleBuilder.BuilderJob; import lombok.experimental.NonFinal; import lombok.experimental.SuperBuilder; +import lombok.spi.Provides; -@ProviderFor(EclipseAnnotationHandler.class) +@Provides @HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes. public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { private static final char[] SELF_METHOD_NAME = "self".toCharArray(); @@ -123,7 +124,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { if (builderMethodName == null) builderMethodName = "builder"; if (buildMethodName == null) buildMethodName = "build"; - builderClassName = fixBuilderClassName(node, ""); + builderClassName = getBuilderClassNameTemplate(node, null); } EclipseNode builderAbstractType; @@ -179,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(); @@ -272,8 +274,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { }; if (extendsClause instanceof QualifiedTypeReference) { QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference)extendsClause; - String superclassClassName = String.valueOf(qualifiedTypeReference.getLastToken()); - String superclassBuilderClassName = job.replaceBuilderClassName(superclassClassName); + char[] superclassClassName = qualifiedTypeReference.getLastToken(); + String builderClassNameTemplate = BuilderJob.getBuilderClassNameTemplate(annotationNode, null); + String superclassBuilderClassName = job.replaceBuilderClassName(superclassClassName, builderClassNameTemplate); char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1); tokens[tokens.length-1] = superclassBuilderClassName.toCharArray(); @@ -289,10 +292,11 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss); } else if (extendsClause != null) { - String superClass = String.valueOf(extendsClause.getTypeName()[0]); - String superclassBuilderClassName = superClass + "Builder"; + char[] superclassClassName = extendsClause.getTypeName()[0]; + String builderClassNameTemplate = BuilderJob.getBuilderClassNameTemplate(annotationNode, null); + String superclassBuilderClassName = job.replaceBuilderClassName(superclassClassName, builderClassNameTemplate); - char[][] tokens = new char[][] {superClass.toCharArray(), superclassBuilderClassName.toCharArray()}; + char[][] tokens = new char[][] {superclassClassName, superclassBuilderClassName.toCharArray()}; long[] poss = new long[tokens.length]; Arrays.fill(poss, job.getPos()); @@ -606,6 +610,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } constructor.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]); + if (job.checkerFramework.generateSideEffectFree()) { + constructor.annotations = new Annotation[] {generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE)}; + } constructor.traverse(new SetGeneratedByVisitor(job.source), typeDeclaration.scope); @@ -635,6 +642,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { AllocationExpression invoke = new AllocationExpression(); invoke.type = namePlusTypeParamsToTypeReference(job.parentType, job.builderImplClassNameArr, false, job.typeParams, p); out.statements = new Statement[] {new ReturnStatement(invoke, pS, pE)}; + if (job.checkerFramework.generateSideEffectFree()) { + out.annotations = new Annotation[] {generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE)}; + } createRelevantNonNullAnnotation(job.parentType, out); out.traverse(new SetGeneratedByVisitor(job.source), ((TypeDeclaration) job.parentType.get()).scope); @@ -673,6 +683,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { invokeFillMethod.selector = FILL_VALUES_METHOD_NAME; invokeFillMethod.arguments = new Expression[] {new ThisReference(0, 0)}; out.statements = new Statement[] {new ReturnStatement(invokeFillMethod, pS, pE)}; + if (job.checkerFramework.generateSideEffectFree()) { + out.annotations = new Annotation[] {generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE)}; + } createRelevantNonNullAnnotation(job.parentType, out); out.traverse(new SetGeneratedByVisitor(job.source), ((TypeDeclaration) job.parentType.get()).scope); @@ -807,9 +820,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { ms.arguments = tgt; } else { Expression ifNull = new EqualExpression(tgt[0], new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL); - MessageSend emptyCollection = new MessageSend(); - emptyCollection.receiver = generateQualifiedNameRef(source, bfd.singularData.getSingularizer().getEmptyMakerReceiver(bfd.singularData.getTargetFqn())); - emptyCollection.selector = bfd.singularData.getSingularizer().getEmptyMakerSelector(bfd.singularData.getTargetFqn()); + MessageSend emptyCollection = bfd.singularData.getSingularizer().getEmptyExpression(bfd.singularData.getTargetFqn(), bfd.singularData, type, source); ms.arguments = new Expression[] {new ConditionalExpression(ifNull, emptyCollection, tgt[1])}; } ms.receiver = new SingleNameReference(BUILDER_VARIABLE_NAME, 0); @@ -1093,6 +1104,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { // 3. Add used type names. if (td.fields != null) { for (FieldDeclaration field : td.fields) { + if (field instanceof Initializer) continue; char[][] typeName = field.type.getTypeName(); if (typeName.length >= 1) // Add the first token, because only that can collide. usedNames.add(String.valueOf(typeName[0])); @@ -1195,7 +1207,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { if ((def.bits & ASTNode.IsDefaultConstructor) != 0) continue; if (!def.isConstructor()) continue; if (isTolerate(type, def)) continue; - if (def.arguments.length != 1) continue; + if (def.arguments == null || def.arguments.length != 1) continue; // Cannot use typeMatches() here, because the parameter could be fully-qualified, partially-qualified, or not qualified. // A string-compare of the last part should work. If it's a false-positive, users could still @Tolerate it. diff --git a/src/core/lombok/eclipse/handlers/HandleSynchronized.java b/src/core/lombok/eclipse/handlers/HandleSynchronized.java index 08d00d91..18d1e7b7 100644 --- a/src/core/lombok/eclipse/handlers/HandleSynchronized.java +++ b/src/core/lombok/eclipse/handlers/HandleSynchronized.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 @@ -36,6 +36,7 @@ import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression; @@ -51,12 +52,11 @@ import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement; import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.mangosdk.spi.ProviderFor; /** * Handles the {@code lombok.Synchronized} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) +@Provides @DeferUntilPostDiet @HandlerPriority(value = 1024) // 2^10; @NonNull must have run first, so that we wrap around the statements generated by it. public class HandleSynchronized extends EclipseAnnotationHandler<Synchronized> { @@ -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 a6bcb24f..171402b3 100644 --- a/src/core/lombok/eclipse/handlers/HandleToString.java +++ b/src/core/lombok/eclipse/handlers/HandleToString.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 @@ -50,9 +50,7 @@ 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; import lombok.AccessLevel; import lombok.ConfigurationKeys; @@ -67,11 +65,12 @@ import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.spi.Provides; /** * Handles the {@code ToString} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) +@Provides public class HandleToString extends EclipseAnnotationHandler<ToString> { public void handle(AnnotationValues<ToString> annotation, Annotation ast, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.TO_STRING_FLAG_USAGE, "@ToString"); @@ -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; } @@ -169,12 +161,12 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> { String typeName = getTypeName(type); boolean isEnum = type.isEnumType(); - + char[] suffix = ")".toCharArray(); String infixS = ", "; char[] infix = infixS.toCharArray(); int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long)pS << 32 | pE; + long p = (long) pS << 32 | pE; final int PLUS = OperatorIds.PLUS; String prefix; diff --git a/src/core/lombok/eclipse/handlers/HandleUtilityClass.java b/src/core/lombok/eclipse/handlers/HandleUtilityClass.java index 2349f839..9a18b20b 100644 --- a/src/core/lombok/eclipse/handlers/HandleUtilityClass.java +++ b/src/core/lombok/eclipse/handlers/HandleUtilityClass.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -25,8 +25,6 @@ import static lombok.core.handlers.HandlerUtil.*; import static lombok.eclipse.Eclipse.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; -import java.util.Arrays; - import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; @@ -45,7 +43,6 @@ import org.eclipse.jdt.internal.compiler.ast.ThrowStatement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.mangosdk.spi.ProviderFor; import lombok.ConfigurationKeys; import lombok.core.AnnotationValues; @@ -54,12 +51,13 @@ import lombok.core.AST.Kind; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.experimental.UtilityClass; +import lombok.spi.Provides; /** * Handles the {@code lombok.experimental.UtilityClass} annotation for eclipse. */ +@Provides @HandlerPriority(-4096) //-2^12; to ensure @FieldDefaults picks up on the 'static' we set here. -@ProviderFor(EclipseAnnotationHandler.class) public class HandleUtilityClass extends EclipseAnnotationHandler<UtilityClass> { @Override public void handle(AnnotationValues<UtilityClass> annotation, Annotation ast, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.UTILITY_CLASS_FLAG_USAGE, "@UtilityClass"); @@ -70,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; } @@ -158,37 +151,28 @@ public class HandleUtilityClass extends EclipseAnnotationHandler<UtilityClass> { ASTNode source = sourceNode.get(); TypeDeclaration typeDeclaration = ((TypeDeclaration) typeNode.get()); - long p = (long) source.sourceStart << 32 | source.sourceEnd; ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) typeNode.top().get()).compilationResult); constructor.modifiers = ClassFileConstants.AccPrivate; constructor.selector = typeDeclaration.name; constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); - constructor.constructorCall.sourceStart = source.sourceStart; - constructor.constructorCall.sourceEnd = source.sourceEnd; constructor.thrownExceptions = null; constructor.typeParameters = null; constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart; - constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd; constructor.arguments = null; - AllocationExpression exception = new AllocationExpression(); - setGeneratedBy(exception, source); long[] ps = new long[JAVA_LANG_UNSUPPORTED_OPERATION_EXCEPTION.length]; - Arrays.fill(ps, p); + AllocationExpression exception = new AllocationExpression(); exception.type = new QualifiedTypeReference(JAVA_LANG_UNSUPPORTED_OPERATION_EXCEPTION, ps); - setGeneratedBy(exception.type, source); exception.arguments = new Expression[] { - new StringLiteral(UNSUPPORTED_MESSAGE, source.sourceStart, source.sourceEnd, 0) + new StringLiteral(UNSUPPORTED_MESSAGE, 0, 0, 0) }; - setGeneratedBy(exception.arguments[0], source); - ThrowStatement throwStatement = new ThrowStatement(exception, source.sourceStart, source.sourceEnd); - setGeneratedBy(throwStatement, source); + ThrowStatement throwStatement = new ThrowStatement(exception, 0, 0); constructor.statements = new Statement[] {throwStatement}; + constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope); injectMethod(typeNode, constructor); } } diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java index 3742ac00..ac53e27e 100644 --- a/src/core/lombok/eclipse/handlers/HandleVal.java +++ b/src/core/lombok/eclipse/handlers/HandleVal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2018 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 @@ -31,6 +31,7 @@ import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseASTAdapter; import lombok.eclipse.EclipseASTVisitor; import lombok.eclipse.EclipseNode; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; @@ -39,12 +40,11 @@ import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; import org.eclipse.jdt.internal.compiler.ast.TypeReference; -import org.mangosdk.spi.ProviderFor; /* * This class just handles 3 basic error cases. The real meat of eclipse 'val' support is in {@code PatchVal} and {@code PatchValEclipse}. */ -@ProviderFor(EclipseASTVisitor.class) +@Provides(EclipseASTVisitor.class) @DeferUntilPostDiet @HandlerPriority(65536) // 2^16; resolution needs to work, so if the RHS expression is i.e. a call to a generated getter, we have to run after that getter has been generated. public class HandleVal extends EclipseASTAdapter { diff --git a/src/core/lombok/eclipse/handlers/HandleValue.java b/src/core/lombok/eclipse/handlers/HandleValue.java index 2e0338a8..7a73e5ed 100644 --- a/src/core/lombok/eclipse/handlers/HandleValue.java +++ b/src/core/lombok/eclipse/handlers/HandleValue.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -34,17 +34,17 @@ import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists; import lombok.experimental.NonFinal; +import lombok.spi.Provides; import lombok.Value; 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; /** * Handles the {@code lombok.Value} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) +@Provides @HandlerPriority(-512) //-2^9; to ensure @EqualsAndHashCode and such pick up on this handler making the class final and messing with the fields' access levels, run earlier. public class HandleValue extends EclipseAnnotationHandler<Value> { private HandleFieldDefaults handleFieldDefaults = new HandleFieldDefaults(); @@ -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/eclipse/handlers/HandleWith.java b/src/core/lombok/eclipse/handlers/HandleWith.java index dce193d8..bfad682b 100644 --- a/src/core/lombok/eclipse/handlers/HandleWith.java +++ b/src/core/lombok/eclipse/handlers/HandleWith.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2020 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -38,6 +38,7 @@ import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.AnnotationValues; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; @@ -57,9 +58,8 @@ 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.ExtraCompilerModifiers; -import org.mangosdk.spi.ProviderFor; -@ProviderFor(EclipseAnnotationHandler.class) +@Provides public class HandleWith extends EclipseAnnotationHandler<With> { public boolean generateWithForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelWith) { if (checkForTypeLevelWith) { diff --git a/src/core/lombok/eclipse/handlers/HandleWithBy.java b/src/core/lombok/eclipse/handlers/HandleWithBy.java index f56004f6..a8d13a84 100644 --- a/src/core/lombok/eclipse/handlers/HandleWithBy.java +++ b/src/core/lombok/eclipse/handlers/HandleWithBy.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Project Lombok Authors. + * Copyright (C) 2020-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 @@ -51,7 +51,6 @@ import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.mangosdk.spi.ProviderFor; import lombok.AccessLevel; import lombok.ConfigurationKeys; @@ -63,8 +62,9 @@ import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.experimental.WithBy; +import lombok.spi.Provides; -@ProviderFor(EclipseAnnotationHandler.class) +@Provides public class HandleWithBy extends EclipseAnnotationHandler<WithBy> { public boolean generateWithByForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelWithBy) { if (checkForTypeLevelWithBy) { diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaMapSingularizer.java index 5956c01b..088a4506 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaMapSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaMapSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -21,12 +21,11 @@ */ package lombok.eclipse.handlers.singulars; -import org.mangosdk.spi.ProviderFor; - import lombok.core.LombokImmutableList; import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; +import lombok.spi.Provides; -@ProviderFor(EclipseSingularizer.class) +@Provides(EclipseSingularizer.class) public class EclipseGuavaMapSingularizer extends EclipseGuavaSingularizer { // TODO cgcc.ImmutableMultimap, cgcc.ImmutableListMultimap, cgcc.ImmutableSetMultimap // TODO cgcc.ImmutableClassToInstanceMap diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSetListSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSetListSingularizer.java index 326a9179..1f3603da 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSetListSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSetListSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -21,12 +21,11 @@ */ package lombok.eclipse.handlers.singulars; -import org.mangosdk.spi.ProviderFor; - import lombok.core.LombokImmutableList; import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; +import lombok.spi.Provides; -@ProviderFor(EclipseSingularizer.class) +@Provides(EclipseSingularizer.class) public class EclipseGuavaSetListSingularizer extends EclipseGuavaSingularizer { // TODO com.google.common.collect.ImmutableRangeSet // TODO com.google.common.collect.ImmutableMultiset and com.google.common.collect.ImmutableSortedMultiset diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java index 395d2e59..7dcf18c9 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -279,7 +279,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { protected abstract String getAddMethodName(); protected abstract String getAddAllTypeName(); - protected int getTypeArgumentsCount() { + @Override protected int getTypeArgumentsCount() { return getArgumentSuffixes().size(); } } diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaTableSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaTableSingularizer.java index 4d25811b..ee92ad5a 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaTableSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaTableSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -21,12 +21,11 @@ */ package lombok.eclipse.handlers.singulars; -import org.mangosdk.spi.ProviderFor; - import lombok.core.LombokImmutableList; import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; +import lombok.spi.Provides; -@ProviderFor(EclipseSingularizer.class) +@Provides(EclipseSingularizer.class) public class EclipseGuavaTableSingularizer extends EclipseGuavaSingularizer { private static final LombokImmutableList<String> SUFFIXES = LombokImmutableList.of("rowKey", "columnKey", "value"); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java index deab4530..882b7adc 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -156,7 +156,7 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToBuilderSingularSetterAnnotations(data.getAnnotation().up())); md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); - + if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md); data.setGeneratedByRecursive(md); HandleNonNull.INSTANCE.fix(injectMethod(builderType, md)); @@ -194,9 +194,13 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource()); Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up())); md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class); - + if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md); data.setGeneratedByRecursive(md); injectMethod(builderType, md); } + + @Override protected int getTypeArgumentsCount() { + return 1; + } } diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSingularizer.java index bf50aef6..0d0f3130 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -31,6 +31,7 @@ import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Assignment; @@ -45,10 +46,8 @@ import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.SwitchStatement; import org.eclipse.jdt.internal.compiler.ast.TypeReference; -import org.mangosdk.spi.ProviderFor; - -@ProviderFor(EclipseSingularizer.class) +@Provides(EclipseSingularizer.class) public class EclipseJavaUtilListSingularizer extends EclipseJavaUtilListSetSingularizer { @Override public LombokImmutableList<String> getSupportedTypes() { return LombokImmutableList.of("java.util.List", "java.util.Collection", "java.lang.Iterable"); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java index 1a40369d..a766612f 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -50,7 +50,6 @@ import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.mangosdk.spi.ProviderFor; import lombok.AccessLevel; import lombok.core.LombokImmutableList; @@ -62,8 +61,9 @@ import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; import lombok.eclipse.handlers.EclipseSingularsRecipes.StatementMaker; import lombok.eclipse.handlers.EclipseSingularsRecipes.TypeReferenceMaker; import lombok.eclipse.handlers.HandleNonNull; +import lombok.spi.Provides; -@ProviderFor(EclipseSingularizer.class) +@Provides(EclipseSingularizer.class) public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer { @Override public LombokImmutableList<String> getSupportedTypes() { return LombokImmutableList.of("java.util.Map", "java.util.SortedMap", "java.util.NavigableMap"); @@ -349,4 +349,8 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, true, true, false, true, "TreeMap", builderVariable)); } } + + @Override protected int getTypeArgumentsCount() { + return 2; + } } diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSetSingularizer.java index 2076ec7d..a432f3fe 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSetSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSetSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -27,11 +27,11 @@ import lombok.core.LombokImmutableList; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; +import lombok.spi.Provides; import org.eclipse.jdt.internal.compiler.ast.Statement; -import org.mangosdk.spi.ProviderFor; -@ProviderFor(EclipseSingularizer.class) +@Provides(EclipseSingularizer.class) public class EclipseJavaUtilSetSingularizer extends EclipseJavaUtilListSetSingularizer { @Override public LombokImmutableList<String> getSupportedTypes() { return LombokImmutableList.of("java.util.Set", "java.util.SortedSet", "java.util.NavigableSet"); diff --git a/src/core/lombok/experimental/StandardException.java b/src/core/lombok/experimental/StandardException.java new file mode 100644 index 00000000..b04ac2ee --- /dev/null +++ b/src/core/lombok/experimental/StandardException.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.experimental; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import lombok.AccessLevel; + +/** + * Put on any class that extends some {@code java.lang.Throwable} type to add the 4 common exception constructors. + * + * Specifically, all 4 constructors derived from the combinatorial explosion of {@code String message} and {@code Throwable cause}. + * You may write any or all of these 4 constructors by hand; lombok will only generate the missing ones. + * <p> + * All but the full {@code (String message, Throwable cause)} constructor are implemented as a {@code this(msg, cause)} call; it is therefore + * possibly to write code to run on construction by writing just the {@code (String message, Throwable cause)} constructor. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.SOURCE) +public @interface StandardException { + /** + * Sets the access level of the generated constuctors. By default, generated constructors are {@code public}. + * Note: This does nothing if you write your own constructors (we won't change their access levels). + * + * @return The constructors will be generated with this access modifier. + */ + AccessLevel access() default lombok.AccessLevel.PUBLIC; +} diff --git a/src/core/lombok/javac/CompilerMessageSuppressor.java b/src/core/lombok/javac/CompilerMessageSuppressor.java index 02dc6c26..7d7b81e6 100644 --- a/src/core/lombok/javac/CompilerMessageSuppressor.java +++ b/src/core/lombok/javac/CompilerMessageSuppressor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 The Project Lombok Authors. + * Copyright (C) 2011-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 @@ -226,7 +226,7 @@ public final class CompilerMessageSuppressor { ListBuffer<Object> newDeferredDiagnostics = new ListBuffer<Object>(); for (Object diag_ : deferredDiagnostics) { if (!(diag_ instanceof JCDiagnostic)) { - newDeferredDiagnostics.add(diag_); + newDeferredDiagnostics.append(diag_); continue; } JCDiagnostic diag = (JCDiagnostic) diag_; @@ -234,7 +234,7 @@ public final class CompilerMessageSuppressor { if (here >= startPos && here < endPos && diag.getSource() == sourcefile) { // We eliminate it } else { - newDeferredDiagnostics.add(diag); + newDeferredDiagnostics.append(diag); } } field.set(receiver, newDeferredDiagnostics); diff --git a/src/core/lombok/javac/JavacAugments.java b/src/core/lombok/javac/JavacAugments.java index bc23131b..e5d1fc43 100644 --- a/src/core/lombok/javac/JavacAugments.java +++ b/src/core/lombok/javac/JavacAugments.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Project Lombok Authors. + * Copyright (C) 2014-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 @@ -24,6 +24,7 @@ package lombok.javac; import lombok.core.FieldAugment; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCImport; public final class JavacAugments { private JavacAugments() { @@ -32,4 +33,5 @@ public final class JavacAugments { public static final FieldAugment<JCTree, Boolean> JCTree_handled = FieldAugment.augment(JCTree.class, boolean.class, "lombok$handled"); public static final FieldAugment<JCTree, JCTree> JCTree_generatedNode = FieldAugment.circularSafeAugment(JCTree.class, JCTree.class, "lombok$generatedNode"); + public static final FieldAugment<JCImport, Boolean> JCImport_deletable = FieldAugment.circularSafeAugment(JCImport.class, Boolean.class, "lombok$deletable"); } 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/JavacResolution.java b/src/core/lombok/javac/JavacResolution.java index 63ca69dd..e96079e0 100644 --- a/src/core/lombok/javac/JavacResolution.java +++ b/src/core/lombok/javac/JavacResolution.java @@ -71,6 +71,16 @@ public class JavacResolution { private final Attr attr; private final CompilerMessageSuppressor messageSuppressor; + private static final Method isLocal; + + static { + Method local = Permit.permissiveGetMethod(TypeSymbol.class, "isLocal"); + if (local == null) { + local = Permit.permissiveGetMethod(TypeSymbol.class, "isDirectlyOrIndirectlyLocal"); + } + isLocal = local; + } + public JavacResolution(Context context) { attr = Attr.instance(context); messageSuppressor = new CompilerMessageSuppressor(context); @@ -352,6 +362,15 @@ public class JavacResolution { return a.compareTo(b); } + private static boolean isLocalType(TypeSymbol symbol) { + try { + return (Boolean) Permit.invoke(isLocal, symbol); + } + catch (Exception e) { + return false; + } + } + private static JCExpression typeToJCTree0(Type type, JavacAST ast, boolean allowCompound, boolean allowVoid, boolean allowCapture) throws TypeNotConvertibleException { // NB: There's such a thing as maker.Type(type), but this doesn't work very well; it screws up anonymous classes, captures, and adds an extra prefix dot for some reason too. // -- so we write our own take on that here. @@ -450,7 +469,7 @@ public class JavacResolution { } String qName; - if (symbol.isLocal()) { + if (isLocalType(symbol)) { qName = symbol.getSimpleName().toString(); } else if (symbol.type != null && symbol.type.getEnclosingType() != null && typeTag(symbol.type.getEnclosingType()).equals(typeTag("CLASS"))) { replacement = typeToJCTree0(type.getEnclosingType(), ast, false, false, false); diff --git a/src/core/lombok/javac/apt/InterceptingJavaFileObject.java b/src/core/lombok/javac/apt/InterceptingJavaFileObject.java index 403b5672..75cf0713 100644 --- a/src/core/lombok/javac/apt/InterceptingJavaFileObject.java +++ b/src/core/lombok/javac/apt/InterceptingJavaFileObject.java @@ -26,7 +26,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.nio.charset.CharsetDecoder; @@ -35,7 +34,6 @@ import javax.lang.model.element.Modifier; import javax.lang.model.element.NestingKind; import javax.tools.JavaFileObject; -import lombok.Lombok; import lombok.core.DiagnosticsReceiver; import lombok.core.PostCompiler; import lombok.permit.Permit; diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index 6e5e603b..6552f15b 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2019 The Project Lombok Authors. + * Copyright (C) 2009-2020 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -63,6 +63,8 @@ import lombok.core.CleanupRegistry; import lombok.core.DiagnosticsReceiver; import lombok.javac.JavacTransformer; import lombok.permit.Permit; +import lombok.permit.dummy.Parent; +import sun.misc.Unsafe; /** * This Annotation Processor is the standard injection mechanism for lombok-enabling the javac compiler. @@ -430,6 +432,7 @@ public class LombokProcessor extends AbstractProcessor { * gradle incremental compilation, the delegate ProcessingEnvironment of the gradle wrapper is returned. */ public JavacProcessingEnvironment getJavacProcessingEnvironment(Object procEnv) { + addOpensForLombok(); if (procEnv instanceof JavacProcessingEnvironment) return (JavacProcessingEnvironment) procEnv; // try to find a "delegate" field in the object, and use this to try to obtain a JavacProcessingEnvironment @@ -446,7 +449,91 @@ public class LombokProcessor extends AbstractProcessor { "Can't get the delegate of the gradle IncrementalProcessingEnvironment. Lombok won't work."); return null; } - + + private static Object getOwnModule() { + try { + Method m = Permit.getMethod(Class.class, "getModule"); + return m.invoke(LombokProcessor.class); + } catch (Exception e) { + return null; + } + } + + private static Object getJdkCompilerModule() { + /* call public api: ModuleLayer.boot().findModule("jdk.compiler").get(); + but use reflection because we don't want this code to crash on jdk1.7 and below. + In that case, none of this stuff was needed in the first place, so we just exit via + the catch block and do nothing. + */ + + try { + Class<?> cModuleLayer = Class.forName("java.lang.ModuleLayer"); + Method mBoot = cModuleLayer.getDeclaredMethod("boot"); + Object bootLayer = mBoot.invoke(null); + Class<?> cOptional = Class.forName("java.util.Optional"); + Method mFindModule = cModuleLayer.getDeclaredMethod("findModule", String.class); + Object oCompilerO = mFindModule.invoke(bootLayer, "jdk.compiler"); + return cOptional.getDeclaredMethod("get").invoke(oCompilerO); + } catch (Exception e) { + return null; + } + } + + /** Useful from jdk9 and up; required from jdk16 and up. This code is supposed to gracefully do nothing on jdk8 and below, as this operation isn't needed there. */ + public static void addOpensForLombok() { + Class<?> cModule; + try { + cModule = Class.forName("java.lang.Module"); + } catch (ClassNotFoundException e) { + return; //jdk8-; this is not needed. + } + + Unsafe unsafe = getUnsafe(); + Object jdkCompilerModule = getJdkCompilerModule(); + Object ownModule = getOwnModule(); + String[] allPkgs = { + "com.sun.tools.javac.code", + "com.sun.tools.javac.comp", + "com.sun.tools.javac.file", + "com.sun.tools.javac.main", + "com.sun.tools.javac.model", + "com.sun.tools.javac.parser", + "com.sun.tools.javac.processing", + "com.sun.tools.javac.tree", + "com.sun.tools.javac.util", + "com.sun.tools.javac.jvm", + }; + + try { + Method m = cModule.getDeclaredMethod("implAddOpens", String.class, cModule); + long firstFieldOffset = getFirstFieldOffset(unsafe); + unsafe.putBooleanVolatile(m, firstFieldOffset, true); + for (String p : allPkgs) m.invoke(jdkCompilerModule, p, ownModule); + } catch (Exception ignore) {} + } + + private static long getFirstFieldOffset(Unsafe unsafe) { + try { + return unsafe.objectFieldOffset(Parent.class.getDeclaredField("first")); + } catch (NoSuchFieldException e) { + // can't happen. + throw new RuntimeException(e); + } catch (SecurityException e) { + // can't happen + throw new RuntimeException(e); + } + } + + private static Unsafe getUnsafe() { + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(null); + } catch (Exception e) { + return null; + } + } + /** * This class returns the given filer as a JavacFiler. In case the filer is no * JavacFiler (e.g. the Gradle IncrementalFiler), its "delegate" field is used to get the JavacFiler diff --git a/src/core/lombok/javac/handlers/HandleAccessors.java b/src/core/lombok/javac/handlers/HandleAccessors.java index 46fe1cd2..60466d78 100644 --- a/src/core/lombok/javac/handlers/HandleAccessors.java +++ b/src/core/lombok/javac/handlers/HandleAccessors.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -24,8 +24,6 @@ package lombok.javac.handlers; import static lombok.core.handlers.HandlerUtil.*; import static lombok.javac.handlers.JavacHandlerUtil.*; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.tree.JCTree.JCAnnotation; import lombok.ConfigurationKeys; @@ -34,8 +32,9 @@ import lombok.core.HandlerPriority; import lombok.experimental.Accessors; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.spi.Provides; -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(65536) public class HandleAccessors extends JavacAnnotationHandler<Accessors> { @Override public void handle(AnnotationValues<Accessors> annotation, JCAnnotation ast, JavacNode annotationNode) { diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index e867fd63..c23dc14c 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2020 The Project Lombok Authors. + * Copyright (C) 2013-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 @@ -30,8 +30,6 @@ import java.util.ArrayList; import javax.lang.model.element.Modifier; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -81,8 +79,9 @@ import lombok.javac.handlers.JavacHandlerUtil.CopyJavadoc; import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; import lombok.javac.handlers.JavacSingularsRecipes.SingularData; +import lombok.spi.Provides; -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes. public class HandleBuilder extends JavacAnnotationHandler<Builder> { private HandleConstructor handleConstructor = new HandleConstructor(); @@ -131,7 +130,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { builderMethodName = ann.builderMethodName(); buildMethodName = ann.buildMethodName(); - builderClassName = fixBuilderClassName(node, ann.builderClassName()); + builderClassName = getBuilderClassNameTemplate(node, ann.builderClassName()); toBuilder = ann.toBuilder(); if (builderMethodName == null) builderMethodName = "builder"; @@ -139,7 +138,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { if (builderClassName == null) builderClassName = ""; } - static String fixBuilderClassName(JavacNode node, String override) { + static String getBuilderClassNameTemplate(JavacNode node, String override) { if (override != null && !override.isEmpty()) return override; override = node.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME); if (override != null && !override.isEmpty()) return override; @@ -147,8 +146,12 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } String replaceBuilderClassName(Name name) { - if (builderClassName.indexOf('*') == -1) return builderClassName; - return builderClassName.replace("*", name.toString()); + return replaceBuilderClassName(name.toString(), builderClassName); + } + + String replaceBuilderClassName(String name, String template) { + if (template.indexOf('*') == -1) return template; + return template.replace("*", name); } JCExpression createBuilderParentTypeReference() { @@ -193,6 +196,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; @@ -230,6 +235,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(); @@ -280,7 +290,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; @@ -388,7 +402,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; } @@ -608,10 +622,6 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { private JCMethodDecl generateToBuilderMethod(BuilderJob job, List<JCTypeParameter> typeParameters, String prefix) { // return new ThingieBuilder<A, B>().setA(this.a).setB(this.b); JavacTreeMaker maker = job.getTreeMaker(); - ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); - for (JCTypeParameter typeParam : typeParameters) { - typeArgs.append(maker.Ident(typeParam.name)); - } JCExpression call = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderClassName), !job.isStatic, job.builderTypeParams), List.<JCExpression>nil(), null); JCExpression invoke = call; @@ -804,13 +814,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { public JCMethodDecl generateBuilderMethod(BuilderJob job) { //String builderClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams, AccessLevel access) { //builderClassName, annotationNode, tdParent, typeParams, accessForOuters); - - JavacTreeMaker maker = job.getTreeMaker(); - ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); - for (JCTypeParameter typeParam : job.typeParams) { - typeArgs.append(maker.Ident(typeParam.name)); - } + JavacTreeMaker maker = job.getTreeMaker(); JCExpression call; if (job.isStatic) { @@ -876,7 +881,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { bfd.createdFields.add(field); } } - for (JCVariableDecl gen : generated) recursiveSetGeneratedBy(gen, job.sourceNode); + for (JCVariableDecl gen : generated) recursiveSetGeneratedBy(gen, job.sourceNode); } public void makePrefixedSetterMethodsForBuilder(BuilderJob job, BuilderFieldData bfd, String prefix) { diff --git a/src/core/lombok/javac/handlers/HandleBuilderDefault.java b/src/core/lombok/javac/handlers/HandleBuilderDefault.java index 54060233..8438057a 100644 --- a/src/core/lombok/javac/handlers/HandleBuilderDefault.java +++ b/src/core/lombok/javac/handlers/HandleBuilderDefault.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 The Project Lombok Authors. + * Copyright (C) 2017-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 @@ -23,8 +23,6 @@ package lombok.javac.handlers; import static lombok.javac.handlers.JavacHandlerUtil.*; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; @@ -36,8 +34,9 @@ import lombok.core.HandlerPriority; import lombok.experimental.SuperBuilder; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.spi.Provides; -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(-1025) //HandleBuilder's level, minus one. public class HandleBuilderDefault extends JavacAnnotationHandler<Builder.Default> { @Override public void handle(AnnotationValues<Builder.Default> annotation, JCAnnotation ast, JavacNode annotationNode) { diff --git a/src/core/lombok/javac/handlers/HandleBuilderDefaultRemove.java b/src/core/lombok/javac/handlers/HandleBuilderDefaultRemove.java index fc0738c3..d7bc28cb 100644 --- a/src/core/lombok/javac/handlers/HandleBuilderDefaultRemove.java +++ b/src/core/lombok/javac/handlers/HandleBuilderDefaultRemove.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Project Lombok Authors. + * Copyright (C) 2018-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 @@ -23,8 +23,6 @@ package lombok.javac.handlers; import static lombok.javac.handlers.JavacHandlerUtil.*; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.tree.JCTree.JCAnnotation; import lombok.Builder; @@ -34,9 +32,10 @@ import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.spi.Provides; -@ProviderFor(JavacAnnotationHandler.class) -@HandlerPriority(65536) +@Provides +@HandlerPriority(32768) @AlreadyHandledAnnotations public class HandleBuilderDefaultRemove extends JavacAnnotationHandler<Builder.Default> { @Override public void handle(AnnotationValues<Default> annotation, JCAnnotation ast, JavacNode annotationNode) { diff --git a/src/core/lombok/javac/handlers/HandleBuilderRemove.java b/src/core/lombok/javac/handlers/HandleBuilderRemove.java index 6e59b40f..a47ed6b0 100644 --- a/src/core/lombok/javac/handlers/HandleBuilderRemove.java +++ b/src/core/lombok/javac/handlers/HandleBuilderRemove.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Project Lombok Authors. + * Copyright (C) 2020-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 @@ -23,8 +23,6 @@ package lombok.javac.handlers; import static lombok.javac.handlers.JavacHandlerUtil.*; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.tree.JCTree.JCAnnotation; import lombok.Builder; @@ -33,9 +31,10 @@ import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.spi.Provides; -@ProviderFor(JavacAnnotationHandler.class) -@HandlerPriority(65536) +@Provides +@HandlerPriority(32768) @AlreadyHandledAnnotations public class HandleBuilderRemove extends JavacAnnotationHandler<Builder> { @Override public void handle(AnnotationValues<Builder> annotation, JCAnnotation ast, JavacNode annotationNode) { diff --git a/src/core/lombok/javac/handlers/HandleCleanup.java b/src/core/lombok/javac/handlers/HandleCleanup.java index 12c3b1e9..785ebf8a 100644 --- a/src/core/lombok/javac/handlers/HandleCleanup.java +++ b/src/core/lombok/javac/handlers/HandleCleanup.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 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,8 +32,7 @@ import lombok.delombok.LombokOptionsFactory; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -59,7 +58,7 @@ import com.sun.tools.javac.util.Name; /** * Handles the {@code lombok.Cleanup} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides public class HandleCleanup extends JavacAnnotationHandler<Cleanup> { @Override public void handle(AnnotationValues<Cleanup> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.CLEANUP_FLAG_USAGE, "@Cleanup"); diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index b582490b..dc70e2ce 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2019 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 @@ -25,8 +25,6 @@ import static lombok.core.handlers.HandlerUtil.*; import static lombok.javac.Javac.*; import static lombok.javac.handlers.JavacHandlerUtil.*; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -59,9 +57,10 @@ import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; +import lombok.spi.Provides; public class HandleConstructor { - @ProviderFor(JavacAnnotationHandler.class) + @Provides public static class HandleNoArgsConstructor extends JavacAnnotationHandler<NoArgsConstructor> { private static final String NAME = NoArgsConstructor.class.getSimpleName(); private HandleConstructor handleConstructor = new HandleConstructor(); @@ -83,7 +82,7 @@ public class HandleConstructor { } } - @ProviderFor(JavacAnnotationHandler.class) + @Provides public static class HandleRequiredArgsConstructor extends JavacAnnotationHandler<RequiredArgsConstructor> { private static final String NAME = RequiredArgsConstructor.class.getSimpleName(); private HandleConstructor handleConstructor = new HandleConstructor(); @@ -133,7 +132,7 @@ public class HandleConstructor { return fields.toList(); } - @ProviderFor(JavacAnnotationHandler.class) + @Provides public static class HandleAllArgsConstructor extends JavacAnnotationHandler<AllArgsConstructor> { private static final String NAME = AllArgsConstructor.class.getSimpleName(); private HandleConstructor handleConstructor = new HandleConstructor(); @@ -179,12 +178,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 15c9c9e7..06524aa8 100644 --- a/src/core/lombok/javac/handlers/HandleData.java +++ b/src/core/lombok/javac/handlers/HandleData.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 @@ -30,8 +30,7 @@ import lombok.core.AnnotationValues; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.handlers.HandleConstructor.SkipIfConstructorExists; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.util.List; @@ -39,7 +38,7 @@ import com.sun.tools.javac.util.List; /** * Handles the {@code lombok.Data} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides public class HandleData extends JavacAnnotationHandler<Data> { private HandleConstructor handleConstructor = new HandleConstructor(); private HandleGetter handleGetter = new HandleGetter(); @@ -52,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/HandleDelegate.java b/src/core/lombok/javac/handlers/HandleDelegate.java index 3e3891c9..4d72eea3 100644 --- a/src/core/lombok/javac/handlers/HandleDelegate.java +++ b/src/core/lombok/javac/handlers/HandleDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 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 @@ -43,8 +43,6 @@ import javax.lang.model.type.ExecutableType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.code.Attribute.Compound; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; @@ -82,8 +80,9 @@ import lombok.javac.JavacResolution.TypeNotConvertibleException; import lombok.javac.JavacTreeMaker; import lombok.javac.ResolutionResetNeeded; import lombok.permit.Permit; +import lombok.spi.Provides; -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(HandleDelegate.HANDLE_DELEGATE_PRIORITY) //2^16; to make sure that we also delegate generated methods. @ResolutionResetNeeded public class HandleDelegate extends JavacAnnotationHandler<Delegate> { diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index e76d701e..ffe882d8 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.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 @@ -30,8 +30,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -70,11 +68,12 @@ import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; +import lombok.spi.Provides; /** * Handles the {@code lombok.EqualsAndHashCode} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHashCode> { private static final String RESULT_NAME = "result"; private static final String PRIME_NAME = "PRIME"; @@ -96,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); } @@ -119,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; } @@ -141,30 +134,6 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas boolean isDirectDescendantOfObject = isDirectDescendantOfObject(typeNode); - if (isDirectDescendantOfObject && callSuper) { - source.addError("Generating equals/hashCode with a supercall to java.lang.Object is pointless."); - return; - } - - if (implicitCallSuper && !isDirectDescendantOfObject) { - CallSuperType cst = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_CALL_SUPER); - if (cst == null) cst = CallSuperType.WARN; - - switch (cst) { - default: - case WARN: - source.addWarning("Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type."); - callSuper = false; - break; - case SKIP: - callSuper = false; - break; - case CALL: - callSuper = true; - break; - } - } - boolean isFinal = (((JCClassDecl) typeNode.get()).mods.flags & Flags.FINAL) != 0; boolean needsCanEqual = !isFinal || !isDirectDescendantOfObject; MemberExistsResult equalsExists = methodExists("equals", typeNode, 1); @@ -193,6 +162,30 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas //fallthrough } + if (isDirectDescendantOfObject && callSuper) { + source.addError("Generating equals/hashCode with a supercall to java.lang.Object is pointless."); + return; + } + + if (implicitCallSuper && !isDirectDescendantOfObject) { + CallSuperType cst = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_CALL_SUPER); + if (cst == null) cst = CallSuperType.WARN; + + switch (cst) { + default: + case WARN: + source.addWarning("Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type."); + callSuper = false; + break; + case SKIP: + callSuper = false; + break; + case CALL: + callSuper = true; + break; + } + } + JCMethodDecl equalsMethod = createEquals(typeNode, members, callSuper, fieldAccess, needsCanEqual, source, onParam); injectMethod(typeNode, equalsMethod); diff --git a/src/core/lombok/javac/handlers/HandleExtensionMethod.java b/src/core/lombok/javac/handlers/HandleExtensionMethod.java index bda8c93a..dd565f72 100644 --- a/src/core/lombok/javac/handlers/HandleExtensionMethod.java +++ b/src/core/lombok/javac/handlers/HandleExtensionMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -39,8 +39,7 @@ import lombok.experimental.ExtensionMethod; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacResolution; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.source.tree.MethodInvocationTree; import com.sun.source.util.TreeScanner; @@ -65,7 +64,7 @@ import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; /** * Handles the {@link ExtensionMethod} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(66560) // 2^16 + 2^10; we must run AFTER HandleVal which is at 2^16 public class HandleExtensionMethod extends JavacAnnotationHandler<ExtensionMethod> { @Override @@ -152,8 +151,9 @@ public class HandleExtensionMethod extends JavacAnnotationHandler<ExtensionMetho @Override public Void visitMethodInvocation(final MethodInvocationTree tree, final Void p) { + super.visitMethodInvocation(tree, p); handleMethodCall((JCMethodInvocation) tree); - return super.visitMethodInvocation(tree, p); + return null; } private void handleMethodCall(final JCMethodInvocation methodCall) { diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java index aa381c0d..ebab67e3 100644 --- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2016 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -34,8 +34,7 @@ import lombok.experimental.PackagePrivate; import lombok.javac.JavacASTAdapter; import lombok.javac.JavacASTVisitor; import lombok.javac.JavacNode; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree; @@ -46,7 +45,7 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; /** * Handles the {@code lombok.FieldDefaults} annotation for javac. */ -@ProviderFor(JavacASTVisitor.class) +@Provides(JavacASTVisitor.class) @HandlerPriority(-2048) //-2^11; to ensure @Value picks up on messing with the fields' 'final' state, run earlier. public class HandleFieldDefaults extends JavacASTAdapter { public boolean generateFieldDefaultsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean makeFinal, boolean checkForTypeLevelFieldDefaults) { @@ -57,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/HandleFieldNameConstants.java b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java index f8bcfbfc..f3c879d5 100644 --- a/src/core/lombok/javac/handlers/HandleFieldNameConstants.java +++ b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2019 The Project Lombok Authors. + * Copyright (C) 2014-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 @@ -36,8 +36,7 @@ import lombok.experimental.FieldNameConstants; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree; @@ -53,7 +52,7 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; -@ProviderFor(JavacAnnotationHandler.class) +@Provides public class HandleFieldNameConstants extends JavacAnnotationHandler<FieldNameConstants> { private static final IdentifierName FIELDS = IdentifierName.valueOf("Fields"); diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index 4b2d01e1..7a7e41f9 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.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 @@ -43,15 +43,13 @@ import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.JavacTreeMaker.TypeTag; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; 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; @@ -70,8 +68,10 @@ import com.sun.tools.javac.util.Name; /** * Handles the {@code lombok.Getter} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@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 +80,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 +165,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; } @@ -279,9 +274,9 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { if (addSuppressWarningsUnchecked) { ListBuffer<JCExpression> suppressions = new ListBuffer<JCExpression>(); if (!Boolean.FALSE.equals(field.getAst().readConfiguration(ConfigurationKeys.ADD_SUPPRESSWARNINGS_ANNOTATIONS))) { - suppressions.add(treeMaker.Literal("all")); + suppressions.append(treeMaker.Literal("all")); } - suppressions.add(treeMaker.Literal("unchecked")); + suppressions.append(treeMaker.Literal("unchecked")); addAnnotation(decl.mods, field, source, "java.lang.SuppressWarnings", treeMaker.NewArray(null, List.<JCExpression>nil(), suppressions.toList())); } diff --git a/src/core/lombok/javac/handlers/HandleHelper.java b/src/core/lombok/javac/handlers/HandleHelper.java index bb92090d..35b0c4f2 100755 --- a/src/core/lombok/javac/handlers/HandleHelper.java +++ b/src/core/lombok/javac/handlers/HandleHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2016 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -29,8 +29,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.Iterator; -import org.mangosdk.spi.ProviderFor; - import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.TreeVisitor; import com.sun.source.util.TreeScanner; @@ -56,8 +54,9 @@ import lombok.experimental.Helper; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; +import lombok.spi.Provides; -@ProviderFor(JavacAnnotationHandler.class) +@Provides public class HandleHelper extends JavacAnnotationHandler<Helper> { private List<JCStatement> getStatementsFromJcNode(JCTree tree) { if (tree instanceof JCBlock) return ((JCBlock) tree).stats; diff --git a/src/core/lombok/javac/handlers/HandleJacksonized.java b/src/core/lombok/javac/handlers/HandleJacksonized.java index f9809865..3ee0eec4 100644 --- a/src/core/lombok/javac/handlers/HandleJacksonized.java +++ b/src/core/lombok/javac/handlers/HandleJacksonized.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Project Lombok Authors. + * Copyright (C) 2020-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 @@ -24,8 +24,6 @@ package lombok.javac.handlers; import static lombok.core.handlers.HandlerUtil.handleExperimentalFlagUsage; import static lombok.javac.handlers.JavacHandlerUtil.*; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -49,13 +47,14 @@ import lombok.extern.jackson.Jacksonized; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; +import lombok.spi.Provides; /** * This (javac) handler deals with {@code @Jacksonized} modifying the (already * generated) {@code @Builder} or {@code @SuperBuilder} to conform to Jackson's * needs for builders. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(-512) // Above Handle(Super)Builder's level (builders must be already generated). public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> { diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java index 7169d33e..47c4098f 100644 --- a/src/core/lombok/javac/handlers/HandleLog.java +++ b/src/core/lombok/javac/handlers/HandleLog.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2019 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 @@ -31,12 +31,12 @@ 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; import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -75,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."); @@ -119,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; } @@ -154,7 +166,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.apachecommons.CommonsLog} annotation for javac. */ - @ProviderFor(JavacAnnotationHandler.class) + @Provides public static class HandleCommonsLog extends JavacAnnotationHandler<lombok.extern.apachecommons.CommonsLog> { @Override public void handle(AnnotationValues<lombok.extern.apachecommons.CommonsLog> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_COMMONS_FLAG_USAGE, "@apachecommons.CommonsLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -165,7 +177,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.java.Log} annotation for javac. */ - @ProviderFor(JavacAnnotationHandler.class) + @Provides public static class HandleJulLog extends JavacAnnotationHandler<lombok.extern.java.Log> { @Override public void handle(AnnotationValues<lombok.extern.java.Log> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_JUL_FLAG_USAGE, "@java.Log", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -176,7 +188,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.log4j.Log4j} annotation for javac. */ - @ProviderFor(JavacAnnotationHandler.class) + @Provides public static class HandleLog4jLog extends JavacAnnotationHandler<lombok.extern.log4j.Log4j> { @Override public void handle(AnnotationValues<lombok.extern.log4j.Log4j> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_LOG4J_FLAG_USAGE, "@Log4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -187,7 +199,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.log4j.Log4j2} annotation for javac. */ - @ProviderFor(JavacAnnotationHandler.class) + @Provides public static class HandleLog4j2Log extends JavacAnnotationHandler<lombok.extern.log4j.Log4j2> { @Override public void handle(AnnotationValues<lombok.extern.log4j.Log4j2> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_LOG4J2_FLAG_USAGE, "@Log4j2", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -198,7 +210,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.slf4j.Slf4j} annotation for javac. */ - @ProviderFor(JavacAnnotationHandler.class) + @Provides public static class HandleSlf4jLog extends JavacAnnotationHandler<lombok.extern.slf4j.Slf4j> { @Override public void handle(AnnotationValues<lombok.extern.slf4j.Slf4j> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_SLF4J_FLAG_USAGE, "@Slf4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -209,7 +221,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.slf4j.XSlf4j} annotation for javac. */ - @ProviderFor(JavacAnnotationHandler.class) + @Provides public static class HandleXSlf4jLog extends JavacAnnotationHandler<lombok.extern.slf4j.XSlf4j> { @Override public void handle(AnnotationValues<lombok.extern.slf4j.XSlf4j> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_XSLF4J_FLAG_USAGE, "@XSlf4j", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -220,7 +232,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.jbosslog.JBossLog} annotation for javac. */ - @ProviderFor(JavacAnnotationHandler.class) + @Provides public static class HandleJBossLog extends JavacAnnotationHandler<lombok.extern.jbosslog.JBossLog> { @Override public void handle(AnnotationValues<lombok.extern.jbosslog.JBossLog> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_JBOSSLOG_FLAG_USAGE, "@JBossLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -231,7 +243,7 @@ public class HandleLog { /** * Handles the {@link lombok.extern.flogger.Flogger} annotation for javac. */ - @ProviderFor(JavacAnnotationHandler.class) + @Provides public static class HandleFloggerLog extends JavacAnnotationHandler<lombok.extern.flogger.Flogger> { @Override public void handle(AnnotationValues<lombok.extern.flogger.Flogger> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_FLOGGER_FLAG_USAGE, "@Flogger", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); @@ -242,7 +254,7 @@ public class HandleLog { /** * Handles the {@link lombok.CustomLog} annotation for javac. */ - @ProviderFor(JavacAnnotationHandler.class) + @Provides public static class HandleCustomLog extends JavacAnnotationHandler<lombok.CustomLog> { @Override public void handle(AnnotationValues<lombok.CustomLog> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.LOG_CUSTOM_FLAG_USAGE, "@CustomLog", ConfigurationKeys.LOG_ANY_FLAG_USAGE, "any @Log"); diff --git a/src/core/lombok/javac/handlers/HandleNonNull.java b/src/core/lombok/javac/handlers/HandleNonNull.java index 3dd7e328..786a7659 100644 --- a/src/core/lombok/javac/handlers/HandleNonNull.java +++ b/src/core/lombok/javac/handlers/HandleNonNull.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2019 The Project Lombok Authors. + * Copyright (C) 2013-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 @@ -27,13 +27,16 @@ import static lombok.javac.JavacTreeMaker.TreeTag.treeTag; import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; import static lombok.javac.handlers.JavacHandlerUtil.*; -import org.mangosdk.spi.ProviderFor; +import java.util.ArrayList; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCAssert; import com.sun.tools.javac.tree.JCTree.JCAssign; 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.JCFieldAccess; @@ -42,15 +45,19 @@ import com.sun.tools.javac.tree.JCTree.JCIf; import com.sun.tools.javac.tree.JCTree.JCLiteral; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.JCModifiers; import com.sun.tools.javac.tree.JCTree.JCParens; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCSynchronized; import com.sun.tools.javac.tree.JCTree.JCThrow; import com.sun.tools.javac.tree.JCTree.JCTry; +import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; +import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.NonNull; import lombok.core.AST.Kind; @@ -58,68 +65,102 @@ import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; +import lombok.spi.Provides; -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(value = 512) // 2^9; onParameter=@__(@NonNull) has to run first. public class HandleNonNull extends JavacAnnotationHandler<NonNull> { - @Override public void handle(AnnotationValues<NonNull> annotation, JCAnnotation ast, JavacNode annotationNode) { - handleFlagUsage(annotationNode, ConfigurationKeys.NON_NULL_FLAG_USAGE, "@NonNull"); + private JCMethodDecl createRecordArgslessConstructor(JavacNode typeNode, JavacNode source) { + JavacTreeMaker maker = typeNode.getTreeMaker(); - if (annotationNode.up().getKind() == Kind.FIELD) { - // This is meaningless unless the field is used to generate a method (@Setter, @RequiredArgsConstructor, etc), - // but in that case those handlers will take care of it. However, we DO check if the annotation is applied to - // a primitive, because those handlers trigger on any annotation named @NonNull and we only want the warning - // behaviour on _OUR_ 'lombok.NonNull'. - - try { - if (isPrimitive(((JCVariableDecl) annotationNode.up().get()).vartype)) { - annotationNode.addWarning("@NonNull is meaningless on a primitive."); + java.util.List<JCVariableDecl> fields = new ArrayList<JCVariableDecl>(); + for (JavacNode child : typeNode.down()) { + if (child.getKind() == Kind.FIELD) { + JCVariableDecl v = (JCVariableDecl) child.get(); + if ((v.mods.flags & RECORD) != 0) { + fields.add(v); } - } catch (Exception ignore) {} - - return; + } } - JCMethodDecl declaration; - JavacNode paramNode; + ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>(); - switch (annotationNode.up().getKind()) { - case ARGUMENT: - paramNode = annotationNode.up(); - break; - case TYPE_USE: - JavacNode typeNode = annotationNode.directUp(); - paramNode = typeNode.directUp(); - break; - default: - return; + for (int i = 0; i < fields.size(); i++) { + JCVariableDecl arg = fields.get(i); + JCModifiers mods = maker.Modifiers(GENERATED_MEMBER | Flags.PARAMETER, arg.mods.annotations); + params.append(maker.VarDef(mods, arg.name, arg.vartype, null)); } - if (paramNode.getKind() != Kind.ARGUMENT) return; - try { - declaration = (JCMethodDecl) paramNode.up().get(); - } catch (Exception e) { - return; + JCModifiers mods = maker.Modifiers(toJavacModifier(AccessLevel.PUBLIC) | COMPACT_RECORD_CONSTRUCTOR, List.<JCAnnotation>nil()); + JCBlock body = maker.Block(0L, List.<JCStatement>nil()); + JCMethodDecl constr = maker.MethodDef(mods, typeNode.toName("<init>"), null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(), body, null); + return recursiveSetGeneratedBy(constr, source); + } + + /** + * If the provided typeNode is a record, returns the compact constructor (there should only be one, but if the file is + * not semantically sound there might be more). If the only one in existence is the default auto-generated one, it is removed, + * a new explicit one is created, and that one is returned in a list. + * + * Otherwise, an empty list is returned. + */ + private List<JCMethodDecl> addCompactConstructorIfNeeded(JavacNode typeNode, JavacNode source) { + List<JCMethodDecl> answer = List.nil(); + + if (typeNode == null || !(typeNode.get() instanceof JCClassDecl)) return answer; + + JCClassDecl cDecl = (JCClassDecl) typeNode.get(); + if ((cDecl.mods.flags & RECORD) == 0) return answer; + + ListBuffer<JCTree> newDefs = new ListBuffer<JCTree>(); + boolean generateConstructor = false; + + for (JCTree def : cDecl.defs) { + boolean remove = false; + if (def instanceof JCMethodDecl) { + JCMethodDecl md = (JCMethodDecl) def; + if (md.name.contentEquals("<init>")) { + if ((md.mods.flags & Flags.GENERATEDCONSTR) != 0) { + remove = true; + generateConstructor = true; + } else { + if (!isTolerate(typeNode, md)) { + if ((md.mods.flags & COMPACT_RECORD_CONSTRUCTOR) != 0) { + generateConstructor = false; + answer = answer.prepend(md); + } + } + } + } + } + if (!remove) newDefs.append(def); } - if (declaration.body == null) { - // This used to be a warning, but as @NonNull also has a documentary purpose, better to not warn about this. Since 1.16.7 - return; + if (generateConstructor) { + cDecl.defs = newDefs.toList(); + JCMethodDecl ctr = createRecordArgslessConstructor(typeNode, source); + injectMethod(typeNode, ctr); + answer = answer.prepend(ctr); } + return answer; + } + + private void addNullCheckIfNeeded(JCMethodDecl method, JavacNode paramNode, JavacNode source) { // Possibly, if 'declaration instanceof ConstructorDeclaration', fetch declaration.constructorCall, search it for any references to our parameter, // and if they exist, create a new method in the class: 'private static <T> T lombok$nullCheck(T expr, String msg) {if (expr == null) throw NPE; return expr;}' and // wrap all references to it in the super/this to a call to this method. - JCStatement nullCheck = recursiveSetGeneratedBy(generateNullCheck(annotationNode.getTreeMaker(), paramNode, annotationNode), annotationNode); + JCStatement nullCheck = recursiveSetGeneratedBy(generateNullCheck(source.getTreeMaker(), paramNode, source), source); if (nullCheck == null) { // @NonNull applied to a primitive. Kinda pointless. Let's generate a warning. - annotationNode.addWarning("@NonNull is meaningless on a primitive."); + source.addWarning("@NonNull is meaningless on a primitive."); return; } - List<JCStatement> statements = declaration.body.stats; + List<JCStatement> statements = method.body.stats; String expectedName = paramNode.getName(); @@ -158,8 +199,71 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> { List<JCStatement> newList = tail.prepend(nullCheck); for (JCStatement stat : head) newList = newList.prepend(stat); - declaration.body.stats = newList; - annotationNode.getAst().setChanged(); + method.body.stats = newList; + source.getAst().setChanged(); + } + + @Override public void handle(AnnotationValues<NonNull> annotation, JCAnnotation ast, JavacNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.NON_NULL_FLAG_USAGE, "@NonNull"); + if (annotationNode.up().getKind() == Kind.FIELD) { + // This is meaningless unless the field is used to generate a method (@Setter, @RequiredArgsConstructor, etc), + // but in that case those handlers will take care of it. However, we DO check if the annotation is applied to + // a primitive, because those handlers trigger on any annotation named @NonNull and we only want the warning + // behaviour on _OUR_ 'lombok.NonNull'. + + try { + if (isPrimitive(((JCVariableDecl) annotationNode.up().get()).vartype)) { + annotationNode.addWarning("@NonNull is meaningless on a primitive."); + } + } catch (Exception ignore) {} + + JCVariableDecl fDecl = (JCVariableDecl) annotationNode.up().get(); + if ((fDecl.mods.flags & RECORD) != 0) { + // well, these kinda double as parameters (of the compact constructor), so we do some work here. + + List<JCMethodDecl> compactConstructors = addCompactConstructorIfNeeded(annotationNode.up().up(), annotationNode); + for (JCMethodDecl ctr : compactConstructors) { + addNullCheckIfNeeded(ctr, annotationNode.up(), annotationNode); + } + } + return; + } + + JCMethodDecl declaration; + JavacNode paramNode; + + switch (annotationNode.up().getKind()) { + case ARGUMENT: + paramNode = annotationNode.up(); + break; + case TYPE_USE: + JavacNode typeNode = annotationNode.directUp(); + paramNode = typeNode.directUp(); + break; + default: + return; + } + + if (paramNode.getKind() != Kind.ARGUMENT) return; + try { + declaration = (JCMethodDecl) paramNode.up().get(); + } catch (Exception e) { + return; + } + + if (declaration.body == null) { + // This used to be a warning, but as @NonNull also has a documentary purpose, better to not warn about this. Since 1.16.7 + return; + } + + if ((declaration.mods.flags & (GENERATED_MEMBER | COMPACT_RECORD_CONSTRUCTOR)) != 0) { + // The 'real' annotations are on the `record Foo(@NonNull Obj x)` part and we just see these + // syntax-sugared over. We deal with it on the field declaration variant, as those are always there, + // not dependent on whether you write out the compact constructor or not. + return; + } + + addNullCheckIfNeeded(declaration, paramNode, annotationNode); } public boolean isNullCheck(JCStatement stat) { diff --git a/src/core/lombok/javac/handlers/HandlePrintAST.java b/src/core/lombok/javac/handlers/HandlePrintAST.java index 0826d1d1..647139bc 100644 --- a/src/core/lombok/javac/handlers/HandlePrintAST.java +++ b/src/core/lombok/javac/handlers/HandlePrintAST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 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 @@ -25,8 +25,6 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.PrintStream; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.tree.JCTree.JCAnnotation; import lombok.Lombok; @@ -36,11 +34,12 @@ import lombok.core.PrintAST; import lombok.javac.JavacASTVisitor; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.spi.Provides; /** * Handles the {@code lombok.core.PrintAST} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(536870912) // 2^29; this handler is customarily run at the very end. public class HandlePrintAST extends JavacAnnotationHandler<PrintAST> { @Override public void handle(AnnotationValues<PrintAST> annotation, JCAnnotation ast, JavacNode annotationNode) { diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index 9943bcc8..a0634494 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.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 @@ -37,8 +37,7 @@ import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -58,8 +57,10 @@ import com.sun.tools.javac.util.Name; /** * Handles the {@code lombok.Setter} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@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)) { @@ -68,13 +69,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; } @@ -148,7 +144,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/HandleSneakyThrows.java b/src/core/lombok/javac/handlers/HandleSneakyThrows.java index 83f97c20..3dde75d8 100644 --- a/src/core/lombok/javac/handlers/HandleSneakyThrows.java +++ b/src/core/lombok/javac/handlers/HandleSneakyThrows.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 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 @@ -35,8 +35,7 @@ import lombok.core.HandlerPriority; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -53,7 +52,7 @@ import lombok.javac.Javac; /** * Handles the {@code lombok.SneakyThrows} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(value = 1024) // 2^10; @NonNull must have run first, so that we wrap around the statements generated by it. public class HandleSneakyThrows extends JavacAnnotationHandler<SneakyThrows> { @Override public void handle(AnnotationValues<SneakyThrows> annotation, JCAnnotation ast, JavacNode annotationNode) { diff --git a/src/core/lombok/javac/handlers/HandleStandardException.java b/src/core/lombok/javac/handlers/HandleStandardException.java new file mode 100644 index 00000000..ea1a0c5c --- /dev/null +++ b/src/core/lombok/javac/handlers/HandleStandardException.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.javac.handlers; + +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Name; +import lombok.AccessLevel; +import lombok.ConfigurationKeys; +import lombok.experimental.StandardException; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.delombok.LombokOptionsFactory; +import lombok.javac.Javac; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; +import lombok.javac.handlers.JavacHandlerUtil.*; +import lombok.spi.Provides; + +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; +import static lombok.javac.Javac.*; +import static lombok.javac.handlers.JavacHandlerUtil.*; + +@Provides +public class HandleStandardException extends JavacAnnotationHandler<StandardException> { + @Override + public void handle(AnnotationValues<StandardException> annotation, JCAnnotation ast, JavacNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.STANDARD_EXCEPTION_FLAG_USAGE, "@StandardException"); + deleteAnnotationIfNeccessary(annotationNode, StandardException.class); + deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel"); + JavacNode typeNode = annotationNode.up(); + + if (!isClass(typeNode)) { + annotationNode.addError("@StandardException is only supported on a class."); + return; + } + + JCClassDecl classDef = (JCClassDecl) typeNode.get(); + if (classDef.extending == null) { + annotationNode.addError("@StandardException requires that you extend a Throwable type"); + return; + } + + AccessLevel access = annotation.getInstance().access(); + if (access == null) access = AccessLevel.PUBLIC; + if (access == AccessLevel.NONE) { + annotationNode.addError("AccessLevel.NONE is not valid here"); + access = AccessLevel.PUBLIC; + } + + generateNoArgsConstructor(typeNode, access, annotationNode); + generateMsgOnlyConstructor(typeNode, access, annotationNode); + generateCauseOnlyConstructor(typeNode, access, annotationNode); + generateFullConstructor(typeNode, access, annotationNode); + } + + private void generateNoArgsConstructor(JavacNode typeNode, AccessLevel level, JavacNode source) { + if (hasConstructor(typeNode) != MemberExistsResult.NOT_EXISTS) return; + JavacTreeMaker maker = typeNode.getTreeMaker(); + + List<JCExpression> args = List.<JCExpression>of(maker.Literal(CTC_BOT, null), maker.Literal(CTC_BOT, null)); + JCStatement thisCall = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(typeNode.toName("this")), args)); + JCMethodDecl constr = createConstructor(level, typeNode, false, false, source, List.of(thisCall)); + injectMethod(typeNode, constr, List.<Type>nil(), Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID)); + } + + private void generateMsgOnlyConstructor(JavacNode typeNode, AccessLevel level, JavacNode source) { + if (hasConstructor(typeNode, String.class) != MemberExistsResult.NOT_EXISTS) return; + JavacTreeMaker maker = typeNode.getTreeMaker(); + + List<JCExpression> args = List.<JCExpression>of(maker.Ident(typeNode.toName("message")), maker.Literal(CTC_BOT, null)); + JCStatement thisCall = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(typeNode.toName("this")), args)); + JCMethodDecl constr = createConstructor(level, typeNode, true, false, source, List.of(thisCall)); + injectMethod(typeNode, constr, List.<Type>of(typeNode.getSymbolTable().stringType), Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID)); + } + + private void generateCauseOnlyConstructor(JavacNode typeNode, AccessLevel level, JavacNode source) { + if (hasConstructor(typeNode, Throwable.class) != MemberExistsResult.NOT_EXISTS) return; + JavacTreeMaker maker = typeNode.getTreeMaker(); + Name causeName = typeNode.toName("cause"); + + JCExpression causeDotGetMessage = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(causeName), typeNode.toName("getMessage")), List.<JCExpression>nil()); + JCExpression msgExpression = maker.Conditional(maker.Binary(CTC_NOT_EQUAL, maker.Ident(causeName), maker.Literal(CTC_BOT, null)), causeDotGetMessage, maker.Literal(CTC_BOT, null)); + + List<JCExpression> args = List.<JCExpression>of(msgExpression, maker.Ident(causeName)); + JCStatement thisCall = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(typeNode.toName("this")), args)); + JCMethodDecl constr = createConstructor(level, typeNode, false, true, source, List.of(thisCall)); + injectMethod(typeNode, constr, List.<Type>of(typeNode.getSymbolTable().throwableType), Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID)); + } + + private void generateFullConstructor(JavacNode typeNode, AccessLevel level, JavacNode source) { + if (hasConstructor(typeNode, String.class, Throwable.class) != MemberExistsResult.NOT_EXISTS) return; + JavacTreeMaker maker = typeNode.getTreeMaker(); + + Name causeName = typeNode.toName("cause"); + Name superName = typeNode.toName("super"); + + List<JCExpression> args = List.<JCExpression>of(maker.Ident(typeNode.toName("message"))); + JCStatement superCall = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(superName), args)); + JCExpression causeNotNull = maker.Binary(CTC_NOT_EQUAL, maker.Ident(causeName), maker.Literal(CTC_BOT, null)); + JCStatement initCauseCall = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(superName), typeNode.toName("initCause")), List.<JCExpression>of(maker.Ident(causeName)))); + JCStatement initCause = maker.If(causeNotNull, initCauseCall, null); + JCMethodDecl constr = createConstructor(level, typeNode, true, true, source, List.of(superCall, initCause)); + injectMethod(typeNode, constr, List.<Type>of(typeNode.getSymbolTable().stringType, typeNode.getSymbolTable().throwableType), Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID)); + } + + private static MemberExistsResult hasConstructor(JavacNode node, Class<?>... paramTypes) { + 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>") && (md.mods.flags & Flags.GENERATEDCONSTR) == 0) { + if (!paramsMatch(node, md.params, paramTypes)) continue; + return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK; + } + } + } + } + + return MemberExistsResult.NOT_EXISTS; + } + + private static boolean paramsMatch(JavacNode node, List<JCVariableDecl> a, Class<?>[] b) { + if (a == null) return b == null || b.length == 0; + if (b == null) return a.size() == 0; + if (a.size() != b.length) return false; + + for (int i = 0; i < a.size(); i++) { + JCVariableDecl param = a.get(i); + Class<?> c = b[i]; + if (!typeMatches(c, node, param.vartype)) return false; + } + + return true; + } + + private static void addConstructorProperties(JCModifiers mods, JavacNode node, boolean msgParam, boolean causeParam) { + if (!msgParam && !causeParam) return; + JavacTreeMaker maker = node.getTreeMaker(); + JCExpression constructorPropertiesType = chainDots(node, "java", "beans", "ConstructorProperties"); + ListBuffer<JCExpression> fieldNames = new ListBuffer<JCExpression>(); + if (msgParam) fieldNames.append(maker.Literal("message")); + if (causeParam) fieldNames.append(maker.Literal("cause")); + JCExpression fieldNamesArray = maker.NewArray(null, List.<JCExpression>nil(), fieldNames.toList()); + JCAnnotation annotation = maker.Annotation(constructorPropertiesType, List.of(fieldNamesArray)); + mods.annotations = mods.annotations.append(annotation); + } + + @SuppressWarnings("deprecation") private static JCMethodDecl createConstructor(AccessLevel level, JavacNode typeNode, boolean msgParam, boolean causeParam, JavacNode source, List<JCStatement> statements) { + JavacTreeMaker maker = typeNode.getTreeMaker(); + + boolean addConstructorProperties; + if ((!msgParam && !causeParam) || isLocalType(typeNode) || !LombokOptionsFactory.getDelombokOptions(typeNode.getContext()).getFormatPreferences().generateConstructorProperties()) { + addConstructorProperties = false; + } else { + Boolean v = typeNode.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_ADD_CONSTRUCTOR_PROPERTIES); + addConstructorProperties = v != null ? v.booleanValue() : + Boolean.FALSE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_SUPPRESS_CONSTRUCTOR_PROPERTIES)); + } + + ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>(); + + if (msgParam) { + Name fieldName = typeNode.toName("message"); + long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext()); + JCExpression pType = genJavaLangTypeRef(typeNode, "String"); + JCVariableDecl param = maker.VarDef(maker.Modifiers(flags), fieldName, pType, null); + params.append(param); + } + + if (causeParam) { + Name fieldName = typeNode.toName("cause"); + long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext()); + JCExpression pType = genJavaLangTypeRef(typeNode, "Throwable"); + JCVariableDecl param = maker.VarDef(maker.Modifiers(flags), fieldName, pType, null); + params.append(param); + } + + JCModifiers mods = maker.Modifiers(toJavacModifier(level), List.<JCAnnotation>nil()); + if (addConstructorProperties) addConstructorProperties(mods, typeNode, msgParam, causeParam); + return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("<init>"), + null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(), + maker.Block(0L, statements), null), source); + } + + public static boolean isLocalType(JavacNode type) { + Kind kind = type.up().getKind(); + if (kind == Kind.COMPILATION_UNIT) return false; + if (kind == Kind.TYPE) return isLocalType(type.up()); + return true; + } +} diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index d9e55a56..87b18576 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2020 The Project Lombok Authors. + * Copyright (C) 2013-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,8 +32,6 @@ import java.util.HashSet; import javax.lang.model.element.Modifier; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree; @@ -84,8 +82,9 @@ import lombok.javac.handlers.JavacSingularsRecipes.ExpressionMaker; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; import lombok.javac.handlers.JavacSingularsRecipes.SingularData; import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker; +import lombok.spi.Provides; -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes. public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { private static final String SELF_METHOD = "self"; @@ -112,7 +111,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { if (builderMethodName == null) builderMethodName = "builder"; if (buildMethodName == null) buildMethodName = "build"; - builderClassName = fixBuilderClassName(node, ""); + builderClassName = getBuilderClassNameTemplate(node, null); } void setBuilderToImpl() { @@ -160,15 +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(); - ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>(); + + // 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)); @@ -211,7 +210,6 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { } addObtainVia(bfd, fieldNode); job.builderFields.add(bfd); - allFields.append(fieldNode); } job.typeParams = job.builderTypeParams = td.typarams; @@ -234,8 +232,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { JCExpression annotatedClass = namePlusTypeParamsToTypeReference(maker, parent, job.typeParams); JCTypeParameter c = maker.TypeParameter(parent.toName(classGenericName), List.<JCExpression>of(annotatedClass)); ListBuffer<JCExpression> typeParamsForBuilder = getTypeParamExpressions(job.typeParams, maker, job.sourceNode); - typeParamsForBuilder.add(maker.Ident(parent.toName(classGenericName))); - typeParamsForBuilder.add(maker.Ident(parent.toName(builderGenericName))); + typeParamsForBuilder.append(maker.Ident(parent.toName(classGenericName))); + typeParamsForBuilder.append(maker.Ident(parent.toName(builderGenericName))); JCTypeApply typeApply = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, parent, job.getBuilderClassName(), false, List.<JCTypeParameter>nil()), typeParamsForBuilder.toList()); JCTypeParameter d = maker.TypeParameter(parent.toName(builderGenericName), List.<JCExpression>of(typeApply)); if (job.typeParams == null || job.typeParams.isEmpty()) { @@ -255,10 +253,12 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { } if (extendsClause instanceof JCFieldAccess) { Name superclassName = ((JCFieldAccess) extendsClause).getIdentifier(); - String superclassBuilderClassName = superclassName.toString() + "Builder"; + String builderClassNameTemplate = BuilderJob.getBuilderClassNameTemplate(annotationNode, null); + String superclassBuilderClassName = job.replaceBuilderClassName(superclassName.toString(), builderClassNameTemplate); superclassBuilderClass = parent.getTreeMaker().Select((JCFieldAccess) extendsClause, parent.toName(superclassBuilderClassName)); } else if (extendsClause != null) { - String superclassBuilderClassName = extendsClause.toString() + "Builder"; + String builderClassNameTemplate = BuilderJob.getBuilderClassNameTemplate(annotationNode, null); + String superclassBuilderClassName = job.replaceBuilderClassName(extendsClause.toString(), builderClassNameTemplate); superclassBuilderClass = chainDots(parent, extendsClause.toString(), superclassBuilderClassName); } @@ -305,7 +305,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { if (sd == null) continue; JavacSingularizer singularizer = sd.getSingularizer(); if (singularizer == null) continue; - if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderType, sd)) { + if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderAbstractType, sd)) { bfd.singularData = null; } } @@ -452,19 +452,19 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { // Keep any type params of the annotated class. ListBuffer<JCTypeParameter> allTypeParams = new ListBuffer<JCTypeParameter>(); - allTypeParams.addAll(copyTypeParams(job.sourceNode, job.typeParams)); + allTypeParams.appendList(copyTypeParams(job.sourceNode, job.typeParams)); // Add builder-specific type params required for inheritable builders. // 1. The return type for the build() method, named "C", which extends the annotated class. JCExpression annotatedClass = namePlusTypeParamsToTypeReference(maker, job.parentType, job.typeParams); - allTypeParams.add(maker.TypeParameter(job.toName(classGenericName), List.<JCExpression>of(annotatedClass))); + allTypeParams.append(maker.TypeParameter(job.toName(classGenericName), List.<JCExpression>of(annotatedClass))); // 2. The return type for all setter methods, named "B", which extends this builder class. Name builderClassName = job.toName(job.builderClassName); ListBuffer<JCExpression> typeParamsForBuilder = getTypeParamExpressions(job.typeParams, maker, job.sourceNode); - typeParamsForBuilder.add(maker.Ident(job.toName(classGenericName))); - typeParamsForBuilder.add(maker.Ident(job.toName(builderGenericName))); + typeParamsForBuilder.append(maker.Ident(job.toName(classGenericName))); + typeParamsForBuilder.append(maker.Ident(job.toName(builderGenericName))); JCTypeApply typeApply = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, job.parentType, builderClassName, false, List.<JCTypeParameter>nil()), typeParamsForBuilder.toList()); - allTypeParams.add(maker.TypeParameter(job.toName(builderGenericName), List.<JCExpression>of(typeApply))); + allTypeParams.append(maker.TypeParameter(job.toName(builderGenericName), List.<JCExpression>of(typeApply))); JCExpression extending = null; if (superclassBuilderClass != null) { @@ -472,8 +472,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { // 1. Add the type parameters of the superclass. typeParamsForBuilder = getTypeParamExpressions(superclassTypeParams, maker, job.sourceNode); // 2. Add the builder type params <C, B>. - typeParamsForBuilder.add(maker.Ident(job.toName(classGenericName))); - typeParamsForBuilder.add(maker.Ident(job.toName(builderGenericName))); + typeParamsForBuilder.append(maker.Ident(job.toName(classGenericName))); + typeParamsForBuilder.append(maker.Ident(job.toName(builderGenericName))); extending = maker.TypeApply(superclassBuilderClass, typeParamsForBuilder.toList()); } @@ -491,9 +491,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { // Extend the abstract builder. JCExpression extending = namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderAbstractClassName), false, List.<JCTypeParameter>nil()); - // Add any type params of the annotated class. - ListBuffer<JCTypeParameter> allTypeParams = new ListBuffer<JCTypeParameter>(); - allTypeParams.addAll(copyTypeParams(job.sourceNode, job.typeParams)); + // Add builder-specific type params required for inheritable builders. // 1. The return type for the build() method (named "C" in the abstract builder), which is the annotated class. JCExpression annotatedClass = namePlusTypeParamsToTypeReference(maker, job.parentType, job.typeParams); @@ -501,8 +499,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { JCExpression builderImplClassExpression = namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderImplClassName), false, job.typeParams); ListBuffer<JCExpression> typeParamsForBuilder = getTypeParamExpressions(job.typeParams, maker, job.sourceNode); - typeParamsForBuilder.add(annotatedClass); - typeParamsForBuilder.add(builderImplClassExpression); + typeParamsForBuilder.append(annotatedClass); + typeParamsForBuilder.append(builderImplClassExpression); extending = maker.TypeApply(extending, typeParamsForBuilder.toList()); JCClassDecl builder = maker.ClassDef(mods, job.toName(job.builderImplClassName), copyTypeParams(job.parentType, job.typeParams), extending, List.<JCExpression>nil(), List.<JCTree>nil()); @@ -556,7 +554,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { } } - List<JCAnnotation> annsOnMethod = job.checkerFramework.generateUnique() ? List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); + List<JCAnnotation> annsOnMethod = job.checkerFramework.generateSideEffectFree() ? List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); JCModifiers mods = maker.Modifiers(toJavacModifier(level), annsOnMethod); // Create a constructor that has just the builder as parameter. @@ -566,9 +564,9 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { ListBuffer<JCExpression> typeParamsForBuilderParameter = getTypeParamExpressions(job.typeParams, maker, job.sourceNode); // Now add the <?, ?>. JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); - typeParamsForBuilderParameter.add(wildcard); + typeParamsForBuilderParameter.append(wildcard); wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); - typeParamsForBuilderParameter.add(wildcard); + typeParamsForBuilderParameter.append(wildcard); JCTypeApply paramType = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, job.parentType, job.getBuilderClassName(), false, List.<JCTypeParameter>nil()), typeParamsForBuilderParameter.toList()); JCVariableDecl param = maker.VarDef(maker.Modifiers(flags), builderVariableName, paramType, null); params.append(param); @@ -591,9 +589,6 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { private JCMethodDecl generateBuilderMethod(SuperBuilderJob job) { JavacTreeMaker maker = job.getTreeMaker(); - ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); - for (JCTypeParameter typeParam : job.typeParams) typeArgs.append(maker.Ident(typeParam.name)); - JCExpression call = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderImplClassName), false, job.typeParams), List.<JCExpression>nil(), null); JCStatement statement = maker.Return(call); @@ -603,14 +598,17 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { // Add any type params of the annotated class to the return type. ListBuffer<JCExpression> typeParameterNames = new ListBuffer<JCExpression>(); - typeParameterNames.addAll(typeParameterNames(maker, job.typeParams)); + typeParameterNames.appendList(typeParameterNames(maker, job.typeParams)); // Now add the <?, ?>. JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); - typeParameterNames.add(wildcard); - typeParameterNames.add(wildcard); - JCTypeApply returnType = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderAbstractClassName), false, List.<JCTypeParameter>nil()), typeParameterNames.toList()); - - List<JCAnnotation> annsOnMethod = job.checkerFramework.generateUnique() ? List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); + typeParameterNames.append(wildcard); + typeParameterNames.append(wildcard); + // And return type annotations. + List<JCAnnotation> annsOnParamType = List.nil(); + if (job.checkerFramework.generateUnique()) annsOnParamType = List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__UNIQUE), List.<JCExpression>nil())); + JCTypeApply returnType = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderAbstractClassName), false, List.<JCTypeParameter>nil(), annsOnParamType), typeParameterNames.toList()); + + List<JCAnnotation> annsOnMethod = job.checkerFramework.generateSideEffectFree() ? List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), job.toName(job.builderMethodName), returnType, copyTypeParams(job.sourceNode, job.typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); createRelevantNonNullAnnotation(job.parentType, methodDef); return methodDef; @@ -627,9 +625,6 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { private JCMethodDecl generateToBuilderMethod(SuperBuilderJob job) { JavacTreeMaker maker = job.getTreeMaker(); - ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); - for (JCTypeParameter typeParam : job.typeParams) typeArgs.append(maker.Ident(typeParam.name)); - JCExpression newClass = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderImplClassName), false, job.typeParams), List.<JCExpression>nil(), null); List<JCExpression> methodArgs = List.<JCExpression>of(maker.Ident(job.toName("this"))); JCMethodInvocation invokeFillMethod = maker.Apply(List.<JCExpression>nil(), maker.Select(newClass, job.toName(FILL_VALUES_METHOD_NAME)), methodArgs); @@ -640,14 +635,14 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { // Add any type params of the annotated class to the return type. ListBuffer<JCExpression> typeParameterNames = new ListBuffer<JCExpression>(); - typeParameterNames.addAll(typeParameterNames(maker, job.typeParams)); + typeParameterNames.appendList(typeParameterNames(maker, job.typeParams)); // Now add the <?, ?>. JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); - typeParameterNames.add(wildcard); - typeParameterNames.add(wildcard); + typeParameterNames.append(wildcard); + typeParameterNames.append(wildcard); JCTypeApply returnType = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderAbstractClassName), false, List.<JCTypeParameter>nil()), typeParameterNames.toList()); - List<JCAnnotation> annsOnMethod = job.checkerFramework.generateUnique() ? List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); + List<JCAnnotation> annsOnMethod = job.checkerFramework.generateSideEffectFree() ? List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), job.toName(TO_BUILDER_METHOD_NAME), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); createRelevantNonNullAnnotation(job.parentType, methodDef); return methodDef; @@ -728,9 +723,9 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { ListBuffer<JCExpression> typeParamsForBuilderParameter = getTypeParamExpressions(job.typeParams, maker, job.sourceNode); // Now add the <?, ?>. JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); - typeParamsForBuilderParameter.add(wildcard); + typeParamsForBuilderParameter.append(wildcard); wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); - typeParamsForBuilderParameter.add(wildcard); + typeParamsForBuilderParameter.append(wildcard); JCTypeApply builderType = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, job.parentType, job.getBuilderClassName(), false, List.<JCTypeParameter>nil()), typeParamsForBuilderParameter.toList()); JCVariableDecl paramBuilder = maker.VarDef(maker.Modifiers(Flags.PARAMETER | Flags.FINAL), job.toName(BUILDER_VARIABLE_NAME), builderType, null); @@ -738,7 +733,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { // Call the builder's setter methods to fill the values from the instance. for (BuilderFieldData bfd : job.builderFields) { - JCExpressionStatement exec = createSetterCallWithInstanceValue(bfd, job.parentType, maker, setterPrefix); + JCExpressionStatement exec = createSetterCallWithInstanceValue(bfd, job, setterPrefix); body.append(exec); } @@ -747,22 +742,23 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { return maker.MethodDef(modifiers, name, returnType, copyTypeParams(job.builderType, job.typeParams), List.of(paramInstance, paramBuilder), List.<JCExpression>nil(), bodyBlock, null); } - private JCExpressionStatement createSetterCallWithInstanceValue(BuilderFieldData bfd, JavacNode type, JavacTreeMaker maker, String setterPrefix) { + private JCExpressionStatement createSetterCallWithInstanceValue(BuilderFieldData bfd, SuperBuilderJob job, String setterPrefix) { + JavacTreeMaker maker = job.getTreeMaker(); JCExpression[] tgt = new JCExpression[bfd.singularData == null ? 1 : 2]; if (bfd.obtainVia == null || !bfd.obtainVia.field().isEmpty()) { for (int i = 0; i < tgt.length; i++) { - tgt[i] = maker.Select(maker.Ident(type.toName(INSTANCE_VARIABLE_NAME)), bfd.obtainVia == null ? bfd.rawName : type.toName(bfd.obtainVia.field())); + tgt[i] = maker.Select(maker.Ident(job.toName(INSTANCE_VARIABLE_NAME)), bfd.obtainVia == null ? bfd.rawName : job.toName(bfd.obtainVia.field())); } } else { if (bfd.obtainVia.isStatic()) { for (int i = 0; i < tgt.length; i++) { - JCExpression typeRef = namePlusTypeParamsToTypeReference(maker, type, List.<JCTypeParameter>nil()); - JCExpression c = maker.Select(typeRef, type.toName(bfd.obtainVia.method())); - tgt[i] = maker.Apply(List.<JCExpression>nil(), c, List.<JCExpression>of(maker.Ident(type.toName(INSTANCE_VARIABLE_NAME)))); + JCExpression typeRef = namePlusTypeParamsToTypeReference(maker, job.parentType, List.<JCTypeParameter>nil()); + JCExpression c = maker.Select(typeRef, job.toName(bfd.obtainVia.method())); + tgt[i] = maker.Apply(List.<JCExpression>nil(), c, List.<JCExpression>of(maker.Ident(job.toName(INSTANCE_VARIABLE_NAME)))); } } else { for (int i = 0; i < tgt.length; i++) { - JCExpression c = maker.Select(maker.Ident(type.toName(INSTANCE_VARIABLE_NAME)), type.toName(bfd.obtainVia.method())); + JCExpression c = maker.Select(maker.Ident(job.toName(INSTANCE_VARIABLE_NAME)), job.toName(bfd.obtainVia.method())); tgt[i] = maker.Apply(List.<JCExpression>nil(), c, List.<JCExpression>nil()); } } @@ -773,13 +769,12 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { arg = tgt[0]; } else { JCExpression eqNull = maker.Binary(CTC_EQUAL, tgt[0], maker.Literal(CTC_BOT, null)); - String emptyMaker = bfd.singularData.getSingularizer().getEmptyMaker(bfd.singularData.getTargetFqn()); - JCExpression emptyCollection = maker.Apply(List.<JCExpression>nil(), chainDots(type, emptyMaker.split("\\.")), List.<JCExpression>nil()); + JCExpression emptyCollection = bfd.singularData.getSingularizer().getEmptyExpression(bfd.singularData.getTargetFqn(), maker, bfd.singularData, job.parentType, job.sourceNode); arg = maker.Conditional(eqNull, emptyCollection, tgt[1]); } String setterName = HandlerUtil.buildAccessorName(setterPrefix, bfd.name.toString()); - JCMethodInvocation apply = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(type.toName(BUILDER_VARIABLE_NAME)), type.toName(setterName)), List.of(arg)); + JCMethodInvocation apply = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(job.toName(BUILDER_VARIABLE_NAME)), job.toName(setterName)), List.of(arg)); JCExpressionStatement exec = maker.Exec(apply); return exec; } @@ -1090,13 +1085,13 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { ListBuffer<JCExpression> typeParamsForBuilderParameter = new ListBuffer<JCExpression>(); for (JCTree typeParam : typeParams) { if (typeParam instanceof JCTypeParameter) { - typeParamsForBuilderParameter.add(maker.Ident(((JCTypeParameter)typeParam).getName())); + typeParamsForBuilderParameter.append(maker.Ident(((JCTypeParameter)typeParam).getName())); } else if (typeParam instanceof JCIdent) { - typeParamsForBuilderParameter.add(maker.Ident(((JCIdent)typeParam).getName())); + typeParamsForBuilderParameter.append(maker.Ident(((JCIdent)typeParam).getName())); } else if (typeParam instanceof JCFieldAccess) { - typeParamsForBuilderParameter.add(copySelect(maker, (JCFieldAccess) typeParam)); + typeParamsForBuilderParameter.append(copySelect(maker, (JCFieldAccess) typeParam)); } else if (typeParam instanceof JCTypeApply) { - typeParamsForBuilderParameter.add(cloneType(maker, (JCTypeApply)typeParam, source)); + typeParamsForBuilderParameter.append(cloneType(maker, (JCTypeApply)typeParam, source)); } } return typeParamsForBuilderParameter; diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilderRemove.java b/src/core/lombok/javac/handlers/HandleSuperBuilderRemove.java index cca69729..d3db5ef4 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilderRemove.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilderRemove.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Project Lombok Authors. + * Copyright (C) 2020-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 @@ -23,8 +23,6 @@ package lombok.javac.handlers; import static lombok.javac.handlers.JavacHandlerUtil.*; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.tree.JCTree.JCAnnotation; import lombok.core.AlreadyHandledAnnotations; @@ -33,9 +31,10 @@ import lombok.core.HandlerPriority; import lombok.experimental.SuperBuilder; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; +import lombok.spi.Provides; -@ProviderFor(JavacAnnotationHandler.class) -@HandlerPriority(65536) +@Provides +@HandlerPriority(32768) @AlreadyHandledAnnotations public class HandleSuperBuilderRemove extends JavacAnnotationHandler<SuperBuilder> { @Override public void handle(AnnotationValues<SuperBuilder> annotation, JCAnnotation ast, JavacNode annotationNode) { diff --git a/src/core/lombok/javac/handlers/HandleSynchronized.java b/src/core/lombok/javac/handlers/HandleSynchronized.java index f7ac50e7..0bf7cbe8 100644 --- a/src/core/lombok/javac/handlers/HandleSynchronized.java +++ b/src/core/lombok/javac/handlers/HandleSynchronized.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 @@ -33,8 +33,7 @@ import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree; @@ -51,7 +50,7 @@ import com.sun.tools.javac.util.List; /** * Handles the {@code lombok.Synchronized} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(value = 1024) // 2^10; @NonNull must have run first, so that we wrap around the statements generated by it. public class HandleSynchronized extends JavacAnnotationHandler<Synchronized> { private static final String INSTANCE_LOCK_NAME = "$lock"; @@ -77,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; @@ -87,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 6bf38a84..3fc6a4e4 100644 --- a/src/core/lombok/javac/handlers/HandleToString.java +++ b/src/core/lombok/javac/handlers/HandleToString.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 @@ -38,8 +38,7 @@ import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -59,7 +58,7 @@ import com.sun.tools.javac.util.List; /** * Handles the {@code ToString} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides public class HandleToString extends JavacAnnotationHandler<ToString> { @Override public void handle(AnnotationValues<ToString> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.TO_STRING_FLAG_USAGE, "@ToString"); @@ -106,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 cd05c285..6fa630e2 100644 --- a/src/core/lombok/javac/handlers/HandleUtilityClass.java +++ b/src/core/lombok/javac/handlers/HandleUtilityClass.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -24,8 +24,6 @@ package lombok.javac.handlers; import static lombok.core.handlers.HandlerUtil.handleExperimentalFlagUsage; import static lombok.javac.handlers.JavacHandlerUtil.*; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCBlock; @@ -47,12 +45,13 @@ import lombok.experimental.UtilityClass; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; +import lombok.spi.Provides; /** * Handles the {@code @UtilityClass} annotation for javac. */ @HandlerPriority(-4096) //-2^12; to ensure @FieldDefaults picks up on the 'static' we set here. -@ProviderFor(JavacAnnotationHandler.class) +@Provides public class HandleUtilityClass extends JavacAnnotationHandler<UtilityClass> { @Override public void handle(AnnotationValues<UtilityClass> annotation, JCAnnotation ast, JavacNode annotationNode) { handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.UTILITY_CLASS_FLAG_USAGE, "@UtilityClass"); @@ -65,13 +64,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/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java index 54645354..0ed831ab 100644 --- a/src/core/lombok/javac/handlers/HandleVal.java +++ b/src/core/lombok/javac/handlers/HandleVal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2018 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 @@ -33,8 +33,7 @@ import lombok.javac.JavacASTVisitor; import lombok.javac.JavacNode; import lombok.javac.JavacResolution; import lombok.javac.ResolutionResetNeeded; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symtab; @@ -49,7 +48,7 @@ import com.sun.tools.javac.tree.JCTree.JCNewArray; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; -@ProviderFor(JavacASTVisitor.class) +@Provides(JavacASTVisitor.class) @HandlerPriority(HANDLE_DELEGATE_PRIORITY + 100) // run slightly after HandleDelegate; resolution needs to work, so if the RHS expression is i.e. a call to a generated getter, we have to run after that getter has been generated. @ResolutionResetNeeded public class HandleVal extends JavacASTAdapter { @@ -59,7 +58,7 @@ public class HandleVal extends JavacASTAdapter { } @SuppressWarnings("deprecation") @Override - public void visitLocal(JavacNode localNode, JCVariableDecl local) { + public void endVisitLocal(JavacNode localNode, JCVariableDecl local) { JCTree typeTree = local.vartype; if (typeTree == null) return; String typeTreeToString = typeTree.toString(); diff --git a/src/core/lombok/javac/handlers/HandleValue.java b/src/core/lombok/javac/handlers/HandleValue.java index 503792fa..cff29801 100644 --- a/src/core/lombok/javac/handlers/HandleValue.java +++ b/src/core/lombok/javac/handlers/HandleValue.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2018 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -33,8 +33,7 @@ import lombok.Value; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.handlers.HandleConstructor.SkipIfConstructorExists; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -45,7 +44,7 @@ import com.sun.tools.javac.util.List; /** * Handles the {@code lombok.Value} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(-512) //-2^9; to ensure @EqualsAndHashCode and such pick up on this handler making the class final and messing with the fields' access levels, run earlier. public class HandleValue extends JavacAnnotationHandler<Value> { private HandleFieldDefaults handleFieldDefaults = new HandleFieldDefaults(); diff --git a/src/core/lombok/javac/handlers/HandleWith.java b/src/core/lombok/javac/handlers/HandleWith.java index 249df096..47f78b1e 100644 --- a/src/core/lombok/javac/handlers/HandleWith.java +++ b/src/core/lombok/javac/handlers/HandleWith.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2020 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -37,8 +37,7 @@ import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacHandlerUtil.CopyJavadoc; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -60,7 +59,7 @@ import com.sun.tools.javac.util.Name; /** * Handles the {@code lombok.With} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides public class HandleWith extends JavacAnnotationHandler<With> { public void generateWithForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelWith) { if (checkForTypeLevelWith) { diff --git a/src/core/lombok/javac/handlers/HandleWithBy.java b/src/core/lombok/javac/handlers/HandleWithBy.java index ed0ed863..4ba4337e 100644 --- a/src/core/lombok/javac/handlers/HandleWithBy.java +++ b/src/core/lombok/javac/handlers/HandleWithBy.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Project Lombok Authors. + * Copyright (C) 2020-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 @@ -41,8 +41,7 @@ import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.JavacTreeMaker.TypeTag; import lombok.javac.handlers.JavacHandlerUtil.CopyJavadoc; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Flags; @@ -65,7 +64,7 @@ import com.sun.tools.javac.util.Name; /** * Handles the {@code lombok.With} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides public class HandleWithBy extends JavacAnnotationHandler<WithBy> { public void generateWithByForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelWithBy) { if (checkForTypeLevelWithBy) { @@ -124,7 +123,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(); @@ -136,7 +134,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 8233f20b..fba13133 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 @@ -103,6 +103,7 @@ import lombok.delombok.LombokOptionsFactory; import lombok.experimental.Accessors; import lombok.experimental.Tolerate; import lombok.javac.Javac; +import lombok.javac.JavacAugments; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.permit.Permit; @@ -537,21 +538,18 @@ public class JavacHandlerUtil { public static void deleteImportFromCompilationUnit(JavacNode node, String name) { if (inNetbeansEditor(node)) return; if (!node.shouldDeleteLombokAnnotations()) return; - ListBuffer<JCTree> newDefs = new ListBuffer<JCTree>(); JCCompilationUnit unit = (JCCompilationUnit) node.top().get(); for (JCTree def : unit.defs) { - boolean delete = false; - if (def instanceof JCImport) { - JCImport imp0rt = (JCImport)def; - delete = (!imp0rt.staticImport && imp0rt.qualid.toString().equals(name)); - } - if (!delete) newDefs.append(def); + if (!(def instanceof JCImport)) continue; + JCImport imp0rt = (JCImport) def; + if (imp0rt.staticImport) continue; + if (!imp0rt.qualid.toString().equals(name)) continue; + JavacAugments.JCImport_deletable.set(imp0rt, true); } - unit.defs = newDefs.toList(); } - + private static List<JCAnnotation> filterList(List<JCAnnotation> annotations, JCTree jcTree) { ListBuffer<JCAnnotation> newAnnotations = new ListBuffer<JCAnnotation>(); for (JCAnnotation ann : annotations) { @@ -807,7 +805,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>")) { @@ -1972,17 +1970,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/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index 1af4f673..4ca09b82 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2020 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -298,7 +298,7 @@ public class JavacSingularsRecipes { private void generateClearMethod(CheckerFrameworkVersion cfv, boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JavacNode source, AccessLevel access) { JCStatement clearStatement = generateClearStatements(maker, data, builderType); ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); - statements.add(clearStatement); + statements.append(clearStatement); Name methodName = builderType.toName(HandlerUtil.buildAccessorName("clear", data.getPluralName().toString())); finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, methodName, List.<JCVariableDecl>nil(), List.<JCAnnotation>nil(), access, null); @@ -357,7 +357,7 @@ public class JavacSingularsRecipes { JCExpression incomingIsNotNull = maker.Binary(CTC_NOT_EQUAL, maker.Ident(data.getPluralName()), maker.Literal(CTC_BOT, null)); JCStatement onNotNull = maker.Block(0, statements.toList()); statements = new ListBuffer<JCStatement>(); - statements.add(maker.If(incomingIsNotNull, onNotNull, null)); + statements.append(maker.If(incomingIsNotNull, onNotNull, null)); } else { statements.prepend(JavacHandlerUtil.generateNullCheck(maker, null, data.getPluralName(), builderType, "%s cannot be null")); } @@ -501,5 +501,11 @@ public class JavacSingularsRecipes { protected abstract int getTypeArgumentsCount(); protected abstract String getEmptyMaker(String target); + + public JCExpression getEmptyExpression(String target, JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source) { + String emptyMaker = getEmptyMaker(target); + List<JCExpression> typeArgs = createTypeArgs(getTypeArgumentsCount(), false, builderType, data.getTypeArgs(), source); + return maker.Apply(typeArgs, chainDots(builderType, emptyMaker.split("\\.")), List.<JCExpression>nil()); + } } } diff --git a/src/core/lombok/javac/handlers/singulars/JavacGuavaMapSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaMapSingularizer.java index e0621cf7..84840799 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaMapSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaMapSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -23,10 +23,9 @@ package lombok.javac.handlers.singulars; import lombok.core.LombokImmutableList; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; +import lombok.spi.Provides; -import org.mangosdk.spi.ProviderFor; - -@ProviderFor(JavacSingularizer.class) +@Provides(JavacSingularizer.class) public class JavacGuavaMapSingularizer extends JavacGuavaSingularizer { // TODO cgcc.ImmutableMultimap, cgcc.ImmutableListMultimap, cgcc.ImmutableSetMultimap // TODO cgcc.ImmutableClassToInstanceMap diff --git a/src/core/lombok/javac/handlers/singulars/JavacGuavaSetListSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaSetListSingularizer.java index 5c7fcab5..44d6d15b 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSetListSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSetListSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -21,12 +21,11 @@ */ package lombok.javac.handlers.singulars; -import org.mangosdk.spi.ProviderFor; - import lombok.core.LombokImmutableList; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; +import lombok.spi.Provides; -@ProviderFor(JavacSingularizer.class) +@Provides(JavacSingularizer.class) public class JavacGuavaSetListSingularizer extends JavacGuavaSingularizer { // TODO com.google.common.collect.ImmutableRangeSet // TODO com.google.common.collect.ImmutableMultiset and com.google.common.collect.ImmutableSortedMultiset diff --git a/src/core/lombok/javac/handlers/singulars/JavacGuavaTableSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaTableSingularizer.java index 080266b8..bdc5facc 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaTableSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaTableSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -21,12 +21,11 @@ */ package lombok.javac.handlers.singulars; -import org.mangosdk.spi.ProviderFor; - import lombok.core.LombokImmutableList; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; +import lombok.spi.Provides; -@ProviderFor(JavacSingularizer.class) +@Provides(JavacSingularizer.class) public class JavacGuavaTableSingularizer extends JavacGuavaSingularizer { private static final LombokImmutableList<String> SUFFIXES = LombokImmutableList.of("rowKey", "columnKey", "value"); diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java index 56a162e3..10f1ddd1 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -24,13 +24,12 @@ package lombok.javac.handlers.singulars; import static lombok.javac.Javac.*; import static lombok.javac.handlers.JavacHandlerUtil.*; -import org.mangosdk.spi.ProviderFor; - import lombok.core.LombokImmutableList; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; import lombok.javac.handlers.JavacSingularsRecipes.SingularData; +import lombok.spi.Provides; import com.sun.tools.javac.tree.JCTree.JCCase; import com.sun.tools.javac.tree.JCTree.JCExpression; @@ -39,7 +38,7 @@ import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; -@ProviderFor(JavacSingularizer.class) +@Provides(JavacSingularizer.class) public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingularizer { @Override public LombokImmutableList<String> getSupportedTypes() { return LombokImmutableList.of("java.util.List", "java.util.Collection", "java.lang.Iterable"); diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java index 22f569f4..b8c931c7 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -36,8 +36,7 @@ import lombok.javac.handlers.JavacSingularsRecipes.ExpressionMaker; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; import lombok.javac.handlers.JavacSingularsRecipes.SingularData; import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker; - -import org.mangosdk.spi.ProviderFor; +import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree.JCBlock; @@ -48,7 +47,7 @@ import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; -@ProviderFor(JavacSingularizer.class) +@Provides(JavacSingularizer.class) public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer { @Override public LombokImmutableList<String> getSupportedTypes() { return LombokImmutableList.of("java.util.Map", "java.util.SortedMap", "java.util.NavigableMap"); diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSetSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSetSingularizer.java index 5a0638d8..6d2e0655 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSetSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSetSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Project Lombok Authors. + * Copyright (C) 2015-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 @@ -21,19 +21,18 @@ */ package lombok.javac.handlers.singulars; -import org.mangosdk.spi.ProviderFor; - import lombok.core.LombokImmutableList; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; import lombok.javac.handlers.JavacSingularsRecipes.SingularData; +import lombok.spi.Provides; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; -@ProviderFor(JavacSingularizer.class) +@Provides(JavacSingularizer.class) public class JavacJavaUtilSetSingularizer extends JavacJavaUtilListSetSingularizer { @Override public LombokImmutableList<String> getSupportedTypes() { return LombokImmutableList.of("java.util.Set", "java.util.SortedSet", "java.util.NavigableSet"); diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java index cf8fea9f..3b6113df 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java @@ -89,7 +89,7 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer { protected JCStatement createConstructBuilderVarIfNeeded(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, JavacNode source) { List<JCExpression> jceBlank = List.nil(); - + Name v1Name = mapMode ? builderType.toName(data.getPluralName() + "$key") : data.getPluralName(); Name v2Name = mapMode ? builderType.toName(data.getPluralName() + "$value") : null; JCExpression thisDotField = maker.Select(maker.Ident(builderType.toName("this")), v1Name); |