diff options
| author | Reinier Zwitserloot <reinier@zwitserloot.com> | 2015-01-15 04:43:36 +0100 |
|---|---|---|
| committer | Reinier Zwitserloot <reinier@zwitserloot.com> | 2015-01-15 04:43:36 +0100 |
| commit | a05360a8eaba0de61f16f75816daf5a5af0a4567 (patch) | |
| tree | 1f58ee60fe30397c1d0367799782225bc04483eb /src/core/lombok/eclipse/handlers/singulars | |
| parent | d700d54ed6c7d171a6498b8727a8e4cfbe8454e2 (diff) | |
| download | lombok-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')
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); + } +} |
