diff options
94 files changed, 2932 insertions, 1278 deletions
@@ -2,6 +2,7 @@ Lombok contributors in alphabetical order: Adam Juraszek <juriad@gmail.com> Aleksandr Zhelezniak <lekan1992@gmail.com> +Andre Brait <andrebrait@gmail.com> Bulgakov Alexander <buls@yandex.ru> Caleb Brinkman <floralvikings@gmail.com> Christian Nüssgens <christian@nuessgens.com> @@ -23,6 +24,7 @@ Maarten Mulders <mthmulders@users.noreply.github.com> Mark Haynes <markhaynes.work@gmail.com> Mart Hagenaars <marthagenaars@gmail.com> Mateusz Matela <mateusz.matela@gmail.com> +Michael Ernst <mernst@alum.mit.edu> Michiel Verheul <cheelio@gmail.com> Pascal Bihler <pascal@qfs.de> Peter Grant <petercgrant@users.noreply.github.com> diff --git a/buildScripts/create-eclipse-project.ant.xml b/buildScripts/create-eclipse-project.ant.xml index da91964f..383ebd8b 100644 --- a/buildScripts/create-eclipse-project.ant.xml +++ b/buildScripts/create-eclipse-project.ant.xml @@ -96,7 +96,7 @@ This buildfile is part of projectlombok.org. It creates the infrastructure neede <path refid="cp.buildtools" /> <pathelement location="build/support" /> </classpath> - <arg value="name=Lombok-test Javac14" /> + <arg value="name=Lombok-test Javac 14" /> <arg value="testType=lombok.TestJavac" /> <arg value="jvmTarget=14" /> <arg value="conf.test=${cp.test}" /> diff --git a/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.38.xml b/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.38.xml new file mode 100644 index 00000000..1ca9c743 --- /dev/null +++ b/buildScripts/ivy-repo/org.projectlombok-lombok.patcher-0.38.xml @@ -0,0 +1,14 @@ +<ivy-module version="2.0"> + <info organisation="org.projectlombok" module="lombok.patcher" revision="0.38" publication="20201008193000"> + <license name="MIT License" url="https://www.opensource.org/licenses/mit-license.php" /> + <ivyauthor name="rzwitserloot" url="https://github.com/rzwitserloot" /> + <ivyauthor name="rspilker" url="https://github.com/rspilker" /> + <description homepage="https://projectlombok.org/" /> + </info> + <configurations> + <conf name="default" /> + </configurations> + <publications> + <artifact conf="default" url="https://projectlombok.org/downloads/lombok.patcher-0.38.jar" /> + </publications> +</ivy-module> diff --git a/buildScripts/ivy.xml b/buildScripts/ivy.xml index 3dfbde7e..8383d00a 100644 --- a/buildScripts/ivy.xml +++ b/buildScripts/ivy.xml @@ -10,7 +10,7 @@ <!-- test: base dependencies required to run the tests. Does not include javac or ecj. --> <conf name="test" /> - <!-- stripe: dependencies that need to be on the classpath during builds --> + <!-- build: dependencies that need to be on the classpath during builds --> <conf name="build" /> <!-- stripe: dependencies that need to be striped into lombok.jar itself, and are required for both build and test/run purposes --> @@ -36,7 +36,7 @@ </configurations> <dependencies> - <dependency org="org.projectlombok" name="lombok.patcher" rev="0.36" conf="build,stripe->default" /> + <dependency org="org.projectlombok" name="lombok.patcher" rev="0.38" conf="build,stripe->default" /> <dependency org="zwitserloot.com" name="cmdreader" rev="1.2" conf="build,stripe->runtime" /> <dependency org="projectlombok.org" name="spi" rev="0.2.7" conf="build" /> <dependency org="org.apache.ant" name="ant" rev="1.10.5" conf="build->default" /> @@ -85,7 +85,10 @@ <dependency org="org.eclipse.jdt" name="org.eclipse.jdt.core" rev="3.13.102" conf="eclipse-oxygen->default" transitive="false" /> <dependency org="org.eclipse.jdt" name="org.eclipse.jdt.ui" rev="3.13.100" conf="eclipse-oxygen->default" transitive="false" /> <dependency org="org.eclipse.platform" name="org.eclipse.equinox.common" rev="3.9.0" conf="eclipse-oxygen->default" transitive="false" /> + <dependency org="org.eclipse.platform" name="org.eclipse.equinox.registry" rev="3.7.0" conf="eclipse-oxygen->default" transitive="false" /> + <dependency org="org.eclipse.platform" name="org.eclipse.equinox.app" rev="1.3.400" conf="eclipse-oxygen->default" transitive="false" /> <dependency org="org.eclipse.platform" name="org.eclipse.core.resources" rev="3.12.0" conf="eclipse-oxygen->default" transitive="false" /> + <dependency org="org.eclipse.platform" name="org.eclipse.core.contenttype" rev="3.6.0" conf="eclipse-oxygen->default" transitive="false" /> <dependency org="org.eclipse.platform" name="org.eclipse.core.jobs" rev="3.9.0" conf="eclipse-oxygen->default" transitive="false" /> <dependency org="org.eclipse.platform" name="org.eclipse.osgi" rev="3.12.100" conf="eclipse-oxygen->default" transitive="false" /> <dependency org="org.eclipse.platform" name="org.eclipse.text" rev="3.6.100" conf="eclipse-oxygen->default" transitive="false" /> @@ -95,7 +98,10 @@ <dependency org="org.eclipse.jdt" name="org.eclipse.jdt.ui" rev="3.21.100" conf="eclipse-202006->default" transitive="false" /> <dependency org="org.eclipse.platform" name="org.eclipse.equinox.common" rev="3.12.0" conf="eclipse-202006->default" transitive="false" /> <dependency org="org.eclipse.platform" name="org.eclipse.equinox.preferences" rev="3.8.0" conf="eclipse-202006->default" transitive="false" /> + <dependency org="org.eclipse.platform" name="org.eclipse.equinox.registry" rev="3.8.700" conf="eclipse-202006->default" transitive="false" /> + <dependency org="org.eclipse.platform" name="org.eclipse.equinox.app" rev="1.4.400" conf="eclipse-202006->default" transitive="false" /> <dependency org="org.eclipse.platform" name="org.eclipse.core.resources" rev="3.13.700" conf="eclipse-202006->default" transitive="false" /> + <dependency org="org.eclipse.platform" name="org.eclipse.core.contenttype" rev="3.7.600" conf="eclipse-202006->default" transitive="false" /> <dependency org="org.eclipse.platform" name="org.eclipse.core.jobs" rev="3.10.800" conf="eclipse-202006->default" transitive="false" /> <dependency org="org.eclipse.platform" name="org.eclipse.osgi" rev="3.15.300" conf="eclipse-202006->default" transitive="false" /> <dependency org="org.eclipse.platform" name="org.eclipse.text" rev="3.10.200" conf="eclipse-202006->default" transitive="false" /> 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/core/AnnotationProcessor.java b/src/core/lombok/core/AnnotationProcessor.java index d4a92408..c72d1bb2 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; @@ -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; + } + } + + /** + * InteliJ >= 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; 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/eclipse/EclipseAugments.java b/src/core/lombok/eclipse/EcjAugments.java index 783e25c9..965c4fb6 100644 --- a/src/core/lombok/eclipse/EclipseAugments.java +++ b/src/core/lombok/eclipse/EcjAugments.java @@ -33,8 +33,8 @@ 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 } @@ -42,6 +42,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<CompilationUnit, Map<String, String>> CompilationUnit_javadoc = FieldAugment.augment(CompilationUnit.class, Map.class, "$javadoc"); - public static final FieldAugment<CompilationUnit, ConcurrentMap<String, List<SourceMethod>>> CompilationUnit_delegateMethods = FieldAugment.augment(CompilationUnit.class, ConcurrentMap.class, "$delegateMethods"); + + public static final class EclipseAugments { + private EclipseAugments() { + // Prevent instantiation + } + + public static final FieldAugment<CompilationUnit, Map<String, String>> CompilationUnit_javadoc = FieldAugment.augment(CompilationUnit.class, Map.class, "$javadoc"); + 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/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 d85c2ee8..03f26341 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -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; @@ -2649,22 +2649,42 @@ public class EclipseHandlerUtil { return null; } + private static class EclipseOnlyUtil { + public static void setDocComment(CompilationUnitDeclaration cud, TypeDeclaration type, ASTNode node, String doc) { + if (cud.compilationResult.compilationUnit instanceof CompilationUnit) { + CompilationUnit compilationUnit = (CompilationUnit) cud.compilationResult.compilationUnit; + Map<String, String> docs = EclipseAugments.CompilationUnit_javadoc.setIfAbsent(compilationUnit, new HashMap<String, String>()); + + if (node instanceof AbstractMethodDeclaration) { + AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) node; + String signature = getSignature(type, methodDeclaration); + /* Add javadoc start marker, add leading asterisks to each line, add javadoc end marker */ + docs.put(signature, String.format("/**%n%s%n */", doc.replaceAll("(?m)^", " * "))); + } + } + } + } + + private static Boolean eclipseMode; + private static boolean eclipseMode() { + if (eclipseMode != null) return eclipseMode.booleanValue(); + try { + Class.forName("org.eclipse.jdt.internal.core.CompilationUnit"); + eclipseMode = true; + } catch (Exception e) { + eclipseMode = false; + } + return eclipseMode; + } + public static void setDocComment(CompilationUnitDeclaration cud, EclipseNode eclipseNode, String doc) { + if (!eclipseMode()) return; setDocComment(cud, (TypeDeclaration) upToTypeNode(eclipseNode).get(), eclipseNode.get(), doc); } - + public static void setDocComment(CompilationUnitDeclaration cud, TypeDeclaration type, ASTNode node, String doc) { - if (cud.compilationResult.compilationUnit instanceof CompilationUnit) { - CompilationUnit compilationUnit = (CompilationUnit) cud.compilationResult.compilationUnit; - Map<String, String> docs = CompilationUnit_javadoc.setIfAbsent(compilationUnit, new HashMap<String, String>()); - - if (node instanceof AbstractMethodDeclaration) { - AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) node; - String signature = getSignature(type, methodDeclaration); - /* Add javadoc start marker, add leading asterisks to each line, add javadoc end marker */ - docs.put(signature, String.format("/**%n%s%n */", doc.replaceAll("(?m)^", " * "))); - } - } + if (!eclipseMode()) return; + EclipseOnlyUtil.setDocComment(cud, type, node, doc); } public static String getSignature(TypeDeclaration type, AbstractMethodDeclaration methodDeclaration) { diff --git a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java index 85243ec1..760f5282 100755 --- a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java +++ b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java @@ -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); } /** diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 9e6c28e8..f8eb9ed0 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -25,7 +25,6 @@ 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; @@ -107,8 +106,16 @@ import lombok.experimental.NonFinal; 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; @@ -117,6 +124,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; @@ -151,10 +247,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); @@ -164,87 +256,57 @@ 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); + BuilderJob job = new BuilderJob(); + job.sourceNode = annotationNode; + job.source = ast; + job.checkerFramework = getCheckerFrameworkVersion(annotationNode); + job.isStatic = true; - long p = (long) ast.sourceStart << 32 | ast.sourceEnd; - - 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); - - 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(); + 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) { @@ -269,22 +331,22 @@ 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); } - handleConstructor.generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER, + 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) { @@ -292,21 +354,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) { @@ -332,12 +393,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) { @@ -376,15 +437,15 @@ 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."); @@ -404,40 +465,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; @@ -456,64 +516,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++) { @@ -521,9 +581,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) { @@ -532,7 +592,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } } } - + static char[] returnTypeToBuilderClassName(EclipseNode annotationNode, MethodDeclaration md, TypeParameter[] typeParams) { char[] token; if (md.returnType instanceof QualifiedTypeReference) { @@ -562,26 +622,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(); @@ -599,13 +664,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); } @@ -618,7 +683,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); @@ -647,7 +712,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); @@ -657,69 +722,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>(); @@ -732,14 +809,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); @@ -749,11 +826,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); @@ -777,8 +854,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; @@ -791,13 +868,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); @@ -806,12 +883,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; } @@ -842,57 +919,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) { @@ -906,45 +981,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++) { @@ -954,27 +1027,18 @@ 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); - } - if (sourceNode.up().getKind() == Kind.METHOD) { - copyJavadocFromParam(originalFieldNode.up(), setter, td, paramName.toString()); + 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(originalFieldNode, setter, td, CopyJavadoc.SETTER, true); + 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) { @@ -991,17 +1055,17 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } } 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/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index 06c9ecd9..3233a8c6 100755 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -461,14 +461,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); @@ -536,6 +534,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); @@ -556,9 +559,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/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index 7147343e..deb19c00 100755 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -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; @@ -59,6 +60,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; @@ -94,6 +97,9 @@ import org.mangosdk.spi.ProviderFor; @ProviderFor(EclipseAnnotationHandler.class) 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,11 +138,11 @@ 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) { + Boolean callSuper, boolean whineIfExists, boolean cacheHashCode, FieldAccess fieldAccess, List<Annotation> onParam) { TypeDeclaration typeDecl = null; @@ -222,12 +230,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; @@ -238,7 +267,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 }; @@ -262,6 +294,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) { @@ -296,7 +344,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); } @@ -391,6 +439,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/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 79b7e816..8fdfd315 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -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.*; @@ -57,13 +58,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; @@ -99,75 +97,100 @@ 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; @ProviderFor(EclipseAnnotationHandler.class) @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 (!(tdParent.get() instanceof TypeDeclaration)) { + List<EclipseNode> nonFinalNonDefaultedFields = null; + + if (!(parent.get() instanceof TypeDeclaration)) { annotationNode.addError("@SuperBuilder is only supported on types."); 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 +203,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 +228,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 +244,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 +294,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 +305,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 +361,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 +415,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 +443,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 +465,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) { - - ASTNode source = sourceNode.get(); + private void generateBuilderBasedConstructor(BuilderJob job, boolean callBuilderBasedSuperConstructor) { + TypeDeclaration typeDeclaration = ((TypeDeclaration) job.parentType.get()); + long p = job.getPos(); - 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 +548,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 +570,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 +586,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 +600,44 @@ 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]); - 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 (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 +649,33 @@ 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 (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 +685,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 +714,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,41 +742,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(source), (ClassScope) null); + out.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); return out; } @@ -783,14 +817,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}; @@ -802,54 +836,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}; @@ -859,43 +891,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) { @@ -909,23 +942,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() { @@ -944,15 +977,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; @@ -966,23 +998,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) { 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/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index 852e5de6..67df5b20 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -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; @@ -432,11 +434,12 @@ public class LombokProcessor extends AbstractProcessor { // 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, @@ -454,11 +457,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 +470,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; + } + } + + /** + * InteliJ >= 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/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 7e87ce11..1c74ce37 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -55,6 +55,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; @@ -88,12 +89,96 @@ import lombok.javac.handlers.JavacSingularsRecipes.SingularData; 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; + JCTree source; + 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; @@ -112,73 +197,49 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { @Override public void handle(AnnotationValues<Builder> annotation, JCAnnotation ast, JavacNode annotationNode) { 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(); + BuilderJob job = new BuilderJob(); + job.sourceNode = annotationNode; + job.source = ast; + job.checkerFramework = getCheckerFrameworkVersion(annotationNode); + job.isStatic = true; + + Builder annInstance = annotation.getInstance(); + job.init(annotation, annInstance, annotationNode); java.util.List<Name> 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; - // 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(); + 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 +250,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,26 +272,26 @@ 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); + if (md != null) injectMethod(parent, md); } addObtainVia(bfd, fieldNode); - builderFields.add(bfd); + job.builderFields.add(bfd); allFields.append(fieldNode); } - handleConstructor.generateConstructor(tdParent, AccessLevel.PACKAGE, List.<JCAnnotation>nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, annotationNode); + 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()) { @@ -238,38 +299,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, ast, annotationNode.getContext()); } - 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; } @@ -282,8 +340,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; @@ -307,13 +365,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.builderType.get()).typarams; typeArgsForToBuilder = new ArrayList<Name>(); for (JCTypeParameter tp : tpOnMethod) { @@ -349,41 +407,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(), ast, annotationNode.getContext()); } 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; @@ -402,75 +460,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); + 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, ast, annotationNode.getContext()); } - 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); + injectMethod(job.builderType, md); recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); } } } - 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, ast); + 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); + JCMethodDecl md = generateBuilderMethod(job); recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); - if (md != null) injectMethod(tdParent, md); + 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); + injectMethod(job.parentType, md); } } } @@ -551,47 +609,45 @@ 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) { + for (JCTypeParameter typeParam : typeParameters) { 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.source, job.getContext()); if (preStatements == null) preStatements = new ListBuffer<JCStatement>(); preStatements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), bfd.name, varType, inv)); } @@ -602,15 +658,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)); } @@ -620,77 +676,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.source, 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.source, job.getContext()); 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.source, 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.source, job.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) 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)); @@ -700,20 +757,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)); @@ -724,10 +781,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; } @@ -743,52 +805,54 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { 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); } - 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); + + JavacTreeMaker maker = job.getTreeMaker(); ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); - for (JCTypeParameter typeParam : typeParams) { + for (JCTypeParameter typeParam : job.typeParams) { typeArgs.append(maker.Ident(typeParam.name)); } 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)); + bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, job.builderType, job.source)); } else { JavacNode field = null, setFlag = null; for (JavacNode exists : existing) { @@ -796,40 +860,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.source, job.getContext()), 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.source, job.getContext()); } - 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; @@ -838,23 +903,24 @@ 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.source, job.getContext()); + 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) { @@ -871,14 +937,16 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } } 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()); + return injectType(job.parentType, builder); } private void addObtainVia(BuilderFieldData bfd, JavacNode node) { diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index 2a683767..f30320dc 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -377,7 +377,6 @@ 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()); @@ -456,7 +455,6 @@ public class HandleConstructor { 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; @@ -469,7 +467,9 @@ 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) { diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index d490738e..c65fa491 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -42,6 +42,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 +58,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; @@ -76,11 +79,13 @@ import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; 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(); @@ -92,8 +97,10 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS); boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration; FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER; - - 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 +114,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) { boolean notAClass = true; if (typeNode.get() instanceof JCClassDecl) { @@ -196,17 +203,39 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas 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.get()); + } + } + + JCMethodDecl hashCodeMethod = createHashCode(typeNode, members, callSuper, cacheHashCode, fieldAccess, source.get()); injectMethod(typeNode, hashCodeMethod); } + + private void createHashCodeCacheField(JavacNode typeNode, JCTree 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, typeNode.getContext()); + } - 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, JCTree 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>(); @@ -217,6 +246,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()))); @@ -234,7 +272,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) { @@ -306,6 +344,20 @@ 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))); } diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index 110941d6..afe2c1b6 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -380,7 +380,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) { */ { diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index 82c95719..5c4c7681 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -226,7 +226,30 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { 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.get(), field.getContext()); + 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(); @@ -277,8 +300,14 @@ 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()); copyJavadoc(field, decl, CopyJavadoc.SETTER, returnStatement != null); diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index f6bf9e1f..99f0ea6a 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -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.*; @@ -78,6 +79,7 @@ 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; @@ -88,58 +90,91 @@ import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker; @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.source = ast; + 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 (!(tdParent.get() instanceof JCClassDecl)) { + if (!(parent.get() instanceof JCClassDecl)) { annotationNode.addError("@SuperBuilder is only supported on types."); return; } // Gather all fields of the class that should be set by the builder. - JCClassDecl td = (JCClassDecl) tdParent.get(); + job.parentType = parent; + JCClassDecl td = (JCClassDecl) parent.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 +184,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 +204,21 @@ 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); + if (md != null) injectMethod(parent, md); } addObtainVia(bfd, fieldNode); - builderFields.add(bfd); + job.builderFields.add(bfd); allFields.append(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("*", 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 +226,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.getContext()); + typeParamsForBuilder.add(maker.Ident(parent.toName(classGenericName))); + typeParamsForBuilder.add(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 +284,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(), ast, annotationNode.getContext()); } 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.builderType, 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, ast); if (addCleaning) { - JavacTreeMaker maker = builderType.getTreeMaker(); - JCVariableDecl uncleanField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), builderType.toName("$lombokUnclean"), maker.TypeIdent(CTC_BOOLEAN), null); + JCVariableDecl uncleanField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), job.toName("$lombokUnclean"), maker.TypeIdent(CTC_BOOLEAN), null); recursiveSetGeneratedBy(uncleanField, ast, annotationNode.getContext()); - injectFieldAndMarkGenerated(builderType, uncleanField); + 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); + JCMethodDecl fvm = generateFillValuesMethod(job, superclassBuilderClass != null, builderGenericName, classGenericName); recursiveSetGeneratedBy(fvm, ast, annotationNode.getContext()); - injectMethod(builderType, fvm); + injectMethod(job.builderType, fvm); // Generate $fillValuesFromInstanceIntoBuilder() method in the builder implementation class. - JCMethodDecl sfvm = generateStaticFillValuesMethod(tdParent, builderClassName, typeParams, builderFields, superbuilderAnnotation.setterPrefix()); + JCMethodDecl sfvm = generateStaticFillValuesMethod(job, annInstance.setterPrefix()); recursiveSetGeneratedBy(sfvm, ast, annotationNode.getContext()); - injectMethod(builderType, sfvm); + injectMethod(job.builderType, sfvm); } // Generate abstract self() and build() methods in the abstract builder. - JCMethodDecl asm = generateAbstractSelfMethod(cfv, tdParent, superclassBuilderClassExpression != null, builderGenericName); + JCMethodDecl asm = generateAbstractSelfMethod(job, superclassBuilderClass != null, builderGenericName); recursiveSetGeneratedBy(asm, ast, annotationNode.getContext()); - injectMethod(builderType, asm); - JCMethodDecl abm = generateAbstractBuildMethod(cfv, tdParent, buildMethodName, builderFields, superclassBuilderClassExpression != null, classGenericName); + injectMethod(job.builderType, asm); + JCMethodDecl abm = generateAbstractBuildMethod(job, superclassBuilderClass != null, classGenericName); recursiveSetGeneratedBy(abm, ast, annotationNode.getContext()); - injectMethod(builderType, abm); + 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, ast); + if (toStringMethod != null) injectMethod(job.builderType, toStringMethod); // If clean methods are requested, add them now. if (addCleaning) { - JCMethodDecl md = generateCleanMethod(builderFields, builderType, ast); + JCMethodDecl md = generateCleanMethod(job.builderFields, job.builderType, ast); recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); - injectMethod(builderType, md); + injectMethod(job.builderType, md); } boolean isAbstract = (td.mods.flags & Flags.ABSTRACT) != 0; @@ -324,69 +370,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(), ast, annotationNode.getContext()); } 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); + JCMethodDecl selfMethod = generateSelfMethod(job); 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); + injectMethod(job.builderType, selfMethod); + if (methodExists(job.buildMethodName, job.builderType, -1) == MemberExistsResult.NOT_EXISTS) { + JCMethodDecl buildMethod = generateBuildMethod(job, buildMethodThrownExceptions); recursiveSetGeneratedBy(buildMethod, ast, annotationNode.getContext()); - injectMethod(builderImplType, buildMethod); + 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, ast, annotationNode.getContext()); + 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, ast, annotationNode.getContext()); + injectMethod(job.parentType, md); + } + break; + default: + // Should not happen. } - break; - default: - // Should not happen. } } @@ -400,95 +448,86 @@ 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.addAll(copyTypeParams(job.sourceNode, job.typeParams)); // Add builder-specific type params required for inheritable builders. // 1. The return type for the build() method, named "C", 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.add(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.getContext()); + typeParamsForBuilder.add(maker.Ident(job.toName(classGenericName))); + typeParamsForBuilder.add(maker.Ident(job.toName(builderGenericName))); + JCTypeApply typeApply = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, job.parentType, builderClassName, false, List.<JCTypeParameter>nil()), typeParamsForBuilder.toList()); + allTypeParams.add(maker.TypeParameter(job.toName(builderGenericName), List.<JCExpression>of(typeApply))); 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.getContext()); // 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.add(maker.Ident(job.toName(classGenericName))); + typeParamsForBuilder.add(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); + 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()); + JCExpression extending = namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderAbstractClassName), false, List.<JCTypeParameter>nil()); // Add any type params of the annotated class. ListBuffer<JCTypeParameter> allTypeParams = new ListBuffer<JCTypeParameter>(); - allTypeParams.addAll(copyTypeParams(source, typeParams)); + allTypeParams.addAll(copyTypeParams(job.sourceNode, job.typeParams)); // Add builder-specific type params required for inheritable builders. // 1. The return type for the build() method (named "C" in the abstract builder), which is the annotated class. - JCExpression annotatedClass = namePlusTypeParamsToTypeReference(maker, 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()); + ListBuffer<JCExpression> typeParamsForBuilder = getTypeParamExpressions(job.typeParams, maker, job.getContext()); typeParamsForBuilder.add(annotatedClass); typeParamsForBuilder.add(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()); + 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"); @@ -496,67 +535,66 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { } 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.generateUnique() ? 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.getContext()); // Now add the <?, ?>. JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); typeParamsForBuilderParameter.add(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()); + 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.source, job.getContext()); - 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(); + private JCMethodDecl generateBuilderMethod(SuperBuilderJob job) { + JavacTreeMaker maker = job.getTreeMaker(); ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); - for (JCTypeParameter typeParam : typeParams) typeArgs.append(maker.Ident(typeParam.name)); + for (JCTypeParameter typeParam : job.typeParams) typeArgs.append(maker.Ident(typeParam.name)); - 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 +603,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.addAll(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()); + 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(builderMethodName), returnType, copyTypeParams(source, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); - createRelevantNonNullAnnotation(type, methodDef); + List<JCAnnotation> annsOnMethod = job.checkerFramework.generateUnique() ? 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 +624,15 @@ 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)); + for (JCTypeParameter typeParam : job.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 +640,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.addAll(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()); + 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.generateUnique() ? 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 +659,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,40 +712,39 @@ 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.getContext()); // Now add the <?, ?>. JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); typeParamsForBuilderParameter.add(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); - + 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.parentType, maker, 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) { @@ -747,80 +784,91 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { 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; } @@ -878,29 +926,30 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { for (JCVariableDecl gen : generated) recursiveSetGeneratedBy(gen, source, builderType.getContext()); } - 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.source, 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 +959,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.source, job.getContext()); newMethod.mods.annotations = annotations.prepend(anno); } - injectMethod(builderType, newMethod); + injectMethod(job.builderType, newMethod); } private void addObtainVia(BuilderFieldData bfd, JavacNode node) { diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 2379d0a0..5ff29758 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -144,12 +144,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); } @@ -1026,7 +1026,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); } @@ -1076,6 +1076,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; @@ -1120,17 +1131,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 +1211,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; @@ -1216,11 +1228,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()); 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>(); @@ -1250,12 +1262,12 @@ 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); } - + private static void fixMethodMirror(Context context, Element typeMirror, long access, Name methodName, List<Type> paramTypes, List<Symbol.VarSymbol> params, Type returnType) { if (typeMirror == null || paramTypes == null || returnType == null) return; ClassSymbol cs = (ClassSymbol) typeMirror; @@ -1428,6 +1440,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,20 +1844,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; } @@ -2078,6 +2101,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. * diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index 7cd52c8c..2fc9329c 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -57,6 +57,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 { @@ -243,20 +244,22 @@ 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, JCTree 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.source, job.oldFluent, returnTypeMaker, returnStatementMaker, job.accessInners); } /** diff --git a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java index 7cd676c0..dadf881d 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java @@ -151,7 +151,7 @@ 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); } diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java index b4ad3428..1f8bbbe9 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java @@ -89,7 +89,7 @@ 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); } diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java index 50950915..5670b5e6 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java @@ -84,7 +84,7 @@ 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); } @@ -143,7 +143,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 +161,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); diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index a1fd0e56..6c15068a 100755 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -701,8 +701,12 @@ public class Delombok { if (!disablePreview && Javac.getJavaCompilerVersion() >= 11) argsList.add("--enable-preview"); - String[] argv = argsList.toArray(new String[0]); - args.init("javac", argv); + if (Javac.getJavaCompilerVersion() < 15) { + String[] argv = argsList.toArray(new String[0]); + args.init("javac", argv); + } else { + args.init("javac", argsList); + } options.put("diags.legacy", "TRUE"); options.put("allowStringFolding", "FALSE"); } else { diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 3412000e..75263bdd 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -50,8 +50,7 @@ import lombok.patcher.scripts.ScriptBuilder; */ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { // At some point I'd like the agent to be capable of auto-detecting if its on eclipse or on ecj. This class is a sure sign we're not in ecj but in eclipse. -ReinierZ - @SuppressWarnings("unused") - private static final String ECLIPSE_SIGNATURE_CLASS = "org/eclipse/core/runtime/adaptor/EclipseStarter"; + private static final String ECLIPSE_SIGNATURE_CLASS = "org.eclipse.core.runtime.adaptor.EclipseStarter"; @Override public void runAgent(String agentArgs, Instrumentation instrumentation, boolean injected, Class<?> launchingContext) throws Exception { String[] args = agentArgs == null ? new String[0] : agentArgs.split(":"); @@ -73,6 +72,12 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { else if (forceEclipse) ecj = false; else ecj = injected; + if (!ecj) try { + Class.forName(ECLIPSE_SIGNATURE_CLASS); + } catch (ClassNotFoundException e) { + ecj = true; + } + registerPatchScripts(instrumentation, injected, ecj, launchingContext); } @@ -117,6 +122,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { patchExtractInterface(sm); patchAboutDialog(sm); patchEclipseDebugPatches(sm); + patchJavadoc(sm); } else { patchPostCompileHookEcj(sm); } @@ -127,7 +133,6 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { patchExtensionMethod(sm, ecjOnly); patchRenameField(sm); patchNullCheck(sm); - patchJavadoc(sm); if (reloadExistingClasses) sm.reloadClasses(instrumentation); } diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java index e92ed674..b90d5762 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java @@ -22,7 +22,7 @@ package lombok.eclipse.agent; import static lombok.eclipse.Eclipse.*; -import static lombok.eclipse.EclipseAugments.*; +import static lombok.eclipse.EcjAugments.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Method; @@ -724,7 +724,7 @@ public class PatchDelegate { private static void cleanupDelegateMethods(CompilationUnitDeclaration cud) { CompilationUnit compilationUnit = getCompilationUnit(cud); if (compilationUnit != null) { - CompilationUnit_delegateMethods.clear(compilationUnit); + EclipseAugments.CompilationUnit_delegateMethods.clear(compilationUnit); } } @@ -819,7 +819,7 @@ public class PatchDelegate { if (sourceType != null) { CompilationUnit compilationUnit = getCompilationUnit(sourceType.getCompilationUnit()); if (compilationUnit != null) { - ConcurrentMap<String, List<SourceMethod>> map = CompilationUnit_delegateMethods.setIfAbsent(compilationUnit, new ConcurrentHashMap<String, List<SourceMethod>>()); + ConcurrentMap<String, List<SourceMethod>> map = EclipseAugments.CompilationUnit_delegateMethods.setIfAbsent(compilationUnit, new ConcurrentHashMap<String, List<SourceMethod>>()); List<SourceMethod> newList = new ArrayList<SourceMethod>(); List<SourceMethod> oldList = map.putIfAbsent(sourceType.getTypeQualifiedName(), newList); return oldList != null ? oldList : newList; diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java b/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java index 4e48aa81..f5678154 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java @@ -21,7 +21,7 @@ */ package lombok.eclipse.agent; -import static lombok.eclipse.EclipseAugments.CompilationUnit_javadoc; +import static lombok.eclipse.EcjAugments.EclipseAugments.CompilationUnit_javadoc; import java.lang.reflect.Method; import java.util.Map; @@ -36,7 +36,6 @@ import org.eclipse.jdt.internal.core.CompilationUnit; import org.eclipse.jdt.internal.core.SourceMethod; import org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2; -import lombok.eclipse.EclipseAugments; import lombok.eclipse.handlers.EclipseHandlerUtil; import lombok.permit.Permit; @@ -52,7 +51,8 @@ public class PatchJavadoc { ICompilationUnit iCompilationUnit = sourceMethod.getCompilationUnit(); if (iCompilationUnit instanceof CompilationUnit) { CompilationUnit compilationUnit = (CompilationUnit) iCompilationUnit; - Map<String, String> docs = EclipseAugments.CompilationUnit_javadoc.get(compilationUnit); + + Map<String, String> docs = CompilationUnit_javadoc.get(compilationUnit); if (docs == null) return null; String signature = getSignature(sourceMethod); @@ -81,7 +81,7 @@ public class PatchJavadoc { } return methodDeclaration.print(tab, output); } - + private static String getSignature(SourceMethod sourceMethod) { StringBuilder sb = new StringBuilder(); sb.append(sourceMethod.getParent().getElementName()); diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java index a2cda66c..55e8e0bf 100755 --- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -66,7 +66,7 @@ import org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner; import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; -import lombok.eclipse.EclipseAugments; +import static lombok.eclipse.EcjAugments.ASTNode_generatedBy; /** These contain a mix of the following: * <ul> @@ -545,14 +545,14 @@ final class PatchFixesHider { public static int fixRetrieveRightBraceOrSemiColonPosition(int retVal, AbstractMethodDeclaration amd) { if (retVal != -1 || amd == null) return retVal; - boolean isGenerated = EclipseAugments.ASTNode_generatedBy.get(amd) != null; + boolean isGenerated = ASTNode_generatedBy.get(amd) != null; if (isGenerated) return amd.declarationSourceEnd; return -1; } public static int fixRetrieveRightBraceOrSemiColonPosition(int retVal, FieldDeclaration fd) { if (retVal != -1 || fd == null) return retVal; - boolean isGenerated = EclipseAugments.ASTNode_generatedBy.get(fd) != null; + boolean isGenerated = ASTNode_generatedBy.get(fd) != null; if (isGenerated) return fd.declarationSourceEnd; return -1; } @@ -578,13 +578,13 @@ final class PatchFixesHider { org.eclipse.jdt.internal.compiler.ast.ASTNode internalNode) throws Exception { if (internalNode == null || domNode == null) return; - boolean isGenerated = EclipseAugments.ASTNode_generatedBy.get(internalNode) != null; + boolean isGenerated = ASTNode_generatedBy.get(internalNode) != null; if (isGenerated) domNode.getClass().getField("$isGenerated").set(domNode, true); } public static void setIsGeneratedFlagForName(org.eclipse.jdt.core.dom.Name name, Object internalNode) throws Exception { if (internalNode instanceof org.eclipse.jdt.internal.compiler.ast.ASTNode) { - boolean isGenerated = EclipseAugments.ASTNode_generatedBy.get((org.eclipse.jdt.internal.compiler.ast.ASTNode) internalNode) != null; + boolean isGenerated = ASTNode_generatedBy.get((org.eclipse.jdt.internal.compiler.ast.ASTNode) internalNode) != null; if (isGenerated) name.getClass().getField("$isGenerated").set(name, true); } } diff --git a/src/stubs/com/sun/tools/javac/main/Arguments.java b/src/stubs/com/sun/tools/javac/main/Arguments.java index ea866b6e..3d91734c 100644 --- a/src/stubs/com/sun/tools/javac/main/Arguments.java +++ b/src/stubs/com/sun/tools/javac/main/Arguments.java @@ -10,4 +10,7 @@ public class Arguments { public void init(String ownName, String... argv) {} public Map<Option, String> getDeferredFileManagerOptions() { return null; } public boolean validate() { return false; } + + // JDK15 + public void init(String ownName, Iterable<String> args) {} } diff --git a/src/utils/lombok/javac/JavacTreeMaker.java b/src/utils/lombok/javac/JavacTreeMaker.java index 15a11151..30d71606 100644 --- a/src/utils/lombok/javac/JavacTreeMaker.java +++ b/src/utils/lombok/javac/JavacTreeMaker.java @@ -24,6 +24,7 @@ package lombok.javac; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -106,7 +107,19 @@ public class JavacTreeMaker { return this; } - private static class MethodId<J> { + private static final class FieldId<J> { + private final Class<?> owner; + private final String name; + private final Class<J> fieldType; + + FieldId(Class<?> owner, String name, Class<J> fieldType) { + this.owner = owner; + this.name = name; + this.fieldType = fieldType; + } + } + + private static final class MethodId<J> { private final Class<?> owner; private final String name; private final Class<J> returnType; @@ -332,9 +345,79 @@ public class JavacTreeMaker { throw new InternalError("Not found: " + name); } - private static final Object METHOD_NOT_FOUND = new Object[0]; - private static final Object METHOD_MULTIPLE_FOUND = new Object[0]; + static <J> FieldId<J> FieldId(Class<?> owner, String name, Class<J> fieldType) { + return new FieldId<J>(owner, name, fieldType); + } + + private static final ConcurrentHashMap<FieldId<?>, Object> FIELD_CACHE = new ConcurrentHashMap<FieldId<?>, Object>(); + + private static boolean has(FieldId<?> f) { + Object field = FIELD_CACHE.get(f); + if (field == REFLECTIVE_ITEM_NOT_FOUND) return false; + if (field instanceof Field) return true; + + try { + return getFromCache(f) != REFLECTIVE_ITEM_NOT_FOUND; + } catch (IllegalStateException e) { + return false; + } + } + + private static <J> J get(Object owner, FieldId<J> f) { + Field field = getFromCache(f); + try { + return f.fieldType.cast(field.get(owner)); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } + } + + private static <J> void set(Object owner, FieldId<J> f, J val) { + Field field = getFromCache(f); + try { + field.set(owner, val); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } catch (IllegalArgumentException e) { + System.err.println("Type mismatch for: " + field); + throw e; + } + } + + private static Field getFromCache(FieldId<?> f) { + Object s = FIELD_CACHE.get(f); + if (s == null) s = addToCache(f); + if (s == REFLECTIVE_ITEM_NOT_FOUND) throw new IllegalStateException("Lombok TreeMaker frontend issue: no match when looking for field: " + f); + return (Field) s; + } + + private static Object addToCache(FieldId<?> f) { + for (Field field : f.owner.getDeclaredFields()) { + if (f.name.equals(field.getName())) { + if (!Modifier.isPublic(field.getModifiers())) field.setAccessible(true); + return FIELD_CACHE.putIfAbsent(f, field); + } + } + + return FIELD_CACHE.putIfAbsent(f, REFLECTIVE_ITEM_NOT_FOUND); + } + + private static final Object REFLECTIVE_ITEM_NOT_FOUND = new Object[0]; + private static final Object REFLECTIVE_ITEM_MULTIPLE_FOUND = new Object[0]; private static final ConcurrentHashMap<MethodId<?>, Object> METHOD_CACHE = new ConcurrentHashMap<MethodId<?>, Object>(); + + private boolean has(MethodId<?> m) { + Object method = METHOD_CACHE.get(m); + if (method == REFLECTIVE_ITEM_NOT_FOUND) return false; + if (method instanceof Method) return true; + + try { + return getFromCache(m) != REFLECTIVE_ITEM_NOT_FOUND; + } catch (IllegalStateException e) { + return false; + } + } + private <J> J invoke(MethodId<J> m, Object... args) { return invokeAny(tm, m, args); } @@ -351,8 +434,8 @@ public class JavacTreeMaker { } catch (IllegalAccessException e) { throw Javac.sneakyThrow(e); } catch (IllegalArgumentException e) { - System.err.println(method); - throw Javac.sneakyThrow(e); + System.err.println("Type mismatch for: " + method); + throw e; } } @@ -366,8 +449,8 @@ public class JavacTreeMaker { private static Method getFromCache(MethodId<?> m) { Object s = METHOD_CACHE.get(m); if (s == null) s = addToCache(m); - if (s == METHOD_MULTIPLE_FOUND) throw new IllegalStateException("Lombok TreeMaker frontend issue: multiple matches when looking for method: " + m); - if (s == METHOD_NOT_FOUND) throw new IllegalStateException("Lombok TreeMaker frontend issue: no match when looking for method: " + m); + if (s == REFLECTIVE_ITEM_MULTIPLE_FOUND) throw new IllegalStateException("Lombok TreeMaker frontend issue: multiple matches when looking for method: " + m); + if (s == REFLECTIVE_ITEM_NOT_FOUND) throw new IllegalStateException("Lombok TreeMaker frontend issue: no match when looking for method: " + m); return (Method) s; } @@ -391,13 +474,13 @@ public class JavacTreeMaker { } if (found == null) found = method; else { - METHOD_CACHE.putIfAbsent(m, METHOD_MULTIPLE_FOUND); - return METHOD_MULTIPLE_FOUND; + METHOD_CACHE.putIfAbsent(m, REFLECTIVE_ITEM_MULTIPLE_FOUND); + return REFLECTIVE_ITEM_MULTIPLE_FOUND; } } if (found == null) { - METHOD_CACHE.putIfAbsent(m, METHOD_NOT_FOUND); - return METHOD_NOT_FOUND; + METHOD_CACHE.putIfAbsent(m, REFLECTIVE_ITEM_NOT_FOUND); + return REFLECTIVE_ITEM_NOT_FOUND; } Permit.setAccessible(found); Object marker = METHOD_CACHE.putIfAbsent(m, found); @@ -431,8 +514,12 @@ public class JavacTreeMaker { //javac versions: 8 private static final MethodId<JCMethodDecl> MethodDefWithRecvParam = MethodId("MethodDef", JCMethodDecl.class, JCModifiers.class, Name.class, JCExpression.class, List.class, JCVariableDecl.class, List.class, List.class, JCBlock.class, JCExpression.class); - public JCMethodDecl MethodDef(JCModifiers mods, Name name, JCExpression resType, List<JCTypeParameter> typarams, JCVariableDecl recvparam, List<JCVariableDecl> params, List<JCExpression> thrown, JCBlock body, JCExpression defaultValue) { - return invoke(MethodDefWithRecvParam, mods, name, resType, recvparam, typarams, params, thrown, body, defaultValue); + public boolean hasMethodDefWithRecvParam() { + return has(MethodDefWithRecvParam); + } + + public JCMethodDecl MethodDefWithRecvParam(JCModifiers mods, Name name, JCExpression resType, List<JCTypeParameter> typarams, JCVariableDecl recvparam, List<JCVariableDecl> params, List<JCExpression> thrown, JCBlock body, JCExpression defaultValue) { + return invoke(MethodDefWithRecvParam, mods, name, resType, typarams, recvparam, params, thrown, body, defaultValue); } //javac versions: 6-8 @@ -878,4 +965,18 @@ public class JavacTreeMaker { public JCExpression Type(Type type) { return invoke(Type, type); } + + private static final FieldId<JCVariableDecl> MethodDecl_recvParam = FieldId(JCMethodDecl.class, "recvparam", JCVariableDecl.class); + //javac versions: 8+ + public boolean hasReceiverParameter() { + return has(MethodDecl_recvParam); + } + + public JCVariableDecl getReceiverParameter(JCMethodDecl method) { + return get(method, MethodDecl_recvParam); + } + + public void setReceiverParameter(JCMethodDecl method, JCVariableDecl param) { + set(method, MethodDecl_recvParam, param); + } }
\ No newline at end of file diff --git a/test/core/src/lombok/DirectoryRunner.java b/test/core/src/lombok/DirectoryRunner.java index a174355d..93b18039 100644 --- a/test/core/src/lombok/DirectoryRunner.java +++ b/test/core/src/lombok/DirectoryRunner.java @@ -180,7 +180,8 @@ public class DirectoryRunner extends Runner { case DELOMBOK: return new RunTestsViaDelombok().createTester(params, file, "javac", params.getVersion()); case ECJ: - return new RunTestsViaEcj().createTester(params, file, "ecj", params.getVersion()); + String platform = RunTestsViaEcj.eclipseAvailable() ? "eclipse" : "ecj"; + return new RunTestsViaEcj().createTester(params, file, platform, params.getVersion()); default: case JAVAC: throw new UnsupportedOperationException(); diff --git a/test/core/src/lombok/LombokTestSource.java b/test/core/src/lombok/LombokTestSource.java index a0a6407a..e23a0f57 100644 --- a/test/core/src/lombok/LombokTestSource.java +++ b/test/core/src/lombok/LombokTestSource.java @@ -65,7 +65,10 @@ public class LombokTestSource { public boolean runOnPlatform(String platform) { if (platforms == null || platforms.isEmpty()) return true; - for (String pl : platforms) if (pl.equalsIgnoreCase(platform)) return true; + for (String pl : platforms) { + if (pl.startsWith("!") && pl.regionMatches(true, 1, platform, 0, platform.length())) return false; + if (pl.equalsIgnoreCase(platform)) return true; + } return false; } diff --git a/test/core/src/lombok/RunTestsViaEcj.java b/test/core/src/lombok/RunTestsViaEcj.java index b98c19b7..1d840a21 100644 --- a/test/core/src/lombok/RunTestsViaEcj.java +++ b/test/core/src/lombok/RunTestsViaEcj.java @@ -35,6 +35,14 @@ import java.util.concurrent.atomic.AtomicReference; import lombok.eclipse.Eclipse; import lombok.javac.CapturingDiagnosticListener.CompilerMessage; +import org.eclipse.core.internal.registry.ExtensionRegistry; +import org.eclipse.core.internal.runtime.Activator; +import org.eclipse.core.internal.runtime.PlatformActivator; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.RegistryFactory; +import org.eclipse.core.runtime.adaptor.EclipseStarter; +import org.eclipse.core.runtime.spi.IRegistryProvider; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.core.compiler.CharOperation; @@ -49,6 +57,9 @@ import org.eclipse.jdt.internal.compiler.batch.FileSystem; import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; +import org.eclipse.jdt.internal.core.JavaModelManager; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; public class RunTestsViaEcj extends AbstractRunTests { protected CompilerOptions ecjCompilerOptions() { @@ -107,7 +118,17 @@ public class RunTestsViaEcj extends AbstractRunTests { String source = readFile(file); char[] sourceArray = source.toCharArray(); - final ICompilationUnit sourceUnit = new TestCompilationUnit(file.getName(), source); + final ICompilationUnit sourceUnit; + try { + if (eclipseAvailable()) { + sourceUnit = new TestCompilationUnitEclipse(file.getName(), source); + } else { + sourceUnit = new TestCompilationUnitEcj(file.getName(), source); + } + } catch (Throwable t) { + t.printStackTrace(); + return false; + } Compiler ecjCompiler = new Compiler(createFileSystem(file, minVersion), ecjErrorHandlingPolicy(), ecjCompilerOptions(), bitbucketRequestor, new DefaultProblemFactory(Locale.ENGLISH)) { @Override protected synchronized void addCompilationUnit(ICompilationUnit inUnit, CompilationUnitDeclaration parsedUnit) { @@ -116,6 +137,8 @@ public class RunTestsViaEcj extends AbstractRunTests { } }; + // initializeEclipseBundles(); + ecjCompiler.compile(new ICompilationUnit[] {sourceUnit}); CompilationResult compilationResult = compilationResult_.get(); @@ -137,7 +160,37 @@ public class RunTestsViaEcj extends AbstractRunTests { return true; } - private boolean eclipseAvailable() { + @SuppressWarnings("unused") + private static class EclipseInitializer { + static void initializeEclipseBundles() throws Exception { + // This code does not work yet, it's research-in-progress. + // The problem is that parts of the eclipse handler (in `PatchValEclipse` and friends) do not work unless + // an actual eclipse exists; PatchVal causes code to run that will end up running `ResourcesPlugin.getWorkspace()`, which + // goes down a rabbit hole of pinging off of various static fields (or `getX()` calls which return static fields), all + // of which are `null` until the plugin they belong to is properly initialized. + // This code is work in progress to 'hack' the initialization of each plugin one-by-one, but I doubt this is the right + // way to do it, as I bet it's fragile (will break when eclipse updates rather easily), and who knows how many fields + // and things need to be initialized. + // A better plan would be to start an actual, real eclipse, by telling `EclipseStarter.startup` to launch some sort of + // application (or at least a bunch of bundles/products/apps, including the JDT). This will then take long enough that + // it'll need to be cached and re-used for each test or the Eclipse test run would take far too long. + + BundleContext context = EclipseStarter.startup(new String[0], null); + RegistryFactory.setDefaultRegistryProvider(new IRegistryProvider() { + private final ExtensionRegistry REG = new ExtensionRegistry(null, null, null); + @Override public IExtensionRegistry getRegistry() { + return REG; + } + }); + new Activator().start(context); + new PlatformActivator().start(context); + for (Bundle b : context.getBundles()) System.out.println("BUNDLE: " + b.getSymbolicName()); + new ResourcesPlugin().start(context); + JavaModelManager.getJavaModelManager().startup(); + } + } + + static boolean eclipseAvailable() { try { Class.forName("org.eclipse.jdt.core.dom.CompilationUnit"); } catch (Throwable t) { @@ -171,7 +224,7 @@ public class RunTestsViaEcj extends AbstractRunTests { i.remove(); } } - if (new File("bin").exists()) classpath.add("bin"); + if (new File("bin/main").exists()) classpath.add("bin/main"); classpath.add("dist/lombok.jar"); if (bootRuntimePath == null || bootRuntimePath.isEmpty()) throw new IllegalStateException("System property delombok.bootclasspath is not set; set it to the rt of java6 or java8"); classpath.add(bootRuntimePath); @@ -184,11 +237,44 @@ public class RunTestsViaEcj extends AbstractRunTests { return new FileSystem(classpath.toArray(new String[0]), new String[] {file.getAbsolutePath()}, "UTF-8"); } - private static final class TestCompilationUnit extends org.eclipse.jdt.internal.core.CompilationUnit { + private static final class TestCompilationUnitEcj implements ICompilationUnit { + private final char[] name, source, mainTypeName; + + TestCompilationUnitEcj(String name, String source) { + this.source = source.toCharArray(); + this.name = name.toCharArray(); + + char[] fileNameCharArray = getFileName(); + int start = CharOperation.lastIndexOf(File.separatorChar, fileNameCharArray) + 1; + int end = CharOperation.lastIndexOf('.', fileNameCharArray); + if (end == -1) { + end = fileNameCharArray.length; + } + mainTypeName = CharOperation.subarray(fileNameCharArray, start, end); + } + + @Override public char[] getFileName() { + return name; + } + + @Override public char[] getContents() { + return source; + } + + @Override public char[] getMainTypeName() { + return mainTypeName; + } + + @Override public char[][] getPackageName() { + return null; + } + } + + private static final class TestCompilationUnitEclipse extends org.eclipse.jdt.internal.core.CompilationUnit { private final char[] source; private final char[] mainTypeName; - private TestCompilationUnit(String name, String source) { + private TestCompilationUnitEclipse(String name, String source) { super(null, name, null); this.source = source.toCharArray(); diff --git a/test/pretty/resource/after/tryWithResourcesVarRef.java b/test/pretty/resource/after/TryWithResourcesVarRef.java index 5117f706..5117f706 100644 --- a/test/pretty/resource/after/tryWithResourcesVarRef.java +++ b/test/pretty/resource/after/TryWithResourcesVarRef.java diff --git a/test/stubs/org/checkerframework/checker/calledmethods/qual/CalledMethods.java b/test/stubs/org/checkerframework/checker/calledmethods/qual/CalledMethods.java new file mode 100644 index 00000000..514e8c6b --- /dev/null +++ b/test/stubs/org/checkerframework/checker/calledmethods/qual/CalledMethods.java @@ -0,0 +1,17 @@ +package org.checkerframework.checker.calledmethods.qual; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +public @interface CalledMethods { + /** + * Methods that have been called, on any expression whose type is annotated. + * + * @return methods that have been called + */ + public String[] value() default {}; +}
\ No newline at end of file diff --git a/test/stubs/org/checkerframework/checker/calledmethods/qual/NotCalledMethods.java b/test/stubs/org/checkerframework/checker/calledmethods/qual/NotCalledMethods.java new file mode 100644 index 00000000..7a9ef37c --- /dev/null +++ b/test/stubs/org/checkerframework/checker/calledmethods/qual/NotCalledMethods.java @@ -0,0 +1,17 @@ +package org.checkerframework.checker.calledmethods.qual; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +public @interface NotCalledMethods { + /** + * Methods that have been called, on any expression whose type is annotated. + * + * @return methods that have been called + */ + public String[] value() default {}; +}
\ No newline at end of file diff --git a/test/stubs/org/checkerframework/common/aliasing/qual/Unique.java b/test/stubs/org/checkerframework/common/aliasing/qual/Unique.java new file mode 100644 index 00000000..fe7acfca --- /dev/null +++ b/test/stubs/org/checkerframework/common/aliasing/qual/Unique.java @@ -0,0 +1,12 @@ +package org.checkerframework.common.aliasing.qual; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +public @interface Unique {}
\ No newline at end of file diff --git a/test/stubs/org/checkerframework/common/returnsreceiver/qual/This.java b/test/stubs/org/checkerframework/common/returnsreceiver/qual/This.java new file mode 100644 index 00000000..8ae1cd59 --- /dev/null +++ b/test/stubs/org/checkerframework/common/returnsreceiver/qual/This.java @@ -0,0 +1,12 @@ +package org.checkerframework.common.returnsreceiver.qual; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Inherited +public @interface This {}
\ No newline at end of file diff --git a/test/stubs/org/checkerframework/dataflow/qual/Pure.java b/test/stubs/org/checkerframework/dataflow/qual/Pure.java new file mode 100644 index 00000000..d9bb1bf4 --- /dev/null +++ b/test/stubs/org/checkerframework/dataflow/qual/Pure.java @@ -0,0 +1,12 @@ +package org.checkerframework.dataflow.qual; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) +public @interface Pure {}
\ No newline at end of file diff --git a/test/stubs/org/checkerframework/dataflow/qual/SideEffectFree.java b/test/stubs/org/checkerframework/dataflow/qual/SideEffectFree.java new file mode 100644 index 00000000..9c32d369 --- /dev/null +++ b/test/stubs/org/checkerframework/dataflow/qual/SideEffectFree.java @@ -0,0 +1,12 @@ +package org.checkerframework.dataflow.qual; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) +public @interface SideEffectFree {}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/BuilderWithDeprecatedAnnOnly.java b/test/transform/resource/after-delombok/BuilderWithDeprecatedAnnOnly.java new file mode 100644 index 00000000..f039c047 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderWithDeprecatedAnnOnly.java @@ -0,0 +1,104 @@ +import com.google.common.collect.ImmutableList; +public class BuilderWithDeprecatedAnnOnly { + @Deprecated + int dep1; + @Deprecated + java.util.List<String> strings; + @Deprecated + ImmutableList<Integer> numbers; + @java.lang.SuppressWarnings("all") + BuilderWithDeprecatedAnnOnly(final int dep1, final java.util.List<String> strings, final ImmutableList<Integer> numbers) { + this.dep1 = dep1; + this.strings = strings; + this.numbers = numbers; + } + @java.lang.SuppressWarnings("all") + public static class BuilderWithDeprecatedAnnOnlyBuilder { + @java.lang.SuppressWarnings("all") + private int dep1; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList<String> strings; + @java.lang.SuppressWarnings("all") + private com.google.common.collect.ImmutableList.Builder<Integer> numbers; + @java.lang.SuppressWarnings("all") + BuilderWithDeprecatedAnnOnlyBuilder() { + } + @java.lang.Deprecated + @java.lang.SuppressWarnings("all") + public BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder dep1(final int dep1) { + this.dep1 = dep1; + return this; + } + @java.lang.Deprecated + @java.lang.SuppressWarnings("all") + public BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder string(final String string) { + if (this.strings == null) this.strings = new java.util.ArrayList<String>(); + this.strings.add(string); + return this; + } + @java.lang.Deprecated + @java.lang.SuppressWarnings("all") + public BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder strings(final java.util.Collection<? extends String> strings) { + if (strings == null) { + throw new java.lang.NullPointerException("strings cannot be null"); + } + if (this.strings == null) this.strings = new java.util.ArrayList<String>(); + this.strings.addAll(strings); + return this; + } + @java.lang.Deprecated + @java.lang.SuppressWarnings("all") + public BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder clearStrings() { + if (this.strings != null) this.strings.clear(); + return this; + } + @java.lang.Deprecated + @java.lang.SuppressWarnings("all") + public BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder number(final Integer number) { + if (this.numbers == null) this.numbers = com.google.common.collect.ImmutableList.builder(); + this.numbers.add(number); + return this; + } + @java.lang.Deprecated + @java.lang.SuppressWarnings("all") + public BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder numbers(final java.lang.Iterable<? extends Integer> numbers) { + if (numbers == null) { + throw new java.lang.NullPointerException("numbers cannot be null"); + } + if (this.numbers == null) this.numbers = com.google.common.collect.ImmutableList.builder(); + this.numbers.addAll(numbers); + return this; + } + @java.lang.Deprecated + @java.lang.SuppressWarnings("all") + public BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder clearNumbers() { + this.numbers = null; + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithDeprecatedAnnOnly build() { + java.util.List<String> strings; + switch (this.strings == null ? 0 : this.strings.size()) { + case 0: + strings = java.util.Collections.emptyList(); + break; + case 1: + strings = java.util.Collections.singletonList(this.strings.get(0)); + break; + default: + strings = java.util.Collections.unmodifiableList(new java.util.ArrayList<String>(this.strings)); + } + com.google.common.collect.ImmutableList<Integer> numbers = this.numbers == null ? com.google.common.collect.ImmutableList.<Integer>of() : this.numbers.build(); + return new BuilderWithDeprecatedAnnOnly(this.dep1, strings, numbers); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder(dep1=" + this.dep1 + ", strings=" + this.strings + ", numbers=" + this.numbers + ")"; + } + } + @java.lang.SuppressWarnings("all") + public static BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder builder() { + return new BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder(); + } +} diff --git a/test/transform/resource/after-delombok/CheckerFrameworkBasic.java b/test/transform/resource/after-delombok/CheckerFrameworkBasic.java index 3077728c..c9b73d7c 100644 --- a/test/transform/resource/after-delombok/CheckerFrameworkBasic.java +++ b/test/transform/resource/after-delombok/CheckerFrameworkBasic.java @@ -2,12 +2,6 @@ class CheckerFrameworkBasic { private final int x; private final int y; private int z; - @org.checkerframework.common.aliasing.qual.Unique - @java.lang.SuppressWarnings("all") - public CheckerFrameworkBasic(final int x, final int y) { - this.x = x; - this.y = y; - } @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") public int getX() { @@ -23,7 +17,7 @@ class CheckerFrameworkBasic { public int getZ() { return this.z; } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") public CheckerFrameworkBasic setZ(final int z) { this.z = z; @@ -64,6 +58,12 @@ class CheckerFrameworkBasic { public java.lang.String toString() { return "CheckerFrameworkBasic(x=" + this.getX() + ", y=" + this.getY() + ", z=" + this.getZ() + ")"; } + @java.lang.SuppressWarnings("all") + public CheckerFrameworkBasic(final int x, final int y, final int z) { + this.x = x; + this.y = y; + this.z = z; + } @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") public CheckerFrameworkBasic withX(final int x) { diff --git a/test/transform/resource/after-delombok/CheckerFrameworkBuilder.java b/test/transform/resource/after-delombok/CheckerFrameworkBuilder.java index ace3adad..38600b8e 100644 --- a/test/transform/resource/after-delombok/CheckerFrameworkBuilder.java +++ b/test/transform/resource/after-delombok/CheckerFrameworkBuilder.java @@ -9,7 +9,6 @@ class CheckerFrameworkBuilder { private static int $default$x() { return 5; } - @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder(final int x, final int y, final int z, final List<String> names) { this.x = x; @@ -29,37 +28,36 @@ class CheckerFrameworkBuilder { private int z; @java.lang.SuppressWarnings("all") private java.util.ArrayList<String> names; - @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") CheckerFrameworkBuilderBuilder() { } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") - public CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder x(@org.checkerframework.checker.builder.qual.NotCalledMethods("x") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder this, final int x) { + public CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder x(CheckerFrameworkBuilder.@org.checkerframework.checker.calledmethods.qual.NotCalledMethods("x") CheckerFrameworkBuilderBuilder this, final int x) { this.x$value = x; x$set = true; return this; } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") - public CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder y(@org.checkerframework.checker.builder.qual.NotCalledMethods("y") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder this, final int y) { + public CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder y(CheckerFrameworkBuilder.@org.checkerframework.checker.calledmethods.qual.NotCalledMethods("y") CheckerFrameworkBuilderBuilder this, final int y) { this.y = y; return this; } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") - public CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder z(@org.checkerframework.checker.builder.qual.NotCalledMethods("z") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder this, final int z) { + public CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder z(CheckerFrameworkBuilder.@org.checkerframework.checker.calledmethods.qual.NotCalledMethods("z") CheckerFrameworkBuilderBuilder this, final int z) { this.z = z; return this; } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") public CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder name(final String name) { if (this.names == null) this.names = new java.util.ArrayList<String>(); this.names.add(name); return this; } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") public CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder names(final java.util.Collection<? extends String> names) { if (names == null) { @@ -69,7 +67,7 @@ class CheckerFrameworkBuilder { this.names.addAll(names); return this; } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") public CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder clearNames() { if (this.names != null) this.names.clear(); @@ -77,7 +75,7 @@ class CheckerFrameworkBuilder { } @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") - public CheckerFrameworkBuilder build(@org.checkerframework.checker.builder.qual.CalledMethods({"y", "z"}) CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder this) { + public CheckerFrameworkBuilder build(CheckerFrameworkBuilder.@org.checkerframework.checker.calledmethods.qual.CalledMethods({"y", "z"}) CheckerFrameworkBuilderBuilder this) { java.util.List<String> names; switch (this.names == null ? 0 : this.names.size()) { case 0: @@ -100,10 +98,10 @@ class CheckerFrameworkBuilder { return "CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder(x$value=" + this.x$value + ", y=" + this.y + ", z=" + this.z + ", names=" + this.names + ")"; } } - @org.checkerframework.common.aliasing.qual.Unique + @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") - public static CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder builder() { + public static CheckerFrameworkBuilder.@org.checkerframework.common.aliasing.qual.Unique CheckerFrameworkBuilderBuilder builder() { return new CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder(); } } diff --git a/test/transform/resource/after-delombok/CheckerFrameworkSuperBuilder.java b/test/transform/resource/after-delombok/CheckerFrameworkSuperBuilder.java index 30408c3b..7c2dff9e 100644 --- a/test/transform/resource/after-delombok/CheckerFrameworkSuperBuilder.java +++ b/test/transform/resource/after-delombok/CheckerFrameworkSuperBuilder.java @@ -22,40 +22,40 @@ class CheckerFrameworkSuperBuilder { private int z; @java.lang.SuppressWarnings("all") private java.util.ArrayList<String> names; - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") protected abstract B self(); @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") - public abstract C build(@org.checkerframework.checker.builder.qual.CalledMethods({"y", "z"}) CheckerFrameworkSuperBuilder.Parent this); - @org.checkerframework.checker.builder.qual.ReturnsReceiver + public abstract C build(CheckerFrameworkSuperBuilder.Parent.@org.checkerframework.checker.calledmethods.qual.CalledMethods({"y", "z"}) ParentBuilder<C, B> this); + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") - public B x(@org.checkerframework.checker.builder.qual.NotCalledMethods("x") CheckerFrameworkSuperBuilder.Parent.ParentBuilder<C, B> this, final int x) { + public B x(CheckerFrameworkSuperBuilder.Parent.@org.checkerframework.checker.calledmethods.qual.NotCalledMethods("x") ParentBuilder<C, B> this, final int x) { this.x$value = x; x$set = true; return self(); } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") - public B y(@org.checkerframework.checker.builder.qual.NotCalledMethods("y") CheckerFrameworkSuperBuilder.Parent.ParentBuilder<C, B> this, final int y) { + public B y(CheckerFrameworkSuperBuilder.Parent.@org.checkerframework.checker.calledmethods.qual.NotCalledMethods("y") ParentBuilder<C, B> this, final int y) { this.y = y; return self(); } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") - public B z(@org.checkerframework.checker.builder.qual.NotCalledMethods("z") CheckerFrameworkSuperBuilder.Parent.ParentBuilder<C, B> this, final int z) { + public B z(CheckerFrameworkSuperBuilder.Parent.@org.checkerframework.checker.calledmethods.qual.NotCalledMethods("z") ParentBuilder<C, B> this, final int z) { this.z = z; return self(); } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") public B name(final String name) { if (this.names == null) this.names = new java.util.ArrayList<String>(); this.names.add(name); return self(); } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") public B names(final java.util.Collection<? extends String> names) { if (names == null) { @@ -65,7 +65,7 @@ class CheckerFrameworkSuperBuilder { this.names.addAll(names); return self(); } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") public B clearNames() { if (this.names != null) this.names.clear(); @@ -80,12 +80,11 @@ class CheckerFrameworkSuperBuilder { } @java.lang.SuppressWarnings("all") private static final class ParentBuilderImpl extends CheckerFrameworkSuperBuilder.Parent.ParentBuilder<CheckerFrameworkSuperBuilder.Parent, CheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl> { - @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") private ParentBuilderImpl() { } @java.lang.Override - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") protected CheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl self() { @@ -94,7 +93,7 @@ class CheckerFrameworkSuperBuilder { @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.Override @java.lang.SuppressWarnings("all") - public CheckerFrameworkSuperBuilder.Parent build(@org.checkerframework.checker.builder.qual.CalledMethods({"y", "z"}) CheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl this) { + public CheckerFrameworkSuperBuilder.Parent build(CheckerFrameworkSuperBuilder.Parent.@org.checkerframework.checker.calledmethods.qual.CalledMethods({"y", "z"}) ParentBuilderImpl this) { return new CheckerFrameworkSuperBuilder.Parent(this); } } @@ -140,24 +139,24 @@ class CheckerFrameworkSuperBuilder { @java.lang.SuppressWarnings("all") private int b; @java.lang.Override - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") protected abstract B self(); @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.Override @java.lang.SuppressWarnings("all") - public abstract C build(@org.checkerframework.checker.builder.qual.CalledMethods("b") CheckerFrameworkSuperBuilder.ZChild this); - @org.checkerframework.checker.builder.qual.ReturnsReceiver + public abstract C build(CheckerFrameworkSuperBuilder.ZChild.@org.checkerframework.checker.calledmethods.qual.CalledMethods("b") ZChildBuilder<C, B> this); + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") - public B a(@org.checkerframework.checker.builder.qual.NotCalledMethods("a") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder<C, B> this, final int a) { + public B a(CheckerFrameworkSuperBuilder.ZChild.@org.checkerframework.checker.calledmethods.qual.NotCalledMethods("a") ZChildBuilder<C, B> this, final int a) { this.a$value = a; a$set = true; return self(); } - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") - public B b(@org.checkerframework.checker.builder.qual.NotCalledMethods("b") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder<C, B> this, final int b) { + public B b(CheckerFrameworkSuperBuilder.ZChild.@org.checkerframework.checker.calledmethods.qual.NotCalledMethods("b") ZChildBuilder<C, B> this, final int b) { this.b = b; return self(); } @@ -170,12 +169,11 @@ class CheckerFrameworkSuperBuilder { } @java.lang.SuppressWarnings("all") private static final class ZChildBuilderImpl extends CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder<CheckerFrameworkSuperBuilder.ZChild, CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl> { - @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") private ZChildBuilderImpl() { } @java.lang.Override - @org.checkerframework.checker.builder.qual.ReturnsReceiver + @org.checkerframework.common.returnsreceiver.qual.This @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") protected CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl self() { @@ -184,7 +182,7 @@ class CheckerFrameworkSuperBuilder { @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.Override @java.lang.SuppressWarnings("all") - public CheckerFrameworkSuperBuilder.ZChild build(@org.checkerframework.checker.builder.qual.CalledMethods("b") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl this) { + public CheckerFrameworkSuperBuilder.ZChild build(CheckerFrameworkSuperBuilder.ZChild.@org.checkerframework.checker.calledmethods.qual.CalledMethods("b") ZChildBuilderImpl this) { return new CheckerFrameworkSuperBuilder.ZChild(this); } } diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeCache.java b/test/transform/resource/after-delombok/EqualsAndHashCodeCache.java new file mode 100644 index 00000000..4f3574b6 --- /dev/null +++ b/test/transform/resource/after-delombok/EqualsAndHashCodeCache.java @@ -0,0 +1,167 @@ +class EqualsAndHashCode { + @java.lang.SuppressWarnings("all") + private transient int $hashCodeCache; + int x; + boolean[] y; + Object[] z; + String a; + String b; + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof EqualsAndHashCode)) return false; + final EqualsAndHashCode other = (EqualsAndHashCode) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (this.x != other.x) return false; + if (!java.util.Arrays.equals(this.y, other.y)) return false; + if (!java.util.Arrays.deepEquals(this.z, other.z)) return false; + final java.lang.Object this$a = this.a; + final java.lang.Object other$a = other.a; + if (this$a == null ? other$a != null : !this$a.equals(other$a)) return false; + final java.lang.Object this$b = this.b; + final java.lang.Object other$b = other.b; + if (this$b == null ? other$b != null : !this$b.equals(other$b)) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof EqualsAndHashCode; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + if (this.$hashCodeCache != 0) return this.$hashCodeCache; + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.x; + result = result * PRIME + java.util.Arrays.hashCode(this.y); + result = result * PRIME + java.util.Arrays.deepHashCode(this.z); + final java.lang.Object $a = this.a; + result = result * PRIME + ($a == null ? 43 : $a.hashCode()); + final java.lang.Object $b = this.b; + result = result * PRIME + ($b == null ? 43 : $b.hashCode()); + if (result == 0) result = java.lang.Integer.MIN_VALUE; + this.$hashCodeCache = result; + return result; + } +} +final class EqualsAndHashCode2 { + @java.lang.SuppressWarnings("all") + private transient int $hashCodeCache; + int x; + long y; + float f; + double d; + boolean b; + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof EqualsAndHashCode2)) return false; + final EqualsAndHashCode2 other = (EqualsAndHashCode2) o; + if (this.x != other.x) return false; + if (this.y != other.y) return false; + if (java.lang.Float.compare(this.f, other.f) != 0) return false; + if (java.lang.Double.compare(this.d, other.d) != 0) return false; + if (this.b != other.b) return false; + return true; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + if (this.$hashCodeCache != 0) return this.$hashCodeCache; + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.x; + final long $y = this.y; + result = result * PRIME + (int) ($y >>> 32 ^ $y); + result = result * PRIME + java.lang.Float.floatToIntBits(this.f); + final long $d = java.lang.Double.doubleToLongBits(this.d); + result = result * PRIME + (int) ($d >>> 32 ^ $d); + result = result * PRIME + (this.b ? 79 : 97); + if (result == 0) result = java.lang.Integer.MIN_VALUE; + this.$hashCodeCache = result; + return result; + } +} +final class EqualsAndHashCode3 extends EqualsAndHashCode { + @java.lang.SuppressWarnings("all") + private transient int $hashCodeCache; + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof EqualsAndHashCode3)) return false; + final EqualsAndHashCode3 other = (EqualsAndHashCode3) o; + if (!other.canEqual((java.lang.Object) this)) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof EqualsAndHashCode3; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + if (this.$hashCodeCache != 0) return this.$hashCodeCache; + int result = 1; + if (result == 0) result = java.lang.Integer.MIN_VALUE; + this.$hashCodeCache = result; + return result; + } +} +class EqualsAndHashCode4 extends EqualsAndHashCode { + @java.lang.SuppressWarnings("all") + private transient int $hashCodeCache; + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof EqualsAndHashCode4)) return false; + final EqualsAndHashCode4 other = (EqualsAndHashCode4) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (!super.equals(o)) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof EqualsAndHashCode4; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + if (this.$hashCodeCache != 0) return this.$hashCodeCache; + int result = super.hashCode(); + if (result == 0) result = java.lang.Integer.MIN_VALUE; + this.$hashCodeCache = result; + return result; + } +} +final class EqualsAndHashCode5 extends EqualsAndHashCode { + @java.lang.SuppressWarnings("all") + private transient int $hashCodeCache; + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof EqualsAndHashCode5)) return false; + final EqualsAndHashCode5 other = (EqualsAndHashCode5) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (!super.equals(o)) return false; + return true; + } + @java.lang.SuppressWarnings("all") + protected boolean canEqual(final java.lang.Object other) { + return other instanceof EqualsAndHashCode5; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + if (this.$hashCodeCache != 0) return this.$hashCodeCache; + int result = super.hashCode(); + if (result == 0) result = java.lang.Integer.MIN_VALUE; + this.$hashCodeCache = result; + return result; + } +} diff --git a/test/transform/resource/after-delombok/WithMethodMarkedDeprecatedAnnOnly.java b/test/transform/resource/after-delombok/WithMethodMarkedDeprecatedAnnOnly.java new file mode 100644 index 00000000..551b59bf --- /dev/null +++ b/test/transform/resource/after-delombok/WithMethodMarkedDeprecatedAnnOnly.java @@ -0,0 +1,11 @@ +class WithMethodMarkedDeprecatedAnnOnly { + @Deprecated + int annotation; + WithMethodMarkedDeprecatedAnnOnly(int annotation) { + } + @java.lang.Deprecated + @java.lang.SuppressWarnings("all") + public WithMethodMarkedDeprecatedAnnOnly withAnnotation(final int annotation) { + return this.annotation == annotation ? this : new WithMethodMarkedDeprecatedAnnOnly(annotation); + } +} diff --git a/test/transform/resource/after-ecj/BuilderWithDeprecatedAnnOnly.java b/test/transform/resource/after-ecj/BuilderWithDeprecatedAnnOnly.java new file mode 100644 index 00000000..d25dacc1 --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderWithDeprecatedAnnOnly.java @@ -0,0 +1,88 @@ +import com.google.common.collect.ImmutableList; +import lombok.Builder; +import lombok.Singular; +public @Builder class BuilderWithDeprecatedAnnOnly { + public static @java.lang.SuppressWarnings("all") class BuilderWithDeprecatedAnnOnlyBuilder { + private @java.lang.SuppressWarnings("all") int dep1; + private @java.lang.SuppressWarnings("all") java.util.ArrayList<String> strings; + private @java.lang.SuppressWarnings("all") com.google.common.collect.ImmutableList.Builder<Integer> numbers; + @java.lang.SuppressWarnings("all") BuilderWithDeprecatedAnnOnlyBuilder() { + super(); + } + public @java.lang.Deprecated @java.lang.SuppressWarnings("all") BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder dep1(final int dep1) { + this.dep1 = dep1; + return this; + } + public @java.lang.Deprecated @java.lang.SuppressWarnings("all") BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder string(final String string) { + if ((this.strings == null)) + this.strings = new java.util.ArrayList<String>(); + this.strings.add(string); + return this; + } + public @java.lang.Deprecated @java.lang.SuppressWarnings("all") BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder strings(final java.util.Collection<? extends String> strings) { + if ((strings == null)) + { + throw new java.lang.NullPointerException("strings cannot be null"); + } + if ((this.strings == null)) + this.strings = new java.util.ArrayList<String>(); + this.strings.addAll(strings); + return this; + } + public @java.lang.Deprecated @java.lang.SuppressWarnings("all") BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder clearStrings() { + if ((this.strings != null)) + this.strings.clear(); + return this; + } + public @java.lang.Deprecated @java.lang.SuppressWarnings("all") BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder number(final Integer number) { + if ((this.numbers == null)) + this.numbers = com.google.common.collect.ImmutableList.builder(); + this.numbers.add(number); + return this; + } + public @java.lang.Deprecated @java.lang.SuppressWarnings("all") BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder numbers(final java.lang.Iterable<? extends Integer> numbers) { + if ((numbers == null)) + { + throw new java.lang.NullPointerException("numbers cannot be null"); + } + if ((this.numbers == null)) + this.numbers = com.google.common.collect.ImmutableList.builder(); + this.numbers.addAll(numbers); + return this; + } + public @java.lang.Deprecated @java.lang.SuppressWarnings("all") BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder clearNumbers() { + this.numbers = null; + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithDeprecatedAnnOnly build() { + java.util.List<String> strings; + switch (((this.strings == null) ? 0 : this.strings.size())) { + case 0 : + strings = java.util.Collections.emptyList(); + break; + case 1 : + strings = java.util.Collections.singletonList(this.strings.get(0)); + break; + default : + strings = java.util.Collections.unmodifiableList(new java.util.ArrayList<String>(this.strings)); + } + com.google.common.collect.ImmutableList<Integer> numbers = ((this.numbers == null) ? com.google.common.collect.ImmutableList.<Integer>of() : this.numbers.build()); + return new BuilderWithDeprecatedAnnOnly(this.dep1, strings, numbers); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((((("BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder(dep1=" + this.dep1) + ", strings=") + this.strings) + ", numbers=") + this.numbers) + ")"); + } + } + @Deprecated int dep1; + @Singular @Deprecated java.util.List<String> strings; + @Singular @Deprecated ImmutableList<Integer> numbers; + @java.lang.SuppressWarnings("all") BuilderWithDeprecatedAnnOnly(final int dep1, final java.util.List<String> strings, final ImmutableList<Integer> numbers) { + super(); + this.dep1 = dep1; + this.strings = strings; + this.numbers = numbers; + } + public static @java.lang.SuppressWarnings("all") BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder builder() { + return new BuilderWithDeprecatedAnnOnly.BuilderWithDeprecatedAnnOnlyBuilder(); + } +} diff --git a/test/transform/resource/after-ecj/CheckerFrameworkBasic.java b/test/transform/resource/after-ecj/CheckerFrameworkBasic.java index ce4d11f8..5411c2a4 100644 --- a/test/transform/resource/after-ecj/CheckerFrameworkBasic.java +++ b/test/transform/resource/after-ecj/CheckerFrameworkBasic.java @@ -1,7 +1,8 @@ +import lombok.AllArgsConstructor; import lombok.Data; import lombok.experimental.Accessors; import lombok.With; -@Data @Accessors(chain = true) class CheckerFrameworkBasic { +@Data @AllArgsConstructor @Accessors(chain = true) class CheckerFrameworkBasic { private final @With int x; private final int y; private int z; @@ -17,7 +18,7 @@ import lombok.With; public @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") int getZ() { return this.z; } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") CheckerFrameworkBasic setZ(final int z) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") CheckerFrameworkBasic setZ(final int z) { this.z = z; return this; } @@ -51,9 +52,10 @@ import lombok.With; public @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") java.lang.String toString() { return (((((("CheckerFrameworkBasic(x=" + this.getX()) + ", y=") + this.getY()) + ", z=") + this.getZ()) + ")"); } - public @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") CheckerFrameworkBasic(final int x, final int y) { + public @java.lang.SuppressWarnings("all") CheckerFrameworkBasic(final int x, final int y, final int z) { super(); this.x = x; this.y = y; + this.z = z; } -} +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/CheckerFrameworkBuilder.java b/test/transform/resource/after-ecj/CheckerFrameworkBuilder.java index 3f998df4..9a15cde8 100644 --- a/test/transform/resource/after-ecj/CheckerFrameworkBuilder.java +++ b/test/transform/resource/after-ecj/CheckerFrameworkBuilder.java @@ -8,29 +8,29 @@ import lombok.Singular; private @java.lang.SuppressWarnings("all") int y; private @java.lang.SuppressWarnings("all") int z; private @java.lang.SuppressWarnings("all") java.util.ArrayList<String> names; - @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") CheckerFrameworkBuilderBuilder() { + @java.lang.SuppressWarnings("all") CheckerFrameworkBuilderBuilder() { super(); } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder x(final @org.checkerframework.checker.builder.qual.NotCalledMethods("x") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder this, final int x) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder x(CheckerFrameworkBuilder.@org.checkerframework.checker.calledmethods.qual.NotCalledMethods("x") CheckerFrameworkBuilderBuilder this, final int x) { this.x$value = x; x$set = true; return this; } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder y(final @org.checkerframework.checker.builder.qual.NotCalledMethods("y") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder this, final int y) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder y(CheckerFrameworkBuilder.@org.checkerframework.checker.calledmethods.qual.NotCalledMethods("y") CheckerFrameworkBuilderBuilder this, final int y) { this.y = y; return this; } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder z(final @org.checkerframework.checker.builder.qual.NotCalledMethods("z") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder this, final int z) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder z(CheckerFrameworkBuilder.@org.checkerframework.checker.calledmethods.qual.NotCalledMethods("z") CheckerFrameworkBuilderBuilder this, final int z) { this.z = z; return this; } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder name(final String name) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder name(final String name) { if ((this.names == null)) this.names = new java.util.ArrayList<String>(); this.names.add(name); return this; } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder names(final java.util.Collection<? extends String> names) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder names(final java.util.Collection<? extends String> names) { if ((names == null)) { throw new java.lang.NullPointerException("names cannot be null"); @@ -40,12 +40,12 @@ import lombok.Singular; this.names.addAll(names); return this; } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder clearNames() { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder clearNames() { if ((this.names != null)) this.names.clear(); return this; } - public @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder build(final @org.checkerframework.checker.builder.qual.CalledMethods({"y", "z"}) CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder this) { + public @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder build(CheckerFrameworkBuilder.@org.checkerframework.checker.calledmethods.qual.CalledMethods({"y", "z"}) CheckerFrameworkBuilderBuilder this) { java.util.List<String> names; switch (((this.names == null) ? 0 : this.names.size())) { case 0 : @@ -73,14 +73,14 @@ import lombok.Singular; private static @java.lang.SuppressWarnings("all") int $default$x() { return 5; } - @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder(final int x, final int y, final int z, final List<String> names) { + @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder(final int x, final int y, final int z, final List<String> names) { super(); this.x = x; this.y = y; this.z = z; this.names = names; } - public static @org.checkerframework.common.aliasing.qual.Unique @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder builder() { + public static @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.@org.checkerframework.common.aliasing.qual.Unique CheckerFrameworkBuilderBuilder builder() { return new CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder(); } }
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/CheckerFrameworkSuperBuilder.java b/test/transform/resource/after-ecj/CheckerFrameworkSuperBuilder.java index 7c8ff0ed..e4cc405d 100644 --- a/test/transform/resource/after-ecj/CheckerFrameworkSuperBuilder.java +++ b/test/transform/resource/after-ecj/CheckerFrameworkSuperBuilder.java @@ -11,28 +11,28 @@ class CheckerFrameworkSuperBuilder { public ParentBuilder() { super(); } - protected abstract @org.checkerframework.checker.builder.qual.ReturnsReceiver @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") B self(); - public abstract @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") C build(final @org.checkerframework.checker.builder.qual.CalledMethods({"y", "z"}) CheckerFrameworkSuperBuilder.Parent.ParentBuilder this); - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B x(final @org.checkerframework.checker.builder.qual.NotCalledMethods("x") CheckerFrameworkSuperBuilder.Parent.ParentBuilder this, final int x) { + protected abstract @org.checkerframework.common.returnsreceiver.qual.This @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") B self(); + public abstract @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") C build(CheckerFrameworkSuperBuilder.Parent. @org.checkerframework.checker.calledmethods.qual.CalledMethods({"y", "z"}) ParentBuilder<C, B> this); + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B x(CheckerFrameworkSuperBuilder.Parent. @org.checkerframework.checker.calledmethods.qual.NotCalledMethods("x") ParentBuilder<C, B> this, final int x) { this.x$value = x; x$set = true; return self(); } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B y(final @org.checkerframework.checker.builder.qual.NotCalledMethods("y") CheckerFrameworkSuperBuilder.Parent.ParentBuilder this, final int y) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B y(CheckerFrameworkSuperBuilder.Parent. @org.checkerframework.checker.calledmethods.qual.NotCalledMethods("y") ParentBuilder<C, B> this, final int y) { this.y = y; return self(); } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B z(final @org.checkerframework.checker.builder.qual.NotCalledMethods("z") CheckerFrameworkSuperBuilder.Parent.ParentBuilder this, final int z) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B z(CheckerFrameworkSuperBuilder.Parent. @org.checkerframework.checker.calledmethods.qual.NotCalledMethods("z") ParentBuilder<C, B> this, final int z) { this.z = z; return self(); } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B name(final String name) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B name(final String name) { if ((this.names == null)) this.names = new java.util.ArrayList<String>(); this.names.add(name); return self(); } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B names(final java.util.Collection<? extends String> names) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B names(final java.util.Collection<? extends String> names) { if ((names == null)) { throw new java.lang.NullPointerException("names cannot be null"); @@ -42,7 +42,7 @@ class CheckerFrameworkSuperBuilder { this.names.addAll(names); return self(); } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B clearNames() { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B clearNames() { if ((this.names != null)) this.names.clear(); return self(); @@ -55,10 +55,10 @@ class CheckerFrameworkSuperBuilder { private ParentBuilderImpl() { super(); } - protected @java.lang.Override @org.checkerframework.checker.builder.qual.ReturnsReceiver @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl self() { + protected @java.lang.Override @org.checkerframework.common.returnsreceiver.qual.This @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl self() { return this; } - public @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.Parent build(final @org.checkerframework.checker.builder.qual.CalledMethods({"y", "z"}) CheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl this) { + public @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.Parent build(CheckerFrameworkSuperBuilder.Parent.@org.checkerframework.checker.calledmethods.qual.CalledMethods({"y", "z"}) ParentBuilderImpl this) { return new CheckerFrameworkSuperBuilder.Parent(this); } } @@ -69,7 +69,7 @@ class CheckerFrameworkSuperBuilder { private static @java.lang.SuppressWarnings("all") int $default$x() { return 5; } - protected @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") Parent(final CheckerFrameworkSuperBuilder.Parent.ParentBuilder<?, ?> b) { + protected @java.lang.SuppressWarnings("all") Parent(final CheckerFrameworkSuperBuilder.Parent.ParentBuilder<?, ?> b) { super(); if (b.x$set) this.x = b.x$value; @@ -90,7 +90,7 @@ class CheckerFrameworkSuperBuilder { } this.names = names; } - public static @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.Parent.ParentBuilder<?, ?> builder() { + public static @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.Parent. @org.checkerframework.common.aliasing.qual.Unique ParentBuilder<?, ?> builder() { return new CheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl(); } } @@ -102,14 +102,14 @@ class CheckerFrameworkSuperBuilder { public ZChildBuilder() { super(); } - protected abstract @java.lang.Override @org.checkerframework.checker.builder.qual.ReturnsReceiver @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") B self(); - public abstract @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") C build(final @org.checkerframework.checker.builder.qual.CalledMethods("b") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder this); - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B a(final @org.checkerframework.checker.builder.qual.NotCalledMethods("a") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder this, final int a) { + protected abstract @java.lang.Override @org.checkerframework.common.returnsreceiver.qual.This @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") C build(CheckerFrameworkSuperBuilder.ZChild. @org.checkerframework.checker.calledmethods.qual.CalledMethods("b") ZChildBuilder<C, B> this); + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B a(CheckerFrameworkSuperBuilder.ZChild. @org.checkerframework.checker.calledmethods.qual.NotCalledMethods("a") ZChildBuilder<C, B> this, final int a) { this.a$value = a; a$set = true; return self(); } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B b(final @org.checkerframework.checker.builder.qual.NotCalledMethods("b") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder this, final int b) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B b(CheckerFrameworkSuperBuilder.ZChild. @org.checkerframework.checker.calledmethods.qual.NotCalledMethods("b") ZChildBuilder<C, B> this, final int b) { this.b = b; return self(); } @@ -121,10 +121,10 @@ class CheckerFrameworkSuperBuilder { private ZChildBuilderImpl() { super(); } - protected @java.lang.Override @org.checkerframework.checker.builder.qual.ReturnsReceiver @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl self() { + protected @java.lang.Override @org.checkerframework.common.returnsreceiver.qual.This @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl self() { return this; } - public @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.ZChild build(final @org.checkerframework.checker.builder.qual.CalledMethods("b") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl this) { + public @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.ZChild build(CheckerFrameworkSuperBuilder.ZChild.@org.checkerframework.checker.calledmethods.qual.CalledMethods("b") ZChildBuilderImpl this) { return new CheckerFrameworkSuperBuilder.ZChild(this); } } @@ -133,7 +133,7 @@ class CheckerFrameworkSuperBuilder { private static @java.lang.SuppressWarnings("all") int $default$a() { return 1; } - protected @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") ZChild(final CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder<?, ?> b) { + protected @java.lang.SuppressWarnings("all") ZChild(final CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder<?, ?> b) { super(b); if (b.a$set) this.a = b.a$value; @@ -141,7 +141,7 @@ class CheckerFrameworkSuperBuilder { this.a = CheckerFrameworkSuperBuilder.ZChild.$default$a(); this.b = b.b; } - public static @org.checkerframework.common.aliasing.qual.Unique @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder<?, ?> builder() { + public static @java.lang.SuppressWarnings("all") CheckerFrameworkSuperBuilder.ZChild. @org.checkerframework.common.aliasing.qual.Unique ZChildBuilder<?, ?> builder() { return new CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl(); } } diff --git a/test/transform/resource/after-ecj/EqualsAndHashCodeCache.java b/test/transform/resource/after-ecj/EqualsAndHashCodeCache.java new file mode 100644 index 00000000..7094b636 --- /dev/null +++ b/test/transform/resource/after-ecj/EqualsAndHashCodeCache.java @@ -0,0 +1,189 @@ +@lombok.EqualsAndHashCode(cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) class EqualsAndHashCode { + private transient @java.lang.SuppressWarnings("all") int $hashCodeCache; + int x; + boolean[] y; + Object[] z; + String a; + String b; + EqualsAndHashCode() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof EqualsAndHashCode))) + return false; + final EqualsAndHashCode other = (EqualsAndHashCode) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((this.x != other.x)) + return false; + if ((! java.util.Arrays.equals(this.y, other.y))) + return false; + if ((! java.util.Arrays.deepEquals(this.z, other.z))) + return false; + final java.lang.Object this$a = this.a; + final java.lang.Object other$a = other.a; + if (((this$a == null) ? (other$a != null) : (! this$a.equals(other$a)))) + return false; + final java.lang.Object this$b = this.b; + final java.lang.Object other$b = other.b; + if (((this$b == null) ? (other$b != null) : (! this$b.equals(other$b)))) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof EqualsAndHashCode); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + if ((this.$hashCodeCache != 0)) + return this.$hashCodeCache; + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.x); + result = ((result * PRIME) + java.util.Arrays.hashCode(this.y)); + result = ((result * PRIME) + java.util.Arrays.deepHashCode(this.z)); + final java.lang.Object $a = this.a; + result = ((result * PRIME) + (($a == null) ? 43 : $a.hashCode())); + final java.lang.Object $b = this.b; + result = ((result * PRIME) + (($b == null) ? 43 : $b.hashCode())); + if ((result == 0)) + result = java.lang.Integer.MIN_VALUE; + this.$hashCodeCache = result; + return result; + } +} +final @lombok.EqualsAndHashCode(cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) class EqualsAndHashCode2 { + private transient @java.lang.SuppressWarnings("all") int $hashCodeCache; + int x; + long y; + float f; + double d; + boolean b; + EqualsAndHashCode2() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof EqualsAndHashCode2))) + return false; + final EqualsAndHashCode2 other = (EqualsAndHashCode2) o; + if ((this.x != other.x)) + return false; + if ((this.y != other.y)) + return false; + if ((java.lang.Float.compare(this.f, other.f) != 0)) + return false; + if ((java.lang.Double.compare(this.d, other.d) != 0)) + return false; + if ((this.b != other.b)) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + if ((this.$hashCodeCache != 0)) + return this.$hashCodeCache; + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.x); + final long $y = this.y; + result = ((result * PRIME) + (int) ($y ^ ($y >>> 32))); + result = ((result * PRIME) + java.lang.Float.floatToIntBits(this.f)); + final long $d = java.lang.Double.doubleToLongBits(this.d); + result = ((result * PRIME) + (int) ($d ^ ($d >>> 32))); + result = ((result * PRIME) + (this.b ? 79 : 97)); + if ((result == 0)) + result = java.lang.Integer.MIN_VALUE; + this.$hashCodeCache = result; + return result; + } +} +final @lombok.EqualsAndHashCode(callSuper = false,cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) class EqualsAndHashCode3 extends EqualsAndHashCode { + private transient @java.lang.SuppressWarnings("all") int $hashCodeCache; + EqualsAndHashCode3() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof EqualsAndHashCode3))) + return false; + final EqualsAndHashCode3 other = (EqualsAndHashCode3) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof EqualsAndHashCode3); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + if ((this.$hashCodeCache != 0)) + return this.$hashCodeCache; + int result = 1; + if ((result == 0)) + result = java.lang.Integer.MIN_VALUE; + this.$hashCodeCache = result; + return result; + } +} +@lombok.EqualsAndHashCode(callSuper = true,cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) class EqualsAndHashCode4 extends EqualsAndHashCode { + private transient @java.lang.SuppressWarnings("all") int $hashCodeCache; + EqualsAndHashCode4() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof EqualsAndHashCode4))) + return false; + final EqualsAndHashCode4 other = (EqualsAndHashCode4) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((! super.equals(o))) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof EqualsAndHashCode4); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + if ((this.$hashCodeCache != 0)) + return this.$hashCodeCache; + int result = super.hashCode(); + if ((result == 0)) + result = java.lang.Integer.MIN_VALUE; + this.$hashCodeCache = result; + return result; + } +} +final @lombok.EqualsAndHashCode(callSuper = true,cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) class EqualsAndHashCode5 extends EqualsAndHashCode { + private transient @java.lang.SuppressWarnings("all") int $hashCodeCache; + EqualsAndHashCode5() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof EqualsAndHashCode5))) + return false; + final EqualsAndHashCode5 other = (EqualsAndHashCode5) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((! super.equals(o))) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof EqualsAndHashCode5); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + if ((this.$hashCodeCache != 0)) + return this.$hashCodeCache; + int result = super.hashCode(); + if ((result == 0)) + result = java.lang.Integer.MIN_VALUE; + this.$hashCodeCache = result; + return result; + } +} diff --git a/test/transform/resource/after-ecj/GetterSetterJavadocEcj.java b/test/transform/resource/after-ecj/GetterSetterJavadocEcj.java new file mode 100644 index 00000000..83c9c3a5 --- /dev/null +++ b/test/transform/resource/after-ecj/GetterSetterJavadocEcj.java @@ -0,0 +1,86 @@ +@lombok.Data class GetterSetterJavadoc1 { + private int fieldName; + public @java.lang.SuppressWarnings("all") int getFieldName() { + return this.fieldName; + } + public @java.lang.SuppressWarnings("all") void setFieldName(final int fieldName) { + this.fieldName = fieldName; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof GetterSetterJavadoc1))) + return false; + final GetterSetterJavadoc1 other = (GetterSetterJavadoc1) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((this.getFieldName() != other.getFieldName())) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) { + return (other instanceof GetterSetterJavadoc1); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.getFieldName()); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("GetterSetterJavadoc1(fieldName=" + this.getFieldName()) + ")"); + } + public @java.lang.SuppressWarnings("all") GetterSetterJavadoc1() { + super(); + } +} +class GetterSetterJavadoc2 { + private @lombok.Getter @lombok.Setter int fieldName; + GetterSetterJavadoc2() { + super(); + } + public @java.lang.SuppressWarnings("all") int getFieldName() { + return this.fieldName; + } + public @java.lang.SuppressWarnings("all") void setFieldName(final int fieldName) { + this.fieldName = fieldName; + } +} +class GetterSetterJavadoc3 { + private @lombok.Getter @lombok.Setter int fieldName; + GetterSetterJavadoc3() { + super(); + } + public @java.lang.SuppressWarnings("all") int getFieldName() { + return this.fieldName; + } + public @java.lang.SuppressWarnings("all") void setFieldName(final int fieldName) { + this.fieldName = fieldName; + } +} +@lombok.experimental.Accessors(chain = true,fluent = true) class GetterSetterJavadoc4 { + private @lombok.Getter @lombok.Setter int fieldName; + GetterSetterJavadoc4() { + super(); + } + public @java.lang.SuppressWarnings("all") int fieldName() { + return this.fieldName; + } + public @java.lang.SuppressWarnings("all") GetterSetterJavadoc4 fieldName(final int fieldName) { + this.fieldName = fieldName; + return this; + } +} +@lombok.experimental.Accessors(chain = true,fluent = true) class GetterSetterJavadoc5 { + private @lombok.Getter @lombok.Setter int fieldName; + GetterSetterJavadoc5() { + super(); + } + public @java.lang.SuppressWarnings("all") int fieldName() { + return this.fieldName; + } + public @java.lang.SuppressWarnings("all") GetterSetterJavadoc5 fieldName(final int fieldName) { + this.fieldName = fieldName; + return this; + } +} diff --git a/test/transform/resource/after-ecj/SetterDeprecatedEcj.java b/test/transform/resource/after-ecj/SetterDeprecatedEcj.java new file mode 100644 index 00000000..d76612b7 --- /dev/null +++ b/test/transform/resource/after-ecj/SetterDeprecatedEcj.java @@ -0,0 +1,14 @@ +import lombok.Setter; +class SetterDeprecated { + @Deprecated @Setter int annotation; + @Setter int javadoc; + SetterDeprecated() { + super(); + } + public @java.lang.Deprecated @java.lang.SuppressWarnings("all") void setAnnotation(final int annotation) { + this.annotation = annotation; + } + public @java.lang.Deprecated @java.lang.SuppressWarnings("all") void setJavadoc(final int javadoc) { + this.javadoc = javadoc; + } +} diff --git a/test/transform/resource/after-ecj/WithMethodMarkedDeprecatedAnnOnly.java b/test/transform/resource/after-ecj/WithMethodMarkedDeprecatedAnnOnly.java new file mode 100644 index 00000000..1dcee0d8 --- /dev/null +++ b/test/transform/resource/after-ecj/WithMethodMarkedDeprecatedAnnOnly.java @@ -0,0 +1,11 @@ +import lombok.With; +class WithMethodMarkedDeprecatedAnnOnly { + @Deprecated @With int annotation; + WithMethodMarkedDeprecatedAnnOnly(int annotation) { + super(); + } + public @java.lang.Deprecated @java.lang.SuppressWarnings("all") WithMethodMarkedDeprecatedAnnOnly withAnnotation(final int annotation) { + return ((this.annotation == annotation) ? this : new WithMethodMarkedDeprecatedAnnOnly(annotation)); + } +} + diff --git a/test/transform/resource/before/BuilderJavadoc.java b/test/transform/resource/before/BuilderJavadoc.java index 390e2096..d966af28 100644 --- a/test/transform/resource/before/BuilderJavadoc.java +++ b/test/transform/resource/before/BuilderJavadoc.java @@ -1,3 +1,4 @@ +//platform !ecj: Javadoc copying not supported on ecj import java.util.List; @lombok.Builder diff --git a/test/transform/resource/before/BuilderWithDeprecated.java b/test/transform/resource/before/BuilderWithDeprecated.java index 1641ccb4..1b41444c 100644 --- a/test/transform/resource/before/BuilderWithDeprecated.java +++ b/test/transform/resource/before/BuilderWithDeprecated.java @@ -1,3 +1,4 @@ +//platform !ecj: Javadoc copying not supported on ecj import com.google.common.collect.ImmutableList; import lombok.Builder; import lombok.Singular; diff --git a/test/transform/resource/before/BuilderWithDeprecatedAnnOnly.java b/test/transform/resource/before/BuilderWithDeprecatedAnnOnly.java new file mode 100644 index 00000000..1d2d199c --- /dev/null +++ b/test/transform/resource/before/BuilderWithDeprecatedAnnOnly.java @@ -0,0 +1,10 @@ +import com.google.common.collect.ImmutableList; +import lombok.Builder; +import lombok.Singular; + +@Builder +public class BuilderWithDeprecatedAnnOnly { + @Deprecated int dep1; + @Singular @Deprecated java.util.List<String> strings; + @Singular @Deprecated ImmutableList<Integer> numbers; +} diff --git a/test/transform/resource/before/CheckerFrameworkBasic.java b/test/transform/resource/before/CheckerFrameworkBasic.java index 8a0bd118..fb43ad08 100644 --- a/test/transform/resource/before/CheckerFrameworkBasic.java +++ b/test/transform/resource/before/CheckerFrameworkBasic.java @@ -1,9 +1,10 @@ //CONF: checkerframework = 4.0 +import lombok.AllArgsConstructor; import lombok.Data; import lombok.experimental.Accessors; import lombok.With; -@Data @Accessors(chain = true) +@Data @AllArgsConstructor @Accessors(chain = true) class CheckerFrameworkBasic { @With private final int x; private final int y; diff --git a/test/transform/resource/before/DelegateAlreadyImplemented.java b/test/transform/resource/before/DelegateAlreadyImplemented.java index c43c1949..feaf3c4b 100644 --- a/test/transform/resource/before/DelegateAlreadyImplemented.java +++ b/test/transform/resource/before/DelegateAlreadyImplemented.java @@ -1,3 +1,4 @@ +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. public class DelegateAlreadyImplemented<T> { @lombok.experimental.Delegate diff --git a/test/transform/resource/before/DelegateFlagUsage.java b/test/transform/resource/before/DelegateFlagUsage.java index 1f274e24..0b52c764 100644 --- a/test/transform/resource/before/DelegateFlagUsage.java +++ b/test/transform/resource/before/DelegateFlagUsage.java @@ -1,3 +1,4 @@ +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. //conf: lombok.delegate.flagUsage = warning //skip compare content: We're just checking if the flagUsage key works. public class DelegateFlagUsage { diff --git a/test/transform/resource/before/DelegateGenerics.java b/test/transform/resource/before/DelegateGenerics.java index e89158a9..f00c90aa 100644 --- a/test/transform/resource/before/DelegateGenerics.java +++ b/test/transform/resource/before/DelegateGenerics.java @@ -1,3 +1,4 @@ +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. public class DelegateGenerics<T> { @lombok.experimental.Delegate I1<T> target; diff --git a/test/transform/resource/before/DelegateOnGetter.java b/test/transform/resource/before/DelegateOnGetter.java index afe09ff4..ad9d1cfb 100644 --- a/test/transform/resource/before/DelegateOnGetter.java +++ b/test/transform/resource/before/DelegateOnGetter.java @@ -1,3 +1,4 @@ +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. import lombok.Delegate; import lombok.Getter; diff --git a/test/transform/resource/before/DelegateOnGetterNone.java b/test/transform/resource/before/DelegateOnGetterNone.java index f9a97e6a..cd471369 100644 --- a/test/transform/resource/before/DelegateOnGetterNone.java +++ b/test/transform/resource/before/DelegateOnGetterNone.java @@ -1,3 +1,4 @@ +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. import lombok.AccessLevel; import lombok.experimental.Delegate; import lombok.Getter; diff --git a/test/transform/resource/before/DelegateOnMethods.java b/test/transform/resource/before/DelegateOnMethods.java index 79189cc1..4ea70d74 100644 --- a/test/transform/resource/before/DelegateOnMethods.java +++ b/test/transform/resource/before/DelegateOnMethods.java @@ -1,3 +1,4 @@ +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. import lombok.experimental.Delegate; abstract class DelegateOnMethods { diff --git a/test/transform/resource/before/DelegateOnStatic.java b/test/transform/resource/before/DelegateOnStatic.java index 7a420b20..b9b728bc 100644 --- a/test/transform/resource/before/DelegateOnStatic.java +++ b/test/transform/resource/before/DelegateOnStatic.java @@ -1,3 +1,4 @@ +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. //skip compare content import lombok.experimental.Delegate; import lombok.Getter; diff --git a/test/transform/resource/before/DelegateRecursion.java b/test/transform/resource/before/DelegateRecursion.java index d74107e2..c6428d06 100644 --- a/test/transform/resource/before/DelegateRecursion.java +++ b/test/transform/resource/before/DelegateRecursion.java @@ -1,3 +1,4 @@ +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. //skip compare content: This test is to see if the 'delegate recursion is not supported' error pops up. import lombok.experimental.Delegate; class DelegateRecursionOuterMost { diff --git a/test/transform/resource/before/DelegateTypesAndExcludes.java b/test/transform/resource/before/DelegateTypesAndExcludes.java index 164261d8..2c0f8770 100644 --- a/test/transform/resource/before/DelegateTypesAndExcludes.java +++ b/test/transform/resource/before/DelegateTypesAndExcludes.java @@ -1,3 +1,4 @@ +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. import lombok.experimental.Delegate; class DelegatePlain { @Delegate(types = Bar.class) diff --git a/test/transform/resource/before/DelegateWithDeprecated.java b/test/transform/resource/before/DelegateWithDeprecated.java index a0deb788..bf3519b3 100644 --- a/test/transform/resource/before/DelegateWithDeprecated.java +++ b/test/transform/resource/before/DelegateWithDeprecated.java @@ -1,3 +1,4 @@ +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. import lombok.experimental.Delegate; class DelegateWithDeprecated { diff --git a/test/transform/resource/before/DelegateWithVarargs.java b/test/transform/resource/before/DelegateWithVarargs.java index 0c266620..91519884 100644 --- a/test/transform/resource/before/DelegateWithVarargs.java +++ b/test/transform/resource/before/DelegateWithVarargs.java @@ -1,3 +1,4 @@ +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. import lombok.experimental.Delegate; class DelegateWithVarargs { diff --git a/test/transform/resource/before/DelegateWithVarargs2.java b/test/transform/resource/before/DelegateWithVarargs2.java index 8a3dbf14..bc3fdf09 100644 --- a/test/transform/resource/before/DelegateWithVarargs2.java +++ b/test/transform/resource/before/DelegateWithVarargs2.java @@ -1,3 +1,4 @@ +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. import lombok.experimental.Delegate; class DelegateWithVarargs2 { diff --git a/test/transform/resource/before/EqualsAndHashCodeCache.java b/test/transform/resource/before/EqualsAndHashCodeCache.java new file mode 100644 index 00000000..3c84ee59 --- /dev/null +++ b/test/transform/resource/before/EqualsAndHashCodeCache.java @@ -0,0 +1,29 @@ +@lombok.EqualsAndHashCode(cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) +class EqualsAndHashCode { + int x; + boolean[] y; + Object[] z; + String a; + String b; +} + +@lombok.EqualsAndHashCode(cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) +final class EqualsAndHashCode2 { + int x; + long y; + float f; + double d; + boolean b; +} + +@lombok.EqualsAndHashCode(callSuper=false, cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) +final class EqualsAndHashCode3 extends EqualsAndHashCode { +} + +@lombok.EqualsAndHashCode(callSuper=true, cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) +class EqualsAndHashCode4 extends EqualsAndHashCode { +} + +@lombok.EqualsAndHashCode(callSuper=true, cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) +final class EqualsAndHashCode5 extends EqualsAndHashCode { +}
\ No newline at end of file diff --git a/test/transform/resource/before/GetterDeprecated.java b/test/transform/resource/before/GetterDeprecated.java index 01b66bca..9d67297b 100644 --- a/test/transform/resource/before/GetterDeprecated.java +++ b/test/transform/resource/before/GetterDeprecated.java @@ -1,3 +1,4 @@ +//platform !ecj: Javadoc copying not supported on ecj import lombok.Getter; class GetterDeprecated { @@ -8,4 +9,4 @@ class GetterDeprecated { * @deprecated */ @Getter int javadoc; -}
\ No newline at end of file +} diff --git a/test/transform/resource/before/GetterSetterJavadoc.java b/test/transform/resource/before/GetterSetterJavadoc.java index 2ad46f8d..44b970e8 100644 --- a/test/transform/resource/before/GetterSetterJavadoc.java +++ b/test/transform/resource/before/GetterSetterJavadoc.java @@ -1,3 +1,4 @@ +//platform !ecj: Javadoc copying not supported on ecj @lombok.Data class GetterSetterJavadoc1 { /** diff --git a/test/transform/resource/before/GetterSetterJavadocEcj.java b/test/transform/resource/before/GetterSetterJavadocEcj.java new file mode 100644 index 00000000..1c24851c --- /dev/null +++ b/test/transform/resource/before/GetterSetterJavadocEcj.java @@ -0,0 +1,65 @@ +//platform ecj: Javadoc copying not supported on ecj - testing that the javadoc doesnt cause any crashes +@lombok.Data +class GetterSetterJavadoc1 { + /** + * Some text + * + * @param fieldName Hello, World1 + * --- GETTER --- + * Getter section + * + * @return Sky is blue1 + */ + private int fieldName; +} + +class GetterSetterJavadoc2 { + /** + * Some text + * + * @param fieldName Hello, World2 + * @return Sky is blue2 + */ + @lombok.Getter @lombok.Setter private int fieldName; +} + +class GetterSetterJavadoc3 { + /** + * Some text + * + * **SETTER** + * Setter section + * @param fieldName Hello, World3 + * **GETTER** + * Getter section + * @return Sky is blue3 + */ + @lombok.Getter @lombok.Setter private int fieldName; +} + +@lombok.experimental.Accessors(chain = true, fluent = true) +class GetterSetterJavadoc4 { + /** + * Some text + * + * @param fieldName Hello, World4 + * @return Sky is blue4 + */ + @lombok.Getter @lombok.Setter private int fieldName; +} + +@lombok.experimental.Accessors(chain = true, fluent = true) +class GetterSetterJavadoc5 { + /** + * Some text + * + * **SETTER** + * Setter section + * @param fieldName Hello, World5 + * @return Sky is blue5 + * **GETTER** + * Getter section + * @return Sky is blue5 + */ + @lombok.Getter @lombok.Setter private int fieldName; +} diff --git a/test/transform/resource/before/OnXJava7StyleOn8.java b/test/transform/resource/before/OnXJava7StyleOn8.java index 582fe6ce..94865c97 100644 --- a/test/transform/resource/before/OnXJava7StyleOn8.java +++ b/test/transform/resource/before/OnXJava7StyleOn8.java @@ -1,4 +1,4 @@ -//platform ecj +//platform ecj,eclipse //version 8: public class OnXJava7StyleOn8 { diff --git a/test/transform/resource/before/OnXJava8StyleOn7.java b/test/transform/resource/before/OnXJava8StyleOn7.java index c006e468..98f76451 100644 --- a/test/transform/resource/before/OnXJava8StyleOn7.java +++ b/test/transform/resource/before/OnXJava8StyleOn7.java @@ -1,4 +1,4 @@ -//platform ecj +//platform ecj,eclipse //version :7 public class OnXJava8StyleOn7 { diff --git a/test/transform/resource/before/SetterAndWithMethodJavadoc.java b/test/transform/resource/before/SetterAndWithMethodJavadoc.java index ba10b7f2..0317cf27 100644 --- a/test/transform/resource/before/SetterAndWithMethodJavadoc.java +++ b/test/transform/resource/before/SetterAndWithMethodJavadoc.java @@ -1,3 +1,4 @@ +//platform !ecj: Javadoc copying not supported on ecj import lombok.With; class SetterAndWithMethodJavadoc { /** diff --git a/test/transform/resource/before/SetterDeprecated.java b/test/transform/resource/before/SetterDeprecated.java index e655622f..a4c2ea94 100644 --- a/test/transform/resource/before/SetterDeprecated.java +++ b/test/transform/resource/before/SetterDeprecated.java @@ -1,3 +1,4 @@ +//platform !ecj: Javadoc copying not supported on ecj import lombok.Setter; class SetterDeprecated { @@ -8,4 +9,4 @@ class SetterDeprecated { * @deprecated */ @Setter int javadoc; -}
\ No newline at end of file +} diff --git a/test/transform/resource/before/SetterDeprecatedEcj.java b/test/transform/resource/before/SetterDeprecatedEcj.java new file mode 100644 index 00000000..361a4fb7 --- /dev/null +++ b/test/transform/resource/before/SetterDeprecatedEcj.java @@ -0,0 +1,12 @@ +//platform ecj: Javadoc copying not supported on ecj +import lombok.Setter; +class SetterDeprecated { + + @Deprecated + @Setter int annotation; + + /** + * @deprecated + */ + @Setter int javadoc; +} diff --git a/test/transform/resource/before/ValDelegateMethodReference.java b/test/transform/resource/before/ValDelegateMethodReference.java index 7adc402a..21b781aa 100644 --- a/test/transform/resource/before/ValDelegateMethodReference.java +++ b/test/transform/resource/before/ValDelegateMethodReference.java @@ -1,4 +1,4 @@ - +//platform !eclipse: Requires a 'full' eclipse with intialized workspace, and we don't (yet) have that set up properly in the test run. import lombok.Getter; import lombok.Setter; import lombok.experimental.Delegate; diff --git a/test/transform/resource/before/WithMethodMarkedDeprecated.java b/test/transform/resource/before/WithMethodMarkedDeprecated.java index 7a6549e5..659ea1de 100644 --- a/test/transform/resource/before/WithMethodMarkedDeprecated.java +++ b/test/transform/resource/before/WithMethodMarkedDeprecated.java @@ -1,3 +1,4 @@ +//platform !ecj: Javadoc copying not supported on ecj import lombok.With; class WithMethodMarkedDeprecated { diff --git a/test/transform/resource/before/WithMethodMarkedDeprecatedAnnOnly.java b/test/transform/resource/before/WithMethodMarkedDeprecatedAnnOnly.java new file mode 100644 index 00000000..50509545 --- /dev/null +++ b/test/transform/resource/before/WithMethodMarkedDeprecatedAnnOnly.java @@ -0,0 +1,10 @@ +import lombok.With; + +class WithMethodMarkedDeprecatedAnnOnly { + + @Deprecated + @With int annotation; + + WithMethodMarkedDeprecatedAnnOnly(int annotation) { + } +}
\ No newline at end of file diff --git a/test/transform/resource/messages-delombok/CheckerFrameworkBasic.java.messages b/test/transform/resource/messages-delombok/CheckerFrameworkBasic.java.messages deleted file mode 100644 index 9ee959a4..00000000 --- a/test/transform/resource/messages-delombok/CheckerFrameworkBasic.java.messages +++ /dev/null @@ -1,4 +0,0 @@ -6 package org.checkerframework.common.aliasing.qual does not exist -8 package org.checkerframework.dataflow.qual does not exist -9 package org.checkerframework.dataflow.qual does not exist -10 package org.checkerframework.dataflow.qual does not exist diff --git a/test/transform/resource/messages-delombok/CheckerFrameworkBuilder.java.messages b/test/transform/resource/messages-delombok/CheckerFrameworkBuilder.java.messages deleted file mode 100644 index 8c736705..00000000 --- a/test/transform/resource/messages-delombok/CheckerFrameworkBuilder.java.messages +++ /dev/null @@ -1 +0,0 @@ -6 package org.checkerframework.common.aliasing.qual does not exist diff --git a/test/transform/resource/messages-delombok/CheckerFrameworkSuperBuilder.java.messages b/test/transform/resource/messages-delombok/CheckerFrameworkSuperBuilder.java.messages deleted file mode 100644 index 5dd6251a..00000000 --- a/test/transform/resource/messages-delombok/CheckerFrameworkSuperBuilder.java.messages +++ /dev/null @@ -1,3 +0,0 @@ -6 package org.checkerframework.dataflow.qual does not exist --1 package org.checkerframework.checker.builder.qual does not exist -14 package org.checkerframework.dataflow.qual does not exist diff --git a/test/transform/resource/messages-ecj/CheckerFrameworkBasic.java.messages b/test/transform/resource/messages-ecj/CheckerFrameworkBasic.java.messages deleted file mode 100644 index 8cc7fb58..00000000 --- a/test/transform/resource/messages-ecj/CheckerFrameworkBasic.java.messages +++ /dev/null @@ -1 +0,0 @@ -6 org.checkerframework.common cannot be resolved to a type diff --git a/test/transform/resource/messages-ecj/CheckerFrameworkBuilder.java.messages b/test/transform/resource/messages-ecj/CheckerFrameworkBuilder.java.messages deleted file mode 100644 index d385a95c..00000000 --- a/test/transform/resource/messages-ecj/CheckerFrameworkBuilder.java.messages +++ /dev/null @@ -1 +0,0 @@ -6 org.checkerframework cannot be resolved to a type diff --git a/test/transform/resource/messages-ecj/CheckerFrameworkSuperBuilder.java.messages b/test/transform/resource/messages-ecj/CheckerFrameworkSuperBuilder.java.messages deleted file mode 100644 index 8cc7fb58..00000000 --- a/test/transform/resource/messages-ecj/CheckerFrameworkSuperBuilder.java.messages +++ /dev/null @@ -1 +0,0 @@ -6 org.checkerframework.common cannot be resolved to a type diff --git a/test/transform/resource/messages-idempotent/CheckerFrameworkBasic.java.messages b/test/transform/resource/messages-idempotent/CheckerFrameworkBasic.java.messages deleted file mode 100644 index 80694a06..00000000 --- a/test/transform/resource/messages-idempotent/CheckerFrameworkBasic.java.messages +++ /dev/null @@ -1,10 +0,0 @@ -5 package org.checkerframework.common.aliasing.qual does not exist -11 package org.checkerframework.dataflow.qual does not exist -16 package org.checkerframework.dataflow.qual does not exist -21 package org.checkerframework.dataflow.qual does not exist -26 package org.checkerframework.checker.builder.qual does not exist -32 package org.checkerframework.dataflow.qual does not exist -45 package org.checkerframework.dataflow.qual does not exist -50 package org.checkerframework.dataflow.qual does not exist -61 package org.checkerframework.dataflow.qual does not exist -67 package org.checkerframework.dataflow.qual does not exist |