diff options
author | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2020-10-03 23:55:10 +0200 |
---|---|---|
committer | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2020-10-03 23:55:10 +0200 |
commit | 14cce76805324dce66fcdfde333a63c677694d64 (patch) | |
tree | 18001068c7052e08ee85a2df565f4be9902ca448 /src/core/lombok/eclipse/handlers | |
parent | 07e921d2b19a660df28e03ee1ed1d0315d5e3458 (diff) | |
download | lombok-14cce76805324dce66fcdfde333a63c677694d64.tar.gz lombok-14cce76805324dce66fcdfde333a63c677694d64.tar.bz2 lombok-14cce76805324dce66fcdfde333a63c677694d64.zip |
[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.
Diffstat (limited to 'src/core/lombok/eclipse/handlers')
3 files changed, 393 insertions, 357 deletions
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 5bda6e1a..f8eb9ed0 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -106,8 +106,16 @@ import lombok.experimental.NonFinal; public class HandleBuilder extends EclipseAnnotationHandler<Builder> { private HandleConstructor handleConstructor = new HandleConstructor(); - private static final char[] CLEAN_FIELD_NAME = "$lombokUnclean".toCharArray(); - private static final char[] CLEAN_METHOD_NAME = "$lombokClean".toCharArray(); + static final char[] CLEAN_FIELD_NAME = "$lombokUnclean".toCharArray(); + static final char[] CLEAN_METHOD_NAME = "$lombokClean".toCharArray(); + static final String TO_BUILDER_METHOD_NAME_STRING = "toBuilder"; + static final char[] TO_BUILDER_METHOD_NAME = TO_BUILDER_METHOD_NAME_STRING.toCharArray(); + static final char[] DEFAULT_PREFIX = {'$', 'd', 'e', 'f', 'a', 'u', 'l', 't', '$'}; + static final char[] SET_PREFIX = {'$', 's', 'e', 't'}; + static final char[] VALUE_PREFIX = {'$', 'v', 'a', 'l', 'u', 'e'}; + static final char[] BUILDER_TEMP_VAR = {'b', 'u', 'i', 'l', 'd', 'e', 'r'}; + static final AbstractMethodDeclaration[] EMPTY_METHODS = {}; + static final String TO_BUILDER_NOT_SUPPORTED = "@Builder(toBuilder=true) is only supported if you return your own type."; private static final boolean toBoolean(Object expr, boolean defaultValue) { if (expr == null) return defaultValue; @@ -118,22 +126,28 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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<BuilderFieldData> 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } 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<Builder> node, Builder ann) { + void init(AnnotationValues<Builder> annValues, Builder ann, EclipseNode node) { accessOuters = ann.access(); if (accessOuters == null) accessOuters = AccessLevel.PUBLIC; if (accessOuters == AccessLevel.NONE) { @@ -166,23 +180,37 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return true; } - private static final char[] DEFAULT_PREFIX = {'$', 'd', 'e', 'f', 'a', 'u', 'l', 't', '$'}; - private static final char[] SET_PREFIX = {'$', 's', 'e', 't'}; - private static final char[] VALUE_PREFIX = {'$', 'v', 'a', 'l', 'u', 'e'}; - private static final char[] prefixWith(char[] prefix, char[] name) { char[] out = new char[prefix.length + name.length]; System.arraycopy(prefix, 0, out, 0, prefix.length); @@ -236,9 +260,10 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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<char[]> typeArgsForToBuilder = null; boolean generateBuilderMethod; @@ -251,45 +276,35 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } 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<BuilderFieldData>(); TypeReference buildMethodReturnType; TypeReference[] buildMethodThrownExceptions; - char[] nameOfStaticBuilderMethod; + char[] nameOfBuilderMethod; EclipseNode fillParametersFrom = parent.get() instanceof AbstractMethodDeclaration ? parent : null; boolean addCleaning = false; - job.isStatic = true; List<EclipseNode> 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<EclipseNode> allFields = new ArrayList<EclipseNode>(); 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { bfd.builderFieldName = prefixWith(bfd.name, VALUE_PREFIX); MethodDeclaration md = generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast); - if (md != null) injectMethod(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.<Annotation>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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } } - 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } } - 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return token; } - private static final char[] BUILDER_TEMP_VAR = {'b', 'u', 'i', 'l', 'd', 'e', 'r'}; private MethodDeclaration generateToBuilderMethod(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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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 class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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 class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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 class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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 class HandleBuilder extends EclipseAnnotationHandler<Builder> { } } - 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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } List<Annotation> methodAnnsList = Collections.<Annotation>emptyList(); - Annotation[] methodAnns = EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); + Annotation[] methodAnns = EclipseHandlerUtil.findCopyableToSetterAnnotations(bfd.originalFieldNode); if (methodAnns != null && methodAnns.length > 0) methodAnnsList = Arrays.asList(methodAnns); ASTNode source = 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.<Annotation>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.<Annotation>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 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } 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 06c9ecd9..3233a8c6 100755 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -461,14 +461,12 @@ public class HandleConstructor { constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[0]); /* Generate annotations that must be put on the generated method, and attach them. */ { - Annotation[] constructorProperties = null, checkerFramework = null; + Annotation[] constructorProperties = null; if (addConstructorProperties && !isLocalType(type)) constructorProperties = createConstructorProperties(source, fieldsToParam); - if (getCheckerFrameworkVersion(type).generateUnique()) checkerFramework = new Annotation[] { generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE) }; constructor.annotations = copyAnnotations(source, onConstructor.toArray(new Annotation[0]), - constructorProperties, - checkerFramework); + constructorProperties); } constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope); @@ -536,6 +534,11 @@ public class HandleConstructor { TypeDeclaration typeDecl = (TypeDeclaration) type.get(); constructor.returnType = EclipseHandlerUtil.namePlusTypeParamsToTypeReference(type, typeDecl.typeParameters, p); constructor.annotations = null; + if (getCheckerFrameworkVersion(type).generateUnique()) { + int len = constructor.returnType.getTypeName().length; + constructor.returnType.annotations = new Annotation[len][]; + constructor.returnType.annotations[len - 1] = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE)}; + } constructor.selector = name.toCharArray(); constructor.thrownExceptions = null; constructor.typeParameters = copyTypeParams(((TypeDeclaration) type.get()).typeParameters, source); @@ -556,9 +559,7 @@ public class HandleConstructor { assigns.add(nameRef); Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL); - Annotation[] checkerFramework = null; - if (getCheckerFrameworkVersion(fieldNode).generateUnique()) checkerFramework = new Annotation[] { generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE) }; - parameter.annotations = copyAnnotations(source, findCopyableAnnotations(fieldNode), checkerFramework); + parameter.annotations = copyAnnotations(source, findCopyableAnnotations(fieldNode)); params.add(parameter); } diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 79b7e816..8fdfd315 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -21,6 +21,7 @@ */ package lombok.eclipse.handlers; +import static lombok.eclipse.handlers.HandleBuilder.*; import static lombok.core.handlers.HandlerUtil.*; import static lombok.eclipse.Eclipse.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; @@ -57,13 +58,10 @@ import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; -import org.eclipse.jdt.internal.compiler.ast.Receiver; import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; -import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.Statement; -import org.eclipse.jdt.internal.compiler.ast.StringLiteral; import org.eclipse.jdt.internal.compiler.ast.SuperReference; import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; @@ -99,75 +97,100 @@ import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; import lombok.eclipse.handlers.EclipseSingularsRecipes.StatementMaker; import lombok.eclipse.handlers.EclipseSingularsRecipes.TypeReferenceMaker; import lombok.eclipse.handlers.HandleBuilder.BuilderFieldData; +import lombok.eclipse.handlers.HandleBuilder.BuilderJob; import lombok.experimental.NonFinal; import lombok.experimental.SuperBuilder; @ProviderFor(EclipseAnnotationHandler.class) @HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes. public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { - private static final char[] CLEAN_FIELD_NAME = "$lombokUnclean".toCharArray(); - private static final char[] CLEAN_METHOD_NAME = "$lombokClean".toCharArray(); - private static final char[] DEFAULT_PREFIX = "$default$".toCharArray(); - private static final char[] SET_PREFIX = "$set".toCharArray(); - private static final char[] VALUE_PREFIX = "$value".toCharArray(); private static final char[] SELF_METHOD_NAME = "self".toCharArray(); - private static final String TO_BUILDER_METHOD_NAME_STRING = "toBuilder"; - private static final char[] TO_BUILDER_METHOD_NAME = TO_BUILDER_METHOD_NAME_STRING.toCharArray(); private static final char[] FILL_VALUES_METHOD_NAME = "$fillValuesFrom".toCharArray(); private static final char[] FILL_VALUES_STATIC_METHOD_NAME = "$fillValuesFromInstanceIntoBuilder".toCharArray(); private static final char[] INSTANCE_VARIABLE_NAME = "instance".toCharArray(); private static final String BUILDER_VARIABLE_NAME_STRING = "b"; private static final char[] BUILDER_VARIABLE_NAME = BUILDER_VARIABLE_NAME_STRING.toCharArray(); - private static final AbstractMethodDeclaration[] EMPTY_METHODS = {}; - - @Override - public void handle(AnnotationValues<SuperBuilder> annotation, Annotation ast, EclipseNode annotationNode) { - handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder"); - CheckerFrameworkVersion cfv = getCheckerFrameworkVersion(annotationNode); - - long p = (long) ast.sourceStart << 32 | ast.sourceEnd; + class SuperBuilderJob extends BuilderJob { + void init(AnnotationValues<SuperBuilder> annValues, SuperBuilder ann, EclipseNode node) { + accessOuters = accessInners = AccessLevel.PUBLIC; + oldFluent = true; + oldChain = true; + + builderMethodName = ann.builderMethodName(); + buildMethodName = ann.buildMethodName(); + toBuilder = ann.toBuilder(); + + if (builderMethodName == null) builderMethodName = "builder"; + if (buildMethodName == null) buildMethodName = "build"; + builderClassName = fixBuilderClassName(node, ""); + } - SuperBuilder superbuilderAnnotation = annotation.getInstance(); + EclipseNode builderAbstractType; + String builderAbstractClassName; + char[] builderAbstractClassNameArr; + EclipseNode builderImplType; + String builderImplClassName; + char[] builderImplClassNameArr; + private TypeParameter[] builderTypeParams_; + void setBuilderToImpl() { + builderType = builderImplType; + builderClassName = builderImplClassName; + builderClassNameArr = builderImplClassNameArr; + builderTypeParams = typeParams; + } - String builderMethodName = superbuilderAnnotation.builderMethodName(); - String buildMethodName = superbuilderAnnotation.buildMethodName(); + void setBuilderToAbstract() { + builderType = builderAbstractType; + builderClassName = builderAbstractClassName; + builderClassNameArr = builderAbstractClassNameArr; + builderTypeParams = builderTypeParams_; + } + } + + @Override public void handle(AnnotationValues<SuperBuilder> annotation, Annotation ast, EclipseNode annotationNode) { + handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder"); + SuperBuilderJob job = new SuperBuilderJob(); + job.sourceNode = annotationNode; + job.source = ast; + job.checkerFramework = getCheckerFrameworkVersion(annotationNode); + job.isStatic = true; - if (builderMethodName == null) builderMethodName = "builder"; - if (buildMethodName == null) buildMethodName = "build"; + SuperBuilder annInstance = annotation.getInstance(); + job.init(annotation, annInstance, annotationNode); boolean generateBuilderMethod; - if (builderMethodName.isEmpty()) { + if (job.builderMethodName.isEmpty()) { generateBuilderMethod = false; - } else if (!checkName("builderMethodName", builderMethodName, annotationNode)) { + } else if (!checkName("builderMethodName", job.builderMethodName, annotationNode)) { return; } else { generateBuilderMethod = true; } - if (!checkName("buildMethodName", buildMethodName, annotationNode)) return; - boolean toBuilder = superbuilderAnnotation.toBuilder(); + if (!checkName("buildMethodName", job.buildMethodName, annotationNode)) return; - EclipseNode tdParent = annotationNode.up(); + EclipseNode parent = annotationNode.up(); - java.util.List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>(); - TypeReference returnType; - TypeParameter[] typeParams; + job.builderFields = new ArrayList<BuilderFieldData>(); + TypeReference buildMethodReturnType; boolean addCleaning = false; - if (!(tdParent.get() instanceof TypeDeclaration)) { + List<EclipseNode> nonFinalNonDefaultedFields = null; + + if (!(parent.get() instanceof TypeDeclaration)) { annotationNode.addError("@SuperBuilder is only supported on types."); return; } - TypeDeclaration td = (TypeDeclaration) tdParent.get(); + job.parentType = parent; + TypeDeclaration td = (TypeDeclaration) parent.get(); // Gather all fields of the class that should be set by the builder. List<EclipseNode> allFields = new ArrayList<EclipseNode>(); - List<EclipseNode> nonFinalNonDefaultedFields = null; - boolean valuePresent = (hasAnnotation(lombok.Value.class, tdParent) || hasAnnotation("lombok.experimental.Value", tdParent)); - for (EclipseNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) { + boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent)); + for (EclipseNode fieldNode : HandleConstructor.findAllFields(parent, true)) { FieldDeclaration fd = (FieldDeclaration) fieldNode.get(); EclipseNode isDefault = findAnnotation(Builder.Default.class, fieldNode); boolean isFinal = ((fd.modifiers & ClassFileConstants.AccFinal) != 0) || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode)); @@ -180,7 +203,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { bfd.builderFieldName = bfd.name; bfd.annotations = copyAnnotations(fd, copyableAnnotations); bfd.type = fd.type; - bfd.singularData = getSingularData(fieldNode, ast, superbuilderAnnotation.setterPrefix()); + bfd.singularData = getSingularData(fieldNode, ast, annInstance.setterPrefix()); bfd.originalFieldNode = fieldNode; if (bfd.singularData != null && isDefault != null) { @@ -205,21 +228,15 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { bfd.builderFieldName = prefixWith(bfd.name, VALUE_PREFIX); MethodDeclaration md = HandleBuilder.generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast); - if (md != null) injectMethod(tdParent, md); + if (md != null) injectMethod(parent, md); } addObtainVia(bfd, fieldNode); - builderFields.add(bfd); + job.builderFields.add(bfd); allFields.add(fieldNode); } - // Set the names of the builder classes. - String builderClassNameTemplate = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME); - if (builderClassNameTemplate == null || builderClassNameTemplate.isEmpty()) builderClassNameTemplate = "*Builder"; - String builderClassName = builderClassNameTemplate.replace("*", String.valueOf(td.name)); - String builderImplClassName = builderClassName + "Impl"; - - typeParams = td.typeParameters != null ? td.typeParameters : new TypeParameter[0]; - returnType = namePlusTypeParamsToTypeReference(tdParent, typeParams, p); + job.typeParams = td.typeParameters != null ? td.typeParameters : new TypeParameter[0]; + buildMethodReturnType = job.createBuilderParentTypeReference(); // <C, B> are the generics for our builder. String classGenericName = "C"; @@ -227,25 +244,41 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { // We have to make sure that the generics' names do not collide with any generics on the annotated class, // the classname itself, or any member type name of the annotated class. // For instance, if there are generics <B, B2, C> on the annotated class, use "C2" and "B3" for our builder. - java.util.Set<String> usedNames = gatherUsedTypeNames(typeParams, td); + java.util.Set<String> usedNames = gatherUsedTypeNames(job.typeParams, td); classGenericName = generateNonclashingNameFor(classGenericName, usedNames); builderGenericName = generateNonclashingNameFor(builderGenericName, usedNames); + TypeParameter[] paddedTypeParameters; { + paddedTypeParameters = new TypeParameter[job.typeParams.length + 2]; + System.arraycopy(job.typeParams, 0, paddedTypeParameters, 0, job.typeParams.length); + + TypeParameter c = new TypeParameter(); + c.name = classGenericName.toCharArray(); + c.type = cloneSelfType(job.parentType, job.source); + paddedTypeParameters[paddedTypeParameters.length - 2] = c; + + TypeParameter b = new TypeParameter(); + b.name = builderGenericName.toCharArray(); + b.type = cloneSelfType(job.parentType, job.source); + paddedTypeParameters[paddedTypeParameters.length - 1] = b; + } + job.builderTypeParams = job.builderTypeParams_ = paddedTypeParameters; + TypeReference extendsClause = td.superclass; TypeReference superclassBuilderClass = null; TypeReference[] typeArguments = new TypeReference[] { new SingleTypeReference(classGenericName.toCharArray(), 0), - new SingleTypeReference(builderGenericName.toCharArray(), 0) + new SingleTypeReference(builderGenericName.toCharArray(), 0), }; if (extendsClause instanceof QualifiedTypeReference) { QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference)extendsClause; String superclassClassName = String.valueOf(qualifiedTypeReference.getLastToken()); - String superclassBuilderClassName = builderClassNameTemplate.replace("*", superclassClassName); + String superclassBuilderClassName = job.replaceBuilderClassName(superclassClassName); char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1); tokens[tokens.length-1] = superclassBuilderClassName.toCharArray(); long[] poss = new long[tokens.length]; - Arrays.fill(poss, p); + Arrays.fill(poss, job.getPos()); TypeReference[] superclassTypeArgs = getTypeParametersFrom(extendsClause); @@ -261,7 +294,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { char[][] tokens = new char[][] {superClass.toCharArray(), superclassBuilderClassName.toCharArray()}; long[] poss = new long[tokens.length]; - Arrays.fill(poss, p); + Arrays.fill(poss, job.getPos()); TypeReference[] superclassTypeArgs = getTypeParametersFrom(extendsClause); @@ -272,40 +305,43 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss); } + job.builderAbstractClassName = job.builderClassName = job.replaceBuilderClassName(td.name); + job.builderAbstractClassNameArr = job.builderClassNameArr = job.builderAbstractClassName.toCharArray(); + job.builderImplClassName = job.builderAbstractClassName + "Impl"; + job.builderImplClassNameArr = job.builderImplClassName.toCharArray(); + // If there is no superclass, superclassBuilderClassExpression is still == null at this point. // You can use it to check whether to inherit or not. - if (!constructorExists(tdParent, builderClassName)) { - generateBuilderBasedConstructor(cfv, tdParent, typeParams, builderFields, annotationNode, builderClassName, - superclassBuilderClass != null); + if (!constructorExists(parent, job.builderClassName)) { + generateBuilderBasedConstructor(job, superclassBuilderClass != null); } // Create the abstract builder class, or reuse an existing one. - EclipseNode builderType = findInnerClass(tdParent, builderClassName); - if (builderType == null) { - builderType = generateBuilderAbstractClass(tdParent, builderClassName, superclassBuilderClass, - typeParams, ast, classGenericName, builderGenericName); + job.builderAbstractType = findInnerClass(parent, job.builderClassName); + if (job.builderAbstractType == null) { + job.builderAbstractType = generateBuilderAbstractClass(job, superclassBuilderClass, classGenericName, builderGenericName); } else { - TypeDeclaration builderTypeDeclaration = (TypeDeclaration) builderType.get(); + TypeDeclaration builderTypeDeclaration = (TypeDeclaration) job.builderAbstractType.get(); if ((builderTypeDeclaration.modifiers & (ClassFileConstants.AccStatic | ClassFileConstants.AccAbstract)) == 0) { annotationNode.addError("Existing Builder must be an abstract static inner class."); return; } - sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode); + sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderAbstractType, annotationNode); // Generate errors for @Singular BFDs that have one already defined node. - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { SingularData sd = bfd.singularData; if (sd == null) continue; EclipseSingularizer singularizer = sd.getSingularizer(); if (singularizer == null) continue; - if (singularizer.checkForAlreadyExistingNodesAndGenerateError(builderType, sd)) { + if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderAbstractType, sd)) { bfd.singularData = null; } } } // Check validity of @ObtainVia fields, and add check if adding cleaning for @Singular is necessary. - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { if (bfd.singularData.getSingularizer().requiresCleaning()) { addCleaning = true; @@ -325,47 +361,52 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } // Generate the fields in the abstract builder class that hold the values for the instance. - generateBuilderFields(builderType, builderFields, ast); + job.setBuilderToAbstract(); + generateBuilderFields(job); if (addCleaning) { FieldDeclaration cleanDecl = new FieldDeclaration(CLEAN_FIELD_NAME, 0, -1); cleanDecl.declarationSourceEnd = -1; cleanDecl.modifiers = ClassFileConstants.AccPrivate; cleanDecl.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); - injectFieldAndMarkGenerated(builderType, cleanDecl); + injectFieldAndMarkGenerated(job.builderType, cleanDecl); } - if (toBuilder) { + if (job.toBuilder) { // Generate $fillValuesFrom() method in the abstract builder. - injectMethod(builderType, generateFillValuesMethod(tdParent, superclassBuilderClass != null, builderGenericName, classGenericName, builderClassName, typeParams)); + injectMethod(job.builderType, generateFillValuesMethod(job, superclassBuilderClass != null, builderGenericName, classGenericName)); // Generate $fillValuesFromInstanceIntoBuilder() method in the builder implementation class. - injectMethod(builderType, generateStaticFillValuesMethod(tdParent, builderClassName, typeParams, builderFields, ast, superbuilderAnnotation.setterPrefix())); + injectMethod(job.builderType, generateStaticFillValuesMethod(job, annInstance.setterPrefix())); } // Generate abstract self() and build() methods in the abstract builder. - injectMethod(builderType, generateAbstractSelfMethod(cfv, tdParent, superclassBuilderClass != null, builderGenericName)); - injectMethod(builderType, generateAbstractBuildMethod(cfv, builderType, buildMethodName, builderFields, superclassBuilderClass != null, classGenericName, ast)); + injectMethod(job.builderType, generateAbstractSelfMethod(job, superclassBuilderClass != null, builderGenericName)); + job.setBuilderToAbstract(); + injectMethod(job.builderType, generateAbstractBuildMethod(job, superclassBuilderClass != null, classGenericName)); // Create the setter methods in the abstract builder. - for (BuilderFieldData bfd : builderFields) { - generateSetterMethodsForBuilder(cfv, builderType, bfd, annotationNode, builderGenericName, superbuilderAnnotation.setterPrefix()); + for (BuilderFieldData bfd : job.builderFields) { + generateSetterMethodsForBuilder(job, bfd, builderGenericName, annInstance.setterPrefix()); } // Create the toString() method for the abstract builder. - if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) { + if (methodExists("toString", job.builderType, 0) == MemberExistsResult.NOT_EXISTS) { List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { for (EclipseNode f : bfd.createdFields) { fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true, false)); } } // Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder. - MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, superclassBuilderClass != null, ast, FieldAccess.ALWAYS_FIELD); + MethodDeclaration md = HandleToString.createToString(job.builderType, fieldNodes, true, superclassBuilderClass != null, ast, FieldAccess.ALWAYS_FIELD); if (md != null) { - injectMethod(builderType, md); + injectMethod(job.builderType, md); } } - if (addCleaning) injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast)); + if (addCleaning) { + job.setBuilderToAbstract(); + injectMethod(job.builderType, generateCleanMethod(job)); + } boolean isAbstract = (td.modifiers & ClassFileConstants.AccAbstract) != 0; if (isAbstract) { @@ -374,26 +415,27 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } // Create the builder implementation class, or reuse an existing one. - EclipseNode builderImplType = findInnerClass(tdParent, builderImplClassName); - if (builderImplType == null) { - builderImplType = generateBuilderImplClass(tdParent, builderImplClassName, builderClassName, typeParams, ast); + job.builderImplType = findInnerClass(parent, job.builderImplClassName); + if (job.builderImplType == null) { + job.builderImplType = generateBuilderImplClass(job, job.builderImplClassName); } else { - TypeDeclaration builderImplTypeDeclaration = (TypeDeclaration) builderImplType.get(); + TypeDeclaration builderImplTypeDeclaration = (TypeDeclaration) job.builderImplType.get(); if ((builderImplTypeDeclaration.modifiers & ClassFileConstants.AccAbstract) != 0 || (builderImplTypeDeclaration.modifiers & ClassFileConstants.AccStatic) == 0) { annotationNode.addError("Existing BuilderImpl must be a non-abstract static inner class."); return; } - sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderImplType, annotationNode); + sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderImplType, annotationNode); } - if (toBuilder) { + job.setBuilderToImpl(); + if (job.toBuilder) { // Add the toBuilder() method to the annotated class. - switch (methodExists(TO_BUILDER_METHOD_NAME_STRING, tdParent, 0)) { + switch (methodExists(TO_BUILDER_METHOD_NAME_STRING, job.parentType, 0)) { case EXISTS_BY_USER: break; case NOT_EXISTS: - injectMethod(tdParent, generateToBuilderMethod(cfv, builderClassName, builderImplClassName, tdParent, typeParams, ast)); + injectMethod(parent, generateToBuilderMethod(job)); break; default: // Should not happen. @@ -401,17 +443,19 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } // Create the self() and build() methods in the BuilderImpl. - injectMethod(builderImplType, generateSelfMethod(cfv, builderImplType, typeParams, p)); + job.setBuilderToImpl(); + injectMethod(job.builderImplType, generateSelfMethod(job)); - if (methodExists(buildMethodName, builderImplType, -1) == MemberExistsResult.NOT_EXISTS) { - injectMethod(builderImplType, generateBuildMethod(cfv, builderImplType, buildMethodName, returnType, builderFields, ast)); + if (methodExists(job.buildMethodName, job.builderImplType, -1) == MemberExistsResult.NOT_EXISTS) { + job.setBuilderToImpl(); + injectMethod(job.builderImplType, generateBuildMethod(job, buildMethodReturnType)); } // Add the builder() method to the annotated class. - if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; + if (generateBuilderMethod && methodExists(job.builderMethodName, parent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false; if (generateBuilderMethod) { - MethodDeclaration md = generateBuilderMethod(cfv, builderMethodName, builderClassName, builderImplClassName, tdParent, typeParams, ast); - if (md != null) injectMethod(tdParent, md); + MethodDeclaration md = generateBuilderMethod(job); + if (md != null) injectMethod(parent, md); } if (nonFinalNonDefaultedFields != null && generateBuilderMethod) { @@ -421,97 +465,82 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } } - private EclipseNode generateBuilderAbstractClass(EclipseNode tdParent, String builderClass, - TypeReference superclassBuilderClass, TypeParameter[] typeParams, - ASTNode source, String classGenericName, String builderGenericName) { - - TypeDeclaration parent = (TypeDeclaration) tdParent.get(); + private EclipseNode generateBuilderAbstractClass(BuilderJob job, TypeReference superclassBuilderClass, String classGenericName, String builderGenericName) { + TypeDeclaration parent = (TypeDeclaration) job.parentType.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; builder.modifiers |= ClassFileConstants.AccPublic | ClassFileConstants.AccStatic | ClassFileConstants.AccAbstract; - builder.name = builderClass.toCharArray(); + builder.name = job.builderClassNameArr; // Keep any type params of the annotated class. - builder.typeParameters = Arrays.copyOf(copyTypeParams(typeParams, source), typeParams.length + 2); + builder.typeParameters = Arrays.copyOf(copyTypeParams(job.typeParams, job.source), job.typeParams.length + 2); // Add builder-specific type params required for inheritable builders. // 1. The return type for the build() method, named "C", which extends the annotated class. TypeParameter o = new TypeParameter(); o.name = classGenericName.toCharArray(); - o.type = cloneSelfType(tdParent, source); + o.type = cloneSelfType(job.parentType, job.source); builder.typeParameters[builder.typeParameters.length - 2] = o; // 2. The return type for all setter methods, named "B", which extends this builder class. o = new TypeParameter(); o.name = builderGenericName.toCharArray(); - TypeReference[] typerefs = appendBuilderTypeReferences(typeParams, classGenericName, builderGenericName); - o.type = generateParameterizedTypeReference(tdParent, builderClass.toCharArray(), false, typerefs, 0); + TypeReference[] typerefs = appendBuilderTypeReferences(job.typeParams, classGenericName, builderGenericName); + o.type = generateParameterizedTypeReference(job.parentType, job.builderClassNameArr, false, typerefs, 0); builder.typeParameters[builder.typeParameters.length - 1] = o; - builder.superclass = copyType(superclassBuilderClass, source); + if (superclassBuilderClass != null) builder.superclass = copyType(superclassBuilderClass, job.source); builder.createDefaultConstructor(false, true); - builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); - return injectType(tdParent, builder); + builder.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); + return injectType(job.parentType, builder); } - private EclipseNode generateBuilderImplClass(EclipseNode tdParent, String builderImplClass, String builderAbstractClass, TypeParameter[] typeParams, ASTNode source) { - TypeDeclaration parent = (TypeDeclaration) tdParent.get(); + private EclipseNode generateBuilderImplClass(BuilderJob job, String builderImplClass) { + TypeDeclaration parent = (TypeDeclaration) job.parentType.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; builder.modifiers |= ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal; builder.name = builderImplClass.toCharArray(); // Add type params if there are any. - if (typeParams != null && typeParams.length > 0) builder.typeParameters = copyTypeParams(typeParams, source); + if (job.typeParams != null && job.typeParams.length > 0) builder.typeParameters = copyTypeParams(job.typeParams, job.source); - if (builderAbstractClass != null) { + if (job.builderClassName != null) { // Extend the abstract builder. // 1. Add any type params of the annotated class. - TypeReference[] typeArgs = new TypeReference[typeParams.length + 2]; - for (int i = 0; i < typeParams.length; i++) { - typeArgs[i] = new SingleTypeReference(typeParams[i].name, 0); + TypeReference[] typeArgs = new TypeReference[job.typeParams.length + 2]; + for (int i = 0; i < job.typeParams.length; i++) { + typeArgs[i] = new SingleTypeReference(job.typeParams[i].name, 0); } // 2. The return type for the build() method (named "C" in the abstract builder), which is the annotated class. // 3. The return type for all setter methods (named "B" in the abstract builder), which is this builder class. - typeArgs[typeArgs.length - 2] = cloneSelfType(tdParent, source); - typeArgs[typeArgs.length - 1] = createTypeReferenceWithTypeParameters(tdParent, builderImplClass, typeParams); - builder.superclass = generateParameterizedTypeReference(tdParent, builderAbstractClass.toCharArray(), false, typeArgs, 0); + typeArgs[typeArgs.length - 2] = cloneSelfType(job.parentType, job.source); + typeArgs[typeArgs.length - 1] = createTypeReferenceWithTypeParameters(job.parentType, builderImplClass, job.typeParams); + builder.superclass = generateParameterizedTypeReference(job.parentType, job.builderClassNameArr, false, typeArgs, 0); } builder.createDefaultConstructor(false, true); - builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); - return injectType(tdParent, builder); + builder.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); + return injectType(job.parentType, builder); } /** * Generates a constructor that has a builder as the only parameter. * The values from the builder are used to initialize the fields of new instances. * - * @param typeNode - * the type (with the {@code @Builder} annotation) for which a - * constructor should be generated. - * @param typeParams - * @param cfv Settings for generating checker framework annotations - * @param builderFields a list of fields in the builder which should be assigned to new instances. - * @param source the annotation (used for setting source code locations for the generated code). * @param callBuilderBasedSuperConstructor * If {@code true}, the constructor will explicitly call a super * constructor with the builder as argument. Requires * {@code builderClassAsParameter != null}. */ - private void generateBuilderBasedConstructor(CheckerFrameworkVersion cfv, EclipseNode typeNode, TypeParameter[] typeParams, List<BuilderFieldData> builderFields, - EclipseNode sourceNode, String builderClassName, boolean callBuilderBasedSuperConstructor) { - - ASTNode source = sourceNode.get(); + private void generateBuilderBasedConstructor(BuilderJob job, boolean callBuilderBasedSuperConstructor) { + TypeDeclaration typeDeclaration = ((TypeDeclaration) job.parentType.get()); + long p = job.getPos(); - TypeDeclaration typeDeclaration = ((TypeDeclaration) typeNode.get()); - long p = (long) source.sourceStart << 32 | source.sourceEnd; - - ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) typeNode.top().get()).compilationResult); + ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) job.parentType.top().get()).compilationResult); constructor.modifiers = toEclipseModifier(AccessLevel.PROTECTED); - if (cfv.generateUnique()) constructor.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE)}; constructor.selector = typeDeclaration.name; if (callBuilderBasedSuperConstructor) { constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.Super); @@ -519,21 +548,21 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } else { constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); } - constructor.constructorCall.sourceStart = source.sourceStart; - constructor.constructorCall.sourceEnd = source.sourceEnd; + constructor.constructorCall.sourceStart = job.source.sourceStart; + constructor.constructorCall.sourceEnd = job.source.sourceEnd; constructor.thrownExceptions = null; constructor.typeParameters = null; constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart; - constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd; + constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = job.source.sourceStart; + constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = job.source.sourceEnd; TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND)}; - TypeReference builderType = generateParameterizedTypeReference(typeNode, builderClassName.toCharArray(), false, mergeToTypeReferences(typeParams, wildcards), p); + TypeReference builderType = generateParameterizedTypeReference(job.parentType, job.builderClassNameArr, false, mergeToTypeReferences(job.typeParams, wildcards), p); constructor.arguments = new Argument[] {new Argument(BUILDER_VARIABLE_NAME, p, builderType, Modifier.FINAL)}; List<Statement> statements = new ArrayList<Statement>(); - for (BuilderFieldData fieldNode : builderFields) { + for (BuilderFieldData fieldNode : job.builderFields) { FieldReference fieldInThis = new FieldReference(fieldNode.rawName, p); int s = (int) (p >> 32); int e = (int) p; @@ -541,7 +570,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { Expression assignmentExpr; if (fieldNode.singularData != null && fieldNode.singularData.getSingularizer() != null) { - fieldNode.singularData.getSingularizer().appendBuildCode(fieldNode.singularData, typeNode, statements, fieldNode.builderFieldName, BUILDER_VARIABLE_NAME_STRING); + fieldNode.singularData.getSingularizer().appendBuildCode(fieldNode.singularData, job.parentType, statements, fieldNode.builderFieldName, BUILDER_VARIABLE_NAME_STRING); assignmentExpr = new SingleNameReference(fieldNode.builderFieldName, p); } else { char[][] variableInBuilder = new char[][] {BUILDER_VARIABLE_NAME, fieldNode.builderFieldName}; @@ -557,11 +586,11 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { QualifiedNameReference setVariableInBuilderRef = new QualifiedNameReference(setVariableInBuilder, positions, s, e); MessageSend defaultMethodCall = new MessageSend(); - defaultMethodCall.sourceStart = source.sourceStart; - defaultMethodCall.sourceEnd = source.sourceEnd; - defaultMethodCall.receiver = generateNameReference(typeNode, 0L); + defaultMethodCall.sourceStart = job.source.sourceStart; + defaultMethodCall.sourceEnd = job.source.sourceEnd; + defaultMethodCall.receiver = generateNameReference(job.parentType, 0L); defaultMethodCall.selector = fieldNode.nameOfDefaultProvider; - defaultMethodCall.typeArguments = typeParameterNames(((TypeDeclaration) typeNode.get()).typeParameters); + defaultMethodCall.typeArguments = typeParameterNames(((TypeDeclaration) job.parentType.get()).typeParameters); Statement defaultAssignment = new Assignment(fieldInThis, defaultMethodCall, (int) p); IfStatement ifBlockForDefault = new IfStatement(setVariableInBuilderRef, assignment, defaultAssignment, s, e); @@ -571,41 +600,44 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } if (hasNonNullAnnotations(fieldNode.originalFieldNode)) { - Statement nullCheck = generateNullCheck((FieldDeclaration) fieldNode.originalFieldNode.get(), sourceNode, null); + Statement nullCheck = generateNullCheck((FieldDeclaration) fieldNode.originalFieldNode.get(), job.sourceNode, null); if (nullCheck != null) statements.add(nullCheck); } } constructor.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]); - constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope); + constructor.traverse(new SetGeneratedByVisitor(job.source), typeDeclaration.scope); - injectMethod(typeNode, constructor); + injectMethod(job.parentType, constructor); } - private MethodDeclaration generateBuilderMethod(CheckerFrameworkVersion cfv, String builderMethodName, String builderClassName, String builderImplClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) { - int pS = source.sourceStart, pE = source.sourceEnd; + private MethodDeclaration generateBuilderMethod(SuperBuilderJob job) { + int pS = job.source.sourceStart, pE = job.source.sourceEnd; long p = (long) pS << 32 | pE; - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); - out.selector = builderMethodName.toCharArray(); + MethodDeclaration out = job.createNewMethodDeclaration(); + out.selector = job.builderMethodName.toCharArray(); out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; // Add type params if there are any. - if (typeParams != null && typeParams.length > 0) out.typeParameters = copyTypeParams(typeParams, source); + if (job.typeParams != null && job.typeParams.length > 0) out.typeParameters = copyTypeParams(job.typeParams, job.source); TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND) }; - out.returnType = generateParameterizedTypeReference(type, builderClassName.toCharArray(), false, mergeToTypeReferences(typeParams, wildcards), p); + out.returnType = generateParameterizedTypeReference(job.parentType, job.builderAbstractClassNameArr, false, mergeToTypeReferences(job.typeParams, wildcards), p); + if (job.checkerFramework.generateUnique()) { + int len = out.returnType.getTypeName().length; + out.returnType.annotations = new Annotation[len][]; + out.returnType.annotations[len - 1] = new Annotation[] {generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__UNIQUE)}; + } AllocationExpression invoke = new AllocationExpression(); - invoke.type = namePlusTypeParamsToTypeReference(type, builderImplClassName.toCharArray(), false, typeParams, p); + invoke.type = namePlusTypeParamsToTypeReference(job.parentType, job.builderImplClassNameArr, false, job.typeParams, p); out.statements = new Statement[] {new ReturnStatement(invoke, pS, pE)}; - if (cfv.generateUnique()) out.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE)}; - - createRelevantNonNullAnnotation(type, out); - out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope); + createRelevantNonNullAnnotation(job.parentType, out); + out.traverse(new SetGeneratedByVisitor(job.source), ((TypeDeclaration) job.parentType.get()).scope); return out; } @@ -617,30 +649,33 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { * } * </pre> */ - private MethodDeclaration generateToBuilderMethod(CheckerFrameworkVersion cfv, String builderClassName, String builderImplClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) { - int pS = source.sourceStart, pE = source.sourceEnd; + private MethodDeclaration generateToBuilderMethod(SuperBuilderJob job) { + int pS = job.source.sourceStart, pE = job.source.sourceEnd; long p = (long) pS << 32 | pE; - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); + MethodDeclaration out = job.createNewMethodDeclaration(); out.selector = TO_BUILDER_METHOD_NAME; out.modifiers = ClassFileConstants.AccPublic; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND) }; - out.returnType = generateParameterizedTypeReference(type, builderClassName.toCharArray(), false, mergeToTypeReferences(typeParams, wildcards), p); + out.returnType = generateParameterizedTypeReference(job.parentType, job.builderAbstractClassNameArr, false, mergeToTypeReferences(job.typeParams, wildcards), p); + if (job.checkerFramework.generateUnique()) { + int len = out.returnType.getTypeName().length; + out.returnType.annotations = new Annotation[len][]; + out.returnType.annotations[len - 1] = new Annotation[] {generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__UNIQUE)}; + } AllocationExpression newClass = new AllocationExpression(); - newClass.type = namePlusTypeParamsToTypeReference(type, builderImplClassName.toCharArray(), false, typeParams, p); + newClass.type = namePlusTypeParamsToTypeReference(job.parentType, job.builderImplClassNameArr, false, job.typeParams, p); MessageSend invokeFillMethod = new MessageSend(); invokeFillMethod.receiver = newClass; invokeFillMethod.selector = FILL_VALUES_METHOD_NAME; invokeFillMethod.arguments = new Expression[] {new ThisReference(0, 0)}; out.statements = new Statement[] {new ReturnStatement(invokeFillMethod, pS, pE)}; - if (cfv.generateUnique()) out.annotations = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE)}; - - createRelevantNonNullAnnotation(type, out); - out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope); + createRelevantNonNullAnnotation(job.parentType, out); + out.traverse(new SetGeneratedByVisitor(job.source), ((TypeDeclaration) job.parentType.get()).scope); return out; } @@ -650,17 +685,17 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { * <pre> * protected B $fillValuesFrom(final C instance) { * super.$fillValuesFrom(instance); - * Foobar.FoobarBuilderImpl.$fillValuesFromInstanceIntoBuilder(instance, this); + * Foobar.FoobarBuilder.$fillValuesFromInstanceIntoBuilder(instance, this); * return self(); * } * </pre> */ - private MethodDeclaration generateFillValuesMethod(EclipseNode tdParent, boolean inherited, String builderGenericName, String classGenericName, String builderClassName, TypeParameter[] typeParams) { - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); + private MethodDeclaration generateFillValuesMethod(SuperBuilderJob job, boolean inherited, String builderGenericName, String classGenericName) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.selector = FILL_VALUES_METHOD_NAME; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccProtected; - if (inherited) out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, tdParent.get())}; + if (inherited) out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, job.parentType.get())}; out.returnType = new SingleTypeReference(builderGenericName.toCharArray(), 0); TypeReference builderType = new SingleTypeReference(classGenericName.toCharArray(), 0); @@ -679,7 +714,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { // Call the builder implemention's helper method that actually fills the values from the instance. MessageSend callStaticFillValuesMethod = new MessageSend(); - callStaticFillValuesMethod.receiver = generateNameReference(tdParent, builderClassName.toCharArray(), 0); + callStaticFillValuesMethod.receiver = generateNameReference(job.parentType, job.builderAbstractClassNameArr, 0); callStaticFillValuesMethod.selector = FILL_VALUES_STATIC_METHOD_NAME; callStaticFillValuesMethod.arguments = new Expression[] {new SingleNameReference(INSTANCE_VARIABLE_NAME, 0), new ThisReference(0, 0)}; body.add(callStaticFillValuesMethod); @@ -707,41 +742,40 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { * </pre> * @param setterPrefix the prefix for setter methods */ - private MethodDeclaration generateStaticFillValuesMethod(EclipseNode tdParent, String builderClassName, TypeParameter[] typeParams, java.util.List<BuilderFieldData> builderFields, ASTNode source, String setterPrefix) { - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); + private MethodDeclaration generateStaticFillValuesMethod(BuilderJob job, String setterPrefix) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.selector = FILL_VALUES_STATIC_METHOD_NAME; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic; out.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0); TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND)}; - TypeReference builderType = generateParameterizedTypeReference(tdParent, builderClassName.toCharArray(), false, mergeToTypeReferences(typeParams, wildcards), 0); + TypeReference builderType = generateParameterizedTypeReference(job.parentType, job.builderClassNameArr, false, mergeToTypeReferences(job.typeParams, wildcards), 0); Argument builderArgument = new Argument(BUILDER_VARIABLE_NAME, 0, builderType, Modifier.FINAL); TypeReference[] typerefs = null; - if (typeParams.length > 0) { - typerefs = new TypeReference[typeParams.length]; - for (int i = 0; i < typeParams.length; i++) typerefs[i] = new SingleTypeReference(typeParams[i].name, 0); + if (job.typeParams.length > 0) { + typerefs = new TypeReference[job.typeParams.length]; + for (int i = 0; i < job.typeParams.length; i++) typerefs[i] = new SingleTypeReference(job.typeParams[i].name, 0); } - long p = source.sourceStart; - p = (p << 32) | source.sourceEnd; + long p = job.getPos(); - TypeReference parentArgument = typerefs == null ? generateTypeReference(tdParent, p) : generateParameterizedTypeReference(tdParent, typerefs, p); + TypeReference parentArgument = typerefs == null ? generateTypeReference(job.parentType, p) : generateParameterizedTypeReference(job.parentType, typerefs, p); out.arguments = new Argument[] {new Argument(INSTANCE_VARIABLE_NAME, 0, parentArgument, Modifier.FINAL), builderArgument}; // Add type params if there are any. - if (typeParams.length > 0) out.typeParameters = copyTypeParams(typeParams, source); + if (job.typeParams.length > 0) out.typeParameters = copyTypeParams(job.typeParams, job.source); List<Statement> body = new ArrayList<Statement>(); // Call the builder's setter methods to fill the values from the instance. - for (BuilderFieldData bfd : builderFields) { - MessageSend exec = createSetterCallWithInstanceValue(bfd, tdParent, source, setterPrefix); + for (BuilderFieldData bfd : job.builderFields) { + MessageSend exec = createSetterCallWithInstanceValue(bfd, job.parentType, job.source, setterPrefix); body.add(exec); } out.statements = body.isEmpty() ? null : body.toArray(new Statement[0]); - out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); + out.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); return out; } @@ -783,14 +817,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { return ms; } - private MethodDeclaration generateAbstractSelfMethod(CheckerFrameworkVersion cfv, EclipseNode tdParent, boolean override, String builderGenericName) { - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); + private MethodDeclaration generateAbstractSelfMethod(BuilderJob job, boolean override, String builderGenericName) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.selector = SELF_METHOD_NAME; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected | ExtraCompilerModifiers.AccSemicolonBody; - Annotation overrideAnn = override ? makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, tdParent.get()) : null; - Annotation rrAnn = cfv.generateReturnsReceiver() ? generateNamedAnnotation(tdParent.get(), CheckerFrameworkVersion.NAME__RETURNS_RECEIVER): null; - Annotation sefAnn = cfv.generatePure() ? generateNamedAnnotation(tdParent.get(), CheckerFrameworkVersion.NAME__PURE): null; + Annotation overrideAnn = override ? makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, job.parentType.get()) : null; + Annotation rrAnn = job.checkerFramework.generateReturnsReceiver() ? generateNamedAnnotation(job.parentType.get(), CheckerFrameworkVersion.NAME__RETURNS_RECEIVER): null; + Annotation sefAnn = job.checkerFramework.generatePure() ? generateNamedAnnotation(job.parentType.get(), CheckerFrameworkVersion.NAME__PURE): null; if (overrideAnn != null && rrAnn != null && sefAnn != null) out.annotations = new Annotation[] {overrideAnn, rrAnn, sefAnn}; else if (overrideAnn != null && rrAnn != null) out.annotations = new Annotation[] {overrideAnn, rrAnn}; else if (overrideAnn != null && sefAnn != null) out.annotations = new Annotation[] {overrideAnn, sefAnn}; @@ -802,54 +836,52 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { return out; } - private MethodDeclaration generateSelfMethod(CheckerFrameworkVersion cfv, EclipseNode builderImplType, TypeParameter[] typeParams, long p) { - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) builderImplType.top().get()).compilationResult); + private MethodDeclaration generateSelfMethod(BuilderJob job) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.selector = SELF_METHOD_NAME; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccProtected; - Annotation overrideAnn = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, builderImplType.get()); - Annotation rrAnn = cfv.generateReturnsReceiver() ? generateNamedAnnotation(builderImplType.get(), CheckerFrameworkVersion.NAME__RETURNS_RECEIVER) : null; - Annotation sefAnn = cfv.generatePure() ? generateNamedAnnotation(builderImplType.get(), CheckerFrameworkVersion.NAME__PURE) : null; + Annotation overrideAnn = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, job.builderType.get()); + Annotation rrAnn = job.checkerFramework.generateReturnsReceiver() ? generateNamedAnnotation(job.builderType.get(), CheckerFrameworkVersion.NAME__RETURNS_RECEIVER) : null; + Annotation sefAnn = job.checkerFramework.generatePure() ? generateNamedAnnotation(job.builderType.get(), CheckerFrameworkVersion.NAME__PURE) : null; if (rrAnn != null && sefAnn != null) out.annotations = new Annotation[] {overrideAnn, rrAnn, sefAnn}; else if (rrAnn != null) out.annotations = new Annotation[] {overrideAnn, rrAnn}; else if (sefAnn != null) out.annotations = new Annotation[] {overrideAnn, sefAnn}; else out.annotations = new Annotation[] {overrideAnn}; - out.returnType = namePlusTypeParamsToTypeReference(builderImplType, typeParams, p); + out.returnType = namePlusTypeParamsToTypeReference(job.builderType, job.typeParams, job.getPos()); out.statements = new Statement[] {new ReturnStatement(new ThisReference(0, 0), 0, 0)}; return out; } - private MethodDeclaration generateAbstractBuildMethod(CheckerFrameworkVersion cfv, EclipseNode builderType, String methodName, List<BuilderFieldData> builderFields, boolean override, - String classGenericName, ASTNode source) { - - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); + private MethodDeclaration generateAbstractBuildMethod(BuilderJob job, boolean override, String classGenericName) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract | ExtraCompilerModifiers.AccSemicolonBody; - out.selector = methodName.toCharArray(); + out.selector = job.buildMethodName.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.returnType = new SingleTypeReference(classGenericName.toCharArray(), 0); - Annotation overrideAnn = override ? makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source) : null; - Annotation sefAnn = cfv.generateSideEffectFree() ? generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE): null; + Annotation overrideAnn = override ? makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, job.source) : null; + Annotation sefAnn = job.checkerFramework.generateSideEffectFree() ? generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE): null; if (overrideAnn != null && sefAnn != null) out.annotations = new Annotation[] {overrideAnn, sefAnn}; else if (overrideAnn != null) out.annotations = new Annotation[] {overrideAnn}; else if (sefAnn != null) out.annotations = new Annotation[] {sefAnn}; - out.receiver = HandleBuilder.generateBuildReceiver(cfv, builderType, builderFields, source); - out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); + out.receiver = HandleBuilder.generateBuildReceiver(job); + out.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); return out; } - private MethodDeclaration generateBuildMethod(CheckerFrameworkVersion cfv, EclipseNode builderType, String name, TypeReference returnType, List<BuilderFieldData> builderFields, ASTNode source) { - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); + private MethodDeclaration generateBuildMethod(BuilderJob job, TypeReference returnType) { + MethodDeclaration out = job.createNewMethodDeclaration(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; List<Statement> statements = new ArrayList<Statement>(); out.modifiers = ClassFileConstants.AccPublic; - out.selector = name.toCharArray(); + out.selector = job.buildMethodName.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.returnType = returnType; - Annotation overrideAnn = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source); - Annotation sefAnn = cfv.generateSideEffectFree() ? generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE): null; + Annotation overrideAnn = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, job.source); + Annotation sefAnn = job.checkerFramework.generateSideEffectFree() ? generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE): null; if (sefAnn != null) out.annotations = new Annotation[] {overrideAnn, sefAnn}; else out.annotations = new Annotation[] {overrideAnn}; @@ -859,43 +891,44 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { allocationStatement.arguments = new Expression[] {new ThisReference(0, 0)}; statements.add(new ReturnStatement(allocationStatement, 0, 0)); out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]); - out.receiver = HandleBuilder.generateBuildReceiver(cfv, builderType, builderFields, source); - createRelevantNonNullAnnotation(builderType, out); - out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); + out.receiver = HandleBuilder.generateBuildReceiver(job); + createRelevantNonNullAnnotation(job.builderType, out); + out.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); return out; } - private MethodDeclaration generateCleanMethod(List<BuilderFieldData> builderFields, EclipseNode builderType, ASTNode source) { + private MethodDeclaration generateCleanMethod(BuilderJob job) { List<Statement> statements = new ArrayList<Statement>(); - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, builderType, statements); + bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, job.builderType, statements); } } FieldReference thisUnclean = new FieldReference(CLEAN_FIELD_NAME, 0); thisUnclean.receiver = new ThisReference(0, 0); statements.add(new Assignment(thisUnclean, new FalseLiteral(0, 0), 0)); - MethodDeclaration decl = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); + MethodDeclaration decl = job.createNewMethodDeclaration(); + //new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); decl.selector = CLEAN_METHOD_NAME; decl.modifiers = ClassFileConstants.AccPrivate; decl.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; decl.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0); decl.statements = statements.toArray(new Statement[0]); - decl.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); + decl.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null); return decl; } - private void generateBuilderFields(EclipseNode builderType, List<BuilderFieldData> builderFields, ASTNode source) { + private void generateBuilderFields(BuilderJob job) { List<EclipseNode> existing = new ArrayList<EclipseNode>(); - for (EclipseNode child : builderType.down()) { + for (EclipseNode child : job.builderType.down()) { if (child.getKind() == Kind.FIELD) existing.add(child); } - for (BuilderFieldData bfd : builderFields) { + for (BuilderFieldData bfd : job.builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, builderType)); + bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, job.builderType)); } else { EclipseNode field = null, setFlag = null; for (EclipseNode exists : existing) { @@ -909,23 +942,23 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { fd.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; fd.modifiers = ClassFileConstants.AccPrivate; fd.type = copyType(bfd.type); - fd.traverse(new SetGeneratedByVisitor(source), (MethodScope) null); - field = injectFieldAndMarkGenerated(builderType, fd); + fd.traverse(new SetGeneratedByVisitor(job.source), (MethodScope) null); + field = injectFieldAndMarkGenerated(job.builderType, fd); } if (setFlag == null && bfd.nameOfSetFlag != null) { FieldDeclaration fd = new FieldDeclaration(bfd.nameOfSetFlag, 0, 0); fd.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; fd.modifiers = ClassFileConstants.AccPrivate; fd.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); - fd.traverse(new SetGeneratedByVisitor(source), (MethodScope) null); - injectFieldAndMarkGenerated(builderType, fd); + fd.traverse(new SetGeneratedByVisitor(job.source), (MethodScope) null); + injectFieldAndMarkGenerated(job.builderType, fd); } bfd.createdFields.add(field); } } } - private void generateSetterMethodsForBuilder(CheckerFrameworkVersion cfv, EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, final String builderGenericName, String setterPrefix) { + private void generateSetterMethodsForBuilder(BuilderJob job, BuilderFieldData bfd, final String builderGenericName, String setterPrefix) { boolean deprecate = isFieldDeprecated(bfd.originalFieldNode); TypeReferenceMaker returnTypeMaker = new TypeReferenceMaker() { @@ -944,15 +977,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { }; if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) { - generateSimpleSetterMethodForBuilder(cfv, builderType, deprecate, bfd.createdFields.get(0), bfd.name, bfd.nameOfSetFlag, returnTypeMaker.make(), returnStatementMaker.make(), sourceNode, bfd.annotations, bfd.originalFieldNode, setterPrefix); + generateSimpleSetterMethodForBuilder(job, deprecate, bfd.createdFields.get(0), bfd.name, bfd.nameOfSetFlag, returnTypeMaker.make(), returnStatementMaker.make(), bfd.annotations, bfd.originalFieldNode, setterPrefix); } else { - bfd.singularData.getSingularizer().generateMethods(cfv, bfd.singularData, deprecate, builderType, true, returnTypeMaker, returnStatementMaker, AccessLevel.PUBLIC); + bfd.singularData.getSingularizer().generateMethods(job.checkerFramework, bfd.singularData, deprecate, job.builderType, true, returnTypeMaker, returnStatementMaker, AccessLevel.PUBLIC); } } - - private void generateSimpleSetterMethodForBuilder(CheckerFrameworkVersion cfv, EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] paramName, char[] nameOfSetFlag, TypeReference returnType, Statement returnStatement, EclipseNode sourceNode, Annotation[] annosOnParam, EclipseNode originalFieldNode, String setterPrefix) { - TypeDeclaration td = (TypeDeclaration) builderType.get(); - ASTNode source = sourceNode.get(); + + private void generateSimpleSetterMethodForBuilder(BuilderJob job, boolean deprecate, EclipseNode fieldNode, char[] paramName, char[] nameOfSetFlag, TypeReference returnType, Statement returnStatement, Annotation[] annosOnParam, EclipseNode originalFieldNode, String setterPrefix) { + TypeDeclaration td = (TypeDeclaration) job.builderType.get(); AbstractMethodDeclaration[] existing = td.methods; if (existing == null) existing = EMPTY_METHODS; int len = existing.length; @@ -966,23 +998,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } List<Annotation> methodAnnsList = Arrays.asList(EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode)); - if (cfv.generateReturnsReceiver()) { + if (job.checkerFramework.generateReturnsReceiver()) { methodAnnsList = new ArrayList<Annotation>(methodAnnsList); - methodAnnsList.add(generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER)); + methodAnnsList.add(generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER)); } MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, paramName, nameOfSetFlag, returnType, returnStatement, ClassFileConstants.AccPublic, - sourceNode, methodAnnsList, annosOnParam != null ? Arrays.asList(copyAnnotations(source, annosOnParam)) : Collections.<Annotation>emptyList()); - if (cfv.generateCalledMethods()) { - char[][] nameNotCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__NOT_CALLED); - SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameNotCalled, poss(source, nameNotCalled.length)), source.sourceStart); - ann.memberValue = new StringLiteral(setterName.toCharArray(), 0, 0, 0); - - QualifiedTypeReference typeReference = (QualifiedTypeReference) generateTypeReference(builderType, 0); - typeReference.annotations = new Annotation[typeReference.tokens.length][]; - typeReference.annotations[0] = new Annotation[] {ann}; - setter.receiver = new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, Modifier.FINAL); - } - injectMethod(builderType, setter); + job.sourceNode, methodAnnsList, annosOnParam != null ? Arrays.asList(copyAnnotations(job.source, annosOnParam)) : Collections.<Annotation>emptyList()); + if (job.checkerFramework.generateCalledMethods()) setter.receiver = generateNotCalledReceiver(job, setterName); + injectMethod(job.builderType, setter); } private void addObtainVia(BuilderFieldData bfd, EclipseNode node) { |