diff options
author | Reinier Zwitserloot <reinier@zwitserloot.com> | 2015-11-17 00:01:29 +0100 |
---|---|---|
committer | Reinier Zwitserloot <reinier@zwitserloot.com> | 2015-11-17 00:01:29 +0100 |
commit | 6a003350f61bbebc3a20d8b17b59df6d065ca648 (patch) | |
tree | 8edcdb4fe1fd2b537e725048f8621d0569238ebd /src/core | |
parent | 329202a37f1c4325117fe83eaf22368088254b60 (diff) | |
parent | 22e1fb91d4699a0bacafcd9f74fdca6acd8b275b (diff) | |
download | lombok-6a003350f61bbebc3a20d8b17b59df6d065ca648.tar.gz lombok-6a003350f61bbebc3a20d8b17b59df6d065ca648.tar.bz2 lombok-6a003350f61bbebc3a20d8b17b59df6d065ca648.zip |
Merge branch 'master' of https://github.com/spacanowski/lombok into spacanowski-master
Conflicts:
test/transform/resource/after-delombok/BuilderSingularGuavaListsSets.java
test/transform/resource/after-ecj/BuilderSingularGuavaListsSets.java
Diffstat (limited to 'src/core')
5 files changed, 178 insertions, 107 deletions
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)); + } } |