diff options
Diffstat (limited to 'src/core/lombok/javac')
12 files changed, 195 insertions, 78 deletions
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 { |