From 14af3bec3b601d52c6a34710a63e22fceebf8dde Mon Sep 17 00:00:00 2001 From: Enrique da Costa Cambio Date: Tue, 17 Mar 2015 18:13:27 -0700 Subject: Allow @Builder on instance methods --- src/core/lombok/Builder.java | 16 +++--- .../lombok/eclipse/handlers/HandleBuilder.java | 40 +++++++++------ src/core/lombok/experimental/Builder.java | 16 +++--- src/core/lombok/javac/handlers/HandleBuilder.java | 57 ++++++++++++++-------- 4 files changed, 78 insertions(+), 51 deletions(-) (limited to 'src/core') diff --git a/src/core/lombok/Builder.java b/src/core/lombok/Builder.java index 9cbd2d58..c56c4004 100644 --- a/src/core/lombok/Builder.java +++ b/src/core/lombok/Builder.java @@ -31,21 +31,21 @@ import java.lang.annotation.Target; * The builder annotation creates a so-called 'builder' aspect to the class that is annotated or the class * that contains a member which is annotated with {@code @Builder}. *

- * If a member is annotated, it must be either a constructor or a static method. If a class is annotated, + * If a member is annotated, it must be either a constructor or a method. If a class is annotated, * then a private constructor is generated with all fields as arguments * (as if {@code @AllArgsConstructor(AccessLevel.PRIVATE)} is present * on the class), and it is as if this constructor has been annotated with {@code @Builder} instead. *

* The effect of {@code @Builder} is that an inner class is generated named TBuilder, - * with a private constructor. Instances of TBuilder are made with the static + * with a private constructor. Instances of TBuilder are made with the * method named {@code builder()} which is also generated for you in the class itself (not in the builder class). *

* The TBuilder class contains 1 method for each parameter of the annotated - * constructor / static method (each field, when annotating a class), which returns the builder itself. + * constructor / method (each field, when annotating a class), which returns the builder itself. * The builder also has a build() method which returns a completed instance of the original type, * created by passing all parameters as set via the various other methods in the builder to the constructor - * or static method that was annotated with {@code @Builder}. The return type of this method will be the same - * as the relevant class, unless a static method has been annotated, in which case it'll be equal to the + * or method that was annotated with {@code @Builder}. The return type of this method will be the same + * as the relevant class, unless a method has been annotated, in which case it'll be equal to the * return type of that method. *

* Complete documentation is found at the project lombok features page for @Builder. @@ -107,15 +107,15 @@ import java.lang.annotation.Target; @Target({TYPE, METHOD, CONSTRUCTOR}) @Retention(SOURCE) public @interface Builder { - /** Name of the static method that creates a new builder instance. Default: {@code builder}. */ + /** Name of the method that creates a new builder instance. Default: {@code builder}. */ String builderMethodName() default "builder"; - /** Name of the instance method in the builder class that creates an instance of your {@code @Builder}-annotated class. */ + /** Name of the method in the builder class that creates an instance of your {@code @Builder}-annotated class. */ String buildMethodName() default "build"; /** Name of the builder class. * Default for {@code @Builder} on types and constructors: {@code (TypeName)Builder}. - * Default for {@code @Builder} on static methods: {@code (ReturnTypeName)Builder}. + * Default for {@code @Builder} on methods: {@code (ReturnTypeName)Builder}. */ String builderClassName() default ""; } diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index c1b0d8a3..2d4db64f 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -49,6 +49,7 @@ import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.OperatorIds; import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; @@ -138,6 +139,7 @@ public class HandleBuilder extends EclipseAnnotationHandler { EclipseNode fillParametersFrom = parent.get() instanceof AbstractMethodDeclaration ? parent : null; boolean addCleaning = false; + boolean isStatic = true; if (parent.get() instanceof TypeDeclaration) { tdParent = parent; @@ -185,10 +187,7 @@ public class HandleBuilder extends EclipseAnnotationHandler { } else if (parent.get() instanceof MethodDeclaration) { MethodDeclaration md = (MethodDeclaration) parent.get(); tdParent = parent.up(); - if (!md.isStatic()) { - annotationNode.addError("@Builder is only supported on types, constructors, and static methods."); - return; - } + isStatic = md.isStatic(); returnType = copyType(md.returnType, ast); typeParams = md.typeParameters; thrownExceptions = md.thrownExceptions; @@ -223,7 +222,7 @@ public class HandleBuilder extends EclipseAnnotationHandler { builderClassName = new String(token) + "Builder"; } } else { - annotationNode.addError("@Builder is only supported on types, constructors, and static methods."); + annotationNode.addError("@Builder is only supported on types, constructors, and methods."); return; } @@ -241,8 +240,16 @@ public class HandleBuilder extends EclipseAnnotationHandler { EclipseNode builderType = findInnerClass(tdParent, builderClassName); if (builderType == null) { - builderType = makeBuilderClass(tdParent, builderClassName, typeParams, ast); + builderType = makeBuilderClass(isStatic, tdParent, builderClassName, typeParams, ast); } else { + TypeDeclaration builderTypeDeclaration = (TypeDeclaration) builderType.get(); + if (isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) == 0) { + annotationNode.addError("Existing Builder must be a static inner class."); + return; + } else if (!isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) != 0) { + annotationNode.addError("Existing Builder must be a non-static inner class."); + return; + } sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode); /* generate errors for @Singular BFDs that have one already defined node. */ { for (BuilderFieldData bfd : builderFields) { @@ -288,7 +295,7 @@ public class HandleBuilder extends EclipseAnnotationHandler { } if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) { - MethodDeclaration md = generateBuildMethod(buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast); + MethodDeclaration md = generateBuildMethod(isStatic, buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast); if (md != null) injectMethod(builderType, md); } @@ -307,7 +314,7 @@ public class HandleBuilder extends EclipseAnnotationHandler { } if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) { - MethodDeclaration md = generateBuilderMethod(builderMethodName, builderClassName, tdParent, typeParams, ast); + MethodDeclaration md = generateBuilderMethod(isStatic, builderMethodName, builderClassName, tdParent, typeParams, ast); if (md != null) injectMethod(tdParent, md); } } @@ -334,7 +341,7 @@ public class HandleBuilder extends EclipseAnnotationHandler { return decl; } - public MethodDeclaration generateBuildMethod(String name, char[] staticName, TypeReference returnType, List builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source) { + public MethodDeclaration generateBuildMethod(boolean isStatic, String name, char[] staticName, TypeReference returnType, List builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source) { MethodDeclaration out = new MethodDeclaration( ((CompilationUnitDeclaration) type.top().get()).compilationResult); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; @@ -380,7 +387,10 @@ public class HandleBuilder extends EclipseAnnotationHandler { } else { MessageSend invoke = new MessageSend(); invoke.selector = staticName; - invoke.receiver = new SingleNameReference(type.up().getName().toCharArray(), 0); + if (isStatic) + invoke.receiver = new SingleNameReference(type.up().getName().toCharArray(), 0); + else + invoke.receiver = new QualifiedThisReference(new SingleTypeReference(type.up().getName().toCharArray(), 0) , 0, 0); TypeParameter[] tps = ((TypeDeclaration) type.get()).typeParameters; if (tps != null) { TypeReference[] trs = new TypeReference[tps.length]; @@ -401,14 +411,15 @@ public class HandleBuilder extends EclipseAnnotationHandler { return out; } - public MethodDeclaration generateBuilderMethod(String builderMethodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) { + public MethodDeclaration generateBuilderMethod(boolean isStatic, String builderMethodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long) pS << 32 | pE; MethodDeclaration out = new MethodDeclaration( ((CompilationUnitDeclaration) type.top().get()).compilationResult); out.selector = builderMethodName.toCharArray(); - out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic; + out.modifiers = ClassFileConstants.AccPublic; + if (isStatic) out.modifiers |= ClassFileConstants.AccStatic; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.returnType = namePlusTypeParamsToTypeReference(builderClassName.toCharArray(), typeParams, p); out.typeParameters = copyTypeParams(typeParams, source); @@ -490,11 +501,12 @@ public class HandleBuilder extends EclipseAnnotationHandler { return null; } - public EclipseNode makeBuilderClass(EclipseNode tdParent, String builderClassName, TypeParameter[] typeParams, ASTNode source) { + public EclipseNode makeBuilderClass(boolean isStatic, EclipseNode tdParent, String builderClassName, TypeParameter[] typeParams, ASTNode source) { TypeDeclaration parent = (TypeDeclaration) tdParent.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; - builder.modifiers |= ClassFileConstants.AccPublic | ClassFileConstants.AccStatic; + builder.modifiers |= ClassFileConstants.AccPublic; + if (isStatic) builder.modifiers |= ClassFileConstants.AccStatic; builder.typeParameters = copyTypeParams(typeParams, source); builder.name = builderClassName.toCharArray(); builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); diff --git a/src/core/lombok/experimental/Builder.java b/src/core/lombok/experimental/Builder.java index 7d89109f..39f51460 100644 --- a/src/core/lombok/experimental/Builder.java +++ b/src/core/lombok/experimental/Builder.java @@ -31,21 +31,21 @@ import java.lang.annotation.Target; * The builder annotation creates a so-called 'builder' aspect to the class that is annotated or the class * that contains a member which is annotated with {@code @Builder}. *

- * If a member is annotated, it must be either a constructor or a static method. If a class is annotated, + * If a member is annotated, it must be either a constructor or a method. If a class is annotated, * then a private constructor is generated with all fields as arguments * (as if {@code @AllArgsConstructor(AccessLevel.PRIVATE)} is present * on the class), and it is as if this constructor has been annotated with {@code @Builder} instead. *

* The effect of {@code @Builder} is that an inner class is generated named TBuilder, - * with a private constructor. Instances of TBuilder are made with the static + * with a private constructor. Instances of TBuilder are made with the * method named {@code builder()} which is also generated for you in the class itself (not in the builder class). *

* The TBuilder class contains 1 method for each parameter of the annotated - * constructor / static method (each field, when annotating a class), which returns the builder itself. + * constructor / method (each field, when annotating a class), which returns the builder itself. * The builder also has a build() method which returns a completed instance of the original type, * created by passing all parameters as set via the various other methods in the builder to the constructor - * or static method that was annotated with {@code @Builder}. The return type of this method will be the same - * as the relevant class, unless a static method has been annotated, in which case it'll be equal to the + * or method that was annotated with {@code @Builder}. The return type of this method will be the same + * as the relevant class, unless a method has been annotated, in which case it'll be equal to the * return type of that method. *

* Complete documentation is found at the project lombok features page for @Builder. @@ -110,15 +110,15 @@ import java.lang.annotation.Target; @Retention(SOURCE) @Deprecated public @interface Builder { - /** Name of the static method that creates a new builder instance. Default: {@code builder}. */ + /** Name of the method that creates a new builder instance. Default: {@code builder}. */ String builderMethodName() default "builder"; - /** Name of the instance method in the builder class that creates an instance of your {@code @Builder}-annotated class. */ + /** Name of the method in the builder class that creates an instance of your {@code @Builder}-annotated class. */ String buildMethodName() default "build"; /** Name of the builder class. * Default for {@code @Builder} on types and constructors: {@code (TypeName)Builder}. - * Default for {@code @Builder} on static methods: {@code (ReturnTypeName)Builder}. + * Default for {@code @Builder} on methods: {@code (ReturnTypeName)Builder}. */ String builderClassName() default ""; diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 30fec45b..ab833195 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -24,6 +24,8 @@ package lombok.javac.handlers; import java.lang.annotation.Annotation; import java.util.ArrayList; +import javax.lang.model.element.Modifier; + import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.code.Flags; @@ -116,11 +118,12 @@ public class HandleBuilder extends JavacAnnotationHandler { JCExpression returnType; List typeParams = List.nil(); List thrownExceptions = List.nil(); - Name nameOfStaticBuilderMethod; + Name nameOfBuilderMethod; JavacNode tdParent; JavacNode fillParametersFrom = parent.get() instanceof JCMethodDecl ? parent : null; boolean addCleaning = false; + boolean isStatic = true; if (parent.get() instanceof JCClassDecl) { tdParent = parent; @@ -147,7 +150,7 @@ public class HandleBuilder extends JavacAnnotationHandler { returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams); typeParams = td.typarams; thrownExceptions = List.nil(); - nameOfStaticBuilderMethod = null; + nameOfBuilderMethod = null; if (builderClassName.isEmpty()) builderClassName = td.name.toString() + "Builder"; } else if (fillParametersFrom != null && fillParametersFrom.getName().toString().equals("")) { JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get(); @@ -161,20 +164,17 @@ public class HandleBuilder extends JavacAnnotationHandler { returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams); typeParams = td.typarams; thrownExceptions = jmd.thrown; - nameOfStaticBuilderMethod = null; + nameOfBuilderMethod = null; if (builderClassName.isEmpty()) builderClassName = td.name.toString() + "Builder"; } else if (fillParametersFrom != null) { tdParent = parent.up(); JCClassDecl td = (JCClassDecl) tdParent.get(); JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get(); - if ((jmd.mods.flags & Flags.STATIC) == 0) { - annotationNode.addError("@Builder is only supported on types, constructors, and static methods."); - return; - } + isStatic = (jmd.mods.flags & Flags.STATIC) != 0; returnType = jmd.restype; typeParams = jmd.typarams; thrownExceptions = jmd.thrown; - nameOfStaticBuilderMethod = jmd.name; + nameOfBuilderMethod = jmd.name; if (builderClassName.isEmpty()) { if (returnType instanceof JCTypeApply) { returnType = ((JCTypeApply) returnType).clazz; @@ -204,7 +204,7 @@ public class HandleBuilder extends JavacAnnotationHandler { } } } else { - annotationNode.addError("@Builder is only supported on types, constructors, and static methods."); + annotationNode.addError("@Builder is only supported on types, constructors, and methods."); return; } @@ -222,8 +222,16 @@ public class HandleBuilder extends JavacAnnotationHandler { JavacNode builderType = findInnerClass(tdParent, builderClassName); if (builderType == null) { - builderType = makeBuilderClass(tdParent, builderClassName, typeParams, ast); + builderType = makeBuilderClass(isStatic, tdParent, builderClassName, typeParams, ast); } else { + JCClassDecl builderTypeDeclaration = (JCClassDecl) builderType.get(); + if (isStatic && !builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)) { + annotationNode.addError("Existing Builder must be a static inner class."); + return; + } else if (!isStatic && builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)) { + annotationNode.addError("Existing Builder must be a non-static inner class."); + return; + } sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode); /* generate errors for @Singular BFDs that have one already defined node. */ { for (BuilderFieldData bfd : builderFields) { @@ -265,7 +273,7 @@ public class HandleBuilder extends JavacAnnotationHandler { } if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl md = generateBuildMethod(buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, ast, addCleaning); + JCMethodDecl md = generateBuildMethod(isStatic, buildMethodName, nameOfBuilderMethod, returnType, builderFields, builderType, thrownExceptions, ast, addCleaning); if (md != null) injectMethod(builderType, md); } @@ -281,7 +289,7 @@ public class HandleBuilder extends JavacAnnotationHandler { if (addCleaning) injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast)); if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl md = generateBuilderMethod(builderMethodName, builderClassName, tdParent, typeParams); + JCMethodDecl md = generateBuilderMethod(isStatic, builderMethodName, builderClassName, tdParent, typeParams); recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); if (md != null) injectMethod(tdParent, md); } @@ -316,7 +324,7 @@ public class HandleBuilder extends JavacAnnotationHandler { */ } - private JCMethodDecl generateBuildMethod(String name, Name staticName, JCExpression returnType, java.util.List builderFields, JavacNode type, List thrownExceptions, JCTree source, boolean addCleaning) { + private JCMethodDecl generateBuildMethod(boolean isStatic, String buildName, Name builderName, JCExpression returnType, java.util.List builderFields, JavacNode type, List thrownExceptions, JCTree source, boolean addCleaning) { JavacTreeMaker maker = type.getTreeMaker(); JCExpression call; @@ -344,16 +352,19 @@ public class HandleBuilder extends JavacAnnotationHandler { statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, true)))); } - if (staticName == null) { + if (builderName == null) { call = maker.NewClass(null, List.nil(), returnType, args.toList(), null); statements.append(maker.Return(call)); } else { + ListBuffer typeParams = new ListBuffer(); for (JCTypeParameter tp : ((JCClassDecl) type.get()).typarams) { typeParams.append(maker.Ident(tp.name)); } - - JCExpression fn = maker.Select(maker.Ident(((JCClassDecl) type.up().get()).name), staticName); + JCExpression callee = maker.Ident(((JCClassDecl) type.up().get()).name); + if (!isStatic) + callee = maker.Select(callee, type.up().toName("this")); + JCExpression fn = maker.Select(callee, builderName); call = maker.Apply(typeParams.toList(), fn, args.toList()); if (returnType instanceof JCPrimitiveTypeTree && CTC_VOID.equals(typeTag(returnType))) { statements.append(maker.Exec(call)); @@ -364,10 +375,10 @@ public class HandleBuilder extends JavacAnnotationHandler { JCBlock body = maker.Block(0, statements.toList()); - return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName(name), returnType, List.nil(), List.nil(), thrownExceptions, body, null); + return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName(buildName), returnType, List.nil(), List.nil(), thrownExceptions, body, null); } - public JCMethodDecl generateBuilderMethod(String builderMethodName, String builderClassName, JavacNode type, List typeParams) { + public JCMethodDecl generateBuilderMethod(boolean isStatic, String builderMethodName, String builderClassName, JavacNode type, List typeParams) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer typeArgs = new ListBuffer(); @@ -379,7 +390,9 @@ public class HandleBuilder extends JavacAnnotationHandler { JCStatement statement = maker.Return(call); JCBlock body = maker.Block(0, List.of(statement)); - return maker.MethodDef(maker.Modifiers(Flags.STATIC | Flags.PUBLIC), type.toName(builderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), copyTypeParams(maker, typeParams), List.nil(), List.nil(), body, null); + int modifiers = Flags.PUBLIC; + if (isStatic) modifiers |= Flags.STATIC; + return maker.MethodDef(maker.Modifiers(modifiers), type.toName(builderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), copyTypeParams(maker, typeParams), List.nil(), List.nil(), body, null); } public void generateBuilderFields(JavacNode builderType, java.util.List builderFields, JCTree source) { @@ -443,9 +456,11 @@ public class HandleBuilder extends JavacAnnotationHandler { return null; } - public JavacNode makeBuilderClass(JavacNode tdParent, String builderClassName, List typeParams, JCAnnotation ast) { + public JavacNode makeBuilderClass(boolean isStatic, JavacNode tdParent, String builderClassName, List typeParams, JCAnnotation ast) { JavacTreeMaker maker = tdParent.getTreeMaker(); - JCModifiers mods = maker.Modifiers(Flags.PUBLIC | Flags.STATIC); + int modifiers = Flags.PUBLIC; + if (isStatic) modifiers |= Flags.STATIC; + JCModifiers mods = maker.Modifiers(modifiers); JCClassDecl builder = maker.ClassDef(mods, tdParent.toName(builderClassName), copyTypeParams(maker, typeParams), null, List.nil(), List.nil()); return injectType(tdParent, builder); } -- cgit From db8281f7f5c027c24cf9a1a8208a2aa92d06a73d Mon Sep 17 00:00:00 2001 From: spc Date: Sun, 4 Oct 2015 09:23:28 +0200 Subject: Added support for builder singular for Guavas ImmutableTable --- src/core/lombok/core/GuavaTypeMap.java | 17 +-- .../singulars/EclipseGuavaSetListSingularizer.java | 16 +-- .../singulars/EclipseGuavaSingularizer.java | 139 +++++++++++++-------- .../singulars/JavacGuavaSetListSingularizer.java | 22 ++-- .../handlers/singulars/JavacGuavaSingularizer.java | 119 +++++++++++------- 5 files changed, 192 insertions(+), 121 deletions(-) (limited to 'src/core') 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 TYPE_TO_GUAVA_TYPE; static { Map m = new HashMap(); - + 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 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 fa121328..c3a4c314 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 @@ -28,12 +28,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import lombok.core.GuavaTypeMap; -import lombok.core.handlers.HandlerUtil; -import lombok.eclipse.EclipseNode; -import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; -import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; - import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.Assignment; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; @@ -59,23 +53,32 @@ 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 lombok.core.GuavaTypeMap; +import lombok.core.handlers.HandlerUtil; +import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; +import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; + 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 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(getTypeAgrumentsCount(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,29 +104,29 @@ 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); } - + 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 statements = new ArrayList(); statements.add(createConstructBuilderVarIfNeeded(data, builderType)); - + FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L); thisDotField.receiver = new ThisReference(0, 0); MessageSend thisDotFieldDotAdd = new MessageSend(); @@ -134,11 +138,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); @@ -146,68 +150,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 statements = new ArrayList(); 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 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 = getTypeAgrumentsCount(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(); @@ -216,32 +239,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 getTypeAgrumentsCount(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 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 41e379f6..399f2239 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 @@ -26,14 +26,6 @@ import static lombok.javac.handlers.JavacHandlerUtil.*; import java.util.Collections; -import lombok.core.GuavaTypeMap; -import lombok.core.handlers.HandlerUtil; -import lombok.javac.JavacNode; -import lombok.javac.JavacTreeMaker; -import lombok.javac.handlers.JavacHandlerUtil; -import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; -import lombok.javac.handlers.JavacSingularsRecipes.SingularData; - import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCBlock; @@ -47,51 +39,60 @@ import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; +import lombok.core.GuavaTypeMap; +import lombok.core.handlers.HandlerUtil; +import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; +import lombok.javac.handlers.JavacHandlerUtil; +import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer; +import lombok.javac.handlers.JavacSingularsRecipes.SingularData; + 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 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(getTypeAgrumentsCount(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); } - + void generateSingularMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent) { List typeParams = List.nil(); List 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 statements = new ListBuffer(); 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 invokeAddExpr; if (mapMode) { invokeAddExpr = List.of(maker.Ident(keyName), maker.Ident(valueName)); @@ -104,7 +105,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 params; if (mapMode) { JCExpression keyType = cloneParamType(0, maker, data.getTypeArgs(), builderType, source); @@ -113,82 +114,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 typeParams = List.nil(); List thrown = List.nil(); boolean mapMode = isMap(); - + JCModifiers mods = maker.Modifiers(Flags.PUBLIC); ListBuffer statements = new ListBuffer(); 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.nil(), thisDotFieldDotAddAll, List.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(getTypeAgrumentsCount(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 statements, Name targetVariableName) { JavacTreeMaker maker = builderType.getTreeMaker(); List 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 = getTypeAgrumentsCount(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 invokeTypeArgs = createTypeArgs(mapMode ? 2 : 1, false, builderType, data.getTypeArgs(), source); + List 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 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 getTypeAgrumentsCount(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)); + } } -- cgit From 22e1fb91d4699a0bacafcd9f74fdca6acd8b275b Mon Sep 17 00:00:00 2001 From: spc Date: Thu, 8 Oct 2015 17:23:42 +0200 Subject: Fixed typo, moved imports --- .../singulars/EclipseGuavaSingularizer.java | 18 ++++++++-------- .../handlers/singulars/JavacGuavaSingularizer.java | 24 +++++++++++----------- 2 files changed, 21 insertions(+), 21 deletions(-) (limited to 'src/core') diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java index c3a4c314..5a85bfa5 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java @@ -28,6 +28,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import lombok.core.GuavaTypeMap; +import lombok.core.handlers.HandlerUtil; +import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; +import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; + import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.Assignment; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; @@ -53,12 +59,6 @@ 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 lombok.core.GuavaTypeMap; -import lombok.core.handlers.HandlerUtil; -import lombok.eclipse.EclipseNode; -import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; -import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; - abstract class EclipseGuavaSingularizer extends EclipseSingularizer { protected static final char[][] JAVA_UTIL_MAP = { {'j', 'a', 'v', 'a'}, {'u', 't', 'i', 'l'}, {'M', 'a', 'p'} @@ -94,7 +94,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { String simpleTypeName = getSimpleTargetTypeName(data); char[][] tokenizedName = makeGuavaTypeName(simpleTypeName, true); TypeReference type = new QualifiedTypeReference(tokenizedName, NULL_POSS); - type = addTypeArgs(getTypeAgrumentsCount(isMap(), simpleTypeName), 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; @@ -220,7 +220,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { boolean mapMode = isMap(); TypeReference varType = new QualifiedTypeReference(fromQualifiedName(data.getTargetFqn()), NULL_POSS); String simpleTypeName = getSimpleTargetTypeName(data); - int agrumentsCount = getTypeAgrumentsCount(mapMode, simpleTypeName); + int agrumentsCount = getTypeArgumentsCount(mapMode, simpleTypeName); varType = addTypeArgs(agrumentsCount, false, builderType, varType, data.getTypeArgs()); MessageSend emptyInvoke; { @@ -268,7 +268,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { return new IfStatement(cond, new Assignment(thisDotField2, createBuilderInvoke, 0), 0, 0); } - private int getTypeAgrumentsCount(boolean isMap, String simpleTypeName) { + private int getTypeArgumentsCount(boolean isMap, String simpleTypeName) { return isMap ? 2 : getListSetTypeArgumentsCount(simpleTypeName); } diff --git a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java index 399f2239..1bf47e6e 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java @@ -26,6 +26,14 @@ import static lombok.javac.han