mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 12:15:00 +00:00
Merge branch 'master' of https://github.com/janrieke/lombok into janrieke-master
Also fixed up style and docs, and updated behaviour when using `@Builder(inherit = true)` to error if you have no parent class.
This commit is contained in:
commit
cde47abc26
16 files changed
+494
-154
No files matched your search
@@ -131,6 +131,48 @@ public @interface Builder {
|
||||
*/
|
||||
String builderClassName() default "";
|
||||
|
||||
/**
|
||||
* Should the generated builder extend the parent class's builder?
|
||||
*
|
||||
* If {@code true}, the generated builder class will extend the builder of the
|
||||
* superclass. This means the builder also contains the methods for fields from
|
||||
* the superclass.
|
||||
* <p>
|
||||
* Note that both this builder and the superclass' builder must be a builder
|
||||
* for a type (so, not for a static method or a constructor). You must mark
|
||||
* the parent extendable: {@code @Builder(extensible = true)}.
|
||||
* <p>
|
||||
* This builder will also be {@code extensible = true} if you set {@code inherit = true}.
|
||||
*
|
||||
* @see #extensible()
|
||||
*/
|
||||
boolean inherit() default false;
|
||||
|
||||
/**
|
||||
* Should the generated builder be extensible by subclasses?
|
||||
*
|
||||
* If {@code true} the generated builder class will be extensible by
|
||||
* {@code @Builder} classes of this class's subclasses, by marking them
|
||||
* with {@code @Builder(inherit = true)}.
|
||||
* <p>
|
||||
* The {@code @Builder} extensible system only works for {@code @Builder}
|
||||
* annotations on types (so, not on a static method or a constructor).
|
||||
*
|
||||
* @see #inherit()
|
||||
*/
|
||||
boolean extensible() default false;
|
||||
|
||||
/**
|
||||
* Name of the builder class in the superclass.
|
||||
*
|
||||
* Only relevant if {@code inherit = true}
|
||||
*
|
||||
* Default: {@code (SuperclassTypeName)Builder}.
|
||||
*
|
||||
* @see #inherit()
|
||||
*/
|
||||
String superclassBuilderClassName() default "";
|
||||
|
||||
/**
|
||||
* If true, generate an instance method to obtain a builder that is initialized with the values of this instance.
|
||||
* Legal only if {@code @Builder} is used on a constructor, on the type itself, or on a static method that returns
|
||||
|
||||
@@ -45,6 +45,8 @@ import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Reference;
|
||||
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.ThisReference;
|
||||
@@ -216,7 +218,7 @@ public class EclipseSingularsRecipes {
|
||||
|
||||
public abstract List<EclipseNode> generateFields(SingularData data, EclipseNode builderType);
|
||||
public abstract void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, boolean chain);
|
||||
public abstract void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName);
|
||||
public abstract void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName, String builderVariable);
|
||||
|
||||
public boolean requiresCleaning() {
|
||||
try {
|
||||
@@ -307,16 +309,16 @@ public class EclipseSingularsRecipes {
|
||||
private static final char[] SIZE_TEXT = new char[] {'s', 'i', 'z', 'e'};
|
||||
|
||||
/** Generates 'this.<em>name</em>.size()' as an expression; if nullGuard is true, it's this.name == null ? 0 : this.name.size(). */
|
||||
protected Expression getSize(EclipseNode builderType, char[] name, boolean nullGuard) {
|
||||
protected Expression getSize(EclipseNode builderType, char[] name, boolean nullGuard, String builderVariable) {
|
||||
MessageSend invoke = new MessageSend();
|
||||
ThisReference thisRef = new ThisReference(0, 0);
|
||||
Reference thisRef = getBuilderReference(builderVariable);
|
||||
FieldReference thisDotName = new FieldReference(name, 0L);
|
||||
thisDotName.receiver = thisRef;
|
||||
invoke.receiver = thisDotName;
|
||||
invoke.selector = SIZE_TEXT;
|
||||
if (!nullGuard) return invoke;
|
||||
|
||||
ThisReference cdnThisRef = new ThisReference(0, 0);
|
||||
Reference cdnThisRef = getBuilderReference(builderVariable);
|
||||
FieldReference cdnThisDotName = new FieldReference(name, 0L);
|
||||
cdnThisDotName.receiver = cdnThisRef;
|
||||
NullLiteral nullLiteral = new NullLiteral(0, 0);
|
||||
@@ -345,5 +347,14 @@ public class EclipseSingularsRecipes {
|
||||
|
||||
return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, NULL_POSS);
|
||||
}
|
||||
|
||||
/** @return a {@code SingleNameReference} to the builder in the variable <code>builderVariable</code>. If {@ code builderVariable == "this"}, a {@code ThisReference} is returned. */
|
||||
protected static Reference getBuilderReference(String builderVariable) {
|
||||
if ("this".equals(builderVariable)) {
|
||||
return new ThisReference(0, 0);
|
||||
} else {
|
||||
return new SingleNameReference(builderVariable.toCharArray(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import static lombok.eclipse.Eclipse.*;
|
||||
import static lombok.core.handlers.HandlerUtil.*;
|
||||
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -40,6 +41,7 @@ import org.eclipse.jdt.internal.compiler.ast.Assignment;
|
||||
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Expression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
|
||||
@@ -50,6 +52,7 @@ import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
|
||||
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.QualifiedThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
|
||||
@@ -81,6 +84,7 @@ import lombok.core.HandlerPriority;
|
||||
import lombok.eclipse.Eclipse;
|
||||
import lombok.eclipse.EclipseAnnotationHandler;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData;
|
||||
import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists;
|
||||
@@ -102,6 +106,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
}
|
||||
|
||||
private static class BuilderFieldData {
|
||||
EclipseNode fieldNode;
|
||||
TypeReference type;
|
||||
char[] rawName;
|
||||
char[] name;
|
||||
@@ -155,6 +160,10 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
String builderMethodName = builderInstance.builderMethodName();
|
||||
String buildMethodName = builderInstance.buildMethodName();
|
||||
String builderClassName = builderInstance.builderClassName();
|
||||
|
||||
boolean inherit = builderInstance.inherit();
|
||||
boolean extensible = inherit || builderInstance.extensible(); // inherit implies extendable
|
||||
|
||||
String toBuilderMethodName = "toBuilder";
|
||||
boolean toBuilder = builderInstance.toBuilder();
|
||||
List<char[]> typeArgsForToBuilder = null;
|
||||
@@ -182,9 +191,11 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
boolean addCleaning = false;
|
||||
boolean isStatic = true;
|
||||
|
||||
TypeDeclaration td = null;
|
||||
|
||||
if (parent.get() instanceof TypeDeclaration) {
|
||||
tdParent = parent;
|
||||
TypeDeclaration td = (TypeDeclaration) tdParent.get();
|
||||
td = (TypeDeclaration) tdParent.get();
|
||||
|
||||
List<EclipseNode> allFields = new ArrayList<EclipseNode>();
|
||||
boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent));
|
||||
@@ -194,6 +205,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
boolean isFinal = ((fd.modifiers & ClassFileConstants.AccFinal) != 0) || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode));
|
||||
|
||||
BuilderFieldData bfd = new BuilderFieldData();
|
||||
bfd.fieldNode = fieldNode;
|
||||
bfd.rawName = fieldNode.getName().toCharArray();
|
||||
bfd.name = removePrefixFromField(fieldNode);
|
||||
bfd.type = fd.type;
|
||||
@@ -227,15 +239,29 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
allFields.add(fieldNode);
|
||||
}
|
||||
|
||||
handleConstructor.generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER,
|
||||
Collections.<Annotation>emptyList(), annotationNode);
|
||||
if (builderClassName.isEmpty()) builderClassName = new String(td.name) + "Builder";
|
||||
|
||||
if (extensible) {
|
||||
boolean callBuilderBasedSuperConstructor = td.superclass != null;
|
||||
generateBuilderBasedConstructor(tdParent, builderFields, annotationNode, builderClassName, callBuilderBasedSuperConstructor);
|
||||
} else {
|
||||
handleConstructor.generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER,
|
||||
Collections.<Annotation>emptyList(), annotationNode);
|
||||
}
|
||||
|
||||
returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p);
|
||||
typeParams = td.typeParameters;
|
||||
thrownExceptions = null;
|
||||
nameOfStaticBuilderMethod = null;
|
||||
if (builderClassName.isEmpty()) builderClassName = new String(td.name) + "Builder";
|
||||
} else if (parent.get() instanceof ConstructorDeclaration) {
|
||||
if (inherit) {
|
||||
annotationNode.addError("@Builder(inherit=true) is only supported for type builders.");
|
||||
return;
|
||||
}
|
||||
if (extensible) {
|
||||
annotationNode.addError("@Builder(extensible=true) is only supported for type builders.");
|
||||
return;
|
||||
}
|
||||
ConstructorDeclaration cd = (ConstructorDeclaration) parent.get();
|
||||
if (cd.typeParameters != null && cd.typeParameters.length > 0) {
|
||||
annotationNode.addError("@Builder is not supported on constructors with constructor type parameters.");
|
||||
@@ -243,13 +269,21 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
}
|
||||
|
||||
tdParent = parent.up();
|
||||
TypeDeclaration td = (TypeDeclaration) tdParent.get();
|
||||
td = (TypeDeclaration) tdParent.get();
|
||||
returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p);
|
||||
typeParams = td.typeParameters;
|
||||
thrownExceptions = cd.thrownExceptions;
|
||||
nameOfStaticBuilderMethod = null;
|
||||
if (builderClassName.isEmpty()) builderClassName = new String(cd.selector) + "Builder";
|
||||
} else if (parent.get() instanceof MethodDeclaration) {
|
||||
if (inherit) {
|
||||
annotationNode.addError("@Builder(inherit=true) is only supported for type builders.");
|
||||
return;
|
||||
}
|
||||
if (extensible) {
|
||||
annotationNode.addError("@Builder(extendable=true) is only supported for type builders.");
|
||||
return;
|
||||
}
|
||||
MethodDeclaration md = (MethodDeclaration) parent.get();
|
||||
tdParent = parent.up();
|
||||
isStatic = md.isStatic();
|
||||
@@ -380,7 +414,20 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
|
||||
EclipseNode builderType = findInnerClass(tdParent, builderClassName);
|
||||
if (builderType == null) {
|
||||
builderType = makeBuilderClass(isStatic, tdParent, builderClassName, typeParams, ast);
|
||||
String superclassBuilderClassName = null;
|
||||
if (inherit) {
|
||||
if (td.superclass == null) {
|
||||
annotationNode.addError("@Builder(inherit = true) requires that your class has an 'extends' clause.");
|
||||
return;
|
||||
}
|
||||
|
||||
superclassBuilderClassName = builderInstance.superclassBuilderClassName();
|
||||
if (superclassBuilderClassName == null || superclassBuilderClassName.isEmpty()) {
|
||||
superclassBuilderClassName = new String(td.superclass.getLastToken()) + "Builder";
|
||||
}
|
||||
}
|
||||
|
||||
builderType = makeBuilderClass(isStatic, tdParent, builderClassName, typeParams, ast, superclassBuilderClassName);
|
||||
} else {
|
||||
TypeDeclaration builderTypeDeclaration = (TypeDeclaration) builderType.get();
|
||||
if (isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) == 0) {
|
||||
@@ -444,7 +491,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
}
|
||||
|
||||
if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) {
|
||||
MethodDeclaration md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast);
|
||||
MethodDeclaration md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast, extensible);
|
||||
if (md != null) injectMethod(builderType, md);
|
||||
}
|
||||
|
||||
@@ -492,8 +539,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
long p = (long) pS << 32 | pE;
|
||||
|
||||
MethodDeclaration out = new MethodDeclaration(
|
||||
((CompilationUnitDeclaration) type.top().get()).compilationResult);
|
||||
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
|
||||
out.selector = methodName.toCharArray();
|
||||
out.modifiers = ClassFileConstants.AccPublic;
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
@@ -531,6 +577,95 @@ public class HandleBuilder extends EclipseAnnotationHandler<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 builderFields a list of fields in the builder which should be assigned to new instances.
|
||||
* @param sourceNode the annotation (used for setting source code locations for the generated code).
|
||||
* @param builderClassnameAsParameter
|
||||
* If {@code != null}, the only parameter of the constructor will
|
||||
* be a builder with this classname; the constructor will then
|
||||
* use the values within this builder to assign the fields of new
|
||||
* instances.
|
||||
* @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(EclipseNode typeNode, List<BuilderFieldData> builderFields, EclipseNode sourceNode,
|
||||
String builderClassnameAsParameter, boolean callBuilderBasedSuperConstructor) {
|
||||
|
||||
ASTNode source = sourceNode.get();
|
||||
|
||||
TypeDeclaration typeDeclaration = ((TypeDeclaration) typeNode.get());
|
||||
long p = (long) source.sourceStart << 32 | source.sourceEnd;
|
||||
|
||||
boolean isEnum = (((TypeDeclaration) typeNode.get()).modifiers & ClassFileConstants.AccEnum) != 0;
|
||||
AccessLevel level = isEnum ? AccessLevel.PRIVATE : AccessLevel.PROTECTED;
|
||||
|
||||
ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) typeNode.top().get()).compilationResult);
|
||||
|
||||
constructor.modifiers = toEclipseModifier(level);
|
||||
constructor.selector = typeDeclaration.name;
|
||||
if (callBuilderBasedSuperConstructor) {
|
||||
constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.Super);
|
||||
constructor.constructorCall.arguments = new Expression[] {new SingleNameReference("b".toCharArray(), p)};
|
||||
} else {
|
||||
constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
|
||||
}
|
||||
constructor.constructorCall.sourceStart = source.sourceStart;
|
||||
constructor.constructorCall.sourceEnd = source.sourceEnd;
|
||||
constructor.thrownExceptions = null;
|
||||
constructor.typeParameters = null;
|
||||
constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart;
|
||||
constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd;
|
||||
constructor.arguments = null;
|
||||
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
List<Statement> nullChecks = new ArrayList<Statement>();
|
||||
|
||||
for (BuilderFieldData fieldNode : builderFields) {
|
||||
char[] fieldName = removePrefixFromField(fieldNode.fieldNode);
|
||||
FieldReference thisX = new FieldReference(fieldNode.rawName, p);
|
||||
int s = (int) (p >> 32);
|
||||
int e = (int) p;
|
||||
thisX.receiver = new ThisReference(s, e);
|
||||
|
||||
Expression assignmentExpr;
|
||||
if (fieldNode.singularData != null && fieldNode.singularData.getSingularizer() != null) {
|
||||
fieldNode.singularData.getSingularizer().appendBuildCode(fieldNode.singularData, typeNode, statements, fieldNode.name, "b");
|
||||
assignmentExpr = new SingleNameReference(fieldNode.name, p);
|
||||
} else {
|
||||
char[][] variableInBuilder = new char[][] {"b".toCharArray(), fieldName};
|
||||
long[] positions = new long[] {p, p};
|
||||
assignmentExpr = new QualifiedNameReference(variableInBuilder, positions, s, e);
|
||||
}
|
||||
|
||||
Assignment assignment = new Assignment(thisX, assignmentExpr, (int) p);
|
||||
statements.add(assignment);
|
||||
Annotation[] nonNulls = findAnnotations((FieldDeclaration)fieldNode.fieldNode.get(), NON_NULL_PATTERN);
|
||||
if (nonNulls.length != 0) {
|
||||
Statement nullCheck = generateNullCheck((FieldDeclaration)fieldNode.fieldNode.get(), sourceNode);
|
||||
if (nullCheck != null) {
|
||||
nullChecks.add(nullCheck);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nullChecks.addAll(statements);
|
||||
constructor.statements = nullChecks.isEmpty() ? null : nullChecks.toArray(new Statement[nullChecks.size()]);
|
||||
constructor.arguments = new Argument[] {new Argument("b".toCharArray(), p, new SingleTypeReference(builderClassnameAsParameter.toCharArray(), p), Modifier.FINAL)};
|
||||
|
||||
constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope);
|
||||
|
||||
injectMethod(typeNode, constructor);
|
||||
}
|
||||
|
||||
private MethodDeclaration generateCleanMethod(List<BuilderFieldData> builderFields, EclipseNode builderType, ASTNode source) {
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
|
||||
@@ -553,49 +688,58 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
return decl;
|
||||
}
|
||||
|
||||
public MethodDeclaration generateBuildMethod(EclipseNode tdParent, boolean isStatic, String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source) {
|
||||
/**
|
||||
* @param useBuilderBasedConstructor
|
||||
* if true, the {@code build()} method will use a constructor
|
||||
* that takes the builder instance as parameter (instead of a
|
||||
* constructor with all relevant fields as parameters)
|
||||
*/
|
||||
public MethodDeclaration generateBuildMethod(EclipseNode tdParent, boolean isStatic, String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source, boolean useBuilderBasedConstructor) {
|
||||
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
|
||||
if (addCleaning) {
|
||||
FieldReference thisUnclean = new FieldReference(CLEAN_FIELD_NAME, 0);
|
||||
thisUnclean.receiver = new ThisReference(0, 0);
|
||||
Expression notClean = new UnaryExpression(thisUnclean, OperatorIds.NOT);
|
||||
MessageSend invokeClean = new MessageSend();
|
||||
invokeClean.selector = CLEAN_METHOD_NAME;
|
||||
statements.add(new IfStatement(notClean, invokeClean, 0, 0));
|
||||
}
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, type, statements, bfd.name);
|
||||
}
|
||||
}
|
||||
|
||||
List<Expression> args = new ArrayList<Expression>();
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.nameOfSetFlag != null) {
|
||||
MessageSend inv = new MessageSend();
|
||||
inv.sourceStart = source.sourceStart;
|
||||
inv.sourceEnd = source.sourceEnd;
|
||||
inv.receiver = new SingleNameReference(((TypeDeclaration) tdParent.get()).name, 0L);
|
||||
inv.selector = bfd.nameOfDefaultProvider;
|
||||
inv.typeArguments = typeParameterNames(((TypeDeclaration) type.get()).typeParameters);
|
||||
|
||||
args.add(new ConditionalExpression(
|
||||
new SingleNameReference(bfd.nameOfSetFlag, 0L),
|
||||
new SingleNameReference(bfd.name, 0L),
|
||||
inv));
|
||||
} else {
|
||||
args.add(new SingleNameReference(bfd.name, 0L));
|
||||
}
|
||||
}
|
||||
|
||||
if (addCleaning) {
|
||||
FieldReference thisUnclean = new FieldReference(CLEAN_FIELD_NAME, 0);
|
||||
thisUnclean.receiver = new ThisReference(0, 0);
|
||||
statements.add(new Assignment(thisUnclean, new TrueLiteral(0, 0), 0));
|
||||
// Extendable builders assign their values in the constructor, not in this build() method.
|
||||
if (!useBuilderBasedConstructor) {
|
||||
if (addCleaning) {
|
||||
FieldReference thisUnclean = new FieldReference(CLEAN_FIELD_NAME, 0);
|
||||
thisUnclean.receiver = new ThisReference(0, 0);
|
||||
Expression notClean = new UnaryExpression(thisUnclean, OperatorIds.NOT);
|
||||
MessageSend invokeClean = new MessageSend();
|
||||
invokeClean.selector = CLEAN_METHOD_NAME;
|
||||
statements.add(new IfStatement(notClean, invokeClean, 0, 0));
|
||||
}
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, type, statements, bfd.name, "this");
|
||||
}
|
||||
}
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.nameOfSetFlag != null) {
|
||||
MessageSend inv = new MessageSend();
|
||||
inv.sourceStart = source.sourceStart;
|
||||
inv.sourceEnd = source.sourceEnd;
|
||||
inv.receiver = new SingleNameReference(((TypeDeclaration) tdParent.get()).name, 0L);
|
||||
inv.selector = bfd.nameOfDefaultProvider;
|
||||
inv.typeArguments = typeParameterNames(((TypeDeclaration) type.get()).typeParameters);
|
||||
|
||||
args.add(new ConditionalExpression(
|
||||
new SingleNameReference(bfd.nameOfSetFlag, 0L),
|
||||
new SingleNameReference(bfd.name, 0L),
|
||||
inv));
|
||||
} else {
|
||||
args.add(new SingleNameReference(bfd.name, 0L));
|
||||
}
|
||||
}
|
||||
|
||||
if (addCleaning) {
|
||||
FieldReference thisUnclean = new FieldReference(CLEAN_FIELD_NAME, 0);
|
||||
thisUnclean.receiver = new ThisReference(0, 0);
|
||||
statements.add(new Assignment(thisUnclean, new TrueLiteral(0, 0), 0));
|
||||
}
|
||||
}
|
||||
|
||||
out.modifiers = ClassFileConstants.AccPublic;
|
||||
@@ -607,7 +751,13 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
if (staticName == null) {
|
||||
AllocationExpression allocationStatement = new AllocationExpression();
|
||||
allocationStatement.type = copyType(out.returnType);
|
||||
allocationStatement.arguments = args.isEmpty() ? null : args.toArray(new Expression[args.size()]);
|
||||
if (useBuilderBasedConstructor) {
|
||||
// Use a constructor that only has this builder as parameter.
|
||||
allocationStatement.arguments = new Expression[] {new ThisReference(0, 0)};
|
||||
} else {
|
||||
// Use a constructor with all the fields.
|
||||
allocationStatement.arguments = args.isEmpty() ? null : args.toArray(new Expression[args.size()]);
|
||||
}
|
||||
statements.add(new ReturnStatement(allocationStatement, 0, 0));
|
||||
} else {
|
||||
MessageSend invoke = new MessageSend();
|
||||
@@ -756,7 +906,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
return null;
|
||||
}
|
||||
|
||||
public EclipseNode makeBuilderClass(boolean isStatic, EclipseNode tdParent, String builderClassName, TypeParameter[] typeParams, ASTNode source) {
|
||||
public EclipseNode makeBuilderClass(boolean isStatic, EclipseNode tdParent, String builderClassName, TypeParameter[] typeParams, ASTNode source, String parentBuilderClassName) {
|
||||
TypeDeclaration parent = (TypeDeclaration) tdParent.get();
|
||||
TypeDeclaration builder = new TypeDeclaration(parent.compilationResult);
|
||||
builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
@@ -764,6 +914,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
if (isStatic) builder.modifiers |= ClassFileConstants.AccStatic;
|
||||
builder.typeParameters = copyTypeParams(typeParams, source);
|
||||
builder.name = builderClassName.toCharArray();
|
||||
if (parentBuilderClassName != null) builder.superclass = new SingleTypeReference(parentBuilderClassName.toCharArray(), 0);
|
||||
builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null);
|
||||
return injectType(tdParent, builder);
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ public class HandleConstructor {
|
||||
}
|
||||
}
|
||||
|
||||
private static final char[][] JAVA_BEANS_CONSTRUCTORPROPERTIES = new char[][] { "java".toCharArray(), "beans".toCharArray(), "ConstructorProperties".toCharArray() };
|
||||
public static final char[][] JAVA_BEANS_CONSTRUCTORPROPERTIES = new char[][] { "java".toCharArray(), "beans".toCharArray(), "ConstructorProperties".toCharArray() };
|
||||
public static Annotation[] createConstructorProperties(ASTNode source, Collection<EclipseNode> fields) {
|
||||
if (fields.isEmpty()) return null;
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer {
|
||||
injectMethod(builderType, md);
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName, String builderVariable) {
|
||||
TypeReference varType = new QualifiedTypeReference(fromQualifiedName(data.getTargetFqn()), NULL_POSS);
|
||||
String simpleTypeName = getSimpleTargetTypeName(data);
|
||||
int agrumentsCount = getTypeArgumentsCount();
|
||||
@@ -219,14 +219,14 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer {
|
||||
invokeBuild = new MessageSend();
|
||||
invokeBuild.selector = new char[] {'b', 'u', 'i', 'l', 'd'};
|
||||
FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
thisDotField.receiver = getBuilderReference(builderVariable);
|
||||
invokeBuild.receiver = thisDotField;
|
||||
}
|
||||
|
||||
Expression isNull; {
|
||||
//this.pluralName == null
|
||||
FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
thisDotField.receiver = getBuilderReference(builderVariable);
|
||||
isNull = new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SwitchStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
@@ -56,9 +55,9 @@ public class EclipseJavaUtilListSingularizer extends EclipseJavaUtilListSetSingu
|
||||
return LombokImmutableList.of("java.util.List", "java.util.Collection", "java.lang.Iterable");
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName, String builderVariable) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, statements, targetVariableName);
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, statements, targetVariableName, builderVariable);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -76,7 +75,7 @@ public class EclipseJavaUtilListSingularizer extends EclipseJavaUtilListSetSingu
|
||||
/* case 1: (singleton) break; */ {
|
||||
switchContents.add(new CaseStatement(makeIntLiteral(new char[] {'1'}, null), 0, 0));
|
||||
FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
thisDotField.receiver = getBuilderReference(builderVariable);
|
||||
MessageSend thisDotFieldGet0 = new MessageSend();
|
||||
thisDotFieldGet0.receiver = thisDotField;
|
||||
thisDotFieldGet0.selector = new char[] {'g', 'e', 't'};
|
||||
@@ -97,7 +96,7 @@ public class EclipseJavaUtilListSingularizer extends EclipseJavaUtilListSetSingu
|
||||
Expression argToUnmodifiable;
|
||||
/* new j.u.ArrayList<Generics>(this.pluralName); */ {
|
||||
FieldReference thisDotPluralName = new FieldReference(data.getPluralName(), 0L);
|
||||
thisDotPluralName.receiver = new ThisReference(0, 0);
|
||||
thisDotPluralName.receiver = getBuilderReference(builderVariable);
|
||||
TypeReference targetTypeExpr = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS);
|
||||
targetTypeExpr = addTypeArgs(1, false, builderType, targetTypeExpr, data.getTypeArgs());
|
||||
AllocationExpression constructorCall = new AllocationExpression();
|
||||
@@ -117,7 +116,7 @@ public class EclipseJavaUtilListSingularizer extends EclipseJavaUtilListSetSingu
|
||||
|
||||
SwitchStatement switchStat = new SwitchStatement();
|
||||
switchStat.statements = switchContents.toArray(new Statement[switchContents.size()]);
|
||||
switchStat.expression = getSize(builderType, data.getPluralName(), true);
|
||||
switchStat.expression = getSize(builderType, data.getPluralName(), true, builderVariable);
|
||||
|
||||
TypeReference localShadowerType = new QualifiedTypeReference(Eclipse.fromQualifiedName(data.getTargetFqn()), NULL_POSS);
|
||||
localShadowerType = addTypeArgs(1, false, builderType, localShadowerType, data.getTypeArgs());
|
||||
|
||||
@@ -298,16 +298,16 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer
|
||||
injectMethod(builderType, md);
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName, String builderVariable) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaMapSingularizer.appendBuildCode(data, builderType, statements, targetVariableName);
|
||||
guavaMapSingularizer.appendBuildCode(data, builderType, statements, targetVariableName, builderVariable);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.getTargetFqn().equals("java.util.Map")) {
|
||||
statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, true, "emptyMap", "singletonMap", "LinkedHashMap"));
|
||||
statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, true, "emptyMap", "singletonMap", "LinkedHashMap", builderVariable));
|
||||
} else {
|
||||
statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, true, true, false, true, "TreeMap"));
|
||||
statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, true, true, false, true, "TreeMap", builderVariable));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,16 +37,16 @@ public class EclipseJavaUtilSetSingularizer extends EclipseJavaUtilListSetSingul
|
||||
return LombokImmutableList.of("java.util.Set", "java.util.SortedSet", "java.util.NavigableSet");
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName, String builderVariable) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, statements, targetVariableName);
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, statements, targetVariableName, builderVariable);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.getTargetFqn().equals("java.util.Set")) {
|
||||
statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, false, "emptySet", "singleton", "LinkedHashSet"));
|
||||
statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, false, "emptySet", "singleton", "LinkedHashSet", builderVariable));
|
||||
} else {
|
||||
statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, false, true, false, true, "TreeSet"));
|
||||
statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, false, true, false, true, "TreeSet", builderVariable));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
return Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_USE_GUAVA));
|
||||
}
|
||||
|
||||
protected List<Statement> createJavaUtilSetMapInitialCapacitySwitchStatements(SingularData data, EclipseNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType) {
|
||||
protected List<Statement> createJavaUtilSetMapInitialCapacitySwitchStatements(SingularData data, EclipseNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType, String builderVariable) {
|
||||
List<Statement> switchContents = new ArrayList<Statement>();
|
||||
char[] keyName = mapMode ? (new String(data.getPluralName()) + "$key").toCharArray() : data.getPluralName();
|
||||
|
||||
@@ -112,7 +112,7 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
/* !mapMode: pluralName = java.util.Collections.singletonCollectionMethod(this.pluralName.get(0));
|
||||
mapMode: pluralName = java.util.Collections.singletonCollectionMethod(this.pluralName$key.get(0), this.pluralName$value.get(0)); */ {
|
||||
FieldReference thisDotKey = new FieldReference(keyName, 0L);
|
||||
thisDotKey.receiver = new ThisReference(0, 0);
|
||||
thisDotKey.receiver = getBuilderReference(builderVariable);
|
||||
MessageSend thisDotKeyGet0 = new MessageSend();
|
||||
thisDotKeyGet0.receiver = thisDotKey;
|
||||
thisDotKeyGet0.selector = new char[] {'g', 'e', 't'};
|
||||
@@ -122,7 +122,7 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
if (mapMode) {
|
||||
char[] valueName = (new String(data.getPluralName()) + "$value").toCharArray();
|
||||
FieldReference thisDotValue = new FieldReference(valueName, 0L);
|
||||
thisDotValue.receiver = new ThisReference(0, 0);
|
||||
thisDotValue.receiver = getBuilderReference(builderVariable);
|
||||
MessageSend thisDotValueGet0 = new MessageSend();
|
||||
thisDotValueGet0.receiver = thisDotValue;
|
||||
thisDotValueGet0.selector = new char[] {'g', 'e', 't'};
|
||||
@@ -143,12 +143,12 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
|
||||
{ // default:
|
||||
switchContents.add(new CaseStatement(null, 0, 0));
|
||||
switchContents.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, mapMode, false, true, emptyCollectionMethod == null, targetType));
|
||||
switchContents.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, mapMode, false, true, emptyCollectionMethod == null, targetType, builderVariable));
|
||||
}
|
||||
|
||||
SwitchStatement switchStat = new SwitchStatement();
|
||||
switchStat.statements = switchContents.toArray(new Statement[switchContents.size()]);
|
||||
switchStat.expression = getSize(builderType, keyName, true);
|
||||
switchStat.expression = getSize(builderType, keyName, true, builderVariable);
|
||||
|
||||
TypeReference localShadowerType = new QualifiedTypeReference(fromQualifiedName(data.getTargetFqn()), NULL_POSS);
|
||||
localShadowerType = addTypeArgs(mapMode ? 2 : 1, false, builderType, localShadowerType, data.getTypeArgs());
|
||||
@@ -157,7 +157,7 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
return Arrays.asList(varDefStat, switchStat);
|
||||
}
|
||||
|
||||
protected List<Statement> createJavaUtilSimpleCreationAndFillStatements(SingularData data, EclipseNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType) {
|
||||
protected List<Statement> createJavaUtilSimpleCreationAndFillStatements(SingularData data, EclipseNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType, String builderVariable) {
|
||||
char[] varName = mapMode ? (new String(data.getPluralName()) + "$key").toCharArray() : data.getPluralName();
|
||||
|
||||
Statement createStat; {
|
||||
@@ -166,11 +166,11 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
if (addInitialCapacityArg) {
|
||||
// this.varName.size() < MAX_POWER_OF_2 ? 1 + this.varName.size() + (this.varName.size() - 3) / 3 : Integer.MAX_VALUE;
|
||||
// lessThanCutOff = this.varName.size() < MAX_POWER_OF_2
|
||||
Expression lessThanCutoff = new BinaryExpression(getSize(builderType, varName, nullGuard), makeIntLiteral("0x40000000".toCharArray(), null), OperatorIds.LESS);
|
||||
Expression lessThanCutoff = new BinaryExpression(getSize(builderType, varName, nullGuard, builderVariable), makeIntLiteral("0x40000000".toCharArray(), null), OperatorIds.LESS);
|
||||
FieldReference integerMaxValue = new FieldReference("MAX_VALUE".toCharArray(), 0L);
|
||||
integerMaxValue.receiver = new QualifiedNameReference(TypeConstants.JAVA_LANG_INTEGER, NULL_POSS, 0, 0);
|
||||
Expression sizeFormulaLeft = new BinaryExpression(makeIntLiteral(new char[] {'1'}, null), getSize(builderType, varName, nullGuard), OperatorIds.PLUS);
|
||||
Expression sizeFormulaRightLeft = new BinaryExpression(getSize(builderType, varName, nullGuard), makeIntLiteral(new char[] {'3'}, null), OperatorIds.MINUS);
|
||||
Expression sizeFormulaLeft = new BinaryExpression(makeIntLiteral(new char[] {'1'}, null), getSize(builderType, varName, nullGuard, builderVariable), OperatorIds.PLUS);
|
||||
Expression sizeFormulaRightLeft = new BinaryExpression(getSize(builderType, varName, nullGuard, builderVariable), makeIntLiteral(new char[] {'3'}, null), OperatorIds.MINUS);
|
||||
Expression sizeFormulaRight = new BinaryExpression(sizeFormulaRightLeft, makeIntLiteral(new char[] {'3'}, null), OperatorIds.DIVIDE);
|
||||
Expression sizeFormula = new BinaryExpression(sizeFormulaLeft, sizeFormulaRight, OperatorIds.PLUS);
|
||||
Expression cond = new ConditionalExpression(lessThanCutoff, sizeFormula, integerMaxValue);
|
||||
@@ -203,9 +203,9 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
pluralnameDotPut.selector = new char[] {'p', 'u', 't'};
|
||||
pluralnameDotPut.receiver = new SingleNameReference(data.getPluralName(), 0L);
|
||||
FieldReference thisDotKey = new FieldReference(varName, 0L);
|
||||
thisDotKey.receiver = new ThisReference(0, 0);
|
||||
thisDotKey.receiver = getBuilderReference(builderVariable);
|
||||
FieldReference thisDotValue = new FieldReference((new String(data.getPluralName()) + "$value").toCharArray(), 0L);
|
||||
thisDotValue.receiver = new ThisReference(0, 0);
|
||||
thisDotValue.receiver = getBuilderReference(builderVariable);
|
||||
MessageSend keyArg = new MessageSend();
|
||||
keyArg.receiver = thisDotKey;
|
||||
keyArg.arguments = new Expression[] {new SingleNameReference(iVar, 0L)};
|
||||
@@ -219,7 +219,7 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
LocalDeclaration forInit = new LocalDeclaration(iVar, 0, 0);
|
||||
forInit.type = TypeReference.baseTypeReference(TypeIds.T_int, 0);
|
||||
forInit.initialization = makeIntLiteral(new char[] {'0'}, null);
|
||||
Expression checkExpr = new BinaryExpression(new SingleNameReference(iVar, 0L), getSize(builderType, varName, nullGuard), OperatorIds.LESS);
|
||||
Expression checkExpr = new BinaryExpression(new SingleNameReference(iVar, 0L), getSize(builderType, varName, nullGuard, builderVariable), OperatorIds.LESS);
|
||||
Expression incrementExpr = new PostfixExpression(new SingleNameReference(iVar, 0L), IntLiteral.One, OperatorIds.PLUS, 0);
|
||||
fillStat = new ForStatement(new Statement[] {forInit}, checkExpr, new Statement[] {incrementExpr}, pluralnameDotPut, true, 0, 0);
|
||||
} else {
|
||||
@@ -228,14 +228,14 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
pluralnameDotAddAll.selector = new char[] {'a', 'd', 'd', 'A', 'l', 'l'};
|
||||
pluralnameDotAddAll.receiver = new SingleNameReference(data.getPluralName(), 0L);
|
||||
FieldReference thisDotPluralname = new FieldReference(varName, 0L);
|
||||
thisDotPluralname.receiver = new ThisReference(0, 0);
|
||||
thisDotPluralname.receiver = getBuilderReference(builderVariable);
|
||||
pluralnameDotAddAll.arguments = new Expression[] {thisDotPluralname};
|
||||
fillStat = pluralnameDotAddAll;
|
||||
}
|
||||
|
||||
if (nullGuard) {
|
||||
FieldReference thisDotField = new FieldReference(varName, 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
thisDotField.receiver = getBuilderReference(builderVariable);
|
||||
Expression cond = new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.NOT_EQUAL);
|
||||
fillStat = new IfStatement(cond, fillStat, 0, 0);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.sun.tools.javac.tree.JCTree.JCIdent;
|
||||
import com.sun.tools.javac.tree.JCTree.JCIf;
|
||||
import com.sun.tools.javac.tree.JCTree.JCLiteral;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCModifiers;
|
||||
import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCStatement;
|
||||
@@ -83,6 +84,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
}
|
||||
|
||||
private static class BuilderFieldData {
|
||||
JavacNode fieldNode;
|
||||
JCExpression type;
|
||||
Name rawName;
|
||||
Name name;
|
||||
@@ -107,6 +109,10 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
String buildMethodName = builderInstance.buildMethodName();
|
||||
String builderClassName = builderInstance.builderClassName();
|
||||
String toBuilderMethodName = "toBuilder";
|
||||
|
||||
boolean inherit = builderInstance.inherit();
|
||||
boolean extensible = inherit || builderInstance.extensible(); // inherit implies extendable
|
||||
|
||||
boolean toBuilder = builderInstance.toBuilder();
|
||||
java.util.List<Name> typeArgsForToBuilder = null;
|
||||
|
||||
@@ -135,9 +141,11 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
boolean addCleaning = false;
|
||||
boolean isStatic = true;
|
||||
|
||||
JCClassDecl td = null;
|
||||
|
||||
if (parent.get() instanceof JCClassDecl) {
|
||||
tdParent = parent;
|
||||
JCClassDecl td = (JCClassDecl) tdParent.get();
|
||||
td = (JCClassDecl) tdParent.get();
|
||||
ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>();
|
||||
boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent));
|
||||
for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) {
|
||||
@@ -145,6 +153,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
JavacNode isDefault = findAnnotation(Builder.Default.class, fieldNode, true);
|
||||
boolean isFinal = (fd.mods.flags & Flags.FINAL) != 0 || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode));
|
||||
BuilderFieldData bfd = new BuilderFieldData();
|
||||
bfd.fieldNode = fieldNode;
|
||||
bfd.rawName = fd.name;
|
||||
bfd.name = removePrefixFromField(fieldNode);
|
||||
bfd.type = fd.vartype;
|
||||
@@ -178,14 +187,30 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
allFields.append(fieldNode);
|
||||
}
|
||||
|
||||
handleConstructor.generateConstructor(tdParent, AccessLevel.PACKAGE, List.<JCAnnotation>nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, annotationNode);
|
||||
if (builderClassName.isEmpty()) builderClassName = td.name.toString() + "Builder";
|
||||
|
||||
JCTree extendsClause = Javac.getExtendsClause(td);
|
||||
|
||||
if (extensible) {
|
||||
boolean callBuilderBasedSuperConstructor = extendsClause != null;
|
||||
generateBuilderBasedConstructor(tdParent, builderFields, annotationNode, builderClassName, callBuilderBasedSuperConstructor);
|
||||
} else {
|
||||
handleConstructor.generateConstructor(tdParent, AccessLevel.PROTECTED, List.<JCAnnotation>nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, annotationNode);
|
||||
}
|
||||
|
||||
returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams);
|
||||
typeParams = td.typarams;
|
||||
thrownExceptions = List.nil();
|
||||
nameOfBuilderMethod = null;
|
||||
if (builderClassName.isEmpty()) builderClassName = td.name.toString() + "Builder";
|
||||
} else if (fillParametersFrom != null && fillParametersFrom.getName().toString().equals("<init>")) {
|
||||
if (inherit) {
|
||||
annotationNode.addError("@Builder(inherit=true) is only supported for type builders.");
|
||||
return;
|
||||
}
|
||||
if (extensible) {
|
||||
annotationNode.addError("@Builder(extendable=true) is only supported for type builders.");
|
||||
return;
|
||||
}
|
||||
JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get();
|
||||
if (!jmd.typarams.isEmpty()) {
|
||||
annotationNode.addError("@Builder is not supported on constructors with constructor type parameters.");
|
||||
@@ -193,15 +218,23 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
}
|
||||
|
||||
tdParent = parent.up();
|
||||
JCClassDecl td = (JCClassDecl) tdParent.get();
|
||||
td = (JCClassDecl) tdParent.get();
|
||||
returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams);
|
||||
typeParams = td.typarams;
|
||||
thrownExceptions = jmd.thrown;
|
||||
nameOfBuilderMethod = null;
|
||||
if (builderClassName.isEmpty()) builderClassName = td.name.toString() + "Builder";
|
||||
} else if (fillParametersFrom != null) {
|
||||
if (inherit) {
|
||||
annotationNode.addError("@Builder(inherit=true) is only supported for type builders.");
|
||||
return;
|
||||
}
|
||||
if (extensible) {
|
||||
annotationNode.addError("@Builder(extendable=true) is only supported for type builders.");
|
||||
return;
|
||||
}
|
||||
tdParent = parent.up();
|
||||
JCClassDecl td = (JCClassDecl) tdParent.get();
|
||||
td = (JCClassDecl) tdParent.get();
|
||||
JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get();
|
||||
isStatic = (jmd.mods.flags & Flags.STATIC) != 0;
|
||||
JCExpression fullReturnType = jmd.restype;
|
||||
@@ -333,7 +366,18 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
|
||||
JavacNode builderType = findInnerClass(tdParent, builderClassName);
|
||||
if (builderType == null) {
|
||||
builderType = makeBuilderClass(isStatic, annotationNode, tdParent, builderClassName, typeParams, ast);
|
||||
String superclassBuilderClassName = null;
|
||||
if (inherit) {
|
||||
JCTree extendsClause = Javac.getExtendsClause(td);
|
||||
if (extendsClause == null) {
|
||||
annotationNode.addError("@Builder(inherit = true) requires that your class has an 'extends' clause.");
|
||||
return;
|
||||
}
|
||||
|
||||
superclassBuilderClassName = builderInstance.superclassBuilderClassName();
|
||||
if (superclassBuilderClassName == null || superclassBuilderClassName.isEmpty()) superclassBuilderClassName = extendsClause + "Builder";
|
||||
}
|
||||
builderType = makeBuilderClass(isStatic, annotationNode, tdParent, builderClassName, typeParams, ast, superclassBuilderClassName);
|
||||
} else {
|
||||
JCClassDecl builderTypeDeclaration = (JCClassDecl) builderType.get();
|
||||
if (isStatic && !builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)) {
|
||||
@@ -393,7 +437,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
}
|
||||
|
||||
if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) {
|
||||
JCMethodDecl md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfBuilderMethod, returnType, builderFields, builderType, thrownExceptions, ast, addCleaning);
|
||||
JCMethodDecl md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfBuilderMethod, returnType, builderFields, builderType, thrownExceptions, ast, addCleaning, extensible);
|
||||
if (md != null) injectMethod(builderType, md);
|
||||
}
|
||||
|
||||
@@ -502,6 +546,82 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
JCBlock body = maker.Block(0, List.<JCStatement>of(statement));
|
||||
return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName(toBuilderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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 builderClassnameAsParameter
|
||||
* If {@code != null}, the only parameter of the constructor will
|
||||
* be a builder with this classname; the constructor will then
|
||||
* use the values within this builder to assign the fields of new
|
||||
* instances.
|
||||
* @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(JavacNode typeNode, java.util.List<BuilderFieldData> builderFields, JavacNode source, String builderClassnameAsParameter, boolean callBuilderBasedSuperConstructor) {
|
||||
JavacTreeMaker maker = typeNode.getTreeMaker();
|
||||
|
||||
boolean isEnum = (((JCClassDecl) typeNode.get()).mods.flags & Flags.ENUM) != 0;
|
||||
AccessLevel level = isEnum ? AccessLevel.PRIVATE : AccessLevel.PROTECTED;
|
||||
|
||||
ListBuffer<JCStatement> nullChecks = new ListBuffer<JCStatement>();
|
||||
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
|
||||
|
||||
Name builderVariableName = typeNode.toName("b");
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
List<JCAnnotation> nonNulls = findAnnotations(bfd.fieldNode, NON_NULL_PATTERN);
|
||||
if (!nonNulls.isEmpty()) {
|
||||
JCStatement nullCheck = generateNullCheck(maker, bfd.fieldNode, source);
|
||||
if (nullCheck != null) {
|
||||
nullChecks.append(nullCheck);
|
||||
}
|
||||
}
|
||||
|
||||
JCExpression rhs;
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, bfd.fieldNode, bfd.type, statements, bfd.name, "b");
|
||||
rhs = maker.Ident(bfd.singularData.getPluralName());
|
||||
} else {
|
||||
rhs = maker.Select(maker.Ident(builderVariableName), bfd.rawName);
|
||||
}
|
||||
JCFieldAccess thisX = maker.Select(maker.Ident(bfd.fieldNode.toName("this")), bfd.rawName);
|
||||
|
||||
JCExpression assign = maker.Assign(thisX, rhs);
|
||||
|
||||
statements.append(maker.Exec(assign));
|
||||
}
|
||||
|
||||
JCModifiers mods = maker.Modifiers(toJavacModifier(level), List.<JCAnnotation>nil());
|
||||
|
||||
// Create a constructor that has just the builder as parameter.
|
||||
ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
|
||||
long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext());
|
||||
Name builderClassname = typeNode.toName(builderClassnameAsParameter);
|
||||
JCVariableDecl param = maker.VarDef(maker.Modifiers(flags), builderVariableName, maker.Ident(builderClassname), null);
|
||||
params.append(param);
|
||||
|
||||
if (callBuilderBasedSuperConstructor) {
|
||||
// The first statement must be the call to the super constructor.
|
||||
JCMethodInvocation callToSuperConstructor = maker.Apply(List.<JCExpression>nil(),
|
||||
maker.Ident(typeNode.toName("super")),
|
||||
List.<JCExpression>of(maker.Ident(builderVariableName)));
|
||||
statements.prepend(maker.Exec(callToSuperConstructor));
|
||||
}
|
||||
|
||||
JCMethodDecl constr = recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("<init>"),
|
||||
null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(),
|
||||
maker.Block(0L, nullChecks.appendList(statements).toList()), null), source.get(), typeNode.getContext());
|
||||
|
||||
injectMethod(typeNode, constr, null, Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID));
|
||||
}
|
||||
|
||||
private JCMethodDecl generateCleanMethod(java.util.List<BuilderFieldData> builderFields, JavacNode type, JCTree source) {
|
||||
JavacTreeMaker maker = type.getTreeMaker();
|
||||
@@ -530,40 +650,56 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
*/
|
||||
}
|
||||
|
||||
private JCMethodDecl generateBuildMethod(JavacNode tdParent, boolean isStatic, String buildName, Name builderName, JCExpression returnType, java.util.List<BuilderFieldData> builderFields, JavacNode type, List<JCExpression> thrownExceptions, JCTree source, boolean addCleaning) {
|
||||
/**
|
||||
* @param useBuilderBasedConstructor
|
||||
* if true, the {@code build()} method will use a constructor
|
||||
* that takes the builder instance as parameter (instead of a
|
||||
* constructor with all relevant fields as parameters)
|
||||
*/
|
||||
private JCMethodDecl generateBuildMethod(JavacNode tdParent, boolean isStatic, String buildName, Name builderName, JCExpression returnType, java.util.List<BuilderFieldData> builderFields, JavacNode type, List<JCExpression> thrownExceptions, JCTree source, boolean addCleaning, boolean useBuilderBasedConstructor) {
|
||||
JavacTreeMaker maker = type.getTreeMaker();
|
||||
|
||||
JCExpression call;
|
||||
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
|
||||
|
||||
if (addCleaning) {
|
||||
JCExpression notClean = maker.Unary(CTC_NOT, maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")));
|
||||
JCStatement invokeClean = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(type.toName("$lombokClean")), List.<JCExpression>nil()));
|
||||
JCIf ifUnclean = maker.If(notClean, invokeClean, null);
|
||||
statements.append(ifUnclean);
|
||||
}
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, type, source, statements, bfd.name);
|
||||
}
|
||||
}
|
||||
|
||||
ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.nameOfSetFlag != null) {
|
||||
statements.append(maker.VarDef(maker.Modifiers(0L), bfd.name, cloneType(maker, bfd.type, source, tdParent.getContext()), maker.Select(maker.Ident(type.toName("this")), bfd.name)));
|
||||
statements.append(maker.If(maker.Unary(CTC_NOT, maker.Ident(bfd.nameOfSetFlag)), maker.Exec(maker.Assign(maker.Ident(bfd.name),maker.Apply(typeParameterNames(maker, ((JCClassDecl) tdParent.get()).typarams), maker.Select(maker.Ident(((JCClassDecl) tdParent.get()).name), bfd.nameOfDefaultProvider), List.<JCExpression>nil()))), null));
|
||||
}
|
||||
args.append(maker.Ident(bfd.name));
|
||||
}
|
||||
|
||||
if (addCleaning) {
|
||||
statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, 1))));
|
||||
// Extendable builders assign their values in the constructor, not in this build() method.
|
||||
if (!useBuilderBasedConstructor) {
|
||||
if (addCleaning) {
|
||||
JCExpression notClean = maker.Unary(CTC_NOT, maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")));
|
||||
JCStatement invokeClean = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(type.toName("$lombokClean")), List.<JCExpression>nil()));
|
||||
JCIf ifUnclean = maker.If(notClean, invokeClean, null);
|
||||
statements.append(ifUnclean);
|
||||
}
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, type, source, statements, bfd.name, "this");
|
||||
}
|
||||
}
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.nameOfSetFlag != null) {
|
||||
statements.append(maker.VarDef(maker.Modifiers(0L), bfd.name, cloneType(maker, bfd.type, source, tdParent.getContext()), maker.Select(maker.Ident(type.toName("this")), bfd.name)));
|
||||
statements.append(maker.If(maker.Unary(CTC_NOT, maker.Ident(bfd.nameOfSetFlag)), maker.Exec(maker.Assign(maker.Ident(bfd.name),maker.Apply(typeParameterNames(maker, ((JCClassDecl) tdParent.get()).typarams), maker.Select(maker.Ident(((JCClassDecl) tdParent.get()).name), bfd.nameOfDefaultProvider), List.<JCExpression>nil()))), null));
|
||||
}
|
||||
args.append(maker.Ident(bfd.name));
|
||||
}
|
||||
|
||||
if (addCleaning) {
|
||||
statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, 1))));
|
||||
}
|
||||
}
|
||||
|
||||
if (builderName == null) {
|
||||
call = maker.NewClass(null, List.<JCExpression>nil(), returnType, args.toList(), null);
|
||||
if (useBuilderBasedConstructor) {
|
||||
// Use a constructor that only has this builder as parameter.
|
||||
List<JCExpression> builderArg = List.<JCExpression>of(maker.Ident(type.toName("this")));
|
||||
call = maker.NewClass(null, List.<JCExpression>nil(), returnType, builderArg, null);
|
||||
} else {
|
||||
// Use a constructor with all the fields.
|
||||
call = maker.NewClass(null, List.<JCExpression>nil(), returnType, args.toList(), null);
|
||||
}
|
||||
statements.append(maker.Return(call));
|
||||
} else {
|
||||
ListBuffer<JCExpression> typeParams = new ListBuffer<JCExpression>();
|
||||
@@ -686,12 +822,13 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
return null;
|
||||
}
|
||||
|
||||
public JavacNode makeBuilderClass(boolean isStatic, JavacNode source, JavacNode tdParent, String builderClassName, List<JCTypeParameter> typeParams, JCAnnotation ast) {
|
||||
public JavacNode makeBuilderClass(boolean isStatic, JavacNode source, JavacNode tdParent, String builderClassName, List<JCTypeParameter> typeParams, JCAnnotation ast, String parentBuilderClassName) {
|
||||
JavacTreeMaker maker = tdParent.getTreeMaker();
|
||||
int modifiers = Flags.PUBLIC;
|
||||
if (isStatic) modifiers |= Flags.STATIC;
|
||||
JCModifiers mods = maker.Modifiers(modifiers);
|
||||
JCClassDecl builder = maker.ClassDef(mods, tdParent.toName(builderClassName), copyTypeParams(source, typeParams), null, List.<JCExpression>nil(), List.<JCTree>nil());
|
||||
JCExpression extending = parentBuilderClassName == null ? null : maker.Ident(tdParent.toName(parentBuilderClassName));
|
||||
JCClassDecl builder = maker.ClassDef(mods, tdParent.toName(builderClassName), copyTypeParams(source, typeParams), extending, List.<JCExpression>nil(), List.<JCTree>nil());
|
||||
return injectType(tdParent, builder);
|
||||
}
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ public class JavacSingularsRecipes {
|
||||
|
||||
public abstract java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source);
|
||||
public abstract void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, boolean chain);
|
||||
public abstract void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName);
|
||||
public abstract void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable);
|
||||
|
||||
public boolean requiresCleaning() {
|
||||
try {
|
||||
@@ -274,9 +274,9 @@ public class JavacSingularsRecipes {
|
||||
return arguments.toList();
|
||||
}
|
||||
|
||||
/** Generates 'this.<em>name</em>.size()' as an expression; if nullGuard is true, it's this.name == null ? 0 : this.name.size(). */
|
||||
protected JCExpression getSize(JavacTreeMaker maker, JavacNode builderType, Name name, boolean nullGuard, boolean parens) {
|
||||
Name thisName = builderType.toName("this");
|
||||
/** Generates '<em>builderVariable</em>.<em>name</em>.size()' as an expression; if nullGuard is true, it's this.name == null ? 0 : this.name.size(). */
|
||||
protected JCExpression getSize(JavacTreeMaker maker, JavacNode builderType, Name name, boolean nullGuard, boolean parens, String builderVariable) {
|
||||
Name thisName = builderType.toName(builderVariable);
|
||||
JCExpression fn = maker.Select(maker.Select(maker.Ident(thisName), name), builderType.toName("size"));
|
||||
JCExpression sizeInvoke = maker.Apply(List.<JCExpression>nil(), fn, List.<JCExpression>nil());
|
||||
if (nullGuard) {
|
||||
|
||||
@@ -168,7 +168,7 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer {
|
||||
injectMethod(builderType, method);
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) {
|
||||
JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
List<JCExpression> jceBlank = List.nil();
|
||||
|
||||
@@ -185,12 +185,12 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer {
|
||||
|
||||
JCExpression invokeBuild; {
|
||||
//this.pluralName.build();
|
||||
invokeBuild = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName().toString(), "build"), jceBlank);
|
||||
invokeBuild = maker.Apply(jceBlank, chainDots(builderType, builderVariable, data.getPluralName().toString(), "build"), jceBlank);
|
||||
}
|
||||
|
||||
JCExpression isNull; {
|
||||
//this.pluralName == null
|
||||
isNull = maker.Binary(CTC_EQUAL, maker.Select(maker.Ident(builderType.toName("this")), data.getPluralName()), maker.Literal(CTC_BOT, null));
|
||||
isNull = maker.Binary(CTC_EQUAL, maker.Select(maker.Ident(builderType.toName(builderVariable)), data.getPluralName()), maker.Literal(CTC_BOT, null));
|
||||
}
|
||||
|
||||
JCExpression init = maker.Conditional(isNull, empty, invokeBuild); // this.pluralName == null ? ImmutableX.of() : this.pluralName.build()
|
||||
|
||||
@@ -46,9 +46,9 @@ public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingulari
|
||||
return LombokImmutableList.of("java.util.List", "java.util.Collection", "java.lang.Iterable");
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName);
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName, builderVariable);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingulari
|
||||
JCStatement assignStat; {
|
||||
// pluralName = java.util.Collections.singletonList(this.pluralName.get(0));
|
||||
JCExpression zeroLiteral = maker.Literal(CTC_INT, 0);
|
||||
JCExpression arg = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName().toString(), "get"), List.of(zeroLiteral));
|
||||
JCExpression arg = maker.Apply(jceBlank, chainDots(builderType, builderVariable, data.getPluralName().toString(), "get"), List.of(zeroLiteral));
|
||||
List<JCExpression> args = List.of(arg);
|
||||
JCExpression invoke = maker.Apply(jceBlank, chainDots(builderType, "java", "util", "Collections", "singletonList"), args);
|
||||
assignStat = maker.Exec(maker.Assign(maker.Ident(data.getPluralName()), invoke));
|
||||
@@ -82,12 +82,12 @@ public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingulari
|
||||
}
|
||||
|
||||
/* default: Create with right size, then addAll */ {
|
||||
List<JCStatement> defStats = createListCopy(maker, data, builderType, source);
|
||||
List<JCStatement> defStats = createListCopy(maker, data, builderType, source, builderVariable);
|
||||
JCCase defaultCase = maker.Case(null, defStats);
|
||||
cases.append(defaultCase);
|
||||
}
|
||||
|
||||
JCStatement switchStat = maker.Switch(getSize(maker, builderType, data.getPluralName(), true, false), cases.toList());
|
||||
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);
|
||||
@@ -95,9 +95,9 @@ public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingulari
|
||||
statements.append(switchStat);
|
||||
}
|
||||
|
||||
private List<JCStatement> createListCopy(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) {
|
||||
private List<JCStatement> createListCopy(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source, String builderVariable) {
|
||||
List<JCExpression> jceBlank = List.nil();
|
||||
Name thisName = builderType.toName("this");
|
||||
Name thisName = builderType.toName(builderVariable);
|
||||
|
||||
JCExpression argToUnmodifiable; {
|
||||
// new java.util.ArrayList<Generics>(this.pluralName);
|
||||
|
||||
@@ -212,18 +212,18 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer {
|
||||
injectMethod(builderType, method);
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaMapSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName);
|
||||
guavaMapSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName, builderVariable);
|
||||
return;
|
||||
}
|
||||
|
||||
JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
|
||||
if (data.getTargetFqn().equals("java.util.Map")) {
|
||||
statements.appendList(createJavaUtilSetMapInitialCapacitySwitchStatements(maker, data, builderType, true, "emptyMap", "singletonMap", "LinkedHashMap", source));
|
||||
statements.appendList(createJavaUtilSetMapInitialCapacitySwitchStatements(maker, data, builderType, true, "emptyMap", "singletonMap", "LinkedHashMap", source, builderVariable));
|
||||
} else {
|
||||
statements.appendList(createJavaUtilSimpleCreationAndFillStatements(maker, data, builderType, true, true, false, true, "TreeMap", source));
|
||||
statements.appendList(createJavaUtilSimpleCreationAndFillStatements(maker, data, builderType, true, true, false, true, "TreeMap", source, builderVariable));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,18 +40,18 @@ public class JavacJavaUtilSetSingularizer extends JavacJavaUtilListSetSingulariz
|
||||
return LombokImmutableList.of("java.util.Set", "java.util.SortedSet", "java.util.NavigableSet");
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName);
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName, builderVariable);
|
||||
return;
|
||||
}
|
||||
|
||||
JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
|
||||
if (data.getTargetFqn().equals("java.util.Set")) {
|
||||
statements.appendList(createJavaUtilSetMapInitialCapacitySwitchStatements(maker, data, builderType, false, "emptySet", "singleton", "LinkedHashSet", source));
|
||||
statements.appendList(createJavaUtilSetMapInitialCapacitySwitchStatements(maker, data, builderType, false, "emptySet", "singleton", "LinkedHashSet", source, builderVariable));
|
||||
} else {
|
||||
statements.appendList(createJavaUtilSimpleCreationAndFillStatements(maker, data, builderType, false, true, false, true, "TreeSet", source));
|
||||
statements.appendList(createJavaUtilSimpleCreationAndFillStatements(maker, data, builderType, false, true, false, true, "TreeSet", source, builderVariable));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
|
||||
return Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_USE_GUAVA));
|
||||
}
|
||||
|
||||
protected List<JCStatement> createJavaUtilSetMapInitialCapacitySwitchStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType, JCTree source) {
|
||||
protected List<JCStatement> createJavaUtilSetMapInitialCapacitySwitchStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType, JCTree source, String builderVariable) {
|
||||
List<JCExpression> jceBlank = List.nil();
|
||||
ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
|
||||
|
||||
@@ -66,11 +66,11 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
|
||||
// !mapMode: pluralName = java.util.Collections.singletonCollectionMethod(this.pluralName.get(0));
|
||||
// mapMode: pluralName = java.util.Collections.singletonCollectionMethod(this.pluralName$key.get(0), this.pluralName$value.get(0));
|
||||
JCExpression zeroLiteral = maker.Literal(CTC_INT, 0);
|
||||
JCExpression arg = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName() + (mapMode ? "$key" : ""), "get"), List.of(zeroLiteral));
|
||||
JCExpression arg = maker.Apply(jceBlank, chainDots(builderType, builderVariable, data.getPluralName() + (mapMode ? "$key" : ""), "get"), List.of(zeroLiteral));
|
||||
List<JCExpression> args;
|
||||
if (mapMode) {
|
||||
JCExpression zeroLiteralClone = maker.Literal(CTC_INT, 0);
|
||||
JCExpression arg2 = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName() + (mapMode ? "$value" : ""), "get"), List.of(zeroLiteralClone));
|
||||
JCExpression arg2 = maker.Apply(jceBlank, chainDots(builderType, builderVariable, data.getPluralName() + (mapMode ? "$value" : ""), "get"), List.of(zeroLiteralClone));
|
||||
args = List.of(arg, arg2);
|
||||
} else {
|
||||
args = List.of(arg);
|
||||
@@ -84,12 +84,12 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
|
||||
}
|
||||
|
||||
{ // default:
|
||||
List<JCStatement> statements = createJavaUtilSimpleCreationAndFillStatements(maker, data, builderType, mapMode, false, true, emptyCollectionMethod == null, targetType, source);
|
||||
List<JCStatement> statements = createJavaUtilSimpleCreationAndFillStatements(maker, data, builderType, mapMode, false, true, emptyCollectionMethod == null, targetType, source, builderVariable);
|
||||
JCCase defaultCase = maker.Case(null, statements);
|
||||
cases.append(defaultCase);
|
||||
}
|
||||
|
||||
JCStatement switchStat = maker.Switch(getSize(maker, builderType, mapMode ? builderType.toName(data.getPluralName() + "$key") : data.getPluralName(), true, false), cases.toList());
|
||||
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);
|
||||
@@ -125,9 +125,9 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
|
||||
return maker.If(cond, thenPart, null);
|
||||
}
|
||||
|
||||
protected List<JCStatement> createJavaUtilSimpleCreationAndFillStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType, JCTree source) {
|
||||
protected List<JCStatement> createJavaUtilSimpleCreationAndFillStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType, JCTree source, String builderVariable) {
|
||||
List<JCExpression> jceBlank = List.nil();
|
||||
Name thisName = builderType.toName("this");
|
||||
Name thisName = builderType.toName(builderVariable);
|
||||
|
||||
JCStatement createStat; {
|
||||
// pluralName = new java.util.TargetType(initialCap);
|
||||
@@ -136,10 +136,10 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
|
||||
Name varName = mapMode ? builderType.toName(data.getPluralName() + "$key") : data.getPluralName();
|
||||
// this.varName.size() < MAX_POWER_OF_2 ? 1 + this.varName.size() + (this.varName.size() - 3) / 3 : Integer.MAX_VALUE;
|
||||
// lessThanCutOff = this.varName.size() < MAX_POWER_OF_2
|
||||
JCExpression lessThanCutoff = maker.Binary(CTC_LESS_THAN, getSize(maker, builderType, varName, nullGuard, true), maker.Literal(CTC_INT, 0x40000000));
|
||||
JCExpression lessThanCutoff = maker.Binary(CTC_LESS_THAN, getSize(maker, builderType, varName, nullGuard, true, builderVariable), maker.Literal(CTC_INT, 0x40000000));
|
||||
JCExpression integerMaxValue = genJavaLangTypeRef(builderType, "Integer", "MAX_VALUE");
|
||||
JCExpression sizeFormulaLeft = maker.Binary(CTC_PLUS, maker.Literal(CTC_INT, 1), getSize(maker, builderType, varName, nullGuard, true));
|
||||
JCExpression sizeFormulaRightLeft = maker.Parens(maker.Binary(CTC_MINUS, getSize(maker, builderType, varName, nullGuard, true), maker.Literal(CTC_INT, 3)));
|
||||
JCExpression sizeFormulaLeft = maker.Binary(CTC_PLUS, maker.Literal(CTC_INT, 1), getSize(maker, builderType, varName, nullGuard, true, builderVariable));
|
||||
JCExpression sizeFormulaRightLeft = maker.Parens(maker.Binary(CTC_MINUS, getSize(maker, builderType, varName, nullGuard, true, builderVariable), maker.Literal(CTC_INT, 3)));
|
||||
JCExpression sizeFormulaRight = maker.Binary(CTC_DIV, sizeFormulaRightLeft, maker.Literal(CTC_INT, 3));
|
||||
JCExpression sizeFormula = maker.Binary(CTC_PLUS, sizeFormulaLeft, sizeFormulaRight);
|
||||
constructorArgs = List.<JCExpression>of(maker.Conditional(lessThanCutoff, sizeFormula, integerMaxValue));
|
||||
@@ -163,14 +163,14 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
|
||||
Name ivar = builderType.toName("$i");
|
||||
Name keyVarName = builderType.toName(data.getPluralName() + "$key");
|
||||
JCExpression pluralnameDotPut = maker.Select(maker.Ident(data.getPluralName()), builderType.toName("put"));
|
||||
JCExpression arg1 = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName() + "$key", "get"), List.<JCExpression>of(maker.Ident(ivar)));
|
||||
JCExpression arg2 = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName() + "$value", "get"), List.<JCExpression>of(maker.Ident(ivar)));
|
||||
JCExpression arg1 = maker.Apply(jceBlank, chainDots(builderType, builderVariable, data.getPluralName() + "$key", "get"), List.<JCExpression>of(maker.Ident(ivar)));
|
||||
JCExpression arg2 = maker.Apply(jceBlank, chainDots(builderType, builderVariable, data.getPluralName() + "$value", "get"), List.<JCExpression>of(maker.Ident(ivar)));
|
||||
// [jdk9] We add an unneccessary (V) cast here. Not doing so gives an error in javac (build 9-ea+156-jigsaw-nightly-h6072-20170212):
|
||||
// error: method put in interface Map<K#2,V#2> cannot be applied to given types;
|
||||
arg2 = maker.TypeCast(createTypeArgs(2, false, builderType, data.getTypeArgs(), source).get(1), arg2);
|
||||
JCStatement putStatement = maker.Exec(maker.Apply(jceBlank, pluralnameDotPut, List.of(arg1, arg2)));
|
||||
JCStatement forInit = maker.VarDef(maker.Modifiers(0), ivar, maker.TypeIdent(CTC_INT), maker.Literal(CTC_INT, 0));
|
||||
JCExpression checkExpr = maker.Binary(CTC_LESS_THAN, maker.Ident(ivar), getSize(maker, builderType, keyVarName, nullGuard, true));
|
||||
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);
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user