diff options
90 files changed, 1150 insertions, 364 deletions
diff --git a/src/core/lombok/AllArgsConstructor.java b/src/core/lombok/AllArgsConstructor.java index 2147bdae..068b7a68 100644 --- a/src/core/lombok/AllArgsConstructor.java +++ b/src/core/lombok/AllArgsConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 The Project Lombok Authors. + * Copyright (C) 2010-2013 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 @@ -49,6 +49,11 @@ 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}))} + */ + AnyAnnotation[] onConstructor() default {}; + + /** * Sets the access level of the constructor. By default, generated constructors are {@code public}. */ AccessLevel access() default lombok.AccessLevel.PUBLIC; @@ -63,4 +68,13 @@ public @interface AllArgsConstructor { */ @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. + */ + @Deprecated + @Retention(RetentionPolicy.SOURCE) + @Target({}) + @interface AnyAnnotation {} } diff --git a/src/core/lombok/Getter.java b/src/core/lombok/Getter.java index fa12ce1b..57f5e40a 100644 --- a/src/core/lombok/Getter.java +++ b/src/core/lombok/Getter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 The Project Lombok Authors. + * Copyright (C) 2009-2013 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 @@ -57,5 +57,19 @@ 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}))} + */ + AnyAnnotation[] onMethod() default @AnyAnnotation; + boolean lazy() default false; + + /** + * Placeholder annotation to enable the placement of annotations on the generated code. + * @deprecated Don't use this annotation, ever - Read the documentation. + */ + @Deprecated + @Retention(RetentionPolicy.SOURCE) + @Target({}) + @interface AnyAnnotation {} } diff --git a/src/core/lombok/NoArgsConstructor.java b/src/core/lombok/NoArgsConstructor.java index ba53e39f..bbf2d9e6 100644 --- a/src/core/lombok/NoArgsConstructor.java +++ b/src/core/lombok/NoArgsConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 The Project Lombok Authors. + * Copyright (C) 2010-2013 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 @@ -51,7 +51,21 @@ 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}))} + */ + AnyAnnotation[] onConstructor() default {}; + + /** * Sets the access level of the constructor. By default, generated constructors are {@code public}. */ AccessLevel access() default lombok.AccessLevel.PUBLIC; + + /** + * Placeholder annotation to enable the placement of annotations on the generated code. + * @deprecated Don't use this annotation, ever - Read the documentation. + */ + @Deprecated + @Retention(RetentionPolicy.SOURCE) + @Target({}) + @interface AnyAnnotation {} } diff --git a/src/core/lombok/RequiredArgsConstructor.java b/src/core/lombok/RequiredArgsConstructor.java index afe9773e..31c4b81d 100644 --- a/src/core/lombok/RequiredArgsConstructor.java +++ b/src/core/lombok/RequiredArgsConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 The Project Lombok Authors. + * Copyright (C) 2010-2013 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 @@ -49,6 +49,11 @@ 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}))} + */ + AnyAnnotation[] onConstructor() default {}; + + /** * Sets the access level of the constructor. By default, generated constructors are {@code public}. */ AccessLevel access() default lombok.AccessLevel.PUBLIC; @@ -63,4 +68,13 @@ public @interface RequiredArgsConstructor { */ @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. + */ + @Deprecated + @Retention(RetentionPolicy.SOURCE) + @Target({}) + @interface AnyAnnotation {} } diff --git a/src/core/lombok/Setter.java b/src/core/lombok/Setter.java index 59ed9346..22622520 100644 --- a/src/core/lombok/Setter.java +++ b/src/core/lombok/Setter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 The Project Lombok Authors. + * Copyright (C) 2009-2013 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 @@ -57,4 +57,23 @@ public @interface Setter { * If you want your setter to be non-public, you can specify an alternate access level here. */ 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}))} + */ + 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}))} + */ + AnyAnnotation[] onParam() default {}; + + /** + * Placeholder annotation to enable the placement of annotations on the generated code. + * @deprecated Don't use this annotation, ever - Read the documentation. + */ + @Deprecated + @Retention(RetentionPolicy.SOURCE) + @Target({}) + @interface AnyAnnotation {} }
\ No newline at end of file diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 96795fe1..78780522 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 The Project Lombok Authors. + * Copyright (C) 2009-2013 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 @@ -473,7 +473,7 @@ public class EclipseHandlerUtil { } } if (allNull) return null; - return result.toArray(EMPTY_ANNOTATION_ARRAY); + return result.toArray(new Annotation[0]); } public static boolean hasAnnotation(Class<? extends java.lang.annotation.Annotation> type, EclipseNode node) { @@ -1492,40 +1492,102 @@ public class EclipseHandlerUtil { intLiteralFactoryMethod = intLiteralFactoryMethod_; } - private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; - static Annotation[] getAndRemoveAnnotationParameter(Annotation annotation, String annotationName) { - - List<Annotation> result = new ArrayList<Annotation>(); - if (annotation instanceof NormalAnnotation) { - NormalAnnotation normalAnnotation = (NormalAnnotation)annotation; - MemberValuePair[] memberValuePairs = normalAnnotation.memberValuePairs; - List<MemberValuePair> pairs = new ArrayList<MemberValuePair>(); - if (memberValuePairs != null) for (MemberValuePair memberValuePair : memberValuePairs) { - if (annotationName.equals(new String(memberValuePair.name))) { - Expression value = memberValuePair.value; - if (value instanceof ArrayInitializer) { - ArrayInitializer array = (ArrayInitializer) value; - for(Expression expression : array.expressions) { - if (expression instanceof Annotation) { - result.add((Annotation)expression); - } - } - } - else if (value instanceof Annotation) { - result.add((Annotation)value); - } - continue; + private static boolean isAllUnderscores(char[] in) { + if (in == null || in.length == 0) return false; + for (char c : in) if (c != '_') return false; + return true; + } + + 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 + // is supposed to remove the value. That means we need to replace the SMA with either + // MarkerAnnotation or NormalAnnotation and that is beyond the scope of this method as we + // don't need that at the time of writing this method; we only unbox onMethod, onParameter + // and onConstructor. Let's exit early and very obviously: + throw new UnsupportedOperationException("Lombok cannot unbox 'value' from SingleMemberAnnotation at this time."); + } + if (!NormalAnnotation.class.equals(annotation.getClass())) { + // Prevent MarkerAnnotation, SingleMemberAnnotation, and + // CompletionOnAnnotationMemberValuePair from triggering this handler. + return Collections.emptyList(); + } + + NormalAnnotation normalAnnotation = (NormalAnnotation) annotation; + MemberValuePair[] pairs = normalAnnotation.memberValuePairs; + + if (pairs == null) return Collections.emptyList(); + + char[] nameAsCharArray = annotationName.toCharArray(); + + for (int i = 0; i < pairs.length; i++) { + if (pairs[i].name == null || !Arrays.equals(nameAsCharArray, pairs[i].name)) continue; + 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 atUnderscore = (Annotation) value; + if (!(atUnderscore.type instanceof SingleTypeReference) || + !isAllUnderscores(((SingleTypeReference) atUnderscore.type).token)) { + errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + return Collections.emptyList(); + } + + if (atUnderscore instanceof MarkerAnnotation) { + // It's @getter(onMethod=@_). This is weird, but fine. + return Collections.emptyList(); + } + + Expression content = null; + + if (atUnderscore instanceof NormalAnnotation) { + MemberValuePair[] mvps = ((NormalAnnotation) atUnderscore).memberValuePairs; + if (mvps == null || mvps.length == 0) { + // It's @getter(onMethod=@_()). This is weird, but fine. + return Collections.emptyList(); + } + if (mvps.length == 1 && Arrays.equals("value".toCharArray(), mvps[0].name)) { + content = mvps[0].value; } - pairs.add(memberValuePair); } - if (!result.isEmpty()) { - normalAnnotation.memberValuePairs = pairs.isEm |
