diff options
105 files changed, 2726 insertions, 2025 deletions
@@ -3,6 +3,7 @@ Lombok contributors in alphabetical order: Christian Sterzl <christian.sterzl@gmail.com> DaveLaw <project.lombok@apconsult.de> Dawid Rusin <dawidrusin90@gmail.com> +Enrique da Costa Cambio <enrique.dacostacambio@gmail.com> Jappe van der Hel <jappe.vanderhel@gmail.com> Luan Nico <luannico27@gmail.com> Maarten Mulders <mthmulders@users.noreply.github.com> @@ -14,5 +15,6 @@ Roel Spilker <r.spilker@gmail.com> Sander Koning <askoning@gmail.com> Szymon Pacanowski <spacanowski@gmail.com> Taiki Sugawara <buzz.taiki@gmail.com> +Yun Zhi Lin <yun@yunspace.com> By adding your name to this list, you grant full and irrevocable copyright and patent indemnity to Project Lombok and all use of Project Lombok, and you certify that you have the right to do so for all commits you add to Project Lombok. diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 0746459e..c4a353d7 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -2,7 +2,12 @@ Lombok Changelog ---------------- ### v1.16.7 "Edgy Guinea Pig" +* FEATURE: `@Builder` updates: It now generates `clearFieldName()` methods if `@Singular` is used. [Issue #967](https://github.com/rzwitserloot/lombok/issues/967). +* FEATURE: `@Builder` updates: The annotation can now be put on instance methods. [Issue #63](https://github.com/rzwitserloot/lombok/issues/63). +* FEATURE: A `lombok.config` key can now be used to make your fields `final` and/or `private`... __everywhere__. We'll be monitoring the performance impact of this for a while. We'll touch every source file if you turn these on, and even if you don't, we have to call into the lombok config system for every file. * BUGFIX: `@Value` and `@FieldDefaults` no longer make uninitialized static fields final. [Issue #928](https://github.com/rzwitserloot/lombok/issues/928). +* BUGFIX: When using delombok, a source file with only `@NonNull` annotations on parameters as lombok feature would not get properly delomboked. [Issue #950](https://github.com/rzwitserloot/lombok/issues/950). +* ENHANCEMENT: Putting `@NonNull` on a parameter of an abstract method no longer generates a warning, to allow you to use this annotation to document intended behaviour [Issue #807](https://github.com/rzwitserloot/lombok/issues/807). ### v1.16.6 (August 18th, 2015) * FEATURE: `@Helper` can be placed on method-local inner classes to make all methods in the class accessible to the rest of the method. [Full documentation](https://projectlombok.org/features/experimental/Helper.html). diff --git a/src/core/lombok/Builder.java b/src/core/lombok/Builder.java index 0639c4cb..6a92028c 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}. * <p> - * 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. * <p> * The effect of {@code @Builder} is that an inner class is generated named <code><strong>T</strong>Builder</code>, - * with a private constructor. Instances of <code><strong>T</strong>Builder</code> are made with the static + * with a private constructor. Instances of <code><strong>T</strong>Builder</code> are made with the * method named {@code builder()} which is also generated for you in the class itself (not in the builder class). * <p> * The <code><strong>T</strong>Builder</code> 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 <code>build()</code> 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. * <p> * Complete documentation is found at <a href="https://projectlombok.org/features/experimental/Builder.html">the project lombok features page for @Builder</a>. @@ -107,10 +107,10 @@ 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"; /** @@ -118,7 +118,7 @@ public @interface Builder { * * Default for {@code @Builder} on types and constructors: {@code (TypeName)Builder}. * <p> - * 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/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 67d51895..dd6732ed 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -396,6 +396,20 @@ public class ConfigurationKeys { // ----- FieldDefaults ----- /** + * lombok configuration: {@code lombok.fieldDefaults.defaultPrivate} = {@code true} | {@code false}. + * + * If set to <code>true</code> <em>any</em> field without an access modifier or {@code @PackagePrivate} is marked as {@code private} by lombok, in all source files compiled. + */ + public static final ConfigurationKey<Boolean> FIELD_DEFAULTS_PRIVATE_EVERYWHERE = new ConfigurationKey<Boolean>("lombok.fieldDefaults.defaultPrivate", "If true, fields without any access modifier, in any file (lombok annotated or not) are marked as private. Use @PackagePrivate or an explicit modifier to override this.") {}; + + /** + * lombok configuration: {@code lombok.fieldDefaults.defaultFinal} = {@code true} | {@code false}. + * + * If set to <code>true</code> <em>any</em> field without {@code @NonFinal} is marked as {@code final} by lombok, in all source files compiled. + */ + public static final ConfigurationKey<Boolean> FIELD_DEFAULTS_FINAL_EVERYWHERE = new ConfigurationKey<Boolean>("lombok.fieldDefaults.defaultFinal", "If true, fields, in any file (lombok annotated or not) are marked as final. Use @NonFinal to override this.") {}; + + /** * lombok configuration: {@code lombok.fieldDefaults.flagUsage} = {@code WARNING} | {@code ERROR}. * * If set, <em>any</em> usage of {@code @FieldDefaults} results in a warning / error. diff --git a/src/core/lombok/Value.java b/src/core/lombok/Value.java index 389d2b36..2cecea63 100644 --- a/src/core/lombok/Value.java +++ b/src/core/lombok/Value.java @@ -29,13 +29,13 @@ import java.lang.annotation.Target; /** * Generates a lot of code which fits with a class that is a representation of an immutable entity. * <p> - * Equivalent to {@code @Getter @FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE) @RequiredArgsConstructor @ToString @EqualsAndHashCode}. + * Equivalent to {@code @Getter @FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE) @AllArgsConstructor @ToString @EqualsAndHashCode}. * <p> * Complete documentation is found at <a href="https://projectlombok.org/features/experimental/Value.html">the project lombok features page for @Value</a>. * * @see lombok.Getter * @see lombok.experimental.FieldDefaults - * @see lombok.RequiredArgsConstructor + * @see lombok.AllArgsConstructor * @see lombok.ToString * @see lombok.EqualsAndHashCode * @see lombok.Data diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index ef06e249..be14653a 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; @@ -163,6 +164,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { EclipseNode fillParametersFrom = parent.get() instanceof AbstractMethodDeclaration ? parent : null; boolean addCleaning = false; + boolean isStatic = true; if (parent.get() instanceof TypeDeclaration) { tdParent = parent; @@ -212,11 +214,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } 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(); + if (toBuilder) { final String TO_BUILDER_NOT_SUPPORTED = "@Builder(toBuilder=true) is only supported if you return your own type."; char[] token; @@ -322,7 +321,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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; } @@ -342,8 +341,16 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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) { @@ -398,7 +405,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } 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); } @@ -417,7 +424,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } 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); } @@ -507,7 +514,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return decl; } - public MethodDeclaration generateBuildMethod(String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> builderFields, EclipseNode type, TypeReference[] thrownExceptions, boolean addCleaning, ASTNode source) { + public MethodDeclaration generateBuildMethod(boolean isStatic, String name, char[] staticName, TypeReference returnType, List<BuilderFieldData> 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; List<Statement> statements = new ArrayList<Statement>(); @@ -552,7 +559,10 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } 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]; @@ -573,13 +583,14 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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); @@ -661,11 +672,12 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { 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/eclipse/handlers/HandleFieldDefaults.java b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java index 33e796b7..5ea5a210 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldDefaults.java @@ -23,12 +23,17 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.*; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import java.util.Arrays; + import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; -import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.Eclipse; +import lombok.eclipse.EclipseASTAdapter; +import lombok.eclipse.EclipseASTVisitor; import lombok.eclipse.EclipseNode; import lombok.experimental.FieldDefaults; import lombok.experimental.NonFinal; @@ -37,16 +42,19 @@ import lombok.experimental.PackagePrivate; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.mangosdk.spi.ProviderFor; /** * Handles the {@code lombok.FieldDefaults} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) +@ProviderFor(EclipseASTVisitor.class) @HandlerPriority(-2048) //-2^11; to ensure @Value picks up on messing with the fields' 'final' state, run earlier. -public class HandleFieldDefaults extends EclipseAnnotationHandler<FieldDefaults> { +public class HandleFieldDefaults extends EclipseASTAdapter { public boolean generateFieldDefaultsForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean makeFinal, boolean checkForTypeLevelFieldDefaults) { if (checkForTypeLevelFieldDefaults) { if (hasAnnotation(FieldDefaults.class, typeNode)) { @@ -105,29 +113,60 @@ public class HandleFieldDefaults extends EclipseAnnotationHandler<FieldDefaults> fieldNode.rebuild(); } - public void handle(AnnotationValues<FieldDefaults> annotation, Annotation ast, EclipseNode annotationNode) { - handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults"); - - EclipseNode node = annotationNode.up(); - FieldDefaults instance = annotation.getInstance(); - AccessLevel level = instance.level(); - boolean makeFinal = instance.makeFinal(); + private static final char[] FIELD_DEFAULTS = "FieldDefaults".toCharArray(); + + @Override public void visitType(EclipseNode typeNode, TypeDeclaration type) { + AnnotationValues<FieldDefaults> fieldDefaults = null; + EclipseNode source = typeNode; - if (level == AccessLevel.NONE && !makeFinal) { - annotationNode.addError("This does nothing; provide either level or makeFinal or both."); - return; + boolean levelIsExplicit = false; + boolean makeFinalIsExplicit = false; + FieldDefaults fd = null; + for (EclipseNode jn : typeNode.down()) { + if (jn.getKind() != Kind.ANNOTATION) continue; + Annotation ann = (Annotation) jn.get(); + TypeReference typeTree = ann.type; + if (typeTree == null) continue; + if (typeTree instanceof SingleTypeReference) { + char[] t = ((SingleTypeReference) typeTree).token; + if (!Arrays.equals(t, FIELD_DEFAULTS)) continue; + } else if (typeTree instanceof QualifiedTypeReference) { + char[][] t = ((QualifiedTypeReference) typeTree).tokens; + if (!Eclipse.nameEquals(t, "lombok.experimental.FieldDefaults")) continue; + } else { + continue; + } + + if (!typeMatches(FieldDefaults.class, jn, typeTree)) continue; + + source = jn; + fieldDefaults = createAnnotation(FieldDefaults.class, jn); + levelIsExplicit = fieldDefaults.isExplicit("level"); + makeFinalIsExplicit = fieldDefaults.isExplicit("makeFinal"); + + handleExperimentalFlagUsage(jn, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults"); + + fd = fieldDefaults.getInstance(); + if (!levelIsExplicit && !makeFinalIsExplicit) { + jn.addError("This does nothing; provide either level or makeFinal or both."); + } + + if (levelIsExplicit && fd.level() == AccessLevel.NONE) { + jn.addError("AccessLevel.NONE doesn't mean anything here. Pick another value."); + levelIsExplicit = false; + } + break; } - if (level == AccessLevel.PACKAGE) { - annotationNode.addError("Setting 'level' to PACKAGE does nothing. To force fields as package private, use the @PackagePrivate annotation on the field."); - } + if (fd == null && (type.modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0) return; - if (!makeFinal && annotation.isExplicit("makeFinal")) { - annotationNode.addError("Setting 'makeFinal' to false does nothing. To force fields to be non-final, use the @NonFinal annotation on the field."); - } + boolean defaultToPrivate = levelIsExplicit ? false : Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_PRIVATE_EVERYWHERE)); + boolean defaultToFinal = makeFinalIsExplicit ? false : Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_FINAL_EVERYWHERE)); - if (node == null) return; + if (!defaultToPrivate && !defaultToFinal && fieldDefaults == null) return; + AccessLevel fdAccessLevel = (fieldDefaults != null && levelIsExplicit) ? fd.level() : defaultToPrivate ? AccessLevel.PRIVATE : null; + boolean fdToFinal = (fieldDefaults != null && makeFinalIsExplicit) ? fd.makeFinal() : defaultToFinal; - generateFieldDefaultsForType(node, annotationNode, level, makeFinal, false); + generateFieldDefaultsForType(typeNode, source, fdAccessLevel, fdToFinal, false); } } diff --git a/src/core/lombok/eclipse/handlers/HandleNonNull.java b/src/core/lombok/eclipse/handlers/HandleNonNull.java index d904de2f..d09993ed 100644 --- a/src/core/lombok/eclipse/handlers/HandleNonNull.java +++ b/src/core/lombok/eclipse/handlers/HandleNonNull.java @@ -91,7 +91,7 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { if (isGenerated(declaration)) return; if (declaration.isAbstract()) { - annotationNode.addWarning("@NonNull is meaningless on a parameter of an abstract method."); + // This used to be a warning, but as @NonNull also has a documentary purpose, better to not warn about this. Since 1.16.7 return; } diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java index 5a85bfa5..d105dd29 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java @@ -113,6 +113,24 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { 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); + + returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); + returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; + generateClearMethod(returnType, returnStatement, data, builderType); + } + + void generateClearMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType) { + MethodDeclaration md = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); + md.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; + md.modifiers = ClassFileConstants.AccPublic; + + FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L); + thisDotField.receiver = new ThisReference(0, 0); + Assignment a = new Assignment(thisDotField, new NullLiteral(0, 0), 0); + md.selector = HandlerUtil.buildAccessorName("clear", new String(data.getPluralName())).toCharArray(); + md.statements = returnStatement != null ? new Statement[] {a, returnStatement} : new Statement[] {a}; + md.returnType = returnType; + injectMethod(builderType, md); } void generateSingularMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) { diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java index 4b59f7a8..2d8083d3 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java @@ -34,11 +34,15 @@ import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldReference; +import org.eclipse.jdt.internal.compiler.ast.IfStatement; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.NullLiteral; +import org.eclipse.jdt.internal.compiler.ast.OperatorIds; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; @@ -96,6 +100,29 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula 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); + + returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); + returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; + generateClearMethod(returnType, returnStatement, data, builderType); + } + + private void generateClearMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType) { + MethodDeclaration md = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); + md.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; + md.modifiers = ClassFileConstants.AccPublic; + + 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); + md.selector = HandlerUtil.buildAccessorName("clear", new String(data.getPluralName())).toCharArray(); + MessageSend clearMsg = new MessageSend(); + clearMsg.receiver = thisDotField2; + clearMsg.selector = "clear".toCharArray(); + Statement clearStatement = new IfStatement(new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.NOT_EQUAL), clearMsg, 0, 0); + md.statements = returnStatement != null ? new Statement[] {clearStatement, returnStatement} : new Statement[] {clearStatement}; + md.returnType = returnType; + injectMethod(builderType, md); } void generateSingularMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) { diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java index 1c6b1ff3..ef9e2a76 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java @@ -32,13 +32,17 @@ import java.util.List; import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.Block; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldReference; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; +import org.eclipse.jdt.internal.compiler.ast.IfStatement; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.NullLiteral; +import org.eclipse.jdt.internal.compiler.ast.OperatorIds; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; @@ -141,6 +145,40 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer 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); + + returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); + returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; + generateClearMethod(returnType, returnStatement, data, builderType); + } + + private void generateClearMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType) { + MethodDeclaration md = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult); + md.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; + md.modifiers = ClassFileConstants.AccPublic; + + String pN = new String(data.getPluralName()); + char[] keyFieldName = (pN + "$key").toCharArray(); + char[] valueFieldName = (pN + "$value").toCharArray(); + + FieldReference thisDotField = new FieldReference(keyFieldName, 0L); + thisDotField.receiver = new ThisReference(0, 0); + FieldReference thisDotField2 = new FieldReference(keyFieldName, 0L); + thisDotField2.receiver = new ThisReference(0, 0); + FieldReference thisDotField3 = new FieldReference(valueFieldName, 0L); + thisDotField3.receiver = new ThisReference(0, 0); + md.selector = HandlerUtil.buildAccessorName("clear", new String(data.getPluralName())).toCharArray(); + MessageSend clearMsg1 = new MessageSend(); + clearMsg1.receiver = thisDotField2; + clearMsg1.selector = "clear".toCharArray(); + MessageSend clearMsg2 = new MessageSend(); + clearMsg2.receiver = thisDotField3; + clearMsg2.selector = "clear".toCharArray(); + Block clearMsgs = new Block(2); + clearMsgs.statements = new Statement[] {clearMsg1, clearMsg2}; + Statement clearStatement = new IfStatement(new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.NOT_EQUAL), clearMsgs, 0, 0); + md.statements = returnStatement != null ? new Statement[] {clearStatement, returnStatement} : new Statement[] {clearStatement}; + md.returnType = returnType; + injectMethod(builderType, md); } private void generateSingularMethod(TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType, boolean fluent) { diff --git a/src/core/lombok/experimental/Builder.java b/src/core/lombok/experimental/Builder.java index 68250ffd..4d5e0f67 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}. * <p> - * 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. * <p> * The effect of {@code @Builder} is that an inner class is generated named <code><strong>T</strong>Builder</code>, - * with a private constructor. Instances of <code><strong>T</strong>Builder</code> are made with the static + * with a private constructor. Instances of <code><strong>T</strong>Builder</code> are made with the * method named {@code builder()} which is also generated for you in the class itself (not in the builder class). * <p> * The <code><strong>T</strong>Builder</code> 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 <code>build()</code> 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. * <p> * Complete documentation is found at <a href="https://projectlombok.org/features/experimental/Builder.html">the project lombok features page for @Builder</a>. @@ -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 f0139b47..efe40da3 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; @@ -124,11 +126,12 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { JCExpression returnType; List<JCTypeParameter> typeParams = List.nil(); List<JCExpression> 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; @@ -157,7 +160,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { 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("<init>")) { JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get(); @@ -171,21 +174,18 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { 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; JCExpression fullReturnType = jmd.restype; returnType = fullReturnType; typeParams = jmd.typarams; thrownExceptions = jmd.thrown; - nameOfStaticBuilderMethod = jmd.name; + nameOfBuilderMethod = jmd.name; if (returnType instanceof JCTypeApply) { returnType = ((JCTypeApply) returnType).clazz; } @@ -278,7 +278,7 @@ public class HandleBuilder extends JavacAnnotationHandler<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; } @@ -298,8 +298,16 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { 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) { @@ -351,7 +359,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } 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); } @@ -367,7 +375,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { 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); } @@ -488,7 +496,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { */ } - private JCMethodDecl generateBuildMethod(String name, Name staticName, JCExpression returnType, java.util.List<BuilderFieldData> builderFields, JavacNode type, List<JCExpression> thrownExceptions, JCTree source, boolean addCleaning) { + private JCMethodDecl generateBuildMethod(boolean isStatic, String buildName, Name builderName, JCExpression returnType, java.util.List<BuilderFieldData> builderFields, JavacNode type, List<JCExpression> thrownExceptions, JCTree source, boolean addCleaning) { JavacTreeMaker maker = type.getTreeMaker(); JCExpression call; @@ -516,16 +524,19 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { 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.<JCExpression>nil(), returnType, args.toList(), null); statements.append(maker.Return(call)); } else { + ListBuffer<JCExpression> typeParams = new ListBuffer<JCExpression>(); 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)); @@ -536,10 +547,10 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { JCBlock body = maker.Block(0, statements.toList()); - return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName(name), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), thrownExceptions, body, null); + return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName(buildName), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), thrownExceptions, body, null); } - public JCMethodDecl generateBuilderMethod(String builderMethodName, String builderClassName, JavacNode type, List<JCTypeParameter> typeParams) { + public JCMethodDecl generateBuilderMethod(boolean isStatic, String builderMethodName, String builderClassName, JavacNode type, List<JCTypeParameter> typeParams) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); @@ -551,7 +562,9 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { JCStatement statement = maker.Return(call); JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); - return maker.MethodDef(maker.Modifiers(Flags.STATIC | Flags.PUBLIC), type.toName(builderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), copyTypeParams(maker, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>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.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); } public void generateBuilderFields(JavacNode builderType, java.util.List<BuilderFieldData> builderFields, JCTree source) { @@ -615,9 +628,11 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { return null; } - public JavacNode makeBuilderClass(JavacNode tdParent, String builderClassName, List<JCTypeParameter> typeParams, JCAnnotation ast) { + public JavacNode makeBuilderClass(boolean isStatic, JavacNode tdParent, String builderClassName, List<JCTypeParameter> 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.<JCExpression>nil(), List.<JCTree>nil()); return injectType(tdParent, builder); } diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index b8afce8e..4bc79f03 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -262,8 +262,8 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas switch (((JCPrimitiveTypeTree) fType).getPrimitiveTypeKind()) { case BOOLEAN: /* this.fieldName ? X : Y */ - statements.append(createResultCalculation(typeNode, maker.Conditional(fieldAccessor, - maker.Literal(HandlerUtil.primeForTrue()), maker.Literal(HandlerUtil.primeForFalse())))); + statements.append(createResultCalculation(typeNode, maker.Parens(maker.Conditional(fieldAccessor, + maker.Literal(HandlerUtil.primeForTrue()), maker.Literal(HandlerUtil.primeForFalse()))))); break; case LONG: { Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name); @@ -308,7 +308,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas statements.append(createResultCalculation(typeNode, maker.Apply(List.<JCExpression>nil(), hcMethod, List.of(fieldAccessor)))); } else /* objects */ { /* final java.lang.Object $fieldName = this.fieldName; */ - /* $fieldName == null ? NULL_PRIME : $fieldName.hashCode() */ + /* ($fieldName == null ? NULL_PRIME : $fieldName.hashCode()) */ Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name); statements.append(maker.VarDef(maker.Modifiers(finalFlag), dollarFieldName, genJavaLangTypeRef(typeNode, "Object"), fieldAccessor)); @@ -316,7 +316,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas JCExpression hcCall = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(dollarFieldName), typeNode.toName("hashCode")), List.<JCExpression>nil()); JCExpression thisEqualsNull = maker.Binary(CTC_EQUAL, maker.Ident(dollarFieldName), maker.Literal(CTC_BOT, null)); - statements.append(createResultCalculation(typeNode, maker.Conditional(thisEqualsNull, maker.Literal(HandlerUtil.primeForNull()), hcCall))); + statements.append(createResultCalculation(typeNode, maker.Parens(maker.Conditional(thisEqualsNull, maker.Literal(HandlerUtil.primeForNull()), hcCall)))); } } @@ -330,7 +330,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } public JCExpressionStatement createResultCalculation(JavacNode typeNode, JCExpression expr) { - /* result = result * PRIME + (expr); */ + /* result = result * PRIME + expr; */ JavacTreeMaker maker = typeNode.getTreeMaker(); Name resultName = typeNode.toName(RESULT_NAME); JCExpression mult = maker.Binary(CTC_MUL, maker.Ident(resultName), maker.Ident(typeNode.toName(PRIME_NAME))); @@ -343,7 +343,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas /* (int) (ref >>> 32 ^ ref) */ JCExpression shift = maker.Binary(CTC_UNSIGNED_SHIFT_RIGHT, ref1, maker.Literal(32)); JCExpression xorBits = maker.Binary(CTC_BITXOR, shift, ref2); - return maker.TypeCast(maker.TypeIdent(CTC_INT), xorBits); + return maker.TypeCast(maker.TypeIdent(CTC_INT), maker.Parens(xorBits)); } public JCExpression createTypeReference(JavacNode type) { @@ -389,9 +389,9 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas maker.Ident(thisName)), returnBool(maker, true), null)); } - /* if (!(o instanceof Outer.Inner.MyType) return false; */ { + /* if (!(o instanceof Outer.Inner.MyType)) return false; */ { - JCUnary notInstanceOf = maker.Unary(CTC_NOT, maker.TypeTest(maker.Ident(oName), createTypeReference(typeNode))); + JCUnary notInstanceOf = maker.Unary(CTC_NOT, maker.Parens(maker.TypeTest(maker.Ident(oName), createTypeReference(typeNode)))); statements.append(maker.If(notInstanceOf, returnBool(maker, false), null)); } @@ -474,7 +474,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas } else /* objects */ { /* final java.lang.Object this$fieldName = this.fieldName; */ /* final java.lang.Object other$fieldName = other.fieldName; */ - /* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false;; */ + /* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false; */ Name fieldName = ((JCVariableDecl) fieldNode.get()).name; Name thisDollarFieldName = thisDollar.append(fieldName); Name otherDollarFieldName = otherDollar.append(fieldName); diff --git a/src/core/lombok/javac/handlers/HandleFieldDefaults.java b/src/core/lombok/javac/handlers/HandleFieldDefaults.java index 95effded..12c22059 100644 --- a/src/core/lombok/javac/handlers/HandleFieldDefaults.java +++ b/src/core/lombok/javac/handlers/HandleFieldDefaults.java @@ -31,23 +31,24 @@ import lombok.core.HandlerPriority; import lombok.experimental.FieldDefaults; import lombok.experimental.NonFinal; import lombok.experimental.PackagePrivate; -import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacASTAdapter; +import lombok.javac.JavacASTVisitor; import lombok.javac.JavacNode; import org.mangosdk.spi.ProviderFor; import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; /** * Handles the {@code lombok.FieldDefaults} annotation for eclipse. */ -@ProviderFor(JavacAnnotationHandler.class) +@ProviderFor(JavacASTVisitor.class) @HandlerPriority(-2048) //-2^11; to ensure @Value picks up on messing with the fields' 'final' state, run earlier. -public class HandleFieldDefaults extends JavacAnnotationHandler<FieldDefaults> { +public class HandleFieldDefaults extends JavacASTAdapter { public boolean generateFieldDefaultsForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean makeFinal, boolean checkForTypeLevelFieldDefaults) { if (checkForTypeLevelFieldDefaults) { if (hasAnnotation(FieldDefaults.class, typeNode)) { @@ -72,13 +73,13 @@ public class HandleFieldDefaults extends JavacAnnotationHandler<FieldDefaults> { //Skip fields that start with $ if (fieldDecl.name.toString().startsWith("$")) continue; - setFieldDefaultsForField(field, errorNode.get(), level, makeFinal); + setFieldDefaultsForField(field, level, makeFinal); } return true; } - public void setFieldDefaultsForField(JavacNode fieldNode, DiagnosticPosition pos, AccessLevel level, boolean makeFinal) { + public void setFieldDefaultsForField(JavacNode fieldNode, AccessLevel level, boolean makeFinal) { JCVariableDecl field = (JCVariableDecl) fieldNode.get(); if (level != null && level != AccessLevel.NONE) { if ((field.mods.flags & (Flags.PUBLIC | Flags.PRIVATE | Flags.PROTECTED)) == 0) { @@ -99,31 +100,53 @@ public class HandleFieldDefaults extends JavacAnnotationHandler<FieldDefaults> { fieldNode.rebuild(); } - @Override public void handle(AnnotationValues<FieldDefaults> annotation, JCAnnotation ast, JavacNode annotationNode) { - handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults"); + @Override public void visitType(JavacNode typeNode, JCClassDecl type) { + AnnotationValues<FieldDefaults> fieldDefaults = null; + JavacNode source = typeNode; - deleteAnnotationIfNeccessary(annotationNode, FieldDefaults.class); - deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel"); - JavacNode node = annotationNode.up(); - FieldDefaults instance = annotation.getInstance(); - AccessLevel level = instance.level(); - boolean makeFinal = instance.makeFinal(); - - if (level == AccessLevel.NONE && !makeFinal) { - annotationNode.addError("This does nothing; provide either level or makeFinal or both."); - return; + boolean levelIsExplicit = false; + boolean makeFinalIsExplicit = false; + FieldDefaults fd = null; + for (JavacNode jn : typeNode.down()) { + if (jn.getKind() != Kind.ANNOTATION) continue; + JCAnnotation ann = (JCAnnotation) jn.get(); + JCTree typeTree = ann.annotationType; + if (typeTree == null) continue; + String typeTreeToString = typeTree.toString(); + if (!typeTreeToString.equals("FieldDefaults") && !typeTreeToString.equals("lombok.experimental.FieldDefaults")) continue; + if (!typeMatches(FieldDefaults.class, jn, typeTree)) continue; + + source = jn; + fieldDefaults = createAnnotation(FieldDefaults.class, jn); + levelIsExplicit = fieldDefaults.isExplicit("level"); + makeFinalIsExplicit = fieldDefaults.isExplicit("makeFinal"); + + handleExperimentalFlagUsage(jn, ConfigurationKeys.FIELD_DEFAULTS_FLAG_USAGE, "@FieldDefaults"); + + fd = fieldDefaults.getInstance(); + if (!levelIsExplicit && !makeFinalIsExplicit) { + jn.addError("This does nothing; provide either level or makeFinal or both."); + } + + if (levelIsExplicit && fd.level() == AccessLevel.NONE) { + jn.addError("AccessLevel.NONE doesn't mean anything here. Pick another value."); + levelIsExplicit = false; + } + + deleteAnnotationIfNeccessary(jn, FieldDefaults.class); + deleteImportFromCompilationUnit(jn, "lombok.AccessLevel"); + break; } - if (level == AccessLevel.PACKAGE) { - annotationNode.addError("Setting 'level' to PACKAGE does nothing. To force fields as package private, use the @PackagePrivate annotation on the field."); - } + if (fd == null && (type.mods.flags & (Flags.INTERFACE | Flags.ANNOTATION)) != 0) return; - if (!makeFinal && annotation.isExplicit("makeFinal")) { - annotationNode.addError("Setting 'makeFinal' to false does nothing. To force fields to be non-final, use the @NonFinal annotation on the field."); - } + boolean defaultToPrivate = levelIsExplicit ? false : Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_PRIVATE_EVERYWHERE)); + boolean defaultToFinal = makeFinalIsExplicit ? false : Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.FIELD_DEFAULTS_FINAL_EVERYWHERE)); - if (node == null) return; + if (!defaultToPrivate && !defaultToFinal && fieldDefaults == null) return; + AccessLevel fdAccessLevel = (fieldDefaults != null && levelIsExplicit) ? fd.level() : defaultToPrivate ? AccessLevel.PRIVATE : null; + boolean fdToFinal = (fieldDefaults != null && makeFinalIsExplicit) ? fd.makeFinal() : defaultToFinal; - generateFieldDefaultsForType(node, annotationNode, level, makeFinal, false); + generateFieldDefaultsForType(typeNode, source, fdAccessLevel, fdToFinal, false); } } diff --git a/src/core/lombok/javac/handlers/HandleNonNull.java b/src/core/lombok/javac/handlers/HandleNonNull.java index cd8e3402..81aa1525 100644 --- a/src/core/lombok/javac/handlers/HandleNonNull.java +++ b/src/core/lombok/javac/handlers/HandleNonNull.java @@ -85,7 +85,7 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> { } if (declaration.body == null) { - annotationNode.addWarning("@NonNull is meaningless on a parameter of an abstract method."); + // This used to be a warning, but as @NonNull also has a documentary purpose, better to not warn about this. Since 1.16.7 return; } @@ -141,6 +141,7 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> { List<JCStatement> newList = tail.prepend(nullCheck); for (JCStatement stat : head) newList = newList.prepend(stat); declaration.body.stats = newList; + annotationNode.getAst().setChanged(); } public boolean isNullCheck(JCStatement stat) { diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java index 9eadd750..337ab2d7 100644 --- a/src/core/lombok/javac/handlers/HandleVal.java +++ b/src/core/lombok/javac/handlers/HandleVal.java @@ -51,11 +51,11 @@ import com.sun.tools.javac.util.List; @ResolutionResetNeeded public class HandleVal extends JavacASTAdapter { @Override public void visitLocal(JavacNode localNode, JCVariableDecl local) { - if (local.vartype == null || (!local.vartype.toString().equals("val") && !local.vartype.toString().equals("lombok.val"))) return; - - JCTree source = local.vartype; - - if (!typeMatches(val.class, localNode, local.vartype)) return; + JCTree typeTree = local.vartype; + if (typeTree == null) return; + String typeTreeToString = typeTree.toString(); + if (!typeTreeToString.equals("val") && !typeTreeToString.equals("lombok.val")) return; + if (!typeMatches(val.class, localNode, typeTree)) return; handleFlagUsage(localNode, ConfigurationKeys.VAL_FLAG_USAGE, "val"); @@ -88,7 +88,7 @@ public class HandleVal extends JavacASTAdapter { local.mods.flags |= Flags.FINAL; if (!localNode.shouldDeleteLombokAnnotations()) { - JCAnnotation valAnnotation = recursiveSetGeneratedBy(localNode.getTreeMaker().Annotation(local.vartype, List.<JCExpression>nil()), source, localNode.getContext()); + JCAnnotation valAnnotation = recursiveSetGeneratedBy(localNode.getTreeMaker().Annotation(local.vartype, List.<JCExpression>nil()), typeTree, localNode.getContext()); local.mods.annotations = local.mods.annotations == null ? List.of(valAnnotation) : local.mods.annotations.append(valAnnotation); } @@ -156,7 +156,7 @@ public class HandleVal extends JavacASTAdapter { local.vartype = JavacResolution.createJavaLangObject(localNode.getAst()); throw e; } finally { - recursiveSetGeneratedBy(local.vartype, source, localNode.getContext()); + recursiveSetGeneratedBy(local.vartype, typeTree, localNode.getContext()); } } } diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index c3607d37..4e9be00b 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -21,6 +21,7 @@ */ package lombok.javac.handlers; +import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR; import static lombok.core.handlers.HandlerUtil.*; import static lombok.javac.Javac.*; import static lombok.javac.JavacAugments.JCTree_generatedNode; @@ -840,14 +841,18 @@ public class JavacHandlerUtil { List<JCTree> insertAfter = null; List<JCTree> insertBefore = type.defs; - while (insertBefore.tail != null) { + while (true) { + boolean skip = false; if (insertBefore.head instanceof JCVariableDecl) { JCVariableDecl f = (JCVariableDecl) insertBefore.head; - if (isEnumConstant(f) || isGenerated(f)) { - insertAfter = insertBefore; - insertBefore = insertBefore.tail; - continue; - } + if (isEnumConstant(f) || isGenerated(f)) skip = true; + } else if (insertBefore.head instanceof JCMethodDecl) { + if ((((JCMethodDecl) insertBefore.head).mods.flags & GENERATEDCONSTR) != 0) skip = true; + } + if (skip) { + insertAfter = insertBefore; + insertBefore = insertBefore.tail; + continue; } break; } diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index 7fca01ae..c6d601bd 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -267,13 +267,15 @@ public class JavacSingularsRecipes { } /** Generates 'this.<em>name</em>.size()' as an expression; if nullGuard is true, it's this.name == null ? 0 : this.name.size(). */ - protected JCExpression getSize(JavacTreeMaker maker, JavacNode builderType, Name name, boolean nullGuard) { + protected JCExpression getSize(JavacTreeMaker maker, JavacNode builderType, Name name, boolean nullGuard, boolean parens) { Name thisName = builderType.toName("this"); JCExpression fn = maker.Select(maker.Select(maker.Ident(thisName), name), builderType.toName("size")); JCExpression sizeInvoke = maker.Apply(List.<JCExpression>nil(), fn, List.<JCExpression>nil()); if (nullGuard) { JCExpression isNull = maker.Binary(CTC_EQUAL, maker.Select(maker.Ident(thisName), name), maker.Literal(CTC_BOT, 0)); - return maker.Conditional(isNull, maker.Literal(CTC_INT, 0), sizeInvoke); + JCExpression out = maker.Conditional(isNull, maker.Literal(CTC_INT, 0), sizeInvoke); + if (parens) return maker.Parens(out); + return out; } return sizeInvoke; } diff --git a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java index 1bf47e6e..ba661eff 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacGuavaSingularizer.java @@ -79,6 +79,26 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer { 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); + + returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(maker, CTC_VOID)); + returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null; + generateClearMethod(maker, returnType, returnStatement, data, builderType, source); + } + + private void generateClearMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source) { + JCModifiers mods = maker.Modifiers(Flags.PUBLIC); + List<JCTypeParameter> typeParams = List.nil(); + List<JCExpression> thrown = List.nil(); + List<JCVariableDecl> params = List.nil(); + + JCExpression thisDotField = maker.Select(maker.Ident(builderType.toName("this")), data.getPluralName()); + JCStatement clearField = maker.Exec(maker.Assign(thisDotField, maker.Literal(CTC_BOT, null))); + List<JCStatement> statements = returnStatement != null ? List.of(clearField, returnStatement) : List.of(clearField); + + JCBlock body = maker.Block(0, statements); + Name methodName = builderType.toName(HandlerUtil.buildAccessorName("clear", data.getPluralName().toString())); + 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) { diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java index 8574ddbf..e167c7e2 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSetSingularizer.java @@ -91,6 +91,30 @@ abstract class JavacJavaUtilListSetSingularizer extends JavacJavaUtilSingularize returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(maker, CTC_VOID)); returnStatement = chain ? maker.Return(maker.Ident(thisName)) : null; generatePluralMethod(maker, returnType, returnStatement, data, builderType, source, fluent); + + returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(maker, CTC_VOID)); + returnStatement = chain ? maker.Return(maker.Ident(thisName)) : null; + generateClearMethod(maker, returnType, returnStatement, data, builderType, source); + } + + private void generateClearMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source) { + JCModifiers mods = maker.Modifiers(Flags.PUBLIC); + List<JCTypeParameter> typeParams = List.nil(); + List<JCExpression> thrown = List.nil(); + List<JCVariableDecl> params = List.nil(); + List<JCExpression> jceBlank = List.nil(); + + JCExpression thisDotField = maker.Select(maker.Ident(builderType.toName("this")), data.getPluralName()); + JCExpression thisDotFieldDotClear = maker.Select(maker.Select(maker.Ident(builderType.toName("this")), data.getPluralName()), builderType.toName("clear")); + JCStatement clearCall = maker.Exec(maker.Apply(jceBlank, thisDotFieldDotClear, jceBlank)); + JCExpression cond = maker.Binary(CTC_NOT_EQUAL, thisDotField, maker.Literal(CTC_BOT, null)); + JCStatement ifSetCallClear = maker.If(cond, clearCall, null); + List<JCStatement> statements = returnStatement != null ? List.of(ifSetCallClear, returnStatement) : List.of(ifSetCallClear); + + JCBlock body = maker.Block(0, statements); + Name methodName = builderType.toName(HandlerUtil.buildAccessorName("clear", data.getPluralName().toString())); + 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) { diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java index 9ec77e78..3002a98f 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilListSingularizer.java @@ -87,7 +87,7 @@ public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingulari cases.append(defaultCase); } - JCStatement switchStat = maker.Switch(getSize(maker, builderType, data.getPluralName(), true), cases.toList()); + JCStatement switchStat = maker.Switch(getSize(maker, builderType, data.getPluralName(), true, false), cases.toList()); JCExpression localShadowerType = chainDotsString(builderType, data.getTargetFqn()); localShadowerType = addTypeArgs(1, false, builderType, localShadowerType, data.getTypeArgs(), source); JCStatement varDefStat = maker.VarDef(maker.Modifiers(0), data.getPluralName(), localShadowerType, null); diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java index 0830c9c9..1acae7e3 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilMapSingularizer.java @@ -115,6 +115,33 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer { 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); + + returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(maker, CTC_VOID)); + returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null; + generateClearMethod(maker, returnType, returnStatement, data, builderType, source); + } + + private void generateClearMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source) { + JCModifiers mods = maker.Modifiers(Flags.PUBLIC); + List<JCTypeParameter> typeParams = List.nil(); + List<JCExpression> thrown = List.nil(); + List<JCVariableDecl> params = List.nil(); + List<JCExpression> jceBlank = List.nil(); + + JCExpression thisDotKeyField = chainDots(builderType, "this", data.getPluralName() + "$key"); + JCExpression thisDotKeyFieldDotClear = chainDots(builderType, "this", data.getPluralName() + "$key", "clear"); + JCExpression thisDotValueFieldDotClear = chainDots(builderType, "this", data.getPluralName() + "$value", "clear"); + JCStatement clearKeyCall = maker.Exec(maker.Apply(jceBlank, thisDotKeyFieldDotClear, jceBlank)); + JCStatement clearValueCall = maker.Exec(maker.Apply(jceBlank, thisDotValueFieldDotClear, jceBlank)); + JCExpression cond = maker.Binary(CTC_NOT_EQUAL, thisDotKeyField, maker.Literal(CTC_BOT, null)); + JCBlock clearCalls = maker.Block(0, List.of(clearKeyCall, clearValueCall)); + JCStatement ifSetCallClear = maker.If(cond, clearCalls, null); + List<JCStatement> statements = returnStatement != null ? List.of(ifSetCallClear, returnStatement) : List.of(ifSetCallClear); + + JCBlock body = maker.Block(0, statements); + Name methodName = builderType.toName(HandlerUtil.buildAccessorName("clear", data.getPluralName().toString())); + JCMethodDecl method = maker.MethodDef(mods, methodName, returnType, typeParams, params, thrown, body, null); + injectMethod(builderType, method); } private void generateSingularMethod(JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean fluent) { diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java index f419a014..25669721 100644 --- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java +++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java @@ -89,7 +89,7 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer { cases.append(defaultCase); } - JCStatement switchStat = maker.Switch(getSize(maker, builderType, mapMode ? builderType.toName(data.getPluralName() + "$key") : data.getPluralName(), true), cases.toList()); + JCStatement switchStat = maker.Switch(getSize(maker, builderType, mapMode ? builderType.toName(data.getPluralName() + "$key") : data.getPluralName(), true, false), cases.toList()); JCExpression localShadowerType = chainDotsString(builderType, data.getTargetFqn()); localShadowerType = addTypeArgs(mapMode ? 2 : 1, false, builderType, localShadowerType, data.getTypeArgs(), source); JCStatement varDefStat = maker.VarDef(maker.Modifiers(0), data.getPluralName(), localShadowerType, null); @@ -136,10 +136,10 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer { Name varName = mapMode ? builderType.toName(data.getPluralName() + "$key") : data.getPluralName(); // this.varName.size() < MAX_POWER_OF_2 ? 1 + this.varName.size() + (this.varName.size() - 3) / 3 : Integer.MAX_VALUE; // lessThanCutOff = this.varName.size() < MAX_POWER_OF_2 - JCExpression lessThanCutoff = maker.Binary(CTC_LESS_THAN, getSize(maker, builderType, varName, nullGuard), maker.Literal(CTC_INT, 0x40000000)); + JCExpression lessThanCutoff = maker.Binary(CTC_LESS_THAN, getSize(maker, builderType, varName, nullGuard, true), maker.Literal(CTC_INT, 0x40000000)); JCExpression integerMaxValue = genJavaLangTypeRef(builderType, "Integer", "MAX_VALUE"); - JCExpression sizeFormulaLeft = maker.Binary(CTC_PLUS, maker.Literal(CTC_INT, 1), getSize(maker, builderType, varName, nullGuard)); - JCExpression sizeFormulaRightLeft = maker.Binary(CTC_MINUS, getSize(maker, builderType, varName, nullGuard), maker.Literal(CTC_INT, 3)); + JCExpression sizeFormulaLeft = maker.Binary(CTC_PLUS, maker.Literal(CTC_INT, 1), getSize(maker, builderType, varName, nullGuard, true)); + JCExpression sizeFormulaRightLeft = maker.Parens(maker.Binary(CTC_MINUS, getSize(maker, builderType, varName, nullGuard, true), maker.Literal(CTC_INT, 3))); JCExpression sizeFormulaRight = maker.Binary(CTC_DIV, sizeFormulaRightLeft, maker.Literal(CTC_INT, 3)); JCExpression sizeFormula = maker.Binary(CTC_PLUS, sizeFormulaLeft, sizeFormulaRight); constructorArgs = List.<JCExpression>of(maker.Conditional(lessThanCutoff, sizeFormula, integerMaxValue)); @@ -167,7 +167,7 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer { JCExpression arg2 = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName() + "$value", "get"), List.<JCExpression>of(maker.Ident(ivar))); JCStatement putStatement = maker.Exec(maker.Apply(jceBlank, pluralnameDotPut, List.of(arg1, arg2))); JCStatement forInit = maker.VarDef(maker.Modifiers(0), ivar, maker.TypeIdent(CTC_INT), maker.Literal(CTC_INT, 0)); - JCExpression checkExpr = maker.Binary(CTC_LESS_THAN, maker.Ident(ivar), getSize(maker, builderType, keyVarName, nullGuard)); + JCExpression checkExpr = maker.Binary(CTC_LESS_THAN, maker.Ident(ivar), getSize(maker, builderType, keyVarName, nullGuard, true)); JCExpression incrementExpr = maker.Unary(CTC_POSTINC, maker.Ident(ivar)); fillStat = maker.ForLoop(List.of(forInit), checkExpr, List.of(maker.Exec(incrementExpr)), putStatement); } else { diff --git a/src/delombok/lombok/delombok/DelombokResult.java b/src/delombok/lombok/delombok/DelombokResult.java index 84aeb68b..8985b257 100644 --- a/src/delombok/lombok/delombok/DelombokResult.java +++ b/src/delombok/lombok/delombok/DelombokResult.java @@ -65,7 +65,8 @@ public class DelombokResult { else comments_ = com.sun.tools.javac.util.List.from(comments.toArray(new CommentInfo[0])); FormatPreferences preferences = new FormatPreferenceScanner().scan(formatPreferences, getContent()); - compilationUnit.accept(new PrettyCommentsPrinter(out, compilationUnit, comments_, preferences)); + //compilationUnit.accept(new PrettyCommentsPrinter(out, compilationUnit, comments_, preferences)); + compilationUnit.accept(new PrettyPrinter(out, compilationUnit, comments_, preferences)); } private CharSequence getContent() throws IOException { diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java deleted file mode 100644 index ca44670d..00000000 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ /dev/null @@ -1,1758 +0,0 @@ -/* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -/* - * Code derived from com.sun.tools.javac.tree.Pretty, from the langtools project. - * A version can be found at, for example, http://hg.openjdk.java.net/jdk7/build/langtools - */ -package lombok.delombok; - -import static com.sun.tools.javac.code.Flags.*; -import static lombok.javac.Javac.*; -import static lombok.javac.JavacTreeMaker.TreeTag.treeTag; -import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; - -import java.io.IOException; -import java.io.Writer; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.Map; - -import lombok.javac.CommentInfo; -import lombok.javac.CommentInfo.EndConnection; -import lombok.javac.CommentInfo.StartConnection; -import lombok.javac.JavacTreeMaker.TreeTag; -import lombok.javac.JavacTreeMaker.TypeTag; - -import com.sun.source.tree.Tree; -import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.tree.DocCommentTable; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCAnnotation; -import com.sun.tools.javac.tree.JCTree.JCArrayAccess; -import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; -import com.sun.tools.javac.tree.JCTree.JCAssert; -import com.sun.tools.javac.tree.JCTree.JCAssign; -import com.sun.tools.javac.tree.JCTree.JCAssignOp; -import com.sun.tools.javac.tree.JCTree.JCBinary; -import com.sun.tools.javac.tree.JCTree.JCBlock; -import com.sun.tools.javac.tree.JCTree.JCBreak; -import com.sun.tools.javac.tree.JCTree.JCCase; -import com.sun.tools.javac.tree.JCTree.JCCatch; -import com.sun.tools.javac.tree.JCTree.JCClassDecl; -import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; -import com.sun.tools.javac.tree.JCTree.JCConditional; -import com.sun.tools.javac.tree.JCTree.JCContinue; -import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop; -import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; -import com.sun.tools.javac.tree.JCTree.JCErroneous; -import com.sun.tools.javac.tree.JCTree.JCExpression; -import com.sun.tools.javac.tree.JCTree.JCExpressionStatement; -import com.sun.tools.javac.tree.JCTree.JCFieldAccess; -import com.sun.tools.javac.tree.JCTree.JCForLoop; -import com.sun.tools.javac.tree.JCTree.JCIdent; -import com.sun.tools.javac.tree.JCTree.JCIf; -import com.sun.tools.javac.tree.JCTree.JCImport; -import com.sun.tools.javac.tree.JCTree.JCInstanceOf; -import com.sun.tools.javac.tree.JCTree.JCLabeledStatement; -import com.sun.tools.javac.tree.JCTree.JCLiteral; -import com.sun.tools.javac.tree.JCTree.JCMethodDecl; -import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; -import com.sun.tools.javac.tree.JCTree.JCModifiers; -import com.sun.tools.javac.tree.JCTree.JCNewArray; -import com.sun.tools.javac.tree.JCTree.JCNewClass; -import com.sun.tools.javac.tree.JCTree.JCParens; -import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree; -import com.sun.tools.javac.tree.JCTree.JCReturn; -import com.sun.tools.javac.tree.JCTree.JCSkip; -import com.sun.tools.javac.tree.JCTree.JCStatement; -import com.sun.tools.javac.tree.JCTree.JCSwitch; -import com.sun.tools.javac.tree.JCTree.JCSynchronized; -import com.sun.tools.javac.tree.JCTree.JCThrow; -import com.sun.tools.javac.tree.JCTree.JCTry; -import com.sun.tools.javac.tree.JCTree.JCTypeApply; -import com.sun.tools.javac.tree.JCTree.JCTypeCast; -import com.sun.tools.javac.tree.JCTree.JCTypeParameter; -import com.sun.tools.javac.tree.JCTree.JCUnary; -import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.tree.JCTree.JCWhileLoop; -import com.sun.tools.javac.tree.JCTree.JCWildcard; -import com.sun.tools.javac.tree.JCTree.LetExpr; -import com.sun.tools.javac.tree.JCTree.TypeBoundKind; -import com.sun.tools.javac.tree.TreeInfo; -import com.sun.tools.javac.tree.TreeScanner; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Name; -import com.sun.tools.javac.util.Position; -//import com.sun.tools.javac.code.TypeTags; - -/** Prints out a tree as an indented Java source program. - * - * <p><b>This is NOT part of any API supported by Sun Microsystems. If - * you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice.</b> - */ -@SuppressWarnings("all") // Mainly sun code that has other warning settings -public class PrettyCommentsPrinter extends JCTree.Visitor { - private static final TreeTag PARENS = treeTag("PARENS"); - private static final TreeTag IMPORT = treeTag("IMPORT"); - private static final TreeTag VARDEF = treeTag("VARDEF"); - private static final TreeTag SELECT = treeTag("SELECT"); - - private static final Map<TreeTag, String> OPERATORS; - - // StandardFlags | DEFAULT - private static final long EXTENDED_STANDARD_FLAGS = 0x0fffL | 1L<<43; - - static { - Map<TreeTag, String> map = new HashMap<TreeTag, String>(); - - map.put(treeTag("POS"), "+"); - map.put(treeTag("NEG"), "-"); - map.put(treeTag("NOT"), "!"); - map.put(treeTag("COMPL"), "~"); - map.put(treeTag("PREINC"), "++"); - map.put(treeTag("PREDEC"), "--"); - map.put(treeTag("POSTINC"), "++"); - map.put(treeTag("POSTDEC"), "--"); - map.put(treeTag("NULLCHK"), "<*nullchk*>"); - map.put(treeTag("OR"), "||"); - map.put(treeTag("AND"), "&&"); - map.put(treeTag("EQ"), "=="); - map.put(treeTag("NE"), "!="); - map.put(treeTag("LT"), "<"); - map.put(treeTag("GT"), ">"); - map.put(treeTag("LE"), "<="); - map.put(treeTag("GE"), ">="); - map.put(treeTag("BITOR"), "|"); - map.put(treeTag("BITXOR"), "^"); - map.put(treeTag("BITAND"), "&"); - map.put(treeTag("SL"), "<<"); - map.put(treeTag("SR"), ">>"); - map.put(treeTag("USR"), ">>>"); - map.put(treeTag("PLUS"), "+"); - map.put(treeTag("MINUS"), "-"); - map.put(treeTag("MUL"), "*"); - map.put(treeTag("DIV"), "/"); - map.put(treeTag("MOD"), "%"); - - map.put(treeTag("BITOR_ASG"), "|="); - map.put(treeTag("BITXOR_ASG"), "^="); - map.put(treeTag("BITAND_ASG"), "&="); - map.put(treeTag("SL_ASG"), "<<="); - map.put(treeTag("SR_ASG"), ">>="); - map.put(treeTag("USR_ASG"), ">>>="); - map.put(treeTag("PLUS_ASG"), "+="); - map.put(treeTag("MINUS_ASG"), "-="); - map.put(treeTag("MUL_ASG"), "*="); - map.put(treeTag("DIV_ASG"), "/="); - map.put(treeTag("MOD_ASG"), "%="); - - OPERATORS = map; - } - - private List<CommentInfo> comments; - private final JCCompilationUnit cu; - private boolean onNewLine = true; - private boolean aligned = false; - private boolean inParams = false; - - private boolean needsSpace = false; - private boolean needsNewLine = false; - private boolean needsAlign = false; - - // Flag for try-with-resources to make them not final and not print the last semicolon. - // This flag is set just before printing the vardef and cleared when printing its modifiers. - private boolean suppressFinalAndSemicolonsInTry = false; - - private final FormatPreferences formatPreferences; - - public PrettyCommentsPrinter(Writer out, JCCompilationUnit cu, List<CommentInfo> comments, FormatPreferences preferences) { - this.out = out; - this.comments = comments; - this.cu = cu; - this.formatPreferences = preferences; - } - - private int endPos(JCTree tree) { - return getEndPosition(tree, cu); - } - - private void consumeComments(int until) throws IOException { - consumeComments(until, null); - } - - private void consumeComments(int until, JCTree tree) throws IOException { - boolean prevNewLine = onNewLine; - CommentInfo head = comments.head; - while (comments.nonEmpty() && head.pos < until) { - printComment(head); - comments = comments.tail; - head = comments.head; - } - if (!onNewLine && prevNewLine) { - println(); - } - } - - private void consumeTrailingComments(int from) throws IOException { - boolean prevNewLine = onNewLine; - CommentInfo head = comments.head; - boolean stop = false; - while (comments.nonEmpty() && head.prevEndPos == from && !stop && !(head.start == StartConnection.ON_NEXT_LINE || head.start == StartConnection.START_OF_LINE)) { - from = head.endPos; - printComment(head); - stop = (head.end == EndConnection.ON_NEXT_LINE); - comments = comments.tail; - head = comments.head; - } - if (!onNewLine && prevNewLine) { - println(); - } - } - - private void printComment(CommentInfo comment) throws IOException { - prepareComment(comment.start); - print(comment.content); - switch (comment.end) { - case ON_NEXT_LINE: - if (!aligned) { - needsNewLine = true; - needsAlign = true; - } - break; - case AFTER_COMMENT: - needsSpace = true; - break; - case DIRECT_AFTER_COMMENT: - // do nothing - break; - } - } - - private void prepareComment(StartConnection start) throws IOException { - switch (start) { - case DIRECT_AFTER_PREVIOUS: - needsSpace = false; - break; - case AFTER_PREVIOUS: - needsSpace = true; - break; - case START_OF_LINE: - needsNewLine = true; - needsAlign = false; - break; - case ON_NEXT_LINE: - if (!aligned) { - needsNewLine = true; - needsAlign = true; - } - break; - } - } - - /** The output stream on which trees are printed. - */ - Writer out; - - /** The current left margin. - */ - int lmargin = 0; - - /** The enclosing class name. - */ - Name enclClassName; - - /** A hashtable mapping trees to their documentation comments - * (can be null) - */ - Map<JCTree, String> docComments = null; - DocCommentTable docTable = null; - - String getJavadocFor(JCTree node) { - if (docComments != null) return docComments.get(node); - if (docTable != null) return docTable.getCommentText(node); - return null; - } - - /** Align code to be indented to left margin. - */ - void align() throws IOException { - onNewLine = false; - aligned = true; - needsAlign = false; - for (int i = 0; i < lmargin; i++) out.write(formatPreferences.indent()); - } - - /** Increase left margin by indentation width. - */ - void indent() { - lmargin++; - } - - /** Decrease left margin by indentation width. - */ - void undent() { - lmargin--; - } - - /** Enter a new precedence level. Emit a `(' if new precedence level - * is less than precedence level so far. - * @param contextPrec The precedence level in force so far. - * @param ownPrec The new precedence level. - */ - void open(int contextPrec, int ownPrec) throws IOException { - if (ownPrec < contextPrec) out.write("("); - } - - /** Leave precedence level. Emit a `(' if inner precedence level - * is less than precedence level we revert to. - * @param contextPrec The precedence level we revert to. - * @param ownPrec The inner precedence level. - */ - void close(int contextPrec, int ownPrec) throws IOException { - if (ownPrec < contextPrec) out.write(")"); - } - - /** Print string, replacing all non-ascii character with unicode escapes. - */ - public void print(Object s) throws IOException { - boolean align = needsAlign; - if (needsNewLine && !onNewLine) { - println(); - } - if (align && !aligned) { - align(); - } - if (needsSpace && !onNewLine && !aligned) { - out.write(' '); - } - needsSpace = false; - - out.write(s.toString()); - - onNewLine = false; - aligned = false; - } - - /** Print new line. - */ - public void println() throws IOException { - onNewLine = true; - aligned = false; - needsNewLine = false; - out.write(lineSep); - } - - String lineSep = System.getProperty("line.separator"); - - /************************************************************************** - * Traversal methods - *************************************************************************/ - - /** Exception to propagate IOException through visitXXX methods */ - private static class UncheckedIOException extends Error { - static final long serialVersionUID = -4032692679158424751L; - UncheckedIOException(IOException e) { - super(e.getMessage(), e); - } - } - - /** Visitor argument: the current precedence level. - */ - int prec; - - /** Visitor method: print expression tree. - * @param prec The current precedence level. - */ - public void printExpr(JCTree tree, int prec) throws IOException { - - int prevPrec = this.prec; - try { - this.prec = prec; - if (tree == null) print("/*missing*/"); - else { - consumeComments(tree.pos, tree); - tree.accept(this); - int endPos = endPos(tree); - consumeTrailingComments(endPos); - } - } catch (UncheckedIOException ex) { - IOException e = new IOException(ex.getMessage()); - e.initCause(ex); - throw e; - } finally { - this.prec = prevPrec; - } - } - - /** Derived visitor method: print expression tree at minimum precedence level - * for expression. - */ - public void printExpr(JCTree tree) throws IOException { - printExpr(tree, TreeInfo.noPrec); - } - - /** Derived visitor method: print statement tree. - */ - public void printStat(JCTree tree) throws IOException { - if (isEmptyStat(tree)) { - // printEmptyStat(); // -- starting in java 7, these get lost, so to be consistent, we never print them. - } else { - printExpr(tree, TreeInfo.notExpression); - } - } - - public void printEmptyStat() throws IOException { - print(";"); - } - - public boolean isEmptyStat(JCTree tree) { - if (!(tree instanceof JCBlock)) return false; - JCBlock block = (JCBlock) tree; - return (Position.NOPOS == block.pos) && block.stats.isEmpty(); - } - - /** Derived visitor method: print list of expression trees, separated by given string. - * @param sep the separator string - */ - public <T extends JCTree> void printExprs(List<T> trees, String sep) throws IOException { - if (trees.nonEmpty()) { - printExpr(trees.head); - for (List<T> l = trees.tail; l.nonEmpty(); l = l.tail) { - print(sep); - printExpr(l.head); - } - } - } - - /** Derived visitor method: print list of expression trees, separated by commas. - */ - public <T extends JCTree> void printExprs(List<T> trees) throws IOException { - printExprs(trees, ", "); - } - - /** Derived visitor method: print list of statements, each on a separate line. - */ - public void printStats(List<? extends JCTree> trees) throws IOException { - for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) { - if (isSuppressed(l.head)) continue; - if (!suppressAlignmentForEmptyLines(l.head)) align(); - printStat(l.head); - println(); - } - } - - private boolean suppressAlignmentForEmptyLines(JCTree tree) { - return !formatPreferences.fillEmpties() && startsWithNewLine(tree); - } - - private boolean startsWithNewLine(JCTree tree) { - return tree instanceof JCMethodDecl || tree instanceof JCClassDecl; - } - - private boolean isSuppressed(JCTree tree) { - if (isEmptyStat(tree)) { - return true; - } - if (tree instanceof JCExpressionStatement) { - return isNoArgsSuperCall(((JCExpressionStatement)tree).expr); - } - return false; - } - - /** Print a set of modifiers. - */ - public void printFlags(long flags) throws IOException { - if ((flags & SYNTHETIC) != 0) print("/*synthetic*/ "); - if (suppressFinalAndSemicolonsInTry) { - flags = flags & ~FINAL; - suppressFinalAndSemicolonsInTry = false; - } - print(TreeInfo.flagNames(flags)); - if ((flags & EXTENDED_STANDARD_FLAGS) != 0) print(" "); - if ((flags & ANNOTATION) != 0) print("@"); - } - - public void printAnnotations(List<JCAnnotation> trees) throws IOException { - for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) { - printStat(l.head); - if (inParams) { - print(" "); - } - else { - println(); - align(); - } - } - } - - /** Print documentation comment, if it exists - * @param tree The tree for which a documentation comment should be printed. - */ - public void printDocComment(JCTree tree) throws IOException { - String dc = getJavadocFor(tree); - if (dc == null) return; - print("/**"); println(); - int pos = 0; - int endpos = lineEndPos(dc, pos); - boolean atStart = true; - while (pos < dc.length()) { - String line = dc.substring(pos, endpos); - if (line.trim().isEmpty() && atStart) { - atStart = false; - continue; - } - atStart = false; - align(); - print(" *"); - if (pos < dc.length() && dc.charAt(pos) > ' ') print(" "); - print(dc.substring(pos, endpos)); println(); - pos = endpos + 1; - endpos = lineEndPos(dc, pos); - } - align(); print(" */"); println(); - align(); - } -//where - static int lineEndPos(String s, int start) { - int pos = s.indexOf('\n', start); - if (pos < 0) pos = s.length(); - return pos; - } - - /** If type parameter list is non-empty, print it enclosed in "<...>" brackets. - */ - public void printTypeParameters(List<JCTypeParameter> trees) throws IOException { - if (trees.nonEmpty()) { - print("<"); - printExprs(trees); - print(">"); - } - } - - /** Print a block. - */ - public void printBlock(List<? extends JCTree> stats, JCTree container) throws IOException { - print("{"); - println(); - indent(); - printStats(stats); - consumeComments(endPos(container)); - undent(); - align(); - print("}"); - } - - /** Print a block. - */ - public void printEnumBody(List<JCTree> stats) throws IOException { - print("{"); - println(); - indent(); - boolean first = true; - for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) { - if (isEnumerator(l.head)) { - if (!first) { - print(","); - println(); - } - align(); - printStat(l.head); - first = false; - } - } - print(";"); - println(); - int x = 0; - for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) { - x++; - if (!isEnumerator(l.head)) { - if (!suppressAlignmentForEmptyLines(l.head)) align(); - printStat(l.head); - println(); - } - } - undent(); - align(); - print("}"); - } - - public void printEnumMember(JCVariableDecl tree) throws IOException { - printAnnotations(tree.mods.annotations); - print(tree.name); - if (tree.init instanceof JCNewClass) { - JCNewClass constructor = (JCNewClass) tree.init; - if (constructor.args != null && constructor.args.nonEmpty()) { - print("("); - printExprs(constructor.args); - print(")"); - } - if (constructor.def != null && constructor.def.defs != null) { - print(" "); - printBlock(constructor.def.defs, constructor.def); - } - } - } - - /** Is the given tree an enumerator definition? */ - boolean isEnumerator(JCTree t) { - return VARDEF.equals(treeTag(t)) && (((JCVariableDecl) t).mods.flags & ENUM) != 0; - } - - /** Print unit consisting of package clause and import statements in toplevel, - * followed by class definition. if class definition == null, - * print all definitions in toplevel. - * @param tree The toplevel tree - * @param cdef The class definition, which is assumed to be part of the - * toplevel tree. - */ - public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException { - Object dc = getDocComments(tree); - loadDocCommentsTable(dc); - printDocComment(tree); - if (tree.pid != null) { - consumeComments(tree.pos, tree); - print("package "); - printExpr(tree.pid); - print(";"); - println(); - } - boolean firstImport = true; - for (List<JCTree> l = tree.defs; - l.nonEmpty() && (cdef == null || IMPORT.equals(treeTag(l.head))); - l = l.tail) { - if (IMPORT.equals(treeTag(l.head))) { - JCImport imp = (JCImport)l.head; - Name name = TreeInfo.name(imp.qualid); - if (name == name.table.fromChars(new char[] {'*'}, 0, 1) || - cdef == null || - isUsed(TreeInfo.symbol(imp.qualid), cdef)) { - if (firstImport) { - firstImport = false; - println(); - } - printStat(imp); - } - } else { - printStat(l.head); - } - } - if (cdef != null) { - printStat(cdef); - println(); - } - } - // where - @SuppressWarnings("unchecked") - private void loadDocCommentsTable(Object dc) { - if (dc instanceof Map<?, ?>) this.docComments = (Map) dc; - else if (dc instanceof DocCommentTable) this.docTable = (DocCommentTable) dc; - } - - boolean isUsed(final Symbol t, JCTree cdef) { - class UsedVisitor extends TreeScanner { - public void scan(JCTree tree) { - if (tree!=null && !result) tree.accept(this); - } - boolean result = false; - public void visitIdent(JCIdent tree) { - if (tree.sym == t) result = true; - } - } - UsedVisitor v = new UsedVisitor(); - v.scan(cdef); - return v.result; - } - - /************************************************************************** - * Visitor methods - *************************************************************************/ - - public void visitTopLevel(JCCompilationUnit tree) { - try { - printUnit(tree, null); - consumeComments(Integer.MAX_VALUE); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitImport(JCImport tree) { - try { - print("import "); - if (tree.staticImport) print("static "); - printExpr(tree.qualid); - print(";"); - println(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitClassDef(JCClassDecl tree) { - try { - consumeComments(tree.pos, tree); - println(); align(); - printDocComment(tree); - printAnnotations(tree.mods.annotations); - printFlags(tree.mods.flags & ~INTERFACE); - Name enclClassNamePrev = enclClassName; - enclClassName = tree.name; - if ((tree.mods.flags & INTERFACE) != 0) { - print("interface " + tree.name); - printTypeParameters(tree.typarams); - if (tree.implementing.nonEmpty()) { - print(" extends "); - printExprs(tree.implementing); - } - } else { - if ((tree.mods.flags & ENUM) != 0) - print("enum " + tree.name); - else - print("class " + tree.name); - printTypeParameters(tree.typarams); - if (getExtendsClause(tree) != null) { - print(" extends "); - printExpr(getExtendsClause(tree)); - } - if (tree.implementing.nonEmpty()) { - print(" implements "); - printExprs(tree.implementing); - } - } - print(" "); - // <Added for delombok by Reinier Zwitserloot> - if ((tree.mods.flags & INTERFACE) != 0) { - removeImplicitModifiersForInterfaceMembers(tree.defs); - } - // </Added for delombok by Reinier Zwitserloot> - if ((tree.mods.flags & ENUM) != 0) { - printEnumBody(tree.defs); - } else { - printBlock(tree.defs, tree); - } - enclClassName = enclClassNamePrev; - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - // Added for delombok by Reinier Zwitserloot - private void removeImplicitModifiersForInterfaceMembers(List<JCTree> defs) { - for (JCTree def :defs) { - if (def instanceof JCVariableDecl) { - ((JCVariableDecl) def).mods.flags &= ~(Flags.PUBLIC | Flags.STATIC | Flags.FINAL); - } - if (def instanceof JCMethodDecl) { - ((JCMethodDecl) def).mods.flags &= ~(Flags.PUBLIC | Flags.ABSTRACT); - } - if (def instanceof JCClassDecl) { - ((JCClassDecl) def).mods.flags &= ~(Flags.PUBLIC | Flags.STATIC); - } - } - } - - public void visitMethodDef(JCMethodDecl tree) { - try { - boolean isConstructor = tree.name == tree.name.table.fromChars("<init>".toCharArray(), 0, 6); - // when producing source output, omit anonymous constructors - if (isConstructor && enclClassName == null) return; - boolean isGeneratedConstructor = isConstructor && ((tree.mods.flags & Flags.GENERATEDCONSTR) != 0); - if (isGeneratedConstructor) return; - println(); align(); - printDocComment(tree); - printExpr(tree.mods); - printTypeParameters(tree.typarams); - if (tree.typarams != null && tree.typarams.length() > 0) print(" "); - if (tree.name == tree.name.table.fromChars("<init>".toCharArray(), 0, 6)) { - print(enclClassName != null ? enclClassName : tree.name); - } else { - printExpr(tree.restype); - print(" " + tree.name); - } - print("("); - inParams = true; - printExprs(tree.params); - inParams = false; - print(")"); - if (tree.thrown.nonEmpty()) { - print(" throws "); - printExprs(tree.thrown); - } - if (tree.defaultValue != null) { - print(" default "); - print(tree.defaultValue); - } - if (tree.body != null) { - print(" "); - printBlock(tree.body.stats, tree.body); - } else { - print(";"); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitVarDef(JCVariableDecl tree) { - try { - boolean suppressSemi = suppressFinalAndSemicolonsInTry; - if (getJavadocFor(tree) != null) { - println(); align(); - } - printDocComment(tree); - if ((tree.mods.flags & ENUM) != 0) { - printEnumMember(tree); - } else { - printExpr(tree.mods); - if ((tree.mods.flags & VARARGS) != 0) { - printExpr(((JCArrayTypeTree) tree.vartype).elemtype); - print("... " + tree.name); - } else { - printExpr(tree.vartype); - print(" " + tree.name); - } - if (tree.init != null) { - print(" = "); - printExpr(tree.init); - } - if (prec == TreeInfo.notExpression && !suppressSemi) print(";"); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitSkip(JCSkip tree) { - try { - print(";"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitBlock(JCBlock tree) { - try { - consumeComments(tree.pos); - printFlags(tree.flags); - printBlock(tree.stats, tree); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitDoLoop(JCDoWhileLoop tree) { - try { - print("do "); - printStat(tree.body); - align(); - print(" while "); - if (PARENS.equals(treeTag(tree.cond))) { - printExpr(tree.cond); - } else { - print("("); - printExpr(tree.cond); - print(")"); - } - print(";"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitWhileLoop(JCWhileLoop tree) { - try { - print("while "); - if (PARENS.equals(treeTag(tree.cond))) { - printExpr(tree.cond); - } else { - print("("); - printExpr(tree.cond); - print(")"); - } - print(" "); - printStat(tree.body); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitForLoop(JCForLoop tree) { - try { - print("for ("); - if (tree.init.nonEmpty()) { - if (VARDEF.equals(treeTag(tree.init.head))) { - printExpr(tree.init.head); - for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) { - JCVariableDecl vdef = (JCVariableDecl)l.head; - print(", " + vdef.name + " = "); - printExpr(vdef.init); - } - } else { - printExprs(tree.init); - } - } - print("; "); - if (tree.cond != null) printExpr(tree.cond); - print("; "); - printExprs(tree.step); - print(") "); - printStat(tree.body); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitForeachLoop(JCEnhancedForLoop tree) { - try { - print("for ("); - printExpr(tree.var); - print(" : "); - printExpr(tree.expr); - print(") "); - printStat(tree.body); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitLabelled(JCLabeledStatement tree) { - try { - print(tree.label + ":"); - if (isEmptyStat(tree.body) || tree.body instanceof JCSkip) { - print(" ;"); - } else if (tree.body instanceof JCBlock) { - print(" "); - printStat(tree.body); - } else { - println(); - align(); - printStat(tree.body); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitSwitch(JCSwitch tree) { - try { - print("switch "); - if (PARENS.equals(treeTag(tree.selector))) { - printExpr(tree.selector); - } else { - print("("); - printExpr(tree.selector); - print(")"); - } - print(" {"); - println(); - printStats(tree.cases); - align(); - print("}"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitCase(JCCase tree) { - try { - if (tree.pat == null) { - print("default"); - } else { - print("case "); - printExpr(tree.pat); - } - print(": "); - println(); - indent(); - printStats(tree.stats); - undent(); - align(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitSynchronized(JCSynchronized tree) { - try { - print("synchronized "); - if (PARENS.equals(treeTag(tree.lock))) { - printExpr(tree.lock); - } else { - print("("); - printExpr(tree.lock); - print(")"); - } - print(" "); - printStat(tree.body); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitTry(JCTry tree) { - try { - print("try "); - List<?> resources = null; - try { - Field f = JCTry.class.getField("resources"); - resources = (List<?>) f.get(tree); - } catch (Exception ignore) { - // In JDK6 and down this field does not exist; resources will retain its initializer value which is what we want. - } - - if (resources != null && resources.nonEmpty()) { - print("("); - int remaining = resources.size(); - if (remaining == 1) { - JCTree var = (JCTree) resources.get(0); - suppressFinalAndSemicolonsInTry = true; - printStat(var); - print(") "); - } else { - indent(); indent(); - for (Object var0 : resources) { - println(); - align(); - JCTree var = (JCTree) var0; - suppressFinalAndSemicolonsInTry = true; - printStat(var); - remaining--; - if (remaining > 0) print(";"); - } - print(") "); - undent(); undent(); - } - } - - printStat(tree.body); - for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { - printStat(l.head); - } - if (tree.finalizer != null) { - print(" finally "); - printStat(tree.finalizer); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitCatch(JCCatch tree) { - try { - print(" catch ("); - printExpr(tree.param); - print(") "); - printStat(tree.body); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitConditional(JCConditional tree) { - try { - open(prec, TreeInfo.condPrec); - printExpr(tree.cond, TreeInfo.condPrec); - print(" ? "); - printExpr(tree.truepart, TreeInfo.condPrec); - print(" : "); - printExpr(tree.falsepart, TreeInfo.condPrec); - close(prec, TreeInfo.condPrec); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitIf(JCIf tree) { - try { - print("if "); - if (PARENS.equals(treeTag(tree.cond))) { - printExpr(tree.cond); - } else { - print("("); - printExpr(tree.cond); - print(")"); - } - print(" "); - printStat(tree.thenpart); - if (tree.elsepart != null) { - print(" else "); - printStat(tree.elsepart); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private boolean isNoArgsSuperCall(JCExpression expr) { - if (!(expr instanceof JCMethodInvocation)) return false; - JCMethodInvocation tree = (JCMethodInvocation) expr; - if (!tree.typeargs.isEmpty() || !tree.args.isEmpty()) return false; - if (!(tree.meth instanceof JCIdent)) return false; - return ((JCIdent) tree.meth).name.toString().equals("super"); - } - - public void visitExec(JCExpressionStatement tree) { - if (isNoArgsSuperCall(tree.expr)) return; - try { - printExpr(tree.expr); - if (prec == TreeInfo.notExpression) print(";"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitBreak(JCBreak tree) { - try { - print("break"); - if (tree.label != null) print(" " + tree.label); - print(";"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitContinue(JCContinue tree) { - try { - print("continue"); - if (tree.label != null) print(" " + tree.label); - print(";"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitReturn(JCReturn tree) { - try { - print("return"); - if (tree.expr != null) { - print(" "); - printExpr(tree.expr); - } - print(";"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitThrow(JCThrow tree) { - try { - print("throw "); - printExpr(tree.expr); - print(";"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitAssert(JCAssert tree) { - try { - print("assert "); - printExpr(tree.cond); - if (tree.detail != null) { - print(" : "); - printExpr(tree.detail); - } - print(";"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitApply(JCMethodInvocation tree) { - try { - if (!tree.typeargs.isEmpty()) { - if (SELECT.equals(treeTag(tree.meth))) { - JCFieldAccess left = (JCFieldAccess)tree.meth; - printExpr(left.selected); - print(".<"); - printExprs(tree.typeargs); - print(">" + left.name); - } else { - print("<"); - printExprs(tree.typeargs); - print(">"); - printExpr(tree.meth); - } - } else { - printExpr(tree.meth); - } - print("("); - printExprs(tree.args); - print(")"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitNewClass(JCNewClass tree) { - try { - if (tree.encl != null) { - printExpr(tree.encl); - print("."); - } - print("new "); - if (!tree.typeargs.isEmpty()) { - print("<"); - printExprs(tree.typeargs); - print(">"); - } - printExpr(tree.clazz); - print("("); - printExprs(tree.args); - print(")"); - if (tree.def != null) { - Name enclClassNamePrev = enclClassName; - enclClassName = - tree.def.name != null ? tree.def.name : - tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.fromChars(new char[0], 0, 0) ? tree.type.tsym.name : - null; - if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/"); - printBlock(tree.def.defs, tree.def); - enclClassName = enclClassNamePrev; - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitNewArray(JCNewArray tree) { - try { - if (tree.elemtype != null) { - print("new "); - JCTree elem = tree.elemtype; - if (elem instanceof JCArrayTypeTree) - printBaseElementType((JCArrayTypeTree) elem); - else - printExpr(elem); - for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) { - print("["); - printExpr(l.head); - print("]"); - } - if (elem instanceof JCArrayTypeTree) - printBrackets((JCArrayTypeTree) elem); - } - if (tree.elems != null) { - if (tree.elemtype != null) print("[]"); - print("{"); - printExprs(tree.elems); - print("}"); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitParens(JCParens tree) { - try { - print("("); - printExpr(tree.expr); - print(")"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitAssign(JCAssign tree) { - try { - open(prec, TreeInfo.assignPrec); - printExpr(tree.lhs, TreeInfo.assignPrec + 1); - print(" = "); - printExpr(tree.rhs, TreeInfo.assignPrec); - close(prec, TreeInfo.assignPrec); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public String operatorName(TreeTag tag) { - String result = OPERATORS.get(tag); - if (result == null) throw new Error(); - return result; - } - - public void visitAssignop(JCAssignOp tree) { - try { - open(prec, TreeInfo.assignopPrec); - printExpr(tree.lhs, TreeInfo.assignopPrec + 1); - String opname = operatorName(treeTag(tree)); - print(" " + opname + " "); - printExpr(tree.rhs, TreeInfo.assignopPrec); - close(prec, TreeInfo.assignopPrec); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitUnary(JCUnary tree) { - try { - int ownprec = isOwnPrec(tree); - String opname = operatorName(treeTag(tree)); - open(prec, ownprec); - if (isPrefixUnary(tree)) { - print(opname); - printExpr(tree.arg, ownprec); - } else { - printExpr(tree.arg, ownprec); - print(opname); - } - close(prec, ownprec); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private int isOwnPrec(JCExpression tree) { - return treeTag(tree).getOperatorPrecedenceLevel(); - } - - private boolean isPrefixUnary(JCUnary tree) { - return treeTag(tree).isPrefixUnaryOp(); - } - - public void visitBinary(JCBinary tree) { - try { - int ownprec = isOwnPrec(tree); - String opname = operatorName(treeTag(tree)); - open(prec, ownprec); - printExpr(tree.lhs, ownprec); - print(" " + opname + " "); - printExpr(tree.rhs, ownprec + 1); - close(prec, ownprec); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitTypeCast(JCTypeCast tree) { - try { - open(prec, TreeInfo.prefixPrec); - print("("); - printExpr(tree.clazz); - print(")"); - printExpr(tree.expr, TreeInfo.prefixPrec); - close(prec, TreeInfo.prefixPrec); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitTypeTest(JCInstanceOf tree) { - try { - open(prec, TreeInfo.ordPrec); - printExpr(tree.expr, TreeInfo.ordPrec); - print(" instanceof "); - printExpr(tree.clazz, TreeInfo.ordPrec + 1); - close(prec, TreeInfo.ordPrec); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitIndexed(JCArrayAccess tree) { - try { - printExpr(tree.indexed, TreeInfo.postfixPrec); - print("["); - printExpr(tree.index); - print("]"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitSelect(JCFieldAccess tree) { - try { - printExpr(tree.selected, TreeInfo.postfixPrec); - print("." + tree.name); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitIdent(JCIdent tree) { - try { - print(tree.name); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitLiteral(JCLiteral tree) { - TypeTag typeTag = typeTag(tree); - try { - if (CTC_INT.equals(typeTag)) print(tree.value.toString()); - else if (CTC_LONG.equals(typeTag)) print(tree.value + "L"); - else if (CTC_FLOAT.equals(typeTag)) print(tree.value + "F"); - else if (CTC_DOUBLE.equals(typeTag)) print(tree.value.toString()); - else if (CTC_CHAR.equals(typeTag)) { - print("\'" + quoteChar((char)((Number)tree.value).intValue()) + "\'"); - } - else if (CTC_BOOLEAN.equals(typeTag)) print(((Number)tree.value).intValue() == 1 ? "true" : "false"); - else if (CTC_BOT.equals(typeTag)) print("null"); - else print("\"" + quoteChars(tree.value.toString()) + "\""); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public static String quoteChars(String s) { - StringBuilder buf = new StringBuilder(); - for (int i = 0; i < s.length(); i++) { - buf.append(quoteChar(s.charAt(i))); - } - return buf.toString(); - } - - /** - * Escapes a character if it has an escape sequence or is non-printable - * ASCII. Leaves non-ASCII characters alone. - */ - public static String quoteChar(char ch) { - switch (ch) { - case '\b': - return "\\b"; - case '\f': - return "\\f"; - case '\n': - return "\\n"; - case '\r': - return "\\r"; - case '\t': - return "\\t"; - case '\'': - return "\\'"; - case '\"': - return "\\\""; - case '\\': - return "\\\\"; - default: - return ch < 32 ? String.format("\\%03o", (int) ch) : String.valueOf(ch); - } - } - - public void visitTypeIdent(JCPrimitiveTypeTree tree) { - TypeTag typetag = typeTag(tree); - try { - if (CTC_BYTE.equals(typetag)) print ("byte"); - else if (CTC_CHAR.equals(typetag)) print ("char"); - else if (CTC_SHORT.equals(typetag)) print ("short"); - else if (CTC_INT.equals(typetag)) print ("int"); - else if (CTC_LONG.equals(typetag)) print ("long"); - else if (CTC_FLOAT.equals(typetag)) print ("float"); - else if (CTC_DOUBLE.equals(typetag)) print ("double"); - else if (CTC_BOOLEAN.equals(typetag)) print ("boolean"); - else if (CTC_VOID.equals(typetag)) print ("void"); - else print("error"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitTypeArray(JCArrayTypeTree tree) { - try { - printBaseElementType(tree); - printBrackets(tree); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - // Prints the inner element type of a nested array - private void printBaseElementType(JCArrayTypeTree tree) throws IOException { - JCTree elem = tree.elemtype; - while (elem instanceof JCWildcard) - elem = ((JCWildcard) elem).inner; - if (elem instanceof JCArrayTypeTree) - printBaseElementType((JCArrayTypeTree) elem); - else - printExpr(elem); - } - - // prints the brackets of a nested array in reverse order - private void printBrackets(JCArrayTypeTree tree) throws IOException { - JCTree elem; - while (true) { - elem = tree.elemtype; - print("[]"); - if (!(elem instanceof JCArrayTypeTree)) break; - tree = (JCArrayTypeTree) elem; - } - } - - public void visitTypeApply(JCTypeApply tree) { - try { - printExpr(tree.clazz); - print("<"); - printExprs(tree.arguments); - print(">"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitTypeParameter(JCTypeParameter tree) { - try { - List<JCExpression> annotations = readExpressionListOrNil(tree, "annotations"); - if (!annotations.isEmpty()) { - printExprs(annotations); - print(" "); - } - print(tree.name); - if (tree.bounds.nonEmpty()) { - print(" extends "); - printExprs(tree.bounds, " & "); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public void visitWildcard(JCWildcard tree) { - try { - Object kind = tree.getClass().getField("kind").get(tree); - print(kind); - if (kind != null && kind.getClass().getSimpleName().equals("TypeBoundKind")) { - kind = kind.getClass().getField("kind").get(kind); - } - - if (tree.getKind() != Tree.Kind.UNBOUNDED_WILDCARD) - printExpr(tree.inner); - } catch (IOException e) { - throw new UncheckedIOException(e); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - public void visitTypeBoundKind(TypeBoundKind tree) { - try { - print(String.valueOf(tree.kind)); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitErroneous(JCErroneous tree) { - try { - print("(ERROR)"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitLetExpr(LetExpr tree) { - try { - print("(let " + tree.defs + " in " + tree.expr + ")"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitModifiers(JCModifiers mods) { - try { - printAnnotations(mods.annotations); - printFlags(mods.flags); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitAnnotation(JCAnnotation tree) { - try { - print("@"); - printExpr(tree.annotationType); - if (tree.args.nonEmpty()) { - print("("); - if (tree.args.length() == 1 && tree.args.get(0) instanceof JCAssign) { - JCExpression lhs = ((JCAssign)tree.args.get(0)).lhs; - if (lhs instanceof JCIdent && ((JCIdent)lhs).name.toString().equals("value")) tree.args = List.of(((JCAssign)tree.args.get(0)).rhs); - } - printExprs(tree.args); - print(")"); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitTree(JCTree tree) { - try { - String simpleName = tree.getClass().getSimpleName(); - if ("JCTypeUnion".equals(simpleName)) { - printExprs(readExpressionList(tree, "alternatives"), " | "); - return; - } else if ("JCTypeIntersection".equals(simpleName)) { - printExprs(readExpressionList(tree, "bounds"), " & "); - return; - } else if ("JCLambda".equals(simpleName)) { - visitLambda0(tree); - return; - } else if ("JCMemberReference".equals(simpleName)) { - visitReference0(tree); - return; - } else if ("JCAnnotatedType".equals(simpleName)) { - visitAnnotatedType0(tree); - } else { - print("(UNKNOWN[" + tree.getClass().getSimpleName() + "]: " + tree + ")"); - println(); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private void visitLambda0(JCTree tree) { - try { - @SuppressWarnings("unchecked") - List<JCVariableDecl> params = (List<JCVariableDecl>) readTreeList(tree, "params"); - boolean explicit = true; - int paramLength = params.size(); - if (paramLength != 1) print("("); - try { - explicit = readObject(tree, "paramKind").toString().equals("EXPLICIT"); - } catch (Exception e) {} - if (explicit) { - printExprs(params); - } else { - String sep = ""; - for (JCVariableDecl param : params) { - print(sep); - print(param.name); - sep = ", "; - } - } - if (paramLength != 1) print(")"); - print(" -> "); - printExpr(readTree(tree, "body")); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - - public void visitReference0(JCTree tree) { - try { - printExpr(readTree(tree, "expr")); - print("::"); - List<JCExpression> typeArgs = readExpressionList(tree, "typeargs"); - if (typeArgs != null) { - print("<"); - printExprs(typeArgs); - print(">"); - } - print(readObject(tree, "mode").toString().equals("INVOKE") ? readObject(tree, "name") : "new"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - public void visitAnnotatedType0(JCTree tree) { - try { - JCTree underlyingType = readTree(tree, "underlyingType"); - if (underlyingType instanceof JCFieldAccess) { - printExpr(((JCFieldAccess) underlyingType).selected); - print("."); - printExprs(readExpressionList(tree, "annotations")); - print(" "); - print(((JCFieldAccess) underlyingType).name); - } else { - printExprs(readExpressionList(tree, "annotations")); - print(" "); - printExpr(underlyingType); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private JCTree readTree(JCTree tree, String fieldName) { - try { - return (JCTree) readObject0(tree, fieldName); - } catch (Exception e) { - return null; - } - } - - @SuppressWarnings("unchecked") - private List<? extends JCTree> readTreeList(JCTree tree, String fieldName) throws IOException { - try { - return (List<? extends JCTree>) readObject0(tree, fieldName); - } catch (Exception e) { - return List.nil(); - } - } - - @SuppressWarnings("unchecked") - private List<JCExpression> readExpressionList(JCTree tree, String fieldName) throws IOException { - try { - return (List<JCExpression>) readObject0(tree, fieldName); - } catch (Exception e) { - return List.nil(); - } - } - - @SuppressWarnings("unchecked") - private List<JCExpression> readExpressionListOrNil(JCTree tree, String fieldName) throws IOException { - try { - return (List<JCExpression>) readObject0(tree, fieldName, List.nil()); - } catch (Exception e) { - return List.nil(); - } - } - - private Object readObject(JCTree tree, String fieldName) { - try { - return readObject0(tree, fieldName); - } catch (Exception e) { - return null; - } - } - - @SuppressWarnings("unchecked") - private Object readObject0(JCTree tree, String fieldName) throws Exception { - try { - return tree.getClass().getDeclaredField(fieldName).get(tree); - } catch (Exception e) { - print("ERROR_READING_FIELD"); - throw e; - } - } - - @SuppressWarnings("unchecked") - private Object readObject0(JCTree tree, String fieldName, Object defaultValue) throws Exception { - try { - return tree.getClass().getDeclaredField(fieldName).get(tree); - } catch (Exception e) { - return defaultValue; - } - } -} diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java new file mode 100644 index 00000000..d3b65cb8 --- /dev/null +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -0,0 +1,1488 @@ +package lombok.delombok; + +import static com.sun.tools.javac.code.Flags.*; +import static lombok.javac.Javac.*; +import static lombok.javac.JavacTreeMaker.TreeTag.treeTag; +import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; + +import java.io.IOException; +import java.io.Writer; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import com.sun.tools.javac.tree.DocCommentTable; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCArrayAccess; +import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; +import com.sun.tools.javac.tree.JCTree.JCAssert; +import com.sun.tools.javac.tree.JCTree.JCAssign; +import com.sun.tools.javac.tree.JCTree.JCAssignOp; +import com.sun.tools.javac.tree.JCTree.JCBinary; +import com.sun.tools.javac.tree.JCTree.JCBlock; +import com.sun.tools.javac.tree.JCTree.JCBreak; +import com.sun.tools.javac.tree.JCTree.JCCase; +import com.sun.tools.javac.tree.JCTree.JCCatch; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCConditional; +import com.sun.tools.javac.tree.JCTree.JCContinue; +import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop; +import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; +import com.sun.tools.javac.tree.JCTree.JCErroneous; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCExpressionStatement; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import com.sun.tools.javac.tree.JCTree.JCForLoop; +import com.sun.tools.javac.tree.JCTree.JCIdent; +import com.sun.tools.javac.tree.JCTree.JCIf; +import com.sun.tools.javac.tree.JCTree.JCImport; +import com.sun.tools.javac.tree.JCTree.JCInstanceOf; +import com.sun.tools.javac.tree.JCTree.JCLabeledStatement; +import com.sun.tools.javac.tree.JCTree.JCLiteral; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.JCModifiers; +import com.sun.tools.javac.tree.JCTree.JCNewArray; +import com.sun.tools.javac.tree.JCTree.JCNewClass; +import com.sun.tools.javac.tree.JCTree.JCParens; +import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree; +import com.sun.tools.javac.tree.JCTree.JCReturn; +import com.sun.tools.javac.tree.JCTree.JCSkip; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCSwitch; +import com.sun.tools.javac.tree.JCTree.JCSynchronized; +import com.sun.tools.javac.tree.JCTree.JCThrow; +import com.sun.tools.javac.tree.JCTree.JCTry; +import com.sun.tools.javac.tree.JCTree.JCTypeApply; +import com.sun.tools.javac.tree.JCTree.JCTypeCast; +import com.sun.tools.javac.tree.JCTree.JCTypeParameter; +import com.sun.tools.javac.tree.JCTree.JCUnary; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.JCTree.JCWhileLoop; +import com.sun.tools.javac.tree.JCTree.JCWildcard; +import com.sun.tools.javac.tree.JCTree.TypeBoundKind; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Position; + +import lombok.javac.CommentInfo; +import lombok.javac.CommentInfo.EndConnection; +import lombok.javac.CommentInfo.StartConnection; +import lombok.javac.JavacTreeMaker.TreeTag; +import lombok.javac.JavacTreeMaker.TypeTag; + +public class PrettyPrinter extends JCTree.Visitor { + private static final String LINE_SEP = System.getProperty("line.separator"); + private static final Map<TreeTag, String> OPERATORS; + + static { + Map<TreeTag, String> map = new HashMap<TreeTag, String>(); + + map.put(treeTag("POS"), "+"); + map.put(treeTag("NEG"), "-"); + map.put(treeTag("NOT"), "!"); + map.put(treeTag("COMPL"), "~"); + map.put(treeTag("PREINC"), "++"); + map.put(treeTag("PREDEC"), "--"); + map.put(treeTag("POSTINC"), "++"); + map.put(treeTag("POSTDEC"), "--"); + map.put(treeTag("NULLCHK"), "<*nullchk*>"); + map.put(treeTag("OR"), "||"); + map.put(treeTag("AND"), "&&"); + map.put(treeTag("EQ"), "=="); + map.put(treeTag("NE"), "!="); + map.put(treeTag("LT"), "<"); + map.put(treeTag("GT"), ">"); + map.put(treeTag("LE"), "<="); + map.put(treeTag("GE"), ">="); + map.put(treeTag("BITOR"), "|"); + map.put(treeTag("BITXOR"), "^"); + map.put(treeTag("BITAND"), "&"); + map.put(treeTag("SL"), "<<"); + map.put(treeTag("SR"), ">>"); + map.put(treeTag("USR"), ">>>"); + map.put(treeTag("PLUS"), "+"); + map.put(treeTag("MINUS"), "-"); + map.put(treeTag("MUL"), "*"); + map.put(treeTag("DIV"), "/"); + map.put(treeTag("MOD"), "%"); + + map.put(treeTag("BITOR_ASG"), "|="); + map.put(treeTag("BITXOR_ASG"), "^="); + map.put(treeTag("BITAND_ASG"), "&="); + map.put(treeTag("SL_ASG"), "<<="); + map.put(treeTag("SR_ASG"), ">>="); + map.put(treeTag("USR_ASG"), ">>>="); + map.put(treeTag("PLUS_ASG"), "+="); + map.put(treeTag("MINUS_ASG"), "-="); + map.put(treeTag("MUL_ASG"), "*="); + map.put(treeTag("DIV_ASG"), "/="); + map.put(treeTag("MOD_ASG"), "%="); + + OPERATORS = map; + } + + private final Writer out; + private final JCCompilationUnit compilationUnit; + private List<CommentInfo> comments; + private final FormatPreferences formatPreferences; + + private final Map<JCTree, String> docComments; + private final DocCommentTable docTable; + private int indent = 0; + + @SuppressWarnings({"unchecked", "rawtypes"}) + public PrettyPrinter(Writer out, JCCompilationUnit cu, List<CommentInfo> comments, FormatPreferences preferences) { + this.out = out; + this.comments = comments; + this.compilationUnit = cu; + this.formatPreferences = preferences; + + /* load doc comments */ { + Object dc = getDocComments(compilationUnit); + if (dc instanceof Map<?, ?>) { + this.docComments = (Map) dc; + this.docTable = null; + } else if (dc instanceof DocCommentTable) { + this.docComments = null; + this.docTable = (DocCommentTable) dc; + } else { + this.docComments = null; + this.docTable = null; + } + } + } + + private int endPos(JCTree tree) { + return getEndPosition(tree, compilationUnit); + } + + private static int lineEndPos(String s, int start) { + int pos = s.indexOf('\n', start); + if (pos < 0) pos = s.length(); + return pos; + } + + private boolean needsAlign, needsNewLine, onNewLine = true, needsSpace, aligned; + + public static final class UncheckedIOException extends RuntimeException { + UncheckedIOException(IOException source) { + super(toMsg(source)); + setStackTrace(source.getStackTrace()); + } + + private static String toMsg(Throwable t) { + String msg = t.getMessage(); + String n = t.getClass().getSimpleName(); + if (msg == null || msg.isEmpty()) return n; + return n + ": " + msg; + } + } + + private void align() { + if (!onNewLine) return; + try { + for (int i = 0; i < indent; i++) out.write(formatPreferences.indent()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + onNewLine = false; + aligned = true; + needsAlign = false; + } + + private void print(JCTree tree) { + if (tree == null) { + print("/*missing*/"); + return; + } + + consumeComments(tree); + tree.accept(this); + consumeTrailingComments(endPos(tree)); + } + + private void print(List<? extends JCTree> trees, String infix) { + boolean first = true; + JCTree prev = null; + for (JCTree tree : trees) { + if (suppress(tree)) continue; + if (!first && infix != null && !infix.isEmpty()) { + if ("\n".equals(infix)) println(prev); + else print(infix); + } + first = false; + print(tree); + prev = tree; + } + } + + private boolean suppress(JCTree tree) { + if (tree instanceof JCBlock) { + JCBlock block = (JCBlock) tree; + return (Position.NOPOS == block.pos) && block.stats.isEmpty(); + } + + if (tree instanceof JCExpressionStatement) { + JCExpression expr = ((JCExpressionStatement)tree).expr; + if (expr instanceof JCMethodInvocation) { + JCMethodInvocation inv = (JCMethodInvocation) expr; + if (!inv.typeargs.isEmpty() || !inv.args.isEmpty()) return false; + if (!(inv.meth instanceof JCIdent)) return false; + return ((JCIdent) inv.meth).name.toString().equals("super"); + } + } + + return false; + } + + private void print(CharSequence s) { + boolean align = needsAlign; + if (needsNewLine && !onNewLine) println(); + if (align && !aligned) align(); + try { + if (needsSpace && !onNewLine && !aligned) out.write(' '); + out.write(s.toString()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + needsSpace = false; + onNewLine = false; + aligned = false; + } + + + private void println() { + try { + out.write(LINE_SEP); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + onNewLine = true; + aligned = false; + needsNewLine = false; + } + + private void println(JCTree completed) { + if (completed != null) { + int endPos = endPos(completed); + consumeTrailingComments(endPos); + } + try { + out.write(LINE_SEP); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + onNewLine = true; + aligned = false; + needsNewLine = false; + } + + private void println(CharSequence s) { + print(s); + println(); + } + + private void println(CharSequence s, JCTree completed) { + print(s); + println(completed); + } + + private void aPrint(CharSequence s) { + align(); + print(s); + } + + private void aPrintln(CharSequence s) { + align(); + print(s); + println(); + } + + private void aPrintln(CharSequence s, JCTree completed) { + align(); + print(s); + println(completed); + } + + private void consumeComments(int until) { + CommentInfo head = comments.head; + while (comments.nonEmpty() && head.pos < until) { + printComment(head); + comments = comments.tail; + head = comments.head; + } + } + + private void consumeComments(JCTree tree) { + consumeComments(tree.pos); + } + + private void consumeTrailingComments(int from) { + boolean prevNewLine = onNewLine; + CommentInfo head = comments.head; + boolean stop = false; + + while (comments.nonEmpty() && head.prevEndPos == from && !stop && !(head.start == StartConnection.ON_NEXT_LINE || head.start == StartConnection.START_OF_LINE)) { + from = head.endPos; + printComment(head); + stop = (head.end == EndConnection.ON_NEXT_LINE); + comments = comments.tail; + head = comments.head; + } + + if (!onNewLine && prevNewLine) { + println(); + } + } + + private String getJavadocFor(JCTree node) { + if (docComments != null) return docComments.get(node); + if (docTable != null) return docTable.getCommentText(node); + return null; + } + + private int dims(JCExpression vartype) { + if (vartype instanceof JCArrayTypeTree) { + return 1 + dims(((JCArrayTypeTree) vartype).elemtype); + } + + return 0; + } + + private void printComment(CommentInfo comment) { + switch (comment.start) { + case DIRECT_AFTER_PREVIOUS: + needsSpace = false; + break; + case AFTER_PREVIOUS: + needsSpace = true; + break; + case START_OF_LINE: + needsNewLine = true; + needsAlign = false; + break; + case ON_NEXT_LINE: + if (!onNewLine) { + needsNewLine = true; + needsAlign = true; + } else if (!aligned) { + needsAlign = true; + } + break; + } + + if (onNewLine && !aligned && comment.start != StartConnection.START_OF_LINE) needsAlign = true; + + print(comment.content); + + switch (comment.end) { + case ON_NEXT_LINE: + if (!aligned) { + needsNewLine = true; + needsAlign = true; + } + break; + case AFTER_COMMENT: + needsSpace = true; + break; + case DIRECT_AFTER_COMMENT: + // do nothing + break; + } + } + + private void printDocComment(JCTree tree) { + String dc = getJavadocFor(tree); + if (dc == null) return; + aPrintln("/**"); + int pos = 0; + int endpos = lineEndPos(dc, pos); + boolean atStart = true; + while (pos < dc.length()) { + String line = dc.substring(pos, endpos); + if (line.trim().isEmpty() && atStart) { + atStart = false; + continue; + } + atStart = false; + aPrint(" *"); + if (pos < dc.length() && dc.charAt(pos) > ' ') print(" "); + println(dc.substring(pos, endpos)); + pos = endpos + 1; + endpos = lineEndPos(dc, pos); + } + aPrintln(" */"); + } + + private Name __INIT__, __VALUE__; + private Name name_init(Name someName) { + if (__INIT__ == null) __INIT__ = someName.table.fromChars("<init>".toCharArray(), 0, 6); + return __INIT__; + } + private Name name_value(Name someName) { + if (__VALUE__ == null) __VALUE__ = someName.table.fromChars("value".toCharArray(), 0, 5); + return __VALUE__; + } + + @Override public void visitTopLevel(JCCompilationUnit tree) { + printDocComment(tree); + if (tree.pid != null) { + consumeComments(tree); + aPrint("package "); + print(tree.pid); + println(";", tree.pid); + } + + boolean first = true; + + for (JCTree child : tree.defs) { + if (!(child instanceof JCImport)) continue; + if (first) println(); + first = false; + print(child); + } + + for (JCTree child : tree.defs) { + if (child instanceof JCImport) continue; + print(child); + } + consumeComments(Integer.MAX_VALUE); + } + + @Override public void visitImport(JCImport tree) { + aPrint("import "); + if (tree.staticImport) print("static "); + print(tree.qualid); + println(";", tree); + } + + private Name currentTypeName; + @Override public void visitClassDef(JCClassDecl tree) { + println(); + printDocComment(tree); + align(); + print(tree.mods); + + boolean isInterface = (tree.mods.flags & INTERFACE) != 0; + boolean isAnnotationInterface = isInterface && (tree.mods.flags & ANNOTATION) != 0; + boolean isEnum = (tree.mods.flags & ENUM) != 0; + + if (isAnnotationInterface) print("@interface "); + else if (isInterface) print("interface "); + else if (isEnum) print("enum "); + else print("class "); + + print(tree.name); + Name prevTypeName = currentTypeName; + currentTypeName = tree.name; + + if (tree.typarams.nonEmpty()) { + print("<"); + print(tree.typarams, ", "); + print(">"); + } + JCTree extendsClause = getExtendsClause(tree); + if (extendsClause != null) { + print(" extends "); + print(extendsClause); + } + + if (tree.implementing.nonEmpty()) { + print(isInterface ? " extends " : " implements "); + print(tree.implementing, ", "); + } + + println(" {"); + indent++; + printClassMembers(tree.defs, isEnum, isInterface); + consumeComments(endPos(tree)); + indent--; + aPrintln("}", tree); + currentTypeName = prevTypeName; + } + + private void printClassMembers(List<JCTree> members, boolean isEnum, boolean isInterface) { + Class<?> prefType = null; + int typeOfPrevEnumMember = isEnum ? 3 : 0; // 1 = normal, 2 = with body, 3 = no enum field yet. + boolean prevWasEnumMember = isEnum; + + for (JCTree member : members) { + if (typeOfPrevEnumMember == 3 && member instanceof JCMethodDecl && (((JCMethodDecl) member).mods.flags & GENERATEDCONSTR) != 0) continue; + boolean isEnumVar = isEnum && member instanceof JCVariableDecl && (((JCVariableDecl) member).mods.flags & ENUM) != 0; + if (!isEnumVar && prevWasEnumMember) { + prevWasEnumMember = false; + if (typeOfPrevEnumMember == 3) align(); + println(";"); + } + + if (isEnumVar) { + if (prefType != null && prefType != JCVariableDecl.class) println(); + switch (typeOfPrevEnumMember) { + case 1: + print(", "); + break; + case 2: + println(","); + align(); + break; + } + print(member); + JCTree init = ((JCVariableDecl) member).init; + typeOfPrevEnumMember = init instanceof JCNewClass && ((JCNewClass) init).def != null ? 2 : 1; + } else if (member instanceof JCVariableDecl) { + if (prefType != null && prefType != JCVariableDecl.class) println(); + if (isInterface) flagMod = -1L & ~(PUBLIC | STATIC | FINAL); + print(member); + } else if (member instanceof JCMethodDecl) { + if ((((JCMethodDecl) member).mods.flags & GENERATEDCONSTR) != 0) continue; + if (prefType != null) println(); + if (isInterface) flagMod = -1L & ~(PUBLIC | ABSTRACT); + print(member); + } else if (member instanceof JCClassDecl) { + if (prefType != null) println(); + if (isInterface) flagMod = -1L & ~(PUBLIC | STATIC); + print(member); + } else { + if (prefType != null) println(); + print(member); + } + + prefType = member.getClass(); + } + + if (prevWasEnumMember) { + prevWasEnumMember = false; + if (typeOfPrevEnumMember == 3) align(); + println(";"); + } + } + + @Override public void visitTypeParameter(JCTypeParameter tree) { + List<JCExpression> annotations = readObject(tree, "annotations", List.<JCExpression>nil()); + if (!annotations.isEmpty()) { + print(annotations, " "); + print(" "); + } + print(tree.name); + if (tree.bounds.nonEmpty()) { + print(" extends "); + print(tree.bounds, " & "); + } + consumeComments(tree); + } + + @Override public void visitVarDef(JCVariableDecl tree) { + printDocComment(tree); + align(); + if ((tree.mods.flags & ENUM) != 0) { + printEnumMember(tree); + return; + } + printAnnotations(tree.mods.annotations, true); + printModifierKeywords(tree.mods); + printVarDef0(tree); + println(";", tree); + } + + private void printVarDefInline(JCVariableDecl tree) { + printAnnotations(tree.mods.annotations, false); + printModifierKeywords(tree.mods); + printVarDef0(tree); + } + + private void printVarDef0(JCVariableDecl tree) { + boolean varargs = (tree.mods.flags & VARARGS) != 0; + if (varargs && tree.vartype instanceof JCArrayTypeTree) { + print(((JCArrayTypeTree) tree.vartype).elemtype); + print("..."); + } else { + print(tree.vartype); + } + print(" "); + print(tree.name); + if (tree.init != null) { + print(" = "); + print(tree.init); + } + } + + private void printEnumMember(JCVariableDecl tree) { + printAnnotations(tree.mods.annotations, true); + print(tree.name); + if (tree.init instanceof JCNewClass) { + JCNewClass constructor = (JCNewClass) tree.init; + if (constructor.args != null && constructor.args.nonEmpty()) { + print("("); + print(constructor.args, ", "); + print(")"); + } + + if (constructor.def != null && constructor.def.defs != null) { + println(" {"); + indent++; + printClassMembers(constructor.def.defs, false, false); + consumeComments(endPos(tree)); + indent--; + aPrint("}"); + } + } + } + + // TODO: Test postfix syntax for methods (?), for decls. Multiline vardefs, possibly with comments. enums with bodies. constructor-local generics, method-local generics, also do/while, finally, try-with-resources, lambdas, annotations in java8 places... + // TODO: Whatever is JCAnnotatedType? We handle it in the 7+ bucket in the old one... + + @Override public void visitTypeApply(JCTypeApply tree) { + print(tree.clazz); + print("<"); + print(tree.arguments, ", "); + print(">"); + } + + @Override public void visitWildcard(JCWildcard tree) { + switch (tree.getKind()) { + default: + case UNBOUNDED_WILDCARD: + print("?"); + return; + case EXTENDS_WILDCARD: + print("? extends "); + print(tree.inner); + return; + case SUPER_WILDCARD: + print("? super "); + print(tree.inner); + return; + } + } + + @Override public void visitLiteral(JCLiteral tree) { + TypeTag typeTag = typeTag(tree); + if (CTC_INT.equals(typeTag)) print("" + tree.value); + else if (CTC_LONG.equals(typeTag)) print(tree.value + "L"); + else if (CTC_FLOAT.equals(typeTag)) print(tree.value + "F"); + else if (CTC_DOUBLE.equals(typeTag)) print("" + tree.value); + else if (CTC_CHAR.equals(typeTag)) { + print("\'" + quoteChar((char)((Number)tree.value).intValue()) + "\'"); + } + else if (CTC_BOOLEAN.equals(typeTag)) print(((Number)tree.value).intValue() == 1 ? "true" : "false"); + else if (CTC_BOT.equals(typeTag)) print("null"); + else print("\"" + quoteChars(tree.value.toString()) + "\""); + } + + @Override public void visitMethodDef(JCMethodDecl tree) { + boolean isConstructor = tree.name == name_init(tree.name); + if (isConstructor && (tree.mods.flags & GENERATEDCONSTR) != 0) return; + printDocComment(tree); + align(); + print(tree.mods); + if (tree.typarams != null && tree.typarams.nonEmpty()) { + print("<"); + print(tree.typarams, ", "); + print("> "); + } + + if (isConstructor) { + print(currentTypeName == null ? "<init>" : currentTypeName); + } else { + print(tree.restype); + print(" "); + print(tree.name); + } + + print("("); + boolean first = true; + for (JCVariableDecl param : tree.params) { + if (!first) print(", "); + first = false; + printVarDefInline(param); + } + print(")"); + + if (tree.thrown.nonEmpty()) { + print(" throws "); + print(tree.thrown, ", "); + } + + if (tree.defaultValue != null) { + print(" default "); + print(tree.defaultValue); + } + + if (tree.body != null) { + print(" "); + print(tree.body); + } else println(";", tree); + } + + @Override public void visitSkip(JCSkip that) { + if (onNewLine && !aligned) { + align(); + } + println(";"); + } + + @Override public void visitAnnotation(JCAnnotation tree) { + print("@"); + print(tree.annotationType); + if (tree.args.isEmpty()) return; + print("("); + boolean done = false; + if (tree.args.length() == 1 && tree.args.get(0) instanceof JCAssign) { + JCAssign arg1 = (JCAssign) tree.args.get(0); + JCIdent arg1Name = arg1.lhs instanceof JCIdent ? ((JCIdent) arg1.lhs) : null; + if (arg1Name != null && arg1Name.name == name_value(arg1Name.name)) { + print(arg1.rhs); + done = true; + } + } + if (!done) print(tree.args, ", "); + print(")"); + } + + @Override public void visitTypeArray(JCArrayTypeTree tree) { + JCTree elem = tree.elemtype; + while (elem instanceof JCWildcard) elem = ((JCWildcard) elem).inner; + print(elem); + print("[]"); + } + + @Override public void visitNewArray(JCNewArray tree) { + JCTree elem = tree.elemtype; + int dims = 0; + if (elem != null) { + print("new "); + + while (elem instanceof JCArrayTypeTree) { + dims++; + elem = ((JCArrayTypeTree) elem).elemtype; + } + print(elem); + + for (JCExpression expr : tree.dims) { + print("["); + print(expr); + print("]"); + } + } + + for (int i = 0; i < dims; i++) print("[]"); + + if (tree.elems != null) { + if (elem != null) print("[] "); + print("{"); + print(tree.elems, ", "); + print("}"); + } + } + + @Override public void visitNewClass(JCNewClass tree) { + if (tree.encl != null) { + print(tree.encl); + print("."); + } + + print("new "); + if (!tree.typeargs.isEmpty()) { + print("<"); + print(tree.typeargs, ", "); + print(">"); + } + print(tree.clazz); + print("("); + print(tree.args, ", "); + print(")"); + if (tree.def != null) { + Name previousTypeName = currentTypeName; + currentTypeName = null; + println(" {"); + indent++; + print(tree.def.defs, ""); + indent--; + aPrint("}"); + currentTypeName = previousTypeName; + } + } + + @Override public void visitIndexed(JCArrayAccess tree) { + print(tree.indexed); + print("["); + print(tree.index); + print("]"); + } + + @Override public void visitTypeIdent(JCPrimitiveTypeTree tree) { + TypeTag typeTag = typeTag(tree); + + if (CTC_BYTE.equals(typeTag)) print("byte"); + else if (CTC_CHAR.equals(typeTag)) print("char"); + else if (CTC_SHORT.equals(typeTag)) print("short"); + else if (CTC_INT.equals(typeTag)) print("int"); + else if (CTC_LONG.equals(typeTag)) print("long"); + else if (CTC_FLOAT.equals(typeTag)) print("float"); + else if (CTC_DOUBLE.equals(typeTag)) print("double"); + else if (CTC_BOOLEAN.equals(typeTag)) print("boolean"); + else if (CTC_VOID.equals(typeTag)) print("void"); + else print("error"); + } + + @Override public void visitLabelled(JCLabeledStatement tree) { + aPrint(tree.label); + print(":"); + if (tree.body instanceof JCSkip || suppress(tree)) { + println(" ;", tree); + } else if (tree.body instanceof JCBlock) { + print(" "); + print(tree.body); + } else { + println(tree); + print(tree.body); + } + } + + private long flagMod = -1L; + private static final long DEFAULT = 1L<<43; + + @Override public void visitModifiers(JCModifiers tree) { + printAnnotations(tree.annotations, true); + printModifierKeywords(tree); + } + + private void printAnnotations(List<JCAnnotation> annotations, boolean newlines) { + for (JCAnnotation ann : annotations) { + print(ann); + if (newlines) { + println(); + align(); + } else print(" "); + } + } + + private void printModifierKeywords(JCModifiers tree) { + long v = flagMod & tree.flags; + flagMod = -1L; + + if ((v & SYNTHETIC) != 0) print("/* synthetic */ "); + if ((v & PUBLIC) != 0) print("public "); + if ((v & PRIVATE) != 0) print("private "); + if ((v & PROTECTED) != 0) print("protected "); + if ((v & STATIC) != 0) print("static "); + if ((v & FINAL) != 0) print("final "); + if ((v & SYNCHRONIZED) != 0) print("synchronized "); + if ((v & VOLATILE) != 0) print("volatile "); + if ((v & TRANSIENT) != 0) print("transient "); + if ((v & NATIVE) != 0) print("native "); + if ((v & ABSTRACT) != 0) print("abstract "); + if ((v & STRICTFP) != 0) print("strictfp "); + if ((v & DEFAULT) != 0 && (v & INTERFACE) == 0) print("default "); + } + + @Override public void visitSelect(JCFieldAccess tree) { + print(tree.selected); + print("."); + print(tree.name); + } + + @Override public void visitIdent(JCIdent tree) { + print(tree.name); + } + + @Override public void visitApply(JCMethodInvocation tree) { + if (tree.typeargs.nonEmpty()) { + if (tree.meth instanceof JCFieldAccess) { + JCFieldAccess fa = (JCFieldAccess) tree.meth; + print(fa.selected); + print(".<"); + print(tree.typeargs, ", "); + print(">"); + print(fa.name); + } else { + print("<"); + print(tree.typeargs, ", "); + print(">"); + print(tree.meth); + } + } else { + print(tree.meth); + } + + print("("); + print(tree.args, ", "); + print(")"); + } + + @Override public void visitAssert(JCAssert tree) { + aPrint("assert "); + print(tree.cond); + if (tree.detail != null) { + print(" : "); + print(tree.detail); + } + println(";", tree); + } + + @Override public void visitAssign(JCAssign tree) { + print(tree.lhs); + print(" = "); + print(tree.rhs); + } + + @Override public void visitAssignop(JCAssignOp tree) { + print(tree.lhs); + String opname = operator(treeTag(tree)); + print(" " + opname + " "); + print(tree.rhs); + } + + private static final int PREFIX = 14; + + @Override public void visitUnary(JCUnary tree) { + String op = operator(treeTag(tree)); + if (treeTag(tree).getOperatorPrecedenceLevel() == PREFIX) { + print(op); + print(tree.arg); + } else { + print(tree.arg); + print(op); + } + } + + @Override public void visitBinary(JCBinary tree) { + String op = operator(treeTag(tree)); + print(tree.lhs); + print(" "); + print(op); + print(" "); + print(tree.rhs); + } + + @Override public void visitTypeTest(JCInstanceOf tree) { + print(tree.expr); + print(" instanceof "); + print(tree.clazz); + } + + @Override public void visitTypeCast(JCTypeCast tree) { + print("("); + print(tree.clazz); + print(") "); + print(tree.expr); + } + + @Override public void visitBlock(JCBlock tree) { + if (tree.pos == Position.NOPOS && tree.stats.isEmpty()) return; + if (onNewLine) align(); + if ((tree.flags & STATIC) != 0) print("static "); + println("{"); + indent++; + print(tree.stats, ""); + consumeComments(endPos(tree)); + indent--; + aPrintln("}", tree); + } + + @Override public void visitBreak(JCBreak tree) { + aPrint("break"); + if (tree.label != null) { + print(" "); + print(tree.label); + } + println(";", tree); + } + + @Override public void visitContinue(JCContinue tree) { + aPrint("continue"); + if (tree.label != null) { + print(" "); + print(tree.label); + } + println(";", tree); + } + + @Override public void visitConditional(JCConditional tree) { + print(tree.cond); + print(" ? "); + print(tree.truepart); + print(" : "); + print(tree.falsepart); + } + + @Override public void visitParens(JCParens tree) { + print("("); + print(tree.expr); + print(")"); + } + + @Override public void visitReturn(JCReturn tree) { + aPrint("return"); + if (tree.expr != null) { + print(" "); + print(tree.expr); + } + println(";", tree); + } + + @Override public void visitThrow(JCThrow tree) { + aPrint("throw "); + print(tree.expr); + println(";", tree); + } + + @Override public void visitWhileLoop(JCWhileLoop tree) { + aPrint("while "); + if (tree.cond instanceof JCParens) { + print(tree.cond); + } else { + print("("); + print(tree.cond); + print(")"); + } + print(" "); + print(tree.body); + // make sure to test while (true) ; and while(true){} and while(true) x = 5; + } + + @Override public void visitForLoop(JCForLoop tree) { + aPrint("for ("); + if (tree.init.nonEmpty()) { + if (tree.init.head instanceof JCVariableDecl) { + boolean first = true; + int dims = 0; + for (JCStatement i : tree.init) { + JCVariableDecl vd = (JCVariableDecl) i; + if (first) { + printVarDefInline(vd); + dims = dims(vd.vartype); + } else { + print(", "); + print(vd.name); + int dimDiff = dims(vd.vartype) - dims; + for (int j = 0; j < dimDiff; j++) print("[]"); + if (vd.init != null) { + print(" = "); + print(vd.init); + } + } + first = false; + } + } else { + print(tree.init, ", "); + } + } + print("; "); + if (tree.cond != null) print(tree.cond); + print("; "); + boolean first = true; + for (JCExpressionStatement exprStatement : tree.step) { + if (!first) print(", "); + first = false; + print(exprStatement.expr); + } + print(") "); + print(tree.body); + } + + @Override public void visitForeachLoop(JCEnhancedForLoop tree) { + aPrint("for ("); + printVarDefInline(tree.var); + print(" : "); + print(tree.expr); + print(") "); + print(tree.body); + } + + @Override public void visitIf(JCIf tree) { + aPrint("if "); + if (tree.cond instanceof JCParens) { + print(tree.cond); + } else { + print("("); + print(tree.cond); + print(")"); + } + print(" "); + if (tree.thenpart instanceof JCBlock) { + println("{"); + indent++; + print(((JCBlock) tree.thenpart).stats, ""); + indent--; + if (tree.elsepart == null) { + aPrintln("}", tree); + } else { + aPrint("}"); + } + } else { + print(tree.thenpart); + } + if (tree.elsepart != null) { + aPrint(" else "); + print(tree.elsepart); + } + } + + @Override public void visitExec(JCExpressionStatement tree) { + align(); + print(tree.expr); + println(";", tree); + } + + @Override public void visitDoLoop(JCDoWhileLoop tree) { + aPrint("do "); + if (tree.body instanceof JCBlock) { + println("{"); + indent++; + print(((JCBlock) tree.body).stats, ""); + indent--; + aPrint("}"); + + } else print(tree.body); + print(" while "); + if (tree.cond instanceof JCParens) { + print(tree.cond); + } else { + print("("); + print(tree.cond); + print(")"); + } + println(";", tree); + } + + @Override public void visitSynchronized(JCSynchronized tree) { + aPrint("synchronized "); + if (tree.lock instanceof JCParens) { + print(tree.lock); + } else { + print("("); + print(tree.lock); + print(")"); + } + print(" "); + print(tree.body); + } + + @Override public void visitCase(JCCase tree) { + if (tree.pat == null) { + aPrint("default"); + } else { + aPrint("case "); + print(tree.pat); + } + println(": "); + indent++; + print(tree.stats, ""); + indent--; + } + + @Override public void visitCatch(JCCatch tree) { + print(" catch ("); + print(tree.param); + print(") "); + print(tree.body); + } + + @Override public void visitSwitch(JCSwitch tree) { + aPrint("switch "); + if (tree.selector instanceof JCParens) { + print(tree.selector); + } else { + print("("); + print(tree.selector); + print(")"); + } + println(" {"); + print(tree.cases, "\n"); + aPrintln("}", tree); + } + + @Override public void visitTry(JCTry tree) { + aPrint("try "); + List<?> resources = readObject(tree, "resources", List.nil()); + int len = resources.length(); + switch (len) { + case 0: + break; + case 1: + print("("); + JCVariableDecl decl = (JCVariableDecl) resources.get(0); + flagMod = -1L & ~FINAL; + printVarDefInline(decl); + print(") "); + break; + default: + println("("); + indent++; + int c = 0; + for (Object i : resources) { + align(); + flagMod = -1L & ~FINAL; + printVarDefInline((JCVariableDecl) i); + if (++c == len) { + print(") "); + } else { + println(";", (JCTree) i); + } + } + indent--; + } + println("{"); + indent++; + for (JCStatement stat : tree.body.stats) print(stat); + indent--; + aPrint("}"); + for (JCCatch catchBlock : tree.catchers) { + printCatch(catchBlock); + } + if (tree.finalizer != null) { + println(" finally {"); + indent++; + for (JCStatement stat : tree.finalizer.stats) print(stat); + indent--; + aPrint("}"); + } + println(tree); + } + + private void printCatch(JCCatch catchBlock) { + print(" catch ("); + printVarDefInline(catchBlock.param); // ExprType1 | ExprType2 handled via JCTypeUnion. + println(") {"); + indent++; + for (JCStatement stat : catchBlock.body.stats) print(stat); + indent--; + aPrint("}"); + } + + public void visitErroneous(JCErroneous tree) { + print("(ERROR)"); + } + + private static String operator(TreeTag tag) { + String op = OPERATORS.get(tag); + if (op == null) return "(?op?)"; + return op; + } + + private static String quoteChars(String s) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) sb.append(quoteChar(s.charAt(i))); + return sb.toString(); + } + + private static String quoteChar(char ch) { + switch (ch) { + case '\b': return "\\b"; + case '\f': return "\\f"; + case '\n': return "\\n"; + case '\r': return "\\r"; + case '\t': return "\\t"; + case '\'': return "\\'"; + case '\"': return "\\\""; + case '\\': return "\\\\"; + default: + if (ch < 32) return String.format("\\%03o", (int) ch); + return String.valueOf(ch); + } + } + + private static final Method getExtendsClause, getEndPosition, storeEnd; + + static { + getExtendsClause = getMethod(JCClassDecl.class, "getExtendsClause", new Class<?>[0]); + getExtendsClause.setAccessible(true); + + if (getJavaCompilerVersion() < 8) { + getEndPosition = getMethod(DiagnosticPosition.class, "getEndPosition", java.util.Map.class); + storeEnd = getMethod(java.util.Map.class, "put", Object.class, Object.class); + } else { + getEndPosition = getMethod(DiagnosticPosition.class, "getEndPosition", "com.sun.tools.javac.tree.EndPosTable"); + Method storeEndMethodTemp; + Class<?> endPosTable; + try { + endPosTable = Class.forName("com.sun.tools.javac.tree.EndPosTable"); + } catch (ClassNotFoundException ex) { + throw sneakyThrow(ex); + } + try { + storeEndMethodTemp = endPosTable.getMethod("storeEnd", JCTree.class, int.class); + } catch (NoSuchMethodException e) { + try { + endPosTable = Class.forName("com.sun.tools.javac.parser.JavacParser$AbstractEndPosTable"); + storeEndMethodTemp = endPosTable.getDeclaredMethod("storeEnd", JCTree.class, int.class); + } catch (NoSuchMethodException ex) { + throw sneakyThrow(ex); + } catch (ClassNotFoundException ex) { + throw sneakyThrow(ex); + } + } + storeEnd = storeEndMethodTemp; + } + getEndPosition.setAccessible(true); + storeEnd.setAccessible(true); + } + + private static Method getMethod(Class<?> clazz, String name, Class<?>... paramTypes) { + try { + return clazz.getMethod(name, paramTypes); + } catch (NoSuchMethodException e) { + throw sneakyThrow(e); + } + } + + private static Method getMethod(Class<?> clazz, String name, String... paramTypes) { + try { + Class<?>[] c = new Class[paramTypes.length]; + for (int i = 0; i < paramTypes.length; i++) c[i] = Class.forName(paramTypes[i]); + return clazz.getMethod(name, c); + } catch (NoSuchMethodException e) { + throw sneakyThrow(e); + } catch (ClassNotFoundException e) { + throw sneakyThrow(e); + } + } + + public static JCTree getExtendsClause(JCClassDecl decl) { + try { + return (JCTree) getExtendsClause.invoke(decl); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } catch (InvocationTargetException e) { + throw sneakyThrow(e.getCause()); + } + } + + static RuntimeException sneakyThrow(Throwable t) { + if (t == null) throw new NullPointerException("t"); + PrettyPrinter.<RuntimeException>sneakyThrow0(t); + return null; + } + + @SuppressWarnings("unchecked") + private static <T extends Throwable> void sneakyThrow0(Throwable t) throws T { + throw (T)t; + } + + private static final Map<Class<?>, Map<String, Field>> reflectionCache = new HashMap<Class<?>, Map<String, Field>>(); + + @SuppressWarnings("unchecked") + private <T> T readObject(JCTree tree, String fieldName, T defaultValue) { + Class<?> tClass = tree.getClass(); + Map<String, Field> c = reflectionCache.get(tClass); + if (c == null) reflectionCache.put(tClass, c = new HashMap<String, Field>()); + Field f = c.get(fieldName); + if (f == null) { + try { + f = tClass.getDeclaredField(fieldName); + } catch (Exception e) { + return defaultValue; + } + f.setAccessible(true); + c.put(fieldName, f); + } + + try { + return (T) f.get(tree); + } catch (Exception e) { + return defaultValue; + } + } + + @Override public void visitTypeBoundKind(TypeBoundKind tree) { + print(String.valueOf(tree.kind)); + } + + @Override public void visitTree(JCTree tree) { + String simpleName = tree.getClass().getSimpleName(); + if ("JCTypeUnion".equals(simpleName)) { + List<JCExpression> types = readObject(tree, "alternatives", List.<JCExpression>nil()); + print(types, " | "); + return; + } else if ("JCTypeIntersection".equals(simpleName)) { + print(readObject(tree, "bounds", List.<JCExpression>nil()), " & "); + return; + } else if ("JCMemberReference".equals(simpleName)) { + printMemberReference0(tree); + return; + } else if ("JCLambda".equals(simpleName)) { + printLambda0(tree); + return; + } else if ("JCAnnotatedType".equals(simpleName)) { + printAnnotatedType0(tree); + return; + } + + throw new AssertionError("Unhandled tree type: " + tree.getClass() + ": " + tree); + } + + private void printMemberReference0(JCTree tree) { + print(readObject(tree, "expr", (JCExpression) null)); + print("::"); + List<JCExpression> typeArgs = readObject(tree, "typeargs", List.<JCExpression>nil()); + if (typeArgs != null && !typeArgs.isEmpty()) { + print("<"); + print(typeArgs, ", "); + print(">"); + } + print(readObject(tree, "mode", new Object()).toString().equals("INVOKE") ? readObject(tree, "name", (Name) null) : "new"); + } + + private void printLambda0(JCTree tree) { + List<JCVariableDecl> params = readObject(tree, "params", List.<JCVariableDecl>nil()); + boolean explicit = true; + int paramLength = params.size(); + if (paramLength != 1) print("("); + try { + explicit = readObject(tree, "paramKind", new Object()).toString().equals("EXPLICIT"); + } catch (Exception e) {} + if (explicit) { + boolean first = true; + for (JCVariableDecl vd : params) { + if (!first) print(", "); + first = false; + printVarDefInline(vd); + } + } else { + String sep = ""; + for (JCVariableDecl param : params) { + print(sep); + print(param.name); + sep = ", "; + } + } + if (paramLength != 1) print(")"); + print(" -> "); + JCTree body = readObject(tree, "body", (JCTree) null); + if (body instanceof JCBlock) { + println("{"); + indent++; + print(((JCBlock) body).stats, ""); + indent--; + aPrint("}"); + } else { + print(body); + } + } + + private void printAnnotatedType0(JCTree tree) { + JCTree underlyingType = readObject(tree, "underlyingType", (JCTree) null); + if (underlyingType instanceof JCFieldAccess) { + print(((JCFieldAccess) underlyingType).selected); + print("."); + print(readObject(tree, "annotations", List.<JCExpression>nil()), " "); + print(" "); + print(((JCFieldAccess) underlyingType).name); + } else { + print(readObject(tree, "annotations", List.<JCExpression>nil()), " "); + print(" "); + print(underlyingType); + } + } +} diff --git a/src/utils/lombok/eclipse/Eclipse.java b/src/utils/lombok/eclipse/Eclipse.java index c2a863d5..18b22256 100644 --- a/src/utils/lombok/eclipse/Eclipse.java +++ b/src/utils/lombok/eclipse/Eclipse.java @@ -98,15 +98,20 @@ public class Eclipse { * string containing the same fully qualified name with dots in the string. */ public static boolean nameEquals(char[][] typeName, String string) { - StringBuilder sb = new StringBuilder(); - boolean first = true; - for (char[] elem : typeName) { - if (first) first = false; - else sb.append('.'); - sb.append(elem); + int pos = 0, len = string.length(); + for (int i = 0; i < typeName.length; i++) { + char[] t = typeName[i]; + if (i > 0) { + if (pos == len) return false; + if (string.charAt(pos++) != '.') return false; + } + for (int j = 0; j < t.length; j++) { + if (pos == len) return false; + if (string.charAt(pos++) != t[j]) return false; + } } - return string.contentEquals(sb); + return true; } public static boolean hasClinit(TypeDeclaration parent) { diff --git a/test/pretty/resource/after/Cast.java b/test/pretty/resource/after/Cast.java index 95237b0f..e32150c3 100644 --- a/test/pretty/resource/after/Cast.java +++ b/test/pretty/resource/after/Cast.java @@ -1,6 +1,6 @@ import java.util.*; public class Cast { public void test(List<?> list) { - RandomAccess r = (/*before*/ RandomAccess /*after*/)list; + RandomAccess r = (/*before*/ RandomAccess /*after*/) list; } }
\ No newline at end of file diff --git a/test/pretty/resource/after/CastWithIntersection.java b/test/pretty/resource/after/CastWithIntersection.java index 2eebdee1..dc0904f6 100644 --- a/test/pretty/resource/after/CastWithIntersection.java +++ b/test/pretty/resource/after/CastWithIntersection.java @@ -1,6 +1,6 @@ import java.util.*; public class CastWithIntersection { public void test(List<?> list) { - RandomAccess r = (RandomAccess & java.io.Serializable)list; + RandomAccess r = (RandomAccess & java.io.Serializable) list; } }
\ No newline at end of file diff --git a/test/pretty/resource/after/DefaultMethod.java b/test/pretty/resource/after/DefaultMethod.java index 864ba60f..fe9594b8 100644 --- a/test/pretty/resource/after/DefaultMethod.java +++ b/test/pretty/resource/after/DefaultMethod.java @@ -3,6 +3,6 @@ interface DefaultMethod { default boolean isEmpty() { return size() == 0; } - default strictfp void run() { + strictfp default void run() { } }
\ No newline at end of file diff --git a/test/pretty/resource/after/Enum.java b/test/pretty/resource/after/Enum.java index dd738b5b..a3b2b643 100644 --- a/test/pretty/resource/after/Enum.java +++ b/test/pretty/resource/after/Enum.java @@ -1,13 +1,8 @@ enum Ranks { - CLUBS, - HEARTS, - DIAMONDS, - SPADES; + CLUBS, HEARTS, DIAMONDS, SPADES; } enum Complex { - RED("ff0000"), - GREEN("00ff00"), - BLUE("0000f"); + RED("ff0000"), GREEN("00ff00"), BLUE("0000f"); private final String webColour; Complex(String webColour) { this.webColour = webColour; diff --git a/test/pretty/resource/after/ExoticJava.java b/test/pretty/resource/after/ExoticJava.java new file mode 100644 index 00000000..fb9a9131 --- /dev/null +++ b/test/pretty/resource/after/ExoticJava.java @@ -0,0 +1,46 @@ +import static java.lang.String.*; +import java.io.*; +class ExoticJava<V> { + public <T> ExoticJava(T genericsInConstructor, V genericsInType) { + System.out.println(new <String>ExoticJava<Integer>("Hello", 5)); + } + public void test() { + int x = 5; + int[] y = {10}; + ; + class MethodLocal implements Serializable, java.util.RandomAccess { + @SuppressWarnings({"unchecked", "rawtypes"}) + public final strictfp int foo() { + int x = super.hashCode(); + x <<= 5; + do { + x <<= 5; + } while (Boolean.FALSE); + return x; + } + } + for (int i = 10, j[] = {20}; i < 5; i++, j[0]++) { + String z = ""; + try ( + PrintWriter pw = new PrintWriter(System.out); + PrintWriter p2 = new PrintWriter(System.out)) { + pw.println(); + } finally { + synchronized (z) { + System.out.println(z); + } + } + if ((y == null)) { + } + if (((y == null))) ; + { + ; + } + java.util.List<String> list = new java.util.ArrayList<>(); + assert Boolean.TRUE : "That\'s weird"; + double d = -1.8E12; + long loooong = 305441741; + int octal = 87; + } + } +}
\ No newline at end of file diff --git a/test/pretty/resource/after/Interfaces.java b/test/pretty/resource/after/Interfaces.java index 6c0a6770..f7f386c0 100644 --- a/test/pretty/resource/after/Interfaces.java +++ b/test/pretty/resource/after/Interfaces.java @@ -1,10 +1,7 @@ @SuppressWarnings("all") interface Interfaces { enum Ranks { - CLUBS, - HEARTS, - DIAMONDS, - SPADES; + CLUBS, HEARTS, DIAMONDS, SPADES; } int x = 10; void y(); diff --git a/test/pretty/resource/before/Cast.java b/test/pretty/resource/before/Cast.java index 95237b0f..e32150c3 100644 --- a/test/pretty/resource/before/Cast.java +++ b/test/pretty/resource/before/Cast.java @@ -1,6 +1,6 @@ import java.util.*; public class Cast { public void test(List<?> list) { - RandomAccess r = (/*before*/ RandomAccess /*after*/)list; + RandomAccess r = (/*before*/ RandomAccess /*after*/) list; } }
\ No newline at end of file diff --git a/test/pretty/resource/before/ExoticJava.java b/test/pretty/resource/before/ExoticJava.java new file mode 100644 index 00000000..b70b1e12 --- /dev/null +++ b/test/pretty/resource/before/ExoticJava.java @@ -0,0 +1,45 @@ +import static java.lang.String.*; + +import java.io.*; + +class ExoticJava<V> { + public <T> ExoticJava(T genericsInConstructor, V genericsInType) { + System.out.println(new <String>ExoticJava<Integer>("Hello", 5)); + } + ;;;; + public void test() { + int x = 5, y[] = {10}; + ; + class MethodLocal implements Serializable, java.util.RandomAccess { + @SuppressWarnings({"unchecked", "rawtypes"}) + strictfp public final int foo() { + int x = super.hashCode(); + x <<= 5; + do { + x <<= 5; + } while (Boolean.FALSE); + return x; + } + } + + for (int i = 10, j[] = {20}; i < 5; i++, j[0]++) { + String z = ""; + try (PrintWriter pw = new PrintWriter(System.out); PrintWriter p2 = new PrintWriter(System.out)) { + pw.println(); + } finally { + synchronized (z) { + System.out.println(z); + } + } + + if ((y == null)) {} + if (((y == null))) ; + {;} + java.util.List<String> list = new java.util.ArrayList<>(); + assert Boolean.TRUE : "That's weird"; + double d = -1.8e12; + long loooong = 0x1234ABCD; + int octal = 0127; + } + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/Accessors.java b/test/transform/resource/after-delombok/Accessors.java index 3f4698e0..a04ea171 100644 --- a/test/transform/resource/after-delombok/Accessors.java +++ b/test/transform/resource/after-delombok/Accessors.java @@ -81,8 +81,8 @@ class AccessorsPrefix3 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof AccessorsPrefix3)) return false; - final AccessorsPrefix3 other = (AccessorsPrefix3)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final AccessorsPrefix3 other = (AccessorsPrefix3) o; + if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$fName = this.getName(); final java.lang.Object other$fName = other.getName(); if (this$fName == null ? other$fName != null : !this$fName.equals(other$fName)) return false; diff --git a/test/transform/resource/after-delombok/BuilderInstanceMethod.java b/test/transform/resource/after-delombok/BuilderInstanceMethod.java new file mode 100644 index 00000000..61e237d0 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderInstanceMethod.java @@ -0,0 +1,66 @@ +import java.util.List; +class BuilderInstanceMethod<T> { + public String create(int show, final int yes, List<T> also, int $andMe) { + return "" + show + yes + also + $andMe; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public class StringBuilder { + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + private int show; + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + private int yes; + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + private List<T> also; + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + private int $andMe; + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + StringBuilder() { + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public StringBuilder show(final int show) { + this.show = show; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public StringBuilder yes(final int yes) { + this.yes = yes; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public StringBuilder also(final List<T> also) { + this.also = also; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public StringBuilder $andMe(final int $andMe) { + this.$andMe = $andMe; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public String build() { + return BuilderInstanceMethod.this.create(show, yes, also, $andMe); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public java.lang.String toString() { + return "BuilderInstanceMethod.StringBuilder(show=" + this.show + ", yes=" + this.yes + ", also=" + this.also + ", $andMe=" + this.$andMe + ")"; + } + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public StringBuilder builder() { + return new StringBuilder(); + } +} diff --git a/test/transform/resource/after-delombok/BuilderSingularGuavaListsSets.java b/test/transform/resource/after-delombok/BuilderSingularGuavaListsSets.java index f676166d..7f1e7149 100644 --- a/test/transform/resource/after-delombok/BuilderSingularGuavaListsSets.java +++ b/test/transform/resource/after-delombok/BuilderSingularGuavaListsSets.java @@ -57,6 +57,12 @@ class BuilderSingularGuavaListsSets<T> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularGuavaListsSetsBuilder<T> clearCards() { + this.cards = null; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularGuavaListsSetsBuilder<T> frog(final Number frog) { if (this.frogs == null) this.frogs = com.google.common.collect.ImmutableList.builder(); this.frogs.add(frog); @@ -71,6 +77,12 @@ class BuilderSingularGuavaListsSets<T> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularGuavaListsSetsBuilder<T> clearFrogs() { + this.frogs = null; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularGuavaListsSetsBuilder<T> rawSet(final java.lang.Object rawSet) { if (this.rawSet == null) this.rawSet = com.google.common.collect.ImmutableSet.builder(); this.rawSet.add(rawSet); @@ -85,6 +97,12 @@ class BuilderSingularGuavaListsSets<T> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularGuavaListsSetsBuilder<T> clearRawSet() { + this.rawSet = null; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularGuavaListsSetsBuilder<T> pass(final String pass) { if (this.passes == null) this.passes = com.google.common.collect.ImmutableSortedSet.naturalOrder(); this.passes.add(pass); @@ -99,6 +117,9 @@ class BuilderSingularGuavaListsSets<T> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularGuavaListsSetsBuilder<T> clearPasses() { + this.passes = null; + } public BuilderSingularGuavaListsSetsBuilder<T> user(final com.google.common.collect.Table.Cell<Number, Number, String> user) { if (this.users == null) this.users = com.google.common.collect.ImmutableTable.builder(); this.users.put(user); diff --git a/test/transform/resource/after-delombok/BuilderSingularGuavaMaps.java b/test/transform/resource/after-delombok/BuilderSingularGuavaMaps.java index 0cb0001b..10545a8f 100644 --- a/test/transform/resource/after-delombok/BuilderSingularGuavaMaps.java +++ b/test/transform/resource/after-delombok/BuilderSingularGuavaMaps.java @@ -45,6 +45,12 @@ class BuilderSingularGuavaMaps<K, V> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularGuavaMapsBuilder<K, V> clearBattleaxes() { + this.battleaxes = null; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularGuavaMapsBuilder<K, V> vertex(final Integer vertex$key, final V vertex$value) { if (this.vertices == null) this.vertices = com.google.common.collect.ImmutableSortedMap.naturalOrder(); this.vertices.put(vertex$key, vertex$value); @@ -59,6 +65,12 @@ class BuilderSingularGuavaMaps<K, V> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularGuavaMapsBuilder<K, V> clearVertices() { + this.vertices = null; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularGuavaMapsBuilder<K, V> rawMap(final java.lang.Object rawMap$key, final java.lang.Object rawMap$value) { if (this.rawMap == null) this.rawMap = com.google.common.collect.ImmutableBiMap.builder(); this.rawMap.put(rawMap$key, rawMap$value); @@ -73,6 +85,12 @@ class BuilderSingularGuavaMaps<K, V> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularGuavaMapsBuilder<K, V> clearRawMap() { + this.rawMap = null; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularGuavaMaps<K, V> build() { com.google.common.collect.ImmutableMap<K, V> battleaxes = this.battleaxes == null ? com.google.common.collect.ImmutableMap.<K, V>of() : this.battleaxes.build(); com.google.common.collect.ImmutableSortedMap<Integer, V> vertices = this.vertices == null ? com.google.common.collect.ImmutableSortedMap.<Integer, V>of() : this.vertices.build(); diff --git a/test/transform/resource/after-delombok/BuilderSingularLists.java b/test/transform/resource/after-delombok/BuilderSingularLists.java index f58934d4..9b409404 100644 --- a/test/transform/resource/after-delombok/BuilderSingularLists.java +++ b/test/transform/resource/after-delombok/BuilderSingularLists.java @@ -44,6 +44,12 @@ class BuilderSingularLists<T> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularListsBuilder<T> clearChildren() { + if (this.children != null) this.children.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularListsBuilder<T> scarf(final Number scarf) { if (this.scarves == null) this.scarves = new java.util.ArrayList<Number>(); this.scarves.add(scarf); @@ -58,6 +64,12 @@ class BuilderSingularLists<T> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularListsBuilder<T> clearScarves() { + if (this.scarves != null) this.scarves.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularListsBuilder<T> rawList(final java.lang.Object rawList) { if (this.rawList == null) this.rawList = new java.util.ArrayList<java.lang.Object>(); this.rawList.add(rawList); @@ -72,6 +84,12 @@ class BuilderSingularLists<T> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularListsBuilder<T> clearRawList() { + if (this.rawList != null) this.rawList.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularLists<T> build() { java.util.List<T> children; switch (this.children == null ? 0 : this.children.size()) { diff --git a/test/transform/resource/after-delombok/BuilderSingularMaps.java b/test/transform/resource/after-delombok/BuilderSingularMaps.java index 212ece26..257a2ec2 100644 --- a/test/transform/resource/after-delombok/BuilderSingularMaps.java +++ b/test/transform/resource/after-delombok/BuilderSingularMaps.java @@ -57,6 +57,14 @@ class BuilderSingularMaps<K, V> { return this; } @SuppressWarnings("all") + public BuilderSingularMapsBuilder<K, V> clearWomen() { + if (this.women$key != null) { + this.women$key.clear(); + this.women$value.clear(); + } + return this; + } + @SuppressWarnings("all") public BuilderSingularMapsBuilder<K, V> man(K manKey, Number manValue) { if (this.men$key == null) { this.men$key = new java.util.ArrayList<K>(); @@ -79,6 +87,14 @@ class BuilderSingularMaps<K, V> { return this; } @SuppressWarnings("all") + public BuilderSingularMapsBuilder<K, V> clearMen() { + if (this.men$key != null) { + this.men$key.clear(); + this.men$value.clear(); + } + return this; + } + @SuppressWarnings("all") public BuilderSingularMapsBuilder<K, V> rawMap(Object rawMapKey, Object rawMapValue) { if (this.rawMap$key == null) { this.rawMap$key = new java.util.ArrayList<Object>(); @@ -101,6 +117,14 @@ class BuilderSingularMaps<K, V> { return this; } @SuppressWarnings("all") + public BuilderSingularMapsBuilder<K, V> clearRawMap() { + if (this.rawMap$key != null) { + this.rawMap$key.clear(); + this.rawMap$value.clear(); + } + return this; + } + @SuppressWarnings("all") public BuilderSingularMapsBuilder<K, V> stringMap(String stringMapKey, V stringMapValue) { if (this.stringMap$key == null) { this.stringMap$key = new java.util.ArrayList<String>(); @@ -123,6 +147,14 @@ class BuilderSingularMaps<K, V> { return this; } @SuppressWarnings("all") + public BuilderSingularMapsBuilder<K, V> clearStringMap() { + if (this.stringMap$key != null) { + this.stringMap$key.clear(); + this.stringMap$value.clear(); + } + return this; + } + @SuppressWarnings("all") public BuilderSingularMaps<K, V> build() { java.util.Map<K, V> women; switch (this.women$key == null ? 0 : this.women$key.size()) { diff --git a/test/transform/resource/after-delombok/BuilderSingularNoAuto.java b/test/transform/resource/after-delombok/BuilderSingularNoAuto.java index 0be33a84..d5cd8f41 100644 --- a/test/transform/resource/after-delombok/BuilderSingularNoAuto.java +++ b/test/transform/resource/after-delombok/BuilderSingularNoAuto.java @@ -42,6 +42,12 @@ class BuilderSingularNoAuto { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularNoAutoBuilder clearThings() { + if (this.things != null) this.things.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularNoAutoBuilder widget(final String widget) { if (this.widgets == null) this.widgets = new java.util.ArrayList<String>(); this.widgets.add(widget); @@ -56,6 +62,12 @@ class BuilderSingularNoAuto { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularNoAutoBuilder clearWidgets() { + if (this.widgets != null) this.widgets.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularNoAutoBuilder items(final String items) { if (this.items == null) this.items = new java.util.ArrayList<String>(); this.items.add(items); @@ -70,6 +82,12 @@ class BuilderSingularNoAuto { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularNoAutoBuilder clearItems() { + if (this.items != null) this.items.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularNoAuto build() { java.util.List<String> things; switch (this.things == null ? 0 : this.things.size()) { diff --git a/test/transform/resource/after-delombok/BuilderSingularRedirectToGuava.java b/test/transform/resource/after-delombok/BuilderSingularRedirectToGuava.java index 0dd40c9f..506a8b4c 100644 --- a/test/transform/resource/after-delombok/BuilderSingularRedirectToGuava.java +++ b/test/transform/resource/after-delombok/BuilderSingularRedirectToGuava.java @@ -44,6 +44,12 @@ class BuilderSingularRedirectToGuava { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularRedirectToGuavaBuilder clearDangerMice() { + this.dangerMice = null; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularRedirectToGuavaBuilder thing(final Integer thing$key, final Number thing$value) { if (this.things == null) this.things = com.google.common.collect.ImmutableSortedMap.naturalOrder(); this.things.put(thing$key, thing$value); @@ -58,6 +64,12 @@ class BuilderSingularRedirectToGuava { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularRedirectToGuavaBuilder clearThings() { + this.things = null; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularRedirectToGuavaBuilder doohickey(final Class<?> doohickey) { if (this.doohickeys == null) this.doohickeys = com.google.common.collect.ImmutableList.builder(); this.doohickeys.add(doohickey); @@ -72,6 +84,12 @@ class BuilderSingularRedirectToGuava { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularRedirectToGuavaBuilder clearDoohickeys() { + this.doohickeys = null; + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularRedirectToGuava build() { java.util.Set<String> dangerMice = this.dangerMice == null ? com.google.common.collect.ImmutableSet.<String>of() : this.dangerMice.build(); java.util.NavigableMap<Integer, Number> things = this.things == null ? com.google.common.collect.ImmutableSortedMap.<Integer, Number>of() : this.things.build(); diff --git a/test/transform/resource/after-delombok/BuilderSingularSets.java b/test/transform/resource/after-delombok/BuilderSingularSets.java index 70372b99..c794726a 100644 --- a/test/transform/resource/after-delombok/BuilderSingularSets.java +++ b/test/transform/resource/after-delombok/BuilderSingularSets.java @@ -49,6 +49,12 @@ class BuilderSingularSets<T> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularSetsBuilder<T> clearDangerMice() { + if (this.dangerMice != null) this.dangerMice.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularSetsBuilder<T> octopus(final Number octopus) { if (this.octopodes == null) this.octopodes = new java.util.ArrayList<Number>(); this.octopodes.add(octopus); @@ -63,6 +69,12 @@ class BuilderSingularSets<T> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularSetsBuilder<T> clearOctopodes() { + if (this.octopodes != null) this.octopodes.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularSetsBuilder<T> rawSet(final java.lang.Object rawSet) { if (this.rawSet == null) this.rawSet = new java.util.ArrayList<java.lang.Object>(); this.rawSet.add(rawSet); @@ -77,6 +89,12 @@ class BuilderSingularSets<T> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularSetsBuilder<T> clearRawSet() { + if (this.rawSet != null) this.rawSet.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularSetsBuilder<T> stringSet(final String stringSet) { if (this.stringSet == null) this.stringSet = new java.util.ArrayList<String>(); this.stringSet.add(stringSet); @@ -91,6 +109,12 @@ class BuilderSingularSets<T> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderSingularSetsBuilder<T> clearStringSet() { + if (this.stringSet != null) this.stringSet.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderSingularSets<T> build() { java.util.Set<T> dangerMice; switch (this.dangerMice == null ? 0 : this.dangerMice.size()) { diff --git a/test/transform/resource/after-delombok/BuilderWithToBuilder.java b/test/transform/resource/after-delombok/BuilderWithToBuilder.java index eb61a6db..7dfb046a 100644 --- a/test/transform/resource/after-delombok/BuilderWithToBuilder.java +++ b/test/transform/resource/after-delombok/BuilderWithToBuilder.java @@ -68,6 +68,12 @@ class BuilderWithToBuilder<T> { } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") + public BuilderWithToBuilderBuilder<T> clearBars() { + if (this.bars != null) this.bars.clear(); + return this; + } + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") public BuilderWithToBuilder<T> build() { java.util.List<T> bars; switch (this.bars == null ? 0 : this.bars.size()) { diff --git a/test/transform/resource/after-delombok/ConflictingStaticConstructorNames.java b/test/transform/resource/after-delombok/ConflictingStaticConstructorNames.java index a47fa244..ff5278ff 100644 --- a/test/transform/resource/after-delombok/ConflictingStaticConstructorNames.java +++ b/test/transform/resource/after-delombok/ConflictingStaticConstructorNames.java @@ -5,8 +5,8 @@ class ConflictingStaticConstructorNames { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof ConflictingStaticConstructorNames)) return false; - final ConflictingStaticConstructorNames other = (ConflictingStaticConstructorNames)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final ConflictingStaticConstructorNames other = (ConflictingStaticConstructorNames) o; + if (!other.canEqual((java.lang.Object) this)) return false; return true; } @java.lang.SuppressWarnings("all") diff --git a/test/transform/resource/after-delombok/DataConfiguration.java b/test/transform/resource/after-delombok/DataConfiguration.java index b83204b8..aadb35b6 100644 --- a/test/transform/resource/after-delombok/DataConfiguration.java +++ b/test/transform/resource/after-delombok/DataConfiguration.java @@ -16,8 +16,8 @@ class DataConfiguration { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof DataConfiguration)) return false; - final DataConfiguration other = (DataConfiguration)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final DataConfiguration other = (DataConfiguration) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.getX() != other.getX()) return false; return true; } diff --git a/test/transform/resource/after-delombok/DataExtended.java b/test/transform/resource/after-delombok/DataExtended.java index 25180429..175738ad 100644 --- a/test/transform/resource/after-delombok/DataExtended.java +++ b/test/transform/resource/after-delombok/DataExtended.java @@ -20,8 +20,8 @@ class DataExtended { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof DataExtended)) return false; - final DataExtended other = (DataExtended)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final DataExtended other = (DataExtended) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.getX() != other.getX()) return false; return true; } diff --git a/test/transform/resource/after-delombok/DataIgnore.java b/test/transform/resource/after-delombok/DataIgnore.java index 0d40a5a8..d5a3d81e 100644 --- a/test/transform/resource/after-delombok/DataIgnore.java +++ b/test/transform/resource/after-delombok/DataIgnore.java @@ -18,8 +18,8 @@ class DataIgnore { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof DataIgnore)) return false; - final DataIgnore other = (DataIgnore)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final DataIgnore other = (DataIgnore) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.getX() != other.getX()) return false; return true; } diff --git a/test/transform/resource/after-delombok/DataOnLocalClass.java b/test/transform/resource/after-delombok/DataOnLocalClass.java index 44b069fd..0e15ab4c 100644 --- a/test/transform/resource/after-delombok/DataOnLocalClass.java +++ b/test/transform/resource/after-delombok/DataOnLocalClass.java @@ -29,8 +29,8 @@ class DataOnLocalClass1 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof Local)) return false; - final Local other = (Local)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final Local other = (Local) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.getX() != other.getX()) return false; final java.lang.Object this$name = this.getName(); final java.lang.Object other$name = other.getName(); @@ -97,8 +97,8 @@ class DataOnLocalClass2 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof Local.InnerLocal)) return false; - final InnerLocal other = (InnerLocal)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final InnerLocal other = (InnerLocal) o; + if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$name = this.getName(); final java.lang.Object other$name = other.getName(); if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false; @@ -142,8 +142,8 @@ class DataOnLocalClass2 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof Local)) return false; - final Local other = (Local)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final Local other = (Local) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.getX() != other.getX()) return false; return true; } diff --git a/test/transform/resource/after-delombok/DataPlain.java b/test/transform/resource/after-delombok/DataPlain.java index cfb72656..ccebc55e 100644 --- a/test/transform/resource/after-delombok/DataPlain.java +++ b/test/transform/resource/after-delombok/DataPlain.java @@ -28,8 +28,8 @@ class Data1 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof Data1)) return false; - final Data1 other = (Data1)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final Data1 other = (Data1) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.getX() != other.getX()) return false; final java.lang.Object this$name = this.getName(); final java.lang.Object other$name = other.getName(); @@ -89,8 +89,8 @@ class Data2 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof Data2)) return false; - final Data2 other = (Data2)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final Data2 other = (Data2) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.getX() != other.getX()) return false; final java.lang.Object this$name = this.getName(); final java.lang.Object other$name = other.getName(); @@ -150,7 +150,7 @@ final class Data3 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof Data3)) return false; - final Data3 other = (Data3)o; + final Data3 other = (Data3) o; if (this.getX() != other.getX()) return false; final java.lang.Object this$name = this.getName(); final java.lang.Object other$name = other.getName(); @@ -201,8 +201,8 @@ final class Data4 extends java.util.Timer { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof Data4)) return false; - final Data4 other = (Data4)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final Data4 other = (Data4) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (!super.equals(o)) return false; if (this.getX() != other.getX()) return false; return true; @@ -234,8 +234,8 @@ class Data5 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof Data5)) return false; - final Data5 other = (Data5)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final Data5 other = (Data5) o; + if (!other.canEqual((java.lang.Object) this)) return false; return true; } @java.lang.SuppressWarnings("all") diff --git a/test/transform/resource/after-delombok/DataWithGetter.java b/test/transform/resource/after-delombok/DataWithGetter.java index f849e0f8..fb51e262 100644 --- a/test/transform/resource/after-delombok/DataWithGetter.java +++ b/test/transform/resource/after-delombok/DataWithGetter.java @@ -24,8 +24,8 @@ class DataWithGetter { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof DataWithGetter)) return false; - final DataWithGetter other = (DataWithGetter)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final DataWithGetter other = (DataWithGetter) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.getX() != other.getX()) return false; if (this.getY() != other.getY()) return false; final java.lang.Object this$z = this.getZ(); diff --git a/test/transform/resource/after-delombok/DataWithGetterNone.java b/test/transform/resource/after-delombok/DataWithGetterNone.java index c46be723..e332db02 100644 --- a/test/transform/resource/after-delombok/DataWithGetterNone.java +++ b/test/transform/resource/after-delombok/DataWithGetterNone.java @@ -24,8 +24,8 @@ class DataWithGetterNone { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof DataWithGetterNone)) return false; - final DataWithGetterNone other = (DataWithGetterNone)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final DataWithGetterNone other = (DataWithGetterNone) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.x != other.x) return false; if (this.y != other.y) return false; final java.lang.Object this$z = this.z; diff --git a/test/transform/resource/after-delombok/DelegateOnGetter.java b/test/transform/resource/after-delombok/DelegateOnGetter.java index 5b5090e9..1d25dcc0 100644 --- a/test/transform/resource/after-delombok/DelegateOnGetter.java +++ b/test/transform/resource/after-delombok/DelegateOnGetter.java @@ -12,7 +12,7 @@ class DelegateOnGetter { synchronized (this.bar) { value = this.bar.get(); if (value == null) { - final Bar actualValue = new Bar(){ + final Bar actualValue = new Bar() { public void setList(java.util.ArrayList<String> list) { } public int getInt() { @@ -24,7 +24,7 @@ class DelegateOnGetter { } } } - return (Bar)(value == this.bar ? null : value); + return (Bar) (value == this.bar ? null : value); } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") diff --git a/test/transform/resource/after-delombok/EqualsAndHashCode.java b/test/transform/resource/after-delombok/EqualsAndHashCode.java index d0ed4067..7ade594a 100644 --- a/test/transform/resource/after-delombok/EqualsAndHashCode.java +++ b/test/transform/resource/after-delombok/EqualsAndHashCode.java @@ -10,8 +10,8 @@ class EqualsAndHashCode { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof EqualsAndHashCode)) return false; - final EqualsAndHashCode other = (EqualsAndHashCode)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final EqualsAndHashCode other = (EqualsAndHashCode) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.x != other.x) return false; if (!java.util.Arrays.equals(this.y, other.y)) return false; if (!java.util.Arrays.deepEquals(this.z, other.z)) return false; @@ -56,7 +56,7 @@ final class EqualsAndHashCode2 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof EqualsAndHashCode2)) return false; - final EqualsAndHashCode2 other = (EqualsAndHashCode2)o; + final EqualsAndHashCode2 other = (EqualsAndHashCode2) o; if (this.x != other.x) return false; if (this.y != other.y) return false; if (java.lang.Float.compare(this.f, other.f) != 0) return false; @@ -72,10 +72,10 @@ final class EqualsAndHashCode2 { int result = 1; result = result * PRIME + this.x; final long $y = this.y; - result = result * PRIME + (int)($y >>> 32 ^ $y); + result = result * PRIME + (int) ($y >>> 32 ^ $y); result = result * PRIME + java.lang.Float.floatToIntBits(this.f); final long $d = java.lang.Double.doubleToLongBits(this.d); - result = result * PRIME + (int)($d >>> 32 ^ $d); + result = result * PRIME + (int) ($d >>> 32 ^ $d); result = result * PRIME + (this.b ? 79 : 97); return result; } @@ -87,8 +87,8 @@ final class EqualsAndHashCode3 extends EqualsAndHashCode { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof EqualsAndHashCode3)) return false; - final EqualsAndHashCode3 other = (EqualsAndHashCode3)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final EqualsAndHashCode3 other = (EqualsAndHashCode3) o; + if (!other.canEqual((java.lang.Object) this)) return false; return true; } @java.lang.SuppressWarnings("all") @@ -111,8 +111,8 @@ class EqualsAndHashCode4 extends EqualsAndHashCode { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof EqualsAndHashCode4)) return false; - final EqualsAndHashCode4 other = (EqualsAndHashCode4)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final EqualsAndHashCode4 other = (EqualsAndHashCode4) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (!super.equals(o)) return false; return true; } diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeWithExistingMethods.java b/test/transform/resource/after-delombok/EqualsAndHashCodeWithExistingMethods.java index 5c9316b4..6978bf00 100644 --- a/test/transform/resource/after-delombok/EqualsAndHashCodeWithExistingMethods.java +++ b/test/transform/resource/after-delombok/EqualsAndHashCodeWithExistingMethods.java @@ -21,8 +21,8 @@ final class EqualsAndHashCodeWithExistingMethods3 extends EqualsAndHashCodeWithE public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof EqualsAndHashCodeWithExistingMethods3)) return false; - final EqualsAndHashCodeWithExistingMethods3 other = (EqualsAndHashCodeWithExistingMethods3)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final EqualsAndHashCodeWithExistingMethods3 other = (EqualsAndHashCodeWithExistingMethods3) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (!super.equals(o)) return false; if (this.x != other.x) return false; return true; diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeWithOnParam.java b/test/transform/resource/after-delombok/EqualsAndHashCodeWithOnParam.java index 69b69d29..4cf00601 100644 --- a/test/transform/resource/after-delombok/EqualsAndHashCodeWithOnParam.java +++ b/test/transform/resource/after-delombok/EqualsAndHashCodeWithOnParam.java @@ -13,8 +13,8 @@ class EqualsAndHashCodeWithOnParam { public boolean equals(@Nullable final java.lang.Object o) { if (o == this) return true; if (!(o instanceof EqualsAndHashCodeWithOnParam)) return false; - final EqualsAndHashCodeWithOnParam other = (EqualsAndHashCodeWithOnParam)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final EqualsAndHashCodeWithOnParam other = (EqualsAndHashCodeWithOnParam) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.x != other.x) return false; if (!java.util.Arrays.equals(this.y, other.y)) return false; if (!java.util.Arrays.deepEquals(this.z, other.z)) return false; diff --git a/test/transform/resource/after-delombok/EqualsAndHashCodeWithSomeExistingMethods.java b/test/transform/resource/after-delombok/EqualsAndHashCodeWithSomeExistingMethods.java index 37eeb8df..b3a1fb0d 100644 --- a/test/transform/resource/after-delombok/EqualsAndHashCodeWithSomeExistingMethods.java +++ b/test/transform/resource/after-delombok/EqualsAndHashCodeWithSomeExistingMethods.java @@ -28,8 +28,8 @@ class EqualsAndHashCodeWithSomeExistingMethods2 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof EqualsAndHashCodeWithSomeExistingMethods2)) return false; - final EqualsAndHashCodeWithSomeExistingMethods2 other = (EqualsAndHashCodeWithSomeExistingMethods2)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final EqualsAndHashCodeWithSomeExistingMethods2 other = (EqualsAndHashCodeWithSomeExistingMethods2) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.x != other.x) return false; return true; } @@ -75,8 +75,8 @@ class EqualsAndHashCodeWithNoExistingMethods { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof EqualsAndHashCodeWithNoExistingMethods)) return false; - final EqualsAndHashCodeWithNoExistingMethods other = (EqualsAndHashCodeWithNoExistingMethods)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final EqualsAndHashCodeWithNoExistingMethods other = (EqualsAndHashCodeWithNoExistingMethods) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.x != other.x) return false; return true; } diff --git a/test/transform/resource/after-delombok/EqualsAndHashcodeOfExclude.java b/test/transform/resource/after-delombok/EqualsAndHashcodeOfExclude.java new file mode 100644 index 00000000..2a75430f --- /dev/null +++ b/test/transform/resource/after-delombok/EqualsAndHashcodeOfExclude.java @@ -0,0 +1,46 @@ +final class EqualsAndHashCodeOf { + int x; + int y; + @java.lang.Override + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof EqualsAndHashCodeOf)) return false; + final EqualsAndHashCodeOf other = (EqualsAndHashCodeOf) o; + if (this.x != other.x) return false; + return true; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.x; + return result; + } +} +final class EqualsAndHashCodeExclude { + int x; + int y; + @java.lang.Override + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof EqualsAndHashCodeExclude)) return false; + final EqualsAndHashCodeExclude other = (EqualsAndHashCodeExclude) o; + if (this.x != other.x) return false; + return true; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.x; + return result; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/FieldDefaultsViaConfig.java b/test/transform/resource/after-delombok/FieldDefaultsViaConfig.java new file mode 100644 index 00000000..096769b6 --- /dev/null +++ b/test/transform/resource/after-delombok/FieldDefaultsViaConfig.java @@ -0,0 +1,11 @@ +class FieldDefaultsViaConfig1 { + private final int x; + private int y; + FieldDefaultsViaConfig1(int x) { + this.x = x; + } +} +class FieldDefaultsViaConfig2 { + final int x = 2; + protected final int y = 0; +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/FieldDefaultsViaConfigAndRequiredArgsConstructor.java b/test/transform/resource/after-delombok/FieldDefaultsViaConfigAndRequiredArgsConstructor.java new file mode 100644 index 00000000..ebe6e2ed --- /dev/null +++ b/test/transform/resource/after-delombok/FieldDefaultsViaConfigAndRequiredArgsConstructor.java @@ -0,0 +1,9 @@ +class FieldDefaultsViaConfigAndRequiredArgsConstructor { + final int x; + @java.beans.ConstructorProperties({"x"}) + @java.lang.SuppressWarnings("all") + @javax.annotation.Generated("lombok") + public FieldDefaultsViaConfigAndRequiredArgsConstructor(final int x) { + this.x = x; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/GetterLazy.java b/test/transform/resource/after-delombok/GetterLazy.java index 9c7db37b..2ea3cbf2 100644 --- a/test/transform/resource/after-delombok/GetterLazy.java +++ b/test/transform/resource/after-delombok/GetterLazy.java @@ -16,6 +16,6 @@ class GetterLazy { } } } - return (ValueType)(value == this.fieldName ? null : value); + return (ValueType) (value == this.fieldName ? null : value); } } diff --git a/test/transform/resource/after-delombok/GetterLazyBoolean.java b/test/transform/resource/after-delombok/GetterLazyBoolean.java index f9a42e66..41349447 100644 --- a/test/transform/resource/after-delombok/GetterLazyBoolean.java +++ b/test/transform/resource/after-delombok/GetterLazyBoolean.java @@ -10,8 +10,8 @@ class GetterLazyBoolean { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof GetterLazyBoolean)) return false; - final GetterLazyBoolean other = (GetterLazyBoolean)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final GetterLazyBoolean other = (GetterLazyBoolean) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.isBooleanValue() != other.isBooleanValue()) return false; return true; } @@ -49,7 +49,7 @@ class GetterLazyBoolean { } } } - return (java.lang.Boolean)value; + return (java.lang.Boolean) value; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") @@ -65,6 +65,6 @@ class GetterLazyBoolean { } } } - return (java.lang.Boolean)value; + return (java.lang.Boolean) value; } } diff --git a/test/transform/resource/after-delombok/GetterLazyEahcToString.java b/test/transform/resource/after-delombok/GetterLazyEahcToString.java index db075cde..973eb6f1 100644 --- a/test/transform/resource/after-delombok/GetterLazyEahcToString.java +++ b/test/transform/resource/after-delombok/GetterLazyEahcToString.java @@ -9,8 +9,8 @@ class GetterLazyEahcToString { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof GetterLazyEahcToString)) return false; - final GetterLazyEahcToString other = (GetterLazyEahcToString)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final GetterLazyEahcToString other = (GetterLazyEahcToString) o; + if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$value = this.getValue(); final java.lang.Object other$value = other.getValue(); if (this$value == null ? other$value != null : !this$value.equals(other$value)) return false; @@ -62,11 +62,10 @@ class GetterLazyEahcToString { } } } - return (String)(value == this.value ? null : value); + return (String) (value == this.value ? null : value); } @java.lang.SuppressWarnings("all") - @javax.annotation.Generated("lombok") public String getValue2() { return this.value2; diff --git a/test/transform/resource/after-delombok/GetterLazyNative.java b/test/transform/resource/after-delombok/GetterLazyNative.java index 50e3ff2b..0d88558d 100644 --- a/test/transform/resource/after-delombok/GetterLazyNative.java +++ b/test/transform/resource/after-delombok/GetterLazyNative.java @@ -22,7 +22,7 @@ class GetterLazyNative { } } } - return (java.lang.Boolean)value; + return (java.lang.Boolean) value; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") @@ -38,7 +38,7 @@ class GetterLazyNative { } } } - return (java.lang.Byte)value; + return (java.lang.Byte) value; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") @@ -54,7 +54,7 @@ class GetterLazyNative { } } } - return (java.lang.Short)value; + return (java.lang.Short) value; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") @@ -70,7 +70,7 @@ class GetterLazyNative { } } } - return (java.lang.Integer)value; + return (java.lang.Integer) value; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") @@ -86,7 +86,7 @@ class GetterLazyNative { } } } - return (java.lang.Long)value; + return (java.lang.Long) value; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") @@ -102,7 +102,7 @@ class GetterLazyNative { } } } - return (java.lang.Float)value; + return (java.lang.Float) value; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") @@ -118,7 +118,7 @@ class GetterLazyNative { } } } - return (java.lang.Double)value; + return (java.lang.Double) value; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") @@ -134,7 +134,7 @@ class GetterLazyNative { } } } - return (java.lang.Character)value; + return (java.lang.Character) value; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") @@ -144,12 +144,12 @@ class GetterLazyNative { synchronized (this.intArrayField) { value = this.intArrayField.get(); if (value == null) { - final int[] actualValue = new int[]{1}; + final int[] actualValue = new int[] {1}; value = actualValue == null ? this.intArrayField : actualValue; this.intArrayField.set(value); } } } - return (int[])(value == this.intArrayField ? null : value); + return (int[]) (value == this.intArrayField ? null : value); } } diff --git a/test/transform/resource/after-delombok/GetterSetterJavadoc.java b/test/transform/resource/after-delombok/GetterSetterJavadoc.java index 45a99c9d..f156de92 100644 --- a/test/transform/resource/after-delombok/GetterSetterJavadoc.java +++ b/test/transform/resource/after-delombok/GetterSetterJavadoc.java @@ -33,8 +33,8 @@ class GetterSetterJavadoc1 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof GetterSetterJavadoc1)) return false; - final GetterSetterJavadoc1 other = (GetterSetterJavadoc1)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final GetterSetterJavadoc1 other = (GetterSetterJavadoc1) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.getFieldName() != other.getFieldName()) return false; return true; } diff --git a/test/transform/resource/after-delombok/InjectField.java b/test/transform/resource/after-delombok/InjectField.java index 55390a60..8215f8d0 100644 --- a/test/transform/resource/after-delombok/InjectField.java +++ b/test/transform/resource/after-delombok/InjectField.java @@ -1,8 +1,7 @@ import java.util.logging.Level; enum InjectField1 { - A, - B; + A, B; @java.lang.SuppressWarnings("all") diff --git a/test/transform/resource/after-delombok/LoggerSlf4jTypes.java b/test/transform/resource/after-delombok/LoggerSlf4jTypes.java index e987d807..a4e13afc 100644 --- a/test/transform/resource/after-delombok/LoggerSlf4jTypes.java +++ b/test/transform/resource/after-delombok/LoggerSlf4jTypes.java @@ -3,7 +3,7 @@ interface LoggerSlf4jTypesInterface { @interface LoggerSlf4jTypesAnnotation { } enum LoggerSlf4jTypesEnum { -; + ; @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jTypesEnum.class); diff --git a/test/transform/resource/after-delombok/NonNullOnParameterOfDefaultMethod.java b/test/transform/resource/after-delombok/NonNullOnParameterOfDefaultMethod.java new file mode 100644 index 00000000..e220296f --- /dev/null +++ b/test/transform/resource/after-delombok/NonNullOnParameterOfDefaultMethod.java @@ -0,0 +1,10 @@ +// version 8: +interface NonNullOnParameterOfDefaultMethod { + void test(@lombok.NonNull String arg); + default void test2(@lombok.NonNull String arg) { + if (arg == null) { + throw new java.lang.NullPointerException("arg"); + } + System.out.println(arg); + } +} diff --git a/test/transform/resource/after-delombok/UtilityClass.java b/test/transform/resource/after-delombok/UtilityClass.java index 7731b49c..6b3c1761 100644 --- a/test/transform/resource/after-delombok/UtilityClass.java +++ b/test/transform/resource/after-delombok/UtilityClass.java @@ -24,8 +24,7 @@ class UtilityInner { } } enum UtilityInsideEnum { - FOO, - BAR; + FOO, BAR; static final class InsideEnum { static int member; @java.lang.SuppressWarnings("all") diff --git a/test/transform/resource/after-delombok/UtilityClassErrors.java b/test/transform/resource/after-delombok/UtilityClassErrors.java index 9626461a..072edf91 100644 --- a/test/transform/resource/after-delombok/UtilityClassErrors.java +++ b/test/transform/resource/after-delombok/UtilityClassErrors.java @@ -8,7 +8,7 @@ final class UtilityClassErrors1 { } } enum UtilityClassErrors2 { -; + ; } class UtilityClassErrors3 { class NonStaticInner { diff --git a/test/transform/resource/after-delombok/ValAnonymousSubclassWithGenerics.java b/test/transform/resource/after-delombok/ValAnonymousSubclassWithGenerics.java index 25a9e0ce..07093e5a 100644 --- a/test/transform/resource/after-delombok/ValAnonymousSubclassWithGenerics.java +++ b/test/transform/resource/after-delombok/ValAnonymousSubclassWithGenerics.java @@ -1,6 +1,6 @@ import java.util.*; public class ValAnonymousSubclassWithGenerics { - Object object = new Object(){ + Object object = new Object() { void foo() { final int j = 1; } @@ -9,7 +9,7 @@ public class ValAnonymousSubclassWithGenerics { final int k = super.hashCode(); int x = k; } - java.util.List<String> names = new java.util.ArrayList<String>(){ + java.util.List<String> names = new java.util.ArrayList<String>() { public String get(int i) { final java.lang.String result = super.get(i); return result; diff --git a/test/transform/resource/after-delombok/ValLambda.java b/test/transform/resource/after-delombok/ValLambda.java index 0b13b5a1..40b056f3 100644 --- a/test/transform/resource/after-delombok/ValLambda.java +++ b/test/transform/resource/after-delombok/ValLambda.java @@ -1,21 +1,21 @@ // version 8: class ValLambda { public void easyLambda() { - final java.lang.Runnable foo = (Runnable)() -> { + final java.lang.Runnable foo = (Runnable) () -> { }; } public void easyIntersectionLambda() { - final java.lang.Object foo = (Runnable & java.io.Serializable)() -> { + final java.lang.Object foo = (Runnable & java.io.Serializable) () -> { }; - final java.lang.Object bar = (java.io.Serializable & Runnable)() -> { + final java.lang.Object bar = (java.io.Serializable & Runnable) () -> { }; } public void easyLubLambda() { - final java.lang.Runnable foo = (System.currentTimeMillis() > 0) ? (Runnable)() -> { - } : (Runnable)System.out::println; + final java.lang.Runnable foo = (System.currentTimeMillis() > 0) ? (Runnable) () -> { + } : (Runnable) System.out::println; } // public void castLubLambda() { -// Runnable foo = (Runnable)((System.currentTimeMillis() > 0) ? ()-> {} : System.out::println); -// lombok.val foo = (Runnable)((System.currentTimeMillis() > 0) ? ()-> {} : System.out::println); +// Runnable foo = (Runnable) ((System.currentTimeMillis() > 0) ? () -> {} : System.out::println); +// lombok.val foo = (Runnable) ((System.currentTimeMillis() > 0) ? () -> {} : System.out::println); // } }
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/ValRawType.java b/test/transform/resource/after-delombok/ValRawType.java index dc297046..122eabda 100644 --- a/test/transform/resource/after-delombok/ValRawType.java +++ b/test/transform/resource/after-delombok/ValRawType.java @@ -5,7 +5,7 @@ public class ValRawType { public void test() { Element propElement = new Element(); for (final java.lang.Object attribute : propElement.attributes()) { - final ValRawType.Attribute attr = (Attribute)attribute; + final ValRawType.Attribute attr = (Attribute) attribute; } } diff --git a/test/transform/resource/after-delombok/ValWeirdTypes.java b/test/transform/resource/after-delombok/ValWeirdTypes.java index 2c2905ed..996ce662 100644 --- a/test/transform/resource/after-delombok/ValWeirdTypes.java +++ b/test/transform/resource/after-delombok/ValWeirdTypes.java @@ -18,7 +18,7 @@ public class ValWeirdTypes<Z> { final long y = 5 + 3L; } public void testAnonymousInnerClass() { - final java.lang.Runnable y = new Runnable(){ + final java.lang.Runnable y = new Runnable() { public void run() { } }; @@ -48,8 +48,8 @@ public class ValWeirdTypes<Z> { final java.lang.Object nully = null; } public void testArrays() { - final int[] intArray = new int[]{1, 2, 3}; - final java.lang.Object[][] multiDimArray = new Object[][]{{}}; + final int[] intArray = new int[] {1, 2, 3}; + final java.lang.Object[][] multiDimArray = new Object[][] {{}}; final int[] copy = intArray; final java.lang.Object[] single = multiDimArray[0]; final int singleInt = copy[0]; diff --git a/test/transform/resource/after-delombok/ValWithLocalClasses.java b/test/transform/resource/after-delombok/ValWithLocalClasses.java index b739b10e..6487eb82 100644 --- a/test/transform/resource/after-delombok/ValWithLocalClasses.java +++ b/test/transform/resource/after-delombok/ValWithLocalClasses.java @@ -1,6 +1,6 @@ class ValWithLocalClasses1 { { - final ValWithLocalClasses2 f2 = new ValWithLocalClasses2(){ + final ValWithLocalClasses2 f2 = new ValWithLocalClasses2() { }; } } diff --git a/test/transform/resource/after-delombok/ValuePlain.java b/test/transform/resource/after-delombok/ValuePlain.java index 8cc19c1e..056cdacf 100644 --- a/test/transform/resource/after-delombok/ValuePlain.java +++ b/test/transform/resource/after-delombok/ValuePlain.java @@ -24,7 +24,7 @@ final class Value1 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof Value1)) return false; - final Value1 other = (Value1)o; + final Value1 other = (Value1) o; if (this.getX() != other.getX()) return false; final java.lang.Object this$name = this.getName(); final java.lang.Object other$name = other.getName(); @@ -75,8 +75,8 @@ class Value2 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof Value2)) return false; - final Value2 other = (Value2)o; - if (!other.canEqual((java.lang.Object)this)) return false; + final Value2 other = (Value2) o; + if (!other.canEqual((java.lang.Object) this)) return false; if (this.getX() != other.getX()) return false; final java.lang.Object this$name = this.getName(); final java.lang.Object other$name = other.getName(); @@ -132,7 +132,7 @@ final class Value3 { public boolean equals(final java.lang.Object o) { if (o == this) return true; if (!(o instanceof Value3)) return false; - final Value3 other = (Value3)o; + final Value3 other = (Value3) o; if (this.getX() != other.getX()) return false; if (this.getY() != other.getY()) return false; return true; diff --git a/test/transform/resource/after-ecj/BuilderInstanceMethod.java b/test/transform/resource/after-ecj/BuilderInstanceMethod.java new file mode 100644 index 00000000..ff7d0aab --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderInstanceMethod.java @@ -0,0 +1,43 @@ +import java.util.List; +class BuilderInstanceMethod<T> { + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") class StringBuilder { + private @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") int show; + private @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") int yes; + private @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") List<T> also; + private @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") int $andMe; + @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") StringBuilder() { + super(); + } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") StringBuilder show(final int show) { + this.show = show; + return this; + } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") StringBuilder yes(final int yes) { + this.yes = yes; + return this; + } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") StringBuilder also(final List<T> also) { + this.also = also; + return this; + } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") StringBuilder $andMe(final int $andMe) { + this.$andMe = $andMe; + return this; + } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") String build() { + return BuilderInstanceMethod.this.create(show, yes, also, $andMe); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") java.lang.String toString() { + return (((((((("BuilderInstanceMethod.StringBuilder(show=" + this.show) + ", yes=") + this.yes) + ", also=") + this.also) + ", $andMe=") + this.$andMe) + ")"); + } + } + BuilderInstanceMethod() { + super(); + } + public @lombok.Builder String create(int show, final int yes, List<T> also, int $andMe) { + return (((("" + show) + yes) + also) + $andMe); + } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") StringBuilder builder() { + return new StringBuilder(); + } +} diff --git a/test/transform/resource/after-ecj/BuilderSingularGuavaListsSets.java b/test/transform/resource/after-ecj/BuilderSingularGuavaListsSets.java index dc53b8fb..28dc2fac 100644 --- a/test/transform/resource/after-ecj/BuilderSingularGuavaListsSets.java +++ b/test/transform/resource/after-ecj/BuilderSingularGuavaListsSets.java @@ -26,6 +26,10 @@ import lombok.Singular; this.cards.addAll(cards); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder<T> clearCards() { + this.cards = null; + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder<T> frog(Number frog) { if ((this.frogs == null)) this.frogs = com.google.common.collect.ImmutableList.builder(); @@ -38,6 +42,10 @@ import lombok.Singular; this.frogs.addAll(frogs); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder<T> clearFrogs() { + this.frogs = null; + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder<T> rawSet(java.lang.Object rawSet) { if ((this.rawSet == null)) this.rawSet = com.google.common.collect.ImmutableSet.builder(); @@ -50,6 +58,10 @@ import lombok.Singular; this.rawSet.addAll(rawSet); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder<T> clearRawSet() { + this.rawSet = null; + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder<T> pass(String pass) { if ((this.passes == null)) this.passes = com.google.common.collect.ImmutableSortedSet.naturalOrder(); @@ -62,6 +74,9 @@ import lombok.Singular; this.passes.addAll(passes); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder<T> clearPasses() { + this.passes = null; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaListsSetsBuilder<T> user(com.google.common.collect.Table.Cell<Number, Number, String> user) { if ((this.users == null)) this.users = com.google.common.collect.ImmutableTable.builder(); diff --git a/test/transform/resource/after-ecj/BuilderSingularGuavaMaps.java b/test/transform/resource/after-ecj/BuilderSingularGuavaMaps.java index d4dfc18a..0a031f2a 100644 --- a/test/transform/resource/after-ecj/BuilderSingularGuavaMaps.java +++ b/test/transform/resource/after-ecj/BuilderSingularGuavaMaps.java @@ -22,6 +22,10 @@ import lombok.Singular; this.battleaxes.putAll(battleaxes); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaMapsBuilder<K, V> clearBattleaxes() { + this.battleaxes = null; + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaMapsBuilder<K, V> vertex(Integer vertex$key, V vertex$value) { if ((this.vertices == null)) this.vertices = com.google.common.collect.ImmutableSortedMap.naturalOrder(); @@ -34,6 +38,10 @@ import lombok.Singular; this.vertices.putAll(vertices); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaMapsBuilder<K, V> clearVertices() { + this.vertices = null; + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaMapsBuilder<K, V> rawMap(java.lang.Object rawMap$key, java.lang.Object rawMap$value) { if ((this.rawMap == null)) this.rawMap = com.google.common.collect.ImmutableBiMap.builder(); @@ -46,6 +54,10 @@ import lombok.Singular; this.rawMap.putAll(rawMap); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaMapsBuilder<K, V> clearRawMap() { + this.rawMap = null; + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularGuavaMaps<K, V> build() { com.google.common.collect.ImmutableMap<K, V> battleaxes = ((this.battleaxes == null) ? com.google.common.collect.ImmutableMap.<K, V>of() : this.battleaxes.build()); com.google.common.collect.ImmutableSortedMap<Integer, V> vertices = ((this.vertices == null) ? com.google.common.collect.ImmutableSortedMap.<Integer, V>of() : this.vertices.build()); diff --git a/test/transform/resource/after-ecj/BuilderSingularLists.java b/test/transform/resource/after-ecj/BuilderSingularLists.java index c66fcf1b..e1036262 100644 --- a/test/transform/resource/after-ecj/BuilderSingularLists.java +++ b/test/transform/resource/after-ecj/BuilderSingularLists.java @@ -22,6 +22,11 @@ import lombok.Singular; this.children.addAll(children); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularListsBuilder<T> clearChildren() { + if ((this.children != null)) + this.children.clear(); + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularListsBuilder<T> scarf(Number scarf) { if ((this.scarves == null)) this.scarves = new java.util.ArrayList<Number>(); @@ -34,6 +39,11 @@ import lombok.Singular; this.scarves.addAll(scarves); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularListsBuilder<T> clearScarves() { + if ((this.scarves != null)) + this.scarves.clear(); + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularListsBuilder<T> rawList(java.lang.Object rawList) { if ((this.rawList == null)) this.rawList = new java.util.ArrayList<java.lang.Object>(); @@ -46,6 +56,11 @@ import lombok.Singular; this.rawList.addAll(rawList); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularListsBuilder<T> clearRawList() { + if ((this.rawList != null)) + this.rawList.clear(); + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularLists<T> build() { java.util.List<T> children; switch (((this.children == null) ? 0 : this.children.size())) { diff --git a/test/transform/resource/after-ecj/BuilderSingularMaps.java b/test/transform/resource/after-ecj/BuilderSingularMaps.java index 8a2e14eb..38ac0ed7 100644 --- a/test/transform/resource/after-ecj/BuilderSingularMaps.java +++ b/test/transform/resource/after-ecj/BuilderSingularMaps.java @@ -37,6 +37,14 @@ import lombok.Singular; } return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularMapsBuilder<K, V> clearWomen() { + if ((this.women$key != null)) + { + this.women$key.clear(); + this.women$value.clear(); + } + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularMapsBuilder<K, V> man(K manKey, Number manValue) { if ((this.men$key == null)) { @@ -60,6 +68,14 @@ import lombok.Singular; } return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularMapsBuilder<K, V> clearMen() { + if ((this.men$key != null)) + { + this.men$key.clear(); + this.men$value.clear(); + } + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularMapsBuilder<K, V> rawMap(java.lang.Object rawMapKey, java.lang.Object rawMapValue) { if ((this.rawMap$key == null)) { @@ -83,6 +99,14 @@ import lombok.Singular; } return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularMapsBuilder<K, V> clearRawMap() { + if ((this.rawMap$key != null)) + { + this.rawMap$key.clear(); + this.rawMap$value.clear(); + } + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularMapsBuilder<K, V> stringMap(String stringMapKey, V stringMapValue) { if ((this.stringMap$key == null)) { @@ -106,6 +130,14 @@ import lombok.Singular; } return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularMapsBuilder<K, V> clearStringMap() { + if ((this.stringMap$key != null)) + { + this.stringMap$key.clear(); + this.stringMap$value.clear(); + } + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularMaps<K, V> build() { java.util.Map<K, V> women; switch (((this.women$key == null) ? 0 : this.women$key.size())) { diff --git a/test/transform/resource/after-ecj/BuilderSingularNoAuto.java b/test/transform/resource/after-ecj/BuilderSingularNoAuto.java index d5b06f1e..1b79538c 100644 --- a/test/transform/resource/after-ecj/BuilderSingularNoAuto.java +++ b/test/transform/resource/after-ecj/BuilderSingularNoAuto.java @@ -20,6 +20,11 @@ import lombok.Singular; this.things.addAll(things); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularNoAutoBuilder clearThings() { + if ((this.things != null)) + this.things.clear(); + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularNoAutoBuilder widget(String widget) { if ((this.widgets == null)) this.widgets = new java.util.ArrayList<String>(); @@ -32,6 +37,11 @@ import lombok.Singular; this.widgets.addAll(widgets); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularNoAutoBuilder clearWidgets() { + if ((this.widgets != null)) + this.widgets.clear(); + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularNoAutoBuilder items(String items) { if ((this.items == null)) this.items = new java.util.ArrayList<String>(); @@ -44,6 +54,11 @@ import lombok.Singular; this.items.addAll(items); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularNoAutoBuilder clearItems() { + if ((this.items != null)) + this.items.clear(); + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularNoAuto build() { java.util.List<String> things; switch (((this.things == null) ? 0 : this.things.size())) { diff --git a/test/transform/resource/after-ecj/BuilderSingularRedirectToGuava.java b/test/transform/resource/after-ecj/BuilderSingularRedirectToGuava.java index 6e18d8ee..02a915d2 100644 --- a/test/transform/resource/after-ecj/BuilderSingularRedirectToGuava.java +++ b/test/transform/resource/after-ecj/BuilderSingularRedirectToGuava.java @@ -22,6 +22,10 @@ import lombok.Singular; this.dangerMice.addAll(dangerMice); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularRedirectToGuavaBuilder clearDangerMice() { + this.dangerMice = null; + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularRedirectToGuavaBuilder thing(Integer thing$key, Number thing$value) { if ((this.things == null)) this.things = com.google.common.collect.ImmutableSortedMap.naturalOrder(); @@ -34,6 +38,10 @@ import lombok.Singular; this.things.putAll(things); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularRedirectToGuavaBuilder clearThings() { + this.things = null; + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularRedirectToGuavaBuilder doohickey(Class<?> doohickey) { if ((this.doohickeys == null)) this.doohickeys = com.google.common.collect.ImmutableList.builder(); @@ -46,6 +54,10 @@ import lombok.Singular; this.doohickeys.addAll(doohickeys); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularRedirectToGuavaBuilder clearDoohickeys() { + this.doohickeys = null; + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularRedirectToGuava build() { java.util.Set<String> dangerMice = ((this.dangerMice == null) ? com.google.common.collect.ImmutableSet.<String>of() : this.dangerMice.build()); java.util.NavigableMap<Integer, Number> things = ((this.things == null) ? com.google.common.collect.ImmutableSortedMap.<Integer, Number>of() : this.things.build()); diff --git a/test/transform/resource/after-ecj/BuilderSingularSets.java b/test/transform/resource/after-ecj/BuilderSingularSets.java index 819de534..118eb16f 100644 --- a/test/transform/resource/after-ecj/BuilderSingularSets.java +++ b/test/transform/resource/after-ecj/BuilderSingularSets.java @@ -22,6 +22,11 @@ import lombok.Singular; this.dangerMice.addAll(dangerMice); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularSetsBuilder<T> clearDangerMice() { + if ((this.dangerMice != null)) + this.dangerMice.clear(); + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularSetsBuilder<T> octopus(Number octopus) { if ((this.octopodes == null)) this.octopodes = new java.util.ArrayList<Number>(); @@ -34,6 +39,11 @@ import lombok.Singular; this.octopodes.addAll(octopodes); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularSetsBuilder<T> clearOctopodes() { + if ((this.octopodes != null)) + this.octopodes.clear(); + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularSetsBuilder<T> rawSet(java.lang.Object rawSet) { if ((this.rawSet == null)) this.rawSet = new java.util.ArrayList<java.lang.Object>(); @@ -46,6 +56,11 @@ import lombok.Singular; this.rawSet.addAll(rawSet); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularSetsBuilder<T> clearRawSet() { + if ((this.rawSet != null)) + this.rawSet.clear(); + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularSetsBuilder<T> stringSet(String stringSet) { if ((this.stringSet == null)) this.stringSet = new java.util.ArrayList<String>(); @@ -58,6 +73,11 @@ import lombok.Singular; this.stringSet.addAll(stringSet); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularSetsBuilder<T> clearStringSet() { + if ((this.stringSet != null)) + this.stringSet.clear(); + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderSingularSets<T> build() { java.util.Set<T> dangerMice; switch (((this.dangerMice == null) ? 0 : this.dangerMice.size())) { diff --git a/test/transform/resource/after-ecj/BuilderWithToBuilder.java b/test/transform/resource/after-ecj/BuilderWithToBuilder.java index 423865ff..0d296cb6 100644 --- a/test/transform/resource/after-ecj/BuilderWithToBuilder.java +++ b/test/transform/resource/after-ecj/BuilderWithToBuilder.java @@ -33,6 +33,11 @@ import lombok.Builder; this.bars.addAll(bars); return this; } + public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderWithToBuilderBuilder<T> clearBars() { + if ((this.bars != null)) + this.bars.clear(); + return this; + } public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") BuilderWithToBuilder<T> build() { java.util.List<T> bars; switch (((this.bars == null) ? 0 : this.bars.size())) { diff --git a/test/transform/resource/after-ecj/EqualsAndHashcodeOfExclude.java b/test/transform/resource/after-ecj/EqualsAndHashcodeOfExclude.java new file mode 100644 index 00000000..283c5430 --- /dev/null +++ b/test/transform/resource/after-ecj/EqualsAndHashcodeOfExclude.java @@ -0,0 +1,46 @@ +final @lombok.EqualsAndHashCode(of = {"x"}) class EqualsAndHashCodeOf { + int x; + int y; + EqualsAndHashCodeOf() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof EqualsAndHashCodeOf))) + return false; + final EqualsAndHashCodeOf other = (EqualsAndHashCodeOf) o; + if ((this.x != other.x)) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.x); + return result; + } +} +final @lombok.EqualsAndHashCode(exclude = {"y"}) class EqualsAndHashCodeExclude { + int x; + int y; + EqualsAndHashCodeExclude() { + super(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof EqualsAndHashCodeExclude))) + return false; + final EqualsAndHashCodeExclude other = (EqualsAndHashCodeExclude) o; + if ((this.x != other.x)) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.x); + return result; + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/FieldDefaultsViaConfig.java b/test/transform/resource/after-ecj/FieldDefaultsViaConfig.java new file mode 100644 index 00000000..689d2601 --- /dev/null +++ b/test/transform/resource/after-ecj/FieldDefaultsViaConfig.java @@ -0,0 +1,15 @@ +class FieldDefaultsViaConfig1 { + private final int x; + private @lombok.experimental.NonFinal int y; + FieldDefaultsViaConfig1(int x) { + super(); + this.x = x; + } +} +@lombok.experimental.FieldDefaults(level = lombok.AccessLevel.PROTECTED) class FieldDefaultsViaConfig2 { + final @lombok.experimental.PackagePrivate int x = 2; + protected final int y = 0; + FieldDefaultsViaConfig2() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/FieldDefaultsViaConfigAndRequiredArgsConstructor.java b/test/transform/resource/after-ecj/FieldDefaultsViaConfigAndRequiredArgsConstructor.java new file mode 100644 index 00000000..6a727f1d --- /dev/null +++ b/test/transform/resource/after-ecj/FieldDefaultsViaConfigAndRequiredArgsConstructor.java @@ -0,0 +1,7 @@ +@lombok.RequiredArgsConstructor class FieldDefaultsViaConfigAndRequiredArgsConstructor { + final int x; + public @java.beans.ConstructorProperties({"x"}) @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") FieldDefaultsViaConfigAndRequiredArgsConstructor(final int x) { + super(); + this.x = x; + } +} diff --git a/test/transform/resource/after-ecj/NonNullOnParameterOfDefaultMethod.java b/test/transform/resource/after-ecj/NonNullOnParameterOfDefaultMethod.java new file mode 100644 index 00000000..85e99702 --- /dev/null +++ b/test/transform/resource/after-ecj/NonNullOnParameterOfDefaultMethod.java @@ -0,0 +1,10 @@ +interface NonNullOnParameterOfDefaultMethod { + void test(@lombok.NonNull String arg); + default void test2(@lombok.NonNull String arg) { + if ((arg == null)) + { + throw new java.lang.NullPointerException("arg"); + } + System.out.println(arg); + } +} diff --git a/test/transform/resource/before/BuilderInstanceMethod.java b/test/transform/resource/before/BuilderInstanceMethod.java new file mode 100644 index 00000000..666664a2 --- /dev/null +++ b/test/transform/resource/before/BuilderInstanceMethod.java @@ -0,0 +1,8 @@ +import java.util.List; + +class BuilderInstanceMethod<T> { + @lombok.Builder + public String create(int show, final int yes, List<T> also, int $andMe) { + return "" + show + yes + also + $andMe; + } +} diff --git a/test/transform/resource/before/EqualsAndHashCodeOfExclude.java b/test/transform/resource/before/EqualsAndHashCodeOfExclude.java new file mode 100644 index 00000000..0625ba52 --- /dev/null +++ b/test/transform/resource/before/EqualsAndHashCodeOfExclude.java @@ -0,0 +1,11 @@ +@lombok.EqualsAndHashCode(of={"x"}) +final class EqualsAndHashCodeOf { + int x; + int y; +} + +@lombok.EqualsAndHashCode(exclude={"y"}) +final class EqualsAndHashCodeExclude { + int x; + int y; +}
\ No newline at end of file diff --git a/test/transform/resource/before/FieldDefaultsViaConfig.java b/test/transform/resource/before/FieldDefaultsViaConfig.java new file mode 100644 index 00000000..61f6daca --- /dev/null +++ b/test/transform/resource/before/FieldDefaultsViaConfig.java @@ -0,0 +1,16 @@ +//CONF: lombok.fieldDefaults.defaultFinal = true +//CONF: lombok.fieldDefaults.defaultPrivate = true +class FieldDefaultsViaConfig1 { + int x; + @lombok.experimental.NonFinal int y; + + FieldDefaultsViaConfig1(int x) { + this.x = x; + } +} + +@lombok.experimental.FieldDefaults(level = lombok.AccessLevel.PROTECTED) +class FieldDefaultsViaConfig2 { + @lombok.experimental.PackagePrivate int x = 2; + int y = 0; +} diff --git a/test/transform/resource/before/FieldDefaultsViaConfigAndRequiredArgsConstructor.java b/test/transform/resource/before/FieldDefaultsViaConfigAndRequiredArgsConstructor.java new file mode 100644 index 00000000..8c0607d7 --- /dev/null +++ b/test/transform/resource/before/FieldDefaultsViaConfigAndRequiredArgsConstructor.java @@ -0,0 +1,5 @@ +//CONF: lombok.fieldDefaults.defaultFinal = true +@lombok.RequiredArgsConstructor +class FieldDefaultsViaConfigAndRequiredArgsConstructor { + int x; +} diff --git a/test/transform/resource/before/NonNullOnParameterOfDefaultMethod.java b/test/transform/resource/before/NonNullOnParameterOfDefaultMethod.java new file mode 100644 index 00000000..ab343ef0 --- /dev/null +++ b/test/transform/resource/before/NonNullOnParameterOfDefaultMethod.java @@ -0,0 +1,7 @@ +// version 8: +interface NonNullOnParameterOfDefaultMethod { + void test(@lombok.NonNull String arg); + default void test2(@lombok.NonNull String arg) { + System.out.println(arg); + } +} diff --git a/test/transform/resource/before/ValLambda.java b/test/transform/resource/before/ValLambda.java index ed843ed7..51c4fba1 100644 --- a/test/transform/resource/before/ValLambda.java +++ b/test/transform/resource/before/ValLambda.java @@ -14,7 +14,7 @@ class ValLambda { } // public void castLubLambda() { -// Runnable foo = (Runnable)((System.currentTimeMillis() > 0) ? ()-> {} : System.out::println); -// lombok.val foo = (Runnable)((System.currentTimeMillis() > 0) ? ()-> {} : System.out::println); +// Runnable foo = (Runnable) ((System.currentTimeMillis() > 0) ? () -> {} : System.out::println); +// lombok.val foo = (Runnable) ((System.currentTimeMillis() > 0) ? () -> {} : System.out::println); // } } diff --git a/test/transform/resource/messages-delombok/NonNullOnParameterAbstract.java.messages b/test/transform/resource/messages-delombok/NonNullOnParameterAbstract.java.messages deleted file mode 100644 index fd5bffd5..00000000 --- a/test/transform/resource/messages-delombok/NonNullOnParameterAbstract.java.messages +++ /dev/null @@ -1 +0,0 @@ -6 @NonNull is meaningless on a parameter of an abstract method. diff --git a/test/transform/resource/messages-ecj/NonNullOnParameterAbstract.java.messages b/test/transform/resource/messages-ecj/NonNullOnParameterAbstract.java.messages deleted file mode 100644 index 8eb312ef..00000000 --- a/test/transform/resource/messages-ecj/NonNullOnParameterAbstract.java.messages +++ /dev/null @@ -1 +0,0 @@ -6 @NonNull is meaningless on a parameter of an abstract method.
\ No newline at end of file diff --git a/test/transform/resource/messages-idempotent/NonNullOnParameterAbstract.java.messages b/test/transform/resource/messages-idempotent/NonNullOnParameterAbstract.java.messages deleted file mode 100644 index 0d9fcfdc..00000000 --- a/test/transform/resource/messages-idempotent/NonNullOnParameterAbstract.java.messages +++ /dev/null @@ -1 +0,0 @@ -9 @NonNull is meaningless on a parameter of an abstract method.
\ No newline at end of file diff --git a/usage_examples/BuilderExample_post.jpage b/usage_examples/BuilderExample_post.jpage index 8a1d1e69..54b064d7 100644 --- a/usage_examples/BuilderExample_post.jpage +++ b/usage_examples/BuilderExample_post.jpage @@ -51,6 +51,14 @@ public class BuilderExample { return this; } + public BuilderExampleBuilder clearOccupations() { + if (this.occupations != null) { + this.occupations.clear(); + } + + return this; + } + public BuilderExample build() { // complicated switch statement to produce a compact properly sized immutable set omitted. // go to https://projectlombok.org/features/Singular-snippet.html to see it. diff --git a/website/features/Builder.html b/website/features/Builder.html index c6f51ff1..88083a27 100644 --- a/website/features/Builder.html +++ b/website/features/Builder.html @@ -18,7 +18,8 @@ <code>@Builder</code> was introduced as experimental feature in lombok v0.12.0. </p><p> <code>@Builder</code> gained <code>@Singular</code> support and was promoted to the main <code>lombok</code> package since lombok v1.16.0. - </p> + </p><p> + <code>@Builder</code> with <code>@Singular</code> adds a clear method since lombok v1.16.8. </div> <div class="overview"> <h3>Overview</h3> @@ -28,16 +29,16 @@ <code>@Builder</code> lets you automatically produce the code required to have your class be instantiable with code such as:<br /> <code>Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();</code> </p><p> - <code>@Builder</code> can be placed on a class, or on a constructor, or on a static method. While the "on a class" and "on a constructor" - mode are the most common use-case, <code>@Builder</code> is most easily explained with the "static method" use-case. + <code>@Builder</code> can be placed on a class, or on a constructor, or on a method. While the "on a class" and "on a constructor" + mode are the most common use-case, <code>@Builder</code> is most easily explained with the "method" use-case. </p><p> - A static method annotated with <code>@Builder</code> (from now on called the <em>target</em>) causes the following 7 things to be generated:<ul> - <li>An inner static class named <code><em>Foo</em>Builder</code>, with the same type arguments as the static method (called the <em>builder</em>).</li> + A method annotated with <code>@Builder</code> (from now on called the <em>target</em>) causes the following 7 things to be generated:<ul> + <li>An inner class named <code><em>Foo</em>Builder</code>, with the same type arguments as the method (called the <em>builder</em>).</li> <li>In the <em>builder</em>: One private non-static non-final field for each parameter of the <em>target</em>.</li> <li>In the <em>builder</em>: A package private no-args empty constructor.</li> <li>In the <em>builder</em>: A 'setter'-like method for each parameter of the <em>target</em>: It has the same type as that parameter and the same name. It returns the builder itself, so that the setter calls can be chained, as in the above example.</li> - <li>In the <em>builder</em>: A <code>build()</code> method which calls the static method, passing in each field. It returns the same type that the + <li>In the <em>builder</em>: A <code>build()</code> method which calls the method, passing in each field. It returns the same type that the <em>target</em> returns.</li> <li>In the <em>builder</em>: A sensible <code>toString()</code> implementation.</li> <li>In the class containing the <em>target</em>: A static <code>builder()</code> method, which creates a new instance of the <em>builder</em>.</li> @@ -51,7 +52,7 @@ element to the list. For example: <code>Person.builder().job("Mythbusters").job("Unchained Reaction").build();</code> would result in the <code>List<String> jobs</code> field to have 2 strings in it. To get this behaviour, the field/parameter needs to be annotated with <code>@Singular</code>. The feature has <a href="#singular">its own documentation</a>. </p><p> - Now that the "static method" mode is clear, putting a <code>@Builder</code> annotation on a constructor functions similarly; effectively, + Now that the "method" mode is clear, putting a <code>@Builder</code> annotation on a constructor functions similarly; effectively, constructors are just static methods that have a special syntax to invoke them: Their 'return type' is the class they construct, and their type parameters are the same as the type parameters of the class itself. </p><p> @@ -63,8 +64,8 @@ </p><p> The name of the builder class is <code><em>Foobar</em>Builder</code>, where <em>Foobar</em> is the simplified, title-cased form of the return type of the <em>target</em> - that is, the name of your type for <code>@Builder</code> on constructors and types, and the name of the return type for <code>@Builder</code> - on static methods. For example, if <code>@Builder</code> is applied to a class named <code>com.yoyodyne.FancyList<T></code>, then the builder name will be - <code>FancyListBuilder<T></code>. If <code>@Builder</code> is applied to a static method that returns <code>void</code>, the builder will be named + on methods. For example, if <code>@Builder</code> is applied to a class named <code>com.yoyodyne.FancyList<T></code>, then the builder name will be + <code>FancyListBuilder<T></code>. If <code>@Builder</code> is applied to a method that returns <code>void</code>, the builder will be named <code>VoidBuilder</code>. </p><p> The configurable aspects of builder are:<ul> @@ -80,13 +81,13 @@ <div class="overview"> <h3><a name="singular">@Singular</a></h3> <p> - By annotating one of the parameters (if annotating a static method or constructor with <code>@Builder</code>) or fields (if annotating a class with <code>@Builder</code>) with the + By annotating one of the parameters (if annotating a method or constructor with <code>@Builder</code>) or fields (if annotating a class with <code>@Builder</code>) with the <code>@Singular</code> annotation, lombok will treat that builder node as a collection, and it generates 2 'adder' methods instead of a 'setter' method. One which adds a single element to the collection, and one - which adds all elements of another collection to the collection. No setter to just set the collection (replacing whatever was already added) will be generated. These 'singular' builders + which adds all elements of another collection to the collection. No setter to just set the collection (replacing whatever was already added) will be generated. A 'clear' method is also generated. These 'singular' builders are very complicated in order to guarantee the following properties: <ul> <li>When invoking <code>build()</code>, the produced collection will be immutable.</li> - <li>Calling one of the 'adder' methods after invoking <code>build()</code> does not modify any already generated objects, and, if <code>build()</code> is later called again, another collection with all the elements added since the creation of the builder is generated.</li> + <li>Calling one of the 'adder' methods, or the 'clear' method, after invoking <code>build()</code> does not modify any already generated objects, and, if <code>build()</code> is later called again, another collection with all the elements added since the creation of the builder is generated.</li> <li>The produced collection will be compacted to the smallest feasible format while remaining efficient.</li> </ul> </p><p> diff --git a/website/features/NonNull.html b/website/features/NonNull.html index d62441f4..50acf627 100644 --- a/website/features/NonNull.html +++ b/website/features/NonNull.html @@ -15,7 +15,7 @@ <div class="overview"> <h3>Overview</h3> <p> - <em>NEW in Lombok 0.11.10: </em>You can use <code>@NonNull</code> on the parameter of a method or constructor to have lombok generate a null-check statement for you. + <em>NEW in Lombok 0.11.10: </em>You can use <code>@NonNull</code> on the parameter of a method or constructor to have lombok generate a null-check statement for you.<br /> </p><p> Lombok has always treated any annotation named <code>@NonNull</code> on a field as a signal to generate a null-check if lombok generates an entire method or constructor for you, via for example <a href="Data.html"><code>@Data</code></a>. Now, however, using lombok's own <code>@lombok.NonNull</code> on a parameter results in the insertion of just the null-check @@ -60,6 +60,9 @@ this feature only triggers on lombok's own <code>@NonNull</code> annotation from the <code>lombok</code> package. </p><p> A <code>@NonNull</code> on a primitive parameter results in a warning. No null-check will be generated. + </p><p> + A <code>@NonNull</code> on a parameter of an abstract method used to generate a warning; starting with version 1.16.8, this is no longer the case, to acknowledge the notion that <code>@NonNull</code> also has a + documentary role. For the same reason, you can annotate a method as <code>@NonNull</code>; this is allowed, generates no warning, and does not generate any code. </p> </div> </div> diff --git a/website/features/configuration.html b/website/features/configuration.html index 7e79a9c0..21864409 100644 --- a/website/features/configuration.html +++ b/website/features/configuration.html @@ -85,6 +85,15 @@ <code>lombok.extern.findbugs.addSuppressFBWarnings = true</code> </div> </div> + <div class="overview" style="clear: left;"> + <h3>Config keys that can even affect source files with 0 lombok annotations</h3> + <p> + <div class="snippet example"> + <code>lombok.fieldDefaults.defaultPrivate = true</code><br /> + <code>lombok.fieldDefaults.defaultFinal = true</code> + </div> + Turning either of these options on means lombok will make <em>every</em> field in <em>every</em> source file final and/or private unless it has an explicit access modifier or annotation to suppress this. <a href="experimental/FieldDefaults.html">See the <code>@FieldDefaults</code> documentation for more</a>. + </div> <div style="clear: left;"></div> <div class="footer"> <a href="index.html">Back to features</a> | <a href="Log.html">Previous feature (@Log)</a> | <span class="disabled">Next feature</span><br /> diff --git a/website/features/experimental/FieldDefaults.html b/website/features/experimental/FieldDefaults.html index 5ad30952..026f23fc 100644 --- a/website/features/experimental/FieldDefaults.html +++ b/website/features/experimental/FieldDefaults.html @@ -61,6 +61,10 @@ <dl> <dt><code>lombok.fieldDefaults.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set)</dt> <dd>Lombok will flag any usage of <code>@FieldDefaults</code> as a warning or error if configured.</dd> + <dt><code>lombok.fieldDefaults.defaultPrivate</code> = [<code>true</code> | <code>false</code>] (default: false)</dt> + <dd>(Since 1.16.8) If set to <code>true</code>, <em>every</em> field in <em>every</em> class or enum anywhere in the sources being compiled will be marked as <code>private</code> unless it has an explicit access modifier or the <code>@PackagePrivate</code> annotation, or an explicit <code>@FieldDefaults</code> annotation is present to override this config key.</dd> + <dt><code>lombok.fieldDefaults.defaultFinal</code> = [<code>true</code> | <code>false</code>] (default: false)</dt> + <dd>(Since 1.16.8) If set to <code>true</code>, <em>every</em> field in <em>every</em> class or enum anywhere in the sources being compiled will be marked as <code>final</code> unless it has the <code>@NonFinal</code> annotation, or an explicit <code>@FieldDefaults</code> annotation is present to override this config key.</dd> </dl> </div> <div class="overview"> |