diff options
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | doc/changelog.markdown | 2 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java | 18 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/JavacHandlerUtil.java | 26 | ||||
-rw-r--r-- | src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java | 22 | ||||
-rw-r--r-- | src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java | 10 | ||||
-rw-r--r-- | test/transform/resource/after-delombok/InjectField.java | 59 | ||||
-rw-r--r-- | test/transform/resource/after-delombok/SynchronizedPlain.java | 8 | ||||
-rw-r--r-- | test/transform/resource/after-ecj/InjectField.java | 63 | ||||
-rw-r--r-- | test/transform/resource/after-ecj/LoggerSlf4jTypes.java | 2 | ||||
-rw-r--r-- | test/transform/resource/after-eclipse/InjectField.java | 63 | ||||
-rw-r--r-- | test/transform/resource/after-eclipse/LoggerSlf4jTypes.java | 2 | ||||
-rw-r--r-- | test/transform/resource/before/InjectField.java | 50 |
13 files changed, 314 insertions, 12 deletions
@@ -5,5 +5,6 @@ Reinier Zwitserloot <reinier@zwitserloot.com> Robbert Jan Grootjans <grootjans@gmail.com> Roel Spilker <r.spilker@gmail.com> Sander Koning <askoning@gmail.com> +Jappe van der Hel <jappe.vanderhel@gmail.com> By adding your name to this list, you grant full and irrevocable copyright and patent indemnity to Project Lombok and all use of Project Lombok, and you certify that you have the right to do so for all commits you add to Project Lombok. diff --git a/doc/changelog.markdown b/doc/changelog.markdown index c70e57cc..8af76f6c 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -23,7 +23,7 @@ Lombok Changelog * FEATURE: Using `@SneakyThrows` no longer requires a runtime dependency on lombok.jar. In fact, any call to `Lombok.sneakyThrows(ex)` is optimized at the bytecode level and no longer requires you to actually have lombok.jar or lombok-runtime.jar on the classpath. * FEATURE: @*X*ArgsConstructor, @Getter, and @ToString can now be used on enum declarations. Previously, behaviour of these annotations on enums was undefined. * FEATURE: @Getter/@Setter (and by extension, @Data) in v0.9.3 and earlier would generate getter and setter method names that did not conform to the beanspec, primarily when faced with boolean properties. This has been fixed. In practice this won't affect you unless you have properties named `isFoo` or `hasFoo`. Now the setter generated for this will be called `setFoo` (as the property name is `foo`) and not `setIsFoo`. Also, `hasFoo` is now no longer special; the names would be `isHasFoo` and `setHasFoo`. The java bean spec does not give `has` special meaning. -* FEATURE: `@EqualsAndHashCode` (and by extension, `@Data`) now add a `canEqual` method which improves the sanity of equality amongst a hierarchy of classes. [More…](file://localhost/Users/rzwitserloot/ws/LOMBOK/lombok/website/features/EqualsAndHashCode.html) +* FEATURE: `@EqualsAndHashCode` (and by extension, `@Data`) now add a `canEqual` method which improves the sanity of equality amongst a hierarchy of classes. [More…](http://projectlombok.org/features/EqualsAndHashCode.html) * FEATURE: `@Getter` now supports a `lazy=true` attribute. [More…](http://projectlombok.org/features/GetterLazy.html) * ENHANCEMENT: The installer will now find Eclipse installations when they are located in a subdirectory of a directory containing the word 'eclipse' . [Issue #210](http://code.google.com/p/projectlombok/issues/detail?id=210) * ENHANCEMENT: Add null check for `@Cleanup` [Issue #154](http://code.google.com/p/projectlombok/issues/detail?id=154) diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 7f144c17..96dea22d 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1013,9 +1013,17 @@ public class EclipseHandlerUtil { parent.fields = new FieldDeclaration[1]; parent.fields[0] = field; } else { - FieldDeclaration[] newArray = new FieldDeclaration[parent.fields.length + 1]; - System.arraycopy(parent.fields, 0, newArray, 1, parent.fields.length); - newArray[0] = field; + int size = parent.fields.length; + FieldDeclaration[] newArray = new FieldDeclaration[size + 1]; + System.arraycopy(parent.fields, 0, newArray, 0, size); + int index = 0; + for (; index < size; index++) { + FieldDeclaration f = newArray[index]; + if (isEnumConstant(f) || isGenerated(f)) continue; + break; + } + System.arraycopy(newArray, index, newArray, index + 1, size - index); + newArray[index] = field; parent.fields = newArray; } @@ -1028,6 +1036,10 @@ public class EclipseHandlerUtil { type.add(field, Kind.FIELD); } + private static boolean isEnumConstant(final FieldDeclaration field) { + return ((field.initialization instanceof AllocationExpression) && (((AllocationExpression) field.initialization).enumConstant == field)); + } + /** * Inserts a method into an existing type. The type must represent a {@code TypeDeclaration}. */ diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 00090be9..fc9435d8 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -532,11 +532,35 @@ public class JavacHandlerUtil { JCClassDecl type = (JCClassDecl) typeNode.get(); if (addSuppressWarnings) addSuppressWarningsAll(field.mods, typeNode, field.pos, getGeneratedBy(field)); - type.defs = type.defs.append(field); + + List<JCTree> insertAfter = null; + List<JCTree> insertBefore = type.defs; + while (insertBefore.tail != null) { + if (insertBefore.head instanceof JCVariableDecl) { + JCVariableDecl f = (JCVariableDecl) insertBefore.head; + if (isEnumConstant(f) || isGenerated(f)) { + insertAfter = insertBefore; + insertBefore = insertBefore.tail; + continue; + } + } + break; + } + List<JCTree> fieldEntry = List.<JCTree>of(field); + fieldEntry.tail = insertBefore; + if (insertAfter == null) { + type.defs = fieldEntry; + } else { + insertAfter.tail = fieldEntry; + } typeNode.add(field, Kind.FIELD); } + private static boolean isEnumConstant(final JCVariableDecl field) { + return (field.mods.flags & Flags.ENUM) != 0; + } + /** * Adds the given new method declaration to the provided type AST Node. * Can also inject constructors. diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 195cdf6c..6043fdef 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -89,6 +89,7 @@ public class EclipsePatcher extends Agent { patchHideGeneratedNodes(sm); patchPostCompileHookEclipse(sm); patchFixSourceTypeConverter(sm); + patchDisableLombokForCodeFormatterAndCleanup(sm); patchListRewriteHandleGeneratedMethods(sm); } else { patchPostCompileHookEcj(sm); @@ -100,6 +101,25 @@ public class EclipsePatcher extends Agent { if (reloadExistingClasses) sm.reloadClasses(instrumentation); } + private static void patchDisableLombokForCodeFormatterAndCleanup(ScriptManager sm) { + sm.addScript(ScriptBuilder.setSymbolDuringMethodCall() + .target(new MethodTarget("org.eclipse.jdt.internal.formatter.DefaultCodeFormatter", "formatCompilationUnit")) + .callToWrap(new Hook("org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil", "parseCompilationUnit", "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration", "char[]", "java.util.Map", "boolean")) + .symbol("lombok.disable") + .build()); + + sm.addScript(ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.ControlStatementsFix$ControlStatementFinder", "visit", "boolean", "org.eclipse.jdt.core.dom.DoStatement")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.ControlStatementsFix$ControlStatementFinder", "visit", "boolean", "org.eclipse.jdt.core.dom.EnhancedForStatement")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.ControlStatementsFix$ControlStatementFinder", "visit", "boolean", "org.eclipse.jdt.core.dom.ForStatement")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.ControlStatementsFix$ControlStatementFinder", "visit", "boolean", "org.eclipse.jdt.core.dom.IfStatement")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.fix.ControlStatementsFix$ControlStatementFinder", "visit", "boolean", "org.eclipse.jdt.core.dom.WhileStatement")) + .decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.Statement")) + .request(StackRequest.PARAM1) + .valueMethod(new Hook("lombok.eclipse.agent.PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.Statement")) + .build()); + } + private static void patchListRewriteHandleGeneratedMethods(ScriptManager sm) { sm.addScript(ScriptBuilder.replaceMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer$ListRewriter", "rewriteList")) @@ -107,7 +127,7 @@ public class EclipsePatcher extends Agent { .replacementMethod(new Hook("lombok.eclipse.agent.PatchFixes", "listRewriteHandleGeneratedMethods", "org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent[]", "org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent")) .build()); } - + private static void patchDomAstReparseIssues(ScriptManager sm) { sm.addScript(ScriptBuilder.replaceMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer", "visit")) diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java b/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java index 3ac71ca5..f5306ab9 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java @@ -43,6 +43,16 @@ import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent; import org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner; public class PatchFixes { + public static boolean isGenerated(org.eclipse.jdt.core.dom.Statement statement) { + boolean result = false; + try { + result = ((Boolean)statement.getClass().getField("$isGenerated").get(statement)).booleanValue(); + } catch (Exception e) { + // better to assume it isn't generated + } + return result; + } + public static int fixRetrieveStartingCatchPosition(int original, int start) { return original == -1 ? start : original; } diff --git a/test/transform/resource/after-delombok/InjectField.java b/test/transform/resource/after-delombok/InjectField.java new file mode 100644 index 00000000..a9b4b1c4 --- /dev/null +++ b/test/transform/resource/after-delombok/InjectField.java @@ -0,0 +1,59 @@ +import java.util.logging.Level; + +enum InjectField1 { + A, + B; + + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(InjectField1.class.getName()); + @java.lang.SuppressWarnings("all") + private final java.lang.Object $lock = new java.lang.Object[0]; + @java.lang.SuppressWarnings("all") + private static final java.lang.Object $LOCK = new java.lang.Object[0]; + + private static final String LOG_MESSAGE = "static initializer"; + + private String fieldA; + + static { + log.log(Level.FINE, LOG_MESSAGE); + } + + private String fieldB; + + void generateLockField() { + synchronized (this.$lock) { + System.out.println("lock field"); + } + } + + static void generateStaticLockField() { + synchronized (InjectField1.$LOCK) { + System.out.println("static lock field"); + } + } +} + +class InjectField2 { + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(InjectField2.class.getName()); + @java.lang.SuppressWarnings("all") + private final java.lang.Object $lock = new java.lang.Object[0]; + + private static final String LOG_MESSAGE = "static initializer"; + + static { + log.log(Level.FINE, LOG_MESSAGE); + } + + void generateLockField() { + synchronized (this.$lock) { + System.out.println("lock field"); + } + } +} + +class InjectField3 { + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(InjectField3.class.getName()); + static { + log.log(Level.FINE, "static initializer"); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-delombok/SynchronizedPlain.java b/test/transform/resource/after-delombok/SynchronizedPlain.java index 695a3089..1a065085 100644 --- a/test/transform/resource/after-delombok/SynchronizedPlain.java +++ b/test/transform/resource/after-delombok/SynchronizedPlain.java @@ -1,4 +1,6 @@ class SynchronizedPlain1 { + @java.lang.SuppressWarnings("all") + private final java.lang.Object $lock = new java.lang.Object[0]; void test() { synchronized (this.$lock) { System.out.println("one"); @@ -9,10 +11,10 @@ class SynchronizedPlain1 { System.out.println("two"); } } - @java.lang.SuppressWarnings("all") - private final java.lang.Object $lock = new java.lang.Object[0]; } class SynchronizedPlain2 { + @java.lang.SuppressWarnings("all") + private static final java.lang.Object $LOCK = new java.lang.Object[0]; static void test() { synchronized (SynchronizedPlain2.$LOCK) { System.out.println("three"); @@ -23,6 +25,4 @@ class SynchronizedPlain2 { System.out.println("four"); } } - @java.lang.SuppressWarnings("all") - private static final java.lang.Object $LOCK = new java.lang.Object[0]; }
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/InjectField.java b/test/transform/resource/after-ecj/InjectField.java new file mode 100644 index 00000000..83d9e5fa --- /dev/null +++ b/test/transform/resource/after-ecj/InjectField.java @@ -0,0 +1,63 @@ +import java.util.logging.Level; +import lombok.extern.java.Log; +import lombok.Synchronized; +@Log enum InjectField1 { + A(), + B(), + private final java.lang.Object $lock = new java.lang.Object[0]; + private static final java.lang.Object $LOCK = new java.lang.Object[0]; + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(InjectField1.class.getName()); + private static final String LOG_MESSAGE = "static initializer"; + private String fieldA; + static { + log.log(Level.FINE, LOG_MESSAGE); + } + private String fieldB; + <clinit>() { + } + InjectField1() { + super(); + } + @Synchronized void generateLockField() { + synchronized (this.$lock) + { + System.out.println("lock field"); + } + } + static @Synchronized void generateStaticLockField() { + synchronized (InjectField1.$LOCK) + { + System.out.println("static lock field"); + } + } +} +@Log class InjectField2 { + private final java.lang.Object $lock = new java.lang.Object[0]; + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(InjectField2.class.getName()); + private static final String LOG_MESSAGE = "static initializer"; + static { + log.log(Level.FINE, LOG_MESSAGE); + } + <clinit>() { + } + InjectField2() { + super(); + } + @Synchronized void generateLockField() { + synchronized (this.$lock) + { + System.out.println("lock field"); + } + } +} +@Log class InjectField3 { + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(InjectField3.class.getName()); + static { + log.log(Level.FINE, "static initializer"); + } + <clinit>() { + } + InjectField3() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/LoggerSlf4jTypes.java b/test/transform/resource/after-ecj/LoggerSlf4jTypes.java index faa77cd7..95ed1ebf 100644 --- a/test/transform/resource/after-ecj/LoggerSlf4jTypes.java +++ b/test/transform/resource/after-ecj/LoggerSlf4jTypes.java @@ -11,8 +11,8 @@ } } @lombok.extern.slf4j.Slf4j enum LoggerSlf4jTypesEnumWithElement { - private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jTypesEnumWithElement.class); FOO(), + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jTypesEnumWithElement.class); <clinit>() { } LoggerSlf4jTypesEnumWithElement() { diff --git a/test/transform/resource/after-eclipse/InjectField.java b/test/transform/resource/after-eclipse/InjectField.java new file mode 100644 index 00000000..83d9e5fa --- /dev/null +++ b/test/transform/resource/after-eclipse/InjectField.java @@ -0,0 +1,63 @@ +import java.util.logging.Level; +import lombok.extern.java.Log; +import lombok.Synchronized; +@Log enum InjectField1 { + A(), + B(), + private final java.lang.Object $lock = new java.lang.Object[0]; + private static final java.lang.Object $LOCK = new java.lang.Object[0]; + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(InjectField1.class.getName()); + private static final String LOG_MESSAGE = "static initializer"; + private String fieldA; + static { + log.log(Level.FINE, LOG_MESSAGE); + } + private String fieldB; + <clinit>() { + } + InjectField1() { + super(); + } + @Synchronized void generateLockField() { + synchronized (this.$lock) + { + System.out.println("lock field"); + } + } + static @Synchronized void generateStaticLockField() { + synchronized (InjectField1.$LOCK) + { + System.out.println("static lock field"); + } + } +} +@Log class InjectField2 { + private final java.lang.Object $lock = new java.lang.Object[0]; + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(InjectField2.class.getName()); + private static final String LOG_MESSAGE = "static initializer"; + static { + log.log(Level.FINE, LOG_MESSAGE); + } + <clinit>() { + } + InjectField2() { + super(); + } + @Synchronized void generateLockField() { + synchronized (this.$lock) + { + System.out.println("lock field"); + } + } +} +@Log class InjectField3 { + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(InjectField3.class.getName()); + static { + log.log(Level.FINE, "static initializer"); + } + <clinit>() { + } + InjectField3() { + super(); + } +} diff --git a/test/transform/resource/after-eclipse/LoggerSlf4jTypes.java b/test/transform/resource/after-eclipse/LoggerSlf4jTypes.java index faa77cd7..95ed1ebf 100644 --- a/test/transform/resource/after-eclipse/LoggerSlf4jTypes.java +++ b/test/transform/resource/after-eclipse/LoggerSlf4jTypes.java @@ -11,8 +11,8 @@ } } @lombok.extern.slf4j.Slf4j enum LoggerSlf4jTypesEnumWithElement { - private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jTypesEnumWithElement.class); FOO(), + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerSlf4jTypesEnumWithElement.class); <clinit>() { } LoggerSlf4jTypesEnumWithElement() { diff --git a/test/transform/resource/before/InjectField.java b/test/transform/resource/before/InjectField.java new file mode 100644 index 00000000..e81cbc5a --- /dev/null +++ b/test/transform/resource/before/InjectField.java @@ -0,0 +1,50 @@ +import java.util.logging.Level; +import lombok.extern.java.Log; +import lombok.Synchronized; + +@Log +enum InjectField1 { + A, + B; + + private static final String LOG_MESSAGE = "static initializer"; + + private String fieldA; + + static { + log.log(Level.FINE, LOG_MESSAGE); + } + + private String fieldB; + + @Synchronized + void generateLockField() { + System.out.println("lock field"); + } + + @Synchronized + static void generateStaticLockField() { + System.out.println("static lock field"); + } +} + +@Log +class InjectField2 { + private static final String LOG_MESSAGE = "static initializer"; + + static { + log.log(Level.FINE, LOG_MESSAGE); + } + + @Synchronized + void generateLockField() { + System.out.println("lock field"); + } +} + +@Log +class InjectField3 { + static { + log.log(Level.FINE, "static initializer"); + } +}
\ No newline at end of file |