aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok/eclipse/handlers/singulars
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@zwitserloot.com>2015-01-15 04:43:36 +0100
committerReinier Zwitserloot <reinier@zwitserloot.com>2015-01-15 04:43:36 +0100
commita05360a8eaba0de61f16f75816daf5a5af0a4567 (patch)
tree1f58ee60fe30397c1d0367799782225bc04483eb /src/core/lombok/eclipse/handlers/singulars
parentd700d54ed6c7d171a6498b8727a8e4cfbe8454e2 (diff)
downloadlombok-a05360a8eaba0de61f16f75816daf5a5af0a4567.tar.gz
lombok-a05360a8eaba0de61f16f75816daf5a5af0a4567.tar.bz2
lombok-a05360a8eaba0de61f16f75816daf5a5af0a4567.zip
ecj @Builder @Singular support for j.u. sets and maps.
Diffstat (limited to 'src/core/lombok/eclipse/handlers/singulars')
-rw-r--r--src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java220
-rw-r--r--src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSetSingularizer.java146
-rw-r--r--src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java288
3 files changed, 654 insertions, 0 deletions
diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java
new file mode 100644
index 00000000..8e250994
--- /dev/null
+++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java
@@ -0,0 +1,220 @@
+/*
+ * 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.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.ast.Block;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+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.ForeachStatement;
+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.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.TypeIds;
+import org.mangosdk.spi.ProviderFor;
+
+import lombok.core.LombokImmutableList;
+import lombok.core.handlers.HandlerUtil;
+import lombok.eclipse.EclipseNode;
+import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer;
+import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData;
+
+@ProviderFor(EclipseSingularizer.class)
+public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer {
+ @Override public LombokImmutableList<String> getSupportedTypes() {
+ return LombokImmutableList.of("java.util.Map", "java.util.SortedMap", "java.util.NavigableMap");
+ }
+
+ @Override public java.util.List<EclipseNode> generateFields(SingularData data, EclipseNode builderType) {
+ char[] keyName = (new String(data.getPluralName()) + "$key").toCharArray();
+ char[] valueName = (new String(data.getPluralName()) + "$value").toCharArray();
+ FieldDeclaration buildKeyField; {
+ TypeReference type = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS);
+ type = addTypeArgs(1, false, builderType, type, data.getTypeArgs());
+ buildKeyField = new FieldDeclaration(keyName, 0, -1);
+ buildKeyField.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
+ buildKeyField.modifiers = ClassFileConstants.AccPrivate;
+ buildKeyField.declarationSourceEnd = -1;
+ buildKeyField.type = type;
+ }
+ FieldDeclaration buildValueField; {
+ TypeReference type = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS);
+ List<TypeReference> tArgs = data.getTypeArgs();
+ if (tArgs != null && tArgs.size() > 1) tArgs = Collections.singletonList(tArgs.get(1));
+ else tArgs = Collections.emptyList();
+ type = addTypeArgs(1, false, builderType, type, tArgs);
+ buildValueField = new FieldDeclaration(valueName, 0, -1);
+ buildValueField.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
+ buildValueField.modifiers = ClassFileConstants.AccPrivate;
+ buildValueField.declarationSourceEnd = -1;
+ buildValueField.type = type;
+ }
+ EclipseNode valueFieldNode = injectField(builderType, buildValueField);
+ EclipseNode keyFieldNode = injectField(builderType, buildKeyField);
+ return Arrays.asList(keyFieldNode, valueFieldNode);
+ }
+
+ @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);
+ }
+
+ private void generateSingularMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) {
+ 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, true));
+
+ String sN = new String(data.getSingularName());
+ String pN = new String(data.getPluralName());
+ char[] keyParamName = (sN + "Key").toCharArray();
+ char[] valueParamName = (sN + "Value").toCharArray();
+ char[] keyFieldName = (pN + "$key").toCharArray();
+ char[] valueFieldName = (pN + "$value").toCharArray();
+
+ /* this.pluralname$key.add(singularnameKey); */ {
+ FieldReference thisDotKeyField = new FieldReference(keyFieldName, 0L);
+ thisDotKeyField.receiver = new ThisReference(0, 0);
+ MessageSend thisDotKeyFieldDotAdd = new MessageSend();
+ thisDotKeyFieldDotAdd.arguments = new Expression[] {new SingleNameReference(keyParamName, 0L)};
+ thisDotKeyFieldDotAdd.receiver = thisDotKeyField;
+ thisDotKeyFieldDotAdd.selector = "add".toCharArray();
+ statements.add(thisDotKeyFieldDotAdd);
+ }
+
+ /* this.pluralname$value.add(singularnameValue); */ {
+ FieldReference thisDotValueField = new FieldReference(valueFieldName, 0L);
+ thisDotValueField.receiver = new ThisReference(0, 0);
+ MessageSend thisDotValueFieldDotAdd = new MessageSend();
+ thisDotValueFieldDotAdd.arguments = new Expression[] {new SingleNameReference(valueParamName, 0L)};
+ thisDotValueFieldDotAdd.receiver = thisDotValueField;
+ thisDotValueFieldDotAdd.selector = "add".toCharArray();
+ statements.add(thisDotValueFieldDotAdd);
+ }
+ if (returnStatement != null) statements.add(returnStatement);
+
+ md.statements = statements.toArray(new Statement[statements.size()]);
+ TypeReference keyParamType = cloneParamType(0, data.getTypeArgs(), builderType);
+ Argument keyParam = new Argument(keyParamName, 0, keyParamType, 0);
+ TypeReference valueParamType = cloneParamType(1, data.getTypeArgs(), builderType);
+ Argument valueParam = new Argument(valueParamName, 0, valueParamType, 0);
+ md.arguments = new Argument[] {keyParam, valueParam};
+ md.returnType = returnType;
+ md.selector = fluent ? data.getSingularName() : HandlerUtil.buildAccessorName("put", new String(data.getSingularName())).toCharArray();
+
+ injectMethod(builderType, md);
+ }
+
+ private void generatePluralMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) {
+ MethodDeclaration md = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult);
+ md.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
+ md.modifiers = ClassFileConstants.AccPublic;
+
+ String pN = new String(data.getPluralName());
+ char[] keyFieldName = (pN + "$key").toCharArray();
+ char[] valueFieldName = (pN + "$value").toCharArray();
+
+ List<Statement> statements = new ArrayList<Statement>();
+ statements.add(createConstructBuilderVarIfNeeded(data, builderType, true));
+
+ char[] entryName = "$lombokEntry".toCharArray();
+
+ TypeReference forEachType = new QualifiedTypeReference(JAVA_UTIL_MAP_ENTRY, NULL_POSS);
+ forEachType = addTypeArgs(2, true, builderType, forEachType, data.getTypeArgs());
+
+ MessageSend keyArg = new MessageSend();
+ keyArg.receiver = new SingleNameReference(entryName, 0L);
+ keyArg.selector = "getKey".toCharArray();
+ MessageSend addKey = new MessageSend();
+ FieldReference thisDotKeyField = new FieldReference(keyFieldName, 0L);
+ thisDotKeyField.receiver = new ThisReference(0, 0);
+ addKey.receiver = thisDotKeyField;
+ addKey.selector = new char[] {'a', 'd', 'd'};
+ addKey.arguments = new Expression[] {keyArg};
+
+ MessageSend valueArg = new MessageSend();
+ valueArg.receiver = new SingleNameReference(entryName, 0L);
+ valueArg.selector = "getValue".toCharArray();
+ MessageSend addValue = new MessageSend();
+ FieldReference thisDotValueField = new FieldReference(valueFieldName, 0L);
+ thisDotValueField.receiver = new ThisReference(0, 0);
+ addValue.receiver = thisDotValueField;
+ addValue.selector = new char[] {'a', 'd', 'd'};
+ addValue.arguments = new Expression[] {valueArg};
+
+ LocalDeclaration elementVariable = new LocalDeclaration(entryName, 0, 0);
+ elementVariable.type = forEachType;
+ ForeachStatement forEach = new ForeachStatement(elementVariable, 0);
+ MessageSend invokeEntrySet = new MessageSend();
+ invokeEntrySet.selector = new char[] { 'e', 'n', 't', 'r', 'y', 'S', 'e', 't'};
+ invokeEntrySet.receiver = new SingleNameReference(data.getPluralName(), 0L);
+ forEach.collection = invokeEntrySet;
+ Block forEachContent = new Block(0);
+ forEachContent.statements = new Statement[] {addKey, addValue};
+ forEach.action = forEachContent;
+ statements.add(forEach);
+ if (returnStatement != null) statements.add(returnStatement);
+
+ md.statements = statements.toArray(new Statement[statements.size()]);
+
+ TypeReference paramType = new QualifiedTypeReference(JAVA_UTIL_MAP, NULL_POSS);
+ paramType = addTypeArgs(2, 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("putAll", new String(data.getPluralName())).toCharArray();
+
+ injectMethod(builderType, md);
+ }
+
+ @Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) {
+ if (data.getTargetFqn().equals("java.util.Map")) {
+ statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, true, "emptyMap", "singletonMap", "LinkedHashMap"));
+ } else {
+ statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, true, true, false, true, "TreeMap"));
+ }
+ }
+}
diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSetSingularizer.java
new file mode 100644
index 00000000..aac8545c
--- /dev/null
+++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSetSingularizer.java
@@ -0,0 +1,146 @@
+/*
+ * 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.LombokImmutableList;
+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.CompilationUnitDeclaration;
+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.MessageSend;
+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+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;
+import org.mangosdk.spi.ProviderFor;
+
+@ProviderFor(EclipseSingularizer.class)
+public class EclipseJavaUtilSetSingularizer extends EclipseJavaUtilSingularizer {
+ @Override public LombokImmutableList<String> getSupportedTypes() {
+ return LombokImmutableList.of("java.util.Set", "java.util.SortedSet", "java.util.NavigableSet");
+ }
+
+ @Override public List<EclipseNode> generateFields(SingularData data, EclipseNode builderType) {
+ TypeReference type = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS);
+ type = addTypeArgs(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;
+ 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);
+ }
+
+ private void generateSingularMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) {
+ 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, false));
+
+ FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L);
+ thisDotField.receiver = new ThisReference(0, 0);
+ MessageSend thisDotFieldDotAdd = new MessageSend();
+ thisDotFieldDotAdd.arguments = new Expression[] {new SingleNameReference(data.getSingularName(), 0L)};
+ thisDotFieldDotAdd.receiver = thisDotField;
+ thisDotFieldDotAdd.selector = "add".toCharArray();
+ statements.add(thisDotFieldDotAdd);
+ if (returnStatement != null) statements.add(returnStatement);
+
+ md.statements = statements.toArray(new Statement[statements.size()]);
+ TypeReference paramType = cloneParamType(0, data.getTypeArgs(), builderType);
+ Argument param = new Argument(data.getSingularName(), 0, paramType, 0);
+ md.arguments = new Argument[] {param};
+ md.returnType = returnType;
+ md.selector = fluent ? data.getSingularName() : HandlerUtil.buildAccessorName("add", new String(data.getSingularName())).toCharArray();
+
+ injectMethod(builderType, md);
+ }
+
+ private void generatePluralMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) {
+ 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, false));
+
+ 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 = "addAll".toCharArray();
+ statements.add(thisDotFieldDotAddAll);
+ if (returnStatement != null) statements.add(returnStatement);
+
+ md.statements = statements.toArray(new Statement[statements.size()]);
+
+ TypeReference paramType = new QualifiedTypeReference(TypeConstants.JAVA_UTIL_COLLECTION, 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("addAll", new String(data.getPluralName())).toCharArray();
+
+ injectMethod(builderType, md);
+ }
+
+ @Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) {
+ if (data.getTargetFqn().equals("java.util.Set")) {
+ statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, false, "emptySet", "singleton", "LinkedHashSet"));
+ } else {
+ statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, false, true, false, true, "TreeSet"));
+ }
+ }
+}
diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java
new file mode 100644
index 00000000..ca1db7bc
--- /dev/null
+++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java
@@ -0,0 +1,288 @@
+/*
+ * 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.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
+import org.eclipse.jdt.internal.compiler.ast.Assignment;
+import org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
+import org.eclipse.jdt.internal.compiler.ast.Block;
+import org.eclipse.jdt.internal.compiler.ast.BreakStatement;
+import org.eclipse.jdt.internal.compiler.ast.CaseStatement;
+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.FieldReference;
+import org.eclipse.jdt.internal.compiler.ast.ForStatement;
+import org.eclipse.jdt.internal.compiler.ast.IfStatement;
+import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
+import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.MessageSend;
+import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
+import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
+import org.eclipse.jdt.internal.compiler.ast.PostfixExpression;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
+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.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+
+import lombok.eclipse.EclipseNode;
+import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer;
+import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData;
+
+abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
+ protected static final char[][] JAVA_UTIL_ARRAYLIST = {
+ {'j', 'a', 'v', 'a'}, {'u', 't', 'i', 'l'}, {'A', 'r', 'r', 'a', 'y', 'L', 'i', 's', 't'}
+ };
+
+ protected static final char[][] JAVA_UTIL_MAP = {
+ {'j', 'a', 'v', 'a'}, {'u', 't', 'i', 'l'}, {'M', 'a', 'p'}
+ };
+
+ protected static final char[][] JAVA_UTIL_MAP_ENTRY = {
+ {'j', 'a', 'v', 'a'}, {'u', 't', 'i', 'l'}, {'M', 'a', 'p'}, {'E', 'n', 't', 'r', 'y'}
+ };
+
+ protected static final char[][] JAVA_UTIL_COLLECTIONS = {
+ {'j', 'a', 'v', 'a'}, {'u', 't', 'i', 'l'}, {'C', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', 's'}
+ };
+
+ protected List<Statement> createJavaUtilSetMapInitialCapacitySwitchStatements(SingularData data, EclipseNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType) {
+ List<Statement> switchContents = new ArrayList<Statement>();
+ char[] keyName = mapMode ? (new String(data.getPluralName()) + "$key").toCharArray() : data.getPluralName();
+
+ if (emptyCollectionMethod != null) { // case 0: (empty); break;
+ switchContents.add(new CaseStatement(makeIntLiteral(new char[] {'0'}, null), 0, 0));
+
+ /* pluralName = java.util.Collections.emptyCollectionMethod(); */ {
+ MessageSend invoke = new MessageSend();
+ invoke.receiver = new QualifiedNameReference(JAVA_UTIL_COLLECTIONS, NULL_POSS, 0, 0);
+ invoke.selector = emptyCollectionMethod.toCharArray();
+ switchContents.add(new Assignment(new SingleNameReference(data.getPluralName(), 0), invoke, 0));
+ }
+
+ switchContents.add(new BreakStatement(null, 0, 0));
+ }
+
+ if (singletonCollectionMethod != null) { // case 1: (singleton); break;
+ switchContents.add(new CaseStatement(makeIntLiteral(new char[] {'1'}, null), 0, 0));
+ /* !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);
+ MessageSend thisDotKeyGet0 = new MessageSend();
+ thisDotKeyGet0.receiver = thisDotKey;
+ thisDotKeyGet0.selector = new char[] {'g', 'e', 't'};
+ thisDotKeyGet0.arguments = new Expression[] {makeIntLiteral(new char[] {'0'}, null)};
+
+ Expression[] args;
+ if (mapMode) {
+ char[] valueName = (new String(data.getPluralName()) + "$value").toCharArray();
+ FieldReference thisDotValue = new FieldReference(valueName, 0L);
+ thisDotValue.receiver = new ThisReference(0, 0);
+ MessageSend thisDotValueGet0 = new MessageSend();
+ thisDotValueGet0.receiver = thisDotValue;
+ thisDotValueGet0.selector = new char[] {'g', 'e', 't'};
+ thisDotValueGet0.arguments = new Expression[] {makeIntLiteral(new char[] {'0'}, null)};
+ args = new Expression[] {thisDotKeyGet0, thisDotValueGet0};
+ } else {
+ args = new Expression[] {thisDotKeyGet0};
+ }
+
+ MessageSend invoke = new MessageSend();
+ invoke.receiver = new QualifiedNameReference(JAVA_UTIL_COLLECTIONS, NULL_POSS, 0, 0);
+ invoke.selector = singletonCollectionMethod.toCharArray();
+ invoke.arguments = args;
+ switchContents.add(new Assignment(new SingleNameReference(data.getPluralName(), 0), invoke, 0));
+ }
+ switchContents.add(new BreakStatement(null, 0, 0));
+ }
+
+ { // default:
+ switchContents.add(new CaseStatement(null, 0, 0));
+ switchContents.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, mapMode, false, true, emptyCollectionMethod == null, targetType));
+ }
+
+ SwitchStatement switchStat = new SwitchStatement();
+ switchStat.statements = switchContents.toArray(new Statement[switchContents.size()]);
+ switchStat.expression = getSize(builderType, keyName, true);
+
+ TypeReference localShadowerType = new QualifiedTypeReference(fromQualifiedName(data.getTargetFqn()), NULL_POSS);
+ localShadowerType = addTypeArgs(mapMode ? 2 : 1, false, builderType, localShadowerType, data.getTypeArgs());
+ LocalDeclaration varDefStat = new LocalDeclaration(data.getPluralName(), 0, 0);
+ varDefStat.type = localShadowerType;
+ return Arrays.asList(varDefStat, switchStat);
+ }
+
+ protected List<Statement> createJavaUtilSimpleCreationAndFillStatements(SingularData data, EclipseNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType) {
+ char[] varName = mapMode ? (new String(data.getPluralName()) + "$key").toCharArray() : data.getPluralName();
+
+ Statement createStat; {
+ // pluralName = new java.util.TargetType(initialCap);
+ Expression[] constructorArgs = null;
+ 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);
+ 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 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);
+ constructorArgs = new Expression[] {cond};
+ }
+
+ TypeReference targetTypeRef = new QualifiedTypeReference(new char[][] {TypeConstants.JAVA, TypeConstants.UTIL, targetType.toCharArray()}, NULL_POSS);
+ targetTypeRef = addTypeArgs(mapMode ? 2 : 1, false, builderType, targetTypeRef, data.getTypeArgs());
+ AllocationExpression constructorCall = new AllocationExpression();
+ constructorCall.type = targetTypeRef;
+ constructorCall.arguments = constructorArgs;
+
+ if (defineVar) {
+ TypeReference localShadowerType = new QualifiedTypeReference(fromQualifiedName(data.getTargetFqn()), NULL_POSS);
+ localShadowerType = addTypeArgs(mapMode ? 2 : 1, false, builderType, localShadowerType, data.getTypeArgs());
+ LocalDeclaration localShadowerDecl = new LocalDeclaration(data.getPluralName(), 0, 0);
+ localShadowerDecl.type = localShadowerType;
+ localShadowerDecl.initialization = constructorCall;
+ createStat = localShadowerDecl;
+ } else {
+ createStat = new Assignment(new SingleNameReference(data.getPluralName(), 0L), constructorCall, 0);
+ }
+ }
+
+ Statement fillStat; {
+ if (mapMode) {
+ // for (int $i = 0; $i < this.pluralname$key.size(); i++) pluralname.put(this.pluralname$key.get($i), this.pluralname$value.get($i));
+ char[] iVar = new char[] {'$', 'i'};
+ MessageSend pluralnameDotPut = new MessageSend();
+ 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);
+ FieldReference thisDotValue = new FieldReference((new String(data.getPluralName()) + "$value").toCharArray(), 0L);
+ thisDotValue.receiver = new ThisReference(0, 0);
+ MessageSend keyArg = new MessageSend();
+ keyArg.receiver = thisDotKey;
+ keyArg.arguments = new Expression[] {new SingleNameReference(iVar, 0L)};
+ keyArg.selector = new char[] {'g', 'e', 't'};
+ MessageSend valueArg = new MessageSend();
+ valueArg.receiver = thisDotValue;
+ valueArg.arguments = new Expression[] {new SingleNameReference(iVar, 0L)};
+ valueArg.selector = new char[] {'g', 'e', 't'};
+ pluralnameDotPut.arguments = new Expression[] {keyArg, valueArg};
+
+ 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 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 {
+ // pluralname.addAll(this.pluralname);
+ MessageSend pluralnameDotAddAll = new MessageSend();
+ 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);
+ pluralnameDotAddAll.arguments = new Expression[] {thisDotPluralname};
+ fillStat = pluralnameDotAddAll;
+ }
+
+ if (nullGuard) {
+ FieldReference thisDotField = new FieldReference(varName, 0L);
+ thisDotField.receiver = new ThisReference(0, 0);
+ Expression cond = new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.NOT_EQUAL);
+ fillStat = new IfStatement(cond, fillStat, 0, 0);
+ }
+ }
+
+ Statement unmodifiableStat; {
+ // pluralname = Collections.unmodifiableInterfaceType(pluralname);
+ Expression arg = new SingleNameReference(data.getPluralName(), 0L);
+ MessageSend invoke = new MessageSend();
+ invoke.arguments = new Expression[] {arg};
+ invoke.selector = ("unmodifiable" + data.getTargetSimpleType()).toCharArray();
+ invoke.receiver = new QualifiedNameReference(JAVA_UTIL_COLLECTIONS, NULL_POSS, 0, 0);
+ unmodifiableStat = new Assignment(new SingleNameReference(data.getPluralName(), 0L), invoke, 0);
+ }
+
+ return Arrays.asList(createStat, fillStat, unmodifiableStat);
+ }
+
+ protected Statement createConstructBuilderVarIfNeeded(SingularData data, EclipseNode builderType, boolean mapMode) {
+ char[] v1Name, v2Name;
+ if (mapMode) {
+ String n = new String(data.getPluralName());
+ v1Name = (n + "$key").toCharArray();
+ v2Name = (n + "$value").toCharArray();
+ } else {
+ v1Name = data.getPluralName();
+ v2Name = null;
+ }
+
+ FieldReference thisDotField = new FieldReference(v1Name, 0L);
+ thisDotField.receiver = new ThisReference(0, 0);
+ Expression cond = new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL);
+
+ thisDotField = new FieldReference(v1Name, 0L);
+ thisDotField.receiver = new ThisReference(0, 0);
+ TypeReference v1Type = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS);
+ v1Type = addTypeArgs(1, false, builderType, v1Type, data.getTypeArgs());
+ AllocationExpression constructArrayList = new AllocationExpression();
+ constructArrayList.type = v1Type;
+ Assignment initV1 = new Assignment(thisDotField, constructArrayList, 0);
+ Statement thenPart;
+ if (mapMode) {
+ thisDotField = new FieldReference(v2Name, 0L);
+ thisDotField.receiver = new ThisReference(0, 0);
+ TypeReference v2Type = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS);
+ List<TypeReference> tArgs = data.getTypeArgs();
+ if (tArgs != null && tArgs.size() > 1) tArgs = Collections.singletonList(tArgs.get(1));
+ else tArgs = Collections.emptyList();
+ v2Type = addTypeArgs(1, false, builderType, v2Type, tArgs);
+ constructArrayList = new AllocationExpression();
+ constructArrayList.type = v2Type;
+ Assignment initV2 = new Assignment(thisDotField, constructArrayList, 0);
+ Block b = new Block(0);
+ b.statements = new Statement[] {initV1, initV2};
+ thenPart = b;
+ } else {
+ thenPart = initV1;
+ }
+
+ return new IfStatement(cond, thenPart, 0, 0);
+ }
+}