diff options
Diffstat (limited to 'src/core')
108 files changed, 2963 insertions, 2091 deletions
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 01a4b576..ba66649b 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -274,7 +274,7 @@ public class ConfigurationKeys { * * For any class with an {@code @ToString} annotation which extends a class other than {@code java.lang.Object}, should a call to superclass's implementation of {@code toString} be included in the generated method? (Default = skip) */ - public static final ConfigurationKey<CallSuperType> TO_STRING_CALL_SUPER = new ConfigurationKey<CallSuperType>("lombok.toString.callSuper", "When generating toString for classes that extend something (other than Object), either automatically take into account superclass implementation (call), or don't (skip), or warn and don't (warn). (default = warn).") {}; + public static final ConfigurationKey<CallSuperType> TO_STRING_CALL_SUPER = new ConfigurationKey<CallSuperType>("lombok.toString.callSuper", "When generating toString for classes that extend something (other than Object), either automatically take into account superclass implementation (call), or don't (skip), or warn and don't (warn). (default = skip).") {}; /** * lombok configuration: {@code lombok.toString.flagUsage} = {@code WARNING} | {@code ERROR}. diff --git a/src/core/lombok/EqualsAndHashCode.java b/src/core/lombok/EqualsAndHashCode.java index 6805d214..279e6e3d 100644 --- a/src/core/lombok/EqualsAndHashCode.java +++ b/src/core/lombok/EqualsAndHashCode.java @@ -71,6 +71,14 @@ public @interface EqualsAndHashCode { * @return If {@code true}, always use direct field access instead of calling the getter method. */ boolean doNotUseGetters() default false; + + /** + * Determines how the result of the {@code hashCode} method will be cached. + * <strong>default: {@link CacheStrategy#NEVER}</strong> + * + * @return The {@code hashCode} cache strategy to be used. + */ + CacheStrategy cacheStrategy() default CacheStrategy.NEVER; /** * Any annotations listed here are put on the generated parameter of {@code equals} and {@code canEqual}. @@ -132,4 +140,19 @@ public @interface EqualsAndHashCode { */ int rank() default 0; } + + public enum CacheStrategy { + /** + * Never cache. Perform the calculation every time the method is called. + */ + NEVER, + /** + * Cache the result of the first invocation of {@code hashCode} and use it for subsequent invocations. + * This can improve performance if all fields used for calculating the {@code hashCode} are immutable + * and thus every invocation of {@code hashCode} will always return the same value. + * <strong>Do not use this if there's <em>any</em> chance that different invocations of {@code hashCode} + * might return different values.</strong> + */ + LAZY + } } 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..14e95c46 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) { diff --git a/src/core/lombok/bytecode/SneakyThrowsRemover.java b/src/core/lombok/bytecode/SneakyThrowsRemover.java index 037cb109..7ed3f80f 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) { diff --git a/src/core/lombok/core/AnnotationProcessor.java b/src/core/lombok/core/AnnotationProcessor.java index d4a92408..28d16298 100644 --- a/src/core/lombok/core/AnnotationProcessor.java +++ b/src/core/lombok/core/AnnotationProcessor.java @@ -26,8 +26,9 @@ import static lombok.core.Augments.ClassLoader_lombokAlreadyAddedTo; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; -import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; @@ -68,7 +69,7 @@ public class AnnotationProcessor extends AbstractProcessor { private final List<String> delayedWarnings = new ArrayList<String>(); /** - * This method is a simplified version of {@link lombok.javac.apt.LombokProcessor.getJavacProcessingEnvironment} + * This method is a simplified version of {@link lombok.javac.apt.LombokProcessor#getJavacProcessingEnvironment} * It simply returns the processing environment, but in case of gradle incremental compilation, * the delegate ProcessingEnvironment of the gradle wrapper is returned. */ @@ -83,15 +84,11 @@ public class AnnotationProcessor extends AbstractProcessor { for (Class<?> procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) { try { - Field field; - try { - field = Permit.getField(procEnvClass, "delegate"); - } catch (NoSuchFieldException e) { - field = Permit.getField(procEnvClass, "processingEnv"); - } - Object delegate = field.get(procEnv); - - return tryRecursivelyObtainJavacProcessingEnvironment((ProcessingEnvironment) delegate); + Object delegate = tryGetDelegateField(procEnvClass, procEnv); + if (delegate == null) delegate = tryGetProcessingEnvField(procEnvClass, procEnv); + if (delegate == null) delegate = tryGetProxyDelegateToField(procEnvClass, procEnv); + + if (delegate != null) return tryRecursivelyObtainJavacProcessingEnvironment((ProcessingEnvironment) delegate); } catch (final Exception e) { // no valid delegate, try superclass } @@ -100,6 +97,40 @@ public class AnnotationProcessor extends AbstractProcessor { return null; } + /** + * Gradle incremental processing + */ + private static Object tryGetDelegateField(Class<?> delegateClass, Object instance) { + try { + return Permit.getField(delegateClass, "delegate").get(instance); + } catch (Exception e) { + return null; + } + } + + /** + * Kotlin incremental processing + */ + private static Object tryGetProcessingEnvField(Class<?> delegateClass, Object instance) { + try { + return Permit.getField(delegateClass, "processingEnv").get(instance); + } catch (Exception e) { + return null; + } + } + + /** + * IntelliJ IDEA >= 2020.3 + */ + private static Object tryGetProxyDelegateToField(Class<?> delegateClass, Object instance) { + try { + InvocationHandler handler = Proxy.getInvocationHandler(instance); + return Permit.getField(handler.getClass(), "val$delegateTo").get(handler); + } catch (Exception e) { + return null; + } + } + static class JavacDescriptor extends ProcessorDescriptor { private Processor processor; @@ -143,7 +174,7 @@ public class AnnotationProcessor extends AbstractProcessor { if (!ClassLoader_lombokAlreadyAddedTo.getAndSet(environmentClassLoader, true)) { Method m = Permit.getMethod(environmentClassLoader.getClass(), "addURL", URL.class); URL selfUrl = new File(ClassRootFinder.findClassRootOfClass(AnnotationProcessor.class)).toURI().toURL(); - m.invoke(environmentClassLoader, selfUrl); + Permit.invoke(m, environmentClassLoader, selfUrl); } } @@ -188,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)); + } } } @@ -226,6 +261,6 @@ public class AnnotationProcessor extends AbstractProcessor { * We just return the latest version of whatever JDK we run on. Stupid? Yeah, but it's either that or warnings on all versions but 1. Blame Joe. */ @Override public SourceVersion getSupportedSourceVersion() { - return SourceVersion.values()[SourceVersion.values().length - 1]; + return SourceVersion.latest(); } } diff --git a/src/core/lombok/core/Main.java b/src/core/lombok/core/Main.java index 47afaefd..2c9d1dcb 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"; diff --git a/src/core/lombok/core/PostCompiler.java b/src/core/lombok/core/PostCompiler.java index 72f4b3a2..122bb268 100644 --- a/src/core/lombok/core/PostCompiler.java +++ b/src/core/lombok/core/PostCompiler.java @@ -28,6 +28,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.Collections; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; public final class PostCompiler { private PostCompiler() {/* prevent instantiation*/}; @@ -67,8 +68,17 @@ public final class PostCompiler { public static OutputStream wrapOutputStream(final OutputStream originalStream, final String fileName, final DiagnosticsReceiver diagnostics) throws IOException { if (System.getProperty("lombok.disablePostCompiler", null) != null) return originalStream; + + // close() can be called more than once and should be idempotent, therefore, ensure we never transform more than once. + final AtomicBoolean closed = new AtomicBoolean(); + return new ByteArrayOutputStream() { @Override public void close() throws IOException { + if (closed.getAndSet(true)) { + originalStream.close(); + return; + } + // no need to call super byte[] original = toByteArray(); byte[] copy = null; 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 2962a8e0..af0941bb 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.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 @@ -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.13"; + private static final String VERSION = "1.18.19"; 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/CheckerFrameworkVersion.java b/src/core/lombok/core/configuration/CheckerFrameworkVersion.java index 5805678f..c37ba91d 100644 --- a/src/core/lombok/core/configuration/CheckerFrameworkVersion.java +++ b/src/core/lombok/core/configuration/CheckerFrameworkVersion.java @@ -32,9 +32,9 @@ public final class CheckerFrameworkVersion implements ConfigurationValueType { public static final String NAME__SIDE_EFFECT_FREE = "org.checkerframework.dataflow.qual.SideEffectFree"; public static final String NAME__PURE = "org.checkerframework.dataflow.qual.Pure"; public static final String NAME__UNIQUE = "org.checkerframework.common.aliasing.qual.Unique"; - public static final String NAME__RETURNS_RECEIVER = "org.checkerframework.checker.builder.qual.ReturnsReceiver"; - public static final String NAME__NOT_CALLED = "org.checkerframework.checker.builder.qual.NotCalledMethods"; - public static final String NAME__CALLED = "org.checkerframework.checker.builder.qual.CalledMethods"; + public static final String NAME__RETURNS_RECEIVER = "org.checkerframework.common.returnsreceiver.qual.This"; + public static final String NAME__NOT_CALLED = "org.checkerframework.checker.calledmethods.qual.NotCalledMethods"; + public static final String NAME__CALLED = "org.checkerframework.checker.calledmethods.qual.CalledMethods"; public static final CheckerFrameworkVersion NONE = new CheckerFrameworkVersion(0); 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 1c4437d7..19cc5a9e 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.regex.Matcher; import java.util.regex.Pattern; import lombok.AllArgsConstructor; @@ -324,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", @@ -756,4 +759,90 @@ public class HandlerUtil { if (PRIMITIVE_WRAPPER_TYPE_NAME_PATTERN.matcher(typeName).matches()) return 800; return 0; } + + private static final Pattern SECTION_FINDER = Pattern.compile("^\\s*\\**\\s*[-*][-*]+\\s*([GS]ETTER|WITH(?:ER)?)\\s*[-*][-*]+\\s*\\**\\s*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); + private static final Pattern LINE_BREAK_FINDER = Pattern.compile("(\\r?\\n)?"); + + public enum JavadocTag { + PARAM("@param(?:eter)?"), + RETURN("@returns?"); + + private Pattern pattern; + + JavadocTag(String regexpFragment) { + pattern = Pattern.compile("\\s?^[ \\t]*\\**[ \\t]*" + regexpFragment + "(\\S|\\s)*?(?=(\\s^\\s*\\**\\s*@|\\Z))", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); + } + } + + public static String stripLinesWithTagFromJavadoc(String javadoc, JavadocTag tag) { + if (javadoc == null || javadoc.isEmpty()) return javadoc; + return tag.pattern.matcher(javadoc).replaceAll(""); + } + + public static String stripSectionsFromJavadoc(String javadoc) { + if (javadoc == null || javadoc.isEmpty()) return javadoc; + Matcher sectionMatcher = SECTION_FINDER.matcher(javadoc); + if (!sectionMatcher.find()) return javadoc; + + return javadoc.substring(0, sectionMatcher.start()); + } + + public static String getJavadocSection(String javadoc, String sectionNameSpec) { + if (javadoc == null || javadoc.isEmpty()) return null; + String[] sectionNames = sectionNameSpec.split("\\|"); + Matcher sectionMatcher = SECTION_FINDER.matcher(javadoc); + Matcher lineBreakMatcher = LINE_BREAK_FINDER.matcher(javadoc); + int sectionStart = -1; + int sectionEnd = -1; + while (sectionMatcher.find()) { + boolean found = false; + for (String sectionName : sectionNames) if (sectionMatcher.group(1).equalsIgnoreCase(sectionName)) { + found = true; + break; + } + if (found) { + lineBreakMatcher.find(sectionMatcher.end()); + sectionStart = lineBreakMatcher.end(); + } else if (sectionStart != -1) { + sectionEnd = sectionMatcher.start(); + } + } + + if (sectionStart != -1) { + if (sectionEnd != -1) return javadoc.substring(sectionStart, sectionEnd); + return javadoc.substring(sectionStart); + } + + return null; + } + + private static final Pattern FIND_RETURN = Pattern.compile("^\\s*\\**\\s*@returns?\\s+.*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); + + public static String addReturnsThisIfNeeded(String in) { + if (in != null && FIND_RETURN.matcher(in).find()) return in; + + return addJavadocLine(in, "@return {@code this}."); + } + + public static String addReturnsUpdatedSelfIfNeeded(String in) { + if (in != null && FIND_RETURN.matcher(in).find()) return in; + + return addJavadocLine(in, "@return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed)."); + } + + public static String addJavadocLine(String in, String line) { + if (in == null) return line; + if (in.endsWith("\n")) return in + line + "\n"; + return in + "\n" + line; + } + + public static String getParamJavadoc(String methodComment, String param) { + if (methodComment == null || methodComment.isEmpty()) return methodComment; + Pattern pattern = Pattern.compile("@param " + param + " (\\S|\\s)+?(?=^ ?@)", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(methodComment); + if (matcher.find()) { + return matcher.group(); + } + return null; + } } 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/EclipseAugments.java b/src/core/lombok/eclipse/EcjAugments.java index f4583ac4..cd7173a8 100644 --- a/src/core/lombok/eclipse/EclipseAugments.java +++ b/src/core/lombok/eclipse/EcjAugments.java @@ -21,14 +21,21 @@ */ package lombok.eclipse; +import java.util.Map; +import java.util.List; +import java.util.concurrent.ConcurrentMap; + import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; +import org.eclipse.jdt.internal.core.CompilationUnit; +import org.eclipse.jdt.internal.core.SourceMethod; import lombok.core.FieldAugment; -public final class EclipseAugments { - private EclipseAugments() { +public final class EcjAugments { + private EcjAugments() { // Prevent instantiation } @@ -36,4 +43,13 @@ public final class EclipseAugments { public static final FieldAugment<ASTNode, Boolean> ASTNode_handled = FieldAugment.augment(ASTNode.class, boolean.class, "lombok$handled"); public static final FieldAugment<ASTNode, ASTNode> ASTNode_generatedBy = FieldAugment.augment(ASTNode.class, ASTNode.class, "$generatedBy"); public static final FieldAugment<Annotation, Boolean> Annotation_applied = FieldAugment.augment(Annotation.class, boolean.class, "lombok$applied"); + public static final FieldAugment<ICompilationUnit, Map<String, String>> CompilationUnit_javadoc = FieldAugment.augment(ICompilationUnit.class, Map.class, "$javadoc"); + + public static final class EclipseAugments { + private EclipseAugments() { + // Prevent instantiation + } + + public static final FieldAugment<CompilationUnit, ConcurrentMap<String, List<SourceMethod>>> CompilationUnit_delegateMethods = FieldAugment.augment(CompilationUnit.class, ConcurrentMap.class, "$delegateMethods"); + } } diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java index 2c860e14..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 @@ -21,11 +21,8 @@ */ package lombok.eclipse; -import static lombok.eclipse.handlers.EclipseHandlerUtil.*; - import java.io.File; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.util.ArrayList; @@ -33,9 +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 static lombok.eclipse.handlers.EclipseHandlerUtil.*; import lombok.permit.Permit; import org.eclipse.core.resources.ResourcesPlugin; @@ -287,23 +284,8 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { */ public static void addProblemToCompilationResult(char[] fileNameArray, CompilationResult result, boolean isWarning, String message, int sourceStart, int sourceEnd) { - try { - EcjReflectionCheck.addProblemToCompilationResult.invoke(null, fileNameArray, result, isWarning, message, sourceStart, sourceEnd); - } catch (NoClassDefFoundError e) { - //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly - //do anything useful here. - } catch (IllegalAccessException e) { - throw Lombok.sneakyThrow(e); - } catch (InvocationTargetException e) { - throw Lombok.sneakyThrow(e); - } catch (NullPointerException e) { - if (!"false".equals(System.getProperty("lombok.debug.reflection", "false"))) { - e.initCause(EcjReflectionCheck.problemAddProblemToCompilationResult); - throw e; - } - //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly - //do anything useful here. - } + + Permit.invokeSneaky(EcjReflectionCheck.problemAddProblemToCompilationResult, EcjReflectionCheck.addProblemToCompilationResult, null, fileNameArray, result, isWarning, message, sourceStart, sourceEnd); } public static Annotation[] getTopLevelTypeReferenceAnnotations(TypeReference tr) { @@ -311,14 +293,14 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { if (m == null) return null; Annotation[][] annss = null; try { - annss = (Annotation[][]) m.invoke(tr); + annss = (Annotation[][]) Permit.invoke(m, tr); if (annss != null) return annss[0]; } catch (Throwable ignore) {} try { Field f = EcjReflectionCheck.typeReferenceAnnotations; if (f == null) return null; - annss = (Annotation[][]) f.get(tr); + annss = (Annotation[][]) Permit.get(f, tr); if (annss == null) return null; return annss[annss.length - 1]; } catch (Throwable t) { @@ -411,7 +393,9 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { private Collection<EclipseNode> buildFields(FieldDeclaration[] children, Annotation[][] annotations) { List<EclipseNode> childNodes = new ArrayList<EclipseNode>(); - if (children != null) for (int i = 0; i < children.length; i++) addIfNotNull(childNodes, buildField(children[i], annotations[i])); + if (children != null) for (int i = 0; i < children.length; i++) { + addIfNotNull(childNodes, buildField(children[i], annotations[i])); + } return childNodes; } @@ -422,7 +406,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { } private EclipseNode buildField(FieldDeclaration field, Annotation[] annotations) { - if (field instanceof Initializer) return buildInitializer((Initializer)field); + if (field instanceof Initializer) return buildInitializer((Initializer) field); if (setAndGetAsHandled(field)) return null; List<EclipseNode> childNodes = new ArrayList<EclipseNode>(); addIfNotNull(childNodes, buildTypeUse(field.type)); diff --git a/src/core/lombok/eclipse/EclipseNode.java b/src/core/lombok/eclipse/EclipseNode.java index 361a8d42..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 diff --git a/src/core/lombok/eclipse/HandlerLibrary.java b/src/core/lombok/eclipse/HandlerLibrary.java index 0e72fb38..8d69325e 100644 --- a/src/core/lombok/eclipse/HandlerLibrary.java +++ b/src/core/lombok/eclipse/HandlerLibrary.java @@ -23,7 +23,7 @@ package lombok.eclipse; import static lombok.eclipse.Eclipse.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; -import static lombok.eclipse.EclipseAugments.ASTNode_handled; +import static lombok.eclipse.EcjAugments.ASTNode_handled; import java.io.IOException; import java.lang.annotation.Annotation; diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index c70e4e5c..defe8d34 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2020 The Project Lombok Authors. + * Copyright (C) 2009-2021 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.*; import static lombok.eclipse.Eclipse.*; -import static lombok.eclipse.EclipseAugments.*; +import static lombok.eclipse.EcjAugments.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.EclipseReflectiveMembers.*; import java.lang.reflect.Array; @@ -39,6 +39,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; @@ -94,6 +95,7 @@ import org.eclipse.jdt.internal.compiler.ast.TypeParameter; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; @@ -121,10 +123,10 @@ import lombok.core.configuration.TypeName; import lombok.core.debug.ProblemReporter; import lombok.core.handlers.HandlerUtil; import lombok.core.handlers.HandlerUtil.FieldAccess; +import lombok.eclipse.EcjAugments; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAST; import lombok.eclipse.EclipseNode; -import lombok.eclipse.Java14Bits; import lombok.experimental.Accessors; import lombok.experimental.Tolerate; import lombok.permit.Permit; @@ -289,9 +291,7 @@ public class EclipseHandlerUtil { MarkerAnnotation ann = new MarkerAnnotation(copyType(annotation.type, source), pS); setGeneratedBy(ann, source); ann.declarationSourceEnd = ann.sourceEnd = ann.statementEnd = pE; - try { - reflectSet(ANNOTATION__MEMBER_VALUE_PAIR_NAME, ann, reflect(ANNOTATION__MEMBER_VALUE_PAIR_NAME, annotation)); - } catch (Exception ignore) { /* Various eclipse versions don't have it */ } + copyMemberValuePairName(ann, annotation); return ann; } @@ -300,9 +300,7 @@ public class EclipseHandlerUtil { setGeneratedBy(ann, source); ann.declarationSourceEnd = ann.sourceEnd = ann.statementEnd = pE; ann.memberValue = copyAnnotationMemberValue(((SingleMemberAnnotation) annotation).memberValue); - try { - reflectSet(ANNOTATION__MEMBER_VALUE_PAIR_NAME, ann, reflect(ANNOTATION__MEMBER_VALUE_PAIR_NAME, annotation)); - } catch (Exception ignore) { /* Various eclipse versions don't have it */ } + copyMemberValuePairName(ann, annotation); return ann; } @@ -318,15 +316,21 @@ public class EclipseHandlerUtil { for (int i = 0; i < inPairs.length; i++) ann.memberValuePairs[i] = new MemberValuePair(inPairs[i].name, inPairs[i].sourceStart, inPairs[i].sourceEnd, copyAnnotationMemberValue(inPairs[i].value)); } - try { - reflectSet(ANNOTATION__MEMBER_VALUE_PAIR_NAME, ann, reflect(ANNOTATION__MEMBER_VALUE_PAIR_NAME, annotation)); - } catch (Exception ignore) { /* Various eclipse versions don't have it */ } + copyMemberValuePairName(ann, annotation); return ann; } return annotation; } + private static void copyMemberValuePairName(Annotation source, Annotation target) { + if (ANNOTATION__MEMBER_VALUE_PAIR_NAME == null) return; + + try { + reflectSet(ANNOTATION__MEMBER_VALUE_PAIR_NAME, source, reflect(ANNOTATION__MEMBER_VALUE_PAIR_NAME, target)); + } catch (Exception ignore) { /* Various eclipse versions don't have it */ } + } + static class EclipseReflectiveMembers { public static final Field STRING_LITERAL__LINE_NUMBER; public static final Field ANNOTATION__MEMBER_VALUE_PAIR_NAME; @@ -372,7 +376,7 @@ public class EclipseHandlerUtil { private static Class<?> getClass(String fqn) { try { return Class.forName(fqn); - } catch (Exception e) { + } catch (Throwable t) { return null; } } @@ -380,7 +384,7 @@ public class EclipseHandlerUtil { private static Field getField(Class<?> c, String fName) { try { return Permit.getField(c, fName); - } catch (Exception e) { + } catch (Throwable t) { return null; } } @@ -775,10 +779,9 @@ public class EclipseHandlerUtil { public static boolean hasNonNullAnnotations(EclipseNode node) { for (EclipseNode child : node.down()) { - if (child.getKind() == Kind.ANNOTATION) { - Annotation annotation = (Annotation) child.get(); - for (String bn : NONNULL_ANNOTATIONS) if (typeMatches(bn, node, annotation.type)) return true; - } + 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; } @@ -1873,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; } } @@ -1889,24 +1889,19 @@ public class EclipseHandlerUtil { } /** - * Checks if there is a constructor generated by lombok. + * Checks if there is at least one constructor that is generated by lombok. * * @param node Any node that represents the Type (TypeDeclaration) to look in, or any child node thereof. */ public static boolean lombokConstructorExists(EclipseNode node) { node = upToTypeNode(node); if (node != null && node.get() instanceof TypeDeclaration) { - TypeDeclaration typeDecl = (TypeDeclaration)node.get(); + TypeDeclaration typeDecl = (TypeDeclaration) node.get(); if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) { - if (def instanceof ConstructorDeclaration) { - if ((def.bits & (ASTNode.IsDefaultConstructor | Java14Bits.IsCanonicalConstructor)) != 0) continue; - - if (isTolerate(node, def)) continue; - - if (getGeneratedBy(def) != null) { - return true; - } - } + if (!(def instanceof ConstructorDeclaration)) continue; + if ((def.bits & ASTNode.IsDefaultConstructor | IsCanonicalConstructor) != 0) continue; + if (isTolerate(node, def)) continue; + if (getGeneratedBy(def) != null) return true; } } @@ -2331,18 +2326,10 @@ public class EclipseHandlerUtil { public static IntLiteral makeIntLiteral(char[] token, ASTNode source) { int pS = source == null ? 0 : source.sourceStart, pE = source == null ? 0 : source.sourceEnd; IntLiteral result; - try { - if (intLiteralConstructor != null) { - result = intLiteralConstructor.newInstance(token, pS, pE); - } else { - result = (IntLiteral) intLiteralFactoryMethod.invoke(null, token, pS, pE); - } - } catch (InvocationTargetException e) { - throw Lombok.sneakyThrow(e.getCause()); - } catch (IllegalAccessException e) { - throw Lombok.sneakyThrow(e); - } catch (InstantiationException e) { - throw Lombok.sneakyThrow(e); + if (intLiteralConstructor != null) { + result = Permit.newInstanceSneaky(intLiteralConstructor, token, pS, pE); + } else { + result = (IntLiteral) Permit.invokeSneaky(intLiteralFactoryMethod, null, token, pS, pE); } if (source != null) setGeneratedBy(result, source); @@ -2496,18 +2483,7 @@ public class EclipseHandlerUtil { } public static NameReference createNameReference(String name, Annotation source) { - int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long)pS << 32 | pE; - - char[][] nameTokens = fromQualifiedName(name); - long[] pos = new long[nameTokens.length]; - Arrays.fill(pos, p); - - QualifiedNameReference nameReference = new QualifiedNameReference(nameTokens, pos, pS, pE); - nameReference.statementEnd = pE; - - setGeneratedBy(nameReference, source); - return nameReference; + return generateQualifiedNameRef(source, fromQualifiedName(name)); } private static long[] copy(long[] array) { @@ -2662,39 +2638,57 @@ public class EclipseHandlerUtil { return ref; } - static boolean isClass(EclipseNode typeNode) { - return isClassAndDoesNotHaveFlags(typeNode, ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation | Java14Bits.AccRecord); + public static TypeReference createTypeReference(String typeName, ASTNode source) { + return generateQualifiedTypeRef(source, fromQualifiedName(typeName)); } - static boolean isClassOrEnum(EclipseNode typeNode) { - return isClassAndDoesNotHaveFlags(typeNode, ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | Java14Bits.AccRecord); + /** + * 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); } - public static boolean isClassAndDoesNotHaveFlags(EclipseNode typeNode, long flags) { + /** + * 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 & flags) == 0; + return (modifiers & AccRecord) != 0; } - public static boolean isRecord(EclipseNode typeNode) { - return typeNode.getKind() == Kind.TYPE && isRecord((TypeDeclaration) typeNode.get()); + /** + * 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; } - public static boolean isRecord(TypeDeclaration typeDeclaration) { - return (typeDeclaration.modifiers & Java14Bits.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 boolean isRecordField(EclipseNode fieldNode) { - return fieldNode.getKind() == Kind.FIELD && (((FieldDeclaration) fieldNode.get()).modifiers & Java14Bits.AccRecord) != 0; - } - public static AbstractVariableDeclaration[] getRecordComponents(TypeDeclaration typeDeclaration) { - if (!isRecord(typeDeclaration)) return null; + if (typeDeclaration == null || (typeDeclaration.modifiers & AccRecord) == 0) return null; try { return (AbstractVariableDeclaration[]) TYPE_DECLARATION_RECORD_COMPONENTS.get(typeDeclaration); } catch (Exception e) { - // Ignore + // This presumably means this isn't a JDK16 - fall through. } return null; } @@ -2707,11 +2701,154 @@ public class EclipseHandlerUtil { if (recordComponents != null) { int j = 0; for (int i = 0; i < typeDeclaration.fields.length; i++) { - if ((typeDeclaration.fields[i].modifiers & Java14Bits.AccRecord) != 0) { + 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) { + FieldDeclaration fieldDeclaration = (FieldDeclaration) node; + char[] rawContent = CharOperation.subarray(compilationUnit.getContents(), fieldDeclaration.declarationSourceStart, fieldDeclaration.declarationSourceEnd); + String rawContentString = new String(rawContent); + int startIndex = rawContentString.indexOf("/**"); + int endIndex = rawContentString.indexOf("*/"); + if (startIndex != -1 && endIndex != -1) { + /* Remove all leading asterisks */ + return rawContentString.substring(startIndex + 3, endIndex).replaceAll("(?m)^\\s*\\* ?", "").trim(); + } + } + return null; + } + + public static void setDocComment(CompilationUnitDeclaration cud, EclipseNode eclipseNode, String doc) { + setDocComment(cud, (TypeDeclaration) upToTypeNode(eclipseNode).get(), eclipseNode.get(), doc); + } + + public static void setDocComment(CompilationUnitDeclaration cud, TypeDeclaration type, ASTNode node, String doc) { + if (doc == null) return; + + Map<String, String> docs = EcjAugments.CompilationUnit_javadoc.setIfAbsent(cud.compilationResult.compilationUnit, new HashMap<String, String>()); + if (node instanceof AbstractMethodDeclaration) { + AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) node; + String signature = getSignature(type, methodDeclaration); + /* Add javadoc start marker, remove trailing line break, add leading asterisks to each line, add javadoc end marker */ + docs.put(signature, String.format("/**%n%s%n */", doc.replaceAll("$\\r?\\n", "").replaceAll("(?m)^", " * "))); + } + } + + public static String getSignature(TypeDeclaration type, AbstractMethodDeclaration methodDeclaration) { + StringBuilder sb = new StringBuilder(); + sb.append(type.name); + sb.append("."); + sb.append(methodDeclaration.selector); + sb.append("("); + Argument[] arguments = methodDeclaration.arguments; + if (arguments != null) { + for (Argument argument : arguments) { + sb.append(String.valueOf(argument.type)); + } + } + sb.append(")"); + return sb.toString(); + } + + public static enum CopyJavadoc { + VERBATIM { + @Override public String apply(final CompilationUnitDeclaration cu, final EclipseNode node) { + return getDocComment(cu, node.get()); + } + }, + GETTER { + @Override public String apply(final CompilationUnitDeclaration cu, final EclipseNode node) { + final ASTNode n = node.get(); + String javadoc = getDocComment(cu, n); + // step 1: Check if there is a 'GETTER' section. If yes, that becomes the new method's javadoc. + String out = getJavadocSection(javadoc, "GETTER"); + final boolean sectionBased = out != null; + if (!sectionBased) { + out = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), JavadocTag.PARAM); + } + return out; + } + }, + SETTER { + @Override public String apply(final CompilationUnitDeclaration cu, final EclipseNode node) { + return applySetter(cu, node, "SETTER"); + } + }, + WITH { + @Override public String apply(final CompilationUnitDeclaration cu, final EclipseNode node) { + return addReturnsUpdatedSelfIfNeeded(applySetter(cu, node, "WITH|WITHER")); + } + }, + WITH_BY { + @Override public String apply(final CompilationUnitDeclaration cu, final EclipseNode node) { + return applySetter(cu, node, "WITHBY|WITH_BY"); + } + }; + + public abstract String apply(final CompilationUnitDeclaration cu, final EclipseNode node); + + private static String applySetter(final CompilationUnitDeclaration cu, EclipseNode node, String sectionName) { + final ASTNode n = node.get(); + String javadoc = getDocComment(cu, n); + // step 1: Check if there is a 'SETTER' section. If yes, that becomes the new method's javadoc. + String out = getJavadocSection(javadoc, sectionName); + final boolean sectionBased = out != null; + if (!sectionBased) { + out = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), JavadocTag.RETURN); + } + return shouldReturnThis(node) ? addReturnsThisIfNeeded(out) : out; + } + } + + /** + * Copies javadoc on one node to the other. + * + * This one is a shortcut for {@link EclipseHandlerUtil#copyJavadoc(EclipseNode, ASTNode, TypeDeclaration, CopyJavadoc, boolean)} + * if source and target node are in the same type. + */ + public static void copyJavadoc(EclipseNode from, ASTNode to, CopyJavadoc copyMode) { + copyJavadoc(from, to, (TypeDeclaration) upToTypeNode(from).get(), copyMode, false); + } + + /** + * Copies javadoc on one node to the other. + * + * This one is a shortcut for {@link EclipseHandlerUtil#copyJavadoc(EclipseNode, ASTNode, TypeDeclaration, CopyJavadoc, boolean)} + * if source and target node are in the same type. + */ + public static void copyJavadoc(EclipseNode from, ASTNode to, CopyJavadoc copyMode, boolean forceAddReturn) { + copyJavadoc(from, to, (TypeDeclaration) upToTypeNode(from).get(), copyMode, forceAddReturn); + } + + public static void copyJavadoc(EclipseNode from, ASTNode to, TypeDeclaration type, CopyJavadoc copyMode) { + copyJavadoc(from, to, type, copyMode, false); + } + + /** + * Copies javadoc on one node to the other. + * + * in 'GETTER' copyMode, first a 'GETTER' segment is searched for. If it exists, that will become the javadoc for the 'to' node, and this section is + * stripped out of the 'from' node. If no 'GETTER' segment is found, then the entire javadoc is taken minus any {@code @param} lines and other sections. + * any {@code @return} lines are stripped from 'from'. + * + * in 'SETTER' mode, stripping works similarly to 'GETTER' mode, except {@code param} are copied and stripped from the original and {@code @return} are skipped. + */ + public static void copyJavadoc(EclipseNode from, ASTNode to, TypeDeclaration type, CopyJavadoc copyMode, boolean forceAddReturn) { + if (copyMode == null) copyMode = CopyJavadoc.VERBATIM; + try { + CompilationUnitDeclaration cud = ((CompilationUnitDeclaration) from.top().get()); + String newJavadoc = copyMode.apply(cud, from); + if (forceAddReturn) { + newJavadoc = addReturnsThisIfNeeded(newJavadoc); + } + setDocComment(cud, type, to, newJavadoc); + } catch (Exception ignore) {} + } } diff --git a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java index 85243ec1..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 @@ -68,6 +68,7 @@ import lombok.core.SpiLoadUtil; import lombok.core.TypeLibrary; import lombok.core.configuration.CheckerFrameworkVersion; import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.HandleBuilder.BuilderJob; public class EclipseSingularsRecipes { public interface TypeReferenceMaker { @@ -258,20 +259,20 @@ public class EclipseSingularsRecipes { * If you need more control over the return type and value, use * {@link #generateMethods(SingularData, boolean, EclipseNode, boolean, TypeReferenceMaker, StatementMaker)}. */ - public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, final EclipseNode builderType, boolean fluent, final boolean chain, AccessLevel access) { + public void generateMethods(final BuilderJob job, SingularData data, boolean deprecate) { TypeReferenceMaker returnTypeMaker = new TypeReferenceMaker() { @Override public TypeReference make() { - return chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); + return job.oldChain ? cloneSelfType(job.builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); } }; StatementMaker returnStatementMaker = new StatementMaker() { @Override public ReturnStatement make() { - return chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; + return job.oldChain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; } }; - generateMethods(cfv, data, deprecate, builderType, fluent, returnTypeMaker, returnStatementMaker, access); + generateMethods(job.checkerFramework, data, deprecate, job.builderType, job.oldFluent, returnTypeMaker, returnStatementMaker, job.accessInners); } /** @@ -450,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 5054703a..c2b73988 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 @@ -21,11 +21,10 @@ */ package lombok.eclipse.handlers; -import static lombok.eclipse.Eclipse.*; import static lombok.core.handlers.HandlerUtil.*; +import static lombok.eclipse.Eclipse.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -75,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; @@ -84,27 +82,38 @@ import lombok.ConfigurationKeys; import lombok.Singular; import lombok.ToString; import lombok.core.AST.Kind; -import lombok.core.handlers.HandlerUtil; -import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.core.configuration.CheckerFrameworkVersion; +import lombok.core.handlers.HandlerUtil; +import lombok.core.handlers.HandlerUtil.FieldAccess; +import lombok.core.handlers.InclusionExclusionUtils.Included; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseHandlerUtil.CopyJavadoc; import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; 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(); - private static final char[] CLEAN_FIELD_NAME = "$lombokUnclean".toCharArray(); - private static final char[] CLEAN_METHOD_NAME = "$lombokClean".toCharArray(); + static final char[] CLEAN_FIELD_NAME = "$lombokUnclean".toCharArray(); + static final char[] CLEAN_METHOD_NAME = "$lombokClean".toCharArray(); + static final String TO_BUILDER_METHOD_NAME_STRING = "toBuilder"; + static final char[] TO_BUILDER_METHOD_NAME = TO_BUILDER_METHOD_NAME_STRING.toCharArray(); + static final char[] DEFAULT_PREFIX = {'$', 'd', 'e', 'f', 'a', 'u', 'l', 't', '$'}; + static final char[] SET_PREFIX = {'$', 's', 'e', 't'}; + static final char[] VALUE_PREFIX = {'$', 'v', 'a', 'l', 'u', 'e'}; + static final char[] BUILDER_TEMP_VAR = {'b', 'u', 'i', 'l', 'd', 'e', 'r'}; + static final AbstractMethodDeclaration[] EMPTY_METHODS = {}; + static final String TO_BUILDER_NOT_SUPPORTED = "@Builder(toBuilder=true) is only supported if you return your own type."; private static final boolean toBoolean(Object expr, boolean defaultValue) { if (expr == null) return defaultValue; @@ -113,6 +122,95 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return ((Boolean) expr).booleanValue(); } + static class BuilderJob { + CheckerFrameworkVersion checkerFramework; + EclipseNode parentType; + String builderMethodName, buildMethodName; + boolean isStatic; + TypeParameter[] typeParams; + TypeParameter[] builderTypeParams; + ASTNode source; + EclipseNode sourceNode; + List<BuilderFieldData> builderFields; + AccessLevel accessInners, accessOuters; + boolean oldFluent, oldChain, toBuilder; + + EclipseNode builderType; + String builderClassName; + char[] builderClassNameArr; + + void setBuilderClassName(String builderClassName) { + this.builderClassName = builderClassName; + this.builderClassNameArr = builderClassName.toCharArray(); + } + + TypeParameter[] copyTypeParams() { + return EclipseHandlerUtil.copyTypeParams(typeParams, source); + } + + long getPos() { + return ((long) source.sourceStart) << 32 | source.sourceEnd; + } + + public TypeReference createBuilderTypeReference() { + return namePlusTypeParamsToTypeReference(parentType, builderClassNameArr, !isStatic, builderTypeParams, getPos()); + } + + public TypeReference createBuilderTypeReferenceForceStatic() { + return namePlusTypeParamsToTypeReference(parentType, builderClassNameArr, false, builderTypeParams, getPos()); + } + + public TypeReference createBuilderParentTypeReference() { + return namePlusTypeParamsToTypeReference(parentType, typeParams, getPos()); + } + + public EclipseNode getTopNode() { + return parentType.top(); + } + + void init(AnnotationValues<Builder> annValues, Builder ann, EclipseNode node) { + accessOuters = ann.access(); + if (accessOuters == null) accessOuters = AccessLevel.PUBLIC; + if (accessOuters == AccessLevel.NONE) { + sourceNode.addError("AccessLevel.NONE is not valid here"); + accessOuters = AccessLevel.PUBLIC; + } + accessInners = accessOuters == AccessLevel.PROTECTED ? AccessLevel.PUBLIC : accessOuters; + + // These exist just to support the 'old' lombok.experimental.Builder, which had these properties. lombok.Builder no longer has them. + oldFluent = toBoolean(annValues.getActualExpression("fluent"), true); + oldChain = toBoolean(annValues.getActualExpression("chain"), true); + + builderMethodName = ann.builderMethodName(); + buildMethodName = ann.buildMethodName(); + setBuilderClassName(fixBuilderClassName(node, ann.builderClassName())); + toBuilder = ann.toBuilder(); + + if (builderMethodName == null) builderMethodName = "builder"; + if (buildMethodName == null) buildMethodName = "build"; + } + + static String fixBuilderClassName(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; + return "*Builder"; + } + + MethodDeclaration createNewMethodDeclaration() { + return new MethodDeclaration(((CompilationUnitDeclaration) getTopNode().get()).compilationResult); + } + + String replaceBuilderClassName(char[] name) { + if (builderClassName.indexOf('*') == -1) return builderClassName; + return builderClassName.replace("*", new String(name)); + } + + String replaceBuilderClassName(String name) { + return builderClassName.replace("*", name); + } + } + static class BuilderFieldData { Annotation[] annotations; TypeReference type; @@ -147,10 +245,6 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return true; } - private static final char[] DEFAULT_PREFIX = {'$', 'd', 'e', 'f', 'a', 'u', 'l', 't', '$'}; - private static final char[] SET_PREFIX = {'$', 's', 'e', 't'}; - private static final char[] VALUE_PREFIX = {'$', 'v', 'a', 'l', 'u', 'e'}; - private static final char[] prefixWith(char[] prefix, char[] name) { char[] out = new char[prefix.length + name.length]; System.arraycopy(prefix, 0, out, 0, prefix.length); @@ -159,88 +253,65 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } @Override public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) { - handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder"); - CheckerFrameworkVersion cfv = getCheckerFrameworkVersion(annotationNode); - - long p = (long) ast.sourceStart << 32 | ast.sourceEnd; + final String BUILDER_NODE_NOT_SUPPORTED_ERR = "@Builder is only supported on classes, records, constructors, and methods."; - Builder builderInstance = annotation.getInstance(); - AccessLevel accessForOuters = builderInstance.access(); - if (accessForOuters == null) accessForOuters = AccessLevel.PUBLIC; - if (builderInstance.access() == AccessLevel.NONE) { - annotationNode.addError("AccessLevel.NONE is not valid here"); - accessForOuters = AccessLevel.PUBLIC; - } - AccessLevel accessForInners = accessForOuters == AccessLevel.PROTECTED ? AccessLevel.PUBLIC : accessForOuters; - - // These exist just to support the 'old' lombok.experimental.Builder, which had these properties. lombok.Builder no longer has them. - boolean fluent = toBoolean(annotation.getActualExpression("fluent"), true); - boolean chain = toBoolean(annotation.getActualExpression("chain"), true); + handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder"); + BuilderJob job = new BuilderJob(); + job.sourceNode = annotationNode; + job.source = ast; + job.checkerFramework = getCheckerFrameworkVersion(annotationNode); + job.isStatic = true; - String builderMethodName = builderInstance.builderMethodName(); - String buildMethodName = builderInstance.buildMethodName(); - String builderClassName = builderInstance.builderClassName(); - String toBuilderMethodName = "toBuilder"; - boolean toBuilder = builderInstance.toBuilder(); + Builder annInstance = annotation.getInstance(); + job.init(annotation, annInstance, annotationNode); List<char[]> typeArgsForToBuilder = null; - if (builderMethodName == null) builderMethodName = "builder"; - if (buildMethodName == null) buildMethodName = "build"; - if (builderClassName == null) builderClassName = ""; - boolean generateBuilderMethod; - if (builderMethodName.isEmpty()) { + if (job.builderMethodName.isEmpty()) { generateBuilderMethod = false; - } else if (!checkName("builderMethodName", builderMethodName, annotationNode)) { + } else if (!checkName("builderMethodName", job.builderMethodName, annotationNode)) { return; } else { generateBuilderMethod = true; } - if (!checkName("buildMethodName", buildMethodName, annotationNode)) return; - if (!builderClassName.isEmpty()) { - if (!checkName("builderClassName", builderClassName, annotationNode)) return; - } + if (!checkName("buildMethodName", job.buildMethodName, annotationNode)) return; EclipseNode parent = annotationNode.up(); - List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>(); - TypeReference returnType; - TypeParameter[] typeParams; - TypeReference[] thrownExceptions; - char[] nameOfStaticBuilderMethod; - EclipseNode tdParent; + job.builderFields = new ArrayList<BuilderFieldData>(); + TypeReference buildMethodReturnType; + TypeReference[] buildMethodThrownExceptions; + char[] nameOfBuilderMethod; EclipseNode fillParametersFrom = parent.get() instanceof AbstractMethodDeclaration ? parent : null; boolean addCleaning = false; - boolean isStatic = true; List<EclipseNode> nonFinalNonDefaultedFields = null; - if (builderClassName.isEmpty()) builderClassName = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME); - if (builderClassName == null || builderClassName.isEmpty()) builderClassName = "*Builder"; - boolean replaceNameInBuilderClassName = builderClassName.contains("*"); - if (parent.get() instanceof TypeDeclaration) { - tdParent = parent; - TypeDeclaration td = (TypeDeclaration) tdParent.get(); + if (!isClass(parent) && !isRecord(parent)) { + annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR); + return; + } + + job.parentType = parent; + TypeDeclaration td = (TypeDeclaration) parent.get(); List<EclipseNode> allFields = new ArrayList<EclipseNode>(); boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent)); - for (EclipseNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) { + for (EclipseNode fieldNode : HandleConstructor.findAllFields(parent, true)) { FieldDeclaration fd = (FieldDeclaration) fieldNode.get(); EclipseNode isDefault = findAnnotation(Builder.Default.class, fieldNode); boolean isFinal = ((fd.modifiers & ClassFileConstants.AccFinal) != 0) || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode)); - Annotation[] copyableAnnotations = findCopyableAnnotations(fieldNode); - BuilderFieldData bfd = new BuilderFieldData(); bfd.rawName = fieldNode.getName().toCharArray(); bfd.name = removePrefixFromField(fieldNode); bfd.builderFieldName = bfd.name; - bfd.annotations = copyAnnotations(fd, copyableAnnotations); + bfd.annotations = copyAnnotations(fd, findCopyableAnnotations(fieldNode)); bfd.type = fd.type; - bfd.singularData = getSingularData(fieldNode, ast, builderInstance.setterPrefix()); + bfd.singularData = getSingularData(fieldNode, ast, annInstance.setterPrefix()); bfd.originalFieldNode = fieldNode; if (bfd.singularData != null && isDefault != null) { @@ -265,24 +336,26 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { bfd.builderFieldName = prefixWith(bfd.name, VALUE_PREFIX); MethodDeclaration md = generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast); - if (md != null) injectMethod(tdParent, md); + if (md != null) injectMethod(parent, md); } addObtainVia(bfd, fieldNode); - builderFields.add(bfd); + job.builderFields.add(bfd); allFields.add(fieldNode); } - if (!isRecord(tdParent)) { - handleConstructor.generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER, + 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); } - returnType = namePlusTypeParamsToTypeReference(tdParent, td.typeParameters, p); - typeParams = td.typeParameters; - thrownExceptions = null; - nameOfStaticBuilderMethod = null; - if (replaceNameInBuilderClassName) builderClassName = builderClassName.replace("*", new String(td.name)); - replaceNameInBuilderClassName = false; + job.typeParams = job.builderTypeParams = td.typeParameters; + buildMethodReturnType = job.createBuilderParentTypeReference(); + buildMethodThrownExceptions = null; + nameOfBuilderMethod = null; + job.setBuilderClassName(job.replaceBuilderClassName(td.name)); + if (!checkName("builderClassName", job.builderClassName, annotationNode)) return; } else if (parent.get() instanceof ConstructorDeclaration) { ConstructorDeclaration cd = (ConstructorDeclaration) parent.get(); if (cd.typeParameters != null && cd.typeParameters.length > 0) { @@ -290,21 +363,20 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return; } - tdParent = parent.up(); - TypeDeclaration td = (TypeDeclaration) tdParent.get(); - returnType = namePlusTypeParamsToTypeReference(tdParent, td.typeParameters, p); - typeParams = td.typeParameters; - thrownExceptions = cd.thrownExceptions; - nameOfStaticBuilderMethod = null; - if (replaceNameInBuilderClassName) builderClassName = builderClassName.replace("*", new String(cd.selector)); - replaceNameInBuilderClassName = false; + job.parentType = parent.up(); + TypeDeclaration td = (TypeDeclaration) job.parentType.get(); + job.typeParams = job.builderTypeParams = td.typeParameters; + buildMethodReturnType = job.createBuilderParentTypeReference(); + buildMethodThrownExceptions = cd.thrownExceptions; + nameOfBuilderMethod = null; + job.setBuilderClassName(job.replaceBuilderClassName(cd.selector)); + if (!checkName("builderClassName", job.builderClassName, annotationNode)) return; } else if (parent.get() instanceof MethodDeclaration) { MethodDeclaration md = (MethodDeclaration) parent.get(); - tdParent = parent.up(); - isStatic = md.isStatic(); + job.parentType = parent.up(); + job.isStatic = md.isStatic(); - if (toBuilder) { - final String TO_BUILDER_NOT_SUPPORTED = "@Builder(toBuilder=true) is only supported if you return your own type."; + if (job.toBuilder) { char[] token; char[][] pkg = null; if (md.returnType.dimensions() > 0) { @@ -330,12 +402,12 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return; } - if (tdParent == null || !equals(tdParent.getName(), token)) { + if (job.parentType == null || !equals(job.parentType.getName(), token)) { annotationNode.addError(TO_BUILDER_NOT_SUPPORTED); return; } - TypeParameter[] tpOnType = ((TypeDeclaration) tdParent.get()).typeParameters; + TypeParameter[] tpOnType = ((TypeDeclaration) job.parentType.get()).typeParameters; TypeParameter[] tpOnMethod = md.typeParameters; TypeReference[][] tpOnRet_ = null; if (md.returnType instanceof ParameterizedSingleTypeReference) { @@ -374,18 +446,18 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } } - returnType = copyType(md.returnType, ast); - typeParams = md.typeParameters; - thrownExceptions = md.thrownExceptions; - nameOfStaticBuilderMethod = md.selector; - if (replaceNameInBuilderClassName) { - char[] token = returnTypeToBuilderClassName(annotationNode, md, typeParams); - if (token == null) - return; - builderClassName = builderClassName.replace("*", new String(token)); + job.typeParams = job.builderTypeParams = md.typeParameters; + buildMethodReturnType = copyType(md.returnType, ast); + buildMethodThrownExceptions = md.thrownExceptions; + nameOfBuilderMethod = md.selector; + if (job.builderClassName.indexOf('*') > -1) { + char[] token = returnTypeToBuilderClassName(annotationNode, md, job.typeParams); + if (token == null) return; // should not happen. + job.setBuilderClassName(job.replaceBuilderClassName(token)); + 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; } @@ -402,40 +474,39 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { bfd.builderFieldName = bfd.name; bfd.annotations = copyAnnotations(arg, copyableAnnotations); bfd.type = arg.type; - bfd.singularData = getSingularData(param, ast, builderInstance.setterPrefix()); + bfd.singularData = getSingularData(param, ast, annInstance.setterPrefix()); bfd.originalFieldNode = param; addObtainVia(bfd, param); - builderFields.add(bfd); + job.builderFields.add(bfd); } } - EclipseNode builderType = findInnerClass(tdParent, builderClassName); - if (builderType == null) { - builderType = makeBuilderClass(isStatic, tdParent, builderClassName, typeParams, ast, accessForOuters); - } else { - TypeDeclaration builderTypeDeclaration = (TypeDeclaration) builderType.get(); - if (isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) == 0) { + job.builderType = findInnerClass(job.parentType, job.builderClassName); + if (job.builderType == null) makeBuilderClass(job); + else { + TypeDeclaration builderTypeDeclaration = (TypeDeclaration) job.builderType.get(); + if (job.isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) == 0) { annotationNode.addError("Existing Builder must be a static inner class."); return; - } else if (!isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) != 0) { + } else if (!job.isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) != 0) { annotationNode.addError("Existing Builder must be a non-static inner class."); return; } - sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode); + sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderType, annotationNode); /* generate errors for @Singular BFDs that have one already defined node. */ { - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { SingularData sd = bfd.singularData; if (sd == null) continue; EclipseSingularizer singularizer = sd.getSingularizer(); if (singularizer == null) continue; - if (singularizer.checkForAlreadyExistingNodesAndGenerateError(builderType, sd)) { + if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderType, sd)) { bfd.singularData = null; } } } } - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { if (bfd.singularData.getSingularizer().requiresCleaning()) { addCleaning = true; @@ -454,64 +525,64 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } } - generateBuilderFields(builderType, builderFields, ast); + generateBuilderFields(job); if (addCleaning) { FieldDeclaration cleanDecl = new FieldDeclaration(CLEAN_FIELD_NAME, 0, -1); cleanDecl.declarationSourceEnd = -1; cleanDecl.modifiers = ClassFileConstants.AccPrivate; cleanDecl.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); cleanDecl.traverse(new SetGeneratedByVisitor(ast), (MethodScope) null); - injectFieldAndMarkGenerated(builderType, cleanDecl); + injectFieldAndMarkGenerated(job.builderType, cleanDecl); } - if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) { + if (constructorExists(job.builderType) == MemberExistsResult.NOT_EXISTS) { ConstructorDeclaration cd = HandleConstructor.createConstructor( - AccessLevel.PACKAGE, builderType, Collections.<EclipseNode>emptyList(), false, + AccessLevel.PACKAGE, job.builderType, Collections.<EclipseNode>emptyList(), false, annotationNode, Collections.<Annotation>emptyList()); - if (cd != null) injectMethod(builderType, cd); + if (cd != null) injectMethod(job.builderType, cd); } - for (BuilderFieldData bfd : builderFields) { - makePrefixedSetterMethodsForBuilder(cfv, builderType, bfd, annotationNode, fluent, chain, accessForInners, bfd.originalFieldNode, builderInstance.setterPrefix()); + for (BuilderFieldData bfd : job.builderFields) { + makePrefixedSetterMethodsForBuilder(job, bfd, annInstance.setterPrefix()); } { - MemberExistsResult methodExists = methodExists(buildMethodName, builderType, -1); - if (methodExists == MemberExistsResult.EXISTS_BY_LOMBOK) methodExists = methodExists(buildMethodName, builderType, 0); + MemberExistsResult methodExists = methodExists(job.buildMethodName, job.builderType, -1); + if (methodExists == MemberExistsResult.EXISTS_BY_LOMBOK) methodExists = methodExists(job.buildMethodName, job.builderType, 0); if (methodExists == MemberExistsResult.NOT_EXISTS) { - MethodDeclaration md = generateBuildMethod(cfv, tdParent, isStatic, buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast, accessForInners); - if (md != null) injectMethod(builderType, md); + MethodDeclaration md = generateBuildMethod(job, nameOfBuilderMethod, buildMethodReturnType, buildMethodThrownExceptions, addCleaning); + if (md != null) injectMethod(job.builderType, md); } } - if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) { + if (methodExists("toString", job.builderType, 0) == MemberExistsResult.NOT_EXISTS) { List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { for (EclipseNode f : bfd.createdFields) { fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true, false)); } } - MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, false, ast, FieldAccess.ALWAYS_FIELD); - if (md != null) injectMethod(builderType, md); + MethodDeclaration md = HandleToString.createToString(job.builderType, fieldNodes, true, false, ast, FieldAccess.ALWAYS_FIELD); + if (md != null) injectMethod(job.builderType, md); } if (addCleaning) { - MethodDeclaration cleanMethod = generateCleanMethod(builderFields, builderType, ast); - if (cleanMethod != null) injectMethod(builderType, cleanMethod); + MethodDeclaration cleanMethod = generateCleanMethod(job); + if (cleanMethod != null) injectMethod(job.builderType, cleanMethod); } - if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; + if (generateBuilderMethod && methodExists(job.builderMethodName, job.parentType, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; if (generateBuilderMethod) { - MethodDeclaration md = generateBuilderMethod(cfv, isStatic, builderMethodName, builderClassName, tdParent, typeParams, ast, accessForOuters); - if (md != null) injectMethod(tdParent, md); + MethodDeclaration md = generateBuilderMethod(job); + if (md != null) injectMethod(job.parentType, md); } - if (toBuilder) switch (methodExists(toBuilderMethodName, tdParent, 0)) { + if (job.toBuilder) switch (methodExists(TO_BUILDER_METHOD_NAME_STRING, job.parentType, 0)) { case EXISTS_BY_USER: annotationNode.addWarning("Not generating toBuilder() as it already exists."); break; case NOT_EXISTS: - TypeParameter[] tps = typeParams; + TypeParameter[] tps = job.typeParams; if (typeArgsForToBuilder != null) { tps = new TypeParameter[typeArgsForToBuilder.size()]; for (int i = 0; i < tps.length; i++) { @@ -519,9 +590,9 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { tps[i].name = typeArgsForToBuilder.get(i); } } - MethodDeclaration md = generateToBuilderMethod(cfv, isStatic, toBuilderMethodName, builderClassName, tdParent, tps, builderFields, fluent, ast, accessForOuters, builderInstance.setterPrefix()); + MethodDeclaration md = generateToBuilderMethod(job, tps, annInstance.setterPrefix()); - if (md != null) injectMethod(tdParent, md); + if (md != null) injectMethod(job.parentType, md); } if (nonFinalNonDefaultedFields != null && generateBuilderMethod) { @@ -530,7 +601,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } } } - + static char[] returnTypeToBuilderClassName(EclipseNode annotationNode, MethodDeclaration md, TypeParameter[] typeParams) { char[] token; if (md.returnType instanceof QualifiedTypeReference) { @@ -560,26 +631,31 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return token; } - private static final char[] BUILDER_TEMP_VAR = {'b', 'u', 'i', 'l', 'd', 'e', 'r'}; - private MethodDeclaration generateToBuilderMethod(CheckerFrameworkVersion cfv, boolean isStatic, String methodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, List<BuilderFieldData> builderFields, boolean fluent, ASTNode source, AccessLevel access, String prefix) { - int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long) pS << 32 | pE; + private MethodDeclaration generateToBuilderMethod(BuilderJob job, TypeParameter[] typeParameters, String prefix) { + int pS = job.source.sourceStart, pE = job.source.sourceEnd; + long p = job.getPos(); - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); - out.selector = methodName.toCharArray(); - out.modifiers = toEclipseModifier(access); + MethodDeclaration out = job.createNewMethodDeclaration(); + out.selector = TO_BUILDER_METHOD_NAME; + out.modifiers = toEclipseModifier(job.accessOuters); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - out.returnType = namePlusTypeParamsToTypeReference(type, builderClassName.toCharArray(), !isStatic, typeParams, p); + + out.returnType = job.createBuilderTypeReference(); + if (job.checkerFramework.generateUnique()) { + int len = out.returnType.getTypeName().length; + out.returnType.annotations = new Annotation[len][]; + out.returnType.annotations[len - 1] = new Annotation[] {generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__UNIQUE)}; + } AllocationExpression invoke = new AllocationExpression(); - invoke.type = namePlusTypeParamsToTypeReference(type, builderClassName.toCharArray(), !isStatic, typeParams, p); + invoke.type = job.createBuilderTypeReference(); Expression receiver = invoke; List<Statement> preStatements = null; List<Statement> postStatements = null; - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { String setterName = new String(bfd.name); - String setterPrefix = !prefix.isEmpty() ? prefix : fluent ? "" : "set"; + String setterPrefix = !prefix.isEmpty() ? prefix : job.oldFluent ? "" : "set"; if (!setterPrefix.isEmpty()) setterName = HandlerUtil.buildAccessorName(setterPrefix, setterName); MessageSend ms = new MessageSend(); @@ -597,13 +673,13 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { boolean obtainIsStatic = bfd.obtainVia.isStatic(); MessageSend obtainExpr = new MessageSend(); if (obtainIsStatic) { - if (typeParams != null && typeParams.length > 0) { - obtainExpr.typeArguments = new TypeReference[typeParams.length]; - for (int j = 0; j<typeParams.length; j++) { - obtainExpr.typeArguments[j] = new SingleTypeReference(typeParams[j].name, 0); + if (typeParameters != null && typeParameters.length > 0) { + obtainExpr.typeArguments = new TypeReference[typeParameters.length]; + for (int j = 0; j < typeParameters.length; j++) { + obtainExpr.typeArguments[j] = new SingleTypeReference(typeParameters[j].name, 0); } } - obtainExpr.receiver = generateNameReference(type, 0); + obtainExpr.receiver = generateNameReference(job.parentType, 0); } else { obtainExpr.receiver = new ThisReference(0, 0); } @@ -616,7 +692,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { // for ecj so we match what javac's handler does. LocalDeclaration ld = new LocalDeclaration(bfd.name, 0, 0); ld.modifiers = ClassFileConstants.AccFinal; - ld.type = EclipseHandlerUtil.copyType(bfd.type, source); + ld.type = EclipseHandlerUtil.copyType(bfd.type, job.source); ld.initialization = obtainExpr; if (preStatements == null) preStatements = new ArrayList<Statement>(); preStatements.add(ld); @@ -645,7 +721,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { LocalDeclaration b = new LocalDeclaration(BUILDER_TEMP_VAR, pS, pE); out.statements[preSs] = b; b.modifiers |= ClassFileConstants.AccFinal; - b.type = namePlusTypeParamsToTypeReference(type, builderClassName.toCharArray(), !isStatic, typeParams, p); + b.type = job.createBuilderTypeReference(); b.type.sourceStart = pS; b.type.sourceEnd = pE; b.initialization = receiver; out.statements[preSs + postSs + 1] = new ReturnStatement(new SingleNameReference(BUILDER_TEMP_VAR, p), pS, pE); @@ -655,69 +731,81 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { out.statements[preSs] = new ReturnStatement(receiver, pS, pE); } - if (cfv.generateUnique()) { - out.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE)}; - } - - createRelevantNonNullAnnotation(type, out); - out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope); + createRelevantNonNullAnnotation(job.parentType, out); + out.traverse(new SetGeneratedByVisitor(job.source), ((TypeDeclaration) job.parentType.get()).scope); return out; } - private MethodDeclaration generateCleanMethod(List<BuilderFieldData> builderFields, EclipseNode builderType, ASTNode source) { + private MethodDeclaration generateCleanMethod(BuilderJob job) { List<Statement> statements = new ArrayList<Statement>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, builderType, statements); + bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, job.builderType, statements); } } FieldReference thisUnclean = new FieldReference(CLEAN_FIELD_NAME, 0); thisUnclean.receiver = new ThisReference(0, 0); statements.add(new Assignment(thisUnclean, new FalseLiteral(0, 0), 0)); - MethodDeclaration decl = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); + MethodDeclaration decl = job.createNewMethodDeclaration(); decl.selector = CLEAN_METHOD_NAME; decl.modifiers = ClassFileConstants.AccPrivate; decl.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; decl.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0); decl.statements = statements.toArray(new Statement[0]); - decl.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); + decl.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); return decl; } - static Receiver generateBuildReceiver(CheckerFrameworkVersion cfv, EclipseNode type, List<BuilderFieldData> builderFields, ASTNode source) { - if (!cfv.generateCalledMethods()) return null; + static Receiver generateNotCalledReceiver(BuilderJob job, String setterName) { + char[][] nameNotCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__NOT_CALLED); + SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameNotCalled, poss(job.source, nameNotCalled.length)), job.source.sourceStart); + ann.memberValue = new StringLiteral(setterName.toCharArray(), 0, 0, 0); + + TypeReference typeReference = job.createBuilderTypeReference(); + int trLen = typeReference.getTypeName().length; + typeReference.annotations = new Annotation[trLen][]; + typeReference.annotations[trLen - 1] = new Annotation[] {ann}; + return new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, 0); + } + + static Receiver generateBuildReceiver(BuilderJob job) { + if (!job.checkerFramework.generateCalledMethods()) return null; List<char[]> mandatories = new ArrayList<char[]>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData == null && bfd.nameOfSetFlag == null) mandatories.add(bfd.name); } if (mandatories.size() == 0) return null; + + int pS = job.source.sourceStart, pE = job.source.sourceEnd; + char[][] nameCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__CALLED); - SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameCalled, poss(source, nameCalled.length)), source.sourceStart); + SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameCalled, poss(job.source, nameCalled.length)), pS); if (mandatories.size() == 1) { ann.memberValue = new StringLiteral(mandatories.get(0), 0, 0, 0); } else { ArrayInitializer arr = new ArrayInitializer(); - arr.sourceStart = source.sourceStart; - arr.sourceEnd = source.sourceEnd; + arr.sourceStart = pS; + arr.sourceEnd = pE; arr.expressions = new Expression[mandatories.size()]; for (int i = 0; i < arr.expressions.length; i++) { - arr.expressions[i] = new StringLiteral(mandatories.get(i), source.sourceStart, source.sourceEnd, 0); + arr.expressions[i] = new StringLiteral(mandatories.get(i), pS, pE, 0); } ann.memberValue = arr; } - - QualifiedTypeReference typeReference = (QualifiedTypeReference) generateTypeReference(type, source.sourceStart); - typeReference.annotations = new Annotation[typeReference.tokens.length][]; - typeReference.annotations[0] = new Annotation[] {ann}; - return new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, Modifier.FINAL); + + TypeReference typeReference = job.createBuilderTypeReference(); + int len = typeReference.getTypeName().length; + typeReference.annotations = new Annotation[len][]; + typeReference.annotations[len - 1] = new Annotation[] {ann}; + return new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, 0); } - public MethodDeclaration generateBuildMethod(CheckerFrameworkVersion cfv, EclipseNode tdParent, boolean isStatic, String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source, AccessLevel access) { - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); + public MethodDeclaration generateBuildMethod(BuilderJob job, char[] staticName, TypeReference returnType, TypeReference[] thrownExceptions, boolean addCleaning) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; List<Statement> statements = new ArrayList<Statement>(); @@ -730,14 +818,14 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { statements.add(new IfStatement(notClean, invokeClean, 0, 0)); } - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, type, statements, bfd.builderFieldName, "this"); + bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, job.builderType, statements, bfd.builderFieldName, "this"); } } List<Expression> args = new ArrayList<Expression>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.nameOfSetFlag != null) { LocalDeclaration ld = new LocalDeclaration(bfd.builderFieldName, 0, 0); ld.type = copyType(bfd.type); @@ -747,11 +835,11 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { statements.add(ld); MessageSend inv = new MessageSend(); - inv.sourceStart = source.sourceStart; - inv.sourceEnd = source.sourceEnd; - inv.receiver = new SingleNameReference(((TypeDeclaration) tdParent.get()).name, 0L); + inv.sourceStart = job.source.sourceStart; + inv.sourceEnd = job.source.sourceEnd; + inv.receiver = new SingleNameReference(((TypeDeclaration) job.parentType.get()).name, 0L); inv.selector = bfd.nameOfDefaultProvider; - inv.typeArguments = typeParameterNames(((TypeDeclaration) type.get()).typeParameters); + inv.typeArguments = typeParameterNames(((TypeDeclaration) job.builderType.get()).typeParameters); Assignment defaultAssign = new Assignment(new SingleNameReference(bfd.builderFieldName, 0L), inv, 0); FieldReference thisSet = new FieldReference(bfd.nameOfSetFlag, 0L); @@ -775,8 +863,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { statements.add(new Assignment(thisUnclean, new TrueLiteral(0, 0), 0)); } - out.modifiers = toEclipseModifier(access); - out.selector = name.toCharArray(); + out.modifiers = toEclipseModifier(job.accessInners); + out.selector = job.buildMethodName.toCharArray(); out.thrownExceptions = copyTypes(thrownExceptions); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.returnType = returnType; @@ -789,13 +877,13 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } else { MessageSend invoke = new MessageSend(); invoke.selector = staticName; - if (isStatic) { - invoke.receiver = new SingleNameReference(type.up().getName().toCharArray(), 0); + if (job.isStatic) { + invoke.receiver = new SingleNameReference(job.builderType.up().getName().toCharArray(), 0); } else { - invoke.receiver = new QualifiedThisReference(generateTypeReference(type.up(), 0) , 0, 0); + invoke.receiver = new QualifiedThisReference(generateTypeReference(job.builderType.up(), 0) , 0, 0); } - invoke.typeArguments = typeParameterNames(((TypeDeclaration) type.get()).typeParameters); + invoke.typeArguments = typeParameterNames(((TypeDeclaration) job.builderType.get()).typeParameters); invoke.arguments = args.isEmpty() ? null : args.toArray(new Expression[0]); if (returnType instanceof SingleTypeReference && Arrays.equals(TypeConstants.VOID, ((SingleTypeReference) returnType).token)) { statements.add(invoke); @@ -804,12 +892,12 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } } out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]); - if (cfv.generateSideEffectFree()) { - out.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE)}; + if (job.checkerFramework.generateSideEffectFree()) { + out.annotations = new Annotation[] {generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE)}; } - out.receiver = generateBuildReceiver(cfv, type, builderFields, source); - if (staticName == null) createRelevantNonNullAnnotation(type, out); - out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); + out.receiver = generateBuildReceiver(job); + if (staticName == null) createRelevantNonNullAnnotation(job.builderType, out); + out.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); return out; } @@ -840,57 +928,55 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return out; } - public MethodDeclaration generateBuilderMethod(CheckerFrameworkVersion cfv, boolean isStatic, String builderMethodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source, AccessLevel access) { - int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long) pS << 32 | pE; - char[] builderClassName_ = builderClassName.toCharArray(); + public MethodDeclaration generateBuilderMethod(BuilderJob job) { + int pS = job.source.sourceStart, pE = job.source.sourceEnd; + long p = job.getPos(); - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); - out.selector = builderMethodName.toCharArray(); - out.modifiers = toEclipseModifier(access); - if (isStatic) out.modifiers |= ClassFileConstants.AccStatic; + MethodDeclaration out = job.createNewMethodDeclaration(); + out.selector = job.builderMethodName.toCharArray(); + out.modifiers = toEclipseModifier(job.accessOuters); + if (job.isStatic) out.modifiers |= ClassFileConstants.AccStatic; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - out.returnType = namePlusTypeParamsToTypeReference(type, builderClassName_, !isStatic, typeParams, p); - out.typeParameters = copyTypeParams(typeParams, source); + out.returnType = job.createBuilderTypeReference(); + if (job.checkerFramework.generateUnique()) { + int len = out.returnType.getTypeName().length; + out.returnType.annotations = new Annotation[len][]; + out.returnType.annotations[len - 1] = new Annotation[] {generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__UNIQUE)}; + } + out.typeParameters = job.copyTypeParams(); AllocationExpression invoke = new AllocationExpression(); - if (isStatic) { - invoke.type = namePlusTypeParamsToTypeReference(type, builderClassName_, false, typeParams, p); + if (job.isStatic) { + invoke.type = job.createBuilderTypeReferenceForceStatic(); out.statements = new Statement[] {new ReturnStatement(invoke, pS, pE)}; } else { // return this.new Builder(); QualifiedAllocationExpression qualifiedInvoke = new QualifiedAllocationExpression(); qualifiedInvoke.enclosingInstance = new ThisReference(pS, pE); - if (typeParams == null || typeParams.length == 0) { - qualifiedInvoke.type = new SingleTypeReference(builderClassName_, p); + if (job.typeParams == null || job.typeParams.length == 0) { + qualifiedInvoke.type = new SingleTypeReference(job.builderClassNameArr, p); } else { - qualifiedInvoke.type = namePlusTypeParamsToTypeReference(null, builderClassName_, false, typeParams, p); + qualifiedInvoke.type = namePlusTypeParamsToTypeReference(null, job.builderClassNameArr, false, job.typeParams, p); } out.statements = new Statement[] {new ReturnStatement(qualifiedInvoke, pS, pE)}; } - Annotation uniqueAnn = cfv.generateUnique() ? generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE) : null; - Annotation sefAnn = cfv.generateSideEffectFree() ? generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE) : null; - if (uniqueAnn != null && sefAnn != null) { - out.annotations = new Annotation[] {uniqueAnn, sefAnn}; - } else if (uniqueAnn != null) { - out.annotations = new Annotation[] {uniqueAnn}; - } else if (sefAnn != null) { - out.annotations = new Annotation[] {sefAnn}; + if (job.checkerFramework.generateSideEffectFree()) { + out.annotations = new Annotation[] {generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE)}; } - createRelevantNonNullAnnotation(type, out); - out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope); + createRelevantNonNullAnnotation(job.builderType, out); + out.traverse(new SetGeneratedByVisitor(job.source), ((TypeDeclaration) job.builderType.get()).scope); return out; } - public void generateBuilderFields(EclipseNode builderType, List<BuilderFieldData> builderFields, ASTNode source) { + public void generateBuilderFields(BuilderJob job) { List<EclipseNode> existing = new ArrayList<EclipseNode>(); - for (EclipseNode child : builderType.down()) { + for (EclipseNode child : job.builderType.down()) { if (child.getKind() == Kind.FIELD) existing.add(child); } - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, builderType)); + bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, job.builderType)); } else { EclipseNode field = null, setFlag = null; for (EclipseNode exists : existing) { @@ -904,45 +990,43 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { fd.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; fd.modifiers = ClassFileConstants.AccPrivate; fd.type = copyType(bfd.type); - fd.traverse(new SetGeneratedByVisitor(source), (MethodScope) null); - field = injectFieldAndMarkGenerated(builderType, fd); + fd.traverse(new SetGeneratedByVisitor(job.source), (MethodScope) null); + field = injectFieldAndMarkGenerated(job.builderType, fd); } if (setFlag == null && bfd.nameOfSetFlag != null) { FieldDeclaration fd = new FieldDeclaration(bfd.nameOfSetFlag, 0, 0); fd.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; fd.modifiers = ClassFileConstants.AccPrivate; fd.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); - fd.traverse(new SetGeneratedByVisitor(source), (MethodScope) null); - injectFieldAndMarkGenerated(builderType, fd); + fd.traverse(new SetGeneratedByVisitor(job.source), (MethodScope) null); + injectFieldAndMarkGenerated(job.builderType, fd); } bfd.createdFields.add(field); } } } - private static final AbstractMethodDeclaration[] EMPTY = {}; - - public void makePrefixedSetterMethodsForBuilder(CheckerFrameworkVersion cfv, EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, boolean fluent, boolean chain, AccessLevel access, EclipseNode originalFieldNode, String prefix) { + public void makePrefixedSetterMethodsForBuilder(BuilderJob job, BuilderFieldData bfd, String prefix) { boolean deprecate = isFieldDeprecated(bfd.originalFieldNode); if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) { - makePrefixedSetterMethodForBuilder(cfv, builderType, deprecate, bfd.createdFields.get(0), bfd.name, bfd.nameOfSetFlag, sourceNode, fluent, chain, bfd.annotations, access, originalFieldNode, prefix); + makePrefixedSetterMethodForBuilder(job, bfd, deprecate, prefix); } else { - bfd.singularData.getSingularizer().generateMethods(cfv, bfd.singularData, deprecate, builderType, fluent, chain, access); + bfd.singularData.getSingularizer().generateMethods(job, bfd.singularData, deprecate); } } - private void makePrefixedSetterMethodForBuilder(CheckerFrameworkVersion cfv, EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] paramName, char[] nameOfSetFlag, EclipseNode sourceNode, boolean fluent, boolean chain, Annotation[] annotations, AccessLevel access, EclipseNode originalFieldNode, String prefix) { - TypeDeclaration td = (TypeDeclaration) builderType.get(); + private void makePrefixedSetterMethodForBuilder(BuilderJob job, BuilderFieldData bfd, boolean deprecate, String prefix) { + TypeDeclaration td = (TypeDeclaration) job.builderType.get(); + EclipseNode fieldNode = bfd.createdFields.get(0); AbstractMethodDeclaration[] existing = td.methods; - if (existing == null) existing = EMPTY; + if (existing == null) existing = EMPTY_METHODS; int len = existing.length; - String setterPrefix = prefix.isEmpty() ? "set" : prefix; String setterName; - if(fluent) { - setterName = prefix.isEmpty() ? new String(paramName) : HandlerUtil.buildAccessorName(setterPrefix, new String(paramName)); + if (job.oldFluent) { + setterName = prefix.isEmpty() ? new String(bfd.name) : HandlerUtil.buildAccessorName(setterPrefix, new String(bfd.name)); } else { - setterName = HandlerUtil.buildAccessorName(setterPrefix, new String(paramName)); + setterName = HandlerUtil.buildAccessorName(setterPrefix, new String(bfd.name)); } for (int i = 0; i < len; i++) { @@ -952,34 +1036,39 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } List<Annotation> methodAnnsList = Collections.<Annotation>emptyList(); - Annotation[] methodAnns = EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); + Annotation[] methodAnns = EclipseHandlerUtil.findCopyableToSetterAnnotations(bfd.originalFieldNode); if (methodAnns != null && methodAnns.length > 0) methodAnnsList = Arrays.asList(methodAnns); - ASTNode source = sourceNode.get(); - MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, paramName, nameOfSetFlag, chain, toEclipseModifier(access), - sourceNode, methodAnnsList, annotations != null ? Arrays.asList(copyAnnotations(source, annotations)) : Collections.<Annotation>emptyList()); - if (cfv.generateCalledMethods()) { - char[][] nameNotCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__NOT_CALLED); - SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameNotCalled, poss(source, nameNotCalled.length)), source.sourceStart); - ann.memberValue = new StringLiteral(setterName.toCharArray(), 0, 0, 0); - - QualifiedTypeReference typeReference = (QualifiedTypeReference) generateTypeReference(builderType, 0); - typeReference.annotations = new Annotation[typeReference.tokens.length][]; - typeReference.annotations[0] = new Annotation[] {ann}; - setter.receiver = new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, Modifier.FINAL); + ASTNode source = job.sourceNode.get(); + MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, bfd.name, bfd.nameOfSetFlag, job.oldChain, toEclipseModifier(job.accessInners), + job.sourceNode, methodAnnsList, bfd.annotations != null ? Arrays.asList(copyAnnotations(source, bfd.annotations)) : Collections.<Annotation>emptyList()); + if (job.checkerFramework.generateCalledMethods()) setter.receiver = generateNotCalledReceiver(job, setterName); + if (job.sourceNode.up().getKind() == Kind.METHOD) { + copyJavadocFromParam(bfd.originalFieldNode.up(), setter, td, bfd.name.toString()); + } else { + copyJavadoc(bfd.originalFieldNode, setter, td, CopyJavadoc.SETTER, true); } - injectMethod(builderType, setter); + injectMethod(job.builderType, setter); + } + + private void copyJavadocFromParam(EclipseNode from, MethodDeclaration to, TypeDeclaration type, String param) { + try { + CompilationUnitDeclaration cud = (CompilationUnitDeclaration) from.top().get(); + String methodComment = getDocComment(cud, from.get()); + String newJavadoc = addReturnsThisIfNeeded(getParamJavadoc(methodComment, param)); + setDocComment(cud, type, to, newJavadoc); + } catch (Exception ignore) {} } - public EclipseNode makeBuilderClass(boolean isStatic, EclipseNode tdParent, String builderClassName, TypeParameter[] typeParams, ASTNode source, AccessLevel access) { - TypeDeclaration parent = (TypeDeclaration) tdParent.get(); + public void makeBuilderClass(BuilderJob job) { + TypeDeclaration parent = (TypeDeclaration) job.parentType.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; - builder.modifiers |= toEclipseModifier(access); - if (isStatic) builder.modifiers |= ClassFileConstants.AccStatic; - builder.typeParameters = copyTypeParams(typeParams, source); - builder.name = builderClassName.toCharArray(); - builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); - return injectType(tdParent, builder); + builder.modifiers |= toEclipseModifier(job.accessOuters); + if (job.isStatic) builder.modifiers |= ClassFileConstants.AccStatic; + builder.typeParameters = job.copyTypeParams(); + builder.name = job.builderClassNameArr; + builder.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); + job.builderType = injectType(job.parentType, builder); } private void addObtainVia(BuilderFieldData bfd, EclipseNode node) { 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 ff81b763..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(); @@ -456,14 +456,12 @@ public class HandleConstructor { constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[0]); /* Generate annotations that must be put on the generated method, and attach them. */ { - Annotation[] constructorProperties = null, checkerFramework = null; + Annotation[] constructorProperties = null; if (addConstructorProperties && !isLocalType(type)) constructorProperties = createConstructorProperties(source, fieldsToParam); - if (getCheckerFrameworkVersion(type).generateUnique()) checkerFramework = new Annotation[] { generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE) }; constructor.annotations = copyAnnotations(source, onConstructor.toArray(new Annotation[0]), - constructorProperties, - checkerFramework); + constructorProperties); } constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope); @@ -531,6 +529,11 @@ public class HandleConstructor { TypeDeclaration typeDecl = (TypeDeclaration) type.get(); constructor.returnType = EclipseHandlerUtil.namePlusTypeParamsToTypeReference(type, typeDecl.typeParameters, p); constructor.annotations = null; + if (getCheckerFrameworkVersion(type).generateUnique()) { + int len = constructor.returnType.getTypeName().length; + constructor.returnType.annotations = new Annotation[len][]; + constructor.returnType.annotations[len - 1] = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE)}; + } constructor.selector = name.toCharArray(); constructor.thrownExceptions = null; constructor.typeParameters = copyTypeParams(((TypeDeclaration) type.get()).typeParameters, source); @@ -551,9 +554,7 @@ public class HandleConstructor { assigns.add(nameRef); Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL); - Annotation[] checkerFramework = null; - if (getCheckerFrameworkVersion(fieldNode).generateUnique()) checkerFramework = new Annotation[] { generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE) }; - parameter.annotations = copyAnnotations(source, findCopyableAnnotations(fieldNode), checkerFramework); + parameter.annotations = copyAnnotations(source, findCopyableAnnotations(fieldNode)); params.add(parameter); } diff --git a/src/core/lombok/eclipse/handlers/HandleData.java b/src/core/lombok/eclipse/handlers/HandleData.java index 6663d7d0..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,7 +22,7 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.*; -import static lombok.eclipse.handlers.EclipseHandlerUtil.isClass; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.util.Collections; @@ -33,14 +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.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(); 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 83e6de61..753c489c 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 @@ -36,6 +36,7 @@ import java.util.Set; import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.EqualsAndHashCode; +import lombok.EqualsAndHashCode.CacheStrategy; import lombok.core.AST.Kind; import lombok.core.handlers.HandlerUtil; import lombok.core.handlers.InclusionExclusionUtils; @@ -47,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; @@ -59,6 +61,8 @@ import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression; import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.Expression; 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.InstanceOfExpression; import org.eclipse.jdt.internal.compiler.ast.IntLiteral; @@ -86,14 +90,16 @@ 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"; + + private final char[] HASH_CODE_CACHE_NAME_ARR = HASH_CODE_CACHE_NAME.toCharArray(); private final char[] PRIME = "PRIME".toCharArray(); private final char[] RESULT = "result".toCharArray(); @@ -116,7 +122,9 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration; FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER; - generateMethods(annotationNode.up(), annotationNode, members, callSuper, true, fieldAccess, onParam); + boolean cacheHashCode = ann.cacheStrategy() == CacheStrategy.LAZY; + + generateMethods(annotationNode.up(), annotationNode, members, callSuper, true, cacheHashCode, fieldAccess, onParam); } public void generateEqualsAndHashCodeForType(EclipseNode typeNode, EclipseNode errorNode) { @@ -130,20 +138,18 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS); FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD; - generateMethods(typeNode, errorNode, members, null, false, access, new ArrayList<Annotation>()); + generateMethods(typeNode, errorNode, members, null, false, false, access, new ArrayList<Annotation>()); } public void generateMethods(EclipseNode typeNode, EclipseNode errorNode, List<Included<EclipseNode, EqualsAndHashCode.Include>> members, - Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<Annotation> onParam) { - - TypeDeclaration typeDecl = null; - if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get(); + Boolean callSuper, boolean whineIfExists, boolean cacheHashCode, FieldAccess fieldAccess, List<Annotation> onParam) { 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) { @@ -156,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); @@ -208,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); @@ -218,12 +224,33 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH injectMethod(typeNode, canEqualMethod); } - MethodDeclaration hashCodeMethod = createHashCode(typeNode, members, callSuper, errorNode.get(), fieldAccess); + if (cacheHashCode){ + if (fieldExists(HASH_CODE_CACHE_NAME, typeNode) != MemberExistsResult.NOT_EXISTS) { + String msg = String.format("Not caching the result of hashCode: A field named %s already exists.", HASH_CODE_CACHE_NAME); + errorNode.addWarning(msg); + cacheHashCode = false; + } else { + createHashCodeCacheField(typeNode, errorNode.get()); + } + } + + MethodDeclaration hashCodeMethod = createHashCode(typeNode, members, callSuper, cacheHashCode, errorNode.get(), fieldAccess); hashCodeMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration)typeNode.get()).scope); injectMethod(typeNode, hashCodeMethod); } + + private void createHashCodeCacheField(EclipseNode typeNode, ASTNode source) { + FieldDeclaration hashCodeCacheDecl = new FieldDeclaration(HASH_CODE_CACHE_NAME_ARR, 0, 0); + hashCodeCacheDecl.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccTransient; + hashCodeCacheDecl.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + hashCodeCacheDecl.type = TypeReference.baseTypeReference(TypeIds.T_int, 0); + hashCodeCacheDecl.declarationSourceEnd = -1; + injectFieldAndMarkGenerated(typeNode, hashCodeCacheDecl); + setGeneratedBy(hashCodeCacheDecl, source); + setGeneratedBy(hashCodeCacheDecl.type, source); + } - public MethodDeclaration createHashCode(EclipseNode type, Collection<Included<EclipseNode, EqualsAndHashCode.Include>> members, boolean callSuper, ASTNode source, FieldAccess fieldAccess) { + 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; @@ -234,7 +261,10 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH method.returnType = TypeReference.baseTypeReference(TypeIds.T_int, 0); setGeneratedBy(method.returnType, source); Annotation overrideAnnotation = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source); - if (getCheckerFrameworkVersion(type).generateSideEffectFree()) { + CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(type); + if (cacheHashCode && checkerFramework.generatePure()) { + method.annotations = new Annotation[] { overrideAnnotation, generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__PURE) }; + } else if (checkerFramework.generateSideEffectFree()) { method.annotations = new Annotation[] { overrideAnnotation, generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE) }; } else { method.annotations = new Annotation[] { overrideAnnotation }; @@ -258,6 +288,22 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH } } + /* if (this.$hashCodeCache != 0) return this.$hashCodeCache; */ { + if (cacheHashCode) { + FieldReference hashCodeCacheRef = new FieldReference(HASH_CODE_CACHE_NAME_ARR, p); + hashCodeCacheRef.receiver = new ThisReference(pS, pE); + setGeneratedBy(hashCodeCacheRef, source); + setGeneratedBy(hashCodeCacheRef.receiver, source); + EqualExpression cacheNotZero = new EqualExpression(hashCodeCacheRef, makeIntLiteral("0".toCharArray(), source), OperatorIds.NOT_EQUAL); + setGeneratedBy(cacheNotZero, source); + ReturnStatement returnCache = new ReturnStatement(hashCodeCacheRef, pS, pE); + setGeneratedBy(returnCache, source); + IfStatement ifStatement = new IfStatement(cacheNotZero, returnCache, pS, pE); + setGeneratedBy(ifStatement, source); + statements.add(ifStatement); + } + } + /* final int PRIME = X; */ { /* Without members, PRIME isn't used, as that would trigger a 'local variable not used' warning. */ if (!isEmpty) { @@ -292,7 +338,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH resultDecl.initialization = init; resultDecl.type = TypeReference.baseTypeReference(TypeIds.T_int, 0); resultDecl.type.sourceStart = pS; resultDecl.type.sourceEnd = pE; - if (isEmpty) resultDecl.modifiers |= Modifier.FINAL; + if (isEmpty && !cacheHashCode) resultDecl.modifiers |= Modifier.FINAL; setGeneratedBy(resultDecl.type, source); statements.add(resultDecl); } @@ -387,6 +433,49 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH } } + /* + * if (result == 0) result = Integer.MIN_VALUE; + * this.$hashCodeCache = result; + * + */ { + if (cacheHashCode) { + SingleNameReference resultRef = new SingleNameReference(RESULT, p); + setGeneratedBy(resultRef, source); + + EqualExpression resultIsZero = new EqualExpression(resultRef, makeIntLiteral("0".toCharArray(), source), OperatorIds.EQUAL_EQUAL); + setGeneratedBy(resultIsZero, source); + + resultRef = new SingleNameReference(RESULT, p); + setGeneratedBy(resultRef, source); + + FieldReference integerMinValue = new FieldReference("MIN_VALUE".toCharArray(), p); + integerMinValue.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_INTEGER); + setGeneratedBy(integerMinValue, source); + + Assignment newResult = new Assignment(resultRef, integerMinValue, pE); + newResult.sourceStart = pS; newResult.statementEnd = newResult.sourceEnd = pE; + setGeneratedBy(newResult, source); + + IfStatement ifStatement = new IfStatement(resultIsZero, newResult, pS, pE); + setGeneratedBy(ifStatement, source); + statements.add(ifStatement); + + + FieldReference hashCodeCacheRef = new FieldReference(HASH_CODE_CACHE_NAME_ARR, p); + hashCodeCacheRef.receiver = new ThisReference(pS, pE); + setGeneratedBy(hashCodeCacheRef, source); + setGeneratedBy(hashCodeCacheRef.receiver, source); + + resultRef = new SingleNameReference(RESULT, p); + setGeneratedBy(resultRef, source); + + Assignment cacheResult = new Assignment(hashCodeCacheRef, resultRef, pE); + cacheResult.sourceStart = pS; cacheResult.statementEnd = cacheResult.sourceEnd = pE; + setGeneratedBy(cacheResult, source); + statements.add(cacheResult); + } + } + /* return result; */ { SingleNameReference resultRef = new SingleNameReference(RESULT, p); setGeneratedBy(resultRef, source); 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 4927a8fb..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) { 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 755311b1..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) { @@ -91,7 +92,7 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { } if (!isClassOrEnum(typeNode)) { - pos.addError("@Getter is only supported on a class, an enum, or a field."); + pos.addError(GETTER_NODE_NOT_SUPPORTED_ERR); return false; } @@ -165,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; } @@ -290,6 +292,7 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { } method.traverse(new SetGeneratedByVisitor(source), parent.scope); + copyJavadoc(fieldNode, method, CopyJavadoc.GETTER); return method; } 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 9eae601b..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 @@ -22,11 +22,9 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.handleFlagUsage; -import static lombok.eclipse.Eclipse.fromQualifiedName; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Modifier; -import java.util.Arrays; import java.util.List; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -35,13 +33,11 @@ import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; 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.SingleTypeReference; 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; @@ -52,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(); } @@ -85,14 +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."); @@ -160,19 +158,6 @@ public class HandleLog { return fieldDecl; } - public static TypeReference createTypeReference(String typeName, Annotation source) { - int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long) pS << 32 | pE; - - char[][] typeNameTokens = fromQualifiedName(typeName); - long[] pos = new long[typeNameTokens.length]; - Arrays.fill(pos, p); - - TypeReference typeReference = new QualifiedTypeReference(typeNameTokens, pos); - setGeneratedBy(typeReference, source); - return typeReference; - } - private static final Expression[] createFactoryParameters(ClassLiteralAccess loggingType, Annotation source, List<LogFactoryParameter> parameters, Expression loggerTopic) { Expression[] expressions = new Expression[parameters.size()]; int pS = source.sourceStart, pE = source.sourceEnd; @@ -223,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"); @@ -234,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"); @@ -245,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"); @@ -256,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"); @@ -267,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"); @@ -278,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"); @@ -289,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"); @@ -300,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"); @@ -311,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 8dc4f4f7..27e78d32 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 @@ -47,7 +47,6 @@ import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement; 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; import lombok.AccessLevel; import lombok.ConfigurationKeys; @@ -55,13 +54,14 @@ import lombok.NonNull; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; +import lombok.eclipse.EcjAugments; import lombok.eclipse.EclipseAST; import lombok.eclipse.EclipseAnnotationHandler; -import lombok.eclipse.EclipseAugments; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists; +import lombok.spi.Provides; -@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(); @@ -91,7 +91,7 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { if (isRecordField(annotationNode.up()) && !lombokConstructorExists(typeNode)) { handleConstructor.generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, null, SkipIfConstructorExists.NO, Collections.<Annotation>emptyList(), annotationNode); } - EclipseAugments.ASTNode_handled.clear(ast); + EcjAugments.ASTNode_handled.clear(ast); return; } 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 9ebbde6d..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)) { @@ -72,7 +74,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { } if (!isClass(typeNode)) { - pos.addError("@Setter is only supported on a class or a field."); + pos.addError(SETTER_NODE_NOT_SUPPORTED_ERR); return false; } @@ -142,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; } @@ -257,6 +259,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { if (returnType != null && returnStatement != null) createRelevantNonNullAnnotation(sourceNode, method); method.traverse(new SetGeneratedByVisitor(source), parent.scope); + copyJavadoc(fieldNode, method, CopyJavadoc.SETTER, returnStatement != null); return method; } } 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/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 89c27fe3..4f4baecd 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 @@ -21,6 +21,7 @@ */ package lombok.eclipse.handlers; +import static lombok.eclipse.handlers.HandleBuilder.*; import static lombok.core.handlers.HandlerUtil.*; import static lombok.eclipse.Eclipse.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; @@ -49,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; @@ -57,13 +59,10 @@ import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; -import org.eclipse.jdt.internal.compiler.ast.Receiver; import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; -import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation; 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.StringLiteral; import org.eclipse.jdt.internal.compiler.ast.SuperReference; import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; @@ -76,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; @@ -99,75 +97,102 @@ import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; import lombok.eclipse.handlers.EclipseSingularsRecipes.StatementMaker; import lombok.eclipse.handlers.EclipseSingularsRecipes.TypeReferenceMaker; 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[] CLEAN_FIELD_NAME = "$lombokUnclean".toCharArray(); - private static final char[] CLEAN_METHOD_NAME = "$lombokClean".toCharArray(); - private static final char[] DEFAULT_PREFIX = "$default$".toCharArray(); - private static final char[] SET_PREFIX = "$set".toCharArray(); - private static final char[] VALUE_PREFIX = "$value".toCharArray(); private static final char[] SELF_METHOD_NAME = "self".toCharArray(); - private static final String TO_BUILDER_METHOD_NAME_STRING = "toBuilder"; - private static final char[] TO_BUILDER_METHOD_NAME = TO_BUILDER_METHOD_NAME_STRING.toCharArray(); private static final char[] FILL_VALUES_METHOD_NAME = "$fillValuesFrom".toCharArray(); private static final char[] FILL_VALUES_STATIC_METHOD_NAME = "$fillValuesFromInstanceIntoBuilder".toCharArray(); private static final char[] INSTANCE_VARIABLE_NAME = "instance".toCharArray(); private static final String BUILDER_VARIABLE_NAME_STRING = "b"; private static final char[] BUILDER_VARIABLE_NAME = BUILDER_VARIABLE_NAME_STRING.toCharArray(); - private static final AbstractMethodDeclaration[] EMPTY_METHODS = {}; - - @Override - public void handle(AnnotationValues<SuperBuilder> annotation, Annotation ast, EclipseNode annotationNode) { - handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder"); - CheckerFrameworkVersion cfv = getCheckerFrameworkVersion(annotationNode); - - long p = (long) ast.sourceStart << 32 | ast.sourceEnd; + class SuperBuilderJob extends BuilderJob { + void init(AnnotationValues<SuperBuilder> annValues, SuperBuilder ann, EclipseNode node) { + accessOuters = accessInners = AccessLevel.PUBLIC; + oldFluent = true; + oldChain = true; + + builderMethodName = ann.builderMethodName(); + buildMethodName = ann.buildMethodName(); + toBuilder = ann.toBuilder(); + + if (builderMethodName == null) builderMethodName = "builder"; + if (buildMethodName == null) buildMethodName = "build"; + builderClassName = fixBuilderClassName(node, ""); + } - SuperBuilder superbuilderAnnotation = annotation.getInstance(); + EclipseNode builderAbstractType; + String builderAbstractClassName; + char[] builderAbstractClassNameArr; + EclipseNode builderImplType; + String builderImplClassName; + char[] builderImplClassNameArr; + private TypeParameter[] builderTypeParams_; + void setBuilderToImpl() { + builderType = builderImplType; + builderClassName = builderImplClassName; + builderClassNameArr = builderImplClassNameArr; + builderTypeParams = typeParams; + } - String builderMethodName = superbuilderAnnotation.builderMethodName(); - String buildMethodName = superbuilderAnnotation.buildMethodName(); + void setBuilderToAbstract() { + builderType = builderAbstractType; + builderClassName = builderAbstractClassName; + builderClassNameArr = builderAbstractClassNameArr; + builderTypeParams = builderTypeParams_; + } + } + + @Override public void handle(AnnotationValues<SuperBuilder> annotation, Annotation ast, EclipseNode annotationNode) { + handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder"); + SuperBuilderJob job = new SuperBuilderJob(); + job.sourceNode = annotationNode; + job.source = ast; + job.checkerFramework = getCheckerFrameworkVersion(annotationNode); + job.isStatic = true; - if (builderMethodName == null) builderMethodName = "builder"; - if (buildMethodName == null) buildMethodName = "build"; + SuperBuilder annInstance = annotation.getInstance(); + job.init(annotation, annInstance, annotationNode); boolean generateBuilderMethod; - if (builderMethodName.isEmpty()) { + if (job.builderMethodName.isEmpty()) { generateBuilderMethod = false; - } else if (!checkName("builderMethodName", builderMethodName, annotationNode)) { + } else if (!checkName("builderMethodName", job.builderMethodName, annotationNode)) { return; } else { generateBuilderMethod = true; } - if (!checkName("buildMethodName", buildMethodName, annotationNode)) return; - boolean toBuilder = superbuilderAnnotation.toBuilder(); + if (!checkName("buildMethodName", job.buildMethodName, annotationNode)) return; - EclipseNode tdParent = annotationNode.up(); + EclipseNode parent = annotationNode.up(); - java.util.List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>(); - TypeReference returnType; - TypeParameter[] typeParams; + job.builderFields = new ArrayList<BuilderFieldData>(); + TypeReference buildMethodReturnType; boolean addCleaning = false; - if (!isClass(tdParent)) { - annotationNode.addError("@SuperBuilder is only supported on types."); + List<EclipseNode> nonFinalNonDefaultedFields = null; + + if (!isClass(parent)) { + annotationNode.addError("@SuperBuilder is only supported on classes."); return; } - TypeDeclaration td = (TypeDeclaration) tdParent.get(); + + job.parentType = parent; + TypeDeclaration td = (TypeDeclaration) parent.get(); // Gather all fields of the class that should be set by the builder. List<EclipseNode> allFields = new ArrayList<EclipseNode>(); - List<EclipseNode> nonFinalNonDefaultedFields = null; - boolean valuePresent = (hasAnnotation(lombok.Value.class, tdParent) || hasAnnotation("lombok.experimental.Value", tdParent)); - for (EclipseNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) { + boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent)); + for (EclipseNode fieldNode : HandleConstructor.findAllFields(parent, true)) { FieldDeclaration fd = (FieldDeclaration) fieldNode.get(); EclipseNode isDefault = findAnnotation(Builder.Default.class, fieldNode); boolean isFinal = ((fd.modifiers & ClassFileConstants.AccFinal) != 0) || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode)); @@ -180,7 +205,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { bfd.builderFieldName = bfd.name; bfd.annotations = copyAnnotations(fd, copyableAnnotations); bfd.type = fd.type; - bfd.singularData = getSingularData(fieldNode, ast, superbuilderAnnotation.setterPrefix()); + bfd.singularData = getSingularData(fieldNode, ast, annInstance.setterPrefix()); bfd.originalFieldNode = fieldNode; if (bfd.singularData != null && isDefault != null) { @@ -205,21 +230,15 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { bfd.builderFieldName = prefixWith(bfd.name, VALUE_PREFIX); MethodDeclaration md = HandleBuilder.generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast); - if (md != null) injectMethod(tdParent, md); + if (md != null) injectMethod(parent, md); } addObtainVia(bfd, fieldNode); - builderFields.add(bfd); + job.builderFields.add(bfd); allFields.add(fieldNode); } - // Set the names of the builder classes. - String builderClassNameTemplate = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME); - if (builderClassNameTemplate == null || builderClassNameTemplate.isEmpty()) builderClassNameTemplate = "*Builder"; - String builderClassName = builderClassNameTemplate.replace("*", String.valueOf(td.name)); - String builderImplClassName = builderClassName + "Impl"; - - typeParams = td.typeParameters != null ? td.typeParameters : new TypeParameter[0]; - returnType = namePlusTypeParamsToTypeReference(tdParent, typeParams, p); + job.typeParams = td.typeParameters != null ? td.typeParameters : new TypeParameter[0]; + buildMethodReturnType = job.createBuilderParentTypeReference(); // <C, B> are the generics for our builder. String classGenericName = "C"; @@ -227,25 +246,41 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { // We have to make sure that the generics' names do not collide with any generics on the annotated class, // the classname itself, or any member type name of the annotated class. // For instance, if there are generics <B, B2, C> on the annotated class, use "C2" and "B3" for our builder. - java.util.Set<String> usedNames = gatherUsedTypeNames(typeParams, td); + java.util.Set<String> usedNames = gatherUsedTypeNames(job.typeParams, td); classGenericName = generateNonclashingNameFor(classGenericName, usedNames); builderGenericName = generateNonclashingNameFor(builderGenericName, usedNames); + TypeParameter[] paddedTypeParameters; { + paddedTypeParameters = new TypeParameter[job.typeParams.length + 2]; + System.arraycopy(job.typeParams, 0, paddedTypeParameters, 0, job.typeParams.length); + + TypeParameter c = new TypeParameter(); + c.name = classGenericName.toCharArray(); + c.type = cloneSelfType(job.parentType, job.source); + paddedTypeParameters[paddedTypeParameters.length - 2] = c; + + TypeParameter b = new TypeParameter(); + b.name = builderGenericName.toCharArray(); + b.type = cloneSelfType(job.parentType, job.source); + paddedTypeParameters[paddedTypeParameters.length - 1] = b; + } + job.builderTypeParams = job.builderTypeParams_ = paddedTypeParameters; + TypeReference extendsClause = td.superclass; TypeReference superclassBuilderClass = null; TypeReference[] typeArguments = new TypeReference[] { new SingleTypeReference(classGenericName.toCharArray(), 0), - new SingleTypeReference(builderGenericName.toCharArray(), 0) + new SingleTypeReference(builderGenericName.toCharArray(), 0), }; if (extendsClause instanceof QualifiedTypeReference) { QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference)extendsClause; String superclassClassName = String.valueOf(qualifiedTypeReference.getLastToken()); - String superclassBuilderClassName = builderClassNameTemplate.replace("*", superclassClassName); + String superclassBuilderClassName = job.replaceBuilderClassName(superclassClassName); char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1); tokens[tokens.length-1] = superclassBuilderClassName.toCharArray(); long[] poss = new long[tokens.length]; - Arrays.fill(poss, p); + Arrays.fill(poss, job.getPos()); TypeReference[] superclassTypeArgs = getTypeParametersFrom(extendsClause); @@ -261,7 +296,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { char[][] tokens = new char[][] {superClass.toCharArray(), superclassBuilderClassName.toCharArray()}; long[] poss = new long[tokens.length]; - Arrays.fill(poss, p); + Arrays.fill(poss, job.getPos()); TypeReference[] superclassTypeArgs = getTypeParametersFrom(extendsClause); @@ -272,40 +307,43 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss); } + job.builderAbstractClassName = job.builderClassName = job.replaceBuilderClassName(td.name); + job.builderAbstractClassNameArr = job.builderClassNameArr = job.builderAbstractClassName.toCharArray(); + job.builderImplClassName = job.builderAbstractClassName + "Impl"; + job.builderImplClassNameArr = job.builderImplClassName.toCharArray(); + // If there is no superclass, superclassBuilderClassExpression is still == null at this point. // You can use it to check whether to inherit or not. - if (!constructorExists(tdParent, builderClassName)) { - generateBuilderBasedConstructor(cfv, tdParent, typeParams, builderFields, annotationNode, builderClassName, - superclassBuilderClass != null); + if (!constructorExists(parent, job.builderClassName)) { + generateBuilderBasedConstructor(job, superclassBuilderClass != null); } // Create the abstract builder class, or reuse an existing one. - EclipseNode builderType = findInnerClass(tdParent, builderClassName); - if (builderType == null) { - builderType = generateBuilderAbstractClass(tdParent, builderClassName, superclassBuilderClass, - typeParams, ast, classGenericName, builderGenericName); + job.builderAbstractType = findInnerClass(parent, job.builderClassName); + if (job.builderAbstractType == null) { + job.builderAbstractType = generateBuilderAbstractClass(job, superclassBuilderClass, classGenericName, builderGenericName); } else { - TypeDeclaration builderTypeDeclaration = (TypeDeclaration) builderType.get(); + TypeDeclaration builderTypeDeclaration = (TypeDeclaration) job.builderAbstractType.get(); if ((builderTypeDeclaration.modifiers & (ClassFileConstants.AccStatic | ClassFileConstants.AccAbstract)) == 0) { annotationNode.addError("Existing Builder must be an abstract static inner class."); return; } - sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode); + sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderAbstractType, annotationNode); // Generate errors for @Singular BFDs that have one already defined node. - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { SingularData sd = bfd.singularData; if (sd == null) continue; EclipseSingularizer singularizer = sd.getSingularizer(); if (singularizer == null) continue; - if (singularizer.checkForAlreadyExistingNodesAndGenerateError(builderType, sd)) { + if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderAbstractType, sd)) { bfd.singularData = null; } } } // Check validity of @ObtainVia fields, and add check if adding cleaning for @Singular is necessary. - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { if (bfd.singularData.getSingularizer().requiresCleaning()) { addCleaning = true; @@ -325,47 +363,52 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } // Generate the fields in the abstract builder class that hold the values for the instance. - generateBuilderFields(builderType, builderFields, ast); + job.setBuilderToAbstract(); + generateBuilderFields(job); if (addCleaning) { FieldDeclaration cleanDecl = new FieldDeclaration(CLEAN_FIELD_NAME, 0, -1); cleanDecl.declarationSourceEnd = -1; cleanDecl.modifiers = ClassFileConstants.AccPrivate; cleanDecl.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); - injectFieldAndMarkGenerated(builderType, cleanDecl); + injectFieldAndMarkGenerated(job.builderType, cleanDecl); } - if (toBuilder) { + if (job.toBuilder) { // Generate $fillValuesFrom() method in the abstract builder. - injectMethod(builderType, generateFillValuesMethod(tdParent, superclassBuilderClass != null, builderGenericName, classGenericName, builderClassName, typeParams)); + injectMethod(job.builderType, generateFillValuesMethod(job, superclassBuilderClass != null, builderGenericName, classGenericName)); // Generate $fillValuesFromInstanceIntoBuilder() method in the builder implementation class. - injectMethod(builderType, generateStaticFillValuesMethod(tdParent, builderClassName, typeParams, builderFields, ast, superbuilderAnnotation.setterPrefix())); + injectMethod(job.builderType, generateStaticFillValuesMethod(job, annInstance.setterPrefix())); } // Generate abstract self() and build() methods in the abstract builder. - injectMethod(builderType, generateAbstractSelfMethod(cfv, tdParent, superclassBuilderClass != null, builderGenericName)); - injectMethod(builderType, generateAbstractBuildMethod(cfv, builderType, buildMethodName, builderFields, superclassBuilderClass != null, classGenericName, ast)); + injectMethod(job.builderType, generateAbstractSelfMethod(job, superclassBuilderClass != null, builderGenericName)); + job.setBuilderToAbstract(); + injectMethod(job.builderType, generateAbstractBuildMethod(job, superclassBuilderClass != null, classGenericName)); // Create the setter methods in the abstract builder. - for (BuilderFieldData bfd : builderFields) { - generateSetterMethodsForBuilder(cfv, builderType, bfd, annotationNode, builderGenericName, superbuilderAnnotation.setterPrefix()); + for (BuilderFieldData bfd : job.builderFields) { + generateSetterMethodsForBuilder(job, bfd, builderGenericName, annInstance.setterPrefix()); } // Create the toString() method for the abstract builder. - if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) { + if (methodExists("toString", job.builderType, 0) == MemberExistsResult.NOT_EXISTS) { List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { for (EclipseNode f : bfd.createdFields) { fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true, false)); } } // Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder. - MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, superclassBuilderClass != null, ast, FieldAccess.ALWAYS_FIELD); + MethodDeclaration md = HandleToString.createToString(job.builderType, fieldNodes, true, superclassBuilderClass != null, ast, FieldAccess.ALWAYS_FIELD); if (md != null) { - injectMethod(builderType, md); + injectMethod(job.builderType, md); } } - if (addCleaning) injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast)); + if (addCleaning) { + job.setBuilderToAbstract(); + injectMethod(job.builderType, generateCleanMethod(job)); + } boolean isAbstract = (td.modifiers & ClassFileConstants.AccAbstract) != 0; if (isAbstract) { @@ -374,26 +417,27 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } // Create the builder implementation class, or reuse an existing one. - EclipseNode builderImplType = findInnerClass(tdParent, builderImplClassName); - if (builderImplType == null) { - builderImplType = generateBuilderImplClass(tdParent, builderImplClassName, builderClassName, typeParams, ast); + job.builderImplType = findInnerClass(parent, job.builderImplClassName); + if (job.builderImplType == null) { + job.builderImplType = generateBuilderImplClass(job, job.builderImplClassName); } else { - TypeDeclaration builderImplTypeDeclaration = (TypeDeclaration) builderImplType.get(); + TypeDeclaration builderImplTypeDeclaration = (TypeDeclaration) job.builderImplType.get(); if ((builderImplTypeDeclaration.modifiers & ClassFileConstants.AccAbstract) != 0 || (builderImplTypeDeclaration.modifiers & ClassFileConstants.AccStatic) == 0) { annotationNode.addError("Existing BuilderImpl must be a non-abstract static inner class."); return; } - sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderImplType, annotationNode); + sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderImplType, annotationNode); } - if (toBuilder) { + job.setBuilderToImpl(); + if (job.toBuilder) { // Add the toBuilder() method to the annotated class. - switch (methodExists(TO_BUILDER_METHOD_NAME_STRING, tdParent, 0)) { + switch (methodExists(TO_BUILDER_METHOD_NAME_STRING, job.parentType, 0)) { case EXISTS_BY_USER: break; case NOT_EXISTS: - injectMethod(tdParent, generateToBuilderMethod(cfv, builderClassName, builderImplClassName, tdParent, typeParams, ast)); + injectMethod(parent, generateToBuilderMethod(job)); break; default: // Should not happen. @@ -401,17 +445,19 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } // Create the self() and build() methods in the BuilderImpl. - injectMethod(builderImplType, generateSelfMethod(cfv, builderImplType, typeParams, p)); + job.setBuilderToImpl(); + injectMethod(job.builderImplType, generateSelfMethod(job)); - if (methodExists(buildMethodName, builderImplType, -1) == MemberExistsResult.NOT_EXISTS) { - injectMethod(builderImplType, generateBuildMethod(cfv, builderImplType, buildMethodName, returnType, builderFields, ast)); + if (methodExists(job.buildMethodName, job.builderImplType, -1) == MemberExistsResult.NOT_EXISTS) { + job.setBuilderToImpl(); + injectMethod(job.builderImplType, generateBuildMethod(job, buildMethodReturnType)); } // Add the builder() method to the annotated class. - if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; + if (generateBuilderMethod && methodExists(job.builderMethodName, parent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; if (generateBuilderMethod) { - MethodDeclaration md = generateBuilderMethod(cfv, builderMethodName, builderClassName, builderImplClassName, tdParent, typeParams, ast); - if (md != null) injectMethod(tdParent, md); + MethodDeclaration md = generateBuilderMethod(job); + if (md != null) injectMethod(parent, md); } if (nonFinalNonDefaultedFields != null && generateBuilderMethod) { @@ -421,97 +467,82 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } } - private EclipseNode generateBuilderAbstractClass(EclipseNode tdParent, String builderClass, - TypeReference superclassBuilderClass, TypeParameter[] typeParams, - ASTNode source, String classGenericName, String builderGenericName) { - - TypeDeclaration parent = (TypeDeclaration) tdParent.get(); + private EclipseNode generateBuilderAbstractClass(BuilderJob job, TypeReference superclassBuilderClass, String classGenericName, String builderGenericName) { + TypeDeclaration parent = (TypeDeclaration) job.parentType.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; builder.modifiers |= ClassFileConstants.AccPublic | ClassFileConstants.AccStatic | ClassFileConstants.AccAbstract; - builder.name = builderClass.toCharArray(); + builder.name = job.builderClassNameArr; // Keep any type params of the annotated class. - builder.typeParameters = Arrays.copyOf(copyTypeParams(typeParams, source), typeParams.length + 2); + builder.typeParameters = Arrays.copyOf(copyTypeParams(job.typeParams, job.source), job.typeParams.length + 2); // Add builder-specific type params required for inheritable builders. // 1. The return type for the build() method, named "C", which extends the annotated class. TypeParameter o = new TypeParameter(); o.name = classGenericName.toCharArray(); - o.type = cloneSelfType(tdParent, source); + o.type = cloneSelfType(job.parentType, job.source); builder.typeParameters[builder.typeParameters.length - 2] = o; // 2. The return type for all setter methods, named "B", which extends this builder class. o = new TypeParameter(); o.name = builderGenericName.toCharArray(); - TypeReference[] typerefs = appendBuilderTypeReferences(typeParams, classGenericName, builderGenericName); - o.type = generateParameterizedTypeReference(tdParent, builderClass.toCharArray(), false, typerefs, 0); + TypeReference[] typerefs = appendBuilderTypeReferences(job.typeParams, classGenericName, builderGenericName); + o.type = generateParameterizedTypeReference(job.parentType, job.builderClassNameArr, false, typerefs, 0); builder.typeParameters[builder.typeParameters.length - 1] = o; - builder.superclass = copyType(superclassBuilderClass, source); + if (superclassBuilderClass != null) builder.superclass = copyType(superclassBuilderClass, job.source); builder.createDefaultConstructor(false, true); - builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); - return injectType(tdParent, builder); + builder.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); + return injectType(job.parentType, builder); } - private EclipseNode generateBuilderImplClass(EclipseNode tdParent, String builderImplClass, String builderAbstractClass, TypeParameter[] typeParams, ASTNode source) { - TypeDeclaration parent = (TypeDeclaration) tdParent.get(); + private EclipseNode generateBuilderImplClass(BuilderJob job, String builderImplClass) { + TypeDeclaration parent = (TypeDeclaration) job.parentType.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; builder.modifiers |= ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal; builder.name = builderImplClass.toCharArray(); // Add type params if there are any. - if (typeParams != null && typeParams.length > 0) builder.typeParameters = copyTypeParams(typeParams, source); + if (job.typeParams != null && job.typeParams.length > 0) builder.typeParameters = copyTypeParams(job.typeParams, job.source); - if (builderAbstractClass != null) { + if (job.builderClassName != null) { // Extend the abstract builder. // 1. Add any type params of the annotated class. - TypeReference[] typeArgs = new TypeReference[typeParams.length + 2]; - for (int i = 0; i < typeParams.length; i++) { - typeArgs[i] = new SingleTypeReference(typeParams[i].name, 0); + TypeReference[] typeArgs = new TypeReference[job.typeParams.length + 2]; + for (int i = 0; i < job.typeParams.length; i++) { + typeArgs[i] = new SingleTypeReference(job.typeParams[i].name, 0); } // 2. The return type for the build() method (named "C" in the abstract builder), which is the annotated class. // 3. The return type for all setter methods (named "B" in the abstract builder), which is this builder class. - typeArgs[typeArgs.length - 2] = cloneSelfType(tdParent, source); - typeArgs[typeArgs.length - 1] = createTypeReferenceWithTypeParameters(tdParent, builderImplClass, typeParams); - builder.superclass = generateParameterizedTypeReference(tdParent, builderAbstractClass.toCharArray(), false, typeArgs, 0); + typeArgs[typeArgs.length - 2] = cloneSelfType(job.parentType, job.source); + typeArgs[typeArgs.length - 1] = createTypeReferenceWithTypeParameters(job.parentType, builderImplClass, job.typeParams); + builder.superclass = generateParameterizedTypeReference(job.parentType, job.builderClassNameArr, false, typeArgs, 0); } builder.createDefaultConstructor(false, true); - builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); - return injectType(tdParent, builder); + builder.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); + return injectType(job.parentType, builder); } /** * Generates a constructor that has a builder as the only parameter. * The values from the builder are used to initialize the fields of new instances. * - * @param typeNode - * the type (with the {@code @Builder} annotation) for which a - * constructor should be generated. - * @param typeParams - * @param cfv Settings for generating checker framework annotations - * @param builderFields a list of fields in the builder which should be assigned to new instances. - * @param source the annotation (used for setting source code locations for the generated code). * @param callBuilderBasedSuperConstructor * If {@code true}, the constructor will explicitly call a super * constructor with the builder as argument. Requires * {@code builderClassAsParameter != null}. */ - private void generateBuilderBasedConstructor(CheckerFrameworkVersion cfv, EclipseNode typeNode, TypeParameter[] typeParams, List<BuilderFieldData> builderFields, - EclipseNode sourceNode, String builderClassName, boolean callBuilderBasedSuperConstructor) { + private void generateBuilderBasedConstructor(BuilderJob job, boolean callBuilderBasedSuperConstructor) { + TypeDeclaration typeDeclaration = ((TypeDeclaration) job.parentType.get()); + long p = job.getPos(); - 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); + ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) job.parentType.top().get()).compilationResult); constructor.modifiers = toEclipseModifier(AccessLevel.PROTECTED); - if (cfv.generateUnique()) constructor.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE)}; constructor.selector = typeDeclaration.name; if (callBuilderBasedSuperConstructor) { constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.Super); @@ -519,21 +550,21 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } else { constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); } - constructor.constructorCall.sourceStart = source.sourceStart; - constructor.constructorCall.sourceEnd = source.sourceEnd; + constructor.constructorCall.sourceStart = job.source.sourceStart; + constructor.constructorCall.sourceEnd = job.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.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = job.source.sourceStart; + constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = job.source.sourceEnd; TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND)}; - TypeReference builderType = generateParameterizedTypeReference(typeNode, builderClassName.toCharArray(), false, mergeToTypeReferences(typeParams, wildcards), p); + TypeReference builderType = generateParameterizedTypeReference(job.parentType, job.builderClassNameArr, false, mergeToTypeReferences(job.typeParams, wildcards), p); constructor.arguments = new Argument[] {new Argument(BUILDER_VARIABLE_NAME, p, builderType, Modifier.FINAL)}; List<Statement> statements = new ArrayList<Statement>(); - for (BuilderFieldData fieldNode : builderFields) { + for (BuilderFieldData fieldNode : job.builderFields) { FieldReference fieldInThis = new FieldReference(fieldNode.rawName, p); int s = (int) (p >> 32); int e = (int) p; @@ -541,7 +572,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { Expression assignmentExpr; if (fieldNode.singularData != null && fieldNode.singularData.getSingularizer() != null) { - fieldNode.singularData.getSingularizer().appendBuildCode(fieldNode.singularData, typeNode, statements, fieldNode.builderFieldName, BUILDER_VARIABLE_NAME_STRING); + fieldNode.singularData.getSingularizer().appendBuildCode(fieldNode.singularData, job.parentType, statements, fieldNode.builderFieldName, BUILDER_VARIABLE_NAME_STRING); assignmentExpr = new SingleNameReference(fieldNode.builderFieldName, p); } else { char[][] variableInBuilder = new char[][] {BUILDER_VARIABLE_NAME, fieldNode.builderFieldName}; @@ -557,11 +588,11 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { QualifiedNameReference setVariableInBuilderRef = new QualifiedNameReference(setVariableInBuilder, positions, s, e); MessageSend defaultMethodCall = new MessageSend(); - defaultMethodCall.sourceStart = source.sourceStart; - defaultMethodCall.sourceEnd = source.sourceEnd; - defaultMethodCall.receiver = generateNameReference(typeNode, 0L); + defaultMethodCall.sourceStart = job.source.sourceStart; + defaultMethodCall.sourceEnd = job.source.sourceEnd; + defaultMethodCall.receiver = generateNameReference(job.parentType, 0L); defaultMethodCall.selector = fieldNode.nameOfDefaultProvider; - defaultMethodCall.typeArguments = typeParameterNames(((TypeDeclaration) typeNode.get()).typeParameters); + defaultMethodCall.typeArguments = typeParameterNames(((TypeDeclaration) job.parentType.get()).typeParameters); Statement defaultAssignment = new Assignment(fieldInThis, defaultMethodCall, (int) p); IfStatement ifBlockForDefault = new IfStatement(setVariableInBuilderRef, assignment, defaultAssignment, s, e); @@ -571,41 +602,50 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } if (hasNonNullAnnotations(fieldNode.originalFieldNode)) { - Statement nullCheck = generateNullCheck((FieldDeclaration) fieldNode.originalFieldNode.get(), sourceNode, null); + Statement nullCheck = generateNullCheck((FieldDeclaration) fieldNode.originalFieldNode.get(), job.sourceNode, null); if (nullCheck != null) statements.add(nullCheck); } } 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(source), typeDeclaration.scope); + constructor.traverse(new SetGeneratedByVisitor(job.source), typeDeclaration.scope); - injectMethod(typeNode, constructor); + injectMethod(job.parentType, constructor); } - private MethodDeclaration generateBuilderMethod(CheckerFrameworkVersion cfv, String builderMethodName, String builderClassName, String builderImplClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) { - int pS = source.sourceStart, pE = source.sourceEnd; + private MethodDeclaration generateBuilderMethod(SuperBuilderJob job) { + int pS = job.source.sourceStart, pE = job.source.sourceEnd; long p = (long) pS << 32 | pE; - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); - out.selector = builderMethodName.toCharArray(); + MethodDeclaration out = job.createNewMethodDeclaration(); + out.selector = job.builderMethodName.toCharArray(); out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; // Add type params if there are any. - if (typeParams != null && typeParams.length > 0) out.typeParameters = copyTypeParams(typeParams, source); + if (job.typeParams != null && job.typeParams.length > 0) out.typeParameters = copyTypeParams(job.typeParams, job.source); TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND) }; - out.returnType = generateParameterizedTypeReference(type, builderClassName.toCharArray(), false, mergeToTypeReferences(typeParams, wildcards), p); + out.returnType = generateParameterizedTypeReference(job.parentType, job.builderAbstractClassNameArr, false, mergeToTypeReferences(job.typeParams, wildcards), p); + if (job.checkerFramework.generateUnique()) { + int len = out.returnType.getTypeName().length; + out.returnType.annotations = new Annotation[len][]; + out.returnType.annotations[len - 1] = new Annotation[] {generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__UNIQUE)}; + } AllocationExpression invoke = new AllocationExpression(); - invoke.type = namePlusTypeParamsToTypeReference(type, builderImplClassName.toCharArray(), false, typeParams, p); + 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)}; + } - if (cfv.generateUnique()) out.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE)}; - - createRelevantNonNullAnnotation(type, out); - out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope); + createRelevantNonNullAnnotation(job.parentType, out); + out.traverse(new SetGeneratedByVisitor(job.source), ((TypeDeclaration) job.parentType.get()).scope); return out; } @@ -617,30 +657,36 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { * } * </pre> */ - private MethodDeclaration generateToBuilderMethod(CheckerFrameworkVersion cfv, String builderClassName, String builderImplClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) { - int pS = source.sourceStart, pE = source.sourceEnd; + private MethodDeclaration generateToBuilderMethod(SuperBuilderJob job) { + int pS = job.source.sourceStart, pE = job.source.sourceEnd; long p = (long) pS << 32 | pE; - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); + MethodDeclaration out = job.createNewMethodDeclaration(); out.selector = TO_BUILDER_METHOD_NAME; out.modifiers = ClassFileConstants.AccPublic; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND) }; - out.returnType = generateParameterizedTypeReference(type, builderClassName.toCharArray(), false, mergeToTypeReferences(typeParams, wildcards), p); + out.returnType = generateParameterizedTypeReference(job.parentType, job.builderAbstractClassNameArr, false, mergeToTypeReferences(job.typeParams, wildcards), p); + if (job.checkerFramework.generateUnique()) { + int len = out.returnType.getTypeName().length; + out.returnType.annotations = new Annotation[len][]; + out.returnType.annotations[len - 1] = new Annotation[] {generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__UNIQUE)}; + } AllocationExpression newClass = new AllocationExpression(); - newClass.type = namePlusTypeParamsToTypeReference(type, builderImplClassName.toCharArray(), false, typeParams, p); + newClass.type = namePlusTypeParamsToTypeReference(job.parentType, job.builderImplClassNameArr, false, job.typeParams, p); MessageSend invokeFillMethod = new MessageSend(); invokeFillMethod.receiver = newClass; 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)}; + } - if (cfv.generateUnique()) out.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE)}; - - createRelevantNonNullAnnotation(type, out); - out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope); + createRelevantNonNullAnnotation(job.parentType, out); + out.traverse(new SetGeneratedByVisitor(job.source), ((TypeDeclaration) job.parentType.get()).scope); return out; } @@ -650,17 +696,17 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { * <pre> * protected B $fillValuesFrom(final C instance) { * super.$fillValuesFrom(instance); - * Foobar.FoobarBuilderImpl.$fillValuesFromInstanceIntoBuilder(instance, this); + * Foobar.FoobarBuilder.$fillValuesFromInstanceIntoBuilder(instance, this); * return self(); * } * </pre> */ - private MethodDeclaration generateFillValuesMethod(EclipseNode tdParent, boolean inherited, String builderGenericName, String classGenericName, String builderClassName, TypeParameter[] typeParams) { - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); + private MethodDeclaration generateFillValuesMethod(SuperBuilderJob job, boolean inherited, String builderGenericName, String classGenericName) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.selector = FILL_VALUES_METHOD_NAME; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccProtected; - if (inherited) out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, tdParent.get())}; + if (inherited) out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, job.parentType.get())}; out.returnType = new SingleTypeReference(builderGenericName.toCharArray(), 0); TypeReference builderType = new SingleTypeReference(classGenericName.toCharArray(), 0); @@ -679,7 +725,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { // Call the builder implemention's helper method that actually fills the values from the instance. MessageSend callStaticFillValuesMethod = new MessageSend(); - callStaticFillValuesMethod.receiver = generateNameReference(tdParent, builderClassName.toCharArray(), 0); + callStaticFillValuesMethod.receiver = generateNameReference(job.parentType, job.builderAbstractClassNameArr, 0); callStaticFillValuesMethod.selector = FILL_VALUES_STATIC_METHOD_NAME; callStaticFillValuesMethod.arguments = new Expression[] {new SingleNameReference(INSTANCE_VARIABLE_NAME, 0), new ThisReference(0, 0)}; body.add(callStaticFillValuesMethod); @@ -707,40 +753,40 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { * </pre> * @param setterPrefix the prefix for setter methods */ - private MethodDeclaration generateStaticFillValuesMethod(EclipseNode tdParent, String builderClassName, TypeParameter[] typeParams, java.util.List<BuilderFieldData> builderFields, ASTNode source, String setterPrefix) { - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); + private MethodDeclaration generateStaticFillValuesMethod(BuilderJob job, String setterPrefix) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.selector = FILL_VALUES_STATIC_METHOD_NAME; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic; out.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0); TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND)}; - TypeReference builderType = generateParameterizedTypeReference(tdParent, builderClassName.toCharArray(), false, mergeToTypeReferences(typeParams, wildcards), 0); + TypeReference builderType = generateParameterizedTypeReference(job.parentType, job.builderClassNameArr, false, mergeToTypeReferences(job.typeParams, wildcards), 0); Argument builderArgument = new Argument(BUILDER_VARIABLE_NAME, 0, builderType, Modifier.FINAL); TypeReference[] typerefs = null; - if (typeParams.length > 0) { - typerefs = new TypeReference[typeParams.length]; - for (int i = 0; i < typeParams.length; i++) typerefs[i] = new SingleTypeReference(typeParams[i].name, 0); + if (job.typeParams.length > 0) { + typerefs = new TypeReference[job.typeParams.length]; + for (int i = 0; i < job.typeParams.length; i++) typerefs[i] = new SingleTypeReference(job.typeParams[i].name, 0); } - long p = source.sourceStart; - p = (p << 32) | source.sourceEnd; + long p = job.getPos(); - TypeReference parentArgument = typerefs == null ? generateTypeReference(tdParent, p) : generateParameterizedTypeReference(tdParent, typerefs, p); + TypeReference parentArgument = typerefs == null ? generateTypeReference(job.parentType, p) : generateParameterizedTypeReference(job.parentType, typerefs, p); out.arguments = new Argument[] {new Argument(INSTANCE_VARIABLE_NAME, 0, parentArgument, Modifier.FINAL), builderArgument}; // Add type params if there are any. - if (typeParams.length > 0) out.typeParameters = copyTypeParams(typeParams, source); + if (job.typeParams.length > 0) out.typeParameters = copyTypeParams(job.typeParams, job.source); List<Statement> body = new ArrayList<Statement>(); // Call the builder's setter methods to fill the values from the instance. - for (BuilderFieldData bfd : builderFields) { - MessageSend exec = createSetterCallWithInstanceValue(bfd, tdParent, source, setterPrefix); + for (BuilderFieldData bfd : job.builderFields) { + MessageSend exec = createSetterCallWithInstanceValue(bfd, job.parentType, job.source, setterPrefix); body.add(exec); } out.statements = body.isEmpty() ? null : body.toArray(new Statement[0]); + out.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); return out; } @@ -772,9 +818,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); @@ -782,14 +826,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { return ms; } - private MethodDeclaration generateAbstractSelfMethod(CheckerFrameworkVersion cfv, EclipseNode tdParent, boolean override, String builderGenericName) { - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); + private MethodDeclaration generateAbstractSelfMethod(BuilderJob job, boolean override, String builderGenericName) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.selector = SELF_METHOD_NAME; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected | ExtraCompilerModifiers.AccSemicolonBody; - Annotation overrideAnn = override ? makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, tdParent.get()) : null; - Annotation rrAnn = cfv.generateReturnsReceiver() ? generateNamedAnnotation(tdParent.get(), CheckerFrameworkVersion.NAME__RETURNS_RECEIVER): null; - Annotation sefAnn = cfv.generatePure() ? generateNamedAnnotation(tdParent.get(), CheckerFrameworkVersion.NAME__PURE): null; + Annotation overrideAnn = override ? makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, job.parentType.get()) : null; + Annotation rrAnn = job.checkerFramework.generateReturnsReceiver() ? generateNamedAnnotation(job.parentType.get(), CheckerFrameworkVersion.NAME__RETURNS_RECEIVER): null; + Annotation sefAnn = job.checkerFramework.generatePure() ? generateNamedAnnotation(job.parentType.get(), CheckerFrameworkVersion.NAME__PURE): null; if (overrideAnn != null && rrAnn != null && sefAnn != null) out.annotations = new Annotation[] {overrideAnn, rrAnn, sefAnn}; else if (overrideAnn != null && rrAnn != null) out.annotations = new Annotation[] {overrideAnn, rrAnn}; else if (overrideAnn != null && sefAnn != null) out.annotations = new Annotation[] {overrideAnn, sefAnn}; @@ -801,54 +845,52 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { return out; } - private MethodDeclaration generateSelfMethod(CheckerFrameworkVersion cfv, EclipseNode builderImplType, TypeParameter[] typeParams, long p) { - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) builderImplType.top().get()).compilationResult); + private MethodDeclaration generateSelfMethod(BuilderJob job) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.selector = SELF_METHOD_NAME; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccProtected; - Annotation overrideAnn = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, builderImplType.get()); - Annotation rrAnn = cfv.generateReturnsReceiver() ? generateNamedAnnotation(builderImplType.get(), CheckerFrameworkVersion.NAME__RETURNS_RECEIVER) : null; - Annotation sefAnn = cfv.generatePure() ? generateNamedAnnotation(builderImplType.get(), CheckerFrameworkVersion.NAME__PURE) : null; + Annotation overrideAnn = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, job.builderType.get()); + Annotation rrAnn = job.checkerFramework.generateReturnsReceiver() ? generateNamedAnnotation(job.builderType.get(), CheckerFrameworkVersion.NAME__RETURNS_RECEIVER) : null; + Annotation sefAnn = job.checkerFramework.generatePure() ? generateNamedAnnotation(job.builderType.get(), CheckerFrameworkVersion.NAME__PURE) : null; if (rrAnn != null && sefAnn != null) out.annotations = new Annotation[] {overrideAnn, rrAnn, sefAnn}; else if (rrAnn != null) out.annotations = new Annotation[] {overrideAnn, rrAnn}; else if (sefAnn != null) out.annotations = new Annotation[] {overrideAnn, sefAnn}; else out.annotations = new Annotation[] {overrideAnn}; - out.returnType = namePlusTypeParamsToTypeReference(builderImplType, typeParams, p); + out.returnType = namePlusTypeParamsToTypeReference(job.builderType, job.typeParams, job.getPos()); out.statements = new Statement[] {new ReturnStatement(new ThisReference(0, 0), 0, 0)}; return out; } - private MethodDeclaration generateAbstractBuildMethod(CheckerFrameworkVersion cfv, EclipseNode builderType, String methodName, List<BuilderFieldData> builderFields, boolean override, - String classGenericName, ASTNode source) { - - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); + private MethodDeclaration generateAbstractBuildMethod(BuilderJob job, boolean override, String classGenericName) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract | ExtraCompilerModifiers.AccSemicolonBody; - out.selector = methodName.toCharArray(); + out.selector = job.buildMethodName.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.returnType = new SingleTypeReference(classGenericName.toCharArray(), 0); - Annotation overrideAnn = override ? makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source) : null; - Annotation sefAnn = cfv.generateSideEffectFree() ? generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE): null; + Annotation overrideAnn = override ? makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, job.source) : null; + Annotation sefAnn = job.checkerFramework.generateSideEffectFree() ? generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE): null; if (overrideAnn != null && sefAnn != null) out.annotations = new Annotation[] {overrideAnn, sefAnn}; else if (overrideAnn != null) out.annotations = new Annotation[] {overrideAnn}; else if (sefAnn != null) out.annotations = new Annotation[] {sefAnn}; - out.receiver = HandleBuilder.generateBuildReceiver(cfv, builderType, builderFields, source); - out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); + out.receiver = HandleBuilder.generateBuildReceiver(job); + out.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); return out; } - private MethodDeclaration generateBuildMethod(CheckerFrameworkVersion cfv, EclipseNode builderType, String name, TypeReference returnType, List<BuilderFieldData> builderFields, ASTNode source) { - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); + private MethodDeclaration generateBuildMethod(BuilderJob job, TypeReference returnType) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; List<Statement> statements = new ArrayList<Statement>(); out.modifiers = ClassFileConstants.AccPublic; - out.selector = name.toCharArray(); + out.selector = job.buildMethodName.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.returnType = returnType; - Annotation overrideAnn = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source); - Annotation sefAnn = cfv.generateSideEffectFree() ? generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE): null; + Annotation overrideAnn = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, job.source); + Annotation sefAnn = job.checkerFramework.generateSideEffectFree() ? generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE): null; if (sefAnn != null) out.annotations = new Annotation[] {overrideAnn, sefAnn}; else out.annotations = new Annotation[] {overrideAnn}; @@ -858,43 +900,44 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { allocationStatement.arguments = new Expression[] {new ThisReference(0, 0)}; statements.add(new ReturnStatement(allocationStatement, 0, 0)); out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]); - out.receiver = HandleBuilder.generateBuildReceiver(cfv, builderType, builderFields, source); - createRelevantNonNullAnnotation(builderType, out); - out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); + out.receiver = HandleBuilder.generateBuildReceiver(job); + createRelevantNonNullAnnotation(job.builderType, out); + out.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); return out; } - private MethodDeclaration generateCleanMethod(List<BuilderFieldData> builderFields, EclipseNode builderType, ASTNode source) { + private MethodDeclaration generateCleanMethod(BuilderJob job) { List<Statement> statements = new ArrayList<Statement>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, builderType, statements); + bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, job.builderType, statements); } } FieldReference thisUnclean = new FieldReference(CLEAN_FIELD_NAME, 0); thisUnclean.receiver = new ThisReference(0, 0); statements.add(new Assignment(thisUnclean, new FalseLiteral(0, 0), 0)); - MethodDeclaration decl = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); + MethodDeclaration decl = job.createNewMethodDeclaration(); + //new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); decl.selector = CLEAN_METHOD_NAME; decl.modifiers = ClassFileConstants.AccPrivate; decl.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; decl.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0); decl.statements = statements.toArray(new Statement[0]); - decl.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); + decl.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); return decl; } - private void generateBuilderFields(EclipseNode builderType, List<BuilderFieldData> builderFields, ASTNode source) { + private void generateBuilderFields(BuilderJob job) { List<EclipseNode> existing = new ArrayList<EclipseNode>(); - for (EclipseNode child : builderType.down()) { + for (EclipseNode child : job.builderType.down()) { if (child.getKind() == Kind.FIELD) existing.add(child); } - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, builderType)); + bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, job.builderType)); } else { EclipseNode field = null, setFlag = null; for (EclipseNode exists : existing) { @@ -908,23 +951,23 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { fd.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; fd.modifiers = ClassFileConstants.AccPrivate; fd.type = copyType(bfd.type); - fd.traverse(new SetGeneratedByVisitor(source), (MethodScope) null); - field = injectFieldAndMarkGenerated(builderType, fd); + fd.traverse(new SetGeneratedByVisitor(job.source), (MethodScope) null); + field = injectFieldAndMarkGenerated(job.builderType, fd); } if (setFlag == null && bfd.nameOfSetFlag != null) { FieldDeclaration fd = new FieldDeclaration(bfd.nameOfSetFlag, 0, 0); fd.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; fd.modifiers = ClassFileConstants.AccPrivate; fd.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); - fd.traverse(new SetGeneratedByVisitor(source), (MethodScope) null); - injectFieldAndMarkGenerated(builderType, fd); + fd.traverse(new SetGeneratedByVisitor(job.source), (MethodScope) null); + injectFieldAndMarkGenerated(job.builderType, fd); } bfd.createdFields.add(field); } } } - private void generateSetterMethodsForBuilder(CheckerFrameworkVersion cfv, EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, final String builderGenericName, String setterPrefix) { + private void generateSetterMethodsForBuilder(BuilderJob job, BuilderFieldData bfd, final String builderGenericName, String setterPrefix) { boolean deprecate = isFieldDeprecated(bfd.originalFieldNode); TypeReferenceMaker returnTypeMaker = new TypeReferenceMaker() { @@ -943,15 +986,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { }; if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) { - generateSimpleSetterMethodForBuilder(cfv, builderType, deprecate, bfd.createdFields.get(0), bfd.name, bfd.nameOfSetFlag, returnTypeMaker.make(), returnStatementMaker.make(), sourceNode, bfd.annotations, bfd.originalFieldNode, setterPrefix); + generateSimpleSetterMethodForBuilder(job, deprecate, bfd.createdFields.get(0), bfd.name, bfd.nameOfSetFlag, returnTypeMaker.make(), returnStatementMaker.make(), bfd.annotations, bfd.originalFieldNode, setterPrefix); } else { - bfd.singularData.getSingularizer().generateMethods(cfv, bfd.singularData, deprecate, builderType, true, returnTypeMaker, returnStatementMaker, AccessLevel.PUBLIC); + bfd.singularData.getSingularizer().generateMethods(job.checkerFramework, bfd.singularData, deprecate, job.builderType, true, returnTypeMaker, returnStatementMaker, AccessLevel.PUBLIC); } } - - private void generateSimpleSetterMethodForBuilder(CheckerFrameworkVersion cfv, EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] paramName, char[] nameOfSetFlag, TypeReference returnType, Statement returnStatement, EclipseNode sourceNode, Annotation[] annosOnParam, EclipseNode originalFieldNode, String setterPrefix) { - TypeDeclaration td = (TypeDeclaration) builderType.get(); - ASTNode source = sourceNode.get(); + + private void generateSimpleSetterMethodForBuilder(BuilderJob job, boolean deprecate, EclipseNode fieldNode, char[] paramName, char[] nameOfSetFlag, TypeReference returnType, Statement returnStatement, Annotation[] annosOnParam, EclipseNode originalFieldNode, String setterPrefix) { + TypeDeclaration td = (TypeDeclaration) job.builderType.get(); AbstractMethodDeclaration[] existing = td.methods; if (existing == null) existing = EMPTY_METHODS; int len = existing.length; @@ -965,23 +1007,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } List<Annotation> methodAnnsList = Arrays.asList(EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode)); - if (cfv.generateReturnsReceiver()) { + if (job.checkerFramework.generateReturnsReceiver()) { methodAnnsList = new ArrayList<Annotation>(methodAnnsList); - methodAnnsList.add(generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER)); + methodAnnsList.add(generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER)); } MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, paramName, nameOfSetFlag, returnType, returnStatement, ClassFileConstants.AccPublic, - sourceNode, methodAnnsList, annosOnParam != null ? Arrays.asList(copyAnnotations(source, annosOnParam)) : Collections.<Annotation>emptyList()); - if (cfv.generateCalledMethods()) { - char[][] nameNotCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__NOT_CALLED); - SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameNotCalled, poss(source, nameNotCalled.length)), source.sourceStart); - ann.memberValue = new StringLiteral(setterName.toCharArray(), 0, 0, 0); - - QualifiedTypeReference typeReference = (QualifiedTypeReference) generateTypeReference(builderType, 0); - typeReference.annotations = new Annotation[typeReference.tokens.length][]; - typeReference.annotations[0] = new Annotation[] {ann}; - setter.receiver = new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, Modifier.FINAL); - } - injectMethod(builderType, setter); + job.sourceNode, methodAnnsList, annosOnParam != null ? Arrays.asList(copyAnnotations(job.source, annosOnParam)) : Collections.<Annotation>emptyList()); + if (job.checkerFramework.generateCalledMethods()) setter.receiver = generateNotCalledReceiver(job, setterName); + injectMethod(job.builderType, setter); } private void addObtainVia(BuilderFieldData bfd, EclipseNode node) { @@ -1069,6 +1102,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])); @@ -1171,7 +1205,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 37d6755c..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> { @@ -153,7 +153,6 @@ public class HandleSynchronized extends EclipseAnnotationHandler<Synchronized> { 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; diff --git a/src/core/lombok/eclipse/handlers/HandleToString.java b/src/core/lombok/eclipse/handlers/HandleToString.java index 9b58474c..72491277 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 @@ -51,7 +51,6 @@ 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.lookup.TypeConstants; -import org.mangosdk.spi.ProviderFor; import lombok.AccessLevel; import lombok.ConfigurationKeys; @@ -66,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"); diff --git a/src/core/lombok/eclipse/handlers/HandleUtilityClass.java b/src/core/lombok/eclipse/handlers/HandleUtilityClass.java index 338aab0d..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"); @@ -71,7 +69,7 @@ public class HandleUtilityClass extends EclipseAnnotationHandler<UtilityClass> { private static boolean checkLegality(EclipseNode typeNode, EclipseNode errorNode) { if (!isClass(typeNode)) { - errorNode.addError("@UtilityClass is only supported on a class (can't be an interface, enum, annotation, or record)."); + errorNode.addError("@UtilityClass is only supported on a class."); return false; } @@ -153,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 abea5603..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,13 +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(); - 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 83357710..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) { @@ -290,6 +290,7 @@ public class HandleWith extends EclipseAnnotationHandler<With> { EclipseHandlerUtil.createRelevantNonNullAnnotation(fieldNode, method); method.traverse(new SetGeneratedByVisitor(source), parent.scope); + copyJavadoc(fieldNode, method, CopyJavadoc.WITH); return method; } } diff --git a/src/core/lombok/eclipse/handlers/HandleWithBy.java b/src/core/lombok/eclipse/handlers/HandleWithBy.java index 5f229aaf..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) { @@ -373,6 +373,7 @@ public class HandleWithBy extends EclipseAnnotationHandler<WithBy> { createRelevantNonNullAnnotation(fieldNode, method); method.traverse(new SetGeneratedByVisitor(source), parent.scope); + copyJavadoc(fieldNode, method, CopyJavadoc.WITH_BY); return method; } } 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/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/HandlerLibrary.java b/src/core/lombok/javac/HandlerLibrary.java index 9e7b8fe5..c2bf8512 100644 --- a/src/core/lombok/javac/HandlerLibrary.java +++ b/src/core/lombok/javac/HandlerLibrary.java @@ -65,7 +65,7 @@ public class HandlerLibrary { /** * Creates a new HandlerLibrary that will report any problems or errors to the provided messager. - * You probably want to use {@link #load(Messager)} instead. + * You probably want to use {@link #load(Messager, Trees)} instead. */ public HandlerLibrary(Messager messager) { ConfigurationKeysLoader.LoaderLoader.loadAllConfigurationKeys(); diff --git a/src/core/lombok/javac/Javac6BasedLombokOptions.java b/src/core/lombok/javac/Javac6BasedLombokOptions.java index fc73181c..93f448a7 100644 --- a/src/core/lombok/javac/Javac6BasedLombokOptions.java +++ b/src/core/lombok/javac/Javac6BasedLombokOptions.java @@ -58,7 +58,7 @@ public class Javac6BasedLombokOptions extends LombokOptions { @Override public void putJavacOption(String optionName, String value) { try { - options_put.invoke(this, optionName_valueOf.invoke(null, optionName), value); + Permit.invoke(options_put, this, Permit.invoke(optionName_valueOf, null, optionName), value); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Can't initialize Javac6-based lombok options due to reflection issue.", e); } catch (InvocationTargetException e) { diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index 86ff7646..f58de60f 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.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 @@ -21,6 +21,7 @@ */ package lombok.javac; +import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URI; @@ -110,14 +111,97 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { return memoizedAbsoluteFileLocation; } + private static Class<?> wrappedFileObjectClass, sbtJavaFileObjectClass, sbtMappedVirtualFileClass, sbtOptionClass; + private static Field wrappedFileObjectField, sbtJavaFileObjectField, sbtMappedVirtualFilePathField, sbtMappedVirtualFileRootsField, sbtOptionField; + private static Method sbtMapGetMethod; + public static URI getAbsoluteFileLocation(JCCompilationUnit cu) { try { - return cu.sourcefile.toUri(); + URI uri = cu.sourcefile.toUri(); + String fn = uri.toString(); + if (fn.startsWith("file:")) return uri; + URI sbtUri = tryGetSbtFile(cu.sourcefile); + if (sbtUri != null) return sbtUri; + return uri; + } catch (Exception e) { + return null; + } + } + + private static URI tryGetSbtFile(JavaFileObject sourcefile) { + try { + return tryGetSbtFile_(sourcefile); } catch (Exception e) { return null; } } + private static URI tryGetSbtFile_(JavaFileObject sourcefile) throws Exception { + Class<?> c = sourcefile.getClass(); + String cn; + + if (wrappedFileObjectClass == null) { + if (!c.getName().equals("com.sun.tools.javac.api.ClientCodeWrapper$WrappedJavaFileObject")) return null; + wrappedFileObjectClass = c; + } + if (c != wrappedFileObjectClass) return null; + + if (wrappedFileObjectField == null) wrappedFileObjectField = Permit.permissiveGetField(wrappedFileObjectClass.getSuperclass(), "clientFileObject"); + if (wrappedFileObjectField == null) return null; + Object fileObject = wrappedFileObjectField.get(sourcefile); + c = fileObject.getClass(); + + if (sbtJavaFileObjectClass == null) { + cn = c.getName(); + if (!cn.startsWith("sbt.") || !cn.endsWith("JavaFileObject")) return null; + sbtJavaFileObjectClass = c; + } + if (sbtJavaFileObjectClass != c) return null; + if (sbtJavaFileObjectField == null) sbtJavaFileObjectField = Permit.permissiveGetField(sbtJavaFileObjectClass, "underlying"); + if (sbtJavaFileObjectField == null) return null; + + Object mappedVirtualFile = sbtJavaFileObjectField.get(fileObject); + c = mappedVirtualFile.getClass(); + + if (sbtMappedVirtualFileClass == null) { + cn = c.getName(); + if (!cn.startsWith("sbt.") || !cn.endsWith("MappedVirtualFile")) return null; + sbtMappedVirtualFileClass = c; + } + if (sbtMappedVirtualFilePathField == null) sbtMappedVirtualFilePathField = Permit.permissiveGetField(sbtMappedVirtualFileClass, "encodedPath"); + if (sbtMappedVirtualFilePathField == null) return null; + if (sbtMappedVirtualFileRootsField == null) sbtMappedVirtualFileRootsField = Permit.permissiveGetField(sbtMappedVirtualFileClass, "rootPathsMap"); + if (sbtMappedVirtualFileRootsField == null) return null; + + String encodedPath = (String) sbtMappedVirtualFilePathField.get(mappedVirtualFile); + if (!encodedPath.startsWith("${")) { + File maybeAbsoluteFile = new File(encodedPath); + if (maybeAbsoluteFile.exists()) { + return maybeAbsoluteFile.toURI(); + } else { + return null; + } + } + int idx = encodedPath.indexOf('}'); + if (idx == -1) return null; + String base = encodedPath.substring(2, idx); + Object roots = sbtMappedVirtualFileRootsField.get(mappedVirtualFile); + if (sbtMapGetMethod == null) sbtMapGetMethod = Permit.getMethod(roots.getClass(), "get", Object.class); + if (sbtMapGetMethod == null) return null; + + Object option = sbtMapGetMethod.invoke(roots, base); + c = option.getClass(); + if (sbtOptionClass == null) { + if (c.getName().equals("scala.Some")) sbtOptionClass = c; + } + if (c != sbtOptionClass) return null; + if (sbtOptionField == null) sbtOptionField = Permit.permissiveGetField(sbtOptionClass, "value"); + if (sbtOptionField == null) return null; + + Object path = sbtOptionField.get(option); + return new File(path.toString() + encodedPath.substring(idx + 1)).toURI(); + } + private static String sourceName(JCCompilationUnit cu) { return cu.sourcefile == null ? null : cu.sourcefile.toString(); } @@ -397,11 +481,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { } private JCTree getBody(JCTree jcTree) { - try { - return (JCTree) getBodyMethod(jcTree.getClass()).invoke(jcTree); - } catch (Exception e) { - throw Javac.sneakyThrow(e); - } + return (JCTree) Permit.invokeSneaky(getBodyMethod(jcTree.getClass()), jcTree); } private final static ConcurrentMap<Class<?>, Method> getBodyMethods = new ConcurrentHashMap<Class<?>, Method>(); @@ -662,42 +742,26 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { } @Override void error1(DiagnosticPosition pos, String message) { - try { - Object error = this.errorKey.invoke(diags, PROC_MESSAGER, new Object[] { message }); - errorMethod.invoke(log, multiple, pos, error); - } catch (Throwable t) { - //t.printStackTrace(); - } + Object error = Permit.invokeSneaky(this.errorKey, diags, PROC_MESSAGER, new Object[] { message }); + if (error != null) Permit.invokeSneaky(errorMethod, log, multiple, pos, error); } @Override void warning1(DiagnosticPosition pos, String message) { - try { - Object warning = this.warningKey.invoke(diags, PROC_MESSAGER, new Object[] { message }); - warningMethod.invoke(log, pos, warning); - } catch (Throwable t) { - //t.printStackTrace(); - } + Object warning = Permit.invokeSneaky(this.warningKey, diags, PROC_MESSAGER, new Object[] { message }); + if (warning != null) Permit.invokeSneaky(warningMethod, log, pos, warning); } @Override void mandatoryWarning1(DiagnosticPosition pos, String message) { - try { - Object warning = this.warningKey.invoke(diags, PROC_MESSAGER, new Object[] { message }); - mandatoryWarningMethod.invoke(log, pos, warning); - } catch (Throwable t) { - //t.printStackTrace(); - } + Object warning = Permit.invokeSneaky(this.warningKey, diags, PROC_MESSAGER, new Object[] { message }); + if (warning != null) Permit.invokeSneaky(mandatoryWarningMethod, log, pos, warning); } @Override void note(DiagnosticPosition pos, String message) { - try { - Object note = this.noteKey.invoke(diags, PROC_MESSAGER, new Object[] { message }); - noteMethod.invoke(log, pos, note); - } catch (Throwable t) { - //t.printStackTrace(); - } + Object note = Permit.invokeSneaky(this.noteKey, diags, PROC_MESSAGER, new Object[] { message }); + if (note != null) Permit.invokeSneaky(noteMethod, log, pos, note); } } } diff --git a/src/core/lombok/javac/JavacASTVisitor.java b/src/core/lombok/javac/JavacASTVisitor.java index 9b67dda3..e8fd295c 100644 --- a/src/core/lombok/javac/JavacASTVisitor.java +++ b/src/core/lombok/javac/JavacASTVisitor.java @@ -22,6 +22,7 @@ package lombok.javac; import java.io.PrintStream; +import java.lang.reflect.Field; import com.sun.source.util.Trees; import com.sun.tools.javac.code.Flags; @@ -32,6 +33,7 @@ import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.util.List; /** * Implement so you can ask any JavacAST.LombokNode to traverse depth-first through all children, @@ -223,6 +225,26 @@ public interface JavacASTVisitor { } else type = "METHOD"; print("<%s %s> %s returns: %s", type, method.name, printFlags(method.mods.flags), method.restype); indent++; + JCVariableDecl recv; + try { + Field f = JCMethodDecl.class.getField("recvparam"); + recv = (JCVariableDecl) f.get(method); + } catch (Exception ignore) { + recv = null; + } + + if (recv != null) { + List<JCAnnotation> annotations = recv.mods.annotations; + if (recv.mods != null) annotations = recv.mods.annotations; + boolean innerContent = annotations != null && annotations.isEmpty(); + print("<RECEIVER-PARAM (%s) %s %s%s> %s", recv.vartype == null ? "null" : recv.vartype.getClass().toString(), recv.vartype, recv.name, innerContent ? "" : " /", printFlags(recv.mods.flags)); + if (innerContent) { + indent++; + for (JCAnnotation ann : annotations) print("<ANNOTATION: %s />", ann); + indent--; + print("</RECEIVER-PARAM>"); + } + } if (printContent) { if (method.body == null) print("(ABSTRACT)"); else print("%s", method.body); @@ -237,11 +259,11 @@ public interface JavacASTVisitor { @Override public void endVisitMethod(JavacNode node, JCMethodDecl method) { if (printContent) disablePrinting--; indent--; - print("</%s %s>", "XMETHOD", method.name); + print("</%s %s>", "METHOD", method.name); } @Override public void visitMethodArgument(JavacNode node, JCVariableDecl arg, JCMethodDecl method) { - print("<METHODARG %s %s> %s", arg.vartype, arg.name, printFlags(arg.mods.flags)); + print("<METHODARG (%s) %s %s> %s", arg.vartype.getClass().toString(), arg.vartype, arg.name, printFlags(arg.mods.flags)); indent++; } diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java index e648cd51..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 diff --git a/src/core/lombok/javac/JavacResolution.java b/src/core/lombok/javac/JavacResolution.java index 6b2f4637..e96079e0 100644 --- a/src/core/lombok/javac/JavacResolution.java +++ b/src/core/lombok/javac/JavacResolution.java @@ -25,7 +25,6 @@ import static lombok.javac.Javac.*; import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayDeque; import java.util.Collection; @@ -65,7 +64,6 @@ import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Name; -import lombok.Lombok; import lombok.core.debug.AssertionLogger; import lombok.permit.Permit; @@ -73,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); @@ -251,27 +259,27 @@ public class JavacResolution { private static class ReflectiveAccess { private static Method UPPER_BOUND; + private static Throwable initError; static { Method upperBound = null; try { upperBound = Permit.getMethod(Types.class, "upperBound", Type.class); - } catch (Throwable ignore) {} + } catch (Throwable e) { + initError = e; + } + if (upperBound == null) try { upperBound = Permit.getMethod(Types.class, "wildUpperBound", Type.class); - } catch (Throwable ignore) {} + } catch (Throwable e) { + initError = e; + } UPPER_BOUND = upperBound; } public static Type Types_upperBound(Types types, Type type) { - try { - return (Type) UPPER_BOUND.invoke(types, type); - } catch (InvocationTargetException e) { - throw Lombok.sneakyThrow(e.getCause()); - } catch (Exception e) { - throw Lombok.sneakyThrow(e); - } + return (Type) Permit.invokeSneaky(initError, UPPER_BOUND, types, type); } } @@ -354,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. @@ -452,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 368928d4..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,9 +34,9 @@ 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; final class InterceptingJavaFileObject implements LombokFileObject { private final JavaFileObject delegate; @@ -63,16 +62,8 @@ final class InterceptingJavaFileObject implements LombokFileObject { } @Override public CharsetDecoder getDecoder(boolean ignoreEncodingErrors) { - if (decoderMethod == null) { - throw new UnsupportedOperationException(); - } - try { - return (CharsetDecoder) decoderMethod.invoke(delegate, ignoreEncodingErrors); - } catch (IllegalAccessException e) { - throw Lombok.sneakyThrow(e); - } catch (InvocationTargetException e) { - throw Lombok.sneakyThrow(e); - } + if (decoderMethod == null) throw new UnsupportedOperationException(); + return (CharsetDecoder) Permit.invokeSneaky(decoderMethod, delegate, ignoreEncodingErrors); } @Override public boolean equals(Object obj) { diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index 852e5de6..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 @@ -24,8 +24,10 @@ package lombok.javac.apt; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; @@ -61,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. @@ -154,10 +158,10 @@ public class LombokProcessor extends AbstractProcessor { disablePartialReparseInNetBeansEditor(context); try { Method keyMethod = Permit.getMethod(Context.class, "key", Class.class); - Object key = keyMethod.invoke(context, JavaFileManager.class); + Object key = Permit.invoke(keyMethod, context, JavaFileManager.class); Field htField = Permit.getField(Context.class, "ht"); @SuppressWarnings("unchecked") - Map<Object,Object> ht = (Map<Object,Object>) htField.get(context); + Map<Object,Object> ht = (Map<Object,Object>) Permit.get(htField, context); final JavaFileManager originalFiler = (JavaFileManager) ht.get(key); if (!(originalFiler instanceof InterceptingJavaFileManager)) { final Messager messager = processingEnv.getMessager(); @@ -180,10 +184,10 @@ public class LombokProcessor extends AbstractProcessor { private void replaceFileManagerJdk9(Context context, JavaFileManager newFiler) { try { - JavaCompiler compiler = (JavaCompiler) Permit.getMethod(JavaCompiler.class, "instance", Context.class).invoke(null, context); + JavaCompiler compiler = (JavaCompiler) Permit.invoke(Permit.getMethod(JavaCompiler.class, "instance", Context.class), null, context); try { Field fileManagerField = Permit.getField(JavaCompiler.class, "fileManager"); - fileManagerField.set(compiler, newFiler); + Permit.set(fileManagerField, compiler, newFiler); } catch (Exception e) {} @@ -191,7 +195,7 @@ public class LombokProcessor extends AbstractProcessor { Field writerField = Permit.getField(JavaCompiler.class, "writer"); ClassWriter writer = (ClassWriter) writerField.get(compiler); Field fileManagerField = Permit.getField(ClassWriter.class, "fileManager"); - fileManagerField.set(writer, newFiler); + Permit.set(fileManagerField, writer, newFiler); } catch (Exception e) {} } @@ -213,8 +217,8 @@ public class LombokProcessor extends AbstractProcessor { private void disablePartialReparseInNetBeansEditor(Context context) { try { Class<?> cancelServiceClass = Class.forName("com.sun.tools.javac.util.CancelService"); - Method cancelServiceInstace = Permit.getMethod(cancelServiceClass, "instance", Context.class); - Object cancelService = cancelServiceInstace.invoke(null, context); + Method cancelServiceInstance = Permit.getMethod(cancelServiceClass, "instance", Context.class); + Object cancelService = Permit.invoke(cancelServiceInstance, null, context); if (cancelService == null) return; Field parserField = Permit.getField(cancelService.getClass(), "parser"); Object parser = parserField.get(cancelService); @@ -386,8 +390,8 @@ public class LombokProcessor extends AbstractProcessor { try { if (qualifiedNamableClass == null) qualifiedNamableClass = Class.forName("javax.lang.model.element.QualifiedNamable"); if (!qualifiedNamableClass.isInstance(element)) return null; - if (qualifiedNamableQualifiedNameMethod == null) qualifiedNamableQualifiedNameMethod = qualifiedNamableClass.getMethod("getQualifiedName"); - String name = qualifiedNamableQualifiedNameMethod.invoke(element).toString().trim(); + if (qualifiedNamableQualifiedNameMethod == null) qualifiedNamableQualifiedNameMethod = Permit.getMethod(qualifiedNamableClass, "getQualifiedName"); + String name = Permit.invoke(qualifiedNamableQualifiedNameMethod, element).toString().trim(); return name.isEmpty() ? null : name; } catch (ClassNotFoundException e) { return null; @@ -428,22 +432,108 @@ 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 for (Class<?> procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) { - try { - return getJavacProcessingEnvironment(tryGetDelegateField(procEnvClass, procEnv)); - } catch (final Exception e) { - // delegate field was not found, try on superclass - } + Object delegate = tryGetDelegateField(procEnvClass, procEnv); + if (delegate == null) delegate = tryGetProxyDelegateToField(procEnvClass, procEnv); + if (delegate == null) delegate = tryGetProcessingEnvField(procEnvClass, procEnv); + + if (delegate != null) return getJavacProcessingEnvironment(delegate); + // delegate field was not found, try on superclass } processingEnv.getMessager().printMessage(Kind.WARNING, "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 @@ -454,11 +544,12 @@ public class LombokProcessor extends AbstractProcessor { // try to find a "delegate" field in the object, and use this to check for a JavacFiler for (Class<?> filerClass = filer.getClass(); filerClass != null; filerClass = filerClass.getSuperclass()) { - try { - return getJavacFiler(tryGetDelegateField(filerClass, filer)); - } catch (final Exception e) { - // delegate field was not found, try on superclass - } + Object delegate = tryGetDelegateField(filerClass, filer); + if (delegate == null) delegate = tryGetProxyDelegateToField(filerClass, filer); + if (delegate == null) delegate = tryGetFilerField(filerClass, filer); + + if (delegate != null) return getJavacFiler(delegate); + // delegate field was not found, try on superclass } processingEnv.getMessager().printMessage(Kind.WARNING, @@ -466,7 +557,48 @@ public class LombokProcessor extends AbstractProcessor { return null; } - private Object tryGetDelegateField(Class<?> delegateClass, Object instance) throws Exception { - return Permit.getField(delegateClass, "delegate").get(instance); + /** + * Gradle incremental processing + */ + private Object tryGetDelegateField(Class<?> delegateClass, Object instance) { + try { + return Permit.getField(delegateClass, "delegate").get(instance); + } catch (Exception e) { + return null; + } + } + + /** + * Kotlin incremental processing + */ + private Object tryGetProcessingEnvField(Class<?> delegateClass, Object instance) { + try { + return Permit.getField(delegateClass, "processingEnv").get(instance); + } catch (Exception e) { + return null; + } + } + + /** + * Kotlin incremental processing + */ + private Object tryGetFilerField(Class<?> delegateClass, Object instance) { + try { + return Permit.getField(delegateClass, "filer").get(instance); + } catch (Exception e) { + return null; + } + } + + /** + * IntelliJ IDEA >= 2020.3 + */ + private Object tryGetProxyDelegateToField(Class<?> delegateClass, Object instance) { + try { + InvocationHandler handler = Proxy.getInvocationHandler(instance); + return Permit.getField(handler.getClass(), "val$delegateTo").get(handler); + } catch (Exception e) { + return null; + } } } diff --git a/src/core/lombok/javac/apt/Processor.java b/src/core/lombok/javac/apt/Processor.java index f15bf74c..e0de363d 100644 --- a/src/core/lombok/javac/apt/Processor.java +++ b/src/core/lombok/javac/apt/Processor.java @@ -222,7 +222,7 @@ public class Processor extends AbstractProcessor { * We just return the latest version of whatever JDK we run on. Stupid? Yeah, but it's either that or warnings on all versions but 1. */ @Override public SourceVersion getSupportedSourceVersion() { - return SourceVersion.values()[SourceVersion.values().length - 1]; + return SourceVersion.latest(); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 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 f9675813..a25baeb0 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 @@ -27,13 +27,9 @@ import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; import static lombok.javac.handlers.JavacHandlerUtil.*; import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; 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; @@ -55,6 +51,7 @@ import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeApply; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; @@ -82,18 +79,102 @@ 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(); + static final String CLEAN_FIELD_NAME = "$lombokUnclean"; + static final String CLEAN_METHOD_NAME = "$lombokClean"; + static final String TO_BUILDER_METHOD_NAME = "toBuilder"; + static final String DEFAULT_PREFIX = "$default$"; + static final String SET_PREFIX = "$set"; + static final String VALUE_PREFIX = "$value"; + static final String BUILDER_TEMP_VAR = "builder"; + static final String TO_BUILDER_NOT_SUPPORTED = "@Builder(toBuilder=true) is only supported if you return your own type."; + private static final boolean toBoolean(Object expr, boolean defaultValue) { if (expr == null) return defaultValue; if (expr instanceof JCLiteral) return ((Integer) ((JCLiteral) expr).value) != 0; return ((Boolean) expr).booleanValue(); } + static class BuilderJob { + CheckerFrameworkVersion checkerFramework; + JavacNode parentType; + String builderMethodName, buildMethodName; + boolean isStatic; + List<JCTypeParameter> typeParams; + List<JCTypeParameter> builderTypeParams; + JavacNode sourceNode; + java.util.List<BuilderFieldData> builderFields; + AccessLevel accessInners, accessOuters; + boolean oldFluent, oldChain, toBuilder; + + JavacNode builderType; + String builderClassName; + + void init(AnnotationValues<Builder> annValues, Builder ann, JavacNode node) { + accessOuters = ann.access(); + if (accessOuters == null) accessOuters = AccessLevel.PUBLIC; + if (accessOuters == AccessLevel.NONE) { + sourceNode.addError("AccessLevel.NONE is not valid here"); + accessOuters = AccessLevel.PUBLIC; + } + accessInners = accessOuters == AccessLevel.PROTECTED ? AccessLevel.PUBLIC : accessOuters; + + oldFluent = toBoolean(annValues.getActualExpression("fluent"), true); + oldChain = toBoolean(annValues.getActualExpression("chain"), true); + + builderMethodName = ann.builderMethodName(); + buildMethodName = ann.buildMethodName(); + builderClassName = fixBuilderClassName(node, ann.builderClassName()); + toBuilder = ann.toBuilder(); + + if (builderMethodName == null) builderMethodName = "builder"; + if (buildMethodName == null) buildMethodName = "build"; + if (builderClassName == null) builderClassName = ""; + } + + static String fixBuilderClassName(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; + return "*Builder"; + } + + String replaceBuilderClassName(Name name) { + if (builderClassName.indexOf('*') == -1) return builderClassName; + return builderClassName.replace("*", name.toString()); + } + + JCExpression createBuilderParentTypeReference() { + return namePlusTypeParamsToTypeReference(parentType.getTreeMaker(), parentType, typeParams); + } + + Name getBuilderClassName() { + return parentType.toName(builderClassName); + } + + List<JCTypeParameter> copyTypeParams() { + return JavacHandlerUtil.copyTypeParams(sourceNode, typeParams); + } + + Name toName(String name) { + return parentType.toName(name); + } + + Context getContext() { + return parentType.getContext(); + } + + JavacTreeMaker getTreeMaker() { + return parentType.getTreeMaker(); + } + } + static class BuilderFieldData { List<JCAnnotation> annotations; JCExpression type; @@ -111,74 +192,56 @@ 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"); - CheckerFrameworkVersion cfv = getCheckerFrameworkVersion(annotationNode); - - Builder builderInstance = annotation.getInstance(); - AccessLevel accessForOuters = builderInstance.access(); - if (accessForOuters == null) accessForOuters = AccessLevel.PUBLIC; - if (accessForOuters == AccessLevel.NONE) { - annotationNode.addError("AccessLevel.NONE is not valid here"); - accessForOuters = AccessLevel.PUBLIC; - } - AccessLevel accessForInners = accessForOuters == AccessLevel.PROTECTED ? AccessLevel.PUBLIC : accessForOuters; - - // These exist just to support the 'old' lombok.experimental.Builder, which had these properties. lombok.Builder no longer has them. - boolean fluent = toBoolean(annotation.getActualExpression("fluent"), true); - boolean chain = toBoolean(annotation.getActualExpression("chain"), true); - - String builderMethodName = builderInstance.builderMethodName(); - String buildMethodName = builderInstance.buildMethodName(); - String builderClassName = builderInstance.builderClassName(); - String toBuilderMethodName = "toBuilder"; - boolean toBuilder = builderInstance.toBuilder(); - java.util.List<Name> typeArgsForToBuilder = null; + BuilderJob job = new BuilderJob(); + job.sourceNode = annotationNode; + job.checkerFramework = getCheckerFrameworkVersion(annotationNode); + job.isStatic = true; - if (builderMethodName == null) builderMethodName = "builder"; - if (buildMethodName == null) buildMethodName = "build"; - if (builderClassName == null) builderClassName = ""; + Builder annInstance = annotation.getInstance(); + job.init(annotation, annInstance, annotationNode); + java.util.List<Name> typeArgsForToBuilder = null; boolean generateBuilderMethod; - if (builderMethodName.isEmpty()) { + if (job.builderMethodName.isEmpty()) { generateBuilderMethod = false; - } else if (!checkName("builderMethodName", builderMethodName, annotationNode)) { + } else if (!checkName("builderMethodName", job.builderMethodName, annotationNode)) { return; } else { generateBuilderMethod = true; } - if (!checkName("buildMethodName", buildMethodName, annotationNode)) return; - if (!builderClassName.isEmpty()) { - if (!checkName("builderClassName", builderClassName, annotationNode)) return; - } + if (!checkName("buildMethodName", job.buildMethodName, annotationNode)) return; - // Do not delete the Builder annotation here, we need it for @Jacksonized. + // Do not delete the Builder annotation yet, we need it for @Jacksonized. JavacNode parent = annotationNode.up(); - java.util.List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>(); - JCExpression returnType; - List<JCTypeParameter> typeParams = List.nil(); - List<JCExpression> thrownExceptions = List.nil(); + job.builderFields = new ArrayList<BuilderFieldData>(); + JCExpression buildMethodReturnType; + job.typeParams = List.nil(); + List<JCExpression> buildMethodThrownExceptions; Name nameOfBuilderMethod; - JavacNode tdParent; JavacNode fillParametersFrom = parent.get() instanceof JCMethodDecl ? parent : null; boolean addCleaning = false; - boolean isStatic = true; ArrayList<JavacNode> nonFinalNonDefaultedFields = null; - if (builderClassName.isEmpty()) builderClassName = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME); - if (builderClassName == null || builderClassName.isEmpty()) builderClassName = "*Builder"; - boolean replaceNameInBuilderClassName = builderClassName.contains("*"); - if (parent.get() instanceof JCClassDecl) { - tdParent = parent; - JCClassDecl td = (JCClassDecl) tdParent.get(); + if (!isClass(parent) && !isRecord(parent)) { + annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR); + return; + } + + job.parentType = parent; + JCClassDecl td = (JCClassDecl) parent.get(); + ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>(); boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent)); - for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) { + for (JavacNode fieldNode : HandleConstructor.findAllFields(parent, true)) { JCVariableDecl fd = (JCVariableDecl) fieldNode.get(); JavacNode isDefault = findAnnotation(Builder.Default.class, fieldNode, false); boolean isFinal = (fd.mods.flags & Flags.FINAL) != 0 || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode)); @@ -189,7 +252,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { bfd.builderFieldName = bfd.name; bfd.annotations = findCopyableAnnotations(fieldNode); bfd.type = fd.vartype; - bfd.singularData = getSingularData(fieldNode, builderInstance.setterPrefix()); + bfd.singularData = getSingularData(fieldNode, annInstance.setterPrefix()); bfd.originalFieldNode = fieldNode; if (bfd.singularData != null && isDefault != null) { @@ -211,28 +274,30 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } if (isDefault != null) { - bfd.nameOfDefaultProvider = parent.toName("$default$" + bfd.name); - bfd.nameOfSetFlag = parent.toName(bfd.name + "$set"); - bfd.builderFieldName = parent.toName(bfd.name + "$value"); + bfd.nameOfDefaultProvider = parent.toName(DEFAULT_PREFIX + bfd.name); + bfd.nameOfSetFlag = parent.toName(bfd.name + SET_PREFIX); + bfd.builderFieldName = parent.toName(bfd.name + VALUE_PREFIX); JCMethodDecl md = generateDefaultProvider(bfd.nameOfDefaultProvider, fieldNode, td.typarams); - recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); - if (md != null) injectMethod(tdParent, md); + recursiveSetGeneratedBy(md, annotationNode); + if (md != null) injectMethod(parent, md); } addObtainVia(bfd, fieldNode); - builderFields.add(bfd); + job.builderFields.add(bfd); allFields.append(fieldNode); } - if (!isRecord(tdParent)) { - handleConstructor.generateConstructor(tdParent, 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); } - returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), tdParent, td.typarams); - typeParams = td.typarams; - thrownExceptions = List.nil(); + buildMethodReturnType = namePlusTypeParamsToTypeReference(parent.getTreeMaker(), parent, td.typarams); + job.typeParams = job.builderTypeParams = td.typarams; + buildMethodThrownExceptions = List.nil(); nameOfBuilderMethod = null; - if (replaceNameInBuilderClassName) builderClassName = builderClassName.replace("*", td.name.toString()); - replaceNameInBuilderClassName = false; + job.builderClassName = job.replaceBuilderClassName(td.name); + if (!checkName("builderClassName", job.builderClassName, annotationNode)) return; } else if (fillParametersFrom != null && fillParametersFrom.getName().toString().equals("<init>")) { JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get(); if (!jmd.typarams.isEmpty()) { @@ -240,38 +305,35 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { return; } - tdParent = parent.up(); - JCClassDecl td = (JCClassDecl) tdParent.get(); - returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), tdParent, td.typarams); - typeParams = td.typarams; - thrownExceptions = jmd.thrown; + job.parentType = parent.up(); + JCClassDecl td = (JCClassDecl) job.parentType.get(); + job.typeParams = job.builderTypeParams = td.typarams; + buildMethodReturnType = job.createBuilderParentTypeReference(); + buildMethodThrownExceptions = jmd.thrown; nameOfBuilderMethod = null; - if (replaceNameInBuilderClassName) builderClassName = builderClassName.replace("*", td.name.toString()); - replaceNameInBuilderClassName = false; + job.builderClassName = job.replaceBuilderClassName(td.name); + if (!checkName("builderClassName", job.builderClassName, annotationNode)) return; } else if (fillParametersFrom != null) { - tdParent = parent.up(); - JCClassDecl td = (JCClassDecl) tdParent.get(); + job.parentType = parent.up(); + JCClassDecl td = (JCClassDecl) job.parentType.get(); JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get(); - isStatic = (jmd.mods.flags & Flags.STATIC) != 0; + job.isStatic = (jmd.mods.flags & Flags.STATIC) != 0; + JCExpression fullReturnType = jmd.restype; - returnType = fullReturnType; - typeParams = jmd.typarams; - thrownExceptions = jmd.thrown; + buildMethodReturnType = fullReturnType; + job.typeParams = job.builderTypeParams = jmd.typarams; + buildMethodThrownExceptions = jmd.thrown; nameOfBuilderMethod = jmd.name; - if (returnType instanceof JCTypeApply) { - returnType = cloneType(tdParent.getTreeMaker(), returnType, ast, annotationNode.getContext()); + if (buildMethodReturnType instanceof JCTypeApply) { + buildMethodReturnType = cloneType(job.getTreeMaker(), buildMethodReturnType, annotationNode); } - if (replaceNameInBuilderClassName) { - String replStr = returnTypeToBuilderClassName(annotationNode, td, returnType, typeParams); - if (replStr == null) - return; - builderClassName = builderClassName.replace("*", replStr); - replaceNameInBuilderClassName = false; + if (job.builderClassName.indexOf('*') > -1) { + String replStr = returnTypeToBuilderClassName(annotationNode, td, buildMethodReturnType, job.typeParams); + if (replStr == null) return; // shuold not happen + job.builderClassName = job.builderClassName.replace("*", replStr); } - if (replaceNameInBuilderClassName) builderClassName = builderClassName.replace("*", td.name.toString()); - if (toBuilder) { - final String TO_BUILDER_NOT_SUPPORTED = "@Builder(toBuilder=true) is only supported if you return your own type."; - if (returnType instanceof JCArrayTypeTree) { + if (job.toBuilder) { + if (fullReturnType instanceof JCArrayTypeTree) { annotationNode.addError(TO_BUILDER_NOT_SUPPORTED); return; } @@ -284,8 +346,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { tpOnRet = ((JCTypeApply) fullReturnType).arguments; } - JCExpression namingType = returnType; - if (returnType instanceof JCTypeApply) namingType = ((JCTypeApply) returnType).clazz; + JCExpression namingType = fullReturnType; + if (buildMethodReturnType instanceof JCTypeApply) namingType = ((JCTypeApply) buildMethodReturnType).clazz; if (namingType instanceof JCIdent) { simpleName = ((JCIdent) namingType).name; @@ -309,13 +371,13 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { return; } - if (!tdParent.getName().contentEquals(simpleName)) { + if (!job.parentType.getName().contentEquals(simpleName)) { annotationNode.addError(TO_BUILDER_NOT_SUPPORTED); return; } List<JCTypeParameter> tpOnMethod = jmd.typarams; - List<JCTypeParameter> tpOnType = ((JCClassDecl) tdParent.get()).typarams; + List<JCTypeParameter> tpOnType = ((JCClassDecl) job.parentType.get()).typarams; typeArgsForToBuilder = new ArrayList<Name>(); for (JCTypeParameter tp : tpOnMethod) { @@ -336,7 +398,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } } } else { - annotationNode.addError("@Builder is only supported on types, constructors, and methods."); + annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR); return; } @@ -351,41 +413,41 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { bfd.rawName = raw.name; bfd.annotations = findCopyableAnnotations(param); bfd.type = raw.vartype; - bfd.singularData = getSingularData(param, builderInstance.setterPrefix()); + bfd.singularData = getSingularData(param, annInstance.setterPrefix()); bfd.originalFieldNode = param; addObtainVia(bfd, param); - builderFields.add(bfd); + job.builderFields.add(bfd); } } - JavacNode builderType = findInnerClass(tdParent, builderClassName); - if (builderType == null) { - builderType = makeBuilderClass(isStatic, annotationNode, tdParent, builderClassName, typeParams, ast, accessForOuters); - recursiveSetGeneratedBy(builderType.get(), ast, annotationNode.getContext()); + job.builderType = findInnerClass(job.parentType, job.builderClassName); + if (job.builderType == null) { + job.builderType = makeBuilderClass(job); + recursiveSetGeneratedBy(job.builderType.get(), annotationNode); } else { - JCClassDecl builderTypeDeclaration = (JCClassDecl) builderType.get(); - if (isStatic && !builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)) { + JCClassDecl builderTypeDeclaration = (JCClassDecl) job.builderType.get(); + if (job.isStatic && !builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)) { annotationNode.addError("Existing Builder must be a static inner class."); return; - } else if (!isStatic && builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)) { + } else if (!job.isStatic && builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)) { annotationNode.addError("Existing Builder must be a non-static inner class."); return; } - sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode); + sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderType, annotationNode); /* generate errors for @Singular BFDs that have one already defined node. */ { - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { SingularData sd = bfd.singularData; if (sd == null) continue; JavacSingularizer singularizer = sd.getSingularizer(); if (singularizer == null) continue; - if (singularizer.checkForAlreadyExistingNodesAndGenerateError(builderType, sd)) { + if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderType, sd)) { bfd.singularData = null; } } } } - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { if (bfd.singularData.getSingularizer().requiresCleaning()) { addCleaning = true; @@ -404,75 +466,75 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } } - generateBuilderFields(builderType, builderFields, ast); + generateBuilderFields(job); if (addCleaning) { - JavacTreeMaker maker = builderType.getTreeMaker(); - JCVariableDecl uncleanField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), builderType.toName("$lombokUnclean"), maker.TypeIdent(CTC_BOOLEAN), null); - injectFieldAndMarkGenerated(builderType, uncleanField); - recursiveSetGeneratedBy(uncleanField, ast, annotationNode.getContext()); + JavacTreeMaker maker = job.getTreeMaker(); + JCVariableDecl uncleanField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), job.builderType.toName(CLEAN_FIELD_NAME), maker.TypeIdent(CTC_BOOLEAN), null); + injectFieldAndMarkGenerated(job.builderType, uncleanField); + recursiveSetGeneratedBy(uncleanField, annotationNode); } - if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, List.<JCAnnotation>nil(), builderType, List.<JavacNode>nil(), false, annotationNode); - if (cd != null) injectMethod(builderType, cd); + if (constructorExists(job.builderType) == MemberExistsResult.NOT_EXISTS) { + JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, List.<JCAnnotation>nil(), job.builderType, List.<JavacNode>nil(), false, annotationNode); + if (cd != null) injectMethod(job.builderType, cd); } - for (BuilderFieldData bfd : builderFields) { - makePrefixedSetterMethodsForBuilder(cfv, builderType, bfd, annotationNode, fluent, chain, accessForInners, builderInstance.setterPrefix()); + for (BuilderFieldData bfd : job.builderFields) { + makePrefixedSetterMethodsForBuilder(job, bfd, annInstance.setterPrefix()); } { - MemberExistsResult methodExists = methodExists(buildMethodName, builderType, -1); - if (methodExists == MemberExistsResult.EXISTS_BY_LOMBOK) methodExists = methodExists(buildMethodName, builderType, 0); + MemberExistsResult methodExists = methodExists(job.buildMethodName, job.builderType, -1); + if (methodExists == MemberExistsResult.EXISTS_BY_LOMBOK) methodExists = methodExists(job.buildMethodName, job.builderType, 0); if (methodExists == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl md = generateBuildMethod(cfv, tdParent, isStatic, buildMethodName, nameOfBuilderMethod, returnType, builderFields, builderType, thrownExceptions, ast, addCleaning, accessForInners); + JCMethodDecl md = generateBuildMethod(job, nameOfBuilderMethod, buildMethodReturnType, buildMethodThrownExceptions, addCleaning); if (md != null) { - injectMethod(builderType, md); - recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); + recursiveSetGeneratedBy(md, annotationNode); + injectMethod(job.builderType, md); } } } - if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) { + if (methodExists("toString", job.builderType, 0) == MemberExistsResult.NOT_EXISTS) { java.util.List<Included<JavacNode, ToString.Include>> fieldNodes = new ArrayList<Included<JavacNode, ToString.Include>>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { for (JavacNode f : bfd.createdFields) { fieldNodes.add(new Included<JavacNode, ToString.Include>(f, null, true, false)); } } - JCMethodDecl md = HandleToString.createToString(builderType, fieldNodes, true, false, FieldAccess.ALWAYS_FIELD, ast); - if (md != null) injectMethod(builderType, md); + JCMethodDecl md = HandleToString.createToString(job.builderType, fieldNodes, true, false, FieldAccess.ALWAYS_FIELD, job.sourceNode); + if (md != null) injectMethod(job.builderType, md); } - if (addCleaning) injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast)); + if (addCleaning) injectMethod(job.builderType, generateCleanMethod(job)); - if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; + if (generateBuilderMethod && methodExists(job.builderMethodName, job.parentType, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; if (generateBuilderMethod) { - JCMethodDecl md = generateBuilderMethod(cfv, isStatic, builderMethodName, builderClassName, annotationNode, tdParent, typeParams, accessForOuters); - recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); - if (md != null) injectMethod(tdParent, md); + JCMethodDecl md = generateBuilderMethod(job); + recursiveSetGeneratedBy(md, annotationNode); + if (md != null) injectMethod(job.parentType, md); } - if (toBuilder) { - switch (methodExists(toBuilderMethodName, tdParent, 0)) { + if (job.toBuilder) { + switch (methodExists(TO_BUILDER_METHOD_NAME, job.parentType, 0)) { case EXISTS_BY_USER: annotationNode.addWarning("Not generating toBuilder() as it already exists."); return; case NOT_EXISTS: - List<JCTypeParameter> tps = typeParams; + List<JCTypeParameter> tps = job.typeParams; if (typeArgsForToBuilder != null) { ListBuffer<JCTypeParameter> lb = new ListBuffer<JCTypeParameter>(); - JavacTreeMaker maker = tdParent.getTreeMaker(); + JavacTreeMaker maker = job.getTreeMaker(); for (Name n : typeArgsForToBuilder) { lb.append(maker.TypeParameter(n, List.<JCExpression>nil())); } tps = lb.toList(); } - JCMethodDecl md = generateToBuilderMethod(cfv, toBuilderMethodName, builderClassName, tdParent, isStatic, tps, builderFields, fluent, ast, accessForOuters, builderInstance.setterPrefix()); + JCMethodDecl md = generateToBuilderMethod(job, tps, annInstance.setterPrefix()); if (md != null) { - recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); - injectMethod(tdParent, md); + recursiveSetGeneratedBy(md, annotationNode); + injectMethod(job.parentType, md); } } } @@ -553,47 +615,41 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { sb.append("__ERR__"); } - private static final String BUILDER_TEMP_VAR = "builder"; - private JCMethodDecl generateToBuilderMethod(CheckerFrameworkVersion cfv, String toBuilderMethodName, String builderClassName, JavacNode type, boolean isStatic, List<JCTypeParameter> typeParams, java.util.List<BuilderFieldData> builderFields, boolean fluent, JCAnnotation ast, AccessLevel access, String prefix) { + private JCMethodDecl generateToBuilderMethod(BuilderJob job, List<JCTypeParameter> typeParameters, String prefix) { // return new ThingieBuilder<A, B>().setA(this.a).setB(this.b); - JavacTreeMaker maker = type.getTreeMaker(); + JavacTreeMaker maker = job.getTreeMaker(); - ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); - for (JCTypeParameter typeParam : typeParams) { - typeArgs.append(maker.Ident(typeParam.name)); - } - - JCExpression call = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, type, type.toName(builderClassName), !isStatic, typeParams), List.<JCExpression>nil(), null); + 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; ListBuffer<JCStatement> preStatements = null; ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); - for (BuilderFieldData bfd : builderFields) { - String setterPrefix = !prefix.isEmpty() ? prefix : fluent ? "" : "set"; + for (BuilderFieldData bfd : job.builderFields) { + String setterPrefix = !prefix.isEmpty() ? prefix : job.oldFluent ? "" : "set"; String prefixedSetterName = bfd.name.toString(); if (!setterPrefix.isEmpty()) prefixedSetterName = HandlerUtil.buildAccessorName(setterPrefix, prefixedSetterName); - Name setterName = type.toName(prefixedSetterName); + Name setterName = job.toName(prefixedSetterName); 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("this")), bfd.obtainVia == null ? bfd.rawName : type.toName(bfd.obtainVia.field())); + tgt[i] = maker.Select(maker.Ident(job.toName("this")), bfd.obtainVia == null ? bfd.rawName : job.toName(bfd.obtainVia.field())); } } else { String name = bfd.obtainVia.method(); JCMethodInvocation inv; if (bfd.obtainVia.isStatic()) { - JCExpression c = maker.Select(maker.Ident(type.toName(type.getName())), type.toName(name)); - inv = maker.Apply(typeParameterNames(maker, typeParams), c, List.<JCExpression>of(maker.Ident(type.toName("this")))); + JCExpression c = maker.Select(maker.Ident(job.toName(job.parentType.getName())), job.toName(name)); + inv = maker.Apply(typeParameterNames(maker, typeParameters), c, List.<JCExpression>of(maker.Ident(job.toName("this")))); } else { - JCExpression c = maker.Select(maker.Ident(type.toName("this")), type.toName(name)); + JCExpression c = maker.Select(maker.Ident(job.toName("this")), job.toName(name)); inv = maker.Apply(List.<JCExpression>nil(), c, List.<JCExpression>nil()); } for (int i = 0; i < tgt.length; i++) tgt[i] = maker.Ident(bfd.name); // javac appears to cache the type of JCMethodInvocation expressions based on position, meaning, if you have 2 ObtainVia-based method invokes on different types, you get bizarre type mismatch errors. // going via a local variable declaration solves the problem. - JCExpression varType = JavacHandlerUtil.cloneType(maker, bfd.type, ast, type.getContext()); + JCExpression varType = JavacHandlerUtil.cloneType(maker, bfd.type, job.sourceNode); if (preStatements == null) preStatements = new ListBuffer<JCStatement>(); preStatements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), bfd.name, varType, inv)); } @@ -604,15 +660,15 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { invoke = maker.Apply(List.<JCExpression>nil(), maker.Select(invoke, setterName), List.of(arg)); } else { JCExpression isNotNull = maker.Binary(CTC_NOT_EQUAL, tgt[0], maker.Literal(CTC_BOT, null)); - JCExpression invokeBuilder = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(type.toName(BUILDER_TEMP_VAR)), setterName), List.<JCExpression>of(tgt[1])); + JCExpression invokeBuilder = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(job.toName(BUILDER_TEMP_VAR)), setterName), List.<JCExpression>of(tgt[1])); statements.append(maker.If(isNotNull, maker.Exec(invokeBuilder), null)); } } if (!statements.isEmpty()) { - JCExpression tempVarType = namePlusTypeParamsToTypeReference(maker, type, type.toName(builderClassName), !isStatic, typeParams); - statements.prepend(maker.VarDef(maker.Modifiers(Flags.FINAL), type.toName(BUILDER_TEMP_VAR), tempVarType, invoke)); - statements.append(maker.Return(maker.Ident(type.toName(BUILDER_TEMP_VAR)))); + JCExpression tempVarType = namePlusTypeParamsToTypeReference(maker, job.parentType, job.getBuilderClassName(), !job.isStatic, typeParameters); + statements.prepend(maker.VarDef(maker.Modifiers(Flags.FINAL), job.toName(BUILDER_TEMP_VAR), tempVarType, invoke)); + statements.append(maker.Return(maker.Ident(job.toName(BUILDER_TEMP_VAR)))); } else { statements.append(maker.Return(invoke)); } @@ -622,77 +678,78 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { statements = preStatements; } JCBlock body = maker.Block(0, statements.toList()); - List<JCAnnotation> annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__UNIQUE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); - JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(toJavacModifier(access), annsOnMethod), type.toName(toBuilderMethodName), namePlusTypeParamsToTypeReference(maker, type, type.toName(builderClassName), !isStatic, typeParams), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); - createRelevantNonNullAnnotation(type, methodDef); + List<JCAnnotation> annsOnParamType = List.nil(); + if (job.checkerFramework.generateUnique()) annsOnParamType = List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__UNIQUE), List.<JCExpression>nil())); + JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(toJavacModifier(job.accessOuters)), job.toName(TO_BUILDER_METHOD_NAME), namePlusTypeParamsToTypeReference(maker, job.parentType, job.getBuilderClassName(), !job.isStatic, typeParameters, annsOnParamType), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); + createRelevantNonNullAnnotation(job.parentType, methodDef); return methodDef; } - private JCMethodDecl generateCleanMethod(java.util.List<BuilderFieldData> builderFields, JavacNode type, JCTree source) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateCleanMethod(BuilderJob job) { + JavacTreeMaker maker = job.getTreeMaker(); ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, type, source, statements); + bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, job.builderType, job.sourceNode, statements); } } - statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, 0)))); + statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(job.toName("this")), job.toName(CLEAN_FIELD_NAME)), maker.Literal(CTC_BOOLEAN, 0)))); JCBlock body = maker.Block(0, statements.toList()); - JCMethodDecl method = maker.MethodDef(maker.Modifiers(toJavacModifier(AccessLevel.PRIVATE)), type.toName("$lombokClean"), maker.Type(Javac.createVoidType(type.getSymbolTable(), CTC_VOID)), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); - recursiveSetGeneratedBy(method, source, type.getContext()); + JCMethodDecl method = maker.MethodDef(maker.Modifiers(toJavacModifier(AccessLevel.PRIVATE)), job.toName(CLEAN_METHOD_NAME), maker.Type(Javac.createVoidType(job.builderType.getSymbolTable(), CTC_VOID)), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); + recursiveSetGeneratedBy(method, job.sourceNode); return method; } - static List<JCVariableDecl> generateBuildArgs(CheckerFrameworkVersion cfv, JavacNode type, java.util.List<BuilderFieldData> builderFields) { - if (!cfv.generateCalledMethods()) return List.<JCVariableDecl>nil(); - + static JCVariableDecl generateReceiver(BuilderJob job) { + if (!job.checkerFramework.generateCalledMethods()) return null; + ArrayList<String> mandatories = new ArrayList<String>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData == null && bfd.nameOfSetFlag == null) mandatories.add(bfd.name.toString()); } - + JCExpression arg; - JavacTreeMaker maker = type.getTreeMaker(); - if (mandatories.size() == 0) return List.<JCVariableDecl>nil(); + JavacTreeMaker maker = job.getTreeMaker(); + if (mandatories.size() == 0) return null; if (mandatories.size() == 1) arg = maker.Literal(mandatories.get(0)); else { List<JCExpression> elems = List.nil(); for (int i = mandatories.size() - 1; i >= 0; i--) elems = elems.prepend(maker.Literal(mandatories.get(i))); arg = maker.NewArray(null, List.<JCExpression>nil(), elems); } - JCAnnotation recvAnno = maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__CALLED), List.of(arg)); - JCClassDecl builderTypeNode = (JCClassDecl) type.get(); - JCVariableDecl recv = maker.VarDef(maker.Modifiers(0L, List.<JCAnnotation>of(recvAnno)), type.toName("this"), namePlusTypeParamsToTypeReference(maker, type, builderTypeNode.typarams), null); - return List.of(recv); + JCAnnotation recvAnno = maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__CALLED), List.of(arg)); + JCClassDecl builderTypeNode = (JCClassDecl) job.builderType.get(); + JCVariableDecl recv = maker.VarDef(maker.Modifiers(Flags.PARAMETER, List.<JCAnnotation>nil()), job.toName("this"), namePlusTypeParamsToTypeReference(maker, job.builderType, builderTypeNode.typarams, List.<JCAnnotation>of(recvAnno)), null); + return recv; } - private JCMethodDecl generateBuildMethod(CheckerFrameworkVersion cfv, JavacNode tdParent, boolean isStatic, String buildName, Name builderName, JCExpression returnType, java.util.List<BuilderFieldData> builderFields, JavacNode type, List<JCExpression> thrownExceptions, JCTree source, boolean addCleaning, AccessLevel access) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateBuildMethod(BuilderJob job, Name staticName, JCExpression returnType, List<JCExpression> thrownExceptions, boolean addCleaning) { + JavacTreeMaker maker = job.getTreeMaker(); JCExpression call; ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); if (addCleaning) { - JCExpression notClean = maker.Unary(CTC_NOT, maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean"))); - JCStatement invokeClean = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(type.toName("$lombokClean")), List.<JCExpression>nil())); + JCExpression notClean = maker.Unary(CTC_NOT, maker.Select(maker.Ident(job.toName("this")), job.toName(CLEAN_FIELD_NAME))); + JCStatement invokeClean = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(job.toName(CLEAN_METHOD_NAME)), List.<JCExpression>nil())); JCIf ifUnclean = maker.If(notClean, invokeClean, null); statements.append(ifUnclean); } - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, type, source, statements, bfd.builderFieldName, "this"); + bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, job.builderType, job.sourceNode, statements, bfd.builderFieldName, "this"); } } ListBuffer<JCExpression> args = new ListBuffer<JCExpression>(); - Name thisName = type.toName("this"); - for (BuilderFieldData bfd : builderFields) { + Name thisName = job.toName("this"); + for (BuilderFieldData bfd : job.builderFields) { if (bfd.nameOfSetFlag != null) { - statements.append(maker.VarDef(maker.Modifiers(0L), bfd.builderFieldName, cloneType(maker, bfd.type, source, tdParent.getContext()), maker.Select(maker.Ident(thisName), bfd.builderFieldName))); - statements.append(maker.If(maker.Unary(CTC_NOT, maker.Select(maker.Ident(thisName), bfd.nameOfSetFlag)), maker.Exec(maker.Assign(maker.Ident(bfd.builderFieldName), maker.Apply(typeParameterNames(maker, ((JCClassDecl) tdParent.get()).typarams), maker.Select(maker.Ident(((JCClassDecl) tdParent.get()).name), bfd.nameOfDefaultProvider), List.<JCExpression>nil()))), null)); + statements.append(maker.VarDef(maker.Modifiers(0L), bfd.builderFieldName, cloneType(maker, bfd.type, job.sourceNode), maker.Select(maker.Ident(thisName), bfd.builderFieldName))); + statements.append(maker.If(maker.Unary(CTC_NOT, maker.Select(maker.Ident(thisName), bfd.nameOfSetFlag)), maker.Exec(maker.Assign(maker.Ident(bfd.builderFieldName), maker.Apply(typeParameterNames(maker, ((JCClassDecl) job.parentType.get()).typarams), maker.Select(maker.Ident(((JCClassDecl) job.parentType.get()).name), bfd.nameOfDefaultProvider), List.<JCExpression>nil()))), null)); } if (bfd.nameOfSetFlag != null || (bfd.singularData != null && bfd.singularData.getSingularizer().shadowedDuringBuild())) { args.append(maker.Ident(bfd.builderFieldName)); @@ -702,20 +759,20 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } if (addCleaning) { - statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, 1)))); + statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(job.toName("this")), job.toName(CLEAN_FIELD_NAME)), maker.Literal(CTC_BOOLEAN, 1)))); } - if (builderName == null) { + if (staticName == null) { call = maker.NewClass(null, List.<JCExpression>nil(), returnType, args.toList(), null); statements.append(maker.Return(call)); } else { ListBuffer<JCExpression> typeParams = new ListBuffer<JCExpression>(); - for (JCTypeParameter tp : ((JCClassDecl) type.get()).typarams) { + for (JCTypeParameter tp : ((JCClassDecl) job.builderType.get()).typarams) { typeParams.append(maker.Ident(tp.name)); } - JCExpression callee = maker.Ident(((JCClassDecl) type.up().get()).name); - if (!isStatic) callee = maker.Select(callee, type.up().toName("this")); - JCExpression fn = maker.Select(callee, builderName); + JCExpression callee = maker.Ident(((JCClassDecl) job.parentType.get()).name); + if (!job.isStatic) callee = maker.Select(callee, job.toName("this")); + JCExpression fn = maker.Select(callee, staticName); call = maker.Apply(typeParams.toList(), fn, args.toList()); if (returnType instanceof JCPrimitiveTypeTree && CTC_VOID.equals(typeTag(returnType))) { statements.append(maker.Exec(call)); @@ -726,10 +783,15 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { JCBlock body = maker.Block(0, statements.toList()); - List<JCAnnotation> annsOnMethod = cfv.generateSideEffectFree() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); - List<JCVariableDecl> params = generateBuildArgs(cfv, type, builderFields); - JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(toJavacModifier(access), annsOnMethod), type.toName(buildName), returnType, List.<JCTypeParameter>nil(), params, thrownExceptions, body, null); - if (builderName == null) createRelevantNonNullAnnotation(type, methodDef); + List<JCAnnotation> annsOnMethod = job.checkerFramework.generateSideEffectFree() ? List.of(maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); + JCVariableDecl recv = generateReceiver(job); + JCMethodDecl methodDef; + if (recv != null && maker.hasMethodDefWithRecvParam()) { + methodDef = maker.MethodDefWithRecvParam(maker.Modifiers(toJavacModifier(job.accessInners), annsOnMethod), job.toName(job.buildMethodName), returnType, List.<JCTypeParameter>nil(), recv, List.<JCVariableDecl>nil(), thrownExceptions, body, null); + } else { + methodDef = maker.MethodDef(maker.Modifiers(toJavacModifier(job.accessInners), annsOnMethod), job.toName(job.buildMethodName), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), thrownExceptions, body, null); + } + if (staticName == null) createRelevantNonNullAnnotation(job.builderType, methodDef); return methodDef; } @@ -742,55 +804,56 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); int modifiers = Flags.PRIVATE | Flags.STATIC; - return maker.MethodDef(maker.Modifiers(modifiers), methodName, cloneType(maker, field.vartype, field, fieldNode.getContext()), copyTypeParams(fieldNode, params), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); + return maker.MethodDef(maker.Modifiers(modifiers), methodName, cloneType(maker, field.vartype, fieldNode), copyTypeParams(fieldNode, params), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); } - public JCMethodDecl generateBuilderMethod(CheckerFrameworkVersion cfv, boolean isStatic, String builderMethodName, String builderClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams, AccessLevel access) { - JavacTreeMaker maker = type.getTreeMaker(); + public JCMethodDecl generateBuilderMethod(BuilderJob job) { + //String builderClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams, AccessLevel access) { + //builderClassName, annotationNode, tdParent, typeParams, accessForOuters); - ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); - for (JCTypeParameter typeParam : typeParams) { - typeArgs.append(maker.Ident(typeParam.name)); - } + JavacTreeMaker maker = job.getTreeMaker(); JCExpression call; - if (isStatic) { - call = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, type, type.toName(builderClassName), false, typeParams), List.<JCExpression>nil(), null); + if (job.isStatic) { + call = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderClassName), false, job.typeParams), List.<JCExpression>nil(), null); } else { - call = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, null, type.toName(builderClassName), false, typeParams), List.<JCExpression>nil(), null); - ((JCNewClass) call).encl = maker.Ident(type.toName("this")); + call = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, null, job.toName(job.builderClassName), false, job.typeParams), List.<JCExpression>nil(), null); + ((JCNewClass) call).encl = maker.Ident(job.toName("this")); } JCStatement statement = maker.Return(call); JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); - int modifiers = toJavacModifier(access); - if (isStatic) modifiers |= Flags.STATIC; - JCAnnotation annUnique = cfv.generateUnique() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__UNIQUE), List.<JCExpression>nil()) : null; - JCAnnotation annSef = cfv.generateSideEffectFree() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil()) : null; - List<JCAnnotation> annsOnMethod; - if (annUnique != null && annSef != null) annsOnMethod = List.of(annUnique, annSef); - else if (annUnique != null) annsOnMethod = List.of(annUnique); - else if (annSef != null) annsOnMethod = List.of(annSef); - else annsOnMethod = List.nil(); - JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), type.toName(builderMethodName), namePlusTypeParamsToTypeReference(maker, type, type.toName(builderClassName), !isStatic, typeParams), copyTypeParams(source, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); - createRelevantNonNullAnnotation(type, methodDef); + int modifiers = toJavacModifier(job.accessOuters); + if (job.isStatic) modifiers |= Flags.STATIC; + List<JCAnnotation> annsOnMethod = List.nil(); + if (job.checkerFramework.generateSideEffectFree()) annsOnMethod = List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())); + List<JCAnnotation> annsOnParamType = List.nil(); + if (job.checkerFramework.generateUnique()) annsOnParamType = List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__UNIQUE), List.<JCExpression>nil())); + + JCExpression returnType = namePlusTypeParamsToTypeReference(maker, job.parentType, job.getBuilderClassName(), !job.isStatic, job.builderTypeParams, annsOnParamType); + JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), job.toName(job.builderMethodName), returnType, job.copyTypeParams(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); + createRelevantNonNullAnnotation(job.parentType, methodDef); return methodDef; } - public void generateBuilderFields(JavacNode builderType, java.util.List<BuilderFieldData> builderFields, JCTree source) { - int len = builderFields.size(); + public void generateBuilderFields(BuilderJob job) { + int len = job.builderFields.size(); java.util.List<JavacNode> existing = new ArrayList<JavacNode>(); - for (JavacNode child : builderType.down()) { + for (JavacNode child : job.builderType.down()) { if (child.getKind() == Kind.FIELD) existing.add(child); } java.util.List<JCVariableDecl> generated = new ArrayList<JCVariableDecl>(); for (int i = len - 1; i >= 0; i--) { - BuilderFieldData bfd = builderFields.get(i); + BuilderFieldData bfd = job.builderFields.get(i); if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, builderType, source)); + java.util.List<JavacNode> generateSingularFields = bfd.singularData.getSingularizer().generateFields(bfd.singularData, job.builderType, job.sourceNode); + for (JavacNode field : generateSingularFields) { + generated.add((JCVariableDecl) field.get()); + } + bfd.createdFields.addAll(generateSingularFields); } else { JavacNode field = null, setFlag = null; for (JavacNode exists : existing) { @@ -798,40 +861,41 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { if (n.equals(bfd.builderFieldName)) field = exists; if (n.equals(bfd.nameOfSetFlag)) setFlag = exists; } - JavacTreeMaker maker = builderType.getTreeMaker(); + JavacTreeMaker maker = job.getTreeMaker(); if (field == null) { JCModifiers mods = maker.Modifiers(Flags.PRIVATE); - JCVariableDecl newField = maker.VarDef(mods, bfd.builderFieldName, cloneType(maker, bfd.type, source, builderType.getContext()), null); - field = injectFieldAndMarkGenerated(builderType, newField); + JCVariableDecl newField = maker.VarDef(mods, bfd.builderFieldName, cloneType(maker, bfd.type, job.sourceNode), null); + field = injectFieldAndMarkGenerated(job.builderType, newField); generated.add(newField); } if (setFlag == null && bfd.nameOfSetFlag != null) { JCModifiers mods = maker.Modifiers(Flags.PRIVATE); JCVariableDecl newField = maker.VarDef(mods, bfd.nameOfSetFlag, maker.TypeIdent(CTC_BOOLEAN), null); - injectFieldAndMarkGenerated(builderType, newField); + injectFieldAndMarkGenerated(job.builderType, newField); generated.add(newField); } bfd.createdFields.add(field); } } - for (JCVariableDecl gen : generated) recursiveSetGeneratedBy(gen, source, builderType.getContext()); + for (JCVariableDecl gen : generated) recursiveSetGeneratedBy(gen, job.sourceNode); } - public void makePrefixedSetterMethodsForBuilder(CheckerFrameworkVersion cfv, JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, boolean fluent, boolean chain, AccessLevel access, String prefix) { - boolean deprecate = isFieldDeprecated(fieldNode.originalFieldNode); - if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) { - makePrefixedSetterMethodForBuilder(cfv, builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.name, fieldNode.nameOfSetFlag, source, fluent, chain, fieldNode.annotations, fieldNode.originalFieldNode, access, prefix); + public void makePrefixedSetterMethodsForBuilder(BuilderJob job, BuilderFieldData bfd, String prefix) { + boolean deprecate = isFieldDeprecated(bfd.originalFieldNode); + if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) { + makePrefixedSetterMethodForBuilder(job, bfd, deprecate, prefix); } else { - fieldNode.singularData.getSingularizer().generateMethods(cfv, fieldNode.singularData, deprecate, builderType, source.get(), fluent, chain, access); + bfd.singularData.getSingularizer().generateMethods(job, bfd.singularData, deprecate); } } - private void makePrefixedSetterMethodForBuilder(CheckerFrameworkVersion cfv, JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, List<JCAnnotation> annosOnParam, JavacNode originalFieldNode, AccessLevel access, String prefix) { - String setterPrefix = !prefix.isEmpty() ? prefix : fluent ? "" : "set"; - String setterName = HandlerUtil.buildAccessorName(setterPrefix, paramName.toString()); - Name setterName_ = builderType.toName(setterName); + private void makePrefixedSetterMethodForBuilder(BuilderJob job, BuilderFieldData bfd, boolean deprecate, String prefix) { + JavacNode fieldNode = bfd.createdFields.get(0); + String setterPrefix = !prefix.isEmpty() ? prefix : job.oldFluent ? "" : "set"; + String setterName = HandlerUtil.buildAccessorName(setterPrefix, bfd.name.toString()); + Name setterName_ = job.builderType.toName(setterName); - for (JavacNode child : builderType.down()) { + for (JavacNode child : job.builderType.down()) { if (child.getKind() != Kind.METHOD) continue; JCMethodDecl methodDecl = (JCMethodDecl) child.get(); Name existingName = methodDecl.name; @@ -840,47 +904,45 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { JavacTreeMaker maker = fieldNode.getTreeMaker(); - List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); - JCMethodDecl newMethod = HandleSetter.createSetter(toJavacModifier(access), deprecate, fieldNode, maker, setterName, paramName, nameOfSetFlag, chain, source, methodAnns, annosOnParam); - if (cfv.generateCalledMethods()) { - JCAnnotation ncAnno = maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__NOT_CALLED), List.<JCExpression>of(maker.Literal(newMethod.getName().toString()))); - JCClassDecl builderTypeNode = (JCClassDecl) builderType.get(); - JCExpression selfType = namePlusTypeParamsToTypeReference(maker, builderType, builderTypeNode.typarams); - JCVariableDecl recv = maker.VarDef(maker.Modifiers(0L, List.<JCAnnotation>of(ncAnno)), builderType.toName("this"), selfType, null); - newMethod.params = List.of(recv, newMethod.params.get(0)); - } - recursiveSetGeneratedBy(newMethod, source.get(), builderType.getContext()); - if (source.up().getKind() == Kind.METHOD) { - copyJavadocFromParam(originalFieldNode.up(), newMethod, paramName.toString()); + List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(bfd.originalFieldNode); + JCMethodDecl newMethod = null; + if (job.checkerFramework.generateCalledMethods() && maker.hasMethodDefWithRecvParam()) { + JCAnnotation ncAnno = maker.Annotation(genTypeRef(job.sourceNode, CheckerFrameworkVersion.NAME__NOT_CALLED), List.<JCExpression>of(maker.Literal(setterName.toString()))); + JCClassDecl builderTypeNode = (JCClassDecl) job.builderType.get(); + JCExpression selfType = namePlusTypeParamsToTypeReference(maker, job.builderType, builderTypeNode.typarams, List.<JCAnnotation>of(ncAnno)); + JCVariableDecl recv = maker.VarDef(maker.Modifiers(Flags.PARAMETER, List.<JCAnnotation>nil()), job.builderType.toName("this"), selfType, null); + newMethod = HandleSetter.createSetterWithRecv(toJavacModifier(job.accessInners), deprecate, fieldNode, maker, setterName, bfd.name, bfd.nameOfSetFlag, job.oldChain, job.sourceNode, methodAnns, bfd.annotations, recv); + } + if (newMethod == null) newMethod = HandleSetter.createSetter(toJavacModifier(job.accessInners), deprecate, fieldNode, maker, setterName, bfd.name, bfd.nameOfSetFlag, job.oldChain, job.sourceNode, methodAnns, bfd.annotations); + recursiveSetGeneratedBy(newMethod, job.sourceNode); + if (job.sourceNode.up().getKind() == Kind.METHOD) { + copyJavadocFromParam(bfd.originalFieldNode.up(), newMethod, bfd.name.toString()); } else { - copyJavadoc(originalFieldNode, newMethod, CopyJavadoc.SETTER, true); + copyJavadoc(bfd.originalFieldNode, newMethod, CopyJavadoc.SETTER, true); } - injectMethod(builderType, newMethod); + injectMethod(job.builderType, newMethod); } private void copyJavadocFromParam(JavacNode from, JCMethodDecl to, String param) { try { JCCompilationUnit cu = ((JCCompilationUnit) from.top().get()); String methodComment = Javac.getDocComment(cu, from.get()); - if (methodComment == null) return; - - Pattern pattern = Pattern.compile("@param " + param + " (\\S|\\s)+?(?=^ ?@)", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); - Matcher matcher = pattern.matcher(methodComment); - if (matcher.find()) { - String newJavadoc = addReturnsThisIfNeeded(matcher.group()); - Javac.setDocComment(cu, to, newJavadoc); - } + String newJavadoc = addReturnsThisIfNeeded(getParamJavadoc(methodComment, param)); + Javac.setDocComment(cu, to, newJavadoc); } catch (Exception ignore) {} - } - - public JavacNode makeBuilderClass(boolean isStatic, JavacNode source, JavacNode tdParent, String builderClassName, List<JCTypeParameter> typeParams, JCAnnotation ast, AccessLevel access) { - JavacTreeMaker maker = tdParent.getTreeMaker(); - int modifiers = toJavacModifier(access); - if (isStatic) modifiers |= Flags.STATIC; + } + + public JavacNode makeBuilderClass(BuilderJob job) { + //boolean isStatic, JavacNode source, JavacNode tdParent, String builderClassName, List<JCTypeParameter> typeParams, JCAnnotation ast, AccessLevel access) { + //isStatic, annotationNode, tdParent, builderClassName, typeParams, ast, accessForOuters + JavacTreeMaker maker = job.getTreeMaker(); + int modifiers = toJavacModifier(job.accessOuters); + if (job.isStatic) modifiers |= Flags.STATIC; JCModifiers mods = maker.Modifiers(modifiers); - JCClassDecl builder = maker.ClassDef(mods, tdParent.toName(builderClassName), copyTypeParams(source, typeParams), null, List.<JCExpression>nil(), List.<JCTree>nil()); - return injectType(tdParent, builder); + JCClassDecl builder = maker.ClassDef(mods, job.getBuilderClassName(), job.copyTypeParams(), null, List.<JCExpression>nil(), List.<JCTree>nil()); + recursiveSetGeneratedBy(builder, job.sourceNode); + return injectType(job.parentType, builder); } private void addObtainVia(BuilderFieldData bfd, JavacNode node) { diff --git a/src/core/lombok/javac/handlers/HandleBuilderDefault.java b/src/core/lombok/javac/handlers/HandleBuilderDefault.java index df5eebc9..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) { @@ -55,6 +54,7 @@ public class HandleBuilderDefault extends JavacAnnotationHandler<Builder.Default JCFieldAccess jfa = (JCFieldAccess) ast.annotationType; if (jfa.selected instanceof JCIdent && ((JCIdent) jfa.selected).name.contentEquals("Builder") && jfa.name.contentEquals("Default")) { JCFieldAccess newJfaSel = annotationNode.getTreeMaker().Select(annotationNode.getTreeMaker().Ident(annotationNode.toName("lombok")), ((JCIdent) jfa.selected).name); + recursiveSetGeneratedBy(newJfaSel, annotationNode); jfa.selected = newJfaSel; } } 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 4aa61764..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; @@ -52,7 +51,6 @@ import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeCast; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; @@ -60,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"); @@ -129,10 +127,9 @@ public class HandleCleanup extends JavacAnnotationHandler<Cleanup> { JCIf ifNotNullCleanup = maker.If(isNull, maker.Block(0, cleanupCall), null); - Context context = annotationNode.getContext(); - JCBlock finalizer = recursiveSetGeneratedBy(maker.Block(0, List.<JCStatement>of(ifNotNullCleanup)), ast, context); + JCBlock finalizer = recursiveSetGeneratedBy(maker.Block(0, List.<JCStatement>of(ifNotNullCleanup)), annotationNode); - newStatements.append(setGeneratedBy(maker.Try(setGeneratedBy(maker.Block(0, tryBlock.toList()), ast, context), List.<JCCatch>nil(), finalizer), ast, context)); + newStatements.append(setGeneratedBy(maker.Try(setGeneratedBy(maker.Block(0, tryBlock.toList()), annotationNode), List.<JCCatch>nil(), finalizer), annotationNode)); if (blockNode instanceof JCBlock) { ((JCBlock)blockNode).stats = newStatements.toList(); diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index 54a9f821..9c74ca0e 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.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Type; @@ -55,18 +53,17 @@ import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; -import lombok.core.LombokNode; import lombok.core.configuration.CheckerFrameworkVersion; import lombok.delombok.LombokOptionsFactory; import lombok.javac.Javac; -import lombok.javac.JavacAST; 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(); @@ -88,7 +85,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(); @@ -138,7 +135,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(); @@ -264,11 +261,11 @@ public class HandleConstructor { generateStaticConstructor(staticConstrRequired, typeNode, staticName, level, allToDefault, fields, source, argTypes_); } - private void generateStaticConstructor(boolean staticConstrRequired, JavacNode typeNode, String staticName, AccessLevel level, boolean allToDefault, List<JavacNode> fields, LombokNode<JavacAST, JavacNode, JCTree> source, List<Type> argTypes_) { + private void generateStaticConstructor(boolean staticConstrRequired, JavacNode typeNode, String staticName, AccessLevel level, boolean allToDefault, List<JavacNode> fields, JavacNode source, List<Type> argTypes_) { if (staticConstrRequired) { ClassSymbol sym = ((JCClassDecl) typeNode.get()).sym; Type returnType = sym == null ? null : sym.type; - JCMethodDecl staticConstr = createStaticConstructor(staticName, level, typeNode, allToDefault ? List.<JavacNode>nil() : fields, source.get()); + JCMethodDecl staticConstr = createStaticConstructor(staticName, level, typeNode, allToDefault ? List.<JavacNode>nil() : fields, source); injectMethod(typeNode, staticConstr, argTypes_, returnType); } } @@ -337,7 +334,7 @@ public class HandleConstructor { Name rawName = field.name; List<JCAnnotation> copyableAnnotations = findCopyableAnnotations(fieldNode); long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext()); - JCExpression pType = cloneType(fieldNode.getTreeMaker(), field.vartype, source.get(), source.getContext()); + JCExpression pType = cloneType(fieldNode.getTreeMaker(), field.vartype, source); JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, copyableAnnotations), fieldName, pType, null); params.append(param); if (hasNonNullAnnotations(fieldNode)) { @@ -372,10 +369,9 @@ public class HandleConstructor { addConstructorProperties(mods, typeNode, fieldsToParam); } if (onConstructor != null) mods.annotations = mods.annotations.appendList(copyAnnotations(onConstructor)); - if (getCheckerFrameworkVersion(source).generateUnique()) mods.annotations = mods.annotations.prepend(maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__UNIQUE), List.<JCExpression>nil())); return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("<init>"), null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(), - maker.Block(0L, nullChecks.appendList(assigns).toList()), null), source.get(), typeNode.getContext()); + maker.Block(0L, nullChecks.appendList(assigns).toList()), null), source); } /** @@ -446,12 +442,11 @@ public class HandleConstructor { return true; } - public JCMethodDecl createStaticConstructor(String name, AccessLevel level, JavacNode typeNode, List<JavacNode> fields, JCTree source) { + public JCMethodDecl createStaticConstructor(String name, AccessLevel level, JavacNode typeNode, List<JavacNode> fields, JavacNode source) { JavacTreeMaker maker = typeNode.getTreeMaker(); JCClassDecl type = (JCClassDecl) typeNode.get(); JCModifiers mods = maker.Modifiers(Flags.STATIC | toJavacModifier(level)); - if (getCheckerFrameworkVersion(typeNode).generateUnique()) mods.annotations = mods.annotations.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__UNIQUE), List.<JCExpression>nil())); JCExpression returnType, constructorType; @@ -464,13 +459,15 @@ public class HandleConstructor { typeParams.append(maker.TypeParameter(param.name, param.bounds)); } } - returnType = namePlusTypeParamsToTypeReference(maker, typeNode, type.typarams); + List<JCAnnotation> annsOnReturnType = List.nil(); + if (getCheckerFrameworkVersion(typeNode).generateUnique()) annsOnReturnType = List.of(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__UNIQUE), List.<JCExpression>nil())); + returnType = namePlusTypeParamsToTypeReference(maker, typeNode, type.typarams, annsOnReturnType); constructorType = namePlusTypeParamsToTypeReference(maker, typeNode, type.typarams); for (JavacNode fieldNode : fields) { JCVariableDecl field = (JCVariableDecl) fieldNode.get(); Name fieldName = removePrefixFromField(fieldNode); - JCExpression pType = cloneType(maker, field.vartype, source, typeNode.getContext()); + JCExpression pType = cloneType(maker, field.vartype, source); List<JCAnnotation> copyableAnnotations = findCopyableAnnotations(fieldNode); long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext()); JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, copyableAnnotations), fieldName, pType, null); @@ -482,6 +479,6 @@ public class HandleConstructor { JCMethodDecl methodDef = maker.MethodDef(mods, typeNode.toName(name), returnType, typeParams.toList(), params.toList(), List.<JCExpression>nil(), body, null); createRelevantNonNullAnnotation(typeNode, methodDef); - return recursiveSetGeneratedBy(methodDef, source, typeNode.getContext()); + return recursiveSetGeneratedBy(methodDef, source); } } 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 d6e76ab1..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; @@ -81,8 +79,10 @@ import lombok.javac.JavacResolution; 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> { @@ -348,7 +348,7 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> { JCStatement body = useReturn ? maker.Return(delegateCall) : maker.Exec(delegateCall); JCBlock bodyBlock = maker.Block(0, com.sun.tools.javac.util.List.of(body)); - return recursiveSetGeneratedBy(maker.MethodDef(mods, sig.name, returnType, toList(typeParams), toList(params), toList(thrown), bodyBlock, null), annotation.get(), annotation.getContext()); + return recursiveSetGeneratedBy(maker.MethodDef(mods, sig.name, returnType, toList(typeParams), toList(params), toList(thrown), bodyBlock, null), annotation); } public static <T> com.sun.tools.javac.util.List<T> toList(ListBuffer<T> collection) { @@ -466,7 +466,7 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> { static { Method m = null; try { - m = Type.class.getDeclaredMethod("unannotatedType"); + m = Permit.getMethod(Type.class, "unannotatedType"); } catch (Exception e) {/* ignore */} unannotated = m; } @@ -474,7 +474,7 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> { static Type unannotatedType(Type t) { if (unannotated == null) return t; try { - return (Type) unannotated.invoke(t); + return (Type) Permit.invoke(unannotated, t); } catch (Exception e) { return t; } diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index e35deb5b..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,11 +30,8 @@ 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; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; import com.sun.tools.javac.tree.JCTree.JCBinary; @@ -42,6 +39,8 @@ 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; +import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCModifiers; @@ -56,6 +55,7 @@ import com.sun.tools.javac.util.Name; import lombok.ConfigurationKeys; import lombok.EqualsAndHashCode; +import lombok.EqualsAndHashCode.CacheStrategy; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.configuration.CallSuperType; @@ -68,19 +68,22 @@ 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"; + private static final String HASH_CODE_CACHE_NAME = "$hashCodeCache"; @Override public void handle(AnnotationValues<EqualsAndHashCode> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.EQUALS_AND_HASH_CODE_FLAG_USAGE, "@EqualsAndHashCode"); deleteAnnotationIfNeccessary(annotationNode, EqualsAndHashCode.class); + deleteImportFromCompilationUnit(annotationNode, CacheStrategy.class.getName()); EqualsAndHashCode ann = annotation.getInstance(); java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(annotationNode.up(), annotation, annotationNode); JavacNode typeNode = annotationNode.up(); @@ -93,7 +96,9 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration; FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER; - generateMethods(typeNode, annotationNode, members, callSuper, true, fieldAccess, onParam); + boolean cacheHashCode = ann.cacheStrategy() == CacheStrategy.LAZY; + + generateMethods(typeNode, annotationNode, members, callSuper, true, cacheHashCode, fieldAccess, onParam); } public void generateEqualsAndHashCodeForType(JavacNode typeNode, JavacNode source) { @@ -107,11 +112,11 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(typeNode, null, null); - generateMethods(typeNode, source, members, null, false, access, List.<JCAnnotation>nil()); + generateMethods(typeNode, source, members, null, false, false, access, List.<JCAnnotation>nil()); } public void generateMethods(JavacNode typeNode, JavacNode source, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members, - Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<JCAnnotation> onParam) { + Boolean callSuper, boolean whineIfExists, boolean cacheHashCode, FieldAccess fieldAccess, List<JCAnnotation> onParam) { if (!isClass(typeNode)) { source.addError("@EqualsAndHashCode is only supported on a class."); @@ -129,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); @@ -181,26 +162,72 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas //fallthrough } - JCMethodDecl equalsMethod = createEquals(typeNode, members, callSuper, fieldAccess, needsCanEqual, source.get(), onParam); + 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); if (needsCanEqual && canEqualExists == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl canEqualMethod = createCanEqual(typeNode, source.get(), onParam); + JCMethodDecl canEqualMethod = createCanEqual(typeNode, source, onParam); injectMethod(typeNode, canEqualMethod); } - JCMethodDecl hashCodeMethod = createHashCode(typeNode, members, callSuper, fieldAccess, source.get()); + if (cacheHashCode){ + if (fieldExists(HASH_CODE_CACHE_NAME, typeNode) != MemberExistsResult.NOT_EXISTS) { + String msg = String.format("Not caching the result of hashCode: A field named %s already exists.", HASH_CODE_CACHE_NAME); + source.addWarning(msg); + cacheHashCode = false; + } else { + createHashCodeCacheField(typeNode, source); + } + } + + JCMethodDecl hashCodeMethod = createHashCode(typeNode, members, callSuper, cacheHashCode, fieldAccess, source); injectMethod(typeNode, hashCodeMethod); } + + private void createHashCodeCacheField(JavacNode typeNode, JavacNode source) { + JavacTreeMaker maker = typeNode.getTreeMaker(); + JCModifiers mods = maker.Modifiers(Flags.PRIVATE | Flags.TRANSIENT); + JCVariableDecl hashCodeCacheField = maker.VarDef(mods, typeNode.toName(HASH_CODE_CACHE_NAME), maker.TypeIdent(CTC_INT), null); + injectFieldAndMarkGenerated(typeNode, hashCodeCacheField); + recursiveSetGeneratedBy(hashCodeCacheField, source); + } - public JCMethodDecl createHashCode(JavacNode typeNode, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members, boolean callSuper, FieldAccess fieldAccess, JCTree source) { + public JCMethodDecl createHashCode(JavacNode typeNode, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members, boolean callSuper, boolean cacheHashCode, FieldAccess fieldAccess, JavacNode source) { JavacTreeMaker maker = typeNode.getTreeMaker(); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil()); List<JCAnnotation> annsOnMethod = List.of(overrideAnnotation); CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(typeNode); - if (checkerFramework.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())); + if (cacheHashCode && checkerFramework.generatePure()) { + annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__PURE), List.<JCExpression>nil())); + } else if (checkerFramework.generateSideEffectFree()) { + annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())); + } JCModifiers mods = maker.Modifiers(Flags.PUBLIC, annsOnMethod); JCExpression returnType = maker.TypeIdent(CTC_INT); ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); @@ -211,6 +238,15 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas boolean isEmpty = members.isEmpty(); + /* if (this.$hashCodeCache != 0) return this.$hashCodeCache; */ { + if (cacheHashCode) { + JCIdent receiver = maker.Ident(typeNode.toName("this")); + JCFieldAccess cacheHashCodeFieldAccess = maker.Select(receiver, typeNode.toName(HASH_CODE_CACHE_NAME)); + JCExpression cacheNotZero = maker.Binary(CTC_NOT_EQUAL, cacheHashCodeFieldAccess, maker.Literal(CTC_INT, 0)); + statements.append(maker.If(cacheNotZero, maker.Return(cacheHashCodeFieldAccess), null)); + } + } + /* final int PRIME = X; */ { if (!isEmpty) { statements.append(maker.VarDef(maker.Modifiers(finalFlag), primeName, maker.TypeIdent(CTC_INT), maker.Literal(HandlerUtil.primeForHashcode()))); @@ -228,7 +264,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas /* ... 1; */ init = maker.Literal(1); } - statements.append(maker.VarDef(maker.Modifiers(isEmpty ? finalFlag : 0), resultName, maker.TypeIdent(CTC_INT), init)); + statements.append(maker.VarDef(maker.Modifiers(isEmpty && !cacheHashCode ? finalFlag : 0L), resultName, maker.TypeIdent(CTC_INT), init)); } for (Included<JavacNode, EqualsAndHashCode.Include> member : members) { @@ -300,13 +336,27 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } } + /* + * if (result == 0) result = Integer.MIN_VALUE; + * this.$hashCodeCache = result; + * + */ { + if (cacheHashCode) { + statements.append(maker.If(maker.Binary(CTC_EQUAL, maker.Ident(resultName), maker.Literal(CTC_INT, 0)), + maker.Exec(maker.Assign(maker.Ident(resultName), genJavaLangTypeRef(typeNode, "Integer", "MIN_VALUE"))), null)); + + JCFieldAccess cacheHashCodeFieldAccess = maker.Select(maker.Ident(typeNode.toName("this")), typeNode.toName(HASH_CODE_CACHE_NAME)); + statements.append(maker.Exec(maker.Assign(cacheHashCodeFieldAccess, maker.Ident(resultName)))); + } + } + /* return result; */ { statements.append(maker.Return(maker.Ident(resultName))); } JCBlock body = maker.Block(0, statements.toList()); return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("hashCode"), returnType, - List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null), source, typeNode.getContext()); + List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null), source); } public JCExpressionStatement createResultCalculation(JavacNode typeNode, JCExpression expr) { @@ -368,7 +418,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas return maker.TypeApply(expr, wildcards.toList()); } - public JCMethodDecl createEquals(JavacNode typeNode, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source, List<JCAnnotation> onParam) { + public JCMethodDecl createEquals(JavacNode typeNode, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JavacNode source, List<JCAnnotation> onParam) { JavacTreeMaker maker = typeNode.getTreeMaker(); Name oName = typeNode.toName("o"); @@ -502,10 +552,10 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } JCBlock body = maker.Block(0, statements.toList()); - return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("equals"), returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source, typeNode.getContext()); + return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("equals"), returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source); } - public JCMethodDecl createCanEqual(JavacNode typeNode, JCTree source, List<JCAnnotation> onParam) { + public JCMethodDecl createCanEqual(JavacNode typeNode, JavacNode source, List<JCAnnotation> onParam) { /* protected boolean canEqual(final java.lang.Object other) { * return other instanceof Outer.Inner.MyType; * } @@ -530,7 +580,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas JCBlock body = maker.Block(0, List.<JCStatement>of( maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode, false))))); - return recursiveSetGeneratedBy(maker.MethodDef(mods, canEqualName, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source, typeNode.getContext()); + return recursiveSetGeneratedBy(maker.MethodDef(mods, canEqualName, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source); } public JCStatement generateCompareFloatOrDouble(JCExpression thisDotField, JCExpression otherDotField, diff --git a/src/core/lombok/javac/handlers/HandleExtensionMethod.java b/src/core/lombok/javac/handlers/HandleExtensionMethod.java index 345c5f8e..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 @@ -28,6 +28,7 @@ import static lombok.javac.handlers.JavacResolver.*; import java.util.ArrayList; import java.util.List; +import java.util.Map; import javax.lang.model.element.ElementKind; @@ -37,12 +38,13 @@ import lombok.core.HandlerPriority; import lombok.experimental.ExtensionMethod; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; - -import org.mangosdk.spi.ProviderFor; +import lombok.javac.JavacResolution; +import lombok.spi.Provides; import com.sun.source.tree.MethodInvocationTree; import com.sun.source.util.TreeScanner; import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.code.Symbol.TypeSymbol; import com.sun.tools.javac.code.Type; @@ -51,6 +53,7 @@ import com.sun.tools.javac.code.Type.ErrorType; import com.sun.tools.javac.code.Type.ForAll; import com.sun.tools.javac.code.Type.MethodType; import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCExpression; @@ -61,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 @@ -148,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) { @@ -166,13 +170,25 @@ public class HandleExtensionMethod extends JavacAnnotationHandler<ExtensionMetho JCExpression receiver = receiverOf(methodCall); String methodName = methodNameOf(methodCall); - if ("this".equals(methodName) || "super".equals(methodName)) return; - Type resolvedMethodCall = CLASS_AND_METHOD.resolveMember(methodCallNode, methodCall); - if (resolvedMethodCall == null) return; - if (!suppressBaseMethods && !(resolvedMethodCall instanceof ErrorType)) return; - Type receiverType = CLASS_AND_METHOD.resolveMember(methodCallNode, receiver); - if (receiverType == null) return; - if (receiverType.tsym.toString().endsWith(receiver.toString())) return; + if ("this".equals(receiver.toString()) || "this".equals(methodName) || "super".equals(methodName)) return; + Map<JCTree, JCTree> resolution = new JavacResolution(methodCallNode.getContext()).resolveMethodMember(methodCallNode); + + JCTree resolvedMethodCall = resolution.get(methodCall); + if (resolvedMethodCall == null || resolvedMethodCall.type == null) return; + if (!suppressBaseMethods && !(resolvedMethodCall.type instanceof ErrorType)) return; + + JCTree resolvedReceiver = resolution.get(receiver); + if (resolvedReceiver == null || resolvedReceiver.type == null) return; + Type receiverType = resolvedReceiver.type; + + // Skip static method access + Symbol sym = null; + if (resolvedReceiver instanceof JCIdent) { + sym = ((JCIdent) resolvedReceiver).sym; + } else if (resolvedReceiver instanceof JCFieldAccess) { + sym = ((JCFieldAccess) resolvedReceiver).sym; + } + if (sym instanceof ClassSymbol) return; Types types = Types.instance(annotationNode.getContext()); for (Extension extension : extensions) { @@ -186,6 +202,7 @@ public class HandleExtensionMethod extends JavacAnnotationHandler<ExtensionMetho if (!types.isAssignable(receiverType, firstArgType)) continue; methodCall.args = methodCall.args.prepend(receiver); methodCall.meth = chainDotsString(annotationNode, extensionProvider.toString() + "." + methodName); + recursiveSetGeneratedBy(methodCall.meth, methodCallNode); return; } } diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java index c974bdb9..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) { diff --git a/src/core/lombok/javac/handlers/HandleFieldNameConstants.java b/src/core/lombok/javac/handlers/HandleFieldNameConstants.java index ec4015c7..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"); @@ -78,7 +77,7 @@ public class HandleFieldNameConstants extends JavacAnnotationHandler<FieldNameCo if (qualified.isEmpty()) { errorNode.addWarning("No fields qualify for @FieldNameConstants, therefore this annotation does nothing"); } else { - createInnerTypeFieldNameConstants(typeNode, errorNode, errorNode.get(), level, qualified, asEnum, innerTypeName, uppercase); + createInnerTypeFieldNameConstants(typeNode, errorNode, level, qualified, asEnum, innerTypeName, uppercase); } } @@ -133,7 +132,7 @@ public class HandleFieldNameConstants extends JavacAnnotationHandler<FieldNameCo generateFieldNameConstantsForType(node, annotationNode, level, asEnum, innerTypeName, annotationInstance.onlyExplicitlyIncluded(), uppercase); } - private void createInnerTypeFieldNameConstants(JavacNode typeNode, JavacNode errorNode, JCTree pos, AccessLevel level, java.util.List<JavacNode> fields, boolean asEnum, IdentifierName innerTypeName, boolean uppercase) { + private void createInnerTypeFieldNameConstants(JavacNode typeNode, JavacNode errorNode, AccessLevel level, java.util.List<JavacNode> fields, boolean asEnum, IdentifierName innerTypeName, boolean uppercase) { if (fields.isEmpty()) return; JavacTreeMaker maker = typeNode.getTreeMaker(); @@ -146,7 +145,7 @@ public class HandleFieldNameConstants extends JavacAnnotationHandler<FieldNameCo if (fieldsType == null) { JCClassDecl innerType = maker.ClassDef(mods, fieldsName, List.<JCTypeParameter>nil(), null, List.<JCExpression>nil(), List.<JCTree>nil()); fieldsType = injectType(typeNode, innerType); - recursiveSetGeneratedBy(innerType, pos, typeNode.getContext()); + recursiveSetGeneratedBy(innerType, errorNode); genConstr = true; } else { JCClassDecl builderTypeDeclaration = (JCClassDecl) fieldsType.get(); @@ -166,7 +165,7 @@ public class HandleFieldNameConstants extends JavacAnnotationHandler<FieldNameCo JCModifiers genConstrMods = maker.Modifiers(Flags.GENERATEDCONSTR | (asEnum ? 0L : Flags.PRIVATE)); JCBlock genConstrBody = maker.Block(0L, List.<JCStatement>of(maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(typeNode.toName("super")), List.<JCExpression>nil())))); JCMethodDecl c = maker.MethodDef(genConstrMods, typeNode.toName("<init>"), null, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), genConstrBody, null); - recursiveSetGeneratedBy(c, pos, typeNode.getContext()); + recursiveSetGeneratedBy(c, errorNode); injectMethod(fieldsType, c); } @@ -187,9 +186,9 @@ public class HandleFieldNameConstants extends JavacAnnotationHandler<FieldNameCo } JCVariableDecl constantField = maker.VarDef(constantValueMods, fName, returnType, init); injectField(fieldsType, constantField, false, true); - setGeneratedBy(constantField, pos, typeNode.getContext()); + setGeneratedBy(constantField, errorNode); generated.add(constantField); } - for (JCVariableDecl cf : generated) recursiveSetGeneratedBy(cf, pos, typeNode.getContext()); + for (JCVariableDecl cf : generated) recursiveSetGeneratedBy(cf, errorNode); } } diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index 1b4d404b..8f6de9bb 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,8 +43,7 @@ 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.code.Type; @@ -70,8 +69,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)) { @@ -81,7 +82,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { } if (!isClassOrEnum(typeNode)) { - errorNode.addError("@Getter is only supported on a class, an enum, or a field."); + errorNode.addError(GETTER_NODE_NOT_SUPPORTED_ERR); return; } @@ -165,7 +166,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { JavacNode fieldNode, JavacNode source, boolean whineIfExists, boolean lazy, List<JCAnnotation> onMethod) { if (fieldNode.getKind() != Kind.FIELD) { - source.addError("@Getter is only supported on a class or a field."); + source.addError(GETTER_NODE_NOT_SUPPORTED_ERR); return; } @@ -213,14 +214,14 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC); - injectMethod(fieldNode.up(), createGetter(access, fieldNode, fieldNode.getTreeMaker(), source.get(), lazy, onMethod), List.<Type>nil(), getMirrorForFieldType(fieldNode)); + injectMethod(fieldNode.up(), createGetter(access, fieldNode, fieldNode.getTreeMaker(), source, lazy, onMethod), List.<Type>nil(), getMirrorForFieldType(fieldNode)); } - public JCMethodDecl createGetter(long access, JavacNode field, JavacTreeMaker treeMaker, JCTree source, boolean lazy, List<JCAnnotation> onMethod) { + public JCMethodDecl createGetter(long access, JavacNode field, JavacTreeMaker treeMaker, JavacNode source, boolean lazy, List<JCAnnotation> onMethod) { JCVariableDecl fieldNode = (JCVariableDecl) field.get(); // Remember the type; lazy will change it - JCExpression methodType = cloneType(treeMaker, copyType(treeMaker, fieldNode), source, field.getContext()); + JCExpression methodType = cloneType(treeMaker, copyType(treeMaker, fieldNode), source); // Generate the methodName; lazy will change the field type Name methodName = field.toName(toGetterName(field)); @@ -261,9 +262,9 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { if (isFieldDeprecated(field)) annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>nil())); JCMethodDecl decl = recursiveSetGeneratedBy(treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType, - methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source, field.getContext()); + methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source); - if (toClearOfMarkers != null) recursiveSetGeneratedBy(toClearOfMarkers, null, null); + if (toClearOfMarkers != null) recursiveSetGeneratedBy(toClearOfMarkers, null); if (methodArgPos != null) { for (int i = 0; i < methodArgPos.length; i++) { ((JCMethodInvocation) toClearOfMarkers).args.get(i).pos = methodArgPos[i]; @@ -274,10 +275,10 @@ 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")); - addAnnotation(decl.mods, field, source.pos, source, field.getContext(), "java.lang.SuppressWarnings", treeMaker.NewArray(null, List.<JCExpression>nil(), suppressions.toList())); + suppressions.append(treeMaker.Literal("unchecked")); + addAnnotation(decl.mods, field, source, "java.lang.SuppressWarnings", treeMaker.NewArray(null, List.<JCExpression>nil(), suppressions.toList())); } copyJavadoc(field, decl, CopyJavadoc.GETTER); @@ -328,7 +329,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { TYPE_MAP = Collections.unmodifiableMap(m); } - public List<JCStatement> createLazyGetterBody(JavacTreeMaker maker, JavacNode fieldNode, JCTree source) { + public List<JCStatement> createLazyGetterBody(JavacTreeMaker maker, JavacNode fieldNode, JavacNode source) { /* java.lang.Object value = this.fieldName.get(); if (value == null) { @@ -374,7 +375,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { /* java.lang.Object value = this.fieldName.get();*/ { JCExpression valueVarType = genJavaLangTypeRef(fieldNode, "Object"); - statements.append(maker.VarDef(maker.Modifiers(0), valueName, valueVarType, callGet(fieldNode, createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD)))); + statements.append(maker.VarDef(maker.Modifiers(0L), valueName, valueVarType, callGet(fieldNode, createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD)))); } /* if (value == null) { */ { @@ -441,8 +442,8 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { /* private final java.util.concurrent.atomic.AtomicReference<Object> fieldName = new java.util.concurrent.atomic.AtomicReference<Object>(); */ { field.vartype = recursiveSetGeneratedBy( - maker.TypeApply(chainDotsString(fieldNode, AR), List.<JCExpression>of(genJavaLangTypeRef(fieldNode, "Object"))), source, fieldNode.getContext()); - field.init = recursiveSetGeneratedBy(maker.NewClass(null, NIL_EXPRESSION, copyType(maker, field), NIL_EXPRESSION, null), source, fieldNode.getContext()); + maker.TypeApply(chainDotsString(fieldNode, AR), List.<JCExpression>of(genJavaLangTypeRef(fieldNode, "Object"))), source); + field.init = recursiveSetGeneratedBy(maker.NewClass(null, NIL_EXPRESSION, copyType(maker, field), NIL_EXPRESSION, null), source); } return statements.toList(); diff --git a/src/core/lombok/javac/handlers/HandleHelper.java b/src/core/lombok/javac/handlers/HandleHelper.java index 6f4361c1..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; @@ -71,7 +70,7 @@ public class HandleHelper extends JavacAnnotationHandler<Helper> { else throw new IllegalArgumentException("Can't set statements on node type: " + tree.getClass()); } - @Override public void handle(AnnotationValues<Helper> annotation, JCAnnotation ast, JavacNode annotationNode) { + @Override public void handle(AnnotationValues<Helper> annotation, JCAnnotation ast, final JavacNode annotationNode) { handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.HELPER_FLAG_USAGE, "@Helper"); deleteAnnotationIfNeccessary(annotationNode, Helper.class); @@ -120,6 +119,7 @@ public class HandleHelper extends JavacAnnotationHandler<Helper> { JCIdent jci = (JCIdent) jcmi.meth; if (Arrays.binarySearch(knownMethodNames_, jci.name.toString()) < 0) return; jcmi.meth = maker.Select(maker.Ident(helperName), jci.name); + recursiveSetGeneratedBy(jcmi.meth, annotationNode); helperUsed[0] = true; } }; @@ -144,6 +144,7 @@ public class HandleHelper extends JavacAnnotationHandler<Helper> { JCExpression init = maker.NewClass(null, List.<JCExpression>nil(), maker.Ident(annotatedType_.name), List.<JCExpression>nil(), null); JCExpression varType = maker.Ident(annotatedType_.name); JCVariableDecl decl = maker.VarDef(maker.Modifiers(Flags.FINAL), helperName, varType, init); + recursiveSetGeneratedBy(decl, annotationNode); newStatements.append(decl); } setStatementsOfJcNode(containingBlock.get(), newStatements.toList()); diff --git a/src/core/lombok/javac/handlers/HandleJacksonized.java b/src/core/lombok/javac/handlers/HandleJacksonized.java index 0aa02d1b..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> { @@ -107,7 +106,7 @@ public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> { JavacTreeMaker maker = annotatedNode.getTreeMaker(); // Now lets find the generated builder class. - String builderClassName = getBuilderClassName(ast, annotationNode, annotatedNode, td, builderAnnotation, maker); + String builderClassName = getBuilderClassName(annotationNode, annotatedNode, td, builderAnnotation, maker); JCClassDecl builderClass = null; for (JCTree member : td.getMembers()) { @@ -132,11 +131,15 @@ public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> { JCFieldAccess builderClassReference = maker.Select(builderClassExpression, annotatedNode.toName("class")); JCExpression assign = maker.Assign(maker.Ident(annotationNode.toName("builder")), builderClassReference); JCAnnotation annotationJsonDeserialize = maker.Annotation(jsonDeserializeType, List.of(assign)); + recursiveSetGeneratedBy(annotationJsonDeserialize, annotationNode); td.mods.annotations = td.mods.annotations.append(annotationJsonDeserialize); // Copy annotations from the class to the builder class. List<JCAnnotation> copyableAnnotations = findJacksonAnnotationsOnClass(tdNode); List<JCAnnotation> copiedAnnotations = copyAnnotations(copyableAnnotations); + for (JCAnnotation anno : copiedAnnotations) { + recursiveSetGeneratedBy(anno, annotationNode); + } builderClass.mods.annotations = builderClass.mods.annotations.appendList(copiedAnnotations); // Insert @JsonPOJOBuilder on the builder class. @@ -144,6 +147,7 @@ public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> { JCExpression withPrefixExpr = maker.Assign(maker.Ident(annotationNode.toName("withPrefix")), maker.Literal(setPrefix)); JCExpression buildMethodNameExpr = maker.Assign(maker.Ident(annotationNode.toName("buildMethodName")), maker.Literal(buildMethodName)); JCAnnotation annotationJsonPOJOBuilder = maker.Annotation(jsonPOJOBuilderType, List.of(withPrefixExpr, buildMethodNameExpr)); + recursiveSetGeneratedBy(annotationJsonPOJOBuilder, annotatedNode); builderClass.mods.annotations = builderClass.mods.annotations.append(annotationJsonPOJOBuilder); // @SuperBuilder? Make it package-private! @@ -151,7 +155,7 @@ public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> { builderClass.mods.flags = builderClass.mods.flags & ~Flags.PRIVATE; } - private String getBuilderClassName(JCAnnotation ast, JavacNode annotationNode, JavacNode annotatedNode, JCClassDecl td, AnnotationValues<Builder> builderAnnotation, JavacTreeMaker maker) { + private String getBuilderClassName(JavacNode annotationNode, JavacNode annotatedNode, JCClassDecl td, AnnotationValues<Builder> builderAnnotation, JavacTreeMaker maker) { String builderClassName = builderAnnotation != null ? builderAnnotation.getInstance().builderClassName() : null; if (builderClassName == null || builderClassName.isEmpty()) { @@ -166,7 +170,7 @@ public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> { JCExpression returnType = fillParametersFrom.restype; List<JCTypeParameter> typeParams = fillParametersFrom.typarams; if (returnType instanceof JCTypeApply) { - returnType = cloneType(maker, returnType, ast, annotationNode.getContext()); + returnType = cloneType(maker, returnType, annotatedNode); } replacement = HandleBuilder.returnTypeToBuilderClassName(annotationNode, td, returnType, typeParams); } else { diff --git a/src/core/lombok/javac/handlers/HandleLog.java b/src/core/lombok/javac/handlers/HandleLog.java index 1ff10ad1..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,15 +31,14 @@ 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; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCExpression; @@ -75,6 +74,7 @@ public class HandleLog { annotationNode.addWarning("Field '" + logFieldName + "' already exists."); return; } + if (isRecord(typeNode) && !useStatic) { annotationNode.addError("Logger fields must be static in records."); return; @@ -82,7 +82,7 @@ public class HandleLog { 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."); @@ -94,7 +94,7 @@ public class HandleLog { } JCFieldAccess loggingType = selfType(typeNode); - createField(framework, typeNode, loggingType, annotationNode.get(), logFieldName.getName(), useStatic, loggerTopic); + createField(framework, typeNode, loggingType, annotationNode, logFieldName.getName(), useStatic, loggerTopic); break; default: annotationNode.addError("@Log is legal only on types."); @@ -108,7 +108,7 @@ public class HandleLog { return maker.Select(maker.Ident(name), typeNode.toName("class")); } - private static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType, JCTree source, String logFieldName, boolean useStatic, JCExpression loggerTopic) { + private static boolean createField(LoggingFramework framework, JavacNode typeNode, JCFieldAccess loggingType, JavacNode source, String logFieldName, boolean useStatic, JCExpression loggerTopic) { JavacTreeMaker maker = typeNode.getTreeMaker(); LogDeclaration logDeclaration = framework.getDeclaration(); @@ -122,17 +122,19 @@ public class HandleLog { JCVariableDecl fieldDecl = recursiveSetGeneratedBy(maker.VarDef( maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (useStatic ? Flags.STATIC : 0)), - typeNode.toName(logFieldName), loggerType, factoryMethodCall), source, typeNode.getContext()); + typeNode.toName(logFieldName), loggerType, factoryMethodCall), source); - // This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8243057 - if (isRecord(typeNode)) { + 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; } - + private static JCExpression[] createFactoryParameters(JavacNode typeNode, JCFieldAccess loggingType, java.util.List<LogFactoryParameter> parameters, JCExpression loggerTopic) { JCExpression[] expressions = new JCExpression[parameters.size()]; JavacTreeMaker maker = typeNode.getTreeMaker(); @@ -164,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"); @@ -175,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"); @@ -186,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"); @@ -197,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"); @@ -208,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"); @@ -219,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"); @@ -230,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"); @@ -241,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"); @@ -252,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 6b6b7efa..2f359c0f 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,8 +27,6 @@ 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 com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCAssert; import com.sun.tools.javac.tree.JCTree.JCAssign; @@ -57,17 +55,16 @@ import lombok.NonNull; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; - -import lombok.javac.Java14Flags; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.handlers.HandleConstructor.SkipIfConstructorExists; +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> { private HandleConstructor handleConstructor = new HandleConstructor(); - + @Override public void handle(AnnotationValues<NonNull> annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.NON_NULL_FLAG_USAGE, "@NonNull"); @@ -117,7 +114,7 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> { // 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), ast, annotationNode.getContext()); + JCStatement nullCheck = recursiveSetGeneratedBy(generateNullCheck(annotationNode.getTreeMaker(), paramNode, annotationNode), annotationNode); if (nullCheck == null) { // @NonNull applied to a primitive. Kinda pointless. Let's generate a warning. @@ -125,19 +122,18 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> { return; } + List<JCStatement> statements = declaration.body.stats; + + String expectedName = paramNode.getName(); + JavacNode typeNode = upToTypeNode(annotationNode); - if ((declaration.mods.flags & Java14Flags.RECORD) != 0) { - if (!lombokConstructorExists(typeNode)) { + if ((declaration.mods.flags & RECORD) != 0) { + if (!lombokConstructorExists(typeNode)) { handleConstructor.generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, null, SkipIfConstructorExists.NO, annotationNode); } - return; } - List<JCStatement> statements = declaration.body.stats; - - String expectedName = paramNode.getName(); - /* Abort if the null check is already there, delving into try and synchronized statements */ { List<JCStatement> stats = statements; int idx = 0; diff --git a/src/core/lombok/javac/handlers/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 b51574b7..5c34f9f5 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.code.Symbol.ClassSymbol; @@ -60,8 +59,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)) { @@ -71,7 +72,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { } if (!isClass(typeNode)) { - errorNode.addError("@Setter is only supported on a class or a field."); + errorNode.addError(SETTER_NODE_NOT_SUPPORTED_ERR); return; } @@ -145,7 +146,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { public void createSetterForField(AccessLevel level, JavacNode fieldNode, JavacNode sourceNode, boolean whineIfExists, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { if (fieldNode.getKind() != Kind.FIELD) { - fieldNode.addError("@Setter is only supported on a class or a field."); + fieldNode.addError(SETTER_NODE_NOT_SUPPORTED_ERR); return; } @@ -215,13 +216,36 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { List<JCAnnotation> annotations = d.mods.annotations; if (annotations == null) annotations = List.nil(); JCAnnotation anno = treeMaker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>nil()); - recursiveSetGeneratedBy(anno, source.get(), field.getContext()); + recursiveSetGeneratedBy(anno, source); + d.mods.annotations = annotations.prepend(anno); + } + return d; + } + + public static JCMethodDecl createSetterWithRecv(long access, boolean deprecate, JavacNode field, JavacTreeMaker treeMaker, String setterName, Name paramName, Name booleanFieldToSet, boolean shouldReturnThis, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam, JCVariableDecl recv) { + JCExpression returnType = null; + JCReturn returnStatement = null; + if (shouldReturnThis) { + returnType = cloneSelfType(field); + returnStatement = treeMaker.Return(treeMaker.Ident(field.toName("this"))); + } + + JCMethodDecl d = createSetterWithRecv(access, deprecate, field, treeMaker, setterName, paramName, booleanFieldToSet, returnType, returnStatement, source, onMethod, onParam, recv); + if (shouldReturnThis && getCheckerFrameworkVersion(source).generateReturnsReceiver()) { + List<JCAnnotation> annotations = d.mods.annotations; + if (annotations == null) annotations = List.nil(); + JCAnnotation anno = treeMaker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>nil()); + recursiveSetGeneratedBy(anno, source); d.mods.annotations = annotations.prepend(anno); } return d; } public static JCMethodDecl createSetter(long access, boolean deprecate, JavacNode field, JavacTreeMaker treeMaker, String setterName, Name paramName, Name booleanFieldToSet, JCExpression methodType, JCStatement returnStatement, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) { + return createSetterWithRecv(access, deprecate, field, treeMaker, setterName, paramName, booleanFieldToSet, methodType, returnStatement, source, onMethod, onParam, null); + } + + public static JCMethodDecl createSetterWithRecv(long access, boolean deprecate, JavacNode field, JavacTreeMaker treeMaker, String setterName, Name paramName, Name booleanFieldToSet, JCExpression methodType, JCStatement returnStatement, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam, JCVariableDecl recv) { if (setterName == null) return null; JCVariableDecl fieldDecl = (JCVariableDecl) field.get(); @@ -237,7 +261,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(copyableAnnotations); long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, field.getContext()); - JCExpression pType = cloneType(treeMaker, fieldDecl.vartype, source.get(), source.getContext()); + JCExpression pType = cloneType(treeMaker, fieldDecl.vartype, source); JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(flags, annsOnParam), paramName, pType, null); if (!hasNonNullAnnotations(field) && !hasNonNullAnnotations(field, onParam)) { @@ -272,10 +296,16 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>nil())); } - JCMethodDecl methodDef = treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType, - methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue); + JCMethodDecl methodDef; + if (recv != null && treeMaker.hasMethodDefWithRecvParam()) { + methodDef = treeMaker.MethodDefWithRecvParam(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType, + methodGenericParams, recv, parameters, throwsClauses, methodBody, annotationMethodDefaultValue); + } else { + methodDef = treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType, + methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue); + } if (returnStatement != null) createRelevantNonNullAnnotation(source, methodDef); - JCMethodDecl decl = recursiveSetGeneratedBy(methodDef, source.get(), field.getContext()); + JCMethodDecl decl = recursiveSetGeneratedBy(methodDef, source); copyJavadoc(field, decl, CopyJavadoc.SETTER, returnStatement != null); return decl; } diff --git a/src/core/lombok/javac/handlers/HandleSneakyThrows.java b/src/core/lombok/javac/handlers/HandleSneakyThrows.java index ffe37a4c..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,11 +35,9 @@ 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; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCBlock; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; @@ -48,14 +46,13 @@ import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTry; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; 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) { @@ -107,7 +104,7 @@ public class HandleSneakyThrows extends JavacAnnotationHandler<SneakyThrows> { } for (String exception : exceptions) { - contents = List.of(buildTryCatchBlock(methodNode, contents, exception, annotation.get())); + contents = List.of(buildTryCatchBlock(methodNode, contents, exception, annotation)); } method.body.stats = isConstructorCall ? List.of(constructorCall).appendList(contents) : contents; @@ -122,11 +119,10 @@ public class HandleSneakyThrows extends JavacAnnotationHandler<SneakyThrows> { } } - public JCStatement buildTryCatchBlock(JavacNode node, List<JCStatement> contents, String exception, JCTree source) { + public JCStatement buildTryCatchBlock(JavacNode node, List<JCStatement> contents, String exception, JavacNode source) { JavacTreeMaker maker = node.getTreeMaker(); - Context context = node.getContext(); - JCBlock tryBlock = setGeneratedBy(maker.Block(0, contents), source, context); + JCBlock tryBlock = setGeneratedBy(maker.Block(0, contents), source); JCExpression varType = chainDots(node, exception.split("\\.")); JCVariableDecl catchParam = maker.VarDef(maker.Modifiers(Flags.FINAL | Flags.PARAMETER), node.toName("$ex"), varType, null); @@ -134,7 +130,7 @@ public class HandleSneakyThrows extends JavacAnnotationHandler<SneakyThrows> { JCBlock catchBody = maker.Block(0, List.<JCStatement>of(maker.Throw(maker.Apply( List.<JCExpression>nil(), lombokLombokSneakyThrowNameRef, List.<JCExpression>of(maker.Ident(node.toName("$ex"))))))); - JCTry tryStatement = maker.Try(tryBlock, List.of(recursiveSetGeneratedBy(maker.Catch(catchParam, catchBody), source, context)), null); + JCTry tryStatement = maker.Try(tryBlock, List.of(recursiveSetGeneratedBy(maker.Catch(catchParam, catchBody), source)), null); if (JavacHandlerUtil.inNetbeansEditor(node)) { //set span (start and end position) of the try statement and the main block //this allows NetBeans to dive into the statement correctly: @@ -146,6 +142,6 @@ public class HandleSneakyThrows extends JavacAnnotationHandler<SneakyThrows> { Javac.storeEnd(tryBlock, endPos, top); Javac.storeEnd(tryStatement, endPos, top); } - return setGeneratedBy(tryStatement, source, context); + return setGeneratedBy(tryStatement, source); } } diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index be6ddae2..9185cedf 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 @@ -21,6 +21,7 @@ */ package lombok.javac.handlers; +import static lombok.javac.handlers.HandleBuilder.*; import static lombok.core.handlers.HandlerUtil.*; import static lombok.javac.Javac.*; import static lombok.javac.handlers.JavacHandlerUtil.*; @@ -31,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; @@ -53,7 +52,6 @@ import com.sun.tools.javac.tree.JCTree.JCTypeApply; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.JCTree.JCWildcard; -import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; @@ -78,68 +76,102 @@ import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; import lombok.javac.handlers.HandleBuilder.BuilderFieldData; +import lombok.javac.handlers.HandleBuilder.BuilderJob; import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; 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"; - private static final String TO_BUILDER_METHOD_NAME = "toBuilder"; private static final String FILL_VALUES_METHOD_NAME = "$fillValuesFrom"; private static final String STATIC_FILL_VALUES_METHOD_NAME = "$fillValuesFromInstanceIntoBuilder"; private static final String INSTANCE_VARIABLE_NAME = "instance"; private static final String BUILDER_VARIABLE_NAME = "b"; - + + class SuperBuilderJob extends BuilderJob { + JavacNode builderAbstractType; + String builderAbstractClassName; + JavacNode builderImplType; + String builderImplClassName; + List<JCTypeParameter> builderTypeParams_; + + void init(AnnotationValues<SuperBuilder> annValues, SuperBuilder ann, JavacNode node) { + accessOuters = accessInners = AccessLevel.PUBLIC; + oldFluent = true; + oldChain = true; + + builderMethodName = ann.builderMethodName(); + buildMethodName = ann.buildMethodName(); + toBuilder = ann.toBuilder(); + + if (builderMethodName == null) builderMethodName = "builder"; + if (buildMethodName == null) buildMethodName = "build"; + builderClassName = fixBuilderClassName(node, ""); + } + + void setBuilderToImpl() { + builderType = builderImplType; + builderClassName = builderImplClassName; + builderTypeParams = typeParams; + } + + void setBuilderToAbstract() { + builderType = builderAbstractType; + builderClassName = builderAbstractClassName; + builderTypeParams = builderTypeParams_; + } + } + @Override public void handle(AnnotationValues<SuperBuilder> annotation, JCAnnotation ast, JavacNode annotationNode) { handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder"); - CheckerFrameworkVersion cfv = getCheckerFrameworkVersion(annotationNode); - SuperBuilder superbuilderAnnotation = annotation.getInstance(); - // Do not delete the SuperBuilder annotation here, we need it for @Jacksonized. + SuperBuilderJob job = new SuperBuilderJob(); + job.sourceNode = annotationNode; + job.checkerFramework = getCheckerFrameworkVersion(annotationNode); + job.isStatic = true; - String builderMethodName = superbuilderAnnotation.builderMethodName(); - String buildMethodName = superbuilderAnnotation.buildMethodName(); + SuperBuilder annInstance = annotation.getInstance(); - if (builderMethodName == null) builderMethodName = "builder"; - if (buildMethodName == null) buildMethodName = "build"; + job.init(annotation, annInstance, annotationNode); boolean generateBuilderMethod; - if (builderMethodName.isEmpty()) { + if (job.builderMethodName.isEmpty()) { generateBuilderMethod = false; - } else if (!checkName("builderMethodName", builderMethodName, annotationNode)) { + } else if (!checkName("builderMethodName", job.builderMethodName, annotationNode)) { return; } else { generateBuilderMethod = true; } - if (!checkName("buildMethodName", buildMethodName, annotationNode)) return; + if (!checkName("buildMethodName", job.buildMethodName, annotationNode)) return; - boolean toBuilder = superbuilderAnnotation.toBuilder(); + // Do not delete the SuperBuilder annotation here, we need it for @Jacksonized. - JavacNode tdParent = annotationNode.up(); + JavacNode parent = annotationNode.up(); - java.util.List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>(); - List<JCTypeParameter> typeParams = List.nil(); - List<JCExpression> thrownExceptions = List.nil(); + job.builderFields = new ArrayList<BuilderFieldData>(); + job.typeParams = List.nil(); + List<JCExpression> buildMethodThrownExceptions = List.nil(); List<JCExpression> superclassTypeParams = List.nil(); - boolean addCleaning = false; - if (!isClass(tdParent)) { - annotationNode.addError("@SuperBuilder is only supported on types."); + if (!isClass(parent)) { + annotationNode.addError("@SuperBuilder is only supported on classes."); return; } + job.parentType = parent; + JCClassDecl td = (JCClassDecl) parent.get(); + // Gather all fields of the class that should be set by the builder. - JCClassDecl td = (JCClassDecl) tdParent.get(); - ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>(); ArrayList<JavacNode> nonFinalNonDefaultedFields = null; - boolean valuePresent = (hasAnnotation(lombok.Value.class, tdParent) || hasAnnotation("lombok.experimental.Value", tdParent)); - for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) { + boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent)); + for (JavacNode fieldNode : HandleConstructor.findAllFields(parent, true)) { JCVariableDecl fd = (JCVariableDecl) fieldNode.get(); JavacNode isDefault = findAnnotation(Builder.Default.class, fieldNode, true); boolean isFinal = (fd.mods.flags & Flags.FINAL) != 0 || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode)); @@ -149,7 +181,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { bfd.builderFieldName = bfd.name; bfd.annotations = findCopyableAnnotations(fieldNode); bfd.type = fd.vartype; - bfd.singularData = getSingularData(fieldNode, superbuilderAnnotation.setterPrefix()); + bfd.singularData = getSingularData(fieldNode, annInstance.setterPrefix()); bfd.originalFieldNode = fieldNode; if (bfd.singularData != null && isDefault != null) { @@ -169,44 +201,20 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { } if (isDefault != null) { - bfd.nameOfDefaultProvider = tdParent.toName("$default$" + bfd.name); - bfd.nameOfSetFlag = tdParent.toName(bfd.name + "$set"); - bfd.builderFieldName = tdParent.toName(bfd.name + "$value"); + bfd.nameOfDefaultProvider = parent.toName(DEFAULT_PREFIX + bfd.name); + bfd.nameOfSetFlag = parent.toName(bfd.name + SET_PREFIX); + bfd.builderFieldName = parent.toName(bfd.name + VALUE_PREFIX); JCMethodDecl md = HandleBuilder.generateDefaultProvider(bfd.nameOfDefaultProvider, fieldNode, td.typarams); - recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); - if (md != null) injectMethod(tdParent, md); + recursiveSetGeneratedBy(md, annotationNode); + if (md != null) injectMethod(parent, md); } addObtainVia(bfd, fieldNode); - builderFields.add(bfd); - allFields.append(fieldNode); + job.builderFields.add(bfd); } - // Set the names of the builder classes. - String builderClassNameTemplate = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME); - if (builderClassNameTemplate == null || builderClassNameTemplate.isEmpty()) builderClassNameTemplate = "*Builder"; - String builderClassName = builderClassNameTemplate.replace("*", td.name.toString()); - String builderImplClassName = builderClassName + "Impl"; - JCTree extendsClause = Javac.getExtendsClause(td); - JCExpression superclassBuilderClassExpression = null; - if (extendsClause instanceof JCTypeApply) { - // Remember the type arguments, because we need them for the extends clause of our abstract builder class. - superclassTypeParams = ((JCTypeApply) extendsClause).getTypeArguments(); - // A class name with a generics type, e.g., "Superclass<A>". - extendsClause = ((JCTypeApply) extendsClause).getType(); - } - if (extendsClause instanceof JCFieldAccess) { - Name superclassClassName = ((JCFieldAccess)extendsClause).getIdentifier(); - String superclassBuilderClassName = builderClassNameTemplate.replace("*", superclassClassName); - superclassBuilderClassExpression = tdParent.getTreeMaker().Select((JCFieldAccess) extendsClause, - tdParent.toName(superclassBuilderClassName)); - } else if (extendsClause != null) { - String superclassBuilderClassName = builderClassNameTemplate.replace("*", extendsClause.toString()); - superclassBuilderClassExpression = chainDots(tdParent, extendsClause.toString(), superclassBuilderClassName); - } - // If there is no superclass, superclassBuilderClassExpression is still == null at this point. - // You can use it to check whether to inherit or not. - - typeParams = td.typarams; + job.typeParams = job.builderTypeParams = td.typarams; + job.builderClassName = job.replaceBuilderClassName(td.name); + if (!checkName("builderClassName", job.builderClassName, annotationNode)) return; // <C, B> are the generics for our builder. String classGenericName = "C"; @@ -214,14 +222,46 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { // We have to make sure that the generics' names do not collide with any generics on the annotated class, // the classname itself, or any member type name of the annotated class. // For instance, if there are generics <B, B2, C> on the annotated class, use "C2" and "B3" for our builder. - java.util.HashSet<String> usedNames = gatherUsedTypeNames(typeParams, td); + java.util.HashSet<String> usedNames = gatherUsedTypeNames(job.typeParams, td); classGenericName = generateNonclashingNameFor(classGenericName, usedNames); builderGenericName = generateNonclashingNameFor(builderGenericName, usedNames); - thrownExceptions = List.nil(); + JavacTreeMaker maker = annotationNode.getTreeMaker(); + + { + 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.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()) { + job.builderTypeParams_ = List.of(c, d); + } else { + job.builderTypeParams_ = job.typeParams.append(c).append(d); + } + } + + JCTree extendsClause = Javac.getExtendsClause(td); + JCExpression superclassBuilderClass = null; + if (extendsClause instanceof JCTypeApply) { + // Remember the type arguments, because we need them for the extends clause of our abstract builder class. + superclassTypeParams = ((JCTypeApply) extendsClause).getTypeArguments(); + // A class name with a generics type, e.g., "Superclass<A>". + extendsClause = ((JCTypeApply) extendsClause).getType(); + } + if (extendsClause instanceof JCFieldAccess) { + Name superclassName = ((JCFieldAccess) extendsClause).getIdentifier(); + String superclassBuilderClassName = superclassName.toString() + "Builder"; + superclassBuilderClass = parent.getTreeMaker().Select((JCFieldAccess) extendsClause, parent.toName(superclassBuilderClassName)); + } else if (extendsClause != null) { + String superclassBuilderClassName = extendsClause.toString() + "Builder"; + superclassBuilderClass = chainDots(parent, extendsClause.toString(), superclassBuilderClassName); + } // Check validity of @ObtainVia fields, and add check if adding cleaning for @Singular is necessary. - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { if (bfd.singularData.getSingularizer().requiresCleaning()) { addCleaning = true; @@ -240,83 +280,85 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { } } + job.builderAbstractClassName = job.builderClassName = job.replaceBuilderClassName(td.name); + job.builderImplClassName = job.builderAbstractClassName + "Impl"; + // Create the abstract builder class. - JavacNode builderType = findInnerClass(tdParent, builderClassName); - if (builderType == null) { - builderType = generateBuilderAbstractClass(annotationNode, tdParent, builderClassName, superclassBuilderClassExpression, - typeParams, superclassTypeParams, classGenericName, builderGenericName); - recursiveSetGeneratedBy(builderType.get(), ast, annotationNode.getContext()); + job.builderAbstractType = findInnerClass(parent, job.builderClassName); + if (job.builderAbstractType == null) { + job.builderAbstractType = generateBuilderAbstractClass(job, superclassBuilderClass, superclassTypeParams, classGenericName, builderGenericName); + recursiveSetGeneratedBy(job.builderAbstractType.get(), annotationNode); } else { - JCClassDecl builderTypeDeclaration = (JCClassDecl) builderType.get(); + JCClassDecl builderTypeDeclaration = (JCClassDecl) job.builderAbstractType.get(); if (!builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC) || !builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.ABSTRACT)) { annotationNode.addError("Existing Builder must be an abstract static inner class."); return; } - sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode); + sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderAbstractType, annotationNode); // Generate errors for @Singular BFDs that have one already defined node. - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { SingularData sd = bfd.singularData; if (sd == null) continue; JavacSingularizer singularizer = sd.getSingularizer(); if (singularizer == null) continue; - if (singularizer.checkForAlreadyExistingNodesAndGenerateError(builderType, sd)) { + if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderAbstractType, sd)) { bfd.singularData = null; } } } // Generate the fields in the abstract builder class that hold the values for the instance. - generateBuilderFields(builderType, builderFields, ast); + job.setBuilderToAbstract(); + generateBuilderFields(job.builderType, job.builderFields, annotationNode); if (addCleaning) { - JavacTreeMaker maker = builderType.getTreeMaker(); - JCVariableDecl uncleanField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), builderType.toName("$lombokUnclean"), maker.TypeIdent(CTC_BOOLEAN), null); - recursiveSetGeneratedBy(uncleanField, ast, annotationNode.getContext()); - injectFieldAndMarkGenerated(builderType, uncleanField); + JCVariableDecl uncleanField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), job.toName("$lombokUnclean"), maker.TypeIdent(CTC_BOOLEAN), null); + recursiveSetGeneratedBy(uncleanField, annotationNode); + injectFieldAndMarkGenerated(job.builderType, uncleanField); } - if (toBuilder) { + if (job.toBuilder) { // Generate $fillValuesFrom() method in the abstract builder. - JCMethodDecl fvm = generateFillValuesMethod(tdParent, superclassBuilderClassExpression != null, builderGenericName, classGenericName, builderClassName); - recursiveSetGeneratedBy(fvm, ast, annotationNode.getContext()); - injectMethod(builderType, fvm); + JCMethodDecl fvm = generateFillValuesMethod(job, superclassBuilderClass != null, builderGenericName, classGenericName); + recursiveSetGeneratedBy(fvm, annotationNode); + injectMethod(job.builderType, fvm); // Generate $fillValuesFromInstanceIntoBuilder() method in the builder implementation class. - JCMethodDecl sfvm = generateStaticFillValuesMethod(tdParent, builderClassName, typeParams, builderFields, superbuilderAnnotation.setterPrefix()); - recursiveSetGeneratedBy(sfvm, ast, annotationNode.getContext()); - injectMethod(builderType, sfvm); + JCMethodDecl sfvm = generateStaticFillValuesMethod(job, annInstance.setterPrefix()); + recursiveSetGeneratedBy(sfvm, annotationNode); + injectMethod(job.builderType, sfvm); } // Generate abstract self() and build() methods in the abstract builder. - JCMethodDecl asm = generateAbstractSelfMethod(cfv, tdParent, superclassBuilderClassExpression != null, builderGenericName); - recursiveSetGeneratedBy(asm, ast, annotationNode.getContext()); - injectMethod(builderType, asm); - JCMethodDecl abm = generateAbstractBuildMethod(cfv, tdParent, buildMethodName, builderFields, superclassBuilderClassExpression != null, classGenericName); - recursiveSetGeneratedBy(abm, ast, annotationNode.getContext()); - injectMethod(builderType, abm); + JCMethodDecl asm = generateAbstractSelfMethod(job, superclassBuilderClass != null, builderGenericName); + recursiveSetGeneratedBy(asm, annotationNode); + injectMethod(job.builderType, asm); + JCMethodDecl abm = generateAbstractBuildMethod(job, superclassBuilderClass != null, classGenericName); + recursiveSetGeneratedBy(abm, annotationNode); + injectMethod(job.builderType, abm); // Create the setter methods in the abstract builder. - for (BuilderFieldData bfd : builderFields) { - generateSetterMethodsForBuilder(cfv, builderType, bfd, annotationNode, builderGenericName, superbuilderAnnotation.setterPrefix()); + for (BuilderFieldData bfd : job.builderFields) { + generateSetterMethodsForBuilder(job, bfd, builderGenericName, annInstance.setterPrefix()); } // Create the toString() method for the abstract builder. java.util.List<Included<JavacNode, ToString.Include>> fieldNodes = new ArrayList<Included<JavacNode, ToString.Include>>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { for (JavacNode f : bfd.createdFields) { fieldNodes.add(new Included<JavacNode, ToString.Include>(f, null, true, false)); } } // Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder. - JCMethodDecl toStringMethod = HandleToString.createToString(builderType, fieldNodes, true, superclassBuilderClassExpression != null, FieldAccess.ALWAYS_FIELD, ast); - if (toStringMethod != null) injectMethod(builderType, toStringMethod); + JCMethodDecl toStringMethod = HandleToString.createToString(job.builderType, fieldNodes, true, superclassBuilderClass != null, FieldAccess.ALWAYS_FIELD, annotationNode); + if (toStringMethod != null) injectMethod(job.builderType, toStringMethod); // If clean methods are requested, add them now. if (addCleaning) { - JCMethodDecl md = generateCleanMethod(builderFields, builderType, ast); - recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); - injectMethod(builderType, md); + JCMethodDecl md = generateCleanMethod(job.builderFields, job.builderType, annotationNode); + recursiveSetGeneratedBy(md, annotationNode); + injectMethod(job.builderType, md); } boolean isAbstract = (td.mods.flags & Flags.ABSTRACT) != 0; @@ -324,69 +366,71 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { // Only non-abstract classes get the Builder implementation. // Create the builder implementation class. - JavacNode builderImplType = findInnerClass(tdParent, builderImplClassName); - if (builderImplType == null) { - builderImplType = generateBuilderImplClass(annotationNode, tdParent, builderImplClassName, builderClassName, typeParams); - recursiveSetGeneratedBy(builderImplType.get(), ast, annotationNode.getContext()); + job.builderImplType = findInnerClass(parent, job.builderImplClassName); + if (job.builderImplType == null) { + job.builderImplType = generateBuilderImplClass(job); + recursiveSetGeneratedBy(job.builderImplType.get(), annotationNode); } else { - JCClassDecl builderImplTypeDeclaration = (JCClassDecl) builderImplType.get(); + JCClassDecl builderImplTypeDeclaration = (JCClassDecl) job.builderImplType.get(); if (!builderImplTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC) || builderImplTypeDeclaration.getModifiers().getFlags().contains(Modifier.ABSTRACT)) { annotationNode.addError("Existing BuilderImpl must be a non-abstract static inner class."); return; } - sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderImplType, annotationNode); + sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderImplType, annotationNode); } // Create a simple constructor for the BuilderImpl class. - JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, List.<JCAnnotation>nil(), builderImplType, List.<JavacNode>nil(), false, annotationNode); - if (cd != null) injectMethod(builderImplType, cd); + JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, List.<JCAnnotation>nil(), job.builderImplType, List.<JavacNode>nil(), false, annotationNode); + if (cd != null) injectMethod(job.builderImplType, cd); + job.setBuilderToImpl(); // Create the self() and build() methods in the BuilderImpl. - JCMethodDecl selfMethod = generateSelfMethod(cfv, builderImplType, typeParams); - recursiveSetGeneratedBy(selfMethod, ast, annotationNode.getContext()); - injectMethod(builderImplType, selfMethod); - if (methodExists(buildMethodName, builderImplType, -1) == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl buildMethod = generateBuildMethod(cfv, buildMethodName, tdParent, builderImplType, builderFields, thrownExceptions); - recursiveSetGeneratedBy(buildMethod, ast, annotationNode.getContext()); - injectMethod(builderImplType, buildMethod); + JCMethodDecl selfMethod = generateSelfMethod(job); + recursiveSetGeneratedBy(selfMethod, annotationNode); + injectMethod(job.builderType, selfMethod); + if (methodExists(job.buildMethodName, job.builderType, -1) == MemberExistsResult.NOT_EXISTS) { + JCMethodDecl buildMethod = generateBuildMethod(job, buildMethodThrownExceptions); + recursiveSetGeneratedBy(buildMethod, annotationNode); + injectMethod(job.builderType, buildMethod); } } // Generate a constructor in the annotated class that takes a builder as argument. - if (!constructorExists(tdParent, builderClassName)) { - generateBuilderBasedConstructor(cfv, tdParent, typeParams, builderFields, annotationNode, builderClassName, - superclassBuilderClassExpression != null); + if (!constructorExists(job.parentType, job.builderAbstractClassName)) { + job.setBuilderToAbstract(); + generateBuilderBasedConstructor(job, superclassBuilderClass != null); } - if (isAbstract) { + if (!isAbstract) { // Only non-abstract classes get the builder() and toBuilder() methods. - return; - } - // Add the builder() method to the annotated class. - // Allow users to specify their own builder() methods, e.g., to provide default values. - if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; - if (generateBuilderMethod) { - JCMethodDecl builderMethod = generateBuilderMethod(cfv, builderMethodName, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); - recursiveSetGeneratedBy(builderMethod, ast, annotationNode.getContext()); - if (builderMethod != null) injectMethod(tdParent, builderMethod); - } - - // Add the toBuilder() method to the annotated class. - if (toBuilder) { - switch (methodExists(TO_BUILDER_METHOD_NAME, tdParent, 0)) { - case EXISTS_BY_USER: - break; - case NOT_EXISTS: - JCMethodDecl md = generateToBuilderMethod(cfv, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); - if (md != null) { - recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); - injectMethod(tdParent, md); + // Add the builder() method to the annotated class. + // Allow users to specify their own builder() methods, e.g., to provide default values. + if (generateBuilderMethod && methodExists(job.builderMethodName, job.parentType, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; + if (generateBuilderMethod) { + JCMethodDecl builderMethod = generateBuilderMethod(job); + if (builderMethod != null) { + recursiveSetGeneratedBy(builderMethod, annotationNode); + injectMethod(job.parentType, builderMethod); + } + } + + // Add the toBuilder() method to the annotated class. + if (job.toBuilder) { + switch (methodExists(TO_BUILDER_METHOD_NAME, job.parentType, 0)) { + case EXISTS_BY_USER: + break; + case NOT_EXISTS: + JCMethodDecl md = generateToBuilderMethod(job); + if (md != null) { + recursiveSetGeneratedBy(md, annotationNode); + injectMethod(job.parentType, md); + } + break; + default: + // Should not happen. } - break; - default: - // Should not happen. } } @@ -400,163 +444,150 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { /** * Creates and returns the abstract builder class and injects it into the annotated class. */ - private JavacNode generateBuilderAbstractClass(JavacNode source, JavacNode tdParent, String builderClass, - JCExpression superclassBuilderClassExpression, List<JCTypeParameter> typeParams, - List<JCExpression> superclassTypeParams, String classGenericName, String builderGenericName) { - - JavacTreeMaker maker = tdParent.getTreeMaker(); + private JavacNode generateBuilderAbstractClass(SuperBuilderJob job, JCExpression superclassBuilderClass, List<JCExpression> superclassTypeParams, String classGenericName, String builderGenericName) { + JavacTreeMaker maker = job.parentType.getTreeMaker(); JCModifiers mods = maker.Modifiers(Flags.STATIC | Flags.ABSTRACT | Flags.PUBLIC); // Keep any type params of the annotated class. ListBuffer<JCTypeParameter> allTypeParams = new ListBuffer<JCTypeParameter>(); - allTypeParams.addAll(copyTypeParams(source, 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, tdParent, typeParams); + JCExpression annotatedClass = namePlusTypeParamsToTypeReference(maker, job.parentType, job.typeParams); - allTypeParams.add(maker.TypeParameter(tdParent.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 = tdParent.toName(builderClass); - ListBuffer<JCExpression> typeParamsForBuilder = getTypeParamExpressions(typeParams, maker, source.getContext()); - typeParamsForBuilder.add(maker.Ident(tdParent.toName(classGenericName))); - typeParamsForBuilder.add(maker.Ident(tdParent.toName(builderGenericName))); - JCTypeApply typeApply = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, tdParent, builderClassName, false, List.<JCTypeParameter>nil()), typeParamsForBuilder.toList()); - allTypeParams.add(maker.TypeParameter(tdParent.toName(builderGenericName), List.<JCExpression>of(typeApply))); + Name builderClassName = job.toName(job.builderClassName); + ListBuffer<JCExpression> typeParamsForBuilder = getTypeParamExpressions(job.typeParams, maker, job.sourceNode); + 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.append(maker.TypeParameter(job.toName(builderGenericName), List.<JCExpression>of(typeApply))); JCExpression extending = null; - if (superclassBuilderClassExpression != null) { + if (superclassBuilderClass != null) { // If the annotated class extends another class, we want this builder to extend the builder of the superclass. // 1. Add the type parameters of the superclass. - typeParamsForBuilder = getTypeParamExpressions(superclassTypeParams, maker, source.getContext()); + typeParamsForBuilder = getTypeParamExpressions(superclassTypeParams, maker, job.sourceNode); // 2. Add the builder type params <C, B>. - typeParamsForBuilder.add(maker.Ident(tdParent.toName(classGenericName))); - typeParamsForBuilder.add(maker.Ident(tdParent.toName(builderGenericName))); - extending = maker.TypeApply(superclassBuilderClassExpression, typeParamsForBuilder.toList()); + typeParamsForBuilder.append(maker.Ident(job.toName(classGenericName))); + typeParamsForBuilder.append(maker.Ident(job.toName(builderGenericName))); + extending = maker.TypeApply(superclassBuilderClass, typeParamsForBuilder.toList()); } JCClassDecl builder = maker.ClassDef(mods, builderClassName, allTypeParams.toList(), extending, List.<JCExpression>nil(), List.<JCTree>nil()); - return injectType(tdParent, builder); + recursiveSetGeneratedBy(builder, job.sourceNode); + return injectType(job.parentType, builder); } /** * Creates and returns the concrete builder implementation class and injects it into the annotated class. */ - private JavacNode generateBuilderImplClass(JavacNode source, JavacNode tdParent, String builderImplClass, String builderAbstractClass, List<JCTypeParameter> typeParams) { - JavacTreeMaker maker = tdParent.getTreeMaker(); + private JavacNode generateBuilderImplClass(SuperBuilderJob job) { + JavacTreeMaker maker = job.getTreeMaker(); JCModifiers mods = maker.Modifiers(Flags.STATIC | Flags.PRIVATE | Flags.FINAL); // Extend the abstract builder. - JCExpression extending = namePlusTypeParamsToTypeReference(maker, tdParent, tdParent.toName(builderAbstractClass), false, List.<JCTypeParameter>nil()); - // Add any type params of the annotated class. - ListBuffer<JCTypeParameter> allTypeParams = new ListBuffer<JCTypeParameter>(); - allTypeParams.addAll(copyTypeParams(source, typeParams)); + JCExpression extending = namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderAbstractClassName), false, List.<JCTypeParameter>nil()); + // 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, tdParent, typeParams); + JCExpression annotatedClass = namePlusTypeParamsToTypeReference(maker, job.parentType, job.typeParams); // 2. The return type for all setter methods (named "B" in the abstract builder), which is this builder class. - JCExpression builderImplClassExpression = namePlusTypeParamsToTypeReference(maker, tdParent, tdParent.toName(builderImplClass), false, typeParams); + JCExpression builderImplClassExpression = namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderImplClassName), false, job.typeParams); - ListBuffer<JCExpression> typeParamsForBuilder = getTypeParamExpressions(typeParams, maker, source.getContext()); - typeParamsForBuilder.add(annotatedClass); - typeParamsForBuilder.add(builderImplClassExpression); + ListBuffer<JCExpression> typeParamsForBuilder = getTypeParamExpressions(job.typeParams, maker, job.sourceNode); + typeParamsForBuilder.append(annotatedClass); + typeParamsForBuilder.append(builderImplClassExpression); extending = maker.TypeApply(extending, typeParamsForBuilder.toList()); - JCClassDecl builder = maker.ClassDef(mods, tdParent.toName(builderImplClass), copyTypeParams(source, typeParams), extending, List.<JCExpression>nil(), List.<JCTree>nil()); - return injectType(tdParent, builder); + JCClassDecl builder = maker.ClassDef(mods, job.toName(job.builderImplClassName), copyTypeParams(job.parentType, job.typeParams), extending, List.<JCExpression>nil(), List.<JCTree>nil()); + recursiveSetGeneratedBy(builder, job.sourceNode); + return injectType(job.parentType, builder); } /** * Generates a constructor that has a builder as the only parameter. * The values from the builder are used to initialize the fields of new instances. * - * @param typeNode - * the type (with the {@code @Builder} annotation) for which a - * constructor should be generated. - * @param typeParams - * @param builderFields a list of fields in the builder which should be assigned to new instances. - * @param source the annotation (used for setting source code locations for the generated code). * @param callBuilderBasedSuperConstructor * If {@code true}, the constructor will explicitly call a super * constructor with the builder as argument. Requires * {@code builderClassAsParameter != null}. */ - private void generateBuilderBasedConstructor(CheckerFrameworkVersion cfv, JavacNode typeNode, List<JCTypeParameter> typeParams, java.util.List<BuilderFieldData> builderFields, JavacNode source, String builderClassName, boolean callBuilderBasedSuperConstructor) { - JavacTreeMaker maker = typeNode.getTreeMaker(); + private void generateBuilderBasedConstructor(SuperBuilderJob job, boolean callBuilderBasedSuperConstructor) { + JavacTreeMaker maker = job.getTreeMaker(); AccessLevel level = AccessLevel.PROTECTED; ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); - Name builderVariableName = typeNode.toName(BUILDER_VARIABLE_NAME); - for (BuilderFieldData bfd : builderFields) { + Name builderVariableName = job.toName(BUILDER_VARIABLE_NAME); + for (BuilderFieldData bfd : job.builderFields) { JCExpression rhs; if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, bfd.originalFieldNode, bfd.type, statements, bfd.builderFieldName, "b"); + bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, bfd.originalFieldNode, job.sourceNode, statements, bfd.builderFieldName, "b"); rhs = maker.Ident(bfd.singularData.getPluralName()); } else { rhs = maker.Select(maker.Ident(builderVariableName), bfd.builderFieldName); } - JCFieldAccess fieldInThis = maker.Select(maker.Ident(typeNode.toName("this")), bfd.rawName); + JCFieldAccess fieldInThis = maker.Select(maker.Ident(job.toName("this")), bfd.rawName); JCStatement assign = maker.Exec(maker.Assign(fieldInThis, rhs)); // In case of @Builder.Default, set the value to the default if it was not set in the builder. if (bfd.nameOfSetFlag != null) { JCFieldAccess setField = maker.Select(maker.Ident(builderVariableName), bfd.nameOfSetFlag); - fieldInThis = maker.Select(maker.Ident(typeNode.toName("this")), bfd.rawName); - JCExpression parentTypeRef = namePlusTypeParamsToTypeReference(maker, typeNode, List.<JCTypeParameter>nil()); - JCAssign assignDefault = maker.Assign(fieldInThis, maker.Apply(typeParameterNames(maker, ((JCClassDecl) typeNode.get()).typarams), maker.Select(parentTypeRef, bfd.nameOfDefaultProvider), List.<JCExpression>nil())); + fieldInThis = maker.Select(maker.Ident(job.toName("this")), bfd.rawName); + JCExpression parentTypeRef = namePlusTypeParamsToTypeReference(maker, job.parentType, List.<JCTypeParameter>nil()); + JCAssign assignDefault = maker.Assign(fieldInThis, maker.Apply(typeParameterNames(maker, ((JCClassDecl) job.parentType.get()).typarams), maker.Select(parentTypeRef, bfd.nameOfDefaultProvider), List.<JCExpression>nil())); statements.append(maker.If(setField, assign, maker.Exec(assignDefault))); } else { statements.append(assign); } if (hasNonNullAnnotations(bfd.originalFieldNode)) { - JCStatement nullCheck = generateNullCheck(maker, bfd.originalFieldNode, source); + JCStatement nullCheck = generateNullCheck(maker, bfd.originalFieldNode, job.sourceNode); if (nullCheck != null) statements.append(nullCheck); } } - List<JCAnnotation> annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(typeNode, 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. ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>(); - long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext()); - Name builderClassname = typeNode.toName(builderClassName); + long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, job.getContext()); // First add all generics that are present on the parent type. - ListBuffer<JCExpression> typeParamsForBuilderParameter = getTypeParamExpressions(typeParams, maker, typeNode.getContext()); + 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); - JCTypeApply paramType = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, typeNode, builderClassname, false, List.<JCTypeParameter>nil()), typeParamsForBuilderParameter.toList()); + 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); if (callBuilderBasedSuperConstructor) { // The first statement must be the call to the super constructor. JCMethodInvocation callToSuperConstructor = maker.Apply(List.<JCExpression>nil(), - maker.Ident(typeNode.toName("super")), + maker.Ident(job.toName("super")), List.<JCExpression>of(maker.Ident(builderVariableName))); statements.prepend(maker.Exec(callToSuperConstructor)); } - JCMethodDecl constr = recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("<init>"), + JCMethodDecl constr = recursiveSetGeneratedBy(maker.MethodDef(mods, job.toName("<init>"), null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(), - maker.Block(0L, statements.toList()), null), source.get(), typeNode.getContext()); + maker.Block(0L, statements.toList()), null), job.sourceNode); - injectMethod(typeNode, constr, null, Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID)); + injectMethod(job.parentType, constr, null, Javac.createVoidType(job.builderType.getSymbolTable(), CTC_VOID)); } - private JCMethodDecl generateBuilderMethod(CheckerFrameworkVersion cfv, String builderMethodName, String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams) { - JavacTreeMaker maker = type.getTreeMaker(); - - ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); - for (JCTypeParameter typeParam : typeParams) typeArgs.append(maker.Ident(typeParam.name)); + private JCMethodDecl generateBuilderMethod(SuperBuilderJob job) { + JavacTreeMaker maker = job.getTreeMaker(); - JCExpression call = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, type, type.toName(builderImplClassName), false, typeParams), List.<JCExpression>nil(), null); + 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); JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); @@ -565,16 +596,19 @@ 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, 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, type, type.toName(builderClassName), false, List.<JCTypeParameter>nil()), typeParameterNames.toList()); - - List<JCAnnotation> annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); - JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), type.toName(builderMethodName), returnType, copyTypeParams(source, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); - createRelevantNonNullAnnotation(type, methodDef); + 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; } @@ -586,15 +620,12 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { * } * </pre> */ - private JCMethodDecl generateToBuilderMethod(CheckerFrameworkVersion cfv, String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateToBuilderMethod(SuperBuilderJob job) { + JavacTreeMaker maker = job.getTreeMaker(); - ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); - for (JCTypeParameter typeParam : typeParams) typeArgs.append(maker.Ident(typeParam.name)); - - JCExpression newClass = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, type, type.toName(builderImplClassName), false, typeParams), List.<JCExpression>nil(), null); - List<JCExpression> methodArgs = List.<JCExpression>of(maker.Ident(type.toName("this"))); - JCMethodInvocation invokeFillMethod = maker.Apply(List.<JCExpression>nil(), maker.Select(newClass, type.toName(FILL_VALUES_METHOD_NAME)), methodArgs); + 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); JCStatement statement = maker.Return(invokeFillMethod); JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); @@ -602,16 +633,16 @@ 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, 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, type, type.toName(builderClassName), false, List.<JCTypeParameter>nil()), typeParameterNames.toList()); + 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 = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil(); - JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), type.toName(TO_BUILDER_METHOD_NAME), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); - createRelevantNonNullAnnotation(type, methodDef); + 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; } @@ -621,43 +652,43 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { * <pre> * protected B $fillValuesFrom(final C instance) { * super.$fillValuesFrom(instance); - * FoobarBuilderImpl.$fillValuesFromInstanceIntoBuilder(instance, this); + * FoobarBuilder.$fillValuesFromInstanceIntoBuilder(instance, this); * return self(); * } * </pre> */ - private JCMethodDecl generateFillValuesMethod(JavacNode type, boolean inherited, String builderGenericName, String classGenericName, String builderImplClassName) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateFillValuesMethod(SuperBuilderJob job, boolean inherited, String builderGenericName, String classGenericName) { + JavacTreeMaker maker = job.getTreeMaker(); List<JCAnnotation> annotations = List.nil(); if (inherited) { - JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil()); + JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(job.builderType, "Override"), List.<JCExpression>nil()); annotations = List.of(overrideAnnotation); } JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED, annotations); - Name name = type.toName(FILL_VALUES_METHOD_NAME); - JCExpression returnType = maker.Ident(type.toName(builderGenericName)); + Name name = job.toName(FILL_VALUES_METHOD_NAME); + JCExpression returnType = maker.Ident(job.toName(builderGenericName)); - JCExpression classGenericNameExpr = maker.Ident(type.toName(classGenericName)); - JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.LocalVarFlags), type.toName(INSTANCE_VARIABLE_NAME), classGenericNameExpr, null); + JCExpression classGenericNameExpr = maker.Ident(job.toName(classGenericName)); + JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.PARAMETER | Flags.FINAL), job.toName(INSTANCE_VARIABLE_NAME), classGenericNameExpr, null); ListBuffer<JCStatement> body = new ListBuffer<JCStatement>(); if (inherited) { // Call super. JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(), - maker.Select(maker.Ident(type.toName("super")), name), - List.<JCExpression>of(maker.Ident(type.toName(INSTANCE_VARIABLE_NAME)))); + maker.Select(maker.Ident(job.toName("super")), name), + List.<JCExpression>of(maker.Ident(job.toName(INSTANCE_VARIABLE_NAME)))); body.append(maker.Exec(callToSuper)); } // Call the builder implemention's helper method that actually fills the values from the instance. - JCExpression ref = namePlusTypeParamsToTypeReference(maker, type, type.toName(builderImplClassName), false, List.<JCTypeParameter>nil()); + JCExpression ref = namePlusTypeParamsToTypeReference(maker, job.parentType, job.getBuilderClassName(), false, List.<JCTypeParameter>nil()); JCMethodInvocation callStaticFillValuesMethod = maker.Apply(List.<JCExpression>nil(), - maker.Select(ref, type.toName(STATIC_FILL_VALUES_METHOD_NAME)), - List.<JCExpression>of(maker.Ident(type.toName(INSTANCE_VARIABLE_NAME)), maker.Ident(type.toName("this")))); + maker.Select(ref, job.toName(STATIC_FILL_VALUES_METHOD_NAME)), + List.<JCExpression>of(maker.Ident(job.toName(INSTANCE_VARIABLE_NAME)), maker.Ident(job.toName("this")))); body.append(maker.Exec(callStaticFillValuesMethod)); - JCReturn returnStatement = maker.Return(maker.Apply(List.<JCExpression>nil(), maker.Ident(type.toName(SELF_METHOD)), List.<JCExpression>nil())); + JCReturn returnStatement = maker.Return(maker.Apply(List.<JCExpression>nil(), maker.Ident(job.toName(SELF_METHOD)), List.<JCExpression>nil())); body.append(returnStatement); JCBlock bodyBlock = maker.Block(0, body.toList()); @@ -674,58 +705,58 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { * b.field(instance.field); * } * </pre> - * @param setterPrefix the prefix for setter methods */ - private JCMethodDecl generateStaticFillValuesMethod(JavacNode type, String builderClassname, List<JCTypeParameter> typeParams, java.util.List<BuilderFieldData> builderFields, String setterPrefix) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateStaticFillValuesMethod(SuperBuilderJob job, String setterPrefix) { + JavacTreeMaker maker = job.getTreeMaker(); List<JCAnnotation> annotations = List.nil(); JCModifiers modifiers = maker.Modifiers(Flags.PRIVATE | Flags.STATIC, annotations); - Name name = type.toName(STATIC_FILL_VALUES_METHOD_NAME); + Name name = job.toName(STATIC_FILL_VALUES_METHOD_NAME); JCExpression returnType = maker.TypeIdent(CTC_VOID); // 1st parameter: "Foobar instance" - JCVariableDecl paramInstance = maker.VarDef(maker.Modifiers(Flags.LocalVarFlags), type.toName(INSTANCE_VARIABLE_NAME), cloneSelfType(type), null); + JCVariableDecl paramInstance = maker.VarDef(maker.Modifiers(Flags.PARAMETER | Flags.FINAL), job.toName(INSTANCE_VARIABLE_NAME), cloneSelfType(job.parentType), null); // 2nd parameter: "FoobarBuilder<?, ?> b" (plus generics on the annotated type) // First add all generics that are present on the parent type. - ListBuffer<JCExpression> typeParamsForBuilderParameter = getTypeParamExpressions(typeParams, maker, type.getContext()); + 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); - JCTypeApply builderType = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, type, type.toName(builderClassname), false, List.<JCTypeParameter>nil()), typeParamsForBuilderParameter.toList()); - JCVariableDecl paramBuilder = maker.VarDef(maker.Modifiers(Flags.LocalVarFlags), type.toName(BUILDER_VARIABLE_NAME), builderType, null); - + 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); + ListBuffer<JCStatement> body = new ListBuffer<JCStatement>(); // Call the builder's setter methods to fill the values from the instance. - for (BuilderFieldData bfd : builderFields) { - JCExpressionStatement exec = createSetterCallWithInstanceValue(bfd, type, maker, setterPrefix); + for (BuilderFieldData bfd : job.builderFields) { + JCExpressionStatement exec = createSetterCallWithInstanceValue(bfd, job, setterPrefix); body.append(exec); } JCBlock bodyBlock = maker.Block(0, body.toList()); - - return maker.MethodDef(modifiers, name, returnType, copyTypeParams(type, typeParams), List.of(paramInstance, paramBuilder), List.<JCExpression>nil(), bodyBlock, null); + + 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()); } } @@ -736,95 +767,105 @@ 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; } - private JCMethodDecl generateAbstractSelfMethod(CheckerFrameworkVersion cfv, JavacNode type, boolean override, String builderGenericName) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateAbstractSelfMethod(SuperBuilderJob job, boolean override, String builderGenericName) { + JavacTreeMaker maker = job.getTreeMaker(); List<JCAnnotation> annotations = List.nil(); - JCAnnotation overrideAnnotation = override ? maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil()) : null; - JCAnnotation rrAnnotation = cfv.generateReturnsReceiver() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>nil()) : null; - JCAnnotation sefAnnotation = cfv.generatePure() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__PURE), List.<JCExpression>nil()) : null; + JCAnnotation overrideAnnotation = override ? maker.Annotation(genJavaLangTypeRef(job.builderType, "Override"), List.<JCExpression>nil()) : null; + JCAnnotation rrAnnotation = job.checkerFramework.generateReturnsReceiver() ? maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>nil()) : null; + JCAnnotation sefAnnotation = job.checkerFramework.generatePure() ? maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__PURE), List.<JCExpression>nil()) : null; if (sefAnnotation != null) annotations = annotations.prepend(sefAnnotation); if (rrAnnotation != null) annotations = annotations.prepend(rrAnnotation); if (overrideAnnotation != null) annotations = annotations.prepend(overrideAnnotation); JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED | Flags.ABSTRACT, annotations); - Name name = type.toName(SELF_METHOD); - JCExpression returnType = maker.Ident(type.toName(builderGenericName)); + Name name = job.toName(SELF_METHOD); + JCExpression returnType = maker.Ident(job.toName(builderGenericName)); return maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null); } - private JCMethodDecl generateSelfMethod(CheckerFrameworkVersion cfv, JavacNode builderImplType, List<JCTypeParameter> typeParams) { - JavacTreeMaker maker = builderImplType.getTreeMaker(); + private JCMethodDecl generateSelfMethod(SuperBuilderJob job) { + JavacTreeMaker maker = job.getTreeMaker(); - JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(builderImplType, "Override"), List.<JCExpression>nil()); - JCAnnotation rrAnnotation = cfv.generateReturnsReceiver() ? maker.Annotation(genTypeRef(builderImplType, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>nil()) : null; - JCAnnotation sefAnnotation = cfv.generatePure() ? maker.Annotation(genTypeRef(builderImplType, CheckerFrameworkVersion.NAME__PURE), List.<JCExpression>nil()) : null; + JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(job.builderType, "Override"), List.<JCExpression>nil()); + JCAnnotation rrAnnotation = job.checkerFramework.generateReturnsReceiver() ? maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>nil()) : null; + JCAnnotation sefAnnotation = job.checkerFramework.generatePure() ? maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__PURE), List.<JCExpression>nil()) : null; List<JCAnnotation> annsOnMethod = List.nil(); if (sefAnnotation != null) annsOnMethod = annsOnMethod.prepend(sefAnnotation); if (rrAnnotation != null) annsOnMethod = annsOnMethod.prepend(rrAnnotation); annsOnMethod = annsOnMethod.prepend(overrideAnnotation); JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED, annsOnMethod); - Name name = builderImplType.toName(SELF_METHOD); + Name name = job.toName(SELF_METHOD); - JCExpression returnType = namePlusTypeParamsToTypeReference(maker, builderImplType.up(), builderImplType.toName(builderImplType.getName()), false, typeParams); - JCStatement statement = maker.Return(maker.Ident(builderImplType.toName("this"))); + JCExpression returnType = namePlusTypeParamsToTypeReference(maker, job.builderType.up(), job.getBuilderClassName(), false, job.typeParams); + JCStatement statement = maker.Return(maker.Ident(job.toName("this"))); JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); return maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); } - private JCMethodDecl generateAbstractBuildMethod(CheckerFrameworkVersion cfv, JavacNode type, String methodName, java.util.List<BuilderFieldData> builderFields, boolean override, String classGenericName) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateAbstractBuildMethod(SuperBuilderJob job, boolean override, String classGenericName) { + JavacTreeMaker maker = job.getTreeMaker(); List<JCAnnotation> annotations = List.nil(); if (override) { - JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil()); + JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(job.builderType, "Override"), List.<JCExpression>nil()); annotations = List.of(overrideAnnotation); } - if (cfv.generateSideEffectFree()) annotations = annotations.prepend(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())); + if (job.checkerFramework.generateSideEffectFree()) annotations = annotations.prepend(maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())); JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC | Flags.ABSTRACT, annotations); - Name name = type.toName(methodName); - JCExpression returnType = maker.Ident(type.toName(classGenericName)); + Name name = job.toName(job.buildMethodName); + JCExpression returnType = maker.Ident(job.toName(classGenericName)); - List<JCVariableDecl> params = HandleBuilder.generateBuildArgs(cfv, type, builderFields); - return maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), null, null); + JCVariableDecl recv = HandleBuilder.generateReceiver(job); + JCMethodDecl methodDef; + if (recv != null && maker.hasMethodDefWithRecvParam()) { + methodDef = maker.MethodDefWithRecvParam(modifiers, name, returnType, List.<JCTypeParameter>nil(), recv, List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null); + } else { + methodDef = maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null); + } + return methodDef; } - - private JCMethodDecl generateBuildMethod(CheckerFrameworkVersion cfv, String buildName, JavacNode returnType, JavacNode type, java.util.List<BuilderFieldData> builderFields, List<JCExpression> thrownExceptions) { - JavacTreeMaker maker = type.getTreeMaker(); + + private JCMethodDecl generateBuildMethod(SuperBuilderJob job, List<JCExpression> thrownExceptions) { + JavacTreeMaker maker = job.getTreeMaker(); JCExpression call; ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); // Use a constructor that only has this builder as parameter. - List<JCExpression> builderArg = List.<JCExpression>of(maker.Ident(type.toName("this"))); - call = maker.NewClass(null, List.<JCExpression>nil(), cloneSelfType(returnType), builderArg, null); + List<JCExpression> builderArg = List.<JCExpression>of(maker.Ident(job.toName("this"))); + call = maker.NewClass(null, List.<JCExpression>nil(), cloneSelfType(job.parentType), builderArg, null); statements.append(maker.Return(call)); JCBlock body = maker.Block(0, statements.toList()); - JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil()); + JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(job.builderType, "Override"), List.<JCExpression>nil()); List<JCAnnotation> annsOnMethod = List.of(overrideAnnotation); - if (cfv.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())); + if (job.checkerFramework.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())); JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC, annsOnMethod); - List<JCVariableDecl> params = HandleBuilder.generateBuildArgs(cfv, type, builderFields); - JCMethodDecl methodDef = maker.MethodDef(modifiers, type.toName(buildName), cloneSelfType(returnType), List.<JCTypeParameter>nil(), params, thrownExceptions, body, null); - createRelevantNonNullAnnotation(type, methodDef); + JCVariableDecl recv = HandleBuilder.generateReceiver(job); + JCMethodDecl methodDef; + if (recv != null && maker.hasMethodDefWithRecvParam()) { + methodDef = maker.MethodDefWithRecvParam(modifiers, job.toName(job.buildMethodName), cloneSelfType(job.parentType), List.<JCTypeParameter>nil(), recv, List.<JCVariableDecl>nil(), thrownExceptions, body, null); + } else { + methodDef = maker.MethodDef(modifiers, job.toName(job.buildMethodName), cloneSelfType(job.parentType), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), thrownExceptions, body, null); + } + createRelevantNonNullAnnotation(job.builderType, methodDef); return methodDef; } - private JCMethodDecl generateCleanMethod(java.util.List<BuilderFieldData> builderFields, JavacNode type, JCTree source) { + private JCMethodDecl generateCleanMethod(java.util.List<BuilderFieldData> builderFields, JavacNode type, JavacNode source) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); @@ -839,7 +880,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName("$lombokClean"), maker.Type(Javac.createVoidType(type.getSymbolTable(), CTC_VOID)), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); } - private void generateBuilderFields(JavacNode builderType, java.util.List<BuilderFieldData> builderFields, JCTree source) { + private void generateBuilderFields(JavacNode builderType, java.util.List<BuilderFieldData> builderFields, JavacNode source) { int len = builderFields.size(); java.util.List<JavacNode> existing = new ArrayList<JavacNode>(); for (JavacNode child : builderType.down()) { @@ -851,7 +892,11 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { for (int i = len - 1; i >= 0; i--) { BuilderFieldData bfd = builderFields.get(i); if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, builderType, source)); + java.util.List<JavacNode> fields = bfd.singularData.getSingularizer().generateFields(bfd.singularData, builderType, source); + for (JavacNode field : fields) { + generated.add((JCVariableDecl) field.get()); + } + bfd.createdFields.addAll(fields); } else { JavacNode field = null, setFlag = null; for (JavacNode exists : existing) { @@ -862,7 +907,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { JavacTreeMaker maker = builderType.getTreeMaker(); if (field == null) { JCModifiers mods = maker.Modifiers(Flags.PRIVATE); - JCVariableDecl newField = maker.VarDef(mods, bfd.builderFieldName, cloneType(maker, bfd.type, source, builderType.getContext()), null); + JCVariableDecl newField = maker.VarDef(mods, bfd.builderFieldName, cloneType(maker, bfd.type, source), null); field = injectFieldAndMarkGenerated(builderType, newField); generated.add(newField); } @@ -875,32 +920,33 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { bfd.createdFields.add(field); } } - for (JCVariableDecl gen : generated) recursiveSetGeneratedBy(gen, source, builderType.getContext()); + for (JCVariableDecl gen : generated) recursiveSetGeneratedBy(gen, source); } - private void generateSetterMethodsForBuilder(CheckerFrameworkVersion cfv, final JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, final String builderGenericName, String setterPrefix) { + private void generateSetterMethodsForBuilder(final SuperBuilderJob job, BuilderFieldData fieldNode, final String builderGenericName, String setterPrefix) { boolean deprecate = isFieldDeprecated(fieldNode.originalFieldNode); - final JavacTreeMaker maker = builderType.getTreeMaker(); + final JavacTreeMaker maker = job.getTreeMaker(); ExpressionMaker returnTypeMaker = new ExpressionMaker() { @Override public JCExpression make() { - return maker.Ident(builderType.toName(builderGenericName)); + return maker.Ident(job.toName(builderGenericName)); }}; StatementMaker returnStatementMaker = new StatementMaker() { @Override public JCStatement make() { - return maker.Return(maker.Apply(List.<JCExpression>nil(), maker.Ident(builderType.toName(SELF_METHOD)), List.<JCExpression>nil())); + return maker.Return(maker.Apply(List.<JCExpression>nil(), maker.Ident(job.toName(SELF_METHOD)), List.<JCExpression>nil())); }}; if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) { - generateSimpleSetterMethodForBuilder(cfv, builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.name, fieldNode.nameOfSetFlag, source, returnTypeMaker.make(), returnStatementMaker.make(), fieldNode.annotations, fieldNode.originalFieldNode, setterPrefix); + generateSimpleSetterMethodForBuilder(job, deprecate, fieldNode.createdFields.get(0), fieldNode.name, fieldNode.nameOfSetFlag, returnTypeMaker.make(), returnStatementMaker.make(), fieldNode.annotations, fieldNode.originalFieldNode, setterPrefix); } else { - fieldNode.singularData.getSingularizer().generateMethods(cfv, fieldNode.singularData, deprecate, builderType, source.get(), true, returnTypeMaker, returnStatementMaker, AccessLevel.PUBLIC); + fieldNode.singularData.getSingularizer().generateMethods(job.checkerFramework, fieldNode.singularData, deprecate, job.builderType, + job.sourceNode, true, returnTypeMaker, returnStatementMaker, AccessLevel.PUBLIC); } } - private void generateSimpleSetterMethodForBuilder(CheckerFrameworkVersion cfv, JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JavacNode source, JCExpression returnType, JCStatement returnStatement, List<JCAnnotation> annosOnParam, JavacNode originalFieldNode, String setterPrefix) { + private void generateSimpleSetterMethodForBuilder(SuperBuilderJob job, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JCExpression returnType, JCStatement returnStatement, List<JCAnnotation> annosOnParam, JavacNode originalFieldNode, String setterPrefix) { String setterName = HandlerUtil.buildAccessorName(setterPrefix, paramName.toString()); - Name setterName_ = builderType.toName(setterName); + Name setterName_ = job.builderType.toName(setterName); - for (JavacNode child : builderType.down()) { + for (JavacNode child : job.builderType.down()) { if (child.getKind() != Kind.METHOD) continue; JCMethodDecl methodDecl = (JCMethodDecl) child.get(); Name existingName = methodDecl.name; @@ -910,23 +956,24 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { JavacTreeMaker maker = fieldNode.getTreeMaker(); List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); - JCMethodDecl newMethod = HandleSetter.createSetter(Flags.PUBLIC, deprecate, fieldNode, maker, setterName, paramName, nameOfSetFlag, returnType, returnStatement, source, methodAnns, annosOnParam); - if (cfv.generateCalledMethods()) { - JCAnnotation ncAnno = maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__NOT_CALLED), List.<JCExpression>of(maker.Literal(newMethod.getName().toString()))); - JCClassDecl builderTypeNode = (JCClassDecl) builderType.get(); - JCExpression selfType = namePlusTypeParamsToTypeReference(maker, builderType, builderTypeNode.typarams); - JCVariableDecl recv = maker.VarDef(maker.Modifiers(0L, List.<JCAnnotation>of(ncAnno)), builderType.toName("this"), selfType, null); - newMethod.params = List.of(recv, newMethod.params.get(0)); + JCMethodDecl newMethod = null; + if (job.checkerFramework.generateCalledMethods() && maker.hasMethodDefWithRecvParam()) { + JCAnnotation ncAnno = maker.Annotation(genTypeRef(job.sourceNode, CheckerFrameworkVersion.NAME__NOT_CALLED), List.<JCExpression>of(maker.Literal(setterName.toString()))); + JCClassDecl builderTypeNode = (JCClassDecl) job.builderType.get(); + JCExpression selfType = namePlusTypeParamsToTypeReference(maker, job.builderType, builderTypeNode.typarams, List.<JCAnnotation>of(ncAnno)); + JCVariableDecl recv = maker.VarDef(maker.Modifiers(0L, List.<JCAnnotation>nil()), job.toName("this"), selfType, null); + newMethod = HandleSetter.createSetterWithRecv(Flags.PUBLIC, deprecate, fieldNode, maker, setterName, paramName, nameOfSetFlag, returnType, returnStatement, job.sourceNode, methodAnns, annosOnParam, recv); } - if (cfv.generateReturnsReceiver()) { + if (newMethod == null) newMethod = HandleSetter.createSetter(Flags.PUBLIC, deprecate, fieldNode, maker, setterName, paramName, nameOfSetFlag, returnType, returnStatement, job.sourceNode, methodAnns, annosOnParam); + if (job.checkerFramework.generateReturnsReceiver()) { List<JCAnnotation> annotations = newMethod.mods.annotations; if (annotations == null) annotations = List.nil(); - JCAnnotation anno = maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>nil()); - recursiveSetGeneratedBy(anno, source.get(), builderType.getContext()); + JCAnnotation anno = maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.<JCExpression>nil()); + recursiveSetGeneratedBy(anno, job.sourceNode); newMethod.mods.annotations = annotations.prepend(anno); } - injectMethod(builderType, newMethod); + injectMethod(job.builderType, newMethod); } private void addObtainVia(BuilderFieldData bfd, JavacNode node) { @@ -1032,17 +1079,17 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { return null; } - private ListBuffer<JCExpression> getTypeParamExpressions(List<? extends JCTree> typeParams, JavacTreeMaker maker, Context context) { + private ListBuffer<JCExpression> getTypeParamExpressions(List<? extends JCTree> typeParams, JavacTreeMaker maker, JavacNode source) { 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, typeParam, context)); + 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 85dc7e80..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; @@ -46,13 +45,12 @@ import com.sun.tools.javac.tree.JCTree.JCNewArray; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.util.Context; 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"; @@ -93,7 +91,6 @@ public class HandleSynchronized extends JavacAnnotationHandler<Synchronized> { } JavacTreeMaker maker = methodNode.getTreeMaker().at(ast.pos); - Context context = methodNode.getContext(); MemberExistsResult exists = MemberExistsResult.NOT_EXISTS; @@ -124,7 +121,7 @@ public class HandleSynchronized extends JavacAnnotationHandler<Synchronized> { List.<JCExpression>of(maker.Literal(CTC_INT, 0)), null); JCVariableDecl fieldDecl = recursiveSetGeneratedBy(maker.VarDef( maker.Modifiers(Flags.PRIVATE | Flags.FINAL | (isStatic[0] ? Flags.STATIC : 0)), - methodNode.toName(lockName), objectType, newObjectArray), ast, context); + methodNode.toName(lockName), objectType, newObjectArray), annotationNode); injectFieldAndMarkGenerated(methodNode.up(), fieldDecl); } @@ -137,8 +134,8 @@ public class HandleSynchronized extends JavacAnnotationHandler<Synchronized> { lockNode = maker.Select(maker.Ident(methodNode.toName("this")), methodNode.toName(lockName)); } - recursiveSetGeneratedBy(lockNode, ast, context); - method.body = setGeneratedBy(maker.Block(0, List.<JCStatement>of(setGeneratedBy(maker.Synchronized(lockNode, method.body), ast, context))), ast, context); + recursiveSetGeneratedBy(lockNode, annotationNode); + method.body = setGeneratedBy(maker.Block(0, List.<JCStatement>of(setGeneratedBy(maker.Synchronized(lockNode, method.body), annotationNode))), annotationNode); methodNode.rebuild(); } diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java index ff0016e4..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,11 +38,9 @@ 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; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; import com.sun.tools.javac.tree.JCTree.JCBlock; @@ -60,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"); @@ -135,7 +133,7 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { } } } - JCMethodDecl method = createToString(typeNode, members, includeFieldNames, callSuper, fieldAccess, source.get()); + JCMethodDecl method = createToString(typeNode, members, includeFieldNames, callSuper, fieldAccess, source); injectMethod(typeNode, method); break; case EXISTS_BY_LOMBOK: @@ -150,7 +148,7 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { } static JCMethodDecl createToString(JavacNode typeNode, Collection<Included<JavacNode, ToString.Include>> members, - boolean includeNames, boolean callSuper, FieldAccess fieldAccess, JCTree source) { + boolean includeNames, boolean callSuper, FieldAccess fieldAccess, JavacNode source) { JavacTreeMaker maker = typeNode.getTreeMaker(); @@ -250,7 +248,7 @@ public class HandleToString extends JavacAnnotationHandler<ToString> { JCMethodDecl methodDef = maker.MethodDef(mods, typeNode.toName("toString"), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); createRelevantNonNullAnnotation(typeNode, methodDef); - return recursiveSetGeneratedBy(methodDef, source, typeNode.getContext()); + return recursiveSetGeneratedBy(methodDef, source); } public static String getTypeName(JavacNode typeNode) { diff --git a/src/core/lombok/javac/handlers/HandleUtilityClass.java b/src/core/lombok/javac/handlers/HandleUtilityClass.java index 9ff33684..e006cc47 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 @@ -25,8 +25,6 @@ import static lombok.core.handlers.HandlerUtil.handleExperimentalFlagUsage; import static lombok.javac.Javac.CTC_VOID; import static lombok.javac.handlers.JavacHandlerUtil.*; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -50,12 +48,13 @@ import lombok.javac.Javac; 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"); @@ -69,7 +68,7 @@ public class HandleUtilityClass extends JavacAnnotationHandler<UtilityClass> { private static boolean checkLegality(JavacNode typeNode, JavacNode errorNode) { if (!isClass(typeNode)) { - errorNode.addError("@UtilityClass is only supported on a class (can't be an interface, enum, annotation, or record)."); + errorNode.addError("@UtilityClass is only supported on a class."); return false; } @@ -141,7 +140,7 @@ public class HandleUtilityClass extends JavacAnnotationHandler<UtilityClass> { Name name = typeNode.toName("<init>"); JCBlock block = maker.Block(0L, createThrowStatement(typeNode, maker)); JCMethodDecl methodDef = maker.MethodDef(mods, name, null, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), block, null); - JCMethodDecl constructor = recursiveSetGeneratedBy(methodDef, typeNode.get(), typeNode.getContext()); + JCMethodDecl constructor = recursiveSetGeneratedBy(methodDef, typeNode); JavacHandlerUtil.injectMethod(typeNode, constructor, List.<Type>nil(), Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID)); } diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java index 23c27bc0..7a524ca3 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 { @@ -63,6 +62,7 @@ public class HandleVal extends JavacASTAdapter { JCTree typeTree = local.vartype; if (typeTree == null) return; String typeTreeToString = typeTree.toString(); + JavacNode typeNode = localNode.getNodeFor(typeTree); if (!(eq(typeTreeToString, "val") || eq(typeTreeToString, "var"))) return; boolean isVal = typeMatches(val.class, localNode, typeTree); @@ -111,7 +111,7 @@ public class HandleVal extends JavacASTAdapter { if (isVal) local.mods.flags |= Flags.FINAL; if (!localNode.shouldDeleteLombokAnnotations()) { - JCAnnotation valAnnotation = recursiveSetGeneratedBy(localNode.getTreeMaker().Annotation(local.vartype, List.<JCExpression>nil()), typeTree, localNode.getContext()); + JCAnnotation valAnnotation = recursiveSetGeneratedBy(localNode.getTreeMaker().Annotation(local.vartype, List.<JCExpression>nil()), typeNode); local.mods.annotations = local.mods.annotations == null ? List.of(valAnnotation) : local.mods.annotations.append(valAnnotation); } @@ -182,7 +182,7 @@ public class HandleVal extends JavacASTAdapter { local.vartype = JavacResolution.createJavaLangObject(localNode.getAst()); throw e; } finally { - recursiveSetGeneratedBy(local.vartype, typeTree, localNode.getContext()); + recursiveSetGeneratedBy(local.vartype, typeNode); } } } diff --git a/src/core/lombok/javac/handlers/HandleValue.java b/src/core/lombok/javac/handlers/HandleValue.java index abc5a5ca..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(); @@ -72,7 +71,6 @@ public class HandleValue extends JavacAnnotationHandler<Value> { JCModifiers jcm = ((JCClassDecl) typeNode.get()).mods; if ((jcm.flags & Flags.FINAL) == 0) { jcm.flags |= Flags.FINAL; - typeNode.rebuild(); } } handleFieldDefaults.generateFieldDefaultsForType(typeNode, annotationNode, AccessLevel.PRIVATE, true, true); diff --git a/src/core/lombok/javac/handlers/HandleWith.java b/src/core/lombok/javac/handlers/HandleWith.java index 4e35a574..f914b4c7 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.code.Type; @@ -62,7 +61,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) { @@ -215,6 +214,7 @@ public class HandleWith extends JavacAnnotationHandler<With> { ClassSymbol sym = ((JCClassDecl) fieldNode.up().get()).sym; Type returnType = sym == null ? null : sym.type; + recursiveSetGeneratedBy(createdWith, source); injectMethod(typeNode, createdWith, List.<Type>of(getMirrorForFieldType(fieldNode)), returnType); } @@ -234,7 +234,7 @@ public class HandleWith extends JavacAnnotationHandler<With> { long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, field.getContext()); List<JCAnnotation> annsOnParam = copyAnnotations(onParam).appendList(copyableAnnotations); - JCExpression pType = cloneType(maker, fieldDecl.vartype, source.get(), source.getContext()); + JCExpression pType = cloneType(maker, fieldDecl.vartype, source); JCVariableDecl param = maker.VarDef(maker.Modifiers(flags, annsOnParam), fieldDecl.name, pType, null); if (!makeAbstract) { @@ -289,7 +289,7 @@ public class HandleWith extends JavacAnnotationHandler<With> { if (makeAbstract) access = access | Flags.ABSTRACT; JCMethodDecl decl = recursiveSetGeneratedBy(maker.MethodDef(maker.Modifiers(access, annsOnMethod), methodName, returnType, - methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source.get(), field.getContext()); + methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source); copyJavadoc(field, decl, CopyJavadoc.WITH); return decl; } diff --git a/src/core/lombok/javac/handlers/HandleWithBy.java b/src/core/lombok/javac/handlers/HandleWithBy.java index 19673172..f1f953b3 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; @@ -67,7 +66,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) { @@ -126,7 +125,6 @@ public class HandleWithBy extends JavacAnnotationHandler<WithBy> { @Override public void handle(AnnotationValues<WithBy> annotation, JCAnnotation ast, JavacNode annotationNode) { handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.WITHBY_FLAG_USAGE, "@WithBy"); - Collection<JavacNode> fields = annotationNode.upFromAnnotationToFields(); deleteAnnotationIfNeccessary(annotationNode, WithBy.class); deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel"); JavacNode node = annotationNode.up(); @@ -138,7 +136,7 @@ public class HandleWithBy extends JavacAnnotationHandler<WithBy> { switch (node.getKind()) { case FIELD: - createWithByForFields(level, fields, annotationNode, true, onMethod); + createWithByForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, true, onMethod); break; case TYPE: if (!onMethod.isEmpty()) annotationNode.addError("'onMethod' is not supported for @WithBy on a type."); @@ -209,6 +207,7 @@ public class HandleWithBy extends JavacAnnotationHandler<WithBy> { ClassSymbol sym = ((JCClassDecl) fieldNode.up().get()).sym; Type returnType = sym == null ? null : sym.type; + recursiveSetGeneratedBy(createdWithBy, source); injectMethod(typeNode, createdWithBy, List.<Type>of(getMirrorForFieldType(fieldNode)), returnType); } @@ -265,7 +264,7 @@ public class HandleWithBy extends JavacAnnotationHandler<WithBy> { } if (functionalInterfaceName == null) { functionalInterfaceName = NAME_JUF_FUNCTION; - parameterizer = cloneType(maker, fieldDecl.vartype, source.get(), field.getContext()); + parameterizer = cloneType(maker, fieldDecl.vartype, source); } if (functionalInterfaceName == NAME_JUF_INTOP) applyMethodName = "applyAsInt"; if (functionalInterfaceName == NAME_JUF_LONGOP) applyMethodName = "applyAsLong"; @@ -274,7 +273,7 @@ public class HandleWithBy extends JavacAnnotationHandler<WithBy> { JCExpression varType = chainDots(field, functionalInterfaceName); if (parameterizer != null && superExtendsStyle) { JCExpression parameterizer1 = parameterizer; - JCExpression parameterizer2 = cloneType(maker, parameterizer, source.get(), field.getContext()); + JCExpression parameterizer2 = cloneType(maker, parameterizer, source); // TODO: Apply copyable annotations to 'parameterizer' and 'parameterizer2'. JCExpression arg1 = maker.Wildcard(maker.TypeBoundKind(BoundKind.SUPER), parameterizer1); JCExpression arg2 = maker.Wildcard(maker.TypeBoundKind(BoundKind.EXTENDS), parameterizer2); @@ -334,7 +333,7 @@ public class HandleWithBy extends JavacAnnotationHandler<WithBy> { if (makeAbstract) access = access | Flags.ABSTRACT; createRelevantNonNullAnnotation(source, param); JCMethodDecl decl = recursiveSetGeneratedBy(maker.MethodDef(maker.Modifiers(access, annsOnMethod), methodName, returnType, - methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source.get(), field.getContext()); + methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source); copyJavadoc(field, decl, CopyJavadoc.WITH_BY); createRelevantNonNullAnnotation(source, decl); return decl; diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index cd4bc70a..b4f2acc4 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2020 The Project Lombok Authors. + * Copyright (C) 2009-2021 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,7 +35,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.lang.model.element.Element; @@ -103,7 +102,6 @@ import lombok.core.handlers.HandlerUtil.FieldAccess; import lombok.delombok.LombokOptionsFactory; import lombok.experimental.Accessors; import lombok.experimental.Tolerate; -import lombok.javac.Java14Flags; import lombok.javac.Javac; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; @@ -118,17 +116,15 @@ public class JavacHandlerUtil { } private static class MarkingScanner extends TreeScanner { - private final JCTree source; - private final Context context; + private final JavacNode source; - MarkingScanner(JCTree source, Context context) { + MarkingScanner(JavacNode source) { this.source = source; - this.context = context; } @Override public void scan(JCTree tree) { if (tree == null) return; - setGeneratedBy(tree, source, context); + setGeneratedBy(tree, source); super.scan(tree); } } @@ -146,12 +142,12 @@ public class JavacHandlerUtil { Options options = Options.instance(context); return (options.keySet().contains("ide") && !options.keySet().contains("backgroundCompilation")); } - + public static boolean inNetbeansCompileOnSave(Context context) { Options options = Options.instance(context); return (options.keySet().contains("ide") && options.keySet().contains("backgroundCompilation")); } - + public static JCTree getGeneratedBy(JCTree node) { return JCTree_generatedNode.get(node); } @@ -160,20 +156,31 @@ public class JavacHandlerUtil { return getGeneratedBy(node) != null; } - public static <T extends JCTree> T recursiveSetGeneratedBy(T node, JCTree source, Context context) { + public static <T extends JCTree> T recursiveSetGeneratedBy(T node, JavacNode source) { if (node == null) return null; - setGeneratedBy(node, source, context); - node.accept(new MarkingScanner(source, context)); + setGeneratedBy(node, source); + node.accept(new MarkingScanner(source)); return node; } - public static <T extends JCTree> T setGeneratedBy(T node, JCTree source, Context context) { + public static <T extends JCTree> T setGeneratedBy(T node, JavacNode sourceNode) { if (node == null) return null; - if (source == null) JCTree_generatedNode.clear(node); - else JCTree_generatedNode.set(node, source); - if (source != null && (!inNetbeansEditor(context) || (node instanceof JCVariableDecl && (((JCVariableDecl) node).mods.flags & Flags.PARAMETER) != 0))) node.pos = source.pos; + if (sourceNode == null) { + JCTree_generatedNode.clear(node); + return node; + } + JCTree_generatedNode.set(node, sourceNode.get()); + + if (!inNetbeansEditor(sourceNode.getContext()) || isParameter(node)) { + node.pos = sourceNode.getStartPos(); + storeEnd(node, sourceNode.getEndPosition(), (JCCompilationUnit) sourceNode.top().get()); + } return node; } + + public static boolean isParameter(JCTree node) { + return node instanceof JCVariableDecl && (((JCVariableDecl) node).mods.flags & Flags.PARAMETER) != 0; + } public static boolean hasAnnotation(String type, JavacNode node) { return hasAnnotation(type, node, false); @@ -800,7 +807,7 @@ public class JavacHandlerUtil { node = upToTypeNode(node); if (node != null && node.get() instanceof JCClassDecl) { - for (JCTree def : ((JCClassDecl)node.get()).defs) { + for (JCTree def : ((JCClassDecl) node.get()).defs) { if (def instanceof JCMethodDecl) { JCMethodDecl md = (JCMethodDecl) def; if (md.name.contentEquals("<init>")) { @@ -816,23 +823,21 @@ public class JavacHandlerUtil { } /** - * Checks if there is a constructor generated by lombok. + * Checks if there is at least one constructor that is generated by lombok. * - * @param node Any node that represents the Type (JCClassDecl) to look in, or any child node thereof. + * @param node Any node that represents the Type (TypeDeclaration) to look in, or any child node thereof. */ public static boolean lombokConstructorExists(JavacNode node) { node = upToTypeNode(node); if (node != null && node.get() instanceof JCClassDecl) { - for (JCTree def : ((JCClassDecl)node.get()).defs) { + for (JCTree def : ((JCClassDecl) node.get()).defs) { if (def instanceof JCMethodDecl) { JCMethodDecl md = (JCMethodDecl) def; if (md.name.contentEquals("<init>")) { if ((md.mods.flags & Flags.GENERATEDCONSTR) != 0) continue; if (isTolerate(node, md)) continue; - if (getGeneratedBy(def) != null) { - return true; - } + if (getGeneratedBy(def) != null) return true; } } } @@ -1054,7 +1059,7 @@ public class JavacHandlerUtil { public static JavacNode injectField(JavacNode typeNode, JCVariableDecl field) { return injectField(typeNode, field, false); } - + public static JavacNode injectField(JavacNode typeNode, JCVariableDecl field, boolean addGenerated) { return injectField(typeNode, field, addGenerated, false); } @@ -1063,8 +1068,8 @@ public class JavacHandlerUtil { JCClassDecl type = (JCClassDecl) typeNode.get(); if (addGenerated) { - addSuppressWarningsAll(field.mods, typeNode, field.pos, getGeneratedBy(field), typeNode.getContext()); - addGenerated(field.mods, typeNode, field.pos, getGeneratedBy(field), typeNode.getContext()); + addSuppressWarningsAll(field.mods, typeNode, typeNode.getNodeFor(getGeneratedBy(field)), typeNode.getContext()); + addGenerated(field.mods, typeNode, typeNode.getNodeFor(getGeneratedBy(field)), typeNode.getContext()); } List<JCTree> insertAfter = null; @@ -1104,6 +1109,17 @@ public class JavacHandlerUtil { private static Constructor<?> CONSTRUCTOR; private static Field ANNOTATIONS, UNDERLYING_TYPE; + private static void initByLoader(ClassLoader classLoader) { + if (TYPE != null) return; + Class<?> c; + try { + c = classLoader.loadClass("com.sun.tools.javac.tree.JCTree$JCAnnotatedType"); + } catch (Exception e) { + return; + } + init(c); + } + private static void init(Class<?> in) { if (TYPE != null) return; if (!in.getName().equals("com.sun.tools.javac.tree.JCTree$JCAnnotatedType")) return; @@ -1148,17 +1164,18 @@ public class JavacHandlerUtil { } static JCExpression create(List<JCAnnotation> annotations, JCExpression underlyingType) { + initByLoader(underlyingType.getClass().getClassLoader()); try { return (JCExpression) CONSTRUCTOR.newInstance(annotations, underlyingType); } catch (Exception e) { - return null; + return underlyingType; } } } - + static class JCAnnotationReflect { private static Field ATTRIBUTE; - + static { try { ATTRIBUTE = Permit.getField(JCAnnotation.class, "attribute"); @@ -1199,7 +1216,7 @@ public class JavacHandlerUtil { try { Scope scope = (Scope) membersField.get(from); if (scope == null) return; - removeMethod.invoke(scope, toRemove); + Permit.invoke(removeMethod, scope, toRemove); } catch (Exception e) {} } @@ -1208,7 +1225,7 @@ public class JavacHandlerUtil { try { Scope scope = (Scope) membersField.get(from); if (scope == null) return; - enterMethod.invoke(scope, toEnter); + Permit.invoke(enterMethod, scope, toEnter); } catch (Exception e) {} } } @@ -1227,7 +1244,7 @@ public class JavacHandlerUtil { Context context = typeNode.getContext(); Symtab symtab = Symtab.instance(context); JCClassDecl type = (JCClassDecl) typeNode.get(); - + if (method.getName().contentEquals("<init>")) { //Scan for default constructor, and remove it. int idx = 0; @@ -1244,11 +1261,11 @@ public class JavacHandlerUtil { idx++; } } - - addSuppressWarningsAll(method.mods, typeNode, method.pos, getGeneratedBy(method), typeNode.getContext()); - addGenerated(method.mods, typeNode, method.pos, getGeneratedBy(method), typeNode.getContext()); + + addSuppressWarningsAll(method.mods, typeNode, typeNode.getNodeFor(getGeneratedBy(method)), typeNode.getContext()); + addGenerated(method.mods, typeNode, typeNode.getNodeFor(getGeneratedBy(method)), typeNode.getContext()); type.defs = type.defs.append(method); - + List<Symbol.VarSymbol> params = null; if (method.getParameters() != null && !method.getParameters().isEmpty()) { ListBuffer<Symbol.VarSymbol> newParams = new ListBuffer<Symbol.VarSymbol>(); @@ -1257,6 +1274,7 @@ public class JavacHandlerUtil { if (param.sym == null) { Type paramType = paramTypes == null ? param.getType().type : paramTypes.get(i); VarSymbol varSymbol = new VarSymbol(param.mods.flags, param.name, paramType, symtab.noSymbol); + varSymbol.adr = 1 << i; List<JCAnnotation> annotations = param.getModifiers().getAnnotations(); if (annotations != null && !annotations.isEmpty()) { ListBuffer<Attribute.Compound> newAnnotations = new ListBuffer<Attribute.Compound>(); @@ -1278,9 +1296,9 @@ public class JavacHandlerUtil { params = newParams.toList(); if (params.length() != method.getParameters().length()) params = null; } - + fixMethodMirror(typeNode.getContext(), typeNode.getElement(), method.getModifiers().flags, method.getName(), paramTypes, params, returnType); - + typeNode.add(method, Kind.METHOD); } @@ -1290,6 +1308,9 @@ public class JavacHandlerUtil { MethodSymbol methodSymbol = new MethodSymbol(access, methodName, new MethodType(paramTypes, returnType, List.<Type>nil(), Symtab.instance(context).methodClass), cs); if (params != null && !params.isEmpty()) { methodSymbol.params = params; + for (VarSymbol varSymbol : params) { + varSymbol.owner = methodSymbol; + } } ClassSymbolMembersField.enter(cs, methodSymbol); } @@ -1303,8 +1324,8 @@ public class JavacHandlerUtil { */ public static JavacNode injectType(JavacNode typeNode, final JCClassDecl type) { JCClassDecl typeDecl = (JCClassDecl) typeNode.get(); - addSuppressWarningsAll(type.mods, typeNode, type.pos, getGeneratedBy(type), typeNode.getContext()); - addGenerated(type.mods, typeNode, type.pos, getGeneratedBy(type), typeNode.getContext()); + addSuppressWarningsAll(type.mods, typeNode, typeNode.getNodeFor(getGeneratedBy(type)), typeNode.getContext()); + addGenerated(type.mods, typeNode, typeNode.getNodeFor(getGeneratedBy(type)), typeNode.getContext()); typeDecl.defs = typeDecl.defs.append(type); return typeNode.add(type, Kind.TYPE); } @@ -1343,7 +1364,7 @@ public class JavacHandlerUtil { } } - public static void addSuppressWarningsAll(JCModifiers mods, JavacNode node, int pos, JCTree source, Context context) { + public static void addSuppressWarningsAll(JCModifiers mods, JavacNode node, JavacNode source, Context context) { if (!LombokOptionsFactory.getDelombokOptions(context).getFormatPreferences().generateSuppressWarnings()) return; boolean addJLSuppress = !Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_SUPPRESSWARNINGS_ANNOTATIONS)); @@ -1359,27 +1380,27 @@ public class JavacHandlerUtil { } } } - if (addJLSuppress) addAnnotation(mods, node, pos, source, context, "java.lang.SuppressWarnings", node.getTreeMaker().Literal("all")); + if (addJLSuppress) addAnnotation(mods, node, source, "java.lang.SuppressWarnings", node.getTreeMaker().Literal("all")); if (Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_FINDBUGS_SUPPRESSWARNINGS_ANNOTATIONS))) { JavacTreeMaker maker = node.getTreeMaker(); JCExpression arg = maker.Assign(maker.Ident(node.toName("justification")), maker.Literal("generated code")); - addAnnotation(mods, node, pos, source, context, "edu.umd.cs.findbugs.annotations.SuppressFBWarnings", arg); + addAnnotation(mods, node, source, "edu.umd.cs.findbugs.annotations.SuppressFBWarnings", arg); } } - public static void addGenerated(JCModifiers mods, JavacNode node, int pos, JCTree source, Context context) { + public static void addGenerated(JCModifiers mods, JavacNode node, JavacNode source, Context context) { if (!LombokOptionsFactory.getDelombokOptions(context).getFormatPreferences().generateGenerated()) return; if (HandlerUtil.shouldAddGenerated(node)) { - addAnnotation(mods, node, pos, source, context, "javax.annotation.Generated", node.getTreeMaker().Literal("lombok")); + addAnnotation(mods, node, source, "javax.annotation.Generated", node.getTreeMaker().Literal("lombok")); } if (Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_LOMBOK_GENERATED_ANNOTATIONS))) { - addAnnotation(mods, node, pos, source, context, "lombok.Generated", null); + addAnnotation(mods, node, source, "lombok.Generated", null); } } - public static void addAnnotation(JCModifiers mods, JavacNode node, int pos, JCTree source, Context context, String annotationTypeFqn, JCExpression arg) { + public static void addAnnotation(JCModifiers mods, JavacNode node, JavacNode source, String annotationTypeFqn, JCExpression arg) { boolean isJavaLangBased; String simpleName; { int idx = annotationTypeFqn.lastIndexOf('.'); @@ -1402,17 +1423,8 @@ public class JavacHandlerUtil { JavacTreeMaker maker = node.getTreeMaker(); JCExpression annType = isJavaLangBased ? genJavaLangTypeRef(node, simpleName) : chainDotsString(node, annotationTypeFqn); - annType.pos = pos; - if (arg != null) { - arg.pos = pos; - if (arg instanceof JCAssign) { - ((JCAssign) arg).lhs.pos = pos; - ((JCAssign) arg).rhs.pos = pos; - } - } List<JCExpression> argList = arg != null ? List.of(arg) : List.<JCExpression>nil(); - JCAnnotation annotation = recursiveSetGeneratedBy(maker.Annotation(annType, argList), source, context); - annotation.pos = pos; + JCAnnotation annotation = recursiveSetGeneratedBy(maker.Annotation(annType, argList), source); mods.annotations = mods.annotations.append(annotation); } @@ -1456,6 +1468,7 @@ public class JavacHandlerUtil { } return e; } + /** * In javac, dotted access of any kind, from {@code java.lang.String} to {@code var.methodName} * is represented by a fold-left of {@code Select} nodes with the leftmost string represented by @@ -1831,13 +1844,12 @@ public class JavacHandlerUtil { if (params == null || params.isEmpty()) return params; ListBuffer<JCTypeParameter> out = new ListBuffer<JCTypeParameter>(); JavacTreeMaker maker = source.getTreeMaker(); - Context context = source.getContext(); for (JCTypeParameter tp : params) { List<JCExpression> bounds = tp.bounds; if (bounds != null && !bounds.isEmpty()) { ListBuffer<JCExpression> boundsCopy = new ListBuffer<JCExpression>(); for (JCExpression expr : tp.bounds) { - boundsCopy.append(cloneType(maker, expr, source.get(), context)); + boundsCopy.append(cloneType(maker, expr, source)); } bounds = boundsCopy.toList(); } @@ -1859,20 +1871,30 @@ public class JavacHandlerUtil { public static JCExpression namePlusTypeParamsToTypeReference(JavacTreeMaker maker, JavacNode type, List<JCTypeParameter> params) { JCClassDecl td = (JCClassDecl) type.get(); boolean instance = (td.mods.flags & Flags.STATIC) == 0; - return namePlusTypeParamsToTypeReference(maker, type.up(), td.name, instance, params); + return namePlusTypeParamsToTypeReference(maker, type.up(), td.name, instance, params, List.<JCAnnotation>nil()); + } + + public static JCExpression namePlusTypeParamsToTypeReference(JavacTreeMaker maker, JavacNode type, List<JCTypeParameter> params, List<JCAnnotation> annotations) { + JCClassDecl td = (JCClassDecl) type.get(); + boolean instance = (td.mods.flags & Flags.STATIC) == 0; + return namePlusTypeParamsToTypeReference(maker, type.up(), td.name, instance, params, annotations); } public static JCExpression namePlusTypeParamsToTypeReference(JavacTreeMaker maker, JavacNode parentType, Name typeName, boolean instance, List<JCTypeParameter> params) { + return namePlusTypeParamsToTypeReference(maker, parentType, typeName, instance, params, List.<JCAnnotation>nil()); + } + + public static JCExpression namePlusTypeParamsToTypeReference(JavacTreeMaker maker, JavacNode parentType, Name typeName, boolean instance, List<JCTypeParameter> params, List<JCAnnotation> annotations) { JCExpression r = null; - if (parentType != null && parentType.getKind() == Kind.TYPE) { JCClassDecl td = (JCClassDecl) parentType.get(); boolean outerInstance = instance && ((td.mods.flags & Flags.STATIC) == 0); List<JCTypeParameter> outerParams = instance ? td.typarams : List.<JCTypeParameter>nil(); - r = namePlusTypeParamsToTypeReference(maker, parentType.up(), td.name, outerInstance, outerParams); + r = namePlusTypeParamsToTypeReference(maker, parentType.up(), td.name, outerInstance, outerParams, List.<JCAnnotation>nil()); } r = r == null ? maker.Ident(typeName) : maker.Select(r, typeName); + if (!annotations.isEmpty()) r = JCAnnotatedTypeReflect.create(annotations, r); if (!params.isEmpty()) r = maker.TypeApply(r, typeParameterNames(maker, params)); return r; } @@ -1926,17 +1948,30 @@ public class JavacHandlerUtil { return out.toList(); } - static boolean isClass(JavacNode typeNode) { - return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ENUM | Flags.ANNOTATION | Java14Flags.RECORD); + /** + * 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 | Java14Flags.RECORD); + /** + * 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, 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; @@ -1950,11 +1985,11 @@ public class JavacHandlerUtil { return node; } - public static List<JCExpression> cloneTypes(JavacTreeMaker maker, List<JCExpression> in, JCTree source, Context context) { + public static List<JCExpression> cloneTypes(JavacTreeMaker maker, List<JCExpression> in, JavacNode source) { if (in.isEmpty()) return List.nil(); - if (in.size() == 1) return List.of(cloneType(maker, in.get(0), source, context)); + if (in.size() == 1) return List.of(cloneType(maker, in.get(0), source)); ListBuffer<JCExpression> lb = new ListBuffer<JCExpression>(); - for (JCExpression expr : in) lb.append(cloneType(maker, expr, source, context)); + for (JCExpression expr : in) lb.append(cloneType(maker, expr, source)); return lb.toList(); } @@ -1968,9 +2003,9 @@ public class JavacHandlerUtil { * the class's own parameter, but as its a static method, the static method's notion of {@code T} is different from the class notion of {@code T}. If you're duplicating * a type used in the class context, you need to use this method. */ - public static JCExpression cloneType(JavacTreeMaker maker, JCExpression in, JCTree source, Context context) { + public static JCExpression cloneType(JavacTreeMaker maker, JCExpression in, JavacNode source) { JCExpression out = cloneType0(maker, in); - if (out != null) recursiveSetGeneratedBy(out, source, context); + if (out != null) recursiveSetGeneratedBy(out, source); return out; } @@ -2031,50 +2066,6 @@ public class JavacHandlerUtil { return (JCExpression) in; } - private static final Pattern SECTION_FINDER = Pattern.compile("^\\s*\\**\\s*[-*][-*]+\\s*([GS]ETTER|WITH(?:ER)?)\\s*[-*][-*]+\\s*\\**\\s*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); - private static final Pattern LINE_BREAK_FINDER = Pattern.compile("(\\r?\\n)?"); - - public static String stripLinesWithTagFromJavadoc(String javadoc, String regexpFragment) { - Pattern p = Pattern.compile("^\\s*\\**\\s*" + regexpFragment + "\\s*\\**\\s*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); - Matcher m = p.matcher(javadoc); - return m.replaceAll(""); - } - - public static String stripSectionsFromJavadoc(String javadoc) { - Matcher sectionMatcher = SECTION_FINDER.matcher(javadoc); - if (!sectionMatcher.find()) return javadoc; - - return javadoc.substring(0, sectionMatcher.start()); - } - - public static String getJavadocSection(String javadoc, String sectionNameSpec) { - String[] sectionNames = sectionNameSpec.split("\\|"); - Matcher sectionMatcher = SECTION_FINDER.matcher(javadoc); - Matcher lineBreakMatcher = LINE_BREAK_FINDER.matcher(javadoc); - int sectionStart = -1; - int sectionEnd = -1; - while (sectionMatcher.find()) { - boolean found = false; - for (String sectionName : sectionNames) if (sectionMatcher.group(1).equalsIgnoreCase(sectionName)) { - found = true; - break; - } - if (found) { - lineBreakMatcher.find(sectionMatcher.end()); - sectionStart = lineBreakMatcher.end(); - } else if (sectionStart != -1) { - sectionEnd = sectionMatcher.start(); - } - } - - if (sectionStart != -1) { - if (sectionEnd != -1) return javadoc.substring(sectionStart, sectionEnd); - return javadoc.substring(sectionStart); - } - - return null; - } - public static enum CopyJavadoc { VERBATIM { @Override public String apply(final JCCompilationUnit cu, final JavacNode node) { @@ -2089,7 +2080,7 @@ public class JavacHandlerUtil { String out = getJavadocSection(javadoc, "GETTER"); final boolean sectionBased = out != null; if (!sectionBased) { - out = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), "@param(?:eter)?\\s+.*"); + out = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), JavadocTag.PARAM); } node.getAst().cleanupTask("javadocfilter-getter", n, new CleanupTask() { @Override public void cleanup() { @@ -2097,7 +2088,7 @@ public class JavacHandlerUtil { if (javadoc == null || javadoc.isEmpty()) return; javadoc = stripSectionsFromJavadoc(javadoc); if (!sectionBased) { - javadoc = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), "@returns?\\s+.*"); + javadoc = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), JavadocTag.RETURN); } Javac.setDocComment(cu, n, javadoc); } @@ -2130,7 +2121,7 @@ public class JavacHandlerUtil { String out = getJavadocSection(javadoc, sectionName); final boolean sectionBased = out != null; if (!sectionBased) { - out = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), "@returns?\\s+.*"); + out = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), JavadocTag.RETURN); } node.getAst().cleanupTask("javadocfilter-setter", n, new CleanupTask() { @Override public void cleanup() { @@ -2138,7 +2129,7 @@ public class JavacHandlerUtil { if (javadoc == null || javadoc.isEmpty()) return; javadoc = stripSectionsFromJavadoc(javadoc); if (!sectionBased) { - javadoc = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), "@param(?:eter)?\\s+.*"); + javadoc = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), JavadocTag.PARAM); } Javac.setDocComment(cu, n, javadoc); } @@ -2150,6 +2141,7 @@ public class JavacHandlerUtil { public static void copyJavadoc(JavacNode from, JCTree to, CopyJavadoc copyMode) { copyJavadoc(from, to, copyMode, false); } + /** * Copies javadoc on one node to the other. * @@ -2164,31 +2156,13 @@ public class JavacHandlerUtil { try { JCCompilationUnit cu = ((JCCompilationUnit) from.top().get()); String newJavadoc = copyMode.apply(cu, from); - if (newJavadoc != null) { - if (forceAddReturn) newJavadoc = addReturnsThisIfNeeded(newJavadoc); - Javac.setDocComment(cu, to, newJavadoc); + if (forceAddReturn) { + newJavadoc = addReturnsThisIfNeeded(newJavadoc); } + Javac.setDocComment(cu, to, newJavadoc); } catch (Exception ignore) {} } - private static final Pattern FIND_RETURN = Pattern.compile("^\\s*\\**\\s*@returns?\\s+.*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); - static String addReturnsThisIfNeeded(String in) { - if (FIND_RETURN.matcher(in).find()) return in; - - return addJavadocLine(in, "@return {@code this}."); - } - - static String addReturnsUpdatedSelfIfNeeded(String in) { - if (FIND_RETURN.matcher(in).find()) return in; - - return addJavadocLine(in, "@return a clone of this object, except with this updated property (returns {@code this} if an identical value is passed)."); - } - - static String addJavadocLine(String in, String line) { - if (in.endsWith("\n")) return in + line + "\n"; - return in + "\n" + line; - } - public static boolean isDirectDescendantOfObject(JavacNode typeNode) { if (!(typeNode.get() instanceof JCClassDecl)) throw new IllegalArgumentException("not a type node"); JCTree extending = Javac.getExtendsClause((JCClassDecl) typeNode.get()); @@ -2232,6 +2206,10 @@ public class JavacHandlerUtil { JCExpression resType = mth.restype; if (resType instanceof JCTypeApply) { JCTypeApply ta = (JCTypeApply) resType; + if (ta.clazz instanceof JCFieldAccess) { + mth.restype = maker.TypeApply(maker.AnnotatedType(List.of(m), ta.clazz), ta.arguments); + return; + } resType = ta.clazz; } @@ -2287,8 +2265,4 @@ public class JavacHandlerUtil { arg.mods.annotations = arg.mods.annotations == null ? List.of(m) : arg.mods.annotations.prepend(m); } } - - public static boolean isRecord(JavacNode typeNode) { - return typeNode.getKind() == Kind.TYPE && (((JCClassDecl) typeNode.get()).mods.flags & Java14Flags.RECORD) != 0; - } } diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index 7cd52c8c..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 @@ -43,7 +43,6 @@ import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.JCTree.JCWildcard; -import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; @@ -57,6 +56,7 @@ import lombok.core.configuration.CheckerFrameworkVersion; import lombok.core.handlers.HandlerUtil; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; +import lombok.javac.handlers.HandleBuilder.BuilderJob; public class JavacSingularsRecipes { public interface ExpressionMaker { @@ -235,7 +235,7 @@ public class JavacSingularsRecipes { return Arrays.asList(p, s); } - public abstract java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source); + public abstract java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JavacNode source); /** * Generates the singular, plural, and clear methods for the given {@link SingularData}. @@ -243,36 +243,38 @@ public class JavacSingularsRecipes { * If you need more control over the return type and value, use * {@link #generateMethods(SingularData, boolean, JavacNode, JCTree, boolean, ExpressionMaker, StatementMaker)}. */ - public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, final JavacNode builderType, JCTree source, boolean fluent, final boolean chain, AccessLevel access) { - final JavacTreeMaker maker = builderType.getTreeMaker(); + public void generateMethods(final BuilderJob job, SingularData data, boolean deprecate) { + //job.checkerFramework, job.builderType, job.source, job.oldFluent, job.oldChain, job.accessInners + //CheckerFrameworkVersion cfv, final JavacNode builderType, JavacNode source, boolean fluent, final boolean chain, AccessLevel access) { + final JavacTreeMaker maker = job.builderType.getTreeMaker(); ExpressionMaker returnTypeMaker = new ExpressionMaker() { @Override public JCExpression make() { - return chain ? - cloneSelfType(builderType) : - maker.Type(createVoidType(builderType.getSymbolTable(), CTC_VOID)); + return job.oldChain ? + cloneSelfType(job.builderType) : + maker.Type(createVoidType(job.builderType.getSymbolTable(), CTC_VOID)); }}; StatementMaker returnStatementMaker = new StatementMaker() { @Override public JCStatement make() { - return chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null; + return job.oldChain ? maker.Return(maker.Ident(job.builderType.toName("this"))) : null; }}; - generateMethods(cfv, data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker, access); + generateMethods(job.checkerFramework, data, deprecate, job.builderType, job.sourceNode, job.oldFluent, returnTypeMaker, returnStatementMaker, job.accessInners); } /** * Generates the singular, plural, and clear methods for the given {@link SingularData}. * Uses the given {@code returnTypeMaker} and {@code returnStatementMaker} for the generated methods. */ - public abstract void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access); + public abstract void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JavacNode source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access); - protected void doGenerateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { + protected void doGenerateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JavacNode source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { JavacTreeMaker maker = builderType.getTreeMaker(); generateSingularMethod(cfv, deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, fluent, access); generatePluralMethod(cfv, deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, fluent, access); generateClearMethod(cfv, deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, access); } - private void finishAndInjectMethod(CheckerFrameworkVersion cfv, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean deprecate, ListBuffer<JCStatement> statements, Name methodName, List<JCVariableDecl> jcVariableDecls, List<JCAnnotation> methodAnnotations, AccessLevel access, Boolean ignoreNullCollections) { + private void finishAndInjectMethod(CheckerFrameworkVersion cfv, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JavacNode source, boolean deprecate, ListBuffer<JCStatement> statements, Name methodName, List<JCVariableDecl> jcVariableDecls, List<JCAnnotation> methodAnnotations, AccessLevel access, Boolean ignoreNullCollections) { if (returnStatement != null) statements.append(returnStatement); JCBlock body = maker.Block(0, statements.toList()); JCModifiers mods = makeMods(maker, cfv, builderType, deprecate, access, methodAnnotations); @@ -288,15 +290,15 @@ public class JavacSingularsRecipes { } JCMethodDecl method = maker.MethodDef(mods, methodName, returnType, typeParams, jcVariableDecls, thrown, body, null); - recursiveSetGeneratedBy(method, source, builderType.getContext()); if (returnStatement != null) createRelevantNonNullAnnotation(builderType, method); + recursiveSetGeneratedBy(method, source); injectMethod(builderType, method); } - private void generateClearMethod(CheckerFrameworkVersion cfv, boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, AccessLevel access) { + 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); @@ -304,7 +306,7 @@ public class JavacSingularsRecipes { protected abstract JCStatement generateClearStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType); - private void generateSingularMethod(CheckerFrameworkVersion cfv, boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent, AccessLevel access) { + private void generateSingularMethod(CheckerFrameworkVersion cfv, boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JavacNode source, boolean fluent, AccessLevel access) { ListBuffer<JCStatement> statements = generateSingularMethodStatements(maker, data, builderType, source); List<JCVariableDecl> params = generateSingularMethodParameters(maker, data, builderType, source); Name name = data.getSingularName(); @@ -317,7 +319,7 @@ public class JavacSingularsRecipes { finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, params, methodAnnotations, access, null); } - protected JCVariableDecl generateSingularMethodParameter(int typeIndex, JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source, Name name) { + protected JCVariableDecl generateSingularMethodParameter(int typeIndex, JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source, Name name) { long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext()); JCExpression type = cloneParamType(typeIndex, maker, data.getTypeArgs(), builderType, source); List<JCAnnotation> typeUseAnns = getTypeUseAnnotations(type); @@ -332,11 +334,11 @@ public class JavacSingularsRecipes { return maker.Exec(invokeAdd); } - protected abstract ListBuffer<JCStatement> generateSingularMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source); + protected abstract ListBuffer<JCStatement> generateSingularMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source); - protected abstract List<JCVariableDecl> generateSingularMethodParameters(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source); + protected abstract List<JCVariableDecl> generateSingularMethodParameters(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source); - private void generatePluralMethod(CheckerFrameworkVersion cfv, boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent, AccessLevel access) { + private void generatePluralMethod(CheckerFrameworkVersion cfv, boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JavacNode source, boolean fluent, AccessLevel access) { ListBuffer<JCStatement> statements = generatePluralMethodStatements(maker, data, builderType, source); Name name = data.getPluralName(); @@ -355,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")); } @@ -365,7 +367,7 @@ public class JavacSingularsRecipes { finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, List.of(param), methodAnnotations, access, ignoreNullCollections); } - protected ListBuffer<JCStatement> generatePluralMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { + protected ListBuffer<JCStatement> generatePluralMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source) { ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); JCExpression thisDotFieldDotAdd = chainDots(builderType, "this", data.getPluralName().toString(), getAddMethodName() + "All"); @@ -377,9 +379,9 @@ public class JavacSingularsRecipes { protected abstract JCExpression getPluralMethodParamType(JavacNode builderType); - protected abstract JCStatement createConstructBuilderVarIfNeeded(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source); + protected abstract JCStatement createConstructBuilderVarIfNeeded(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source); - public abstract void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable); + public abstract void appendBuildCode(SingularData data, JavacNode builderType, JavacNode source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable); public boolean shadowedDuringBuild() { return true; @@ -393,7 +395,7 @@ public class JavacSingularsRecipes { } } - public void appendCleaningCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements) { + public void appendCleaningCode(SingularData data, JavacNode builderType, JavacNode source, ListBuffer<JCStatement> statements) { } // -- Utility methods -- @@ -409,16 +411,15 @@ public class JavacSingularsRecipes { * @param typeArgs the list of type args to clone. * @param source The source annotation that is the root cause of this code generation. */ - protected JCExpression addTypeArgs(int count, boolean addExtends, JavacNode node, JCExpression type, List<JCExpression> typeArgs, JCTree source) { + protected JCExpression addTypeArgs(int count, boolean addExtends, JavacNode node, JCExpression type, List<JCExpression> typeArgs, JavacNode source) { JavacTreeMaker maker = node.getTreeMaker(); List<JCExpression> clonedAndFixedTypeArgs = createTypeArgs(count, addExtends, node, typeArgs, source); return maker.TypeApply(type, clonedAndFixedTypeArgs); } - protected List<JCExpression> createTypeArgs(int count, boolean addExtends, JavacNode node, List<JCExpression> typeArgs, JCTree source) { + protected List<JCExpression> createTypeArgs(int count, boolean addExtends, JavacNode node, List<JCExpression> typeArgs, JavacNode source) { JavacTreeMaker maker = node.getTreeMaker(); - Context context = node.getContext(); if (count < 0) throw new IllegalArgumentException("count is negative"); if (count == 0) return List.nil(); @@ -435,17 +436,17 @@ public class JavacSingularsRecipes { } catch (Exception e) { inner = genJavaLangTypeRef(node, "Object"); } - arguments.append(cloneType(maker, inner, source, context)); + arguments.append(cloneType(maker, inner, source)); } else { - arguments.append(cloneType(maker, orig, source, context)); + arguments.append(cloneType(maker, orig, source)); } } else { if (orig.getKind() == Kind.UNBOUNDED_WILDCARD || orig.getKind() == Kind.SUPER_WILDCARD) { arguments.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null)); } else if (orig.getKind() == Kind.EXTENDS_WILDCARD) { - arguments.append(cloneType(maker, orig, source, context)); + arguments.append(cloneType(maker, orig, source)); } else { - arguments.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.EXTENDS), cloneType(maker, orig, source, context))); + arguments.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.EXTENDS), cloneType(maker, orig, source))); } } if (--count == 0) break; @@ -468,7 +469,7 @@ public class JavacSingularsRecipes { JCExpression fn = maker.Select(maker.Select(maker.Ident(thisName), name), builderType.toName("size")); JCExpression sizeInvoke = maker.Apply(List.<JCExpression>nil(), fn, List.<JCExpression>nil()); if (nullGuard) { - JCExpression isNull = maker.Binary(CTC_EQUAL, maker.Select(maker.Ident(thisName), name), maker.Literal(CTC_BOT, 0)); + JCExpression isNull = maker.Binary(CTC_EQUAL, maker.Select(maker.Ident(thisName), name), maker.Literal(CTC_BOT, null)); JCExpression out = maker.Conditional(isNull, maker.Literal(CTC_INT, 0), sizeInvoke); if (parens) return maker.Parens(out); return out; @@ -476,7 +477,7 @@ public class JavacSingularsRecipes { return sizeInvoke; } - protected JCExpression cloneParamType(int index, JavacTreeMaker maker, List<JCExpression> typeArgs, JavacNode builderType, JCTree source) { + protected JCExpression cloneParamType(int index, JavacTreeMaker maker, List<JCExpression> typeArgs, JavacNode builderType, JavacNode source) { if (typeArgs == null || typeArgs.size() <= index) { return genJavaLangTypeRef(builderType, "Object"); } else { @@ -485,12 +486,12 @@ public class JavacSingularsRecipes { return genJavaLangTypeRef(builderType, "Object"); } else if (originalType.getKind() == Kind.EXTENDS_WILDCARD) { try { - return cloneType(maker, (JCExpression) ((JCWildcard) originalType).inner, source, builderType.getContext()); + return cloneType(maker, (JCExpression) ((JCWildcard) originalType).inner, source); } catch (Exception e) { return genJavaLangTypeRef(builderType, "Object"); } } else { - return cloneType(maker, originalType, source, builderType.getContext()); + return cloneType(maker, originalType, source); } } } @@ -500,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/JavacGuavaSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java index 7cd676c0..ce5aad5e 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java @@ -39,7 +39,6 @@ import lombok.javac.handlers.JavacSingularsRecipes.SingularData; import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker; import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; @@ -62,7 +61,7 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { return "builder"; } - @Override public java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source) { + @Override public java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JavacNode source) { JavacTreeMaker maker = builderType.getTreeMaker(); String simpleTypeName = getSimpleTargetTypeName(data); JCExpression type = JavacHandlerUtil.chainDots(builderType, "com", "google", "common", "collect", simpleTypeName, "Builder"); @@ -72,7 +71,7 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { return Collections.singletonList(injectFieldAndMarkGenerated(builderType, buildField)); } - @Override public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { + @Override public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JavacNode source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { doGenerateMethods(cfv, data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker, access); } @@ -83,7 +82,7 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { } @Override - protected List<JCVariableDecl> generateSingularMethodParameters(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { + protected List<JCVariableDecl> generateSingularMethodParameters(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source) { Name[] names = generateSingularMethodParameterNames(data, builderType); ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>(); for (int i = 0; i < names.length; i++) { @@ -93,7 +92,7 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { } @Override - protected ListBuffer<JCStatement> generateSingularMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { + protected ListBuffer<JCStatement> generateSingularMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source) { Name[] names = generateSingularMethodParameterNames(data, builderType); JCExpression thisDotFieldDotAdd = chainDots(builderType, "this", data.getPluralName().toString(), getAddMethodName()); @@ -124,7 +123,7 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { return genTypeRef(builderType, getAddAllTypeName()); } - @Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) { + @Override public void appendBuildCode(SingularData data, JavacNode builderType, JavacNode source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) { JavacTreeMaker maker = builderType.getTreeMaker(); List<JCExpression> jceBlank = List.nil(); @@ -151,12 +150,12 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { JCExpression init = maker.Conditional(isNull, empty, invokeBuild); // this.pluralName == null ? ImmutableX.of() : this.pluralName.build() - JCStatement jcs = maker.VarDef(maker.Modifiers(0), data.getPluralName(), varType, init); + JCStatement jcs = maker.VarDef(maker.Modifiers(0L), data.getPluralName(), varType, init); statements.append(jcs); } @Override - protected JCStatement createConstructBuilderVarIfNeeded(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { + protected JCStatement createConstructBuilderVarIfNeeded(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source) { List<JCExpression> jceBlank = List.nil(); JCExpression thisDotField = maker.Select(maker.Ident(builderType.toName("this")), data.getPluralName()); 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/JavacJavaUtilListSetSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java index 634a086d..dfc8c7b0 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java @@ -37,7 +37,6 @@ import lombok.javac.handlers.JavacSingularsRecipes.SingularData; import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker; import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; @@ -58,7 +57,7 @@ abstract class JavacJavaUtilListSetSingularizer extends JavacJavaUtilSingularize return super.listMethodsToBeGenerated(data, builderType); } - @Override public java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source) { + @Override public java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JavacNode source) { JavacTreeMaker maker = builderType.getTreeMaker(); JCExpression type = JavacHandlerUtil.chainDots(builderType, "java", "util", "ArrayList"); type = addTypeArgs(1, false, builderType, type, data.getTypeArgs(), source); @@ -67,7 +66,7 @@ abstract class JavacJavaUtilListSetSingularizer extends JavacJavaUtilSingularize return Collections.singletonList(injectFieldAndMarkGenerated(builderType, buildField)); } - @Override public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { + @Override public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JavacNode source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { doGenerateMethods(cfv, data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker, access); } @@ -84,13 +83,13 @@ abstract class JavacJavaUtilListSetSingularizer extends JavacJavaUtilSingularize } @Override - protected ListBuffer<JCStatement> generateSingularMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { + protected ListBuffer<JCStatement> generateSingularMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source) { return new ListBuffer<JCStatement>() .append(generateSingularMethodAddStatement(maker, builderType, data.getSingularName(), data.getPluralName().toString())); } @Override - protected List<JCVariableDecl> generateSingularMethodParameters(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { + protected List<JCVariableDecl> generateSingularMethodParameters(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source) { JCVariableDecl param = generateSingularMethodParameter(0, maker, data, builderType, source, data.getSingularName()); return List.of(param); } @@ -101,7 +100,7 @@ abstract class JavacJavaUtilListSetSingularizer extends JavacJavaUtilSingularize } @Override - protected JCStatement createConstructBuilderVarIfNeeded(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { + protected JCStatement createConstructBuilderVarIfNeeded(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source) { return createConstructBuilderVarIfNeeded(maker, data, builderType, false, source); } diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java index b4ad3428..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,15 +24,13 @@ 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; import com.sun.tools.javac.tree.JCTree.JCCase; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCStatement; @@ -40,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"); @@ -50,7 +48,7 @@ public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingulari return "java.util.Collections.emptyList"; } - @Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) { + @Override public void appendBuildCode(SingularData data, JavacNode builderType, JavacNode source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) { JavacTreeMaker maker = builderType.getTreeMaker(); List<JCExpression> jceBlank = List.nil(); ListBuffer<JCCase> cases = new ListBuffer<JCCase>(); @@ -89,12 +87,12 @@ public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingulari JCStatement switchStat = maker.Switch(getSize(maker, builderType, data.getPluralName(), true, false, builderVariable), cases.toList()); JCExpression localShadowerType = chainDotsString(builderType, data.getTargetFqn()); localShadowerType = addTypeArgs(1, false, builderType, localShadowerType, data.getTypeArgs(), source); - JCStatement varDefStat = maker.VarDef(maker.Modifiers(0), data.getPluralName(), localShadowerType, null); + JCStatement varDefStat = maker.VarDef(maker.Modifiers(0L), data.getPluralName(), localShadowerType, null); statements.append(varDefStat); statements.append(switchStat); } - private List<JCStatement> createListCopy(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source, String builderVariable) { + private List<JCStatement> createListCopy(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source, String builderVariable) { List<JCExpression> jceBlank = List.nil(); Name thisName = builderType.toName(builderVariable); diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java index 8dc7ecff..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,11 +36,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 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.JCBlock; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCStatement; @@ -49,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"); @@ -74,7 +72,7 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer { return super.listMethodsToBeGenerated(data, builderType); } - @Override public java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source) { + @Override public java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JavacNode source) { JavacTreeMaker maker = builderType.getTreeMaker(); JCVariableDecl buildKeyField; { @@ -98,7 +96,7 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer { return Arrays.asList(keyFieldNode, valueFieldNode); } - @Override public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { + @Override public void generateMethods(CheckerFrameworkVersion cfv, SingularData data, boolean deprecate, JavacNode builderType, JavacNode source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker, AccessLevel access) { doGenerateMethods(cfv, data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker, access); } @@ -117,7 +115,7 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer { } @Override - protected ListBuffer<JCStatement> generateSingularMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { + protected ListBuffer<JCStatement> generateSingularMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source) { Name keyName = builderType.toName(data.getSingularName().toString() + "Key"); Name valueName = builderType.toName(data.getSingularName().toString() + "Value"); @@ -130,7 +128,7 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer { } @Override - protected List<JCVariableDecl> generateSingularMethodParameters(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { + protected List<JCVariableDecl> generateSingularMethodParameters(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source) { Name keyName = builderType.toName(data.getSingularName().toString() + "Key"); Name valueName = builderType.toName(data.getSingularName().toString() + "Value"); JCVariableDecl paramKey = generateSingularMethodParameter(0, maker, data, builderType, source, keyName); @@ -139,7 +137,7 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer { } @Override - protected ListBuffer<JCStatement> generatePluralMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { + protected ListBuffer<JCStatement> generatePluralMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source) { List<JCExpression> jceBlank = List.nil(); ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); long baseFlags = JavacHandlerUtil.addFinalIfNeeded(0, builderType.getContext()); @@ -164,11 +162,11 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer { } @Override - protected JCStatement createConstructBuilderVarIfNeeded(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) { + protected JCStatement createConstructBuilderVarIfNeeded(JavacTreeMaker maker, SingularData data, JavacNode builderType, JavacNode source) { return createConstructBuilderVarIfNeeded(maker, data, builderType, true, source); } - @Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) { + @Override public void appendBuildCode(SingularData data, JavacNode builderType, JavacNode source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) { JavacTreeMaker maker = builderType.getTreeMaker(); if (data.getTargetFqn().equals("java.util.Map")) { diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSetSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSetSingularizer.java index 7c870c0a..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,20 +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; 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"); @@ -46,7 +44,7 @@ public class JavacJavaUtilSetSingularizer extends JavacJavaUtilListSetSingulariz return "java.util.Collections.emptySet"; } - @Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) { + @Override public void appendBuildCode(SingularData data, JavacNode builderType, JavacNode source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) { JavacTreeMaker maker = builderType.getTreeMaker(); if (data.getTargetFqn().equals("java.util.Set")) { diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java index 50950915..3b6113df 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java @@ -24,7 +24,6 @@ package lombok.javac.handlers.singulars; import static lombok.javac.Javac.*; import static lombok.javac.handlers.JavacHandlerUtil.*; -import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCCase; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCStatement; @@ -38,7 +37,7 @@ import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; import lombok.javac.handlers.JavacSingularsRecipes.SingularData; abstract class JavacJavaUtilSingularizer extends JavacSingularizer { - protected List<JCStatement> createJavaUtilSetMapInitialCapacitySwitchStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType, JCTree source, String builderVariable) { + protected List<JCStatement> createJavaUtilSetMapInitialCapacitySwitchStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType, JavacNode source, String builderVariable) { List<JCExpression> jceBlank = List.nil(); ListBuffer<JCCase> cases = new ListBuffer<JCCase>(); @@ -84,13 +83,13 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer { JCStatement switchStat = maker.Switch(getSize(maker, builderType, mapMode ? builderType.toName(data.getPluralName() + "$key") : data.getPluralName(), true, false, builderVariable), cases.toList()); JCExpression localShadowerType = chainDotsString(builderType, data.getTargetFqn()); localShadowerType = addTypeArgs(mapMode ? 2 : 1, false, builderType, localShadowerType, data.getTypeArgs(), source); - JCStatement varDefStat = maker.VarDef(maker.Modifiers(0), data.getPluralName(), localShadowerType, null); + JCStatement varDefStat = maker.VarDef(maker.Modifiers(0L), data.getPluralName(), localShadowerType, null); return List.of(varDefStat, switchStat); } - protected JCStatement createConstructBuilderVarIfNeeded(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, JCTree source) { + 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); @@ -117,7 +116,7 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer { return maker.If(cond, thenPart, null); } - protected List<JCStatement> createJavaUtilSimpleCreationAndFillStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType, JCTree source, String builderVariable) { + protected List<JCStatement> createJavaUtilSimpleCreationAndFillStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType, JavacNode source, String builderVariable) { List<JCExpression> jceBlank = List.nil(); Name thisName = builderType.toName(builderVariable); @@ -143,7 +142,7 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer { if (defineVar) { JCExpression localShadowerType = chainDotsString(builderType, data.getTargetFqn()); localShadowerType = addTypeArgs(mapMode ? 2 : 1, false, builderType, localShadowerType, data.getTypeArgs(), source); - createStat = maker.VarDef(maker.Modifiers(0), data.getPluralName(), localShadowerType, constructorCall); + createStat = maker.VarDef(maker.Modifiers(0L), data.getPluralName(), localShadowerType, constructorCall); } else { createStat = maker.Exec(maker.Assign(maker.Ident(data.getPluralName()), constructorCall)); } @@ -161,7 +160,7 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer { // error: method put in interface Map<K#2,V#2> cannot be applied to given types; arg2 = maker.TypeCast(createTypeArgs(2, false, builderType, data.getTypeArgs(), source).get(1), arg2); JCStatement putStatement = maker.Exec(maker.Apply(jceBlank, pluralnameDotPut, List.of(arg1, arg2))); - JCStatement forInit = maker.VarDef(maker.Modifiers(0), ivar, maker.TypeIdent(CTC_INT), maker.Literal(CTC_INT, 0)); + JCStatement forInit = maker.VarDef(maker.Modifiers(0L), ivar, maker.TypeIdent(CTC_INT), maker.Literal(CTC_INT, 0)); JCExpression checkExpr = maker.Binary(CTC_LESS_THAN, maker.Ident(ivar), getSize(maker, builderType, keyVarName, nullGuard, true, builderVariable)); JCExpression incrementExpr = maker.Unary(CTC_POSTINC, maker.Ident(ivar)); fillStat = maker.ForLoop(List.of(forInit), checkExpr, List.of(maker.Exec(incrementExpr)), putStatement); |