From 14cce76805324dce66fcdfde333a63c677694d64 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Sat, 3 Oct 2020 23:55:10 +0200 Subject: [PATCH] [builder] big refactor: Fixing CheckerFramework features + all params now in an object These handlers had methods with humongous argument lists, and they needed to grow even more in order to accommodate some new needs to properly implement checkerframework (where annos can be type-use based, which means they were being put in the wrong place. void foo(com.foo.@X Bar paramName) // correct void foo(@X com.foo.Bar paramName) // wrong For example, the CalledMethod annotation is a type-use annotation. This commit covers both that refactor and fixing checkerframework generation. --- .../eclipse/handlers/HandleBuilder.java | 218 ++++--- .../eclipse/handlers/HandleConstructor.java | 15 +- .../eclipse/handlers/HandleSuperBuilder.java | 517 ++++++++------- .../lombok/javac/handlers/HandleBuilder.java | 554 +++++++++------- .../javac/handlers/HandleConstructor.java | 6 +- .../handlers/HandleEqualsAndHashCode.java | 2 +- .../lombok/javac/handlers/HandleGetter.java | 2 +- .../lombok/javac/handlers/HandleSetter.java | 33 +- .../javac/handlers/HandleSuperBuilder.java | 610 ++++++++++-------- .../javac/handlers/JavacSingularsRecipes.java | 17 +- .../singulars/JavacGuavaSingularizer.java | 2 +- .../JavacJavaUtilListSingularizer.java | 2 +- .../singulars/JavacJavaUtilSingularizer.java | 6 +- .../after-delombok/CheckerFrameworkBasic.java | 14 +- .../CheckerFrameworkBuilder.java | 26 +- .../CheckerFrameworkSuperBuilder.java | 44 +- .../after-ecj/CheckerFrameworkBasic.java | 10 +- .../after-ecj/CheckerFrameworkBuilder.java | 20 +- .../CheckerFrameworkSuperBuilder.java | 40 +- .../before/CheckerFrameworkBasic.java | 3 +- .../CheckerFrameworkBasic.java.messages | 4 - .../CheckerFrameworkBuilder.java.messages | 1 - ...CheckerFrameworkSuperBuilder.java.messages | 3 - .../CheckerFrameworkBasic.java.messages | 1 - .../CheckerFrameworkBuilder.java.messages | 1 - ...CheckerFrameworkSuperBuilder.java.messages | 1 - .../CheckerFrameworkBasic.java.messages | 10 - 27 files changed, 1163 insertions(+), 999 deletions(-) delete mode 100644 test/transform/resource/messages-delombok/CheckerFrameworkBasic.java.messages delete mode 100644 test/transform/resource/messages-delombok/CheckerFrameworkBuilder.java.messages delete mode 100644 test/transform/resource/messages-delombok/CheckerFrameworkSuperBuilder.java.messages delete mode 100644 test/transform/resource/messages-ecj/CheckerFrameworkBasic.java.messages delete mode 100644 test/transform/resource/messages-ecj/CheckerFrameworkBuilder.java.messages delete mode 100644 test/transform/resource/messages-ecj/CheckerFrameworkSuperBuilder.java.messages delete mode 100644 test/transform/resource/messages-idempotent/CheckerFrameworkBasic.java.messages diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 5bda6e1a52..f8eb9ed0d2 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -106,8 +106,16 @@ public class HandleBuilder extends EclipseAnnotationHandler { 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; @@ -118,22 +126,28 @@ private static final boolean toBoolean(Object expr, boolean defaultValue) { static class BuilderJob { CheckerFrameworkVersion checkerFramework; - EclipseNode builderTypeParent, builderType; - String builderClassName, builderMethodName, buildMethodName, toBuilderMethodName; + EclipseNode parentType; + String builderMethodName, buildMethodName; boolean isStatic; TypeParameter[] typeParams; + TypeParameter[] builderTypeParams; ASTNode source; EclipseNode sourceNode; List builderFields; AccessLevel accessInners, accessOuters; boolean oldFluent, oldChain, toBuilder; - TypeParameter[] copyTypeParams() { - return EclipseHandlerUtil.copyTypeParams(typeParams, source); + EclipseNode builderType; + String builderClassName; + char[] builderClassNameArr; + + void setBuilderClassName(String builderClassName) { + this.builderClassName = builderClassName; + this.builderClassNameArr = builderClassName.toCharArray(); } - char[] getBuilderClassName() { - return builderClassName.toCharArray(); + TypeParameter[] copyTypeParams() { + return EclipseHandlerUtil.copyTypeParams(typeParams, source); } long getPos() { @@ -141,22 +155,22 @@ long getPos() { } public TypeReference createBuilderTypeReference() { - return namePlusTypeParamsToTypeReference(builderTypeParent, getBuilderClassName(), !isStatic, typeParams, getPos()); + return namePlusTypeParamsToTypeReference(parentType, builderClassNameArr, !isStatic, builderTypeParams, getPos()); } public TypeReference createBuilderTypeReferenceForceStatic() { - return namePlusTypeParamsToTypeReference(builderTypeParent, getBuilderClassName(), false, typeParams, getPos()); + return namePlusTypeParamsToTypeReference(parentType, builderClassNameArr, false, builderTypeParams, getPos()); } public TypeReference createBuilderParentTypeReference() { - return namePlusTypeParamsToTypeReference(builderTypeParent, typeParams, getPos()); + return namePlusTypeParamsToTypeReference(parentType, typeParams, getPos()); } public EclipseNode getTopNode() { - return builderTypeParent.top(); + return parentType.top(); } - public void init(AnnotationValues node, Builder ann) { + void init(AnnotationValues annValues, Builder ann, EclipseNode node) { accessOuters = ann.access(); if (accessOuters == null) accessOuters = AccessLevel.PUBLIC; if (accessOuters == AccessLevel.NONE) { @@ -166,23 +180,37 @@ public void init(AnnotationValues node, Builder ann) { 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(node.getActualExpression("fluent"), true); - oldChain = toBoolean(node.getActualExpression("chain"), true); + oldFluent = toBoolean(annValues.getActualExpression("fluent"), true); + oldChain = toBoolean(annValues.getActualExpression("chain"), true); builderMethodName = ann.builderMethodName(); buildMethodName = ann.buildMethodName(); - builderClassName = ann.builderClassName(); - toBuilderMethodName = "toBuilder"; + setBuilderClassName(fixBuilderClassName(node, ann.builderClassName())); toBuilder = ann.toBuilder(); if (builderMethodName == null) builderMethodName = "builder"; if (buildMethodName == null) buildMethodName = "build"; - if (builderClassName == null) builderClassName = ""; } - public MethodDeclaration createNewMethodDeclaration() { + 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 { @@ -219,10 +247,6 @@ private static boolean equals(String a, char[][] b) { 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); @@ -236,9 +260,10 @@ private static final char[] prefixWith(char[] prefix, char[] name) { job.sourceNode = annotationNode; job.source = ast; job.checkerFramework = getCheckerFrameworkVersion(annotationNode); + job.isStatic = true; Builder annInstance = annotation.getInstance(); - job.init(annotation, annInstance); + job.init(annotation, annInstance, annotationNode); List typeArgsForToBuilder = null; boolean generateBuilderMethod; @@ -251,45 +276,35 @@ private static final char[] prefixWith(char[] prefix, char[] name) { } if (!checkName("buildMethodName", job.buildMethodName, annotationNode)) return; - if (!job.builderClassName.isEmpty()) { - if (!checkName("builderClassName", job.builderClassName, annotationNode)) return; - } EclipseNode parent = annotationNode.up(); job.builderFields = new ArrayList(); TypeReference buildMethodReturnType; TypeReference[] buildMethodThrownExceptions; - char[] nameOfStaticBuilderMethod; + char[] nameOfBuilderMethod; EclipseNode fillParametersFrom = parent.get() instanceof AbstractMethodDeclaration ? parent : null; boolean addCleaning = false; - job.isStatic = true; List nonFinalNonDefaultedFields = null; - if (job.builderClassName.isEmpty()) job.builderClassName = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME); - if (job.builderClassName == null || job.builderClassName.isEmpty()) job.builderClassName = "*Builder"; - boolean replaceNameInBuilderClassName = job.builderClassName.contains("*"); - if (parent.get() instanceof TypeDeclaration) { - job.builderTypeParent = parent; - TypeDeclaration td = (TypeDeclaration) job.builderTypeParent.get(); + job.parentType = parent; + TypeDeclaration td = (TypeDeclaration) parent.get(); List allFields = new ArrayList(); boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent)); - for (EclipseNode fieldNode : HandleConstructor.findAllFields(job.builderTypeParent, 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, annInstance.setterPrefix()); bfd.originalFieldNode = fieldNode; @@ -316,22 +331,22 @@ private static final char[] prefixWith(char[] prefix, char[] name) { bfd.builderFieldName = prefixWith(bfd.name, VALUE_PREFIX); MethodDeclaration md = generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast); - if (md != null) injectMethod(job.builderTypeParent, md); + if (md != null) injectMethod(parent, md); } addObtainVia(bfd, fieldNode); job.builderFields.add(bfd); allFields.add(fieldNode); } - handleConstructor.generateConstructor(job.builderTypeParent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER, + handleConstructor.generateConstructor(parent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER, Collections.emptyList(), annotationNode); - job.typeParams = td.typeParameters; + job.typeParams = job.builderTypeParams = td.typeParameters; buildMethodReturnType = job.createBuilderParentTypeReference(); buildMethodThrownExceptions = null; - nameOfStaticBuilderMethod = null; - if (replaceNameInBuilderClassName) job.builderClassName = job.builderClassName.replace("*", new String(td.name)); - replaceNameInBuilderClassName = false; + 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) { @@ -339,21 +354,20 @@ private static final char[] prefixWith(char[] prefix, char[] name) { return; } - job.builderTypeParent = parent.up(); - TypeDeclaration td = (TypeDeclaration) job.builderTypeParent.get(); - job.typeParams = td.typeParameters; + job.parentType = parent.up(); + TypeDeclaration td = (TypeDeclaration) job.parentType.get(); + job.typeParams = job.builderTypeParams = td.typeParameters; buildMethodReturnType = job.createBuilderParentTypeReference(); buildMethodThrownExceptions = cd.thrownExceptions; - nameOfStaticBuilderMethod = null; - if (replaceNameInBuilderClassName) job.builderClassName = job.builderClassName.replace("*", new String(cd.selector)); - replaceNameInBuilderClassName = false; + 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(); - job.builderTypeParent = parent.up(); + job.parentType = parent.up(); job.isStatic = md.isStatic(); if (job.toBuilder) { - final String TO_BUILDER_NOT_SUPPORTED = "@Builder(toBuilder=true) is only supported if you return your own type."; char[] token; char[][] pkg = null; if (md.returnType.dimensions() > 0) { @@ -379,12 +393,12 @@ private static final char[] prefixWith(char[] prefix, char[] name) { return; } - if (job.builderTypeParent == null || !equals(job.builderTypeParent.getName(), token)) { + if (job.parentType == null || !equals(job.parentType.getName(), token)) { annotationNode.addError(TO_BUILDER_NOT_SUPPORTED); return; } - TypeParameter[] tpOnType = ((TypeDeclaration) job.builderTypeParent.get()).typeParameters; + TypeParameter[] tpOnType = ((TypeDeclaration) job.parentType.get()).typeParameters; TypeParameter[] tpOnMethod = md.typeParameters; TypeReference[][] tpOnRet_ = null; if (md.returnType instanceof ParameterizedSingleTypeReference) { @@ -423,15 +437,15 @@ private static final char[] prefixWith(char[] prefix, char[] name) { } } - job.typeParams = md.typeParameters; + job.typeParams = job.builderTypeParams = md.typeParameters; buildMethodReturnType = copyType(md.returnType, ast); buildMethodThrownExceptions = md.thrownExceptions; - nameOfStaticBuilderMethod = md.selector; - if (replaceNameInBuilderClassName) { + nameOfBuilderMethod = md.selector; + if (job.builderClassName.indexOf('*') > -1) { char[] token = returnTypeToBuilderClassName(annotationNode, md, job.typeParams); - if (token == null) - return; - job.builderClassName = job.builderClassName.replace("*", new String(token)); + 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."); @@ -458,7 +472,7 @@ private static final char[] prefixWith(char[] prefix, char[] name) { } } - job.builderType = findInnerClass(job.builderTypeParent, job.builderClassName); + job.builderType = findInnerClass(job.parentType, job.builderClassName); if (job.builderType == null) makeBuilderClass(job); else { TypeDeclaration builderTypeDeclaration = (TypeDeclaration) job.builderType.get(); @@ -527,7 +541,7 @@ private static final char[] prefixWith(char[] prefix, char[] name) { 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(job, nameOfStaticBuilderMethod, buildMethodReturnType, buildMethodThrownExceptions, addCleaning); + MethodDeclaration md = generateBuildMethod(job, nameOfBuilderMethod, buildMethodReturnType, buildMethodThrownExceptions, addCleaning); if (md != null) injectMethod(job.builderType, md); } } @@ -548,13 +562,13 @@ private static final char[] prefixWith(char[] prefix, char[] name) { if (cleanMethod != null) injectMethod(job.builderType, cleanMethod); } - if (generateBuilderMethod && methodExists(job.builderMethodName, job.builderTypeParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; + if (generateBuilderMethod && methodExists(job.builderMethodName, job.parentType, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; if (generateBuilderMethod) { MethodDeclaration md = generateBuilderMethod(job); - if (md != null) injectMethod(job.builderTypeParent, md); + if (md != null) injectMethod(job.parentType, md); } - if (job.toBuilder) switch (methodExists(job.toBuilderMethodName, job.builderTypeParent, 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; @@ -569,7 +583,7 @@ private static final char[] prefixWith(char[] prefix, char[] name) { } MethodDeclaration md = generateToBuilderMethod(job, tps, annInstance.setterPrefix()); - if (md != null) injectMethod(job.builderTypeParent, md); + if (md != null) injectMethod(job.parentType, md); } if (nonFinalNonDefaultedFields != null && generateBuilderMethod) { @@ -608,13 +622,12 @@ static char[] returnTypeToBuilderClassName(EclipseNode annotationNode, MethodDec return token; } - private static final char[] BUILDER_TEMP_VAR = {'b', 'u', 'i', 'l', 'd', 'e', 'r'}; private MethodDeclaration generateToBuilderMethod(BuilderJob job, TypeParameter[] typeParameters, String prefix) { int pS = job.source.sourceStart, pE = job.source.sourceEnd; long p = job.getPos(); MethodDeclaration out = job.createNewMethodDeclaration(); - out.selector = job.toBuilderMethodName.toCharArray(); + out.selector = TO_BUILDER_METHOD_NAME; out.modifiers = toEclipseModifier(job.accessOuters); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; @@ -657,7 +670,7 @@ private MethodDeclaration generateToBuilderMethod(BuilderJob job, TypeParameter[ obtainExpr.typeArguments[j] = new SingleTypeReference(typeParameters[j].name, 0); } } - obtainExpr.receiver = generateNameReference(job.builderTypeParent, 0); + obtainExpr.receiver = generateNameReference(job.parentType, 0); } else { obtainExpr.receiver = new ThisReference(0, 0); } @@ -709,8 +722,8 @@ private MethodDeclaration generateToBuilderMethod(BuilderJob job, TypeParameter[ out.statements[preSs] = new ReturnStatement(receiver, pS, pE); } - createRelevantNonNullAnnotation(job.builderTypeParent, out); - out.traverse(new SetGeneratedByVisitor(job.source), ((TypeDeclaration) job.builderTypeParent.get()).scope); + createRelevantNonNullAnnotation(job.parentType, out); + out.traverse(new SetGeneratedByVisitor(job.source), ((TypeDeclaration) job.parentType.get()).scope); return out; } @@ -736,6 +749,18 @@ private MethodDeclaration generateCleanMethod(BuilderJob job) { return decl; } + 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; @@ -803,7 +828,7 @@ public MethodDeclaration generateBuildMethod(BuilderJob job, char[] staticName, MessageSend inv = new MessageSend(); inv.sourceStart = job.source.sourceStart; inv.sourceEnd = job.source.sourceEnd; - inv.receiver = new SingleNameReference(((TypeDeclaration) job.builderTypeParent.get()).name, 0L); + inv.receiver = new SingleNameReference(((TypeDeclaration) job.parentType.get()).name, 0L); inv.selector = bfd.nameOfDefaultProvider; inv.typeArguments = typeParameterNames(((TypeDeclaration) job.builderType.get()).typeParameters); @@ -897,7 +922,6 @@ public static MethodDeclaration generateDefaultProvider(char[] methodName, TypeP public MethodDeclaration generateBuilderMethod(BuilderJob job) { int pS = job.source.sourceStart, pE = job.source.sourceEnd; long p = job.getPos(); - char[] builderClassName = job.getBuilderClassName(); MethodDeclaration out = job.createNewMethodDeclaration(); out.selector = job.builderMethodName.toCharArray(); @@ -920,9 +944,9 @@ public MethodDeclaration generateBuilderMethod(BuilderJob job) { QualifiedAllocationExpression qualifiedInvoke = new QualifiedAllocationExpression(); qualifiedInvoke.enclosingInstance = new ThisReference(pS, pE); if (job.typeParams == null || job.typeParams.length == 0) { - qualifiedInvoke.type = new SingleTypeReference(builderClassName, p); + qualifiedInvoke.type = new SingleTypeReference(job.builderClassNameArr, p); } else { - qualifiedInvoke.type = namePlusTypeParamsToTypeReference(null, builderClassName, false, job.typeParams, p); + qualifiedInvoke.type = namePlusTypeParamsToTypeReference(null, job.builderClassNameArr, false, job.typeParams, p); } out.statements = new Statement[] {new ReturnStatement(qualifiedInvoke, pS, pE)}; @@ -973,29 +997,27 @@ public void generateBuilderFields(BuilderJob job) { } } - private static final AbstractMethodDeclaration[] EMPTY = {}; - public void makePrefixedSetterMethodsForBuilder(BuilderJob job, BuilderFieldData bfd, String prefix) { boolean deprecate = isFieldDeprecated(bfd.originalFieldNode); if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) { - makePrefixedSetterMethodForBuilder(job, deprecate, bfd.createdFields.get(0), bfd.name, bfd.nameOfSetFlag, bfd.annotations, bfd.originalFieldNode, prefix); + makePrefixedSetterMethodForBuilder(job, bfd, deprecate, prefix); } else { bfd.singularData.getSingularizer().generateMethods(job, bfd.singularData, deprecate); } } - private void makePrefixedSetterMethodForBuilder(BuilderJob job, boolean deprecate, EclipseNode fieldNode, char[] paramName, char[] nameOfSetFlag, Annotation[] annotations, EclipseNode originalFieldNode, String prefix) { + 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 (job.oldFluent) { - setterName = prefix.isEmpty() ? new String(paramName) : HandlerUtil.buildAccessorName(setterPrefix, new String(paramName)); + 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++) { @@ -1005,26 +1027,16 @@ private void makePrefixedSetterMethodForBuilder(BuilderJob job, boolean deprecat } List methodAnnsList = Collections.emptyList(); - Annotation[] methodAnns = EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); + Annotation[] methodAnns = EclipseHandlerUtil.findCopyableToSetterAnnotations(bfd.originalFieldNode); if (methodAnns != null && methodAnns.length > 0) methodAnnsList = Arrays.asList(methodAnns); ASTNode source = job.sourceNode.get(); - MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, paramName, nameOfSetFlag, job.oldChain, toEclipseModifier(job.accessInners), - job.sourceNode, methodAnnsList, annotations != null ? Arrays.asList(copyAnnotations(source, annotations)) : Collections.emptyList()); - if (job.checkerFramework.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); - - TypeReference typeReference = job.createBuilderTypeReference(); - int trLen = typeReference.getTypeName().length; - typeReference.annotations = new Annotation[trLen][]; - typeReference.annotations[trLen - 1] = new Annotation[] {ann}; - setter.receiver = new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, 0); - } + 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.emptyList()); + if (job.checkerFramework.generateCalledMethods()) setter.receiver = generateNotCalledReceiver(job, setterName); if (job.sourceNode.up().getKind() == Kind.METHOD) { - copyJavadocFromParam(originalFieldNode.up(), setter, td, paramName.toString()); + 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(job.builderType, setter); } @@ -1045,15 +1057,15 @@ private void copyJavadocFromParam(EclipseNode from, MethodDeclaration to, TypeDe } public void makeBuilderClass(BuilderJob job) { - TypeDeclaration parent = (TypeDeclaration) job.builderTypeParent.get(); + TypeDeclaration parent = (TypeDeclaration) job.parentType.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; builder.modifiers |= toEclipseModifier(job.accessOuters); if (job.isStatic) builder.modifiers |= ClassFileConstants.AccStatic; builder.typeParameters = job.copyTypeParams(); - builder.name = job.getBuilderClassName(); + builder.name = job.builderClassNameArr; builder.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); - job.builderType = injectType(job.builderTypeParent, builder); + 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 06c9ecd9db..3233a8c6fc 100755 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -461,14 +461,12 @@ private static final char[] prefixWith(char[] prefix, char[] name) { 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 MethodDeclaration createStaticConstructor(AccessLevel level, String name, 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 MethodDeclaration createStaticConstructor(AccessLevel level, String name, 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/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 79b7e816f8..8fdfd31536 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.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.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 { - 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 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 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 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 builderFields = new ArrayList(); - TypeReference returnType; - TypeParameter[] typeParams; + job.builderFields = new ArrayList(); + TypeReference buildMethodReturnType; boolean addCleaning = false; - if (!(tdParent.get() instanceof TypeDeclaration)) { + List 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 allFields = new ArrayList(); - List 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 void handle(AnnotationValues annotation, Annotation ast, Ec 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 void handle(AnnotationValues annotation, Annotation ast, Ec 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(); // are the generics for our builder. String classGenericName = "C"; @@ -227,25 +244,41 @@ public void handle(AnnotationValues annotation, Annotation ast, Ec // 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 on the annotated class, use "C2" and "B3" for our builder. - java.util.Set usedNames = gatherUsedTypeNames(typeParams, td); + java.util.Set 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 void handle(AnnotationValues annotation, Annotation ast, Ec 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 void handle(AnnotationValues annotation, Annotation ast, Ec 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 void handle(AnnotationValues annotation, Annotation ast, Ec } // 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> fieldNodes = new ArrayList>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { for (EclipseNode f : bfd.createdFields) { fieldNodes.add(new Included(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 void handle(AnnotationValues annotation, Annotation ast, Ec } // 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 void handle(AnnotationValues annotation, Annotation ast, Ec } // 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 void handle(AnnotationValues annotation, Annotation ast, Ec } } - 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 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 @@ private void generateBuilderBasedConstructor(CheckerFrameworkVersion cfv, Eclips } 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 statements = new ArrayList(); - 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 @@ private void generateBuilderBasedConstructor(CheckerFrameworkVersion cfv, Eclips 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 @@ private void generateBuilderBasedConstructor(CheckerFrameworkVersion cfv, Eclips 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 @@ private void generateBuilderBasedConstructor(CheckerFrameworkVersion cfv, Eclips } 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 @@ private MethodDeclaration generateBuilderMethod(CheckerFrameworkVersion cfv, Str * } * */ - 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 @@ private MethodDeclaration generateToBuilderMethod(CheckerFrameworkVersion cfv, S *
 	 * protected B $fillValuesFrom(final C instance) {
 	 *     super.$fillValuesFrom(instance);
-	 *     Foobar.FoobarBuilderImpl.$fillValuesFromInstanceIntoBuilder(instance, this);
+	 *     Foobar.FoobarBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
 	 *     return self();
 	 * }
 	 * 
*/ - 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 @@ private MethodDeclaration generateFillValuesMethod(EclipseNode tdParent, boolean // 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 @@ private MethodDeclaration generateFillValuesMethod(EclipseNode tdParent, boolean * * @param setterPrefix the prefix for setter methods */ - private MethodDeclaration generateStaticFillValuesMethod(EclipseNode tdParent, String builderClassName, TypeParameter[] typeParams, java.util.List 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 body = new ArrayList(); // 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 @@ private MessageSend createSetterCallWithInstanceValue(BuilderFieldData bfd, Ecli 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 @@ private MethodDeclaration generateAbstractSelfMethod(CheckerFrameworkVersion cfv 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 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 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 statements = new ArrayList(); 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 @@ private MethodDeclaration generateBuildMethod(CheckerFrameworkVersion cfv, Eclip 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 builderFields, EclipseNode builderType, ASTNode source) { + private MethodDeclaration generateCleanMethod(BuilderJob job) { List statements = new ArrayList(); - 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 builderFields, ASTNode source) { + private void generateBuilderFields(BuilderJob job) { List existing = new ArrayList(); - 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 @@ private void generateBuilderFields(EclipseNode builderType, List methodAnnsList = Arrays.asList(EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode)); - if (cfv.generateReturnsReceiver()) { + if (job.checkerFramework.generateReturnsReceiver()) { methodAnnsList = new ArrayList(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.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.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/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 7e87ce11f5..1c74ce3741 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.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 @@ public class HandleBuilder extends JavacAnnotationHandler { 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 typeParams; + List builderTypeParams; + JCTree source; + JavacNode sourceNode; + java.util.List builderFields; + AccessLevel accessInners, accessOuters; + boolean oldFluent, oldChain, toBuilder; + + JavacNode builderType; + String builderClassName; + + void init(AnnotationValues 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 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 annotations; JCExpression type; @@ -112,73 +197,49 @@ static class BuilderFieldData { @Override public void handle(AnnotationValues 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 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 builderFields = new ArrayList(); - JCExpression returnType; - List typeParams = List.nil(); - List thrownExceptions = List.nil(); + job.builderFields = new ArrayList(); + JCExpression buildMethodReturnType; + job.typeParams = List.nil(); + List buildMethodThrownExceptions; Name nameOfBuilderMethod; - JavacNode tdParent; JavacNode fillParametersFrom = parent.get() instanceof JCMethodDecl ? parent : null; boolean addCleaning = false; - boolean isStatic = true; ArrayList 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 allFields = new ListBuffer(); 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 @@ static class BuilderFieldData { 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 @@ static class BuilderFieldData { } 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.nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, annotationNode); + handleConstructor.generateConstructor(parent, AccessLevel.PACKAGE, List.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("")) { JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get(); if (!jmd.typarams.isEmpty()) { @@ -238,38 +299,35 @@ static class BuilderFieldData { 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 @@ static class BuilderFieldData { 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 @@ static class BuilderFieldData { return; } - if (!tdParent.getName().contentEquals(simpleName)) { + if (!job.parentType.getName().contentEquals(simpleName)) { annotationNode.addError(TO_BUILDER_NOT_SUPPORTED); return; } List tpOnMethod = jmd.typarams; - List tpOnType = ((JCClassDecl) tdParent.get()).typarams; + List tpOnType = ((JCClassDecl) job.builderType.get()).typarams; typeArgsForToBuilder = new ArrayList(); for (JCTypeParameter tp : tpOnMethod) { @@ -349,41 +407,41 @@ static class BuilderFieldData { 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 @@ static class BuilderFieldData { } } - 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.nil(), builderType, List.nil(), false, annotationNode); - if (cd != null) injectMethod(builderType, cd); + if (constructorExists(job.builderType) == MemberExistsResult.NOT_EXISTS) { + JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, List.nil(), job.builderType, List.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> fieldNodes = new ArrayList>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { for (JavacNode f : bfd.createdFields) { fieldNodes.add(new Included(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 tps = typeParams; + List tps = job.typeParams; if (typeArgsForToBuilder != null) { ListBuffer lb = new ListBuffer(); - JavacTreeMaker maker = tdParent.getTreeMaker(); + JavacTreeMaker maker = job.getTreeMaker(); for (Name n : typeArgsForToBuilder) { lb.append(maker.TypeParameter(n, List.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 @@ private static void unpack(StringBuilder sb, JCExpression expr) { 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 typeParams, java.util.List builderFields, boolean fluent, JCAnnotation ast, AccessLevel access, String prefix) { + private JCMethodDecl generateToBuilderMethod(BuilderJob job, List typeParameters, String prefix) { // return new ThingieBuilder().setA(this.a).setB(this.b); - JavacTreeMaker maker = type.getTreeMaker(); - + JavacTreeMaker maker = job.getTreeMaker(); ListBuffer typeArgs = new ListBuffer(); - for (JCTypeParameter typeParam : typeParams) { + for (JCTypeParameter typeParam : typeParameters) { typeArgs.append(maker.Ident(typeParam.name)); } - JCExpression call = maker.NewClass(null, List.nil(), namePlusTypeParamsToTypeReference(maker, type, type.toName(builderClassName), !isStatic, typeParams), List.nil(), null); + JCExpression call = maker.NewClass(null, List.nil(), namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderClassName), !job.isStatic, job.builderTypeParams), List.nil(), null); JCExpression invoke = call; ListBuffer preStatements = null; ListBuffer statements = new ListBuffer(); - 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.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.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.nil(), c, List.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(); preStatements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), bfd.name, varType, inv)); } @@ -602,15 +658,15 @@ private JCMethodDecl generateToBuilderMethod(CheckerFrameworkVersion cfv, String invoke = maker.Apply(List.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.nil(), maker.Select(maker.Ident(type.toName(BUILDER_TEMP_VAR)), setterName), List.of(tgt[1])); + JCExpression invokeBuilder = maker.Apply(List.nil(), maker.Select(maker.Ident(job.toName(BUILDER_TEMP_VAR)), setterName), List.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 @@ private JCMethodDecl generateToBuilderMethod(CheckerFrameworkVersion cfv, String statements = preStatements; } JCBlock body = maker.Block(0, statements.toList()); - List annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__UNIQUE), List.nil())) : List.nil(); - JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(toJavacModifier(access), annsOnMethod), type.toName(toBuilderMethodName), namePlusTypeParamsToTypeReference(maker, type, type.toName(builderClassName), !isStatic, typeParams), List.nil(), List.nil(), List.nil(), body, null); - createRelevantNonNullAnnotation(type, methodDef); + List annsOnParamType = List.nil(); + if (job.checkerFramework.generateUnique()) annsOnParamType = List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__UNIQUE), List.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.nil(), List.nil(), List.nil(), body, null); + createRelevantNonNullAnnotation(job.parentType, methodDef); return methodDef; } - private JCMethodDecl generateCleanMethod(java.util.List builderFields, JavacNode type, JCTree source) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateCleanMethod(BuilderJob job) { + JavacTreeMaker maker = job.getTreeMaker(); ListBuffer statements = new ListBuffer(); - 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.nil(), List.nil(), List.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.nil(), List.nil(), List.nil(), body, null); + recursiveSetGeneratedBy(method, job.source, job.getContext()); return method; } - static List generateBuildArgs(CheckerFrameworkVersion cfv, JavacNode type, java.util.List builderFields) { - if (!cfv.generateCalledMethods()) return List.nil(); - + static JCVariableDecl generateReceiver(BuilderJob job) { + if (!job.checkerFramework.generateCalledMethods()) return null; + ArrayList mandatories = new ArrayList(); - 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.nil(); + JavacTreeMaker maker = job.getTreeMaker(); + if (mandatories.size() == 0) return null; if (mandatories.size() == 1) arg = maker.Literal(mandatories.get(0)); else { List 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.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.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.nil()), job.toName("this"), namePlusTypeParamsToTypeReference(maker, job.builderType, builderTypeNode.typarams, List.of(recvAnno)), null); + return recv; } - private JCMethodDecl generateBuildMethod(CheckerFrameworkVersion cfv, JavacNode tdParent, boolean isStatic, String buildName, Name builderName, JCExpression returnType, java.util.List builderFields, JavacNode type, List thrownExceptions, JCTree source, boolean addCleaning, AccessLevel access) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateBuildMethod(BuilderJob job, Name staticName, JCExpression returnType, List thrownExceptions, boolean addCleaning) { + JavacTreeMaker maker = job.getTreeMaker(); JCExpression call; ListBuffer statements = new ListBuffer(); 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.nil(), maker.Ident(type.toName("$lombokClean")), List.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.nil(), maker.Ident(job.toName(CLEAN_METHOD_NAME)), List.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 args = new ListBuffer(); - 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.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.nil()))), null)); } if (bfd.nameOfSetFlag != null || (bfd.singularData != null && bfd.singularData.getSingularizer().shadowedDuringBuild())) { args.append(maker.Ident(bfd.builderFieldName)); @@ -700,20 +757,20 @@ private JCMethodDecl generateBuildMethod(CheckerFrameworkVersion cfv, JavacNode } 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.nil(), returnType, args.toList(), null); statements.append(maker.Return(call)); } else { ListBuffer typeParams = new ListBuffer(); - 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 @@ private JCMethodDecl generateBuildMethod(CheckerFrameworkVersion cfv, JavacNode JCBlock body = maker.Block(0, statements.toList()); - List annsOnMethod = cfv.generateSideEffectFree() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())) : List.nil(); - List params = generateBuildArgs(cfv, type, builderFields); - JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(toJavacModifier(access), annsOnMethod), type.toName(buildName), returnType, List.nil(), params, thrownExceptions, body, null); - if (builderName == null) createRelevantNonNullAnnotation(type, methodDef); + List annsOnMethod = job.checkerFramework.generateSideEffectFree() ? List.of(maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())) : List.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.nil(), recv, List.nil(), thrownExceptions, body, null); + } else { + methodDef = maker.MethodDef(maker.Modifiers(toJavacModifier(job.accessInners), annsOnMethod), job.toName(job.buildMethodName), returnType, List.nil(), List.nil(), thrownExceptions, body, null); + } + if (staticName == null) createRelevantNonNullAnnotation(job.builderType, methodDef); return methodDef; } @@ -743,52 +805,54 @@ public static JCMethodDecl generateDefaultProvider(Name methodName, JavacNode fi return maker.MethodDef(maker.Modifiers(modifiers), methodName, cloneType(maker, field.vartype, field, fieldNode.getContext()), copyTypeParams(fieldNode, params), List.nil(), List.nil(), body, null); } - public JCMethodDecl generateBuilderMethod(CheckerFrameworkVersion cfv, boolean isStatic, String builderMethodName, String builderClassName, JavacNode source, JavacNode type, List typeParams, AccessLevel access) { - JavacTreeMaker maker = type.getTreeMaker(); + public JCMethodDecl generateBuilderMethod(BuilderJob job) { + //String builderClassName, JavacNode source, JavacNode type, List typeParams, AccessLevel access) { + //builderClassName, annotationNode, tdParent, typeParams, accessForOuters); + + JavacTreeMaker maker = job.getTreeMaker(); ListBuffer typeArgs = new ListBuffer(); - for (JCTypeParameter typeParam : typeParams) { + for (JCTypeParameter typeParam : job.typeParams) { typeArgs.append(maker.Ident(typeParam.name)); } JCExpression call; - if (isStatic) { - call = maker.NewClass(null, List.nil(), namePlusTypeParamsToTypeReference(maker, type, type.toName(builderClassName), false, typeParams), List.nil(), null); + if (job.isStatic) { + call = maker.NewClass(null, List.nil(), namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderClassName), false, job.typeParams), List.nil(), null); } else { - call = maker.NewClass(null, List.nil(), namePlusTypeParamsToTypeReference(maker, null, type.toName(builderClassName), false, typeParams), List.nil(), null); - ((JCNewClass) call).encl = maker.Ident(type.toName("this")); + call = maker.NewClass(null, List.nil(), namePlusTypeParamsToTypeReference(maker, null, job.toName(job.builderClassName), false, job.typeParams), List.nil(), null); + ((JCNewClass) call).encl = maker.Ident(job.toName("this")); } JCStatement statement = maker.Return(call); JCBlock body = maker.Block(0, List.of(statement)); - int modifiers = toJavacModifier(access); - if (isStatic) modifiers |= Flags.STATIC; - JCAnnotation annUnique = cfv.generateUnique() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__UNIQUE), List.nil()) : null; - JCAnnotation annSef = cfv.generateSideEffectFree() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil()) : null; - List 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.nil(), List.nil(), body, null); - createRelevantNonNullAnnotation(type, methodDef); + int modifiers = toJavacModifier(job.accessOuters); + if (job.isStatic) modifiers |= Flags.STATIC; + List annsOnMethod = List.nil(); + if (job.checkerFramework.generateSideEffectFree()) annsOnMethod = List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())); + List annsOnParamType = List.nil(); + if (job.checkerFramework.generateUnique()) annsOnParamType = List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__UNIQUE), List.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.nil(), List.nil(), body, null); + createRelevantNonNullAnnotation(job.parentType, methodDef); return methodDef; } - public void generateBuilderFields(JavacNode builderType, java.util.List builderFields, JCTree source) { - int len = builderFields.size(); + public void generateBuilderFields(BuilderJob job) { + int len = job.builderFields.size(); java.util.List existing = new ArrayList(); - for (JavacNode child : builderType.down()) { + for (JavacNode child : job.builderType.down()) { if (child.getKind() == Kind.FIELD) existing.add(child); } java.util.List generated = new ArrayList(); 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 void generateBuilderFields(JavacNode builderType, java.util.List 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 @@ private void makePrefixedSetterMethodForBuilder(CheckerFrameworkVersion cfv, Jav JavacTreeMaker maker = fieldNode.getTreeMaker(); - List 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.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.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 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.of(maker.Literal(setterName.toString()))); + JCClassDecl builderTypeNode = (JCClassDecl) job.builderType.get(); + JCExpression selfType = namePlusTypeParamsToTypeReference(maker, job.builderType, builderTypeNode.typarams, List.of(ncAnno)); + JCVariableDecl recv = maker.VarDef(maker.Modifiers(Flags.PARAMETER, List.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 @@ private void copyJavadocFromParam(JavacNode from, JCMethodDecl to, String param) } } catch (Exception ignore) {} } - - public JavacNode makeBuilderClass(boolean isStatic, JavacNode source, JavacNode tdParent, String builderClassName, List 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 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.nil(), List.nil()); - return injectType(tdParent, builder); + JCClassDecl builder = maker.ClassDef(mods, job.getBuilderClassName(), job.copyTypeParams(), null, List.nil(), List.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 2a68376732..f30320dcfb 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -377,7 +377,6 @@ public static void addConstructorProperties(JCModifiers mods, JavacNode node, Li 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.nil())); return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName(""), null, List.nil(), params.toList(), List.nil(), maker.Block(0L, nullChecks.appendList(assigns).toList()), null), source.get(), typeNode.getContext()); @@ -456,7 +455,6 @@ public JCMethodDecl createStaticConstructor(String name, AccessLevel level, Java 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.nil())); JCExpression returnType, constructorType; @@ -469,7 +467,9 @@ public JCMethodDecl createStaticConstructor(String name, AccessLevel level, Java typeParams.append(maker.TypeParameter(param.name, param.bounds)); } } - returnType = namePlusTypeParamsToTypeReference(maker, typeNode, type.typarams); + List annsOnReturnType = List.nil(); + if (getCheckerFrameworkVersion(typeNode).generateUnique()) annsOnReturnType = List.of(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__UNIQUE), List.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 d490738eb7..3935ab4eef 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -234,7 +234,7 @@ public JCMethodDecl createHashCode(JavacNode typeNode, java.util.List member : members) { diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index 110941d66a..afe2c1b634 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -380,7 +380,7 @@ public List createLazyGetterBody(JavacTreeMaker maker, JavacNode fi /* 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 82c9571917..5c4c768167 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -226,7 +226,30 @@ public static JCMethodDecl createSetter(long access, boolean deprecate, JavacNod 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 onMethod, List 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 annotations = d.mods.annotations; + if (annotations == null) annotations = List.nil(); + JCAnnotation anno = treeMaker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.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 onMethod, List 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 onMethod, List onParam, JCVariableDecl recv) { if (setterName == null) return null; JCVariableDecl fieldDecl = (JCVariableDecl) field.get(); @@ -277,8 +300,14 @@ public static JCMethodDecl createSetter(long access, boolean deprecate, JavacNod annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.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 f6bf9e1fbd..99f0ea6ada 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.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 @@ @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 { 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 builderTypeParams_; + + void init(AnnotationValues 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 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 builderFields = new ArrayList(); - List typeParams = List.nil(); - List thrownExceptions = List.nil(); + job.builderFields = new ArrayList(); + job.typeParams = List.nil(); + List buildMethodThrownExceptions = List.nil(); List 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 allFields = new ListBuffer(); ArrayList 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 void handle(AnnotationValues annotation, JCAnnotation ast, 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 void handle(AnnotationValues annotation, JCAnnotation ast, } 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". - 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; // are the generics for our builder. String classGenericName = "C"; @@ -214,14 +226,46 @@ public void handle(AnnotationValues annotation, JCAnnotation ast, // 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 on the annotated class, use "C2" and "B3" for our builder. - java.util.HashSet usedNames = gatherUsedTypeNames(typeParams, td); + java.util.HashSet 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.of(annotatedClass)); + ListBuffer 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.nil()), typeParamsForBuilder.toList()); + JCTypeParameter d = maker.TypeParameter(parent.toName(builderGenericName), List.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". + 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 void handle(AnnotationValues annotation, JCAnnotation ast, } } + 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> fieldNodes = new ArrayList>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { for (JavacNode f : bfd.createdFields) { fieldNodes.add(new Included(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 void handle(AnnotationValues annotation, JCAnnotation ast, // 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.nil(), builderImplType, List.nil(), false, annotationNode); - if (cd != null) injectMethod(builderImplType, cd); + JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, List.nil(), job.builderImplType, List.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 void handle(AnnotationValues annotation, JCAnnotation ast, /** * 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 typeParams, - List superclassTypeParams, String classGenericName, String builderGenericName) { - - JavacTreeMaker maker = tdParent.getTreeMaker(); + private JavacNode generateBuilderAbstractClass(SuperBuilderJob job, JCExpression superclassBuilderClass, List 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 allTypeParams = new ListBuffer(); - 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.of(annotatedClass))); + allTypeParams.add(maker.TypeParameter(job.toName(classGenericName), List.of(annotatedClass))); // 2. The return type for all setter methods, named "B", which extends this builder class. - Name builderClassName = tdParent.toName(builderClass); - ListBuffer 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.nil()), typeParamsForBuilder.toList()); - allTypeParams.add(maker.TypeParameter(tdParent.toName(builderGenericName), List.of(typeApply))); + Name builderClassName = job.toName(job.builderClassName); + ListBuffer 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.nil()), typeParamsForBuilder.toList()); + allTypeParams.add(maker.TypeParameter(job.toName(builderGenericName), List.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 . - 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.nil(), List.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 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.nil()); + JCExpression extending = namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderAbstractClassName), false, List.nil()); // Add any type params of the annotated class. ListBuffer allTypeParams = new ListBuffer(); - 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 typeParamsForBuilder = getTypeParamExpressions(typeParams, maker, source.getContext()); + ListBuffer 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.nil(), List.nil()); - return injectType(tdParent, builder); + JCClassDecl builder = maker.ClassDef(mods, job.toName(job.builderImplClassName), copyTypeParams(job.parentType, job.typeParams), extending, List.nil(), List.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 typeParams, java.util.List 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 statements = new ListBuffer(); - 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 @@ private void generateBuilderBasedConstructor(CheckerFrameworkVersion cfv, JavacN } 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.nil()); - JCAssign assignDefault = maker.Assign(fieldInThis, maker.Apply(typeParameterNames(maker, ((JCClassDecl) typeNode.get()).typarams), maker.Select(parentTypeRef, bfd.nameOfDefaultProvider), List.nil())); + fieldInThis = maker.Select(maker.Ident(job.toName("this")), bfd.rawName); + JCExpression parentTypeRef = namePlusTypeParamsToTypeReference(maker, job.parentType, List.nil()); + JCAssign assignDefault = maker.Assign(fieldInThis, maker.Apply(typeParameterNames(maker, ((JCClassDecl) job.parentType.get()).typarams), maker.Select(parentTypeRef, bfd.nameOfDefaultProvider), List.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 annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())) : List.nil(); + List annsOnMethod = job.checkerFramework.generateUnique() ? List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())) : List.nil(); JCModifiers mods = maker.Modifiers(toJavacModifier(level), annsOnMethod); // Create a constructor that has just the builder as parameter. ListBuffer params = new ListBuffer(); - 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 typeParamsForBuilderParameter = getTypeParamExpressions(typeParams, maker, typeNode.getContext()); + ListBuffer 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.nil()), typeParamsForBuilderParameter.toList()); + JCTypeApply paramType = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, job.parentType, job.getBuilderClassName(), false, List.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.nil(), - maker.Ident(typeNode.toName("super")), + maker.Ident(job.toName("super")), List.of(maker.Ident(builderVariableName))); statements.prepend(maker.Exec(callToSuperConstructor)); } - JCMethodDecl constr = recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName(""), + JCMethodDecl constr = recursiveSetGeneratedBy(maker.MethodDef(mods, job.toName(""), null, List.nil(), params.toList(), List.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 typeParams) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateBuilderMethod(SuperBuilderJob job) { + JavacTreeMaker maker = job.getTreeMaker(); ListBuffer typeArgs = new ListBuffer(); - 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.nil(), namePlusTypeParamsToTypeReference(maker, type, type.toName(builderImplClassName), false, typeParams), List.nil(), null); + JCExpression call = maker.NewClass(null, List.nil(), namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderImplClassName), false, job.typeParams), List.nil(), null); JCStatement statement = maker.Return(call); JCBlock body = maker.Block(0, List.of(statement)); @@ -565,16 +603,16 @@ private JCMethodDecl generateBuilderMethod(CheckerFrameworkVersion cfv, String b // Add any type params of the annotated class to the return type. ListBuffer typeParameterNames = new ListBuffer(); - 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.nil()), typeParameterNames.toList()); + JCTypeApply returnType = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderAbstractClassName), false, List.nil()), typeParameterNames.toList()); - List annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())) : List.nil(); - JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), type.toName(builderMethodName), returnType, copyTypeParams(source, typeParams), List.nil(), List.nil(), body, null); - createRelevantNonNullAnnotation(type, methodDef); + List annsOnMethod = job.checkerFramework.generateUnique() ? List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())) : List.nil(); + JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), job.toName(job.builderMethodName), returnType, copyTypeParams(job.sourceNode, job.typeParams), List.nil(), List.nil(), body, null); + createRelevantNonNullAnnotation(job.parentType, methodDef); return methodDef; } @@ -586,15 +624,15 @@ private JCMethodDecl generateBuilderMethod(CheckerFrameworkVersion cfv, String b * } * */ - private JCMethodDecl generateToBuilderMethod(CheckerFrameworkVersion cfv, String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List typeParams) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateToBuilderMethod(SuperBuilderJob job) { + JavacTreeMaker maker = job.getTreeMaker(); ListBuffer typeArgs = new ListBuffer(); - 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.nil(), namePlusTypeParamsToTypeReference(maker, type, type.toName(builderImplClassName), false, typeParams), List.nil(), null); - List methodArgs = List.of(maker.Ident(type.toName("this"))); - JCMethodInvocation invokeFillMethod = maker.Apply(List.nil(), maker.Select(newClass, type.toName(FILL_VALUES_METHOD_NAME)), methodArgs); + JCExpression newClass = maker.NewClass(null, List.nil(), namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderImplClassName), false, job.typeParams), List.nil(), null); + List methodArgs = List.of(maker.Ident(job.toName("this"))); + JCMethodInvocation invokeFillMethod = maker.Apply(List.nil(), maker.Select(newClass, job.toName(FILL_VALUES_METHOD_NAME)), methodArgs); JCStatement statement = maker.Return(invokeFillMethod); JCBlock body = maker.Block(0, List.of(statement)); @@ -602,16 +640,16 @@ private JCMethodDecl generateToBuilderMethod(CheckerFrameworkVersion cfv, String // Add any type params of the annotated class to the return type. ListBuffer typeParameterNames = new ListBuffer(); - 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.nil()), typeParameterNames.toList()); + JCTypeApply returnType = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, job.parentType, job.toName(job.builderAbstractClassName), false, List.nil()), typeParameterNames.toList()); - List annsOnMethod = cfv.generateUnique() ? List.of(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())) : List.nil(); - JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), type.toName(TO_BUILDER_METHOD_NAME), returnType, List.nil(), List.nil(), List.nil(), body, null); - createRelevantNonNullAnnotation(type, methodDef); + List annsOnMethod = job.checkerFramework.generateUnique() ? List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())) : List.nil(); + JCMethodDecl methodDef = maker.MethodDef(maker.Modifiers(modifiers, annsOnMethod), job.toName(TO_BUILDER_METHOD_NAME), returnType, List.nil(), List.nil(), List.nil(), body, null); + createRelevantNonNullAnnotation(job.parentType, methodDef); return methodDef; } @@ -621,43 +659,43 @@ private JCMethodDecl generateToBuilderMethod(CheckerFrameworkVersion cfv, String *
 	 * protected B $fillValuesFrom(final C instance) {
 	 *     super.$fillValuesFrom(instance);
-	 *     FoobarBuilderImpl.$fillValuesFromInstanceIntoBuilder(instance, this);
+	 *     FoobarBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
 	 *     return self();
 	 * }
 	 * 
*/ - 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 annotations = List.nil(); if (inherited) { - JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.nil()); + JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(job.builderType, "Override"), List.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 body = new ListBuffer(); if (inherited) { // Call super. JCMethodInvocation callToSuper = maker.Apply(List.nil(), - maker.Select(maker.Ident(type.toName("super")), name), - List.of(maker.Ident(type.toName(INSTANCE_VARIABLE_NAME)))); + maker.Select(maker.Ident(job.toName("super")), name), + List.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.nil()); + JCExpression ref = namePlusTypeParamsToTypeReference(maker, job.parentType, job.getBuilderClassName(), false, List.nil()); JCMethodInvocation callStaticFillValuesMethod = maker.Apply(List.nil(), - maker.Select(ref, type.toName(STATIC_FILL_VALUES_METHOD_NAME)), - List.of(maker.Ident(type.toName(INSTANCE_VARIABLE_NAME)), maker.Ident(type.toName("this")))); + maker.Select(ref, job.toName(STATIC_FILL_VALUES_METHOD_NAME)), + List.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.nil(), maker.Ident(type.toName(SELF_METHOD)), List.nil())); + JCReturn returnStatement = maker.Return(maker.Apply(List.nil(), maker.Ident(job.toName(SELF_METHOD)), List.nil())); body.append(returnStatement); JCBlock bodyBlock = maker.Block(0, body.toList()); @@ -674,40 +712,39 @@ private JCMethodDecl generateFillValuesMethod(JavacNode type, boolean inherited, * b.field(instance.field); * } * - * @param setterPrefix the prefix for setter methods */ - private JCMethodDecl generateStaticFillValuesMethod(JavacNode type, String builderClassname, List typeParams, java.util.List builderFields, String setterPrefix) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateStaticFillValuesMethod(SuperBuilderJob job, String setterPrefix) { + JavacTreeMaker maker = job.getTreeMaker(); List 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 typeParamsForBuilderParameter = getTypeParamExpressions(typeParams, maker, type.getContext()); + ListBuffer 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.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.nil()), typeParamsForBuilderParameter.toList()); + JCVariableDecl paramBuilder = maker.VarDef(maker.Modifiers(Flags.PARAMETER | Flags.FINAL), job.toName(BUILDER_VARIABLE_NAME), builderType, null); + ListBuffer body = new ListBuffer(); // 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.nil(), bodyBlock, null); + + return maker.MethodDef(modifiers, name, returnType, copyTypeParams(job.builderType, job.typeParams), List.of(paramInstance, paramBuilder), List.nil(), bodyBlock, null); } private JCExpressionStatement createSetterCallWithInstanceValue(BuilderFieldData bfd, JavacNode type, JavacTreeMaker maker, String setterPrefix) { @@ -747,80 +784,91 @@ private JCExpressionStatement createSetterCallWithInstanceValue(BuilderFieldData 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 annotations = List.nil(); - JCAnnotation overrideAnnotation = override ? maker.Annotation(genJavaLangTypeRef(type, "Override"), List.nil()) : null; - JCAnnotation rrAnnotation = cfv.generateReturnsReceiver() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.nil()) : null; - JCAnnotation sefAnnotation = cfv.generatePure() ? maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__PURE), List.nil()) : null; + JCAnnotation overrideAnnotation = override ? maker.Annotation(genJavaLangTypeRef(job.builderType, "Override"), List.nil()) : null; + JCAnnotation rrAnnotation = job.checkerFramework.generateReturnsReceiver() ? maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.nil()) : null; + JCAnnotation sefAnnotation = job.checkerFramework.generatePure() ? maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__PURE), List.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.nil(), List.nil(), List.nil(), null, null); } - private JCMethodDecl generateSelfMethod(CheckerFrameworkVersion cfv, JavacNode builderImplType, List typeParams) { - JavacTreeMaker maker = builderImplType.getTreeMaker(); + private JCMethodDecl generateSelfMethod(SuperBuilderJob job) { + JavacTreeMaker maker = job.getTreeMaker(); - JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(builderImplType, "Override"), List.nil()); - JCAnnotation rrAnnotation = cfv.generateReturnsReceiver() ? maker.Annotation(genTypeRef(builderImplType, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.nil()) : null; - JCAnnotation sefAnnotation = cfv.generatePure() ? maker.Annotation(genTypeRef(builderImplType, CheckerFrameworkVersion.NAME__PURE), List.nil()) : null; + JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(job.builderType, "Override"), List.nil()); + JCAnnotation rrAnnotation = job.checkerFramework.generateReturnsReceiver() ? maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.nil()) : null; + JCAnnotation sefAnnotation = job.checkerFramework.generatePure() ? maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__PURE), List.nil()) : null; List 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.of(statement)); return maker.MethodDef(modifiers, name, returnType, List.nil(), List.nil(), List.nil(), body, null); } - private JCMethodDecl generateAbstractBuildMethod(CheckerFrameworkVersion cfv, JavacNode type, String methodName, java.util.List builderFields, boolean override, String classGenericName) { - JavacTreeMaker maker = type.getTreeMaker(); + private JCMethodDecl generateAbstractBuildMethod(SuperBuilderJob job, boolean override, String classGenericName) { + JavacTreeMaker maker = job.getTreeMaker(); List annotations = List.nil(); if (override) { - JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.nil()); + JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(job.builderType, "Override"), List.nil()); annotations = List.of(overrideAnnotation); } - if (cfv.generateSideEffectFree()) annotations = annotations.prepend(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())); + if (job.checkerFramework.generateSideEffectFree()) annotations = annotations.prepend(maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.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 params = HandleBuilder.generateBuildArgs(cfv, type, builderFields); - return maker.MethodDef(modifiers, name, returnType, List.nil(), params, List.nil(), null, null); + JCVariableDecl recv = HandleBuilder.generateReceiver(job); + JCMethodDecl methodDef; + if (recv != null && maker.hasMethodDefWithRecvParam()) { + methodDef = maker.MethodDefWithRecvParam(modifiers, name, returnType, List.nil(), recv, List.nil(), List.nil(), null, null); + } else { + methodDef = maker.MethodDef(modifiers, name, returnType, List.nil(), List.nil(), List.nil(), null, null); + } + return methodDef; } - - private JCMethodDecl generateBuildMethod(CheckerFrameworkVersion cfv, String buildName, JavacNode returnType, JavacNode type, java.util.List builderFields, List thrownExceptions) { - JavacTreeMaker maker = type.getTreeMaker(); + + private JCMethodDecl generateBuildMethod(SuperBuilderJob job, List thrownExceptions) { + JavacTreeMaker maker = job.getTreeMaker(); JCExpression call; ListBuffer statements = new ListBuffer(); // Use a constructor that only has this builder as parameter. - List builderArg = List.of(maker.Ident(type.toName("this"))); - call = maker.NewClass(null, List.nil(), cloneSelfType(returnType), builderArg, null); + List builderArg = List.of(maker.Ident(job.toName("this"))); + call = maker.NewClass(null, List.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.nil()); + JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(job.builderType, "Override"), List.nil()); List annsOnMethod = List.of(overrideAnnotation); - if (cfv.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(type, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())); + if (job.checkerFramework.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.nil())); JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC, annsOnMethod); - List params = HandleBuilder.generateBuildArgs(cfv, type, builderFields); - JCMethodDecl methodDef = maker.MethodDef(modifiers, type.toName(buildName), cloneSelfType(returnType), List.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.nil(), recv, List.nil(), thrownExceptions, body, null); + } else { + methodDef = maker.MethodDef(modifiers, job.toName(job.buildMethodName), cloneSelfType(job.parentType), List.nil(), List.nil(), thrownExceptions, body, null); + } + createRelevantNonNullAnnotation(job.builderType, methodDef); return methodDef; } @@ -878,29 +926,30 @@ private void generateBuilderFields(JavacNode builderType, java.util.Listnil(), maker.Ident(builderType.toName(SELF_METHOD)), List.nil())); + return maker.Return(maker.Apply(List.nil(), maker.Ident(job.toName(SELF_METHOD)), List.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 annosOnParam, JavacNode originalFieldNode, String setterPrefix) { + private void generateSimpleSetterMethodForBuilder(SuperBuilderJob job, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JCExpression returnType, JCStatement returnStatement, List 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 @@ private void generateSimpleSetterMethodForBuilder(CheckerFrameworkVersion cfv, J JavacTreeMaker maker = fieldNode.getTreeMaker(); List 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.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.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.of(maker.Literal(setterName.toString()))); + JCClassDecl builderTypeNode = (JCClassDecl) job.builderType.get(); + JCExpression selfType = namePlusTypeParamsToTypeReference(maker, job.builderType, builderTypeNode.typarams, List.of(ncAnno)); + JCVariableDecl recv = maker.VarDef(maker.Modifiers(0L, List.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 annotations = newMethod.mods.annotations; if (annotations == null) annotations = List.nil(); - JCAnnotation anno = maker.Annotation(genTypeRef(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.nil()); - recursiveSetGeneratedBy(anno, source.get(), builderType.getContext()); + JCAnnotation anno = maker.Annotation(genTypeRef(job.builderType, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.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/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index 7cd52c8c83..2fc9329c55 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -57,6 +57,7 @@ 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 java.util.List listMethodsToBeGenerated(SingularData data, JavacNod * 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 7cd676c008..dadf881d5d 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java @@ -151,7 +151,7 @@ protected JCExpression getPluralMethodParamType(JavacNode builderType) { 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 b4ad3428eb..1f8bbbe961 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 50950915d8..5670b5e655 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java @@ -84,7 +84,7 @@ protected List createJavaUtilSetMapInitialCapacitySwitchStatements( 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 @@ protected List createJavaUtilSimpleCreationAndFillStatements(JavacT 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 @@ protected List createJavaUtilSimpleCreationAndFillStatements(JavacT // error: method put in interface Map 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/test/transform/resource/after-delombok/CheckerFrameworkBasic.java b/test/transform/resource/after-delombok/CheckerFrameworkBasic.java index 3077728cc6..c9b73d7cc3 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 @@ public int getY() { 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 @@ public int hashCode() { 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 ace3adadd2..213a1af6ac 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 names) { this.x = x; @@ -29,37 +28,36 @@ public static class CheckerFrameworkBuilderBuilder { private int z; @java.lang.SuppressWarnings("all") private java.util.ArrayList 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.objectconstruction.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.objectconstruction.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.objectconstruction.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(); 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 names) { if (names == null) { @@ -69,7 +67,7 @@ public CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder names(final java.u 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 @@ public CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder clearNames() { } @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.objectconstruction.qual.CalledMethods({"y", "z"}) CheckerFrameworkBuilderBuilder this) { java.util.List names; switch (this.names == null ? 0 : this.names.size()) { case 0: @@ -100,10 +98,10 @@ public java.lang.String toString() { 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 30408c3bc2..18e4e33353 100644 --- a/test/transform/resource/after-delombok/CheckerFrameworkSuperBuilder.java +++ b/test/transform/resource/after-delombok/CheckerFrameworkSuperBuilder.java @@ -22,40 +22,40 @@ public static abstract class ParentBuilder 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.objectconstruction.qual.CalledMethods({"y", "z"}) ParentBuilder this); + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") - public B x(@org.checkerframework.checker.builder.qual.NotCalledMethods("x") CheckerFrameworkSuperBuilder.Parent.ParentBuilder this, final int x) { + public B x(CheckerFrameworkSuperBuilder.Parent.@org.checkerframework.checker.objectconstruction.qual.NotCalledMethods("x") ParentBuilder 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 this, final int y) { + public B y(CheckerFrameworkSuperBuilder.Parent.@org.checkerframework.checker.objectconstruction.qual.NotCalledMethods("y") ParentBuilder 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 this, final int z) { + public B z(CheckerFrameworkSuperBuilder.Parent.@org.checkerframework.checker.objectconstruction.qual.NotCalledMethods("z") ParentBuilder 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(); 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 names) { if (names == null) { @@ -65,7 +65,7 @@ public B names(final java.util.Collection names) { 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 @@ public java.lang.String toString() { } @java.lang.SuppressWarnings("all") private static final class ParentBuilderImpl extends CheckerFrameworkSuperBuilder.Parent.ParentBuilder { - @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 @@ protected CheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl self() { @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.objectconstruction.qual.CalledMethods({"y", "z"}) ParentBuilderImpl this) { return new CheckerFrameworkSuperBuilder.Parent(this); } } @@ -140,24 +139,24 @@ public static abstract class ZChildBuilder this); + @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") - public B a(@org.checkerframework.checker.builder.qual.NotCalledMethods("a") CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder this, final int a) { + public B a(CheckerFrameworkSuperBuilder.ZChild.@org.checkerframework.checker.objectconstruction.qual.NotCalledMethods("a") ZChildBuilder 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 this, final int b) { + public B b(CheckerFrameworkSuperBuilder.ZChild.@org.checkerframework.checker.objectconstruction.qual.NotCalledMethods("b") ZChildBuilder this, final int b) { this.b = b; return self(); } @@ -170,12 +169,11 @@ public java.lang.String toString() { } @java.lang.SuppressWarnings("all") private static final class ZChildBuilderImpl extends CheckerFrameworkSuperBuilder.ZChild.ZChildBuilder { - @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 @@ protected CheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl self() { @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.objectconstruction.qual.CalledMethods("b") ZChildBuilderImpl this) { return new CheckerFrameworkSuperBuilder.ZChild(this); } } diff --git a/test/transform/resource/after-ecj/CheckerFrameworkBasic.java b/test/transform/resource/after-ecj/CheckerFrameworkBasic.java index ce4d11f81e..5411c2a417 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 @@ 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 @@ 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 3f998df4f6..f5c41b24e8 100644 --- a/test/transform/resource/after-ecj/CheckerFrameworkBuilder.java +++ b/test/transform/resource/after-ecj/CheckerFrameworkBuilder.java @@ -8,29 +8,29 @@ private @java.lang.SuppressWarnings("all") int y; private @java.lang.SuppressWarnings("all") int z; private @java.lang.SuppressWarnings("all") java.util.ArrayList 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.objectconstruction.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.objectconstruction.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.objectconstruction.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(); this.names.add(name); return this; } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder names(final java.util.Collection names) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder.CheckerFrameworkBuilderBuilder names(final java.util.Collection names) { if ((names == null)) { throw new java.lang.NullPointerException("names cannot be null"); @@ -40,12 +40,12 @@ 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.objectconstruction.qual.CalledMethods({"y", "z"}) CheckerFrameworkBuilderBuilder this) { java.util.List names; switch (((this.names == null) ? 0 : this.names.size())) { case 0 : @@ -73,14 +73,14 @@ 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 names) { + @java.lang.SuppressWarnings("all") CheckerFrameworkBuilder(final int x, final int y, final int z, final List 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 7c8ff0ed21..b8a1d2d01b 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.objectconstruction.qual.CalledMethods({"y", "z"}) ParentBuilder this); + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B x(CheckerFrameworkSuperBuilder.Parent. @org.checkerframework.checker.objectconstruction.qual.NotCalledMethods("x") ParentBuilder 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.objectconstruction.qual.NotCalledMethods("y") ParentBuilder 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.objectconstruction.qual.NotCalledMethods("z") ParentBuilder 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(); this.names.add(name); return self(); } - public @org.checkerframework.checker.builder.qual.ReturnsReceiver @java.lang.SuppressWarnings("all") B names(final java.util.Collection names) { + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B names(final java.util.Collection names) { if ((names == null)) { throw new java.lang.NullPointerException("names cannot be null"); @@ -42,7 +42,7 @@ public ParentBuilder() { 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 @@ public ParentBuilder() { 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.objectconstruction.qual.CalledMethods({"y", "z"}) ParentBuilderImpl this) { return new CheckerFrameworkSuperBuilder.Parent(this); } } @@ -69,7 +69,7 @@ private ParentBuilderImpl() { 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 @@ private ParentBuilderImpl() { } 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 @@ private ParentBuilderImpl() { 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.objectconstruction.qual.CalledMethods("b") ZChildBuilder this); + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B a(CheckerFrameworkSuperBuilder.ZChild. @org.checkerframework.checker.objectconstruction.qual.NotCalledMethods("a") ZChildBuilder 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.objectconstruction.qual.NotCalledMethods("b") ZChildBuilder this, final int b) { this.b = b; return self(); } @@ -121,10 +121,10 @@ public ZChildBuilder() { 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.objectconstruction.qual.CalledMethods("b") ZChildBuilderImpl this) { return new CheckerFrameworkSuperBuilder.ZChild(this); } } @@ -133,7 +133,7 @@ private ZChildBuilderImpl() { 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 @@ private ZChildBuilderImpl() { 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/before/CheckerFrameworkBasic.java b/test/transform/resource/before/CheckerFrameworkBasic.java index 8a0bd118bf..fb43ad0852 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/messages-delombok/CheckerFrameworkBasic.java.messages b/test/transform/resource/messages-delombok/CheckerFrameworkBasic.java.messages deleted file mode 100644 index 9ee959a402..0000000000 --- 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 8c7367056b..0000000000 --- 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 5dd6251a06..0000000000 --- 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 8cc7fb5807..0000000000 --- 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 d385a95cf9..0000000000 --- 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 8cc7fb5807..0000000000 --- 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 80694a061c..0000000000 --- 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