diff options
10 files changed, 222 insertions, 113 deletions
@@ -13,6 +13,7 @@ Reinier Zwitserloot <reinier@zwitserloot.com> Robbert Jan Grootjans <grootjans@gmail.com> Roel Spilker <r.spilker@gmail.com> Sander Koning <askoning@gmail.com> +Szymon Pacanowski <spacanowski@gmail.com> Taiki Sugawara <buzz.taiki@gmail.com> Yun Zhi Lin <yun@yunspace.com> diff --git a/src/core/lombok/core/GuavaTypeMap.java b/src/core/lombok/core/GuavaTypeMap.java index 900d2b72..e84a32be 100644 --- a/src/core/lombok/core/GuavaTypeMap.java +++ b/src/core/lombok/core/GuavaTypeMap.java @@ -1,16 +1,16 @@ /* * 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 @@ -28,7 +28,7 @@ import java.util.Map; public final class GuavaTypeMap { private static final Map<String, String> TYPE_TO_GUAVA_TYPE; static { Map<String, String> m = new HashMap<String, String>(); - + m.put("java.util.NavigableSet", "ImmutableSortedSet"); m.put("java.util.NavigableMap", "ImmutableSortedMap"); m.put("java.util.SortedSet", "ImmutableSortedSet"); @@ -37,7 +37,7 @@ public final class GuavaTypeMap { m.put("java.util.Map", "ImmutableMap"); m.put("java.util.Collection", "ImmutableList"); m.put("java.util.List", "ImmutableList"); - + m.put("com.google.common.collect.ImmutableSet", "ImmutableSet"); m.put("com.google.common.collect.ImmutableSortedSet", "ImmutableSortedSet"); m.put("com.google.common.collect.ImmutableMap", "ImmutableMap"); @@ -45,14 +45,15 @@ public final class GuavaTypeMap { m.put("com.google.common.collect.ImmutableSortedMap", "ImmutableSortedMap"); m.put("com.google.common.collect.ImmutableList", "ImmutableList"); m.put("com.google.common.collect.ImmutableCollection", "ImmutableList"); - + m.put("com.google.common.collect.ImmutableTable", "ImmutableTable"); + TYPE_TO_GUAVA_TYPE = Collections.unmodifiableMap(m); } - + public static String getGuavaTypeName(String fqn) { String target = TYPE_TO_GUAVA_TYPE.get(fqn); return target != null ? target : "ImmutableList"; } - + private GuavaTypeMap() {} } diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSetListSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSetListSingularizer.java index bc2893bf..e2ca1270 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSetListSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSetListSingularizer.java @@ -1,16 +1,16 @@ /* * 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 @@ -28,15 +28,15 @@ 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"); + "com.google.common.collect.ImmutableCollection", + "com.google.common.collect.ImmutableList", + "com.google.common.collect.ImmutableSet", + "com.google.common.collect.ImmutableSortedSet", + "com.google.common.collect.ImmutableTable"); } @Override protected boolean isMap() { diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java index d1c4d53c..d105dd29 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java @@ -1,16 +1,16 @@ /* * 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 @@ -63,19 +63,22 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { protected static final char[][] JAVA_UTIL_MAP = { {'j', 'a', 'v', 'a'}, {'u', 't', 'i', 'l'}, {'M', 'a', 'p'} }; - + protected static final char[][] GUAVA_COLLECT_TABLE = { + {'c', 'o', 'm'}, {'g', 'o', 'o', 'g', 'l', 'e'}, {'c', 'o', 'm', 'm', 'o', 'n'}, {'c', 'o', 'l', 'l', 'e', 'c', 't'}, {'T', 'a', 'b', 'l', 'e'} + }; + protected String getSimpleTargetTypeName(SingularData data) { return GuavaTypeMap.getGuavaTypeName(data.getTargetFqn()); } - + protected char[] getBuilderMethodName(SingularData data) { String simpleTypeName = getSimpleTargetTypeName(data); 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'}; @@ -86,12 +89,13 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { 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); + String simpleTypeName = getSimpleTargetTypeName(data); + char[][] tokenizedName = makeGuavaTypeName(simpleTypeName, true); TypeReference type = new QualifiedTypeReference(tokenizedName, NULL_POSS); - type = addTypeArgs(isMap() ? 2 : 1, false, builderType, type, data.getTypeArgs()); - + type = addTypeArgs(getTypeArgumentsCount(isMap(), simpleTypeName), false, builderType, type, data.getTypeArgs()); + FieldDeclaration buildField = new FieldDeclaration(data.getPluralName(), 0, -1); buildField.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; buildField.modifiers = ClassFileConstants.AccPrivate; @@ -100,12 +104,12 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { data.setGeneratedByRecursive(buildField); return Collections.singletonList(injectFieldAndMarkGenerated(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); @@ -128,19 +132,19 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { md.returnType = returnType; injectMethod(builderType, md); } - + 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(); @@ -152,11 +156,11 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { thisDotFieldDotAdd.arguments = new Expression[] {new SingleNameReference(keyName, 0L)}; } thisDotFieldDotAdd.receiver = thisDotField; - thisDotFieldDotAdd.selector = (mapMode ? "put" : "add").toCharArray(); + thisDotFieldDotAdd.selector = (shouldUsePut(data, 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); @@ -164,68 +168,87 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { 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); + final Argument param; + + if (isSpecialTypeOfListSet(data)) { + char[][] cellTypeName = makeGuavaTypeName("Table", true); + cellTypeName[5] = new char[] { 'C', 'e', 'l', 'l' }; + TypeReference type = new QualifiedTypeReference(cellTypeName, NULL_POSS); + type = addTypeArgs(3, false, builderType, type, data.getTypeArgs()); + + param = new Argument(keyName, 0, type, 0); + } else { + TypeReference paramType = cloneParamType(0, data.getTypeArgs(), builderType); + 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(); - + md.selector = fluent ? data.getSingularName() : HandlerUtil.buildAccessorName(shouldUsePut(data, 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(); + thisDotFieldDotAddAll.selector = (shouldUsePut(data, 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()); + if (isSpecialTypeOfListSet(data)) { + paramType = new QualifiedTypeReference(GUAVA_COLLECT_TABLE, NULL_POSS); + } else { + paramType = new QualifiedTypeReference(TypeConstants.JAVA_LANG_ITERABLE, NULL_POSS); + } + + paramType = addTypeArgs(getListSetTypeArgumentsCount(getSimpleTargetTypeName(data)), 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(); - + md.selector = fluent ? data.getPluralName() : HandlerUtil.buildAccessorName(shouldUsePut(data, 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()); - + String simpleTypeName = getSimpleTargetTypeName(data); + int agrumentsCount = getTypeArgumentsCount(mapMode, simpleTypeName); + varType = addTypeArgs(agrumentsCount, 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); - emptyInvoke.typeArguments = createTypeArgs(mapMode ? 2 : 1, false, builderType, data.getTypeArgs()); + emptyInvoke.receiver = new QualifiedNameReference(makeGuavaTypeName(simpleTypeName, false), NULL_POSS, 0, 0); + emptyInvoke.typeArguments = createTypeArgs(agrumentsCount, false, builderType, data.getTypeArgs()); } - + MessageSend invokeBuild; { //this.pluralName.build(); invokeBuild = new MessageSend(); @@ -234,32 +257,48 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { 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); } + + private int getTypeArgumentsCount(boolean isMap, String simpleTypeName) { + return isMap ? 2 : getListSetTypeArgumentsCount(simpleTypeName); + } + + private int getListSetTypeArgumentsCount(String simpleTypeName) { + return "ImmutableTable".equals(simpleTypeName) ? 3 : 1; + } + + private boolean shouldUsePut(SingularData data, boolean mapMode) { + return mapMode || isSpecialTypeOfListSet(data); + } + + private boolean isSpecialTypeOfListSet(SingularData data) { + return "ImmutableTable".equals(getSimpleTargetTypeName(data)); + } } diff --git a/src/core/lombok/javac/handlers/singulars/JavacGuavaSetListSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaSetListSingularizer.java index 2e404ca8..fe8e8dc0 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSetListSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSetListSingularizer.java @@ -1,16 +1,16 @@ /* * 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 @@ -21,24 +21,24 @@ */ package lombok.javac.handlers.singulars; +import org.mangosdk.spi.ProviderFor; + import lombok.core.LombokImmutableList; import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; -import org.mangosdk.spi.ProviderFor; - @ProviderFor(JavacSingularizer.class) public class JavacGuavaSetListSingularizer extends JavacGuavaSingularizer { - // 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"); + "com.google.common.collect.ImmutableCollection", + "com.google.common.collect.ImmutableList", + "com.google.common.collect.ImmutableSet", + "com.google.common.collect.ImmutableSortedSet", + "com.google.common.collect.ImmutableTable"); } - + @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 97e5f9be..ba661eff 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java @@ -1,16 +1,16 @@ /* * 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 @@ -51,30 +51,31 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { protected String getSimpleTargetTypeName(SingularData data) { return GuavaTypeMap.getGuavaTypeName(data.getTargetFqn()); } - + protected String getBuilderMethodName(SingularData data) { String simpleTypeName = getSimpleTargetTypeName(data); if ("ImmutableSortedSet".equals(simpleTypeName) || "ImmutableSortedMap".equals(simpleTypeName)) return "naturalOrder"; 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); - + String simpleTypeName = getSimpleTargetTypeName(data); + JCExpression type = JavacHandlerUtil.chainDots(builderType, "com", "google", "common", "collect", simpleTypeName, "Builder"); + type = addTypeArgs(getTypeArgumentsCount(isMap(), simpleTypeName), false, builderType, type, data.getTypeArgs(), source); + JCVariableDecl buildField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), data.getPluralName(), type, null); return Collections.singletonList(injectFieldAndMarkGenerated(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); @@ -99,19 +100,19 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { JCMethodDecl method = maker.MethodDef(mods, methodName, returnType, typeParams, params, thrown, body, null); injectMethod(builderType, method); } - + 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"); + JCExpression thisDotFieldDotAdd = chainDots(builderType, "this", data.getPluralName().toString(), shouldUsePut(data, mapMode) ? "put" : "add"); List<JCExpression> invokeAddExpr; if (mapMode) { invokeAddExpr = List.<JCExpression>of(maker.Ident(keyName), maker.Ident(valueName)); @@ -124,7 +125,7 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { 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())); + if (!fluent) methodName = builderType.toName(HandlerUtil.buildAccessorName(shouldUsePut(data, mapMode) ? "put" : "add", methodName.toString())); List<JCVariableDecl> params; if (mapMode) { JCExpression keyType = cloneParamType(0, maker, data.getTypeArgs(), builderType, source); @@ -133,82 +134,112 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { 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); + final JCExpression paramType; + + if (isSpecialTypeOfListSet(data)) { + JCExpression cellType = JavacHandlerUtil.chainDots(builderType, "com", "google", "common", "collect", "Table", "Cell"); + paramType = addTypeArgs(3, false, builderType, cellType, data.getTypeArgs(), source); + } else { + 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 thisDotFieldDotAddAll = chainDots(builderType, "this", data.getPluralName().toString(), shouldUsePut(data, 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())); + if (!fluent) methodName = builderType.toName(HandlerUtil.buildAccessorName(shouldUsePut(data, mapMode) ? "putAll" : "addAll", methodName.toString())); JCExpression paramType; if (mapMode) { paramType = chainDots(builderType, "java", "util", "Map"); } else { - paramType = genJavaLangTypeRef(builderType, "Iterable"); + if (isSpecialTypeOfListSet(data)) { + paramType = chainDots(builderType, "com", "google", "common", "collect", "Table"); + } else { + paramType = genJavaLangTypeRef(builderType, "Iterable"); + } } - paramType = addTypeArgs(mapMode ? 2 : 1, true, builderType, paramType, data.getTypeArgs(), source); + String simpleTypeName = getSimpleTargetTypeName(data); + paramType = addTypeArgs(getTypeArgumentsCount(mapMode, simpleTypeName), 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(); - + + String simpleTypeName = getSimpleTargetTypeName(data); JCExpression varType = chainDotsString(builderType, data.getTargetFqn()); - varType = addTypeArgs(mapMode ? 2 : 1, false, builderType, varType, data.getTypeArgs(), source); - + int agrumentsCount = getTypeArgumentsCount(mapMode, simpleTypeName); + varType = addTypeArgs(agrumentsCount, false, builderType, varType, data.getTypeArgs(), source); + JCExpression empty; { //ImmutableX.of() JCExpression emptyMethod = chainDots(builderType, "com", "google", "common", "collect", getSimpleTargetTypeName(data), "of"); - List<JCExpression> invokeTypeArgs = createTypeArgs(mapMode ? 2 : 1, false, builderType, data.getTypeArgs(), source); + List<JCExpression> invokeTypeArgs = createTypeArgs(agrumentsCount, false, builderType, data.getTypeArgs(), source); empty = maker.Apply(invokeTypeArgs, 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(); - + JCExpression thisDotField = maker.Select(maker.Ident(builderType.toName("this")), data.getPluralName()); JCExpression thisDotField2 = maker.Select(maker.Ident(builderType.toName("this")), data.getPluralName()); JCExpression cond = maker.Binary(CTC_EQUAL, thisDotField, maker.Literal(CTC_BOT, null)); - + JCExpression create = maker.Apply(jceBlank, chainDots(builderType, "com", "google", "common", "collect", getSimpleTargetTypeName(data), getBuilderMethodName(data)), jceBlank); JCStatement thenPart = maker.Exec(maker.Assign(thisDotField2, create)); - + return maker.If(cond, thenPart, null); } + + private int getTypeArgumentsCount(boolean isMap, String simpleTypeName) { + return isMap ? 2 : getListSetTypeArgumentsCount(simpleTypeName); + } + + private int getListSetTypeArgumentsCount(String simpleTypeName) { + return "ImmutableTable".equals(simpleTypeName) ? 3 : 1; + } + + private boolean shouldUsePut(SingularData data, boolean mapMode) { + return mapMode || isSpecialTypeOfListSet(data); + } + + private boolean isSpecialTypeOfListSet(SingularData data) { + return "ImmutableTable".equals(getSimpleTargetTypeName(data)); + } } diff --git a/test/transform/resource/after-delombok/BuilderSingularGuavaListsSets.java b/test/transform/resource/after-delombok/BuilderSingularGuavaListsSets.java index 3339d809..7f1e7149 100644 --- a/test/transform/resource/after-delombok/BuilderSingularGuavaListsSets.java +++ b/test/transform/resource/after-delombok/BuilderSingularGuavaListsSets.java @@ -2,19 +2,22 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.ImmutableTable; class BuilderSingularGuavaListsSets<T> { private ImmutableList<T> cards; private ImmutableCollection<? extends Number> frogs; @SuppressWarnings("all") private ImmutableSet rawSet; private ImmutableSortedSet<String> passes; + private ImmutableTable<? extends Number, ? extends Number, String> users; @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") - BuilderSingularGuavaListsSets(final ImmutableList<T> cards, final ImmutableCollection<? extends Number> frogs, final ImmutableSet rawSet, final ImmutableSortedSet<String> passes) { + BuilderSingularGuavaListsSets(final ImmutableList<T> cards, final ImmutableCollection<? extends Number> frogs, final ImmutableSet rawSet, final ImmutableSortedSet<String> passes, final ImmutableTable<? extends Number, ? extends Number, String> users) { this.cards = cards; this.frogs = frogs; this.rawSet = rawSet; this.passes = passes; + this.users = users; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") @@ -33,6 +36,9 @@ class BuilderSingularGuavaListsSets<T> { private com.google.common.collect.ImmutableSortedSet.Builder<String> passes; @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + private com.google.common.collect.ImmutableTable.Builder<Number, Number, String> users; + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder() { } @java.lang.SuppressWarnings("all") @@ -113,6 +119,17 @@ class BuilderSingularGuavaListsSets<T> { @javax.annotation.Generated("lombok") public BuilderSingularGuavaListsSetsBuilder<T> clearPasses() { this.passes = null; + } + public BuilderSingularGuavaListsSetsBuilder<T> user(final com.google.common.collect.Table.Cell<Number, Number, String> user) { + if (this.users == null) this.users = com.google.common.collect.ImmutableTable.builder(); + this.users.put(user); + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public BuilderSingularGuavaListsSetsBuilder<T> users(final com.google.common.collect.Table<? extends Number, ? extends Number, ? extends String> users) { + if (this.users == null) this.users = com.google.common.collect.ImmutableTable.builder(); + this.users.putAll(users); return this; } @java.lang.SuppressWarnings("all") @@ -122,13 +139,14 @@ class BuilderSingularGuavaListsSets<T> { com.google.common.collect.ImmutableCollection<Number> frogs = this.frogs == null ? com.google.common.collect.ImmutableList.<Number>of() : this.frogs.build(); com.google.common.collect.ImmutableSet<java.lang.Object> rawSet = this.rawSet == null ? com.google.common.collect.ImmutableSet.<java.lang.Object>of() : this.rawSet.build(); com.google.common.collect.ImmutableSortedSet<String> passes = this.passes == null ? com.google.common.collect.ImmutableSortedSet.<String>of() : this.passes.build(); - return new BuilderSingularGuavaListsSets<T>(cards, frogs, rawSet, passes); + com.google.common.collect.ImmutableTable<Number, Number, String> users = this.users == null ? com.google.common.collect.ImmutableTable.<Number, Number, String>of() : this.users.build(); + return new BuilderSingularGuavaListsSets<T>(cards, frogs, rawSet, passes, users); } @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") public java.lang.String toString() { - return "BuilderSingularGuavaListsSets.BuilderSingularGuavaListsSetsBuilder(cards=" + this.cards + ", frogs=" + this.frogs + ", rawSet=" + this.rawSet + ", passes=" + this.passes + ")"; + return "BuilderSingularGuavaListsSets.BuilderSingularGuavaListsSetsBuilder(cards=" + this.cards + ", frogs=" + this.frogs + ", rawSet=" + this.rawSet + ", passes=" + this.passes + ", users=" + this.users + ")"; } } @java.lang.SuppressWarnings("all") diff --git a/test/transform/resource/after-ecj/BuilderSingularGuavaListsSets.java b/test/transform/resource/after-ecj/BuilderSingularGuavaListsSets.java index 46b37acb..28dc2fac 100644 --- a/test/transform/resource/after-ecj/BuilderSingularGuavaListsSets.java +++ b/test/transform/resource/after-ecj/BuilderSingularGuavaListsSets.java @@ -2,6 +2,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.ImmutableTable; import lombok.Singular; @lombok.Builder class BuilderSingularGuavaListsSets<T> { public static @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") class BuilderSingularGuavaListsSetsBuilder<T> { @@ -9,6 +10,7 @@ import lombok.Singular; private @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") com.google.common.collect.ImmutableList.Builder<Number> frogs; private @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") com.google.common.collect.ImmutableSet.Builder<java.lang.Object> rawSet; private @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") com.google.common.collect.ImmutableSortedSet.Builder<String> passes; + private @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") com.google.common.collect.ImmutableTable.Builder<Number, Number, String> users; @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder() { super(); } @@ -74,6 +76,17 @@ import lombok.Singular; } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder<T> clearPasses() { this.passes = null; + } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder<T> user(com.google.common.collect.Table.Cell<Number, Number, String> user) { + if ((this.users == null)) + this.users = com.google.common.collect.ImmutableTable.builder(); + this.users.put(user); + return this; + } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder<T> users(com.google.common.collect.Table<? extends Number, ? extends Number, ? extends String> users) { + if ((this.users == null)) + this.users = com.google.common.collect.ImmutableTable.builder(); + this.users.putAll(users); return this; } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSets<T> build() { @@ -81,22 +94,25 @@ import lombok.Singular; com.google.common.collect.ImmutableCollection<Number> frogs = ((this.frogs == null) ? com.google.common.collect.ImmutableList.<Number>of() : this.frogs.build()); com.google.common.collect.ImmutableSet<java.lang.Object> rawSet = ((this.rawSet == null) ? com.google.common.collect.ImmutableSet.<java.lang.Object>of() : this.rawSet.build()); com.google.common.collect.ImmutableSortedSet<String> passes = ((this.passes == null) ? com.google.common.collect.ImmutableSortedSet.<String>of() : this.passes.build()); - return new BuilderSingularGuavaListsSets<T>(cards, frogs, rawSet, passes); + com.google.common.collect.ImmutableTable<Number, Number, String> users = ((this.users == null) ? com.google.common.collect.ImmutableTable.<Number, Number, String>of() : this.users.build()); + return new BuilderSingularGuavaListsSets<T>(cards, frogs, rawSet, passes, users); } public @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") java.lang.String toString() { - return (((((((("BuilderSingularGuavaListsSets.BuilderSingularGuavaListsSetsBuilder(cards=" + this.cards) + ", frogs=") + this.frogs) + ", rawSet=") + this.rawSet) + ", passes=") + this.passes) + ")"); + return (((((((((("BuilderSingularGuavaListsSets.BuilderSingularGuavaListsSetsBuilder(cards=" + this.cards) + ", frogs=") + this.frogs) + ", rawSet=") + this.rawSet) + ", passes=") + this.passes) + ", users=") + this.users) + ")"); } } private @Singular ImmutableList<T> cards; private @Singular ImmutableCollection<? extends Number> frogs; private @SuppressWarnings("all") @Singular("rawSet") ImmutableSet rawSet; private @Singular ImmutableSortedSet<String> passes; - @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSets(final ImmutableList<T> cards, final ImmutableCollection<? extends Number> frogs, final ImmutableSet rawSet, final ImmutableSortedSet<String> passes) { + private @Singular ImmutableTable<? extends Number, ? extends Number, String> users; + @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSets(final ImmutableList<T> cards, final ImmutableCollection<? extends Number> frogs, final ImmutableSet rawSet, final ImmutableSortedSet<String> passes, final ImmutableTable<? extends Number, ? extends Number, String> users) { super(); this.cards = cards; this.frogs = frogs; this.rawSet = rawSet; this.passes = passes; + this.users = users; } public static @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") <T>BuilderSingularGuavaListsSetsBuilder<T> builder() { return new BuilderSingularGuavaListsSetsBuilder<T>(); diff --git a/test/transform/resource/before/BuilderSingularGuavaListsSets.java b/test/transform/resource/before/BuilderSingularGuavaListsSets.java index 995c00e8..73e8018c 100644 --- a/test/transform/resource/before/BuilderSingularGuavaListsSets.java +++ b/test/transform/resource/before/BuilderSingularGuavaListsSets.java @@ -2,6 +2,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.ImmutableTable; import lombok.Singular; @@ -11,4 +12,5 @@ class BuilderSingularGuavaListsSets<T> { @Singular private ImmutableCollection<? extends Number> frogs; @SuppressWarnings("all") @Singular("rawSet") private ImmutableSet rawSet; @Singular private ImmutableSortedSet<String> passes; + @Singular private ImmutableTable<? extends Number, ? extends Number, String> users; } diff --git a/website/features/Builder.html b/website/features/Builder.html index 1ebc08ca..88083a27 100644 --- a/website/features/Builder.html +++ b/website/features/Builder.html @@ -102,6 +102,7 @@ <li><code>ImmutableCollection</code> and <code>ImmutableList</code> (backed by the builder feature of <code>ImmutableList</code>).</li> <li><code>ImmutableSet</code> and <code>ImmutableSortedSet</code> (backed by the builder feature of those types).</li> <li><code>ImmutableMap</code>, <code>ImmutableBiMap</code>, and <code>ImmutableSortedMap</code> (backed by the builder feature of those types).</li> + <li><code>ImmutableTable</code> (backed by the builder feature of <code>ImmutableTable</code>).</li> </ul></li> </ul> </p><p> |