From 66f32d5073bc726f76f958471ea93ec5a29c354b Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 18 Mar 2013 23:57:09 +0100 Subject: Fixed issue 459: Delombok would choke on try-with-resources. --- .../lombok/delombok/PrettyCommentsPrinter.java | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'src/delombok/lombok') diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index 6e9a1c94..9c6a2bd7 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -22,6 +22,11 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ + +/* + * Code derived from com.sun.tools.javac.tree.Pretty, from the langtools project. + * A version can be found at, for example, http://hg.openjdk.java.net/jdk7/build/langtools + */ package lombok.delombok; import static com.sun.tools.javac.code.Flags.ANNOTATION; @@ -981,6 +986,29 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitTry(JCTry tree) { try { print("try "); + List resources = null; + try { + Field f = JCTry.class.getField("resources"); + resources = (List) f.get(tree); + } catch (Exception ignore) { + // In JDK6 and down this field does not exist; resources will retain its initializer value which is what we want. + } + + if (resources != null && resources.nonEmpty()) { + boolean first = true; + print("("); + for (Object var0 : resources) { + JCTree var = (JCTree) var0; + if (!first) { + println(); + indent(); + } + printStat(var); + first = false; + } + print(") "); + } + printStat(tree.body); for (List l = tree.catchers; l.nonEmpty(); l = l.tail) { printStat(l.head); -- cgit From b5747963c022f680168ff66ebdc7860adb954882 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Tue, 25 Jun 2013 00:23:02 +0200 Subject: Value has been promoted to the main package. --- doc/changelog.markdown | 2 +- src/core/lombok/Data.java | 4 +- src/core/lombok/Value.java | 58 ++++++++++++++++ src/core/lombok/core/LombokInternalAliasing.java | 52 ++++++++++++++ src/core/lombok/core/TypeLibrary.java | 6 ++ src/core/lombok/core/TypeResolver.java | 9 +-- src/core/lombok/eclipse/EclipseImportList.java | 13 ++-- src/core/lombok/eclipse/handlers/HandleValue.java | 2 +- src/core/lombok/javac/JavacImportList.java | 9 ++- src/core/lombok/javac/handlers/HandleValue.java | 4 +- .../lombok/javac/handlers/JavacHandlerUtil.java | 19 ++++- src/delombok/lombok/delombok/DelombokApp.java | 1 + .../resource/after-delombok/ValueExperimental.java | 46 ++++++++++++ .../ValueExperimentalStarImport.java | 25 +++++++ .../resource/after-ecj/ValueExperimental.java | 39 +++++++++++ .../after-ecj/ValueExperimentalStarImport.java | 20 ++++++ test/transform/resource/after-ecj/ValuePlain.java | 4 +- .../resource/before/ValueExperimental.java | 9 +++ .../before/ValueExperimentalStarImport.java | 5 ++ test/transform/resource/before/ValuePlain.java | 4 +- website/features/Data.html | 2 +- website/features/SneakyThrows.html | 2 +- website/features/Value.html | 76 ++++++++++++++++++++ website/features/experimental/Value.html | 81 ---------------------- website/features/experimental/Wither.html | 2 +- website/features/experimental/index.html | 9 ++- website/features/experimental/onX.html | 2 +- website/features/index.html | 2 + 28 files changed, 396 insertions(+), 111 deletions(-) create mode 100644 src/core/lombok/Value.java create mode 100644 src/core/lombok/core/LombokInternalAliasing.java create mode 100644 test/transform/resource/after-delombok/ValueExperimental.java create mode 100644 test/transform/resource/after-delombok/ValueExperimentalStarImport.java create mode 100644 test/transform/resource/after-ecj/ValueExperimental.java create mode 100644 test/transform/resource/after-ecj/ValueExperimentalStarImport.java create mode 100644 test/transform/resource/before/ValueExperimental.java create mode 100644 test/transform/resource/before/ValueExperimentalStarImport.java create mode 100644 website/features/Value.html delete mode 100644 website/features/experimental/Value.html (limited to 'src/delombok/lombok') diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 85fcd86a..95ee5764 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -2,7 +2,7 @@ Lombok Changelog ---------------- ### v0.11.9 (Edgy Guinea Pig) -* FEATURE: {Experimental} `@Builder` support. One of our earliest feature request issues has finally been addressed. [@Builder documentation](http://projectlombok.org/features/experimental/Builder.html). +* FEATURE: {Experimental} `@Builder` support. One of our earliest feature request issues, [Issue #16](https://code.google.com/p/projectlombok/issues/detail?id=16), has finally been addressed. [@Builder documentation](http://projectlombok.org/features/experimental/Builder.html). * FEATURE: `@NonNull` on a method or constructor parameter now generates a null-check statement at the start of your method. This nullcheck will throw a `NullPointerException` with the name of the parameter as the message. [Issue #514](https://code.google.com/p/projectlombok/issues/detail?id=514) * BUGFIX: Usage of `Lombok.sneakyThrow()` or `@SneakyThrows` would sometimes result in invalid classes (classes which fail with `VerifyError`). [Issue #470](https://code.google.com/p/projectlombok/issues/detail?id=470) * BUGFIX: Using `val` in try-with-resources did not work for javac. [Issue #520](https://code.google.com/p/projectlombok/issues/detail?id=520) diff --git a/src/core/lombok/Data.java b/src/core/lombok/Data.java index ee6f2fcb..bbc8d920 100644 --- a/src/core/lombok/Data.java +++ b/src/core/lombok/Data.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 @@ -39,7 +39,7 @@ import java.lang.annotation.Target; * @see RequiredArgsConstructor * @see ToString * @see EqualsAndHashCode - * @see lombok.experimental.Value + * @see lombok.Value */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) diff --git a/src/core/lombok/Value.java b/src/core/lombok/Value.java new file mode 100644 index 00000000..2cffe15b --- /dev/null +++ b/src/core/lombok/Value.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012-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 + * 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; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Generates a lot of code which fits with a class that is a representation of an immutable entity. + *

+ * Equivalent to {@code @Getter @FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE) @RequiredArgsConstructor @ToString @EqualsAndHashCode}. + *

+ * Complete documentation is found at the project lombok features page for @Value. + * + * @see lombok.Getter + * @see lombok.experimental.FieldDefaults + * @see lombok.RequiredArgsConstructor + * @see lombok.ToString + * @see lombok.EqualsAndHashCode + * @see lombok.Data + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.SOURCE) +public @interface Value { + /** + * If you specify a static constructor name, then the generated constructor will be private, and + * instead a static factory method is created that other classes can use to create instances. + * We suggest the name: "of", like so: + * + *

+	 *     public @Data(staticConstructor = "of") class Point { final int x, y; }
+	 * 
+ * + * Default: No static constructor, instead the normal constructor is public. + */ + String staticConstructor() default ""; +} diff --git a/src/core/lombok/core/LombokInternalAliasing.java b/src/core/lombok/core/LombokInternalAliasing.java new file mode 100644 index 00000000..4fd7b29d --- /dev/null +++ b/src/core/lombok/core/LombokInternalAliasing.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 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 + * 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.core; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class LombokInternalAliasing { + public static final Map IMPLIED_EXTRA_STAR_IMPORTS; + public static final Map ALIASES; + + /** + * Provide a fully qualified name (FQN), and the canonical version of this is returned. + */ + public static String processAliases(String in) { + if (in == null) return null; + for (Map.Entry e : ALIASES.entrySet()) { + if (in.equals(e.getKey())) return e.getValue(); + } + return in; + } + + static { + Map m = new HashMap(); + m.put("lombok.experimental", "lombok"); + IMPLIED_EXTRA_STAR_IMPORTS = Collections.unmodifiableMap(m); + + m = new HashMap(); + m.put("lombok.experimental.Value", "lombok.Value"); + ALIASES = Collections.unmodifiableMap(m); + } +} diff --git a/src/core/lombok/core/TypeLibrary.java b/src/core/lombok/core/TypeLibrary.java index a89091c4..c0e9dc43 100644 --- a/src/core/lombok/core/TypeLibrary.java +++ b/src/core/lombok/core/TypeLibrary.java @@ -74,6 +74,9 @@ public class TypeLibrary { unqualifiedToQualifiedMap.put(unqualified, fullyQualifiedTypeName); unqualifiedToQualifiedMap.put(fullyQualifiedTypeName, fullyQualifiedTypeName); + for (Map.Entry e : LombokInternalAliasing.ALIASES.entrySet()) { + if (fullyQualifiedTypeName.equals(e.getValue())) unqualifiedToQualifiedMap.put(e.getKey(), fullyQualifiedTypeName); + } } /** @@ -85,6 +88,9 @@ public class TypeLibrary { public String toQualified(String typeReference) { if (unqualifiedToQualifiedMap == null) { if (typeReference.equals(unqualified) || typeReference.equals(qualified)) return qualified; + for (Map.Entry e : LombokInternalAliasing.ALIASES.entrySet()) { + if (e.getKey().equals(typeReference)) return e.getValue(); + } return null; } return unqualifiedToQualifiedMap.get(typeReference); diff --git a/src/core/lombok/core/TypeResolver.java b/src/core/lombok/core/TypeResolver.java index e2ba03b5..287a085f 100644 --- a/src/core/lombok/core/TypeResolver.java +++ b/src/core/lombok/core/TypeResolver.java @@ -39,19 +39,12 @@ public class TypeResolver { this.imports = importList; } -// private static ImportList makeImportList(String packageString, Collection importStrings) { -// Set imports = new HashSet(); -// if (packageString != null) imports.add(packageString + ".*"); -// imports.addAll(importStrings == null ? Collections.emptySet() : importStrings); -// imports.add("java.lang.*"); -// return imports; -// } -// public boolean typeMatches(LombokNode context, String fqn, String typeRef) { return typeRefToFullyQualifiedName(context, TypeLibrary.createLibraryForSingleType(fqn), typeRef) != null; } public String typeRefToFullyQualifiedName(LombokNode context, TypeLibrary library, String typeRef) { + typeRef = LombokInternalAliasing.processAliases(typeRef); // When asking if 'Foo' could possibly be referring to 'bar.Baz', the answer is obviously no. String qualified = library.toQualified(typeRef); if (qualified == null) return null; diff --git a/src/core/lombok/eclipse/EclipseImportList.java b/src/core/lombok/eclipse/EclipseImportList.java index 264ed91f..69246b3c 100644 --- a/src/core/lombok/eclipse/EclipseImportList.java +++ b/src/core/lombok/eclipse/EclipseImportList.java @@ -21,19 +21,21 @@ */ package lombok.eclipse; -import static lombok.eclipse.Eclipse.*; +import static lombok.eclipse.Eclipse.toQualifiedName; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; + +import lombok.core.ImportList; +import lombok.core.LombokInternalAliasing; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.ImportReference; -import lombok.core.ImportList; - public class EclipseImportList implements ImportList { private ImportReference[] imports; private ImportReference pkg; @@ -53,13 +55,16 @@ public class EclipseImportList implements ImportList { int len = token.length; if (len != unqualified.length()) continue; for (int i = 0; i < len; i++) if (token[i] != unqualified.charAt(i)) continue outer; - return toQualifiedName(tokens); + return LombokInternalAliasing.processAliases(toQualifiedName(tokens)); } } return null; } @Override public boolean hasStarImport(String packageName) { + for (Map.Entry e : LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.entrySet()) { + if (e.getValue().equals(packageName) && hasStarImport(e.getKey())) return true; + } if (isEqual(packageName, pkg)) return true; if ("java.lang".equals(packageName)) return true; if (imports != null) for (ImportReference imp : imports) { diff --git a/src/core/lombok/eclipse/handlers/HandleValue.java b/src/core/lombok/eclipse/handlers/HandleValue.java index 60938649..0607137b 100644 --- a/src/core/lombok/eclipse/handlers/HandleValue.java +++ b/src/core/lombok/eclipse/handlers/HandleValue.java @@ -32,7 +32,7 @@ import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists; import lombok.experimental.NonFinal; -import lombok.experimental.Value; +import lombok.Value; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; diff --git a/src/core/lombok/javac/JavacImportList.java b/src/core/lombok/javac/JavacImportList.java index fbd4a518..d5d7460a 100644 --- a/src/core/lombok/javac/JavacImportList.java +++ b/src/core/lombok/javac/JavacImportList.java @@ -23,6 +23,7 @@ package lombok.javac; import java.util.ArrayList; import java.util.Collection; +import java.util.Map; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; @@ -32,6 +33,7 @@ import com.sun.tools.javac.tree.JCTree.JCImport; import com.sun.tools.javac.util.List; import lombok.core.ImportList; +import lombok.core.LombokInternalAliasing; public class JavacImportList implements ImportList { private final JCExpression pkg; @@ -48,13 +50,18 @@ public class JavacImportList implements ImportList { JCTree qual = ((JCImport) def).qualid; if (!(qual instanceof JCFieldAccess)) continue; String simpleName = ((JCFieldAccess) qual).name.toString(); - if (simpleName.equals(unqualified)) return qual.toString(); + if (simpleName.equals(unqualified)) { + return LombokInternalAliasing.processAliases(qual.toString()); + } } return null; } @Override public boolean hasStarImport(String packageName) { + for (Map.Entry e : LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.entrySet()) { + if (e.getValue().equals(packageName) && hasStarImport(e.getKey())) return true; + } if (pkg != null && pkg.toString().equals(packageName)) return true; if ("java.lang".equals(packageName)) return true; diff --git a/src/core/lombok/javac/handlers/HandleValue.java b/src/core/lombok/javac/handlers/HandleValue.java index a59865f7..c0127f3c 100644 --- a/src/core/lombok/javac/handlers/HandleValue.java +++ b/src/core/lombok/javac/handlers/HandleValue.java @@ -26,7 +26,7 @@ import lombok.AccessLevel; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.experimental.NonFinal; -import lombok.experimental.Value; +import lombok.Value; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.handlers.HandleConstructor.SkipIfConstructorExists; @@ -45,7 +45,7 @@ import com.sun.tools.javac.tree.JCTree.JCModifiers; @HandlerPriority(-512) //-2^9; to ensure @EqualsAndHashCode and such pick up on this handler making the class final and messing with the fields' access levels, run earlier. public class HandleValue extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { - deleteAnnotationIfNeccessary(annotationNode, Value.class); + deleteAnnotationIfNeccessary(annotationNode, Value.class, lombok.experimental.Value.class); JavacNode typeNode = annotationNode.up(); boolean notAClass = !isClass(typeNode); diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 92cebf4c..1784be90 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -280,7 +280,22 @@ public class JavacHandlerUtil { * then removes any import statement that imports this exact annotation (not star imports). * Only does this if the DeleteLombokAnnotations class is in the context. */ + @SuppressWarnings("unchecked") public static void deleteAnnotationIfNeccessary(JavacNode annotation, Class annotationType) { + deleteAnnotationIfNeccessary0(annotation, annotationType); + } + + /** + * Removes the annotation from javac's AST (it remains in lombok's AST), + * then removes any import statement that imports this exact annotation (not star imports). + * Only does this if the DeleteLombokAnnotations class is in the context. + */ + @SuppressWarnings("unchecked") + public static void deleteAnnotationIfNeccessary(JavacNode annotation, Class annotationType1, Class annotationType2) { + deleteAnnotationIfNeccessary0(annotation, annotationType1, annotationType2); + } + + private static void deleteAnnotationIfNeccessary0(JavacNode annotation, Class... annotationTypes) { if (inNetbeansEditor(annotation)) return; if (!annotation.shouldDeleteLombokAnnotations()) return; JavacNode parentNode = annotation.directUp(); @@ -309,7 +324,9 @@ public class JavacHandlerUtil { } parentNode.getAst().setChanged(); - deleteImportFromCompilationUnit(annotation, annotationType.getName()); + for (Class annotationType : annotationTypes) { + deleteImportFromCompilationUnit(annotation, annotationType.getName()); + } } public static void deleteImportFromCompilationUnit(JavacNode node, String name) { diff --git a/src/delombok/lombok/delombok/DelombokApp.java b/src/delombok/lombok/delombok/DelombokApp.java index 90a7b55e..5b97be08 100644 --- a/src/delombok/lombok/delombok/DelombokApp.java +++ b/src/delombok/lombok/delombok/DelombokApp.java @@ -84,6 +84,7 @@ public class DelombokApp extends LombokApp { return null; } + @SuppressWarnings("resource") final JarFile toolsJarFile = new JarFile(toolsJar); ClassLoader loader = new ClassLoader() { diff --git a/test/transform/resource/after-delombok/ValueExperimental.java b/test/transform/resource/after-delombok/ValueExperimental.java new file mode 100644 index 00000000..77a48ec9 --- /dev/null +++ b/test/transform/resource/after-delombok/ValueExperimental.java @@ -0,0 +1,46 @@ +final class ValueExperimental1 { + @java.lang.SuppressWarnings("all") + public ValueExperimental1() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof ValueExperimental1)) return false; + return true; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + int result = 1; + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "ValueExperimental1()"; + } +} +final class ValueExperimental2 { + @java.lang.SuppressWarnings("all") + public ValueExperimental2() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof ValueExperimental2)) return false; + return true; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + int result = 1; + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "ValueExperimental2()"; + } +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/ValueExperimentalStarImport.java b/test/transform/resource/after-delombok/ValueExperimentalStarImport.java new file mode 100644 index 00000000..6911f260 --- /dev/null +++ b/test/transform/resource/after-delombok/ValueExperimentalStarImport.java @@ -0,0 +1,25 @@ +import lombok.experimental.*; +final class ValueExperimentalStarImport { + @java.lang.SuppressWarnings("all") + public ValueExperimentalStarImport() { + + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof ValueExperimentalStarImport)) return false; + return true; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + int result = 1; + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "ValueExperimentalStarImport()"; + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValueExperimental.java b/test/transform/resource/after-ecj/ValueExperimental.java new file mode 100644 index 00000000..dd13574a --- /dev/null +++ b/test/transform/resource/after-ecj/ValueExperimental.java @@ -0,0 +1,39 @@ +import lombok.experimental.Value; +final @Value class ValueExperimental1 { + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof ValueExperimental1))) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + int result = 1; + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return "ValueExperimental1()"; + } + public @java.lang.SuppressWarnings("all") ValueExperimental1() { + super(); + } +} +final @lombok.experimental.Value class ValueExperimental2 { + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof ValueExperimental2))) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + int result = 1; + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return "ValueExperimental2()"; + } + public @java.lang.SuppressWarnings("all") ValueExperimental2() { + super(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/ValueExperimentalStarImport.java b/test/transform/resource/after-ecj/ValueExperimentalStarImport.java new file mode 100644 index 00000000..b69e85d9 --- /dev/null +++ b/test/transform/resource/after-ecj/ValueExperimentalStarImport.java @@ -0,0 +1,20 @@ +import lombok.experimental.*; +final @Value class ValueExperimentalStarImport { + public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof ValueExperimentalStarImport))) + return false; + return true; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() { + int result = 1; + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return "ValueExperimentalStarImport()"; + } + public @java.lang.SuppressWarnings("all") ValueExperimentalStarImport() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/ValuePlain.java b/test/transform/resource/after-ecj/ValuePlain.java index b798b308..d095913f 100644 --- a/test/transform/resource/after-ecj/ValuePlain.java +++ b/test/transform/resource/after-ecj/ValuePlain.java @@ -1,5 +1,5 @@ -import lombok.experimental.Value; -final @lombok.experimental.Value class Value1 { +import lombok.Value; +final @lombok.Value class Value1 { private final int x; private final String name; public @java.lang.SuppressWarnings("all") int getX() { diff --git a/test/transform/resource/before/ValueExperimental.java b/test/transform/resource/before/ValueExperimental.java new file mode 100644 index 00000000..6bae26a0 --- /dev/null +++ b/test/transform/resource/before/ValueExperimental.java @@ -0,0 +1,9 @@ +import lombok.experimental.Value; + +@Value +class ValueExperimental1 { +} + +@lombok.experimental.Value +class ValueExperimental2 { +} \ No newline at end of file diff --git a/test/transform/resource/before/ValueExperimentalStarImport.java b/test/transform/resource/before/ValueExperimentalStarImport.java new file mode 100644 index 00000000..5f18cffe --- /dev/null +++ b/test/transform/resource/before/ValueExperimentalStarImport.java @@ -0,0 +1,5 @@ +import lombok.experimental.*; + +@Value +class ValueExperimentalStarImport { +} \ No newline at end of file diff --git a/test/transform/resource/before/ValuePlain.java b/test/transform/resource/before/ValuePlain.java index 39c583cc..3fe33705 100644 --- a/test/transform/resource/before/ValuePlain.java +++ b/test/transform/resource/before/ValuePlain.java @@ -1,5 +1,5 @@ -import lombok.experimental.Value; -@lombok.experimental.Value class Value1 { +import lombok.Value; +@lombok.Value class Value1 { final int x; String name; } diff --git a/website/features/Data.html b/website/features/Data.html index 1c8510b7..ad3aa892 100644 --- a/website/features/Data.html +++ b/website/features/Data.html @@ -75,7 +75,7 @@
diff --git a/website/features/SneakyThrows.html b/website/features/SneakyThrows.html index 573bd95c..3b3987e4 100644 --- a/website/features/SneakyThrows.html +++ b/website/features/SneakyThrows.html @@ -70,7 +70,7 @@
diff --git a/website/features/Value.html b/website/features/Value.html new file mode 100644 index 00000000..92fcc825 --- /dev/null +++ b/website/features/Value.html @@ -0,0 +1,76 @@ + + + + + + + + @ExtensionMethod +
+
+
+ +

@Value

+ +
+

Since

+

+ @Value was introduced as experimental feature in lombok v0.11.4. +

+ @Value no longer implies @Wither since lombok v0.11.8. +

+ @Value promoted to the main lombok package since lombok v0.11.10. +

+
+

Overview

+

+ @Value is the immutable variant of @Data; all fields are made private and final by default, and setters are not generated. The class itself is also made final by default, because immutability is not something that can be forced onto a subclass. Like @Data, useful toString(), equals() and hashCode() methods are also generated, each field gets a getter method, and a constructor that covers every + argument (except final fields that are initialized in the field declaration) is also generated. +

+ In practice, @Value is shorthand for: final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter. +

+ It is possible to override the final-by-default and private-by-default behaviour using either an explicit access level on a field, or by using the @NonFinal or @PackagePrivate annotations.
+ It is possible to override any default behaviour for any of the 'parts' that make up @Value by explicitly using that annotation. +

+
+
+
+

With Lombok

+
@HTML_PRE@
+
+
+
+

Vanilla Java

+
@HTML_POST@
+
+
+
+
+

Small print

+

+ Look for the documentation on the 'parts' of @Value: @ToString, @EqualsAndHashCode, @AllArgsConstructor, @FieldDefaults, and @Getter. +

+ For classes with generics, it's useful to have a static method which serves as a constructor, because inference of generic parameters via static methods works in java6 and avoids having to use the diamond operator. While you can force this by applying an explicit @AllArgsConstructor(staticConstructor="of") annotation, there's also the @Value(staticConstructor="of") feature, which will make the generated all-arguments constructor private, and generates a public static method named of which is a wrapper around this private constructor. +

+ @Value was an experimental feature from v0.11.4 to v0.11.9 (as @lombok.experimental.Value). It has since been moved into the core package. The old annotation is still + around (and is an alias). It will eventually be removed in a future version, though. +

+
+ +
+
+
+ + + diff --git a/website/features/experimental/Value.html b/website/features/experimental/Value.html deleted file mode 100644 index d2acfee4..00000000 --- a/website/features/experimental/Value.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - EXPERIMENTAL - @ExtensionMethod -
-
-
- -

@Value

- -
-

Since

-

- @Value was introduced as experimental feature in lombok v0.11.4. -

- @Value no longer implies @Wither since lombok v0.11.8. -

-
-

Experimental

-

- Experimental because: -

    -
  • Various choices still have to be vetted as being the correct 'least surprise' choice: Should the class be made final by default, etc.
  • -
- Current status: positive - Currently we feel this feature may move out of experimental status with no or minor changes soon. -
-
-

Overview

-

- @Value is the immutable variant of @Data; all fields are made private and final by default, and setters are not generated. The class itself is also made final by default, because immutability is not something that can be forced onto a subclass. Like @Data, useful toString(), equals() and hashCode() methods are also generated, each field gets a getter method, and a constructor that covers every - argument (except final fields that are initialized in the field declaration) is also generated. -

- In practice, @Value is shorthand for: final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter. -

- It is possible to override the final-by-default and private-by-default behaviour using either an explicit access level on a field, or by using the @NonFinal or @PackagePrivate annotations.
- It is possible to override any default behaviour for any of the 'parts' that make up @Value by explicitly using that annotation. -

-
-
-
-

With Lombok

-
@HTML_PRE@
-
-
-
-

Vanilla Java

-
@HTML_POST@
-
-
-
-
-

Small print

-

- Look for the documentation on the 'parts' of @Value: @ToString, @EqualsAndHashCode, @AllArgsConstructor, @FieldDefaults, and @Getter. -

- For classes with generics, it's useful to have a static method which serves as a constructor, because inference of generic parameters via static methods works in java6 and avoids having to use the diamond operator. While you can force this by applying an explicit @AllArgsConstructor(staticConstructor="of") annotation, there's also the @Value(staticConstructor="of") feature, which will make the generated all-arguments constructor private, and generates a public static method named of which is a wrapper around this private constructor. -

-
-
- -
-
-
- - - diff --git a/website/features/experimental/Wither.html b/website/features/experimental/Wither.html index da2156cd..9cbcd5ed 100644 --- a/website/features/experimental/Wither.html +++ b/website/features/experimental/Wither.html @@ -83,7 +83,7 @@
diff --git a/website/features/experimental/index.html b/website/features/experimental/index.html index d0a086a0..31fcd5ad 100644 --- a/website/features/experimental/index.html +++ b/website/features/experimental/index.html @@ -32,12 +32,17 @@
New default field modifiers for the 21st century.
@Wither
Immutable 'setters' - methods that create a clone but with one changed field.
-
@Value
-
Immutable classes made very easy.
onMethod= / onConstructor= / onParam
Sup dawg, we heard you like annotations, so we put annotations in your annotations so you can annotate while you're annotating.
+
+

Putting the "Ex" in "Experimental": promoted or deleted experimental features.

+
+
@Value: Promoted
+
@Value has proven its value and has been moved to the main package. +
+
diff --git a/website/features/experimental/onX.html b/website/features/experimental/onX.html index 99365deb..66b0164f 100644 --- a/website/features/experimental/onX.html +++ b/website/features/experimental/onX.html @@ -69,7 +69,7 @@
diff --git a/website/features/index.html b/website/features/index.html index 8b3765c1..f9b8cdfa 100644 --- a/website/features/index.html +++ b/website/features/index.html @@ -30,6 +30,8 @@
@Data
All together now: A shortcut for @ToString, @EqualsAndHashCode, @Getter on all fields, and @Setter on all non-final fields, and @RequiredArgsConstructor!
+
@Value
+
Immutable classes made very easy.
@SneakyThrows
To boldly throw checked exceptions where no one has thrown them before!
@Synchronized
-- cgit From dfc682a0010ff1ba77496dd7644a6dcbe93017e5 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Sun, 7 Jul 2013 09:48:58 +0200 Subject: lombok's compile target is 1.6, but, eclipse project was generated as 1.7. This caused a bunch of weirdness because eclipse changes a bunch of warnings and quickfixes based on this (such as complaining about lack of @SafeVarargs, a 1.7-only feature). --- build.xml | 2 +- src/delombok/lombok/delombok/DelombokApp.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'src/delombok/lombok') diff --git a/build.xml b/build.xml index bf13eeff..fb328e3e 100644 --- a/build.xml +++ b/build.xml @@ -256,7 +256,7 @@ the common tasks and can be called on to run the main aspects of all the sub-scr - + diff --git a/src/delombok/lombok/delombok/DelombokApp.java b/src/delombok/lombok/delombok/DelombokApp.java index 5b97be08..90a7b55e 100644 --- a/src/delombok/lombok/delombok/DelombokApp.java +++ b/src/delombok/lombok/delombok/DelombokApp.java @@ -84,7 +84,6 @@ public class DelombokApp extends LombokApp { return null; } - @SuppressWarnings("resource") final JarFile toolsJarFile = new JarFile(toolsJar); ClassLoader loader = new ClassLoader() { -- cgit From a6c1be550fd1911084faaf7f54ae7bbbd5673642 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 8 Jul 2013 04:58:00 +0200 Subject: A lot of refactoring on how javadoc is handled, to prepare for copying javadoc from field to setter/getter in javac. --- .../lombok/delombok/PrettyCommentsPrinter.java | 32 +- .../sun/tools/javac/parser/DocCommentScanner.java | 25 ++ src/stubs/com/sun/tools/javac/parser/Scanner.java | 7 + .../com/sun/tools/javadoc/DocCommentScanner.java | 25 ++ src/utils/lombok/javac/CommentCatcher.java | 4 +- src/utils/lombok/javac/CommentInfo.java | 2 +- .../java6/CommentCollectingParserFactory.java | 2 +- .../javac/java6/CommentCollectingScanner.java | 5 +- .../java6/CommentCollectingScannerFactory.java | 2 +- .../lombok/javac/java6/DocCommentScanner.java | 461 +++++++++++++++++++++ .../java7/CommentCollectingParserFactory.java | 4 +- .../javac/java7/CommentCollectingScanner.java | 7 +- 12 files changed, 557 insertions(+), 19 deletions(-) create mode 100644 src/stubs/com/sun/tools/javac/parser/DocCommentScanner.java create mode 100644 src/stubs/com/sun/tools/javadoc/DocCommentScanner.java create mode 100644 src/utils/lombok/javac/java6/DocCommentScanner.java (limited to 'src/delombok/lombok') diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index 9c6a2bd7..342e3323 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -224,12 +224,21 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { return tree.getEndPosition(cu.endPositions); } - private void consumeComments(int till) throws IOException { + private void consumeComments(int until) throws IOException { + consumeComments(until, null); + } + private void consumeComments(int until, JCTree tree) throws IOException { boolean prevNewLine = onNewLine; boolean found = false; CommentInfo head = comments.head; - while (comments.nonEmpty() && head.pos < till) { - printComment(head); + while (comments.nonEmpty() && head.pos < until) { + if (tree != null && docComments != null && docComments.containsKey(tree) && head.isJavadoc() && noFurtherJavadocForthcoming(until)) { + // This is (presumably) the exact same javadoc that has already been associated with the node that we're just about to + // print. These javadoc can be modified by lombok handlers, and as such we should NOT print them from the consumed comments db, + // and instead print the actual javadoc associated with the upcoming node (which the visit method for that node will take care of). + } else { + printComment(head); + } comments = comments.tail; head = comments.head; } @@ -237,6 +246,17 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { println(); } } + + private boolean noFurtherJavadocForthcoming(int until) { + List c = comments; + if (c.nonEmpty()) c = c.tail; + while (c.nonEmpty()) { + if (c.head.pos >= until) return true; + if (c.head.isJavadoc()) return false; + c = c.tail; + } + return true; + } private void consumeTrailingComments(int from) throws IOException { boolean prevNewLine = onNewLine; @@ -408,7 +428,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { this.prec = prec; if (tree == null) print("/*missing*/"); else { - consumeComments(tree.pos); + consumeComments(tree.pos, tree); tree.accept(this); int endPos = endPos(tree); consumeTrailingComments(endPos); @@ -620,7 +640,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { docComments = tree.docComments; printDocComment(tree); if (tree.pid != null) { - consumeComments(tree.pos); + consumeComments(tree.pos, tree); print("package "); printExpr(tree.pid); print(";"); @@ -694,7 +714,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitClassDef(JCClassDecl tree) { try { - consumeComments(tree.pos); + consumeComments(tree.pos, tree); println(); align(); printDocComment(tree); printAnnotations(tree.mods.annotations); diff --git a/src/stubs/com/sun/tools/javac/parser/DocCommentScanner.java b/src/stubs/com/sun/tools/javac/parser/DocCommentScanner.java new file mode 100644 index 00000000..d461d54b --- /dev/null +++ b/src/stubs/com/sun/tools/javac/parser/DocCommentScanner.java @@ -0,0 +1,25 @@ +/* + * These are stub versions of various bits of javac-internal API (for various different versions of javac). Lombok is compiled against these. + */ +package com.sun.tools.javac.parser; + +import java.nio.CharBuffer; + +public class DocCommentScanner extends Scanner { + protected DocCommentScanner(Factory fac, CharBuffer buffer) { + super(fac, buffer); + } + + protected DocCommentScanner(Factory fac, char[] input, int inputLength) { + super(fac, input, inputLength); + } + + protected DocCommentScanner(ScannerFactory fac, CharBuffer buffer) { + super(fac, buffer); + } + + protected DocCommentScanner(ScannerFactory fac, char[] input, int inputLength) { + super(fac, input, inputLength); + } + +} diff --git a/src/stubs/com/sun/tools/javac/parser/Scanner.java b/src/stubs/com/sun/tools/javac/parser/Scanner.java index af94bacc..266208e5 100644 --- a/src/stubs/com/sun/tools/javac/parser/Scanner.java +++ b/src/stubs/com/sun/tools/javac/parser/Scanner.java @@ -59,4 +59,11 @@ public class Scanner implements Lexer { public char[] getRawCharacters(int beginIndex, int endIndex) { return null; } + + public void nextToken() { + } + + public char[] getRawCharacters() { + return new char[0]; + } } diff --git a/src/stubs/com/sun/tools/javadoc/DocCommentScanner.java b/src/stubs/com/sun/tools/javadoc/DocCommentScanner.java new file mode 100644 index 00000000..e2ea9614 --- /dev/null +++ b/src/stubs/com/sun/tools/javadoc/DocCommentScanner.java @@ -0,0 +1,25 @@ +/* + * These are stub versions of various bits of javac-internal API (for various different versions of javac). Lombok is compiled against these. + */ +package com.sun.tools.javadoc; + +import java.nio.CharBuffer; + +import com.sun.tools.javac.parser.Scanner; +import com.sun.tools.javac.util.Context; + +public class DocCommentScanner extends Scanner { + protected DocCommentScanner(com.sun.tools.javadoc.DocCommentScanner.Factory fac, CharBuffer buffer) { + super(fac, buffer); + } + + protected DocCommentScanner(com.sun.tools.javadoc.DocCommentScanner.Factory fac, char[] input, int inputLength) { + super(fac, input, inputLength); + } + + public static class Factory extends Scanner.Factory { + protected Factory(Context context) { + super(context); + } + } +} diff --git a/src/utils/lombok/javac/CommentCatcher.java b/src/utils/lombok/javac/CommentCatcher.java index 2825cd30..565a166d 100644 --- a/src/utils/lombok/javac/CommentCatcher.java +++ b/src/utils/lombok/javac/CommentCatcher.java @@ -78,10 +78,10 @@ public class CommentCatcher { try { if (Javac.getJavaCompilerVersion() <= 6) { Class parserFactory = Class.forName("lombok.javac.java6.CommentCollectingParserFactory"); - parserFactory.getMethod("setInCompiler",JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); + parserFactory.getMethod("setInCompiler", JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); } else { Class parserFactory = Class.forName("lombok.javac.java7.CommentCollectingParserFactory"); - parserFactory.getMethod("setInCompiler",JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); + parserFactory.getMethod("setInCompiler", JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); } } catch (Exception e) { if (e instanceof RuntimeException) throw (RuntimeException)e; diff --git a/src/utils/lombok/javac/CommentInfo.java b/src/utils/lombok/javac/CommentInfo.java index 7375d51a..afdd8469 100644 --- a/src/utils/lombok/javac/CommentInfo.java +++ b/src/utils/lombok/javac/CommentInfo.java @@ -66,7 +66,7 @@ public final class CommentInfo { } public boolean isJavadoc() { - return content.startsWith("/**"); + return content.startsWith("/**") && content.length() > 4; } @Override diff --git a/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java b/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java index b2a248c8..7e34b723 100644 --- a/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java +++ b/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java @@ -25,7 +25,7 @@ public class CommentCollectingParserFactory extends Parser.Factory { } @Override public Parser newParser(Lexer S, boolean keepDocComments, boolean genEndPos) { - Object x = new CommentCollectingParser(this, S, keepDocComments, commentsMap); + Object x = new CommentCollectingParser(this, S, true, commentsMap); return (Parser) x; // CCP is based on a stub which extends nothing, but at runtime the stub is replaced with either //javac6's EndPosParser which extends Parser, or javac7's EndPosParser which implements Parser. diff --git a/src/utils/lombok/javac/java6/CommentCollectingScanner.java b/src/utils/lombok/javac/java6/CommentCollectingScanner.java index 66e1514d..b584ec16 100644 --- a/src/utils/lombok/javac/java6/CommentCollectingScanner.java +++ b/src/utils/lombok/javac/java6/CommentCollectingScanner.java @@ -27,12 +27,10 @@ import lombok.javac.CommentInfo; import lombok.javac.CommentInfo.EndConnection; import lombok.javac.CommentInfo.StartConnection; -import com.sun.tools.javac.parser.Scanner; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; - -public class CommentCollectingScanner extends Scanner { +public class CommentCollectingScanner extends DocCommentScanner { private final ListBuffer comments = ListBuffer.lb(); private int endComment = 0; @@ -56,6 +54,7 @@ public class CommentCollectingScanner extends Scanner { CommentInfo comment = new CommentInfo(prevEndPos, pos, endPos, content, start, end); comments.append(comment); + super.processComment(style); } private EndConnection determineEndConnection(int pos) { diff --git a/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java b/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java index b7d8ed13..f3d6bd72 100644 --- a/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java +++ b/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java @@ -26,7 +26,7 @@ import java.nio.CharBuffer; import com.sun.tools.javac.parser.Scanner; import com.sun.tools.javac.util.Context; -public class CommentCollectingScannerFactory extends Scanner.Factory { +public class CommentCollectingScannerFactory extends DocCommentScanner.Factory { @SuppressWarnings("all") public static void preRegister(final Context context) { diff --git a/src/utils/lombok/javac/java6/DocCommentScanner.java b/src/utils/lombok/javac/java6/DocCommentScanner.java new file mode 100644 index 00000000..ff3eadd4 --- /dev/null +++ b/src/utils/lombok/javac/java6/DocCommentScanner.java @@ -0,0 +1,461 @@ +package lombok.javac.java6; + +/* + * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import static com.sun.tools.javac.util.LayoutCharacters.*; + +import java.nio.CharBuffer; + +import com.sun.tools.javac.parser.Scanner; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Position; + +/** An extension to the base lexical analyzer that captures + * and processes the contents of doc comments. It does so by + * translating Unicode escape sequences and by stripping the + * leading whitespace and starts from each line of the comment. + * + *

This is NOT part of any API supported by Sun Microsystems. If + * you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class DocCommentScanner extends Scanner { + + /** A factory for creating scanners. */ + public static class Factory extends Scanner.Factory { + + @SuppressWarnings({"unchecked", "all"}) + public static void preRegister(final Context context) { + context.put(scannerFactoryKey, new Context.Factory() { + public Object make() { + return new Factory(context); + } + + public Object make(Context c) { + return new Factory(c); + } + }); + } + + /** Create a new scanner factory. */ + protected Factory(Context context) { + super(context); + } + + @Override + public Scanner newScanner(CharSequence input) { + if (input instanceof CharBuffer) { + return new DocCommentScanner(this, (CharBuffer)input); + } else { + char[] array = input.toString().toCharArray(); + return newScanner(array, array.length); + } + } + + @Override + public Scanner newScanner(char[] input, int inputLength) { + return new DocCommentScanner(this, input, inputLength); + } + } + + + /** Create a scanner from the input buffer. buffer must implement + * array() and compact(), and remaining() must be less than limit(). + */ + protected DocCommentScanner(Factory fac, CharBuffer buffer) { + super(fac, buffer); + } + + /** Create a scanner from the input array. The array must have at + * least a single character of extra space. + */ + protected DocCommentScanner(Factory fac, char[] input, int inputLength) { + super(fac, input, inputLength); + } + + /** Starting position of the comment in original source + */ + private int pos; + + /** The comment input buffer, index of next chacter to be read, + * index of one past last character in buffer. + */ + private char[] buf; + private int bp; + private int buflen; + + /** The current character. + */ + private char ch; + + /** The column number position of the current character. + */ + private int col; + + /** The buffer index of the last converted Unicode character + */ + private int unicodeConversionBp = 0; + + /** + * Buffer for doc comment. + */ + private char[] docCommentBuffer = new char[1024]; + + /** + * Number of characters in doc comment buffer. + */ + private int docCommentCount; + + /** + * Translated and stripped contents of doc comment + */ + private String docComment = null; + + + /** Unconditionally expand the comment buffer. + */ + private void expandCommentBuffer() { + char[] newBuffer = new char[docCommentBuffer.length * 2]; + System.arraycopy(docCommentBuffer, 0, newBuffer, + 0, docCommentBuffer.length); + docCommentBuffer = newBuffer; + } + + /** Convert an ASCII digit from its base (8, 10, or 16) + * to its value. + */ + private int digit(int base) { + char c = ch; + int result = Character.digit(c, base); + if (result >= 0 && c > 0x7f) { + ch = "0123456789abcdef".charAt(result); + } + return result; + } + + /** Convert Unicode escape; bp points to initial '\' character + * (Spec 3.3). + */ + private void convertUnicode() { + if (ch == '\\' && unicodeConversionBp != bp) { + bp++; ch = buf[bp]; col++; + if (ch == 'u') { + do { + bp++; ch = buf[bp]; col++; + } while (ch == 'u'); + int limit = bp + 3; + if (limit < buflen) { + int d = digit(16); + int code = d; + while (bp < limit && d >= 0) { + bp++; ch = buf[bp]; col++; + d = digit(16); + code = (code << 4) + d; + } + if (d >= 0) { + ch = (char)code; + unicodeConversionBp = bp; + return; + } + } + // "illegal.Unicode.esc", reported by base scanner + } else { + bp--; + ch = '\\'; + col--; + } + } + } + + + /** Read next character. + */ + private void scanChar() { + bp++; + ch = buf[bp]; + switch (ch) { + case '\r': // return + col = 0; + break; + case '\n': // newline + if (bp == 0 || buf[bp-1] != '\r') { + col = 0; + } + break; + case '\t': // tab + col = (col / TabInc * TabInc) + TabInc; + break; + case '\\': // possible Unicode + col++; + convertUnicode(); + break; + default: + col++; + break; + } + } + + /** + * Read next character in doc comment, skipping over double '\' characters. + * If a double '\' is skipped, put in the buffer and update buffer count. + */ + private void scanDocCommentChar() { + scanChar(); + if (ch == '\\') { + if (buf[bp+1] == '\\' && unicodeConversionBp != bp) { + if (docCommentCount == docCommentBuffer.length) + expandCommentBuffer(); + docCommentBuffer[docCommentCount++] = ch; + bp++; col++; + } else { + convertUnicode(); + } + } + } + + /* Reset doc comment before reading each new token + */ + public void nextToken() { + docComment = null; + super.nextToken(); + } + + /** + * Returns the documentation string of the current token. + */ + public String docComment() { + return docComment; + } + + /** + * Process a doc comment and make the string content available. + * Strips leading whitespace and stars. + */ + @SuppressWarnings("fallthrough") + protected void processComment(CommentStyle style) { + if (style != CommentStyle.JAVADOC) { + return; + } + + pos = pos(); + buf = getRawCharacters(pos, endPos()); + buflen = buf.length; + bp = 0; + col = 0; + + docCommentCount = 0; + + boolean firstLine = true; + + // Skip over first slash + scanDocCommentChar(); + // Skip over first star + scanDocCommentChar(); + + // consume any number of stars + while (bp < buflen && ch == '*') { + scanDocCommentChar(); + } + // is the comment in the form /**/, /***/, /****/, etc. ? + if (bp < buflen && ch == '/') { + docComment = ""; + return; + } + + // skip a newline on the first line of the comment. + if (bp < buflen) { + if (ch == LF) { + scanDocCommentChar(); + firstLine = false; + } else if (ch == CR) { + scanDocCommentChar(); + if (ch == LF) { + scanDocCommentChar(); + firstLine = false; + } + } + } + + outerLoop: + + // The outerLoop processes the doc comment, looping once + // for each line. For each line, it first strips off + // whitespace, then it consumes any stars, then it + // puts the rest of the line into our buffer. + while (bp < buflen) { + + // The wsLoop consumes whitespace from the beginning + // of each line. + wsLoop: + + while (bp < buflen) { + switch(ch) { + case ' ': + scanDocCommentChar(); + break; + case '\t': + col = ((col - 1) / TabInc * TabInc) + TabInc; + scanDocCommentChar(); + break; + case FF: + col = 0; + scanDocCommentChar(); + break; +// Treat newline at beginning of line (blank line, no star) +// as comment text. Old Javadoc compatibility requires this. +/*---------------------------------* + case CR: // (Spec 3.4) + scanDocCommentChar(); + if (ch == LF) { + col = 0; + scanDocCommentChar(); + } + break; + case LF: // (Spec 3.4) + scanDocCommentChar(); + break; +*---------------------------------*/ + default: + // we've seen something that isn't whitespace; + // jump out. + break wsLoop; + } + } + + // Are there stars here? If so, consume them all + // and check for the end of comment. + if (ch == '*') { + // skip all of the stars + do { + scanDocCommentChar(); + } while (ch == '*'); + + // check for the closing slash. + if (ch == '/') { + // We're done with the doc comment + // scanChar() and breakout. + break outerLoop; + } + } else if (! firstLine) { + //The current line does not begin with a '*' so we will indent it. + for (int i = 1; i < col; i++) { + if (docCommentCount == docCommentBuffer.length) + expandCommentBuffer(); + docCommentBuffer[docCommentCount++] = ' '; + } + } + + // The textLoop processes the rest of the characters + // on the line, adding them to our buffer. + textLoop: + while (bp < buflen) { + switch (ch) { + case '*': + // Is this just a star? Or is this the + // end of a comment? + scanDocCommentChar(); + if (ch == '/') { + // This is the end of the comment, + // set ch and return our buffer. + break outerLoop; + } + // This is just an ordinary star. Add it to + // the buffer. + if (docCommentCount == docCommentBuffer.length) + expandCommentBuffer(); + docCommentBuffer[docCommentCount++] = '*'; + break; + case ' ': + case '\t': + if (docCommentCount == docCommentBuffer.length) + expandCommentBuffer(); + docCommentBuffer[docCommentCount++] = ch; + scanDocCommentChar(); + break; + case FF: + scanDocCommentChar(); + break textLoop; // treat as end of line + case CR: // (Spec 3.4) + scanDocCommentChar(); + if (ch != LF) { + // Canonicalize CR-only line terminator to LF + if (docCommentCount == docCommentBuffer.length) + expandCommentBuffer(); + docCommentBuffer[docCommentCount++] = (char)LF; + break textLoop; + } + /* fall through to LF case */ + case LF: // (Spec 3.4) + // We've seen a newline. Add it to our + // buffer and break out of this loop, + // starting fresh on a new line. + if (docCommentCount == docCommentBuffer.length) + expandCommentBuffer(); + docCommentBuffer[docCommentCount++] = ch; + scanDocCommentChar(); + break textLoop; + default: + // Add the character to our buffer. + if (docCommentCount == docCommentBuffer.length) + expandCommentBuffer(); + docCommentBuffer[docCommentCount++] = ch; + scanDocCommentChar(); + } + } // end textLoop + firstLine = false; + } // end outerLoop + + if (docCommentCount > 0) { + int i = docCommentCount - 1; + trailLoop: + while (i > -1) { + switch (docCommentBuffer[i]) { + case '*': + i--; + break; + default: + break trailLoop; + } + } + docCommentCount = i + 1; + + // Store the text of the doc comment + docComment = new String(docCommentBuffer, 0 , docCommentCount); + } else { + docComment = ""; + } + } + + /** Build a map for translating between line numbers and + * positions in the input. + * + * @return a LineMap */ + public Position.LineMap getLineMap() { + char[] buf = getRawCharacters(); + return Position.makeLineMap(buf, buf.length, true); + } +} diff --git a/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java b/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java index e361a5bd..e9575c14 100644 --- a/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java +++ b/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java @@ -30,8 +30,8 @@ public class CommentCollectingParserFactory extends ParserFactory { public Parser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap) { ScannerFactory scannerFactory = ScannerFactory.instance(context); - Lexer lexer = scannerFactory.newScanner(input, keepDocComments); - Object x = new CommentCollectingParser(this, lexer, keepDocComments, keepLineMap, commentsMap); + Lexer lexer = scannerFactory.newScanner(input, true); + Object x = new CommentCollectingParser(this, lexer, true, keepLineMap, commentsMap); return (Parser) x; // CCP is based on a stub which extends nothing, but at runtime the stub is replaced with either //javac6's EndPosParser which extends Parser, or javac7's EndPosParser which implements Parser. diff --git a/src/utils/lombok/javac/java7/CommentCollectingScanner.java b/src/utils/lombok/javac/java7/CommentCollectingScanner.java index e2d040f2..6ebd3ac1 100644 --- a/src/utils/lombok/javac/java7/CommentCollectingScanner.java +++ b/src/utils/lombok/javac/java7/CommentCollectingScanner.java @@ -26,12 +26,12 @@ import java.nio.CharBuffer; import lombok.javac.CommentInfo; import lombok.javac.CommentInfo.EndConnection; import lombok.javac.CommentInfo.StartConnection; + import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.parser.DocCommentScanner; -import com.sun.tools.javac.parser.Scanner; - -public class CommentCollectingScanner extends Scanner { +public class CommentCollectingScanner extends DocCommentScanner { private final ListBuffer comments = ListBuffer.lb(); private int endComment = 0; @@ -55,6 +55,7 @@ public class CommentCollectingScanner extends Scanner { CommentInfo comment = new CommentInfo(prevEndPos, pos, endPos, content, start, end); comments.append(comment); + super.processComment(style); } private EndConnection determineEndConnection(int pos) { -- cgit From 867929c79f344e2fa63aa280cf452d39eb7aabf7 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 8 Jul 2013 06:06:49 +0200 Subject: added tests for new javadoc behaviour, javac implementation of copying javadoc for getters/setters, and fixed pretty printer to no longer inject an extra newline at the top of javadoc. --- .../lombok/delombok/PrettyCommentsPrinter.java | 7 ++ .../after-delombok/CommentsInterspersed.java | 8 +- .../after-delombok/DelegateWithDeprecated.java | 4 +- .../resource/after-delombok/GetterDeprecated.java | 3 + .../after-delombok/GetterSetterJavadoc.java | 100 +++++++++++++++++++++ .../resource/after-delombok/JavadocGenerally.java | 24 +++++ .../resource/after-delombok/SetterDeprecated.java | 3 + .../resource/before/CommentsInterspersed.java | 8 +- .../resource/before/DelegateWithDeprecated.java | 4 +- .../resource/before/GetterSetterJavadoc.java | 37 ++++++++ .../resource/before/JavadocGenerally.java | 27 ++++++ 11 files changed, 219 insertions(+), 6 deletions(-) create mode 100644 test/transform/resource/after-delombok/GetterSetterJavadoc.java create mode 100644 test/transform/resource/after-delombok/JavadocGenerally.java create mode 100644 test/transform/resource/before/GetterSetterJavadoc.java create mode 100644 test/transform/resource/before/JavadocGenerally.java (limited to 'src/delombok/lombok') diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index 342e3323..1bb2ce23 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -530,7 +530,14 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { print("/**"); println(); int pos = 0; int endpos = lineEndPos(dc, pos); + boolean atStart = true; while (pos < dc.length()) { + String line = dc.substring(pos, endpos); + if (line.trim().isEmpty() && atStart) { + atStart = false; + continue; + } + atStart = false; align(); print(" *"); if (pos < dc.length() && dc.charAt(pos) > ' ') print(" "); diff --git a/test/transform/resource/after-delombok/CommentsInterspersed.java b/test/transform/resource/after-delombok/CommentsInterspersed.java index 5aaafe42..833f2ce0 100644 --- a/test/transform/resource/after-delombok/CommentsInterspersed.java +++ b/test/transform/resource/after-delombok/CommentsInterspersed.java @@ -1,9 +1,13 @@ /* cmt *//* cmt2 */ /* cmt3 */ /*bla */ public class CommentsInterspersed { - /** javadoc for field */ + /** + * javadoc for field + */ private int x; /* bla2 */ private String test = "foo"; //$NON-NLS-1$ - /** Javadoc on method */ + /** + * Javadoc on method + */ public native void gwtTest(); /*-{ javascript; }-*/ diff --git a/test/transform/resource/after-delombok/DelegateWithDeprecated.java b/test/transform/resource/after-delombok/DelegateWithDeprecated.java index 04e12160..f7bd1e6d 100644 --- a/test/transform/resource/after-delombok/DelegateWithDeprecated.java +++ b/test/transform/resource/after-delombok/DelegateWithDeprecated.java @@ -3,7 +3,9 @@ class DelegateWithDeprecated { private interface Bar { @Deprecated void deprecatedAnnotation(); - /** @deprecated */ + /** + * @deprecated + */ void deprecatedComment(); void notDeprecated(); } diff --git a/test/transform/resource/after-delombok/GetterDeprecated.java b/test/transform/resource/after-delombok/GetterDeprecated.java index 3387540f..09ea9929 100644 --- a/test/transform/resource/after-delombok/GetterDeprecated.java +++ b/test/transform/resource/after-delombok/GetterDeprecated.java @@ -10,6 +10,9 @@ class GetterDeprecated { public int getAnnotation() { return this.annotation; } + /** + * @deprecated + */ @java.lang.Deprecated @java.lang.SuppressWarnings("all") public int getJavadoc() { diff --git a/test/transform/resource/after-delombok/GetterSetterJavadoc.java b/test/transform/resource/after-delombok/GetterSetterJavadoc.java new file mode 100644 index 00000000..7bf92d1f --- /dev/null +++ b/test/transform/resource/after-delombok/GetterSetterJavadoc.java @@ -0,0 +1,100 @@ +class GetterSetterJavadoc1 { + /** + * Some text + */ + private int fieldName; + @java.lang.SuppressWarnings("all") + public GetterSetterJavadoc1() { + } + /** + * Getter section + * + * @return Sky is blue + */ + @java.lang.SuppressWarnings("all") + public int getFieldName() { + return this.fieldName; + } + /** + * Some text + * + * @param fieldName Hello, World + */ + @java.lang.SuppressWarnings("all") + public void setFieldName(final int fieldName) { + this.fieldName = fieldName; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof GetterSetterJavadoc1)) return false; + final GetterSetterJavadoc1 other = (GetterSetterJavadoc1)o; + if (!other.canEqual((java.lang.Object)this)) return false; + if (this.getFieldName() != other.getFieldName()) return false; + return true; + } + @java.lang.SuppressWarnings("all") + public boolean canEqual(final java.lang.Object other) { + return other instanceof GetterSetterJavadoc1; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = result * PRIME + this.getFieldName(); + return result; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "GetterSetterJavadoc1(fieldName=" + this.getFieldName() + ")"; + } +} +class GetterSetterJavadoc2 { + /** + * Some text + */ + private int fieldName; + /** + * Some text + * + * @return Sky is blue + */ + @java.lang.SuppressWarnings("all") + public int getFieldName() { + return this.fieldName; + } + /** + * Some text + * + * @param fieldName Hello, World + */ + @java.lang.SuppressWarnings("all") + public void setFieldName(final int fieldName) { + this.fieldName = fieldName; + } +} +class GetterSetterJavadoc3 { + /** + * Some text + */ + private int fieldName; + /** + * Getter section + * @return Sky is blue + */ + @java.lang.SuppressWarnings("all") + public int getFieldName() { + return this.fieldName; + } + /** + * Setter section + * @param fieldName Hello, World + */ + @java.lang.SuppressWarnings("all") + public void setFieldName(final int fieldName) { + this.fieldName = fieldName; + } +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/JavadocGenerally.java b/test/transform/resource/after-delombok/JavadocGenerally.java new file mode 100644 index 00000000..729cdce3 --- /dev/null +++ b/test/transform/resource/after-delombok/JavadocGenerally.java @@ -0,0 +1,24 @@ +/** + * Doc on package + */ +package testPackage; +/** Weird doc */ +/** + * Doc on class + */ +class JavadocGenerally { + /** + * Doc on field + */ + private int someField; + /** + * Doc on method + */ + public void test() { + } + /** + * Doc on inner + */ + public interface TestingInner { + } +} diff --git a/test/transform/resource/after-delombok/SetterDeprecated.java b/test/transform/resource/after-delombok/SetterDeprecated.java index 5a6cf9f3..72a609ad 100644 --- a/test/transform/resource/after-delombok/SetterDeprecated.java +++ b/test/transform/resource/after-delombok/SetterDeprecated.java @@ -10,6 +10,9 @@ class SetterDeprecated { public void setAnnotation(final int annotation) { this.annotation = annotation; } + /** + * @deprecated + */ @java.lang.Deprecated @java.lang.SuppressWarnings("all") public void setJavadoc(final int javadoc) { diff --git a/test/transform/resource/before/CommentsInterspersed.java b/test/transform/resource/before/CommentsInterspersed.java index e7898aaa..23a1060b 100644 --- a/test/transform/resource/before/CommentsInterspersed.java +++ b/test/transform/resource/before/CommentsInterspersed.java @@ -1,12 +1,16 @@ import /* cmt */ lombok./* cmt2 */Getter /* cmt3 */ ; public /*bla */ class CommentsInterspersed { - /** javadoc for field */ + /** + * javadoc for field + */ private int x; private /* bla2 */ @Getter String test = "foo"; //$NON-NLS-1$ - /** Javadoc on method */ + /** + * Javadoc on method + */ public native void gwtTest(); /*-{ javascript; }-*/ diff --git a/test/transform/resource/before/DelegateWithDeprecated.java b/test/transform/resource/before/DelegateWithDeprecated.java index b748c6ec..064e951d 100644 --- a/test/transform/resource/before/DelegateWithDeprecated.java +++ b/test/transform/resource/before/DelegateWithDeprecated.java @@ -6,7 +6,9 @@ class DelegateWithDeprecated { private interface Bar { @Deprecated void deprecatedAnnotation(); - /** @deprecated */ + /** + * @deprecated + */ void deprecatedComment(); void notDeprecated(); } diff --git a/test/transform/resource/before/GetterSetterJavadoc.java b/test/transform/resource/before/GetterSetterJavadoc.java new file mode 100644 index 00000000..e3ae0aac --- /dev/null +++ b/test/transform/resource/before/GetterSetterJavadoc.java @@ -0,0 +1,37 @@ +@lombok.Data +class GetterSetterJavadoc1 { + /** + * Some text + * + * @param fieldName Hello, World + * --- GETTER --- + * Getter section + * + * @return Sky is blue + */ + private int fieldName; +} + +class GetterSetterJavadoc2 { + /** + * Some text + * + * @param fieldName Hello, World + * @return Sky is blue + */ + @lombok.Getter @lombok.Setter private int fieldName; +} + +class GetterSetterJavadoc3 { + /** + * Some text + * + * **SETTER** + * Setter section + * @param fieldName Hello, World + * **GETTER** + * Getter section + * @return Sky is blue + */ + @lombok.Getter @lombok.Setter private int fieldName; +} diff --git a/test/transform/resource/before/JavadocGenerally.java b/test/transform/resource/before/JavadocGenerally.java new file mode 100644 index 00000000..ee015acf --- /dev/null +++ b/test/transform/resource/before/JavadocGenerally.java @@ -0,0 +1,27 @@ +/** + * Doc on package + */ +package testPackage; + +/** Weird doc */ +/** + * Doc on class + */ +class JavadocGenerally { + /** + * Doc on field + */ + private int someField; + + /** + * Doc on method + */ + public void test() { + } + + /** + * Doc on inner + */ + public interface TestingInner { + } +} -- cgit