diff options
Diffstat (limited to 'src/core')
28 files changed, 511 insertions, 269 deletions
diff --git a/src/core/lombok/AllArgsConstructor.java b/src/core/lombok/AllArgsConstructor.java index 3037c9db..75f87211 100644 --- a/src/core/lombok/AllArgsConstructor.java +++ b/src/core/lombok/AllArgsConstructor.java @@ -49,7 +49,12 @@ public @interface AllArgsConstructor { String staticName() default ""; /** - * Any annotations listed here are put on the generated constructor. The syntax for this feature is: {@code @AllArgsConstructor(onConstructor=@__({@AnnotationsGoHere}))} + * Any annotations listed here are put on the generated constructor. + * The syntax for this feature depends on JDK version (nothing we can do about that; it's to work around javac bugs).<br /> + * up to JDK7:<br /> + * {@code @AllArgsConstructor(onConstructor=@__({@AnnotationsGoHere}))}<br /> + * from JDK8:<br /> + * {@code @AllArgsConstructor(onConstructor_={@AnnotationsGohere})} // note the underscore after {@code onConstructor}. */ AnyAnnotation[] onConstructor() default {}; @@ -59,16 +64,6 @@ public @interface AllArgsConstructor { AccessLevel access() default lombok.AccessLevel.PUBLIC; /** - * Constructors are generated with the {@link java.beans.ConstructorProperties} annotation. - * However, this annotation is new in 1.6 which means those compiling for 1.5 will need - * to set this value to true. - * - * @deprecated THIS FEATURE WILL BE REMOVED after March 31st 2015. Use configuration key {@link ConfigurationKeys#ANY_CONSTRUCTOR_SUPPRESS_CONSTRUCTOR_PROPERTIES} instead. - */ - @Deprecated - boolean suppressConstructorProperties() default false; - - /** * Placeholder annotation to enable the placement of annotations on the generated code. * @deprecated Don't use this annotation, ever - Read the documentation. */ diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index ff17ca09..f0e070e2 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -41,30 +41,28 @@ public class ConfigurationKeys { /** * lombok configuration: {@code lombok.addGeneratedAnnotation} = {@code true} | {@code false}. * - * If unset or {@code true}, lombok generates various annotations to mark generated code like {@code @javax.annotation.Generated("lombok")} and {@code @lombok.Generated}. + * If unset or {@code true}, lombok generates {@code @javax.annotation.Generated("lombok")} on all fields, methods, and types that are generated, unless {@code lombok.addJavaxGeneratedAnnotation} is set. * * @see ConfigurationKeys#ADD_JAVAX_GENERATED_ANNOTATIONS * @see ConfigurationKeys#ADD_LOMBOK_GENERATED_ANNOTATIONS + * @deprecated Since version 1.16.14, use {@link #ADD_JAVAX_GENERATED_ANNOTATIONS} instead. */ - public static final ConfigurationKey<Boolean> ADD_GENERATED_ANNOTATIONS = new ConfigurationKey<Boolean>("lombok.addGeneratedAnnotation", "Generate @javax.annotation.Generated on all generated code (default: true).") {}; + @Deprecated + public static final ConfigurationKey<Boolean> ADD_GENERATED_ANNOTATIONS = new ConfigurationKey<Boolean>("lombok.addGeneratedAnnotation", "Generate @javax.annotation.Generated on all generated code (default: true). Deprecated, use 'lombok.addJavaxGeneratedAnnotation' instead.") {}; /** * lombok configuration: {@code lombok.addJavaxGeneratedAnnotation} = {@code true} | {@code false}. * * If unset or {@code true}, lombok generates {@code @javax.annotation.Generated("lombok")} on all fields, methods, and types that are generated, unless {@code lombok.addGeneratedAnnotation} is set to {@code false}. - * - * @see ConfigurationKeys#ADD_GENERATED_ANNOTATIONS */ public static final ConfigurationKey<Boolean> ADD_JAVAX_GENERATED_ANNOTATIONS = new ConfigurationKey<Boolean>("lombok.addJavaxGeneratedAnnotation", "Generate @javax.annotation.Generated on all generated code (default: follow lombok.addGeneratedAnnotation).") {}; /** * lombok configuration: {@code lombok.addLombokGeneratedAnnotation} = {@code true} | {@code false}. * - * If unset or {@code true}, lombok generates {@code @lombok.Generated} on all fields, methods, and types that are generated, unless {@code lombok.addGeneratedAnnotation} is set to {@code false}. - * - * @see ConfigurationKeys#ADD_GENERATED_ANNOTATIONS + * If {@code true}, lombok generates {@code @lombok.Generated} on all fields, methods, and types that are generated. */ - public static final ConfigurationKey<Boolean> ADD_LOMBOK_GENERATED_ANNOTATIONS = new ConfigurationKey<Boolean>("lombok.addLombokGeneratedAnnotation", "Generate @lombok.Generated on all generated code (default: follow lombok.addGeneratedAnnotation).") {}; + public static final ConfigurationKey<Boolean> ADD_LOMBOK_GENERATED_ANNOTATIONS = new ConfigurationKey<Boolean>("lombok.addLombokGeneratedAnnotation", "Generate @lombok.Generated on all generated code (default: false).") {}; /** * lombok configuration: {@code lombok.extern.findbugs.addSuppressFBWarnings} = {@code true} | {@code false}. diff --git a/src/core/lombok/EqualsAndHashCode.java b/src/core/lombok/EqualsAndHashCode.java index 605815ed..34f4ffc6 100644 --- a/src/core/lombok/EqualsAndHashCode.java +++ b/src/core/lombok/EqualsAndHashCode.java @@ -63,8 +63,13 @@ public @interface EqualsAndHashCode { boolean doNotUseGetters() default false; /** - * Any annotations listed here are put on the generated parameter of {@code equals} and {@code canEqual}. The syntax for this feature is: {@code @EqualsAndHashCode(onParam=@__({@AnnotationsGoHere}))} - * This is useful to add for example a {@code Nullable} annotation. + * Any annotations listed here are put on the generated parameter of {@code equals} and {@code canEqual}. + * This is useful to add for example a {@code Nullable} annotation.<br /> + * The syntax for this feature depends on JDK version (nothing we can do about that; it's to work around javac bugs).<br /> + * up to JDK7:<br /> + * {@code @EqualsAndHashCode(onParam=@__({@AnnotationsGoHere}))}<br /> + * from JDK8:<br /> + * {@code @EqualsAndHashCode(onParam_={@AnnotationsGohere})} // note the underscore after {@code onParam}. */ AnyAnnotation[] onParam() default {}; diff --git a/src/core/lombok/Getter.java b/src/core/lombok/Getter.java index 906ae60f..5a4056fa 100644 --- a/src/core/lombok/Getter.java +++ b/src/core/lombok/Getter.java @@ -58,9 +58,14 @@ public @interface Getter { lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC; /** - * Any annotations listed here are put on the generated method. The syntax for this feature is: {@code @Getter(onMethod=@__({@AnnotationsGoHere}))} + * Any annotations listed here are put on the generated method. + * The syntax for this feature depends on JDK version (nothing we can do about that; it's to work around javac bugs).<br /> + * up to JDK7:<br /> + * {@code @Getter(onMethod=@__({@AnnotationsGoHere}))}<br /> + * from JDK8:<br /> + * {@code @Getter(onMethod_={@AnnotationsGohere})} // note the underscore after {@code onMethod}. */ - AnyAnnotation[] onMethod() default @AnyAnnotation; + AnyAnnotation[] onMethod() default {}; boolean lazy() default false; diff --git a/src/core/lombok/NoArgsConstructor.java b/src/core/lombok/NoArgsConstructor.java index ff437bba..5f2268a8 100644 --- a/src/core/lombok/NoArgsConstructor.java +++ b/src/core/lombok/NoArgsConstructor.java @@ -51,7 +51,12 @@ public @interface NoArgsConstructor { String staticName() default ""; /** - * Any annotations listed here are put on the generated constructor. The syntax for this feature is: {@code @NoArgsConstructor(onConstructor=@__({@AnnotationsGoHere}))} + * Any annotations listed here are put on the generated constructor. + * The syntax for this feature depends on JDK version (nothing we can do about that; it's to work around javac bugs).<br /> + * up to JDK7:<br /> + * {@code @NoArgsConstructor(onConstructor=@__({@AnnotationsGoHere}))}<br /> + * from JDK8:<br /> + * {@code @NoArgsConstructor(onConstructor_={@AnnotationsGohere})} // note the underscore after {@code onConstructor}. */ AnyAnnotation[] onConstructor() default {}; diff --git a/src/core/lombok/RequiredArgsConstructor.java b/src/core/lombok/RequiredArgsConstructor.java index 7a9da3f9..2f4d0aaf 100644 --- a/src/core/lombok/RequiredArgsConstructor.java +++ b/src/core/lombok/RequiredArgsConstructor.java @@ -49,7 +49,12 @@ public @interface RequiredArgsConstructor { String staticName() default ""; /** - * Any annotations listed here are put on the generated constructor. The syntax for this feature is: {@code @RequiredArgsConstructor(onConstructor=@__({@AnnotationsGoHere}))} + * Any annotations listed here are put on the generated constructor. + * The syntax for this feature depends on JDK version (nothing we can do about that; it's to work around javac bugs).<br /> + * up to JDK7:<br /> + * {@code @RequiredArgsConstructor(onConstructor=@__({@AnnotationsGoHere}))}<br /> + * from JDK8:<br /> + * {@code @RequiredArgsConstructor(onConstructor_={@AnnotationsGohere})} // note the underscore after {@code onConstructor}. */ AnyAnnotation[] onConstructor() default {}; @@ -59,16 +64,6 @@ public @interface RequiredArgsConstructor { AccessLevel access() default lombok.AccessLevel.PUBLIC; /** - * Constructors are generated with the {@link java.beans.ConstructorProperties} annotation. - * However, this annotation is new in 1.6 which means those compiling for 1.5 will need - * to set this value to true. - * - * @deprecated THIS FEATURE WILL BE REMOVED after March 31st 2015. Use configuration key {@link ConfigurationKeys#ANY_CONSTRUCTOR_SUPPRESS_CONSTRUCTOR_PROPERTIES} instead. - */ - @Deprecated - boolean suppressConstructorProperties() default false; - - /** * Placeholder annotation to enable the placement of annotations on the generated code. * @deprecated Don't use this annotation, ever - Read the documentation. */ diff --git a/src/core/lombok/Setter.java b/src/core/lombok/Setter.java index ba9e9759..f2ebe5b3 100644 --- a/src/core/lombok/Setter.java +++ b/src/core/lombok/Setter.java @@ -59,12 +59,22 @@ public @interface Setter { lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC; /** - * Any annotations listed here are put on the generated method. The syntax for this feature is: {@code @Setter(onMethod=@__({@AnnotationsGoHere}))} + * Any annotations listed here are put on the generated method. + * The syntax for this feature depends on JDK version (nothing we can do about that; it's to work around javac bugs).<br /> + * up to JDK7:<br /> + * {@code @Setter(onMethod=@__({@AnnotationsGoHere}))}<br /> + * from JDK8:<br /> + * {@code @Setter(onMethod_={@AnnotationsGohere})} // note the underscore after {@code onMethod}. */ AnyAnnotation[] onMethod() default {}; /** - * Any annotations listed here are put on the generated method's parameter. The syntax for this feature is: {@code @Setter(onParam=@__({@AnnotationsGoHere}))} + * Any annotations listed here are put on the generated method's parameter. + * The syntax for this feature depends on JDK version (nothing we can do about that; it's to work around javac bugs).<br /> + * up to JDK7:<br /> + * {@code @Setter(onParam=@__({@AnnotationsGoHere}))}<br /> + * from JDK8:<br /> + * {@code @Setter(onParam_={@AnnotationsGohere})} // note the underscore after {@code onParam}. */ AnyAnnotation[] onParam() default {}; diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java index 4fdb7216..a50b72d5 100644 --- a/src/core/lombok/core/Version.java +++ b/src/core/lombok/core/Version.java @@ -30,7 +30,7 @@ public class Version { // ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries). // Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example. // Official builds always end in an even number. (Since 0.10.2). - private static final String VERSION = "1.16.13"; + private static final String VERSION = "1.16.15"; private static final String RELEASE_NAME = "Edgy Guinea Pig"; // private static final String RELEASE_NAME = "Candid Duck"; diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index a05578d4..6c3a0b79 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -109,8 +109,9 @@ public class HandlerUtil { } } - public static boolean shouldAddGenerated(LombokNode<?, ?, ?> node, ConfigurationKey<Boolean> key) { - Boolean add = node.getAst().readConfiguration(key); + @SuppressWarnings("deprecation") + public static boolean shouldAddGenerated(LombokNode<?, ?, ?> node) { + Boolean add = node.getAst().readConfiguration(ConfigurationKeys.ADD_JAVAX_GENERATED_ANNOTATIONS); if (add != null) return add; return !Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_GENERATED_ANNOTATIONS)); } diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index f822e095..4726b17e 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1345,10 +1345,10 @@ public class EclipseHandlerUtil { public static Annotation[] addGenerated(EclipseNode node, ASTNode source, Annotation[] originalAnnotationArray) { Annotation[] result = originalAnnotationArray; - if (HandlerUtil.shouldAddGenerated(node, ConfigurationKeys.ADD_JAVAX_GENERATED_ANNOTATIONS)) { + if (HandlerUtil.shouldAddGenerated(node)) { result = addAnnotation(source, result, JAVAX_ANNOTATION_GENERATED, new StringLiteral(LOMBOK, 0, 0, 0)); } - if (HandlerUtil.shouldAddGenerated(node, ConfigurationKeys.ADD_LOMBOK_GENERATED_ANNOTATIONS)) { + if (Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_LOMBOK_GENERATED_ANNOTATIONS))) { result = addAnnotation(source, result, LOMBOK_GENERATED, null); } return result; @@ -1616,6 +1616,14 @@ public class EclipseHandlerUtil { return true; } + public static void addError(String errorName, EclipseNode node) { + if (node.getLatestJavaSpecSupported() < 8) { + node.addError("The correct format is " + errorName + "_={@SomeAnnotation, @SomeOtherAnnotation})"); + } else { + node.addError("The correct format is " + errorName + "=@__({@SomeAnnotation, @SomeOtherAnnotation}))"); + } + } + public static List<Annotation> unboxAndRemoveAnnotationParameter(Annotation annotation, String annotationName, String errorName, EclipseNode errorNode) { if ("value".equals(annotationName)) { // We can't unbox this, because SingleMemberAnnotation REQUIRES a value, and this method @@ -1638,51 +1646,70 @@ public class EclipseHandlerUtil { char[] nameAsCharArray = annotationName.toCharArray(); + top: for (int i = 0; i < pairs.length; i++) { - if (pairs[i].name == null || !Arrays.equals(nameAsCharArray, pairs[i].name)) continue; + boolean allowRaw; + char[] name = pairs[i].name; + if (name == null) continue; + if (name.length < nameAsCharArray.length) continue; + for (int j = 0; j < nameAsCharArray.length; j++) { + if (name[j] != nameAsCharArray[j]) continue top; + } + allowRaw = name.length > nameAsCharArray.length; + for (int j = nameAsCharArray.length; j < name.length; j++) { + if (name[j] != '_') continue top; + } + // If we're still here it's the targeted annotation param. Expression value = pairs[i].value; MemberValuePair[] newPairs = new MemberValuePair[pairs.length - 1]; if (i > 0) System.arraycopy(pairs, 0, newPairs, 0, i); if (i < pairs.length - 1) System.arraycopy(pairs, i + 1, newPairs, i, pairs.length - i - 1); normalAnnotation.memberValuePairs = newPairs; - // We have now removed the annotation parameter and stored '@__({... annotations ...})', - // which we must now unbox. - if (!(value instanceof Annotation)) { - errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); - return Collections.emptyList(); - } - - Annotation atDummyIdentifier = (Annotation) value; - if (!(atDummyIdentifier.type instanceof SingleTypeReference) || - !isAllValidOnXCharacters(((SingleTypeReference) atDummyIdentifier.type).token)) { - errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); - return Collections.emptyList(); - } - - if (atDummyIdentifier instanceof MarkerAnnotation) { - // It's @Getter(onMethod=@__). This is weird, but fine. - return Collections.emptyList(); - } + // We have now removed the annotation parameter and stored the value, + // which we must now unbox. It's either annotations, or @__(annotations). Expression content = null; - if (atDummyIdentifier instanceof NormalAnnotation) { - MemberValuePair[] mvps = ((NormalAnnotation) atDummyIdentifier).memberValuePairs; - if (mvps == null || mvps.length == 0) { - // It's @Getter(onMethod=@__()). This is weird, but fine. + if (value instanceof ArrayInitializer) { + if (!allowRaw) { + addError(errorName, errorNode); return Collections.emptyList(); } - if (mvps.length == 1 && Arrays.equals("value".toCharArray(), mvps[0].name)) { - content = mvps[0].value; + content = value; + } else if (!(value instanceof Annotation)) { + addError(errorName, errorNode); + return Collections.emptyList(); + } else { + Annotation atDummyIdentifier = (Annotation) value; + if (atDummyIdentifier.type instanceof SingleTypeReference && isAllValidOnXCharacters(((SingleTypeReference) atDummyIdentifier.type).token)) { + if (atDummyIdentifier instanceof MarkerAnnotation) { + return Collections.emptyList(); + } else if (atDummyIdentifier instanceof NormalAnnotation) { + MemberValuePair[] mvps = ((NormalAnnotation) atDummyIdentifier).memberValuePairs; + if (mvps == null || mvps.length == 0) { + return Collections.emptyList(); + } + if (mvps.length == 1 && Arrays.equals("value".toCharArray(), mvps[0].name)) { + content = mvps[0].value; + } + } else if (atDummyIdentifier instanceof SingleMemberAnnotation) { + content = ((SingleMemberAnnotation) atDummyIdentifier).memberValue; + } else { + addError(errorName, errorNode); + return Collections.emptyList(); + } + } else { + if (allowRaw) { + content = atDummyIdentifier; + } else { + addError(errorName, errorNode); + return Collections.emptyList(); + } } } - if (atDummyIdentifier instanceof SingleMemberAnnotation) { - content = ((SingleMemberAnnotation) atDummyIdentifier).memberValue; - } - if (content == null) { - errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); + addError(errorName, errorNode); return Collections.emptyList(); } @@ -1694,13 +1721,13 @@ public class EclipseHandlerUtil { if (expressions != null) for (Expression ex : expressions) { if (ex instanceof Annotation) result.add((Annotation) ex); else { - errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); + addError(errorName, errorNode); return Collections.emptyList(); } } return result; } else { - errorNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); + addError(errorName, errorNode); return Collections.emptyList(); } } diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index afa03538..8c200a94 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -189,7 +189,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { allFields.add(fieldNode); } - new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER, null, + new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER, Collections.<Annotation>emptyList(), annotationNode); returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p); @@ -395,7 +395,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) { ConstructorDeclaration cd = HandleConstructor.createConstructor( - AccessLevel.PACKAGE, builderType, Collections.<EclipseNode>emptyList(), false, null, + AccessLevel.PACKAGE, builderType, Collections.<EclipseNode>emptyList(), false, annotationNode, Collections.<Annotation>emptyList()); if (cd != null) injectMethod(builderType, cd); } diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index a3b0585d..49b09231 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -93,9 +93,9 @@ public class HandleConstructor { boolean force = ann.force(); List<EclipseNode> fields = force ? findFinalFields(typeNode) : Collections.<EclipseNode>emptyList(); - List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@NoArgsConstructor(onConstructor=", annotationNode); + List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@NoArgsConstructor(onConstructor", annotationNode); - new HandleConstructor().generateConstructor(typeNode, level, fields, force, staticName, SkipIfConstructorExists.NO, null, onConstructor, annotationNode); + new HandleConstructor().generateConstructor(typeNode, level, fields, force, staticName, SkipIfConstructorExists.NO, onConstructor, annotationNode); } } @@ -110,18 +110,15 @@ public class HandleConstructor { AccessLevel level = ann.access(); if (level == AccessLevel.NONE) return; String staticName = ann.staticName(); - Boolean suppressConstructorProperties = null; if (annotation.isExplicit("suppressConstructorProperties")) { - @SuppressWarnings("deprecation") - boolean suppress = ann.suppressConstructorProperties(); - suppressConstructorProperties = suppress; + annotationNode.addError("This deprecated feature is no longer supported. Remove it; you can create a lombok.config file with 'lombok.anyConstructor.suppressConstructorProperties = true'."); } - List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@RequiredArgsConstructor(onConstructor=", annotationNode); + List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@RequiredArgsConstructor(onConstructor", annotationNode); new HandleConstructor().generateConstructor( typeNode, level, findRequiredFields(typeNode), false, staticName, SkipIfConstructorExists.NO, - suppressConstructorProperties, onConstructor, annotationNode); + onConstructor, annotationNode); } } @@ -172,18 +169,15 @@ public class HandleConstructor { AccessLevel level = ann.access(); if (level == AccessLevel.NONE) return; String staticName = ann.staticName(); - Boolean suppressConstructorProperties = null; if (annotation.isExplicit("suppressConstructorProperties")) { - @SuppressWarnings("deprecation") - boolean suppress = ann.suppressConstructorProperties(); - suppressConstructorProperties = suppress; + annotationNode.addError("This deprecated feature is no longer supported. Remove it; you can create a lombok.config file with 'lombok.anyConstructor.suppressConstructorProperties = true'."); } - List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@AllArgsConstructor(onConstructor=", annotationNode); + List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@AllArgsConstructor(onConstructor", annotationNode); new HandleConstructor().generateConstructor( typeNode, level, findAllFields(typeNode), false, staticName, SkipIfConstructorExists.NO, - suppressConstructorProperties, onConstructor, annotationNode); + onConstructor, annotationNode); } } @@ -205,14 +199,14 @@ public class HandleConstructor { EclipseNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, List<Annotation> onConstructor, EclipseNode sourceNode) { - generateConstructor(typeNode, level, findRequiredFields(typeNode), false, staticName, skipIfConstructorExists, null, onConstructor, sourceNode); + generateConstructor(typeNode, level, findRequiredFields(typeNode), false, staticName, skipIfConstructorExists, onConstructor, sourceNode); } public void generateAllArgsConstructor( EclipseNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, List<Annotation> onConstructor, EclipseNode sourceNode) { - generateConstructor(typeNode, level, findAllFields(typeNode), false, staticName, skipIfConstructorExists, null, onConstructor, sourceNode); + generateConstructor(typeNode, level, findAllFields(typeNode), false, staticName, skipIfConstructorExists, onConstructor, sourceNode); } public enum SkipIfConstructorExists { @@ -221,7 +215,7 @@ public class HandleConstructor { public void generateConstructor( EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists, - Boolean suppressConstructorProperties, List<Annotation> onConstructor, EclipseNode sourceNode) { + List<Annotation> onConstructor, EclipseNode sourceNode) { ASTNode source = sourceNode.get(); boolean staticConstrRequired = staticName != null && !staticName.equals(""); @@ -256,7 +250,7 @@ public class HandleConstructor { ConstructorDeclaration constr = createConstructor( staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, allToDefault, - suppressConstructorProperties, sourceNode, onConstructor); + sourceNode, onConstructor); injectMethod(typeNode, constr); if (staticConstrRequired) { MethodDeclaration staticConstr = createStaticConstructor(level, staticName, typeNode, allToDefault ? Collections.<EclipseNode>emptyList() : fields, source); @@ -298,7 +292,7 @@ public class HandleConstructor { public static ConstructorDeclaration createConstructor( AccessLevel level, EclipseNode type, Collection<EclipseNode> fields, boolean allToDefault, - Boolean suppressConstructorProperties, EclipseNode sourceNode, List<Annotation> onConstructor) { + EclipseNode sourceNode, List<Annotation> onConstructor) { ASTNode source = sourceNode.get(); TypeDeclaration typeDeclaration = ((TypeDeclaration) type.get()); @@ -308,12 +302,11 @@ public class HandleConstructor { if (isEnum) level = AccessLevel.PRIVATE; - if (suppressConstructorProperties == null) { - if (fields.isEmpty()) { - suppressConstructorProperties = false; - } else { - suppressConstructorProperties = Boolean.TRUE.equals(type.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_SUPPRESS_CONSTRUCTOR_PROPERTIES)); - } + boolean suppressConstructorProperties; + if (fields.isEmpty()) { + suppressConstructorProperties = false; + } else { + suppressConstructorProperties = Boolean.TRUE.equals(type.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_SUPPRESS_CONSTRUCTOR_PROPERTIES)); } ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index a56eee89..ceef3d3c 100644 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -67,6 +67,7 @@ import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.NameReference; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; 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.QualifiedNameReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; @@ -128,7 +129,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH List<String> includes = Arrays.asList(ann.of()); EclipseNode typeNode = annotationNode.up(); - List<Annotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@EqualsAndHashCode(onParam=", annotationNode); + List<Annotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@EqualsAndHashCode(onParam", annotationNode); checkForBogusFieldNames(typeNode, annotation); Boolean callSuper = ann.callSuper(); @@ -458,7 +459,14 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH return assignment; } - public TypeReference createTypeReference(EclipseNode type, long p) { + /** + * @param type Type to 'copy' into a typeref + * @param p position + * @param addWildcards If false, all generics are cut off. If true, replaces all genericparams with a ?. + * @return + */ + public TypeReference createTypeReference(EclipseNode type, long p, ASTNode source, boolean addWildcards) { + int pS = source.sourceStart; int pE = source.sourceEnd; List<String> list = new ArrayList<String>(); list.add(type.getName()); EclipseNode tNode = type.up(); @@ -468,21 +476,44 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH } Collections.reverse(list); - if (list.size() == 1) return new SingleTypeReference(list.get(0).toCharArray(), p); + TypeDeclaration typeDecl = (TypeDeclaration) type.get(); + int typeParamCount = typeDecl.typeParameters == null ? 0 : typeDecl.typeParameters.length; + if (typeParamCount == 0) addWildcards = false; + TypeReference[] typeArgs = null; + if (addWildcards) { + typeArgs = new TypeReference[typeParamCount]; + for (int i = 0; i < typeParamCount; i++) { + typeArgs[i] = new Wildcard(Wildcard.UNBOUND); + typeArgs[i].sourceStart = pS; typeArgs[i].sourceEnd = pE; + setGeneratedBy(typeArgs[i], source); + } + } + + if (list.size() == 1) { + if (addWildcards) { + return new ParameterizedSingleTypeReference(list.get(0).toCharArray(), typeArgs, 0, p); + } else { + return new SingleTypeReference(list.get(0).toCharArray(), p); + } + } long[] ps = new long[list.size()]; char[][] tokens = new char[list.size()][]; for (int i = 0; i < list.size(); i++) { ps[i] = p; tokens[i] = list.get(i).toCharArray(); } - - return new QualifiedTypeReference(tokens, ps); + if (addWildcards) { + TypeReference[][] typeArgs2 = new TypeReference[tokens.length][]; + typeArgs2[typeArgs2.length - 1] = typeArgs; + return new ParameterizedQualifiedTypeReference(tokens, typeArgs2, 0, ps); + } else { + return new QualifiedTypeReference(tokens, ps); + } } public MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, FieldAccess fieldAccess, boolean needsCanEqual, List<Annotation> onParam) { int pS = source.sourceStart; int pE = source.sourceEnd; long p = (long)pS << 32 | pE; - TypeDeclaration typeDecl = (TypeDeclaration)type.get(); MethodDeclaration method = new MethodDeclaration( ((CompilationUnitDeclaration) type.top().get()).compilationResult); @@ -528,7 +559,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH SingleNameReference oRef = new SingleNameReference(new char[] { 'o' }, p); setGeneratedBy(oRef, source); - TypeReference typeReference = createTypeReference(type, p); + TypeReference typeReference = createTypeReference(type, p, source, false); setGeneratedBy(typeReference, source); InstanceOfExpression instanceOf = new InstanceOfExpression(oRef, typeReference); @@ -551,30 +582,15 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH char[] otherName = "other".toCharArray(); - /* MyType<?> other = (MyType<?>) o; */ { + /* Outer.Inner.MyType<?> other = (Outer.Inner.MyType<?>) o; */ { if (!fields.isEmpty() || needsCanEqual) { LocalDeclaration other = new LocalDeclaration(otherName, pS, pE); other.modifiers |= ClassFileConstants.AccFinal; setGeneratedBy(other, source); - char[] typeName = typeDecl.name; - TypeReference targetType; - if (typeDecl.typeParameters == null || typeDecl.typeParameters.length == 0) { - targetType = new SingleTypeReference(typeName, p); - setGeneratedBy(targetType, source); - other.type = new SingleTypeReference(typeName, p); - setGeneratedBy(other.type, source); - } else { - TypeReference[] typeArgs = new TypeReference[typeDecl.typeParameters.length]; - for (int i = 0; i < typeArgs.length; i++) { - typeArgs[i] = new Wildcard(Wildcard.UNBOUND); - typeArgs[i].sourceStart = pS; typeArgs[i].sourceEnd = pE; - setGeneratedBy(typeArgs[i], source); - } - targetType = new ParameterizedSingleTypeReference(typeName, typeArgs, 0, p); - setGeneratedBy(targetType, source); - other.type = new ParameterizedSingleTypeReference(typeName, copyTypes(typeArgs, source), 0, p); - setGeneratedBy(other.type, source); - } + TypeReference targetType = createTypeReference(type, p, source, true); + setGeneratedBy(targetType, source); + other.type = createTypeReference(type, p, source, true); + setGeneratedBy(other.type, source); NameReference oRef = new SingleNameReference(new char[] { 'o' }, p); setGeneratedBy(oRef, source); other.initialization = makeCastExpression(oRef, targetType, source); @@ -772,7 +788,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH SingleNameReference otherRef = new SingleNameReference(otherName, p); setGeneratedBy(otherRef, source); - TypeReference typeReference = createTypeReference(type, p); + TypeReference typeReference = createTypeReference(type, p, source, false); setGeneratedBy(typeReference, source); InstanceOfExpression instanceOf = new InstanceOfExpression(otherRef, typeReference); diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java index 77d678f2..c11303f3 100644 --- a/src/core/lombok/eclipse/handlers/HandleGetter.java +++ b/src/core/lombok/eclipse/handlers/HandleGetter.java @@ -148,7 +148,7 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { if (node == null) return; - List<Annotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Getter(onMethod=", annotationNode); + List<Annotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Getter(onMethod", annotationNode); switch (node.getKind()) { case FIELD: diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index 1fcf751d..7e7ea121 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -125,8 +125,8 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { AccessLevel level = annotation.getInstance().value(); if (level == AccessLevel.NONE || node == null) return; - List<Annotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Setter(onMethod=", annotationNode); - List<Annotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@Setter(onParam=", annotationNode); + List<Annotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Setter(onMethod", annotationNode); + List<Annotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@Setter(onParam", annotationNode); switch (node.getKind()) { case FIELD: diff --git a/src/core/lombok/eclipse/handlers/HandleUtilityClass.java b/src/core/lombok/eclipse/handlers/HandleUtilityClass.java index 199ce102..959c1d20 100644 --- a/src/core/lombok/eclipse/handlers/HandleUtilityClass.java +++ b/src/core/lombok/eclipse/handlers/HandleUtilityClass.java @@ -49,6 +49,7 @@ import org.mangosdk.spi.ProviderFor; import lombok.ConfigurationKeys; import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; import lombok.core.AST.Kind; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; @@ -57,6 +58,7 @@ import lombok.experimental.UtilityClass; /** * Handles the {@code lombok.experimental.UtilityClass} annotation for eclipse. */ +@HandlerPriority(-4096) //-2^12; to ensure @FieldDefaults picks up on the 'static' we set here. @ProviderFor(EclipseAnnotationHandler.class) public class HandleUtilityClass extends EclipseAnnotationHandler<UtilityClass> { @Override public void handle(AnnotationValues<UtilityClass> annotation, Annotation ast, EclipseNode annotationNode) { diff --git a/src/core/lombok/eclipse/handlers/HandleWither.java b/src/core/lombok/eclipse/handlers/HandleWither.java index d8ac8df6..200ebde7 100644 --- a/src/core/lombok/eclipse/handlers/HandleWither.java +++ b/src/core/lombok/eclipse/handlers/HandleWither.java @@ -127,8 +127,8 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { AccessLevel level = annotation.getInstance().value(); if (level == AccessLevel.NONE || node == null) return; - List<Annotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Wither(onMethod=", annotationNode); - List<Annotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@Wither(onParam=", annotationNode); + List<Annotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Wither(onMethod", annotationNode); + List<Annotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@Wither(onParam", annotationNode); switch (node.getKind()) { case FIELD: diff --git a/src/core/lombok/experimental/Wither.java b/src/core/lombok/experimental/Wither.java index b4131187..3fb767d1 100644 --- a/src/core/lombok/experimental/Wither.java +++ b/src/core/lombok/experimental/Wither.java @@ -60,12 +60,22 @@ public @interface Wither { AccessLevel value() default AccessLevel.PUBLIC; /** - * Any annotations listed here are put on the generated method. The syntax for this feature is: {@code @Setter(onMethod=@__({@AnnotationsGoHere}))} + * Any annotations listed here are put on the generated method. + * The syntax for this feature depends on JDK version (nothing we can do about that; it's to work around javac bugs).<br /> + * up to JDK7:<br /> + * {@code @Wither(onMethod=@__({@AnnotationsGoHere}))}<br /> + * from JDK8:<br /> + * {@code @Wither(onMethod_={@AnnotationsGohere})} // note the underscore after {@code onMethod}. */ AnyAnnotation[] onMethod() default {}; /** - * Any annotations listed here are put on the generated method's parameter. The syntax for this feature is: {@code @Setter(onParam=@__({@AnnotationsGoHere}))} + * Any annotations listed here are put on the generated method's parameter. + * The syntax for this feature depends on JDK version (nothing we can do about that; it's to work around javac bugs).<br /> + * up to JDK7:<br /> + * {@code @Wither(onParam=@__({@AnnotationsGoHere}))}<br /> + * from JDK8:<br /> + * {@code @Wither(onParam_={@AnnotationsGohere})} // note the underscore after {@code onParam}. */ AnyAnnotation[] onParam() default {}; diff --git a/src/core/lombok/javac/apt/Javac9BaseFileObjectWrapper.java b/src/core/lombok/javac/apt/Javac9BaseFileObjectWrapper.java new file mode 100644 index 00000000..f9fe2a7d --- /dev/null +++ b/src/core/lombok/javac/apt/Javac9BaseFileObjectWrapper.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2010-2017 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package lombok.javac.apt; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.net.URI; +import java.nio.file.Path; + +import javax.lang.model.element.Modifier; +import javax.lang.model.element.NestingKind; + +import com.sun.tools.javac.file.BaseFileManager; + +class Javac9BaseFileObjectWrapper extends com.sun.tools.javac.file.PathFileObject { + private final LombokFileObject delegate; + + public Javac9BaseFileObjectWrapper(BaseFileManager fileManager, Path path, LombokFileObject delegate) { + super(fileManager, path); + this.delegate = delegate; + } + + @Override public boolean isNameCompatible(String simpleName, Kind kind) { + return delegate.isNameCompatible(simpleName, kind); + } + + @Override public URI toUri() { + return delegate.toUri(); + } + + @SuppressWarnings("all") + @Override public String getName() { + return delegate.getName(); + } + + @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return delegate.getCharContent(ignoreEncodingErrors); + } + + @Override public InputStream openInputStream() throws IOException { + return delegate.openInputStream(); + } + + @Override public Reader openReader(boolean ignoreEncodingErrors) throws IOException { + return delegate.openReader(ignoreEncodingErrors); + } + + @Override public Writer openWriter() throws IOException { + return delegate.openWriter(); + } + + @Override public OutputStream openOutputStream() throws IOException { + return delegate.openOutputStream(); + } + + @Override public long getLastModified() { + return delegate.getLastModified(); + } + + @Override public boolean delete() { + return delegate.delete(); + } + + @Override public Kind getKind() { + return delegate.getKind(); + } + + @Override public NestingKind getNestingKind() { + return delegate.getNestingKind(); + } + + @Override public Modifier getAccessLevel() { + return delegate.getAccessLevel(); + } + + @Override public boolean equals(Object obj) { + if (!(obj instanceof Javac9BaseFileObjectWrapper)) { + return false; + } + return delegate.equals(((Javac9BaseFileObjectWrapper)obj).delegate); + } + + @Override public int hashCode() { + return delegate.hashCode(); + } + + @Override public String toString() { + return delegate.toString(); + } +}
\ No newline at end of file diff --git a/src/core/lombok/javac/apt/LombokFileObjects.java b/src/core/lombok/javac/apt/LombokFileObjects.java index 412e449b..7e818cab 100644 --- a/src/core/lombok/javac/apt/LombokFileObjects.java +++ b/src/core/lombok/javac/apt/LombokFileObjects.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 The Project Lombok Authors. + * Copyright (C) 2010-2017 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,19 +23,24 @@ package lombok.javac.apt; import java.lang.reflect.Method; +import java.net.URI; +import java.nio.file.Paths; import java.util.concurrent.atomic.AtomicBoolean; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; +import com.sun.tools.javac.file.BaseFileManager; + import lombok.core.DiagnosticsReceiver; //Can't use SimpleJavaFileObject so we copy/paste most of its content here, because javac doesn't follow the interface, //and casts to its own BaseFileObject type. D'oh! final class LombokFileObjects { - enum Compiler { - JAVAC6 { + + interface Compiler { + Compiler JAVAC6 = new Compiler() { private Method decoderMethod = null; private final AtomicBoolean decoderIsSet = new AtomicBoolean(); @@ -46,13 +51,13 @@ final class LombokFileObjects { @Override public Method getDecoderMethod() { synchronized (decoderIsSet) { if (decoderIsSet.get()) return decoderMethod; - decoderMethod = getDecoderMethod("com.sun.tools.javac.util.BaseFileObject"); + decoderMethod = LombokFileObjects.getDecoderMethod("com.sun.tools.javac.util.BaseFileObject"); decoderIsSet.set(true); return decoderMethod; } } - }, - JAVAC7 { + }; + Compiler JAVAC7 = new Compiler() { private Method decoderMethod = null; private final AtomicBoolean decoderIsSet = new AtomicBoolean(); @@ -63,28 +68,28 @@ final class LombokFileObjects { @Override public Method getDecoderMethod() { synchronized (decoderIsSet) { if (decoderIsSet.get()) return decoderMethod; - decoderMethod = getDecoderMethod("com.sun.tools.javac.file.BaseFileObject"); + decoderMethod = LombokFileObjects.getDecoderMethod("com.sun.tools.javac.file.BaseFileObject"); decoderIsSet.set(true); return decoderMethod; } } }; - static Method getDecoderMethod(String className) { - Method m = null; - try { - m = Class.forName(className).getDeclaredMethod("getDecoder", boolean.class); - m.setAccessible(true); - } catch (NoSuchMethodException e) { - // Intentional fallthrough - getDecoder(boolean) is not always present. - } catch (ClassNotFoundException e) { - // Intentional fallthrough - getDecoder(boolean) is not always present. - } - return m; - } + JavaFileObject wrap(LombokFileObject fileObject); + Method getDecoderMethod(); + } - abstract JavaFileObject wrap(LombokFileObject fileObject); - abstract Method getDecoderMethod(); + static Method getDecoderMethod(String className) { + Method m = null; + try { + m = Class.forName(className).getDeclaredMethod("getDecoder", boolean.class); + m.setAccessible(true); + } catch (NoSuchMethodException e) { + // Intentional fallthrough - getDecoder(boolean) is not always present. + } catch (ClassNotFoundException e) { + // Intentional fallthrough - getDecoder(boolean) is not always present. + } + return m; } private LombokFileObjects() {} @@ -93,7 +98,16 @@ final class LombokFileObjects { String jfmClassName = jfm != null ? jfm.getClass().getName() : "null"; if (jfmClassName.equals("com.sun.tools.javac.util.DefaultFileManager")) return Compiler.JAVAC6; if (jfmClassName.equals("com.sun.tools.javac.util.JavacFileManager")) return Compiler.JAVAC6; - if (jfmClassName.equals("com.sun.tools.javac.file.JavacFileManager")) return Compiler.JAVAC7; + if (jfmClassName.equals("com.sun.tools.javac.file.JavacFileManager")) { + try { + Class<?> superType = Class.forName("com.sun.tools.javac.file.BaseFileManager"); + if (superType.isInstance(jfm)) { + return new Java9Compiler(jfm); + } + } + catch (Exception e) {} + return Compiler.JAVAC7; + } try { if (Class.forName("com.sun.tools.javac.file.BaseFileObject") == null) throw new NullPointerException(); return Compiler.JAVAC7; @@ -112,4 +126,24 @@ final class LombokFileObjects { static JavaFileObject createIntercepting(Compiler compiler, JavaFileObject delegate, String fileName, DiagnosticsReceiver diagnostics) { return compiler.wrap(new InterceptingJavaFileObject(delegate, fileName, diagnostics, compiler.getDecoderMethod())); } + + static class Java9Compiler implements Compiler { + private final BaseFileManager fileManager; + + public Java9Compiler(JavaFileManager jfm) { + fileManager = (BaseFileManager) jfm; + } + + @Override public JavaFileObject wrap(LombokFileObject fileObject) { + URI uri = fileObject.toUri(); + if (uri.getScheme() == null) { + uri = URI.create("file://" + uri); + } + return new Javac9BaseFileObjectWrapper(fileManager, Paths.get(uri), fileObject); + } + + @Override public Method getDecoderMethod() { + throw new UnsupportedOperationException(); + } + } } diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 8588fc16..4c670433 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -155,7 +155,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { allFields.append(fieldNode); } - new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, List.<JCAnnotation>nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, null, annotationNode); + new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, List.<JCAnnotation>nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, annotationNode); returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams); typeParams = td.typarams; @@ -270,8 +270,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } if (pos == -1 || tpOnType.size() <= pos) { - annotationNode.addError("**" + returnType.getClass().toString()); -// annotationNode.addError("@Builder(toBuilder=true) requires that each type parameter on the static method is part of the typeargs of the return value. Type parameter " + tp.name + " is not part of the return type."); + annotationNode.addError("@Builder(toBuilder=true) requires that each type parameter on the static method is part of the typeargs of the return value. Type parameter " + tp.name + " is not part of the return type."); return; } typeArgsForToBuilder.add(tpOnType.get(pos).name); @@ -298,7 +297,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { JavacNode builderType = findInnerClass(tdParent, builderClassName); if (builderType == null) { - builderType = makeBuilderClass(isStatic, tdParent, builderClassName, typeParams, ast); + builderType = makeBuilderClass(isStatic, annotationNode, tdParent, builderClassName, typeParams, ast); } else { JCClassDecl builderTypeDeclaration = (JCClassDecl) builderType.get(); if (isStatic && !builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)) { @@ -320,7 +319,6 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } } } - } for (BuilderFieldData bfd : builderFields) { @@ -350,7 +348,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, List.<JCAnnotation>nil(), builderType, List.<JavacNode>nil(), false, null, annotationNode); + JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, List.<JCAnnotation>nil(), builderType, List.<JavacNode>nil(), false, annotationNode); if (cd != null) injectMethod(builderType, cd); } @@ -375,7 +373,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(isStatic, builderMethodName, builderClassName, tdParent, typeParams); + JCMethodDecl md = generateBuilderMethod(isStatic, builderMethodName, builderClassName, annotationNode, tdParent, typeParams); recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); if (md != null) injectMethod(tdParent, md); } @@ -550,7 +548,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName(buildName), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), thrownExceptions, body, null); } - public JCMethodDecl generateBuilderMethod(boolean isStatic, String builderMethodName, String builderClassName, JavacNode type, List<JCTypeParameter> typeParams) { + public JCMethodDecl generateBuilderMethod(boolean isStatic, String builderMethodName, String builderClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams) { JavacTreeMaker maker = type.getTreeMaker(); ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); @@ -564,7 +562,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); 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); + return maker.MethodDef(maker.Modifiers(modifiers), type.toName(builderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), copyTypeParams(source, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); } public void generateBuilderFields(JavacNode builderType, java.util.List<BuilderFieldData> builderFields, JCTree source) { @@ -629,12 +627,12 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { return null; } - public JavacNode makeBuilderClass(boolean isStatic, JavacNode tdParent, String builderClassName, List<JCTypeParameter> typeParams, JCAnnotation ast) { + public JavacNode makeBuilderClass(boolean isStatic, JavacNode source, JavacNode tdParent, String builderClassName, List<JCTypeParameter> typeParams, JCAnnotation ast) { JavacTreeMaker maker = tdParent.getTreeMaker(); 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()); + JCClassDecl builder = maker.ClassDef(mods, tdParent.toName(builderClassName), copyTypeParams(source, typeParams), null, List.<JCExpression>nil(), List.<JCTree>nil()); return injectType(tdParent, builder); } diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index 5f523ce6..25e96d75 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -71,14 +71,14 @@ public class HandleConstructor { deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel"); JavacNode typeNode = annotationNode.up(); if (!checkLegality(typeNode, annotationNode, NoArgsConstructor.class.getSimpleName())) return; - List<JCAnnotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@NoArgsConstructor(onConstructor=", annotationNode); + List<JCAnnotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@NoArgsConstructor(onConstructor", annotationNode); NoArgsConstructor ann = annotation.getInstance(); AccessLevel level = ann.access(); if (level == AccessLevel.NONE) return; String staticName = ann.staticName(); boolean force = ann.force(); List<JavacNode> fields = force ? findFinalFields(typeNode) : List.<JavacNode>nil(); - new HandleConstructor().generateConstructor(typeNode, level, onConstructor, fields, force, staticName, SkipIfConstructorExists.NO, null, annotationNode); + new HandleConstructor().generateConstructor(typeNode, level, onConstructor, fields, force, staticName, SkipIfConstructorExists.NO, annotationNode); } } @@ -91,19 +91,16 @@ public class HandleConstructor { deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel"); JavacNode typeNode = annotationNode.up(); if (!checkLegality(typeNode, annotationNode, RequiredArgsConstructor.class.getSimpleName())) return; - List<JCAnnotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@RequiredArgsConstructor(onConstructor=", annotationNode); + List<JCAnnotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@RequiredArgsConstructor(onConstructor", annotationNode); RequiredArgsConstructor ann = annotation.getInstance(); AccessLevel level = ann.access(); if (level == AccessLevel.NONE) return; String staticName = ann.staticName(); - Boolean suppressConstructorProperties = null; if (annotation.isExplicit("suppressConstructorProperties")) { - @SuppressWarnings("deprecation") - boolean suppress = ann.suppressConstructorProperties(); - suppressConstructorProperties = suppress; + annotationNode.addError("This deprecated feature is no longer supported. Remove it; you can create a lombok.config file with 'lombok.anyConstructor.suppressConstructorProperties = true'."); } - new HandleConstructor().generateConstructor(typeNode, level, onConstructor, findRequiredFields(typeNode), false, staticName, SkipIfConstructorExists.NO, suppressConstructorProperties, annotationNode); + new HandleConstructor().generateConstructor(typeNode, level, onConstructor, findRequiredFields(typeNode), false, staticName, SkipIfConstructorExists.NO, annotationNode); } } @@ -141,18 +138,15 @@ public class HandleConstructor { deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel"); JavacNode typeNode = annotationNode.up(); if (!checkLegality(typeNode, annotationNode, AllArgsConstructor.class.getSimpleName())) return; - List<JCAnnotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@AllArgsConstructor(onConstructor=", annotationNode); + List<JCAnnotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@AllArgsConstructor(onConstructor", annotationNode); AllArgsConstructor ann = annotation.getInstance(); AccessLevel level = ann.access(); if (level == AccessLevel.NONE) return; String staticName = ann.staticName(); - Boolean suppressConstructorProperties = null; if (annotation.isExplicit("suppressConstructorProperties")) { - @SuppressWarnings("deprecation") - boolean suppress = ann.suppressConstructorProperties(); - suppressConstructorProperties = suppress; + annotationNode.addError("This deprecated feature is no longer supported. Remove it; you can create a lombok.config file with 'lombok.anyConstructor.suppressConstructorProperties = true'."); } - new HandleConstructor().generateConstructor(typeNode, level, onConstructor, findAllFields(typeNode), false, staticName, SkipIfConstructorExists.NO, suppressConstructorProperties, annotationNode); + new HandleConstructor().generateConstructor(typeNode, level, onConstructor, findAllFields(typeNode), false, staticName, SkipIfConstructorExists.NO, annotationNode); } } @@ -188,7 +182,7 @@ public class HandleConstructor { } public void generateRequiredArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) { - generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findRequiredFields(typeNode), false, staticName, skipIfConstructorExists, null, source); + generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findRequiredFields(typeNode), false, staticName, skipIfConstructorExists, source); } public enum SkipIfConstructorExists { @@ -196,10 +190,10 @@ public class HandleConstructor { } public void generateAllArgsConstructor(JavacNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) { - generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findAllFields(typeNode), false, staticName, skipIfConstructorExists, null, source); + generateConstructor(typeNode, level, List.<JCAnnotation>nil(), findAllFields(typeNode), false, staticName, skipIfConstructorExists, source); } - public void generateConstructor(JavacNode typeNode, AccessLevel level, List<JCAnnotation> onConstructor, List<JavacNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists, Boolean suppressConstructorProperties, JavacNode source) { + public void generateConstructor(JavacNode typeNode, AccessLevel level, List<JCAnnotation> onConstructor, List<JavacNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists, JavacNode source) { boolean staticConstrRequired = staticName != null && !staticName.equals(""); if (skipIfConstructorExists != SkipIfConstructorExists.NO && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return; @@ -228,7 +222,7 @@ public class HandleConstructor { } } - JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, onConstructor, typeNode, fields, allToDefault, suppressConstructorProperties, source); + JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, onConstructor, typeNode, fields, allToDefault, source); ListBuffer<Type> argTypes = new ListBuffer<Type>(); for (JavacNode fieldNode : fields) { Type mirror = getMirrorForFieldType(fieldNode); @@ -262,18 +256,18 @@ public class HandleConstructor { mods.annotations = mods.annotations.append(annotation); } - public static JCMethodDecl createConstructor(AccessLevel level, List<JCAnnotation> onConstructor, JavacNode typeNode, List<JavacNode> fields, boolean allToDefault, Boolean suppressConstructorProperties, JavacNode source) { + public static JCMethodDecl createConstructor(AccessLevel level, List<JCAnnotation> onConstructor, JavacNode typeNode, List<JavacNode> fields, boolean allToDefault, JavacNode source) { JavacTreeMaker maker = typeNode.getTreeMaker(); boolean isEnum = (((JCClassDecl) typeNode.get()).mods.flags & Flags.ENUM) != 0; if (isEnum) level = AccessLevel.PRIVATE; - if (suppressConstructorProperties == null) { - if (fields.isEmpty()) { - suppressConstructorProperties = false; - } else { - suppressConstructorProperties = Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_SUPPRESS_CONSTRUCTOR_PROPERTIES)); - } + boolean suppressConstructorProperties; + + if (fields.isEmpty()) { + suppressConstructorProperties = false; + } else { + suppressConstructorProperties = Boolean.TRUE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_SUPPRESS_CONSTRUCTOR_PROPERTIES)); } ListBuffer<JCStatement> nullChecks = new ListBuffer<JCStatement>(); diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index f34b4f6b..6df56ed6 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -95,7 +95,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas List<String> excludes = List.from(ann.exclude()); List<String> includes = List.from(ann.of()); JavacNode typeNode = annotationNode.up(); - List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@EqualsAndHashCode(onParam=", annotationNode); + List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@EqualsAndHashCode(onParam", annotationNode); checkForBogusFieldNames(typeNode, annotation); Boolean callSuper = ann.callSuper(); @@ -363,7 +363,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas return maker.TypeCast(maker.TypeIdent(CTC_INT), maker.Parens(xorBits)); } - public JCExpression createTypeReference(JavacNode type) { + public JCExpression createTypeReference(JavacNode type, boolean addWildcards) { java.util.List<String> list = new ArrayList<String>(); list.add(type.getName()); JavacNode tNode = type.up(); @@ -372,20 +372,28 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas tNode = tNode.up(); } Collections.reverse(list); + JCClassDecl typeDecl = (JCClassDecl) type.get(); JavacTreeMaker maker = type.getTreeMaker(); + JCExpression chain = maker.Ident(type.toName(list.get(0))); for (int i = 1; i < list.size(); i++) { chain = maker.Select(chain, type.toName(list.get(i))); } - return chain; + if (!addWildcards || typeDecl.typarams.length() == 0) return chain; + + ListBuffer<JCExpression> wildcards = new ListBuffer<JCExpression>(); + for (int i = 0 ; i < typeDecl.typarams.length() ; i++) { + wildcards.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null)); + } + + return maker.TypeApply(chain, wildcards.toList()); } public JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source, List<JCAnnotation> onParam) { JavacTreeMaker maker = typeNode.getTreeMaker(); - JCClassDecl type = (JCClassDecl) typeNode.get(); Name oName = typeNode.toName("o"); Name otherName = typeNode.toName("other"); @@ -408,27 +416,13 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas /* if (!(o instanceof Outer.Inner.MyType)) return false; */ { - JCUnary notInstanceOf = maker.Unary(CTC_NOT, maker.Parens(maker.TypeTest(maker.Ident(oName), createTypeReference(typeNode)))); + JCUnary notInstanceOf = maker.Unary(CTC_NOT, maker.Parens(maker.TypeTest(maker.Ident(oName), createTypeReference(typeNode, false)))); statements.append(maker.If(notInstanceOf, returnBool(maker, false), null)); } - /* MyType<?> other = (MyType<?>) o; */ { + /* Outer.Inner.MyType<?> other = (Outer.Inner.MyType<?>) o; */ { if (!fields.isEmpty() || needsCanEqual) { - final JCExpression selfType1, selfType2; - ListBuffer<JCExpression> wildcards1 = new ListBuffer<JCExpression>(); - ListBuffer<JCExpression> wildcards2 = new ListBuffer<JCExpression>(); - for (int i = 0 ; i < type.typarams.length() ; i++) { - wildcards1.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null)); - wildcards2.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null)); - } - - if (type.typarams.isEmpty()) { - selfType1 = maker.Ident(type.name); - selfType2 = maker.Ident(type.name); - } else { - selfType1 = maker.TypeApply(maker.Ident(type.name), wildcards1.toList()); - selfType2 = maker.TypeApply(maker.Ident(type.name), wildcards2.toList()); - } + final JCExpression selfType1 = createTypeReference(typeNode, true), selfType2 = createTypeReference(typeNode, true); statements.append( maker.VarDef(maker.Modifiers(finalFlag), otherName, selfType1, maker.TypeCast(selfType2, maker.Ident(oName)))); @@ -533,7 +527,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(flags, onParam), otherName, objectType, null)); JCBlock body = maker.Block(0, List.<JCStatement>of( - maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode))))); + maker.Return(maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode, false))))); return recursiveSetGeneratedBy(maker.MethodDef(mods, canEqualName, returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source, typeNode.getContext()); } diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index 60dbe8ee..5a2e1993 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -147,7 +147,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> { if (node == null) return; - List<JCAnnotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Getter(onMethod=", annotationNode); + List<JCAnnotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Getter(onMethod", annotationNode); switch (node.getKind()) { case FIELD: diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index 02cc3775..e766127a 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -129,8 +129,8 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { if (level == AccessLevel.NONE || node == null) return; - List<JCAnnotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Setter(onMethod=", annotationNode); - List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@Setter(onParam=", annotationNode); + List<JCAnnotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Setter(onMethod", annotationNode); + List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@Setter(onParam", annotationNode); switch (node.getKind()) { case FIELD: diff --git a/src/core/lombok/javac/handlers/HandleUtilityClass.java b/src/core/lombok/javac/handlers/HandleUtilityClass.java index 6d3ec63b..ee8081d6 100644 --- a/src/core/lombok/javac/handlers/HandleUtilityClass.java +++ b/src/core/lombok/javac/handlers/HandleUtilityClass.java @@ -44,6 +44,7 @@ import com.sun.tools.javac.util.Name; import lombok.ConfigurationKeys; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; import lombok.experimental.UtilityClass; import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; @@ -53,6 +54,7 @@ import lombok.javac.JavacTreeMaker; /** * Handles the {@code @UtilityClass} annotation for javac. */ +@HandlerPriority(-4096) //-2^12; to ensure @FieldDefaults picks up on the 'static' we set here. @ProviderFor(JavacAnnotationHandler.class) public class HandleUtilityClass extends JavacAnnotationHandler<UtilityClass> { @Override public void handle(AnnotationValues<UtilityClass> annotation, JCAnnotation ast, JavacNode annotationNode) { diff --git a/src/core/lombok/javac/handlers/HandleWither.java b/src/core/lombok/javac/handlers/HandleWither.java index 8aec0240..987a3d34 100644 --- a/src/core/lombok/javac/handlers/HandleWither.java +++ b/src/core/lombok/javac/handlers/HandleWither.java @@ -131,8 +131,8 @@ public class HandleWither extends JavacAnnotationHandler<Wither> { if (level == AccessLevel.NONE || node == null) return; - List<JCAnnotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Wither(onMethod=", annotationNode); - List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@Wither(onParam=", annotationNode); + List<JCAnnotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Wither(onMethod", annotationNode); + List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@Wither(onParam", annotationNode); switch (node.getKind()) { case FIELD: diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 949c9f5c..68d8061c 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -92,6 +92,7 @@ import com.sun.tools.javac.tree.JCTree.JCTypeParameter; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.JCTree.JCWildcard; import com.sun.tools.javac.tree.JCTree.TypeBoundKind; +import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @@ -894,16 +895,20 @@ public class JavacHandlerUtil { static class ClassSymbolMembersField { private static final Field membersField; private static final Method removeMethod; + private static final Method enterMethod; static { Field f = null; - Method m = null; + Method r = null; + Method e = null; try { f = ClassSymbol.class.getField("members_field"); - m = f.getType().getMethod("remove", Symbol.class); - } catch (Exception e) {} + r = f.getType().getMethod("remove", Symbol.class); + e = f.getType().getMethod("enter", Symbol.class); + } catch (Exception ex) {} membersField = f; - removeMethod = m; + removeMethod = r; + enterMethod = e; } static void remove(ClassSymbol from, Symbol toRemove) { @@ -914,6 +919,15 @@ public class JavacHandlerUtil { removeMethod.invoke(scope, toRemove); } catch (Exception e) {} } + + static void enter(ClassSymbol from, Symbol toEnter) { + if (from == null) return; + try { + Scope scope = (Scope) membersField.get(from); + if (scope == null) return; + enterMethod.invoke(scope, toEnter); + } catch (Exception e) {} + } } public static void injectMethod(JavacNode typeNode, JCMethodDecl method) { @@ -959,7 +973,7 @@ public class JavacHandlerUtil { if (typeMirror == null || paramTypes == null || returnType == null) return; ClassSymbol cs = (ClassSymbol) typeMirror; MethodSymbol methodSymbol = new MethodSymbol(access, methodName, new MethodType(paramTypes, returnType, List.<Type>nil(), Symtab.instance(context).methodClass), cs); - cs.members_field.enter(methodSymbol); + ClassSymbolMembersField.enter(cs, methodSymbol); } /** @@ -1025,10 +1039,10 @@ public class JavacHandlerUtil { public static void addGenerated(JCModifiers mods, JavacNode node, int pos, JCTree source, Context context) { if (!LombokOptionsFactory.getDelombokOptions(context).getFormatPreferences().generateGenerated()) return; - if (HandlerUtil.shouldAddGenerated(node, ConfigurationKeys.ADD_JAVAX_GENERATED_ANNOTATIONS)) { + if (HandlerUtil.shouldAddGenerated(node)) { addAnnotation(mods, node, pos, source, context, "javax.annotation.Generated", node.getTreeMaker().Literal("lombok")); } - if (HandlerUtil.shouldAddGenerated(node, ConfigurationKeys.ADD_LOMBOK_GENERATED_ANNOTATIONS)) { + if (Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.ADD_LOMBOK_GENERATED_ANNOTATIONS))) { addAnnotation(mods, node, pos, source, context, "lombok.Generated", null); } } @@ -1233,19 +1247,9 @@ public class JavacHandlerUtil { ListBuffer<JCExpression> params = new ListBuffer<JCExpression>(); ListBuffer<JCAnnotation> result = new ListBuffer<JCAnnotation>(); - try { - for (JCExpression arg : ast.args) { - String argName = "value"; - if (arg instanceof JCAssign) { - JCAssign as = (JCAssign) arg; - argName = as.lhs.toString(); - } - if (!argName.equals(parameterName)) continue; - } - } catch (Exception ignore) {} - outer: for (JCExpression param : ast.args) { + boolean allowRaw; String nameOfParam = "value"; JCExpression valueOfParam = null; if (param instanceof JCAssign) { @@ -1257,6 +1261,15 @@ public class JavacHandlerUtil { valueOfParam = assign.rhs; } + /* strip trailing underscores */ { + int lastIdx; + for (lastIdx = nameOfParam.length() ; lastIdx > 0; lastIdx--) { + if (nameOfParam.charAt(lastIdx - 1) != '_') break; + } + allowRaw = lastIdx < nameOfParam.length(); + nameOfParam = nameOfParam.substring(0, lastIdx); + } + if (!parameterName.equals(nameOfParam)) { params.append(param); continue outer; @@ -1269,52 +1282,84 @@ public class JavacHandlerUtil { String dummyAnnotationName = ((JCAnnotation) valueOfParam).annotationType.toString(); dummyAnnotationName = dummyAnnotationName.replace("_", "").replace("$", "").replace("x", "").replace("X", ""); if (dummyAnnotationName.length() > 0) { - annotationNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); - continue outer; - } - for (JCExpression expr : ((JCAnnotation) valueOfParam).args) { - if (expr instanceof JCAssign && ((JCAssign) expr).lhs instanceof JCIdent) { - JCIdent id = (JCIdent) ((JCAssign) expr).lhs; - if ("value".equals(id.name.toString())) { - expr = ((JCAssign) expr).rhs; - } else { - annotationNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); - continue outer; - } + if (allowRaw) { + result.append((JCAnnotation) valueOfParam); + } else { + addError(errorName, annotationNode); + continue outer; } - - if (expr instanceof JCAnnotation) { - result.append((JCAnnotation) expr); - } else if (expr instanceof JCNewArray) { - for (JCExpression expr2 : ((JCNewArray) expr).elems) { - if (expr2 instanceof JCAnnotation) { - result.append((JCAnnotation) expr2); + } else { + for (JCExpression expr : ((JCAnnotation) valueOfParam).args) { + if (expr instanceof JCAssign && ((JCAssign) expr).lhs instanceof JCIdent) { + JCIdent id = (JCIdent) ((JCAssign) expr).lhs; + if ("value".equals(id.name.toString())) { + expr = ((JCAssign) expr).rhs; } else { - annotationNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); - continue outer; + addError(errorName, annotationNode); } } - } else { - annotationNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); - continue outer; + + if (expr instanceof JCAnnotation) { + result.append((JCAnnotation) expr); + } else if (expr instanceof JCNewArray) { + for (JCExpression expr2 : ((JCNewArray) expr).elems) { + if (expr2 instanceof JCAnnotation) { + result.append((JCAnnotation) expr2); + } else { + addError(errorName, annotationNode); + continue outer; + } + } + } else { + addError(errorName, annotationNode); + continue outer; + } } } - } else { - if (valueOfParam instanceof JCNewArray && ((JCNewArray) valueOfParam).elems.isEmpty()) { - // Then we just remove it and move on (it's onMethod={} for example). + } else if (valueOfParam instanceof JCNewArray) { + JCNewArray arr = (JCNewArray) valueOfParam; + if (arr.elems.isEmpty()) { + // Just remove it, this is always fine. + } else if (allowRaw) { + for (JCExpression jce : arr.elems) { + if (jce instanceof JCAnnotation) result.append((JCAnnotation) jce); + else addError(errorName, annotationNode); + } } else { - annotationNode.addError("The correct format is " + errorName + "@__({@SomeAnnotation, @SomeOtherAnnotation}))"); + addError(errorName, annotationNode); } + } else { + addError(errorName, annotationNode); } } ast.args = params.toList(); return result.toList(); } - public static List<JCTypeParameter> copyTypeParams(JavacTreeMaker maker, List<JCTypeParameter> params) { + private static void addError(String errorName, JavacNode node) { + if (node.getLatestJavaSpecSupported() < 8) { + node.addError("The correct format up to JDK7 is " + errorName + "=@__({@SomeAnnotation, @SomeOtherAnnotation}))"); + } else { + node.addError("The correct format for JDK8+ is " + errorName + "_={@SomeAnnotation, @SomeOtherAnnotation})"); + } + } + + public static List<JCTypeParameter> copyTypeParams(JavacNode source, List<JCTypeParameter> params) { if (params == null || params.isEmpty()) return params; ListBuffer<JCTypeParameter> out = new ListBuffer<JCTypeParameter>(); - for (JCTypeParameter tp : params) out.append(maker.TypeParameter(tp.name, tp.bounds)); + JavacTreeMaker maker = source.getTreeMaker(); + Context context = source.getContext(); + for (JCTypeParameter tp : params) { + List<JCExpression> bounds = tp.bounds; + if (bounds != null && !bounds.isEmpty()) { + ListBuffer<JCExpression> boundsCopy = new ListBuffer<JCExpression>(); + for (JCExpression expr : tp.bounds) { + boundsCopy.append(cloneType(maker, expr, source.get(), context)); + } + bounds = boundsCopy.toList(); + } + out.append(maker.TypeParameter(tp.name, bounds)); + } return out.toList(); } |