diff options
Diffstat (limited to 'src')
11 files changed, 533 insertions, 257 deletions
diff --git a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java index 0157552b..e61e5d68 100644 --- a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java +++ b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java @@ -8,9 +8,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression; import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldReference; import org.eclipse.jdt.internal.compiler.ast.IntLiteral; import org.eclipse.jdt.internal.compiler.ast.MessageSend; @@ -24,6 +27,8 @@ import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; +import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import lombok.core.LombokImmutableList; @@ -101,14 +106,28 @@ public class EclipseSingularsRecipes { private final List<TypeReference> typeArgs; private final String targetFqn; private final EclipseSingularizer singularizer; + private final ASTNode source; - public SingularData(EclipseNode annotation, char[] singularName, char[] pluralName, List<TypeReference> typeArgs, String targetFqn, EclipseSingularizer singularizer) { + public SingularData(EclipseNode annotation, char[] singularName, char[] pluralName, List<TypeReference> typeArgs, String targetFqn, EclipseSingularizer singularizer, ASTNode source) { this.annotation = annotation; this.singularName = singularName; this.pluralName = pluralName; this.typeArgs = typeArgs; this.targetFqn = targetFqn; this.singularizer = singularizer; + this.source = source; + } + + public void setGeneratedByRecursive(ASTNode target) { + SetGeneratedByVisitor visitor = new SetGeneratedByVisitor(source); + + if (target instanceof AbstractMethodDeclaration) { + ((AbstractMethodDeclaration) target).traverse(visitor, (ClassScope) null); + } else if (target instanceof FieldDeclaration) { + ((FieldDeclaration) target).traverse(visitor, (MethodScope) null); + } else { + target.traverse(visitor, null); + } } public EclipseNode getAnnotation() { diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 365256c7..b2ea7bbc 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -62,6 +62,7 @@ import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.UnaryExpression; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.mangosdk.spi.ProviderFor; @@ -71,6 +72,7 @@ import lombok.Builder; import lombok.ConfigurationKeys; import lombok.Singular; import lombok.core.AST.Kind; +import lombok.core.handlers.HandlerUtil; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.eclipse.Eclipse; @@ -89,6 +91,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { private static final boolean toBoolean(Object expr, boolean defaultValue) { if (expr == null) return defaultValue; + if (expr instanceof FalseLiteral) return false; + if (expr instanceof TrueLiteral) return true; return ((Boolean) expr).booleanValue(); } @@ -153,7 +157,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { BuilderFieldData bfd = new BuilderFieldData(); bfd.name = removePrefixFromField(fieldNode); bfd.type = fd.type; - bfd.singularData = getSingularData(fieldNode); + bfd.singularData = getSingularData(fieldNode, ast); builderFields.add(bfd); allFields.add(fieldNode); } @@ -232,7 +236,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { Argument arg = (Argument) param.get(); bfd.name = arg.name; bfd.type = arg.type; - bfd.singularData = getSingularData(param); + bfd.singularData = getSingularData(param, ast); builderFields.add(bfd); } } @@ -253,12 +257,13 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } } - generateBuilderFields(builderType, builderFields); + generateBuilderFields(builderType, builderFields, ast); 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); + System.out.println("INJECTING: cleaning"); injectField(builderType, cleanDecl); } @@ -274,7 +279,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) { - MethodDeclaration md = generateBuildMethod(buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning); + MethodDeclaration md = generateBuildMethod(buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast); if (md != null) injectMethod(builderType, md); } @@ -287,17 +292,18 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { if (md != null) injectMethod(builderType, md); } - if (addCleaning) injectMethod(builderType, generateCleanMethod(builderFields, builderType)); + if (addCleaning) { + MethodDeclaration cleanMethod = generateCleanMethod(builderFields, builderType, ast); + if (cleanMethod != null) injectMethod(builderType, cleanMethod); + } if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) { MethodDeclaration md = generateBuilderMethod(builderMethodName, builderClassName, tdParent, typeParams, ast); if (md != null) injectMethod(tdParent, md); } - - builderType.get().traverse(new SetGeneratedByVisitor(ast), null); } - private MethodDeclaration generateCleanMethod(List<BuilderFieldData> builderFields, EclipseNode builderType) { + private MethodDeclaration generateCleanMethod(List<BuilderFieldData> builderFields, EclipseNode builderType, ASTNode source) { List<Statement> statements = new ArrayList<Statement>(); for (BuilderFieldData bfd : builderFields) { @@ -309,16 +315,17 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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 = 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); return decl; } - public MethodDeclaration generateBuildMethod(String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning) { + public MethodDeclaration generateBuildMethod(String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source) { MethodDeclaration out = new MethodDeclaration( ((CompilationUnitDeclaration) type.top().get()).compilationResult); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; @@ -381,6 +388,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } } out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[statements.size()]); + out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return out; } @@ -403,16 +411,14 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return out; } - public void generateBuilderFields(EclipseNode builderType, List<BuilderFieldData> builderFields) { - int len = builderFields.size(); + public void generateBuilderFields(EclipseNode builderType, List<BuilderFieldData> builderFields, ASTNode source) { List<EclipseNode> existing = new ArrayList<EclipseNode>(); for (EclipseNode child : builderType.down()) { if (child.getKind() == Kind.FIELD) existing.add(child); } top: - for (int i = len - 1; i >= 0; i--) { - BuilderFieldData bfd = builderFields.get(i); + for (BuilderFieldData bfd : builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, builderType)); } else { @@ -428,6 +434,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { fd.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; fd.modifiers = ClassFileConstants.AccPrivate; fd.type = copyType(bfd.type); + fd.traverse(new SetGeneratedByVisitor(source), (MethodScope) null); bfd.createdFields.add(injectField(builderType, fd)); } } @@ -457,8 +464,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { if (Arrays.equals(name, existingName)) return; } - boolean isBoolean = isBoolean(fd.type); - String setterName = fluent ? fieldNode.getName() : toSetterName(builderType.getAst(), null, fieldNode.getName(), isBoolean); + String setterName = fluent ? fieldNode.getName() : HandlerUtil.buildAccessorName("set", fieldNode.getName()); MethodDeclaration setter = HandleSetter.createSetter(td, fieldNode, setterName, chain, ClassFileConstants.AccPublic, sourceNode, Collections.<Annotation>emptyList(), Collections.<Annotation>emptyList()); @@ -492,7 +498,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { * * @param node The node (field or method param) to inspect for its name and potential {@code @Singular} annotation. */ - private SingularData getSingularData(EclipseNode node) { + private SingularData getSingularData(EclipseNode node, ASTNode source) { for (EclipseNode child : node.down()) { if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Singular.class, child)) { char[] pluralName = node.getKind() == Kind.FIELD ? removePrefixFromField(node) : ((AbstractVariableDeclaration) node.get()).name; @@ -534,7 +540,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return null; } - return new SingularData(child, singularName, pluralName, typeArgs == null ? Collections.<TypeReference>emptyList() : Arrays.asList(typeArgs), targetFqn, singularizer); + return new SingularData(child, singularName, pluralName, typeArgs == null ? Collections.<TypeReference>emptyList() : Arrays.asList(typeArgs), targetFqn, singularizer, source); } } diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaMapSingularizer.java new file mode 100644 index 00000000..95fd8935 --- /dev/null +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaMapSingularizer.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.handlers.singulars; + +import org.mangosdk.spi.ProviderFor; + +import lombok.core.LombokImmutableList; +import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; + +@ProviderFor(EclipseSingularizer.class) +public class EclipseGuavaMapSingularizer extends EclipseGuavaSingularizer { + // TODO cgcc.ImmutableMultimap, cgcc.ImmutableListMultimap, cgcc.ImmutableSetMultimap + // TODO cgcc.ImmutableClassToInstanceMap + // TODO cgcc.ImmutableRangeMap + + @Override public LombokImmutableList<String> getSupportedTypes() { + return LombokImmutableList.of( + "com.google.common.collect.ImmutableMap", + "com.google.common.collect.ImmutableBiMap", + "com.google.common.collect.ImmutableSortedMap"); + } + + @Override protected boolean isMap() { + return true; + } +} diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSetListSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSetListSingularizer.java new file mode 100644 index 00000000..bc2893bf --- /dev/null +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSetListSingularizer.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.handlers.singulars; + +import org.mangosdk.spi.ProviderFor; + +import lombok.core.LombokImmutableList; +import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; + +@ProviderFor(EclipseSingularizer.class) +public class EclipseGuavaSetListSingularizer extends EclipseGuavaSingularizer { + // TODO com.google.common.collect.ImmutableTable + // TODO com.google.common.collect.ImmutableRangeSet + // TODO com.google.common.collect.ImmutableMultiset and com.google.common.collect.ImmutableSortedMultiset + @Override public LombokImmutableList<String> getSupportedTypes() { + return LombokImmutableList.of( + "com.google.common.collect.ImmutableCollection", + "com.google.common.collect.ImmutableList", + "com.google.common.collect.ImmutableSet", + "com.google.common.collect.ImmutableSortedSet"); + } + + @Override protected boolean isMap() { + return false; + } +} diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java new file mode 100644 index 00000000..775d4ed5 --- /dev/null +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2015 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.handlers.singulars; + +import static lombok.eclipse.Eclipse.*; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import lombok.core.handlers.HandlerUtil; +import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; +import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; + +import org.eclipse.jdt.internal.compiler.ast.Argument; +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.EqualExpression; +import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.FieldReference; +import org.eclipse.jdt.internal.compiler.ast.IfStatement; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MessageSend; +import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.NullLiteral; +import org.eclipse.jdt.internal.compiler.ast.OperatorIds; +import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; +import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; +import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.ThisReference; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; + +abstract class EclipseGuavaSingularizer extends EclipseSingularizer { + protected static final char[][] JAVA_UTIL_MAP = { + {'j', 'a', 'v', 'a'}, {'u', 't', 'i', 'l'}, {'M', 'a', 'p'} + }; + + protected String getSimpleTargetTypeName(SingularData data) { + String simpleTypeName = data.getTargetSimpleType(); + if ("ImmutableCollection".equals(simpleTypeName)) return "ImmutableList"; + return simpleTypeName; + } + + protected char[] getBuilderMethodName(SingularData data) { + String simpleTypeName = data.getTargetSimpleType(); + if ("ImmutableSortedSet".equals(simpleTypeName) || "ImmutableSortedMap".equals(simpleTypeName)) return "naturalOrder".toCharArray(); + return "builder".toCharArray(); + } + + protected abstract boolean isMap(); + + protected char[][] makeGuavaTypeName(String simpleName, boolean addBuilder) { + char[][] tokenizedName = new char[addBuilder ? 6 : 5][]; + tokenizedName[0] = new char[] {'c', 'o', 'm'}; + tokenizedName[1] = new char[] {'g', 'o', 'o', 'g', 'l', 'e'}; + tokenizedName[2] = new char[] {'c', 'o', 'm', 'm', 'o', 'n'}; + tokenizedName[3] = new char[] {'c', 'o', 'l', 'l', 'e', 'c', 't'}; + tokenizedName[4] = simpleName.toCharArray(); + if (addBuilder) tokenizedName[5] = new char[] { 'B', 'u', 'i', 'l', 'd', 'e', 'r'}; + return tokenizedName; + } + + @Override public List<EclipseNode> generateFields(SingularData data, EclipseNode builderType) { + char[][] tokenizedName = makeGuavaTypeName(getSimpleTargetTypeName(data), true); + TypeReference type = new QualifiedTypeReference(tokenizedName, NULL_POSS); + type = addTypeArgs(isMap() ? 2 : 1, false, builderType, type, data.getTypeArgs()); + + FieldDeclaration buildField = new FieldDeclaration(data.getPluralName(), 0, -1); + buildField.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; + buildField.modifiers = ClassFileConstants.AccPrivate; + buildField.declarationSourceEnd = -1; + buildField.type = type; + data.setGeneratedByRecursive(buildField); + return Collections.singletonList(injectField(builderType, buildField)); + } + + @Override public void generateMethods(SingularData data, EclipseNode builderType, boolean fluent, boolean chain) { + TypeReference returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); + Statement returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; + generateSingularMethod(returnType, returnStatement, data, builderType, fluent); + + returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); + returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; + generatePluralMethod(returnType, returnStatement, data, builderType, fluent); + } + + void generateSingularMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) { + boolean mapMode = isMap(); + char[] keyName = !mapMode ? data.getSingularName() : (new String(data.getSingularName()) + "$key").toCharArray(); + char[] valueName = !mapMode ? null : (new String(data.getSingularName()) + "$value").toCharArray(); + + MethodDeclaration md = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); + md.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; + md.modifiers = ClassFileConstants.AccPublic; + + List<Statement> statements = new ArrayList<Statement>(); + statements.add(createConstructBuilderVarIfNeeded(data, builderType)); + + FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L); + thisDotField.receiver = new ThisReference(0, 0); + MessageSend thisDotFieldDotAdd = new MessageSend(); + if (mapMode) { + thisDotFieldDotAdd.arguments = new Expression[] { + new SingleNameReference(keyName, 0L), + new SingleNameReference(valueName, 0L)}; + } else { + thisDotFieldDotAdd.arguments = new Expression[] {new SingleNameReference(keyName, 0L)}; + } + thisDotFieldDotAdd.receiver = thisDotField; + thisDotFieldDotAdd.selector = (mapMode ? "put" : "add").toCharArray(); + statements.add(thisDotFieldDotAdd); + if (returnStatement != null) statements.add(returnStatement); + md.statements = statements.toArray(new Statement[statements.size()]); + + if (mapMode) { + TypeReference keyType = cloneParamType(0, data.getTypeArgs(), builderType); + Argument keyParam = new Argument(keyName, 0, keyType, 0); + TypeReference valueType = cloneParamType(1, data.getTypeArgs(), builderType); + Argument valueParam = new Argument(valueName, 0, valueType, 0); + md.arguments = new Argument[] {keyParam, valueParam}; + } else { + TypeReference paramType = cloneParamType(0, data.getTypeArgs(), builderType); + Argument param = new Argument(keyName, 0, paramType, 0); + md.arguments = new Argument[] {param}; + } + md.returnType = returnType; + md.selector = fluent ? data.getSingularName() : HandlerUtil.buildAccessorName(mapMode ? "put" : "add", new String(data.getSingularName())).toCharArray(); + + data.setGeneratedByRecursive(md); + injectMethod(builderType, md); + } + + void generatePluralMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) { + boolean mapMode = isMap(); + + MethodDeclaration md = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); + md.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; + md.modifiers = ClassFileConstants.AccPublic; + + List<Statement> statements = new ArrayList<Statement>(); + statements.add(createConstructBuilderVarIfNeeded(data, builderType)); + + FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L); + thisDotField.receiver = new ThisReference(0, 0); + MessageSend thisDotFieldDotAddAll = new MessageSend(); + thisDotFieldDotAddAll.arguments = new Expression[] {new SingleNameReference(data.getPluralName(), 0L)}; + thisDotFieldDotAddAll.receiver = thisDotField; + thisDotFieldDotAddAll.selector = (mapMode ? "putAll" : "addAll").toCharArray(); + statements.add(thisDotFieldDotAddAll); + if (returnStatement != null) statements.add(returnStatement); + + md.statements = statements.toArray(new Statement[statements.size()]); + + TypeReference paramType; + if (mapMode) { + paramType = new QualifiedTypeReference(JAVA_UTIL_MAP, NULL_POSS); + paramType = addTypeArgs(2, true, builderType, paramType, data.getTypeArgs()); + } else { + paramType = new QualifiedTypeReference(TypeConstants.JAVA_LANG_ITERABLE, NULL_POSS); + paramType = addTypeArgs(1, true, builderType, paramType, data.getTypeArgs()); + } + Argument param = new Argument(data.getPluralName(), 0, paramType, 0); + md.arguments = new Argument[] {param}; + md.returnType = returnType; + md.selector = fluent ? data.getPluralName() : HandlerUtil.buildAccessorName(mapMode ? "putAll" : "addAll", new String(data.getPluralName())).toCharArray(); + + data.setGeneratedByRecursive(md); + injectMethod(builderType, md); + } + + @Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) { + boolean mapMode = isMap(); + TypeReference varType = new QualifiedTypeReference(fromQualifiedName(data.getTargetFqn()), NULL_POSS); + varType = addTypeArgs(mapMode ? 2 : 1, false, builderType, varType, data.getTypeArgs()); + + MessageSend emptyInvoke; { + //ImmutableX.of() + emptyInvoke = new MessageSend(); + emptyInvoke.selector = new char[] {'o', 'f'}; + emptyInvoke.receiver = new QualifiedNameReference(makeGuavaTypeName(getSimpleTargetTypeName(data), false), NULL_POSS, 0, 0); + } + + MessageSend invokeBuild; { + //this.pluralName.build(); + 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); + invokeBuild.receiver = thisDotField; + } + + Expression isNull; { + //this.pluralName == null + FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L); + thisDotField.receiver = new ThisReference(0, 0); + isNull = new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL); + } + + Expression init = new ConditionalExpression(isNull, emptyInvoke, invokeBuild); + LocalDeclaration varDefStat = new LocalDeclaration(data.getPluralName(), 0, 0); + varDefStat.type = varType; + varDefStat.initialization = init; + statements.add(varDefStat); + } + + protected Statement createConstructBuilderVarIfNeeded(SingularData data, EclipseNode builderType) { + FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L); + thisDotField.receiver = new ThisReference(0, 0); + FieldReference thisDotField2 = new FieldReference(data.getPluralName(), 0L); + thisDotField2.receiver = new ThisReference(0, 0); + Expression cond = new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL); + + MessageSend createBuilderInvoke = new MessageSend(); + char[][] tokenizedName = makeGuavaTypeName(getSimpleTargetTypeName(data), false); + createBuilderInvoke.receiver = new QualifiedNameReference(tokenizedName, NULL_POSS, 0, 0); + createBuilderInvoke.selector = getBuilderMethodName(data); + return new IfStatement(cond, new Assignment(thisDotField2, createBuilderInvoke, 0), 0, 0); + } +} diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java index 64b8bd40..f64748a8 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java @@ -59,6 +59,7 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula buildField.modifiers = ClassFileConstants.AccPrivate; buildField.declarationSourceEnd = -1; buildField.type = type; + data.setGeneratedByRecursive(buildField); return Collections.singletonList(injectField(builderType, buildField)); } @@ -96,6 +97,7 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula md.returnType = returnType; md.selector = fluent ? data.getSingularName() : HandlerUtil.buildAccessorName("add", new String(data.getSingularName())).toCharArray(); + data.setGeneratedByRecursive(md); injectMethod(builderType, md); } @@ -125,6 +127,7 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula md.returnType = returnType; md.selector = fluent ? data.getPluralName() : HandlerUtil.buildAccessorName("addAll", new String(data.getPluralName())).toCharArray(); + data.setGeneratedByRecursive(md); injectMethod(builderType, md); } } diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java index 8e250994..6558baa5 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java @@ -85,8 +85,10 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer buildValueField.declarationSourceEnd = -1; buildValueField.type = type; } - EclipseNode valueFieldNode = injectField(builderType, buildValueField); + data.setGeneratedByRecursive(buildKeyField); + data.setGeneratedByRecursive(buildValueField); EclipseNode keyFieldNode = injectField(builderType, buildKeyField); + EclipseNode valueFieldNode = injectField(builderType, buildValueField); return Arrays.asList(keyFieldNode, valueFieldNode); } @@ -145,6 +147,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer md.returnType = returnType; md.selector = fluent ? data.getSingularName() : HandlerUtil.buildAccessorName("put", new String(data.getSingularName())).toCharArray(); + data.setGeneratedByRecursive(md); injectMethod(builderType, md); } @@ -207,6 +210,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer md.returnType = returnType; md.selector = fluent ? data.getPluralName() : HandlerUtil.buildAccessorName("putAll", new String(data.getPluralName())).toCharArray(); + data.setGeneratedByRecursive(md); injectMethod(builderType, md); } diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 86598b3e..24e9dee4 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -54,6 +54,7 @@ import lombok.Singular; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; +import lombok.core.handlers.HandlerUtil; import lombok.experimental.NonFinal; import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; @@ -416,8 +417,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { if (existingName.equals(fieldName)) return; } - boolean isBoolean = isBoolean(fieldNode); - String setterName = fluent ? fieldNode.getName() : toSetterName(fieldNode.getAst(), null, fieldNode.getName(), isBoolean); + String setterName = fluent ? fieldNode.getName() : HandlerUtil.buildAccessorName("set", fieldNode.getName()); JavacTreeMaker maker = fieldNode.getTreeMaker(); JCMethodDecl newMethod = HandleSetter.createSetter(Flags.PUBLIC, fieldNode, maker, setterName, chain, source, List.<JCAnnotation>nil(), List.<JCAnnotation>nil()); diff --git a/src/core/lombok/javac/handlers/singulars/JavacGuavaMapSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaMapSingularizer.java index af39c3ba..0700e2e5 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaMapSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaMapSingularizer.java @@ -21,34 +21,11 @@ */ package lombok.javac.handlers.singulars; -import static lombok.javac.Javac.*; -import static lombok.javac.handlers.JavacHandlerUtil.*; - -import java.util.Collections; - import lombok.core.LombokImmutableList; -import lombok.core.handlers.HandlerUtil; -import lombok.javac.JavacNode; -import lombok.javac.JavacTreeMaker; -import lombok.javac.handlers.JavacHandlerUtil; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; -import lombok.javac.handlers.JavacSingularsRecipes.SingularData; import org.mangosdk.spi.ProviderFor; -import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCBlock; -import com.sun.tools.javac.tree.JCTree.JCExpression; -import com.sun.tools.javac.tree.JCTree.JCMethodDecl; -import com.sun.tools.javac.tree.JCTree.JCModifiers; -import com.sun.tools.javac.tree.JCTree.JCStatement; -import com.sun.tools.javac.tree.JCTree.JCTypeParameter; -import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.ListBuffer; -import com.sun.tools.javac.util.Name; - @ProviderFor(JavacSingularizer.class) public class JavacGuavaMapSingularizer extends JavacGuavaSingularizer { // TODO cgcc.ImmutableMultimap, cgcc.ImmutableListMultimap, cgcc.ImmutableSetMultimap @@ -62,99 +39,7 @@ public class JavacGuavaMapSingularizer extends JavacGuavaSingularizer { "com.google.common.collect.ImmutableSortedMap"); } - @Override public java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source) { - JavacTreeMaker maker = builderType.getTreeMaker(); - JCExpression type = JavacHandlerUtil.chainDots(builderType, "com", "google", "common", "collect", getSimpleTargetTypeName(data), "Builder"); - type = addTypeArgs(2, false, builderType, type, data.getTypeArgs(), source); - - JCVariableDecl buildField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), data.getPluralName(), type, null); - return Collections.singletonList(injectField(builderType, buildField)); - } - - @Override public void generateMethods(SingularData data, JavacNode builderType, JCTree source, boolean fluent, boolean chain) { - JavacTreeMaker maker = builderType.getTreeMaker(); - JCExpression returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(maker, CTC_VOID)); - JCStatement returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null; - generateSingularMethod(maker, returnType, returnStatement, data, builderType, source, fluent); - - returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(maker, CTC_VOID)); - returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null; - generatePluralMethod(maker, returnType, returnStatement, data, builderType, source, fluent); - } - - private void generateSingularMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent) { - List<JCTypeParameter> typeParams = List.nil(); - List<JCExpression> thrown = List.nil(); - - Name keyName = builderType.toName(data.getSingularName() + "$key"); - Name valueName = builderType.toName(data.getSingularName() + "$value"); - - JCModifiers mods = maker.Modifiers(Flags.PUBLIC); - ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); - statements.append(createConstructBuilderVarIfNeeded(maker, data, builderType, true, source)); - JCExpression thisDotFieldDotPut = chainDots(builderType, "this", data.getPluralName().toString(), "put"); - JCExpression invokePut = maker.Apply(List.<JCExpression>nil(), thisDotFieldDotPut, List.<JCExpression>of(maker.Ident(keyName), maker.Ident(valueName))); - statements.append(maker.Exec(invokePut)); - if (returnStatement != null) statements.append(returnStatement); - JCBlock body = maker.Block(0, statements.toList()); - Name name = data.getSingularName(); - long paramFlags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext()); - if (!fluent) name = builderType.toName(HandlerUtil.buildAccessorName("put", name.toString())); - JCExpression keyType = cloneParamType(0, maker, data.getTypeArgs(), builderType, source); - JCExpression valueType = cloneParamType(1, maker, data.getTypeArgs(), builderType, source); - JCVariableDecl paramKey = maker.VarDef(maker.Modifiers(paramFlags), keyName, keyType, null); - JCVariableDecl paramValue = maker.VarDef(maker.Modifiers(paramFlags), valueName, valueType, null); - JCMethodDecl method = maker.MethodDef(mods, name, returnType, typeParams, List.of(paramKey, paramValue), thrown, body, null); - injectMethod(builderType, method); - } - - private void generatePluralMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent) { - List<JCTypeParameter> typeParams = List.nil(); - List<JCExpression> thrown = List.nil(); - JCModifiers mods = maker.Modifiers(Flags.PUBLIC); - ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); - statements.append(createConstructBuilderVarIfNeeded(maker, data, builderType, true, source)); - JCExpression thisDotFieldDotPutAll = chainDots(builderType, "this", data.getPluralName().toString(), "putAll"); - JCExpression invokePutAll = maker.Apply(List.<JCExpression>nil(), thisDotFieldDotPutAll, List.<JCExpression>of(maker.Ident(data.getPluralName()))); - statements.append(maker.Exec(invokePutAll)); - if (returnStatement != null) statements.append(returnStatement); - JCBlock body = maker.Block(0, statements.toList()); - Name name = data.getPluralName(); - long paramFlags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext()); - if (!fluent) name = builderType.toName(HandlerUtil.buildAccessorName("putAll", name.toString())); - JCExpression paramType = chainDots(builderType, "java", "util", "Map"); - paramType = addTypeArgs(2, true, builderType, paramType, data.getTypeArgs(), source); - JCVariableDecl param = maker.VarDef(maker.Modifiers(paramFlags), data.getPluralName(), paramType, null); - JCMethodDecl method = maker.MethodDef(mods, name, returnType, typeParams, List.of(param), thrown, body, null); - injectMethod(builderType, method); - } - - @Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) { - JavacTreeMaker maker = builderType.getTreeMaker(); - List<JCExpression> jceBlank = List.nil(); - - JCExpression varType = chainDotsString(builderType, data.getTargetFqn()); - varType = addTypeArgs(2, false, builderType, varType, data.getTypeArgs(), source); - - JCExpression empty; { - //ImmutableX.of() - JCExpression emptyMethod = chainDots(builderType, "com", "google", "common", "collect", getSimpleTargetTypeName(data), "of"); - empty = maker.Apply(jceBlank, emptyMethod, jceBlank); - } - - JCExpression invokeBuild; { - //this.pluralName.build(); - invokeBuild = maker.Apply(jceBlank, chainDots(builderType, "this", 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)); - } - - JCExpression init = maker.Conditional(isNull, empty, invokeBuild); // this.pluralName == null ? ImmutableX.of() : this.pluralName.build() - - JCStatement jcs = maker.VarDef(maker.Modifiers(0), data.getPluralName(), varType, init); - statements.append(jcs); + @Override protected boolean isMap() { + return true; } } diff --git a/src/core/lombok/javac/handlers/singulars/JavacGuavaSetListSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaSetListSingularizer.java index 54ba091b..2e404ca8 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSetListSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSetListSingularizer.java @@ -21,33 +21,10 @@ */ package lombok.javac.handlers.singulars; -import static lombok.javac.Javac.*; -import static lombok.javac.handlers.JavacHandlerUtil.*; - -import java.util.Collections; - -import org.mangosdk.spi.ProviderFor; - import lombok.core.LombokImmutableList; -import lombok.core.handlers.HandlerUtil; -import lombok.javac.JavacNode; -import lombok.javac.JavacTreeMaker; -import lombok.javac.handlers.JavacHandlerUtil; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; -import lombok.javac.handlers.JavacSingularsRecipes.SingularData; -import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCBlock; -import com.sun.tools.javac.tree.JCTree.JCExpression; -import com.sun.tools.javac.tree.JCTree.JCMethodDecl; -import com.sun.tools.javac.tree.JCTree.JCModifiers; -import com.sun.tools.javac.tree.JCTree.JCStatement; -import com.sun.tools.javac.tree.JCTree.JCTypeParameter; -import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.ListBuffer; -import com.sun.tools.javac.util.Name; +import org.mangosdk.spi.ProviderFor; @ProviderFor(JavacSingularizer.class) public class JavacGuavaSetListSingularizer extends JavacGuavaSingularizer { @@ -62,94 +39,7 @@ public class JavacGuavaSetListSingularizer extends JavacGuavaSingularizer { "com.google.common.collect.ImmutableSortedSet"); } - @Override public java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source) { - JavacTreeMaker maker = builderType.getTreeMaker(); - JCExpression type = JavacHandlerUtil.chainDots(builderType, "com", "google", "common", "collect", getSimpleTargetTypeName(data), "Builder"); - type = addTypeArgs(1, false, builderType, type, data.getTypeArgs(), source); - - JCVariableDecl buildField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), data.getPluralName(), type, null); - return Collections.singletonList(injectField(builderType, buildField)); - } - - @Override public void generateMethods(SingularData data, JavacNode builderType, JCTree source, boolean fluent, boolean chain) { - JavacTreeMaker maker = builderType.getTreeMaker(); - JCExpression returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(maker, CTC_VOID)); - JCStatement returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null; - generateSingularMethod(maker, returnType, returnStatement, data, builderType, source, fluent); - - returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(maker, CTC_VOID)); - returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null; - generatePluralMethod(maker, returnType, returnStatement, data, builderType, source, fluent); - } - - private void generateSingularMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent) { - List<JCTypeParameter> typeParams = List.nil(); - List<JCExpression> thrown = List.nil(); - - JCModifiers mods = maker.Modifiers(Flags.PUBLIC); - ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); - statements.append(createConstructBuilderVarIfNeeded(maker, data, builderType, false, source)); - JCExpression thisDotFieldDotAdd = chainDots(builderType, "this", data.getPluralName().toString(), "add"); - JCExpression invokeAdd = maker.Apply(List.<JCExpression>nil(), thisDotFieldDotAdd, List.<JCExpression>of(maker.Ident(data.getSingularName()))); - statements.append(maker.Exec(invokeAdd)); - if (returnStatement != null) statements.append(returnStatement); - JCBlock body = maker.Block(0, statements.toList()); - Name name = data.getSingularName(); - long paramFlags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext()); - if (!fluent) name = builderType.toName(HandlerUtil.buildAccessorName("add", name.toString())); - JCExpression paramType = cloneParamType(0, maker, data.getTypeArgs(), builderType, source); - JCVariableDecl param = maker.VarDef(maker.Modifiers(paramFlags), data.getSingularName(), paramType, null); - JCMethodDecl method = maker.MethodDef(mods, name, returnType, typeParams, List.of(param), thrown, body, null); - injectMethod(builderType, method); - } - - private void generatePluralMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent) { - List<JCTypeParameter> typeParams = List.nil(); - List<JCExpression> thrown = List.nil(); - JCModifiers mods = maker.Modifiers(Flags.PUBLIC); - ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); - statements.append(createConstructBuilderVarIfNeeded(maker, data, builderType, false, source)); - JCExpression thisDotFieldDotAdd = chainDots(builderType, "this", data.getPluralName().toString(), "addAll"); - JCExpression invokeAdd = maker.Apply(List.<JCExpression>nil(), thisDotFieldDotAdd, List.<JCExpression>of(maker.Ident(data.getPluralName()))); - statements.append(maker.Exec(invokeAdd)); - if (returnStatement != null) statements.append(returnStatement); - JCBlock body = maker.Block(0, statements.toList()); - Name name = data.getPluralName(); - long paramFlags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext()); - if (!fluent) name = builderType.toName(HandlerUtil.buildAccessorName("addAll", name.toString())); - JCExpression paramType = chainDots(builderType, "java", "lang", "Iterable"); - paramType = addTypeArgs(1, true, builderType, paramType, data.getTypeArgs(), source); - JCVariableDecl param = maker.VarDef(maker.Modifiers(paramFlags), data.getPluralName(), paramType, null); - JCMethodDecl method = maker.MethodDef(mods, name, returnType, typeParams, List.of(param), thrown, body, null); - injectMethod(builderType, method); - } - - @Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) { - JavacTreeMaker maker = builderType.getTreeMaker(); - List<JCExpression> jceBlank = List.nil(); - - JCExpression varType = chainDotsString(builderType, data.getTargetFqn()); - varType = addTypeArgs(1, false, builderType, varType, data.getTypeArgs(), source); - - JCExpression empty; { - //ImmutableX.of() - JCExpression emptyMethod = chainDots(builderType, "com", "google", "common", "collect", getSimpleTargetTypeName(data), "of"); - empty = maker.Apply(jceBlank, emptyMethod, jceBlank); - } - - JCExpression invokeBuild; { - //this.pluralName.build(); - invokeBuild = maker.Apply(jceBlank, chainDots(builderType, "this", 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)); - } - - JCExpression init = maker.Conditional(isNull, empty, invokeBuild); // this.pluralName == null ? ImmutableX.of() : this.pluralName.build() - - JCStatement jcs = maker.VarDef(maker.Modifiers(0), data.getPluralName(), varType, init); - statements.append(jcs); + @Override protected boolean isMap() { + return false; } } diff --git a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java index ae9f34c5..62cbc98b 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java @@ -22,18 +22,30 @@ package lombok.javac.handlers.singulars; import static lombok.javac.Javac.*; -import static lombok.javac.handlers.JavacHandlerUtil.chainDots; +import static lombok.javac.handlers.JavacHandlerUtil.*; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCExpression; -import com.sun.tools.javac.tree.JCTree.JCStatement; -import com.sun.tools.javac.util.List; +import java.util.Collections; +import lombok.core.handlers.HandlerUtil; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; +import lombok.javac.handlers.JavacHandlerUtil; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; import lombok.javac.handlers.JavacSingularsRecipes.SingularData; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCBlock; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCModifiers; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCTypeParameter; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Name; + abstract class JavacGuavaSingularizer extends JavacSingularizer { protected String getSimpleTargetTypeName(SingularData data) { String simpleTypeName = data.getTargetSimpleType(); @@ -47,6 +59,126 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { return "builder"; } + protected abstract boolean isMap(); + + @Override public java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source) { + JavacTreeMaker maker = builderType.getTreeMaker(); + JCExpression type = JavacHandlerUtil.chainDots(builderType, "com", "google", "common", "collect", getSimpleTargetTypeName(data), "Builder"); + type = addTypeArgs(isMap() ? 2 : 1, false, builderType, type, data.getTypeArgs(), source); + + JCVariableDecl buildField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), data.getPluralName(), type, null); + return Collections.singletonList(injectField(builderType, buildField)); + } + + @Override public void generateMethods(SingularData data, JavacNode builderType, JCTree source, boolean fluent, boolean chain) { + JavacTreeMaker maker = builderType.getTreeMaker(); + JCExpression returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(maker, CTC_VOID)); + JCStatement returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null; + generateSingularMethod(maker, returnType, returnStatement, data, builderType, source, fluent); + + returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(maker, CTC_VOID)); + returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null; + generatePluralMethod(maker, returnType, returnStatement, data, builderType, source, fluent); + } + + void generateSingularMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent) { + List<JCTypeParameter> typeParams = List.nil(); + List<JCExpression> thrown = List.nil(); + boolean mapMode = isMap(); + + Name keyName = !mapMode ? data.getSingularName() : builderType.toName(data.getSingularName() + "$key"); + Name valueName = !mapMode ? null : builderType.toName(data.getSingularName() + "$value"); + + JCModifiers mods = maker.Modifiers(Flags.PUBLIC); + ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); + statements.append(createConstructBuilderVarIfNeeded(maker, data, builderType, mapMode, source)); + JCExpression thisDotFieldDotAdd = chainDots(builderType, "this", data.getPluralName().toString(), mapMode ? "put" : "add"); + List<JCExpression> invokeAddExpr; + if (mapMode) { + invokeAddExpr = List.<JCExpression>of(maker.Ident(keyName), maker.Ident(valueName)); + } else { + invokeAddExpr = List.<JCExpression>of(maker.Ident(keyName)); + } + JCExpression invokeAdd = maker.Apply(List.<JCExpression>nil(), thisDotFieldDotAdd, invokeAddExpr); + statements.append(maker.Exec(invokeAdd)); + if (returnStatement != null) statements.append(returnStatement); + JCBlock body = maker.Block(0, statements.toList()); + Name methodName = data.getSingularName(); + long paramFlags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext()); + if (!fluent) methodName = builderType.toName(HandlerUtil.buildAccessorName(mapMode ? "put" : "add", methodName.toString())); + List<JCVariableDecl> params; + if (mapMode) { + JCExpression keyType = cloneParamType(0, maker, data.getTypeArgs(), builderType, source); + JCExpression valueType = cloneParamType(1, maker, data.getTypeArgs(), builderType, source); + JCVariableDecl paramKey = maker.VarDef(maker.Modifiers(paramFlags), keyName, keyType, null); + JCVariableDecl paramValue = maker.VarDef(maker.Modifiers(paramFlags), valueName, valueType, null); + params = List.of(paramKey, paramValue); + } else { + JCExpression paramType = cloneParamType(0, maker, data.getTypeArgs(), builderType, source); + params = List.of(maker.VarDef(maker.Modifiers(paramFlags), data.getSingularName(), paramType, null)); + } + JCMethodDecl method = maker.MethodDef(mods, methodName, returnType, typeParams, params, thrown, body, null); + injectMethod(builderType, method); + } + + protected void generatePluralMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent) { + List<JCTypeParameter> typeParams = List.nil(); + List<JCExpression> thrown = List.nil(); + boolean mapMode = isMap(); + + JCModifiers mods = maker.Modifiers(Flags.PUBLIC); + ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); + statements.append(createConstructBuilderVarIfNeeded(maker, data, builderType, mapMode, source)); + JCExpression thisDotFieldDotAddAll = chainDots(builderType, "this", data.getPluralName().toString(), mapMode ? "putAll" : "addAll"); + JCExpression invokeAddAll = maker.Apply(List.<JCExpression>nil(), thisDotFieldDotAddAll, List.<JCExpression>of(maker.Ident(data.getPluralName()))); + statements.append(maker.Exec(invokeAddAll)); + if (returnStatement != null) statements.append(returnStatement); + JCBlock body = maker.Block(0, statements.toList()); + Name methodName = data.getPluralName(); + long paramFlags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, builderType.getContext()); + if (!fluent) methodName = builderType.toName(HandlerUtil.buildAccessorName(mapMode ? "putAll" : "addAll", methodName.toString())); + JCExpression paramType; + if (mapMode) { + paramType = chainDots(builderType, "java", "util", "Map"); + } else { + paramType = chainDots(builderType, "java", "lang", "Iterable"); + } + paramType = addTypeArgs(mapMode ? 2 : 1, true, builderType, paramType, data.getTypeArgs(), source); + JCVariableDecl param = maker.VarDef(maker.Modifiers(paramFlags), data.getPluralName(), paramType, null); + JCMethodDecl method = maker.MethodDef(mods, methodName, returnType, typeParams, List.of(param), thrown, body, null); + injectMethod(builderType, method); + } + + @Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) { + JavacTreeMaker maker = builderType.getTreeMaker(); + List<JCExpression> jceBlank = List.nil(); + boolean mapMode = isMap(); + + JCExpression varType = chainDotsString(builderType, data.getTargetFqn()); + varType = addTypeArgs(mapMode ? 2 : 1, false, builderType, varType, data.getTypeArgs(), source); + + JCExpression empty; { + //ImmutableX.of() + JCExpression emptyMethod = chainDots(builderType, "com", "google", "common", "collect", getSimpleTargetTypeName(data), "of"); + empty = maker.Apply(jceBlank, emptyMethod, jceBlank); + } + + JCExpression invokeBuild; { + //this.pluralName.build(); + invokeBuild = maker.Apply(jceBlank, chainDots(builderType, "this", 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)); + } + + JCExpression init = maker.Conditional(isNull, empty, invokeBuild); // this.pluralName == null ? ImmutableX.of() : this.pluralName.build() + + JCStatement jcs = maker.VarDef(maker.Modifiers(0), data.getPluralName(), varType, init); + statements.append(jcs); + } + protected JCStatement createConstructBuilderVarIfNeeded(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, JCTree source) { List<JCExpression> jceBlank = List.nil(); |