diff options
-rw-r--r-- | doc/changelog.markdown | 1 | ||||
-rw-r--r-- | src/core/lombok/core/CleanupRegistry.java | 64 | ||||
-rw-r--r-- | src/core/lombok/core/CleanupTask.java | 26 | ||||
-rw-r--r-- | src/core/lombok/javac/JavacAST.java | 12 | ||||
-rw-r--r-- | src/core/lombok/javac/JavacTransformer.java | 7 | ||||
-rw-r--r-- | src/core/lombok/javac/apt/LombokProcessor.java | 11 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/JavacHandlerUtil.java | 172 | ||||
-rw-r--r-- | src/utils/lombok/javac/Javac.java | 75 | ||||
-rw-r--r-- | test/transform/resource/after-delombok/SetterWitherJavadocParamCopy.java | 28 | ||||
-rw-r--r-- | test/transform/resource/after-ecj/SetterWitherJavadocParamCopy.java | 13 | ||||
-rw-r--r-- | test/transform/resource/before/SetterWitherJavadocParamCopy.java | 16 |
11 files changed, 311 insertions, 114 deletions
diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 00faa993..90a70ca7 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -3,6 +3,7 @@ Lombok Changelog ### v1.18.5 "Edgy Guinea Pig" * BUGFIX: Since version 1.18.4, the delombok ant task didn't work and errored with a `NoClassDefFoundError`. [Issue #1932](https://github.com/rzwitserloot/lombok/issues/1932) +* BUGFIX: Combining both `@Setter` and `@Wither` on the same field, when that field also has javadoc with a `--setter--` section or an `@param` tag, resulted in a race condition where the first handler to get to the field would take that part of the javadoc. This is a step along the way to fixing [Issue #1033](https://github.com/rzwitserloot/lombok/issues/1033) * FEATURE: The `@FieldNameConstants` feature now allows you to write the inner type by hand and add whatever you like to it; lombok will add the constants to this class. See the updated [FieldNameConstants feature](https://projectlombok.org/features/experimental/FieldNameConstants) page. * FEATURE: There is now a `lombok.config` key to configure `@ToString`'s call super behavior; it's just like `@EqualsAndHashCode` which has had it for a while now. [Issue #1918](https://github.com/rzwitserloot/lombok/issues/1918) * ENHANCEMENT: The toString generation of enums now contains the name of the enum constant. [Issue #1916](https://github.com/rzwitserloot/lombok/issues/1916) diff --git a/src/core/lombok/core/CleanupRegistry.java b/src/core/lombok/core/CleanupRegistry.java new file mode 100644 index 00000000..82a52fdb --- /dev/null +++ b/src/core/lombok/core/CleanupRegistry.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 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.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class CleanupRegistry { + private static final class CleanupKey { + private final String key; + private final Object target; + + CleanupKey(String key, Object target) { + this.key = key; + this.target = target; + } + + @Override public boolean equals(Object other) { + if (other == null) return false; + if (other == this) return true; + if (!(other instanceof CleanupKey)) return false; + CleanupKey o = (CleanupKey) other; + if (!key.equals(o.key)) return false; + return target == o.target; + } + + @Override public int hashCode() { + return 109 * System.identityHashCode(target) + key.hashCode(); + } + } + + private final Map<CleanupKey, CleanupTask> tasks = new ConcurrentHashMap<CleanupKey, CleanupTask>(); + + public void registerTask(String key, Object target, CleanupTask task) { + CleanupKey ck = new CleanupKey(key, target); + tasks.putIfAbsent(ck, task); + } + + public void run() { + for (CleanupTask task : tasks.values()) { + task.cleanup(); + } + tasks.clear(); + } +} diff --git a/src/core/lombok/core/CleanupTask.java b/src/core/lombok/core/CleanupTask.java new file mode 100644 index 00000000..4bc4db96 --- /dev/null +++ b/src/core/lombok/core/CleanupTask.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019 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; + +public interface CleanupTask { + void cleanup(); +} diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index 9a5305a6..f2901038 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2019 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 @@ -37,6 +37,8 @@ import javax.tools.JavaFileObject; import com.sun.tools.javac.util.JCDiagnostic; import lombok.core.AST; +import lombok.core.CleanupRegistry; +import lombok.core.CleanupTask; import lombok.permit.Permit; import com.sun.tools.javac.code.Source; @@ -65,6 +67,7 @@ import com.sun.tools.javac.util.Name; * something javac's own AST system does not offer. */ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { + private final CleanupRegistry cleanup; private final JavacElements elements; private final JavacTreeMaker treeMaker; private final Symtab symtab; @@ -80,7 +83,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { * @param context A Context object for interfacing with the compiler. * @param top The compilation unit, which serves as the top level node in the tree to be built. */ - public JavacAST(Messager messager, Context context, JCCompilationUnit top) { + public JavacAST(Messager messager, Context context, JCCompilationUnit top, CleanupRegistry cleanup) { super(sourceName(top), PackageName.getPackageName(top), new JavacImportList(top), statementTypes()); setTop(buildCompilationUnit(top)); this.context = context; @@ -90,6 +93,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { this.treeMaker = new JavacTreeMaker(TreeMaker.instance(context)); this.symtab = Symtab.instance(context); this.javacTypes = JavacTypes.instance(context); + this.cleanup = cleanup; clearChanged(); } @@ -140,6 +144,10 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { return Javac.getJavaCompilerVersion(); } + public void cleanupTask(String key, JCTree target, CleanupTask task) { + cleanup.registerTask(key, target, task); + } + /** @return A Name object generated for the proper name table belonging to this AST. */ public Name toName(String name) { return elements.getName(name); diff --git a/src/core/lombok/javac/JavacTransformer.java b/src/core/lombok/javac/JavacTransformer.java index 2e37b32b..0a4f1f73 100644 --- a/src/core/lombok/javac/JavacTransformer.java +++ b/src/core/lombok/javac/JavacTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2019 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 @@ -36,6 +36,7 @@ import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import lombok.ConfigurationKeys; +import lombok.core.CleanupRegistry; import lombok.core.LombokConfiguration; public class JavacTransformer { @@ -55,7 +56,7 @@ public class JavacTransformer { return handlers.getPrioritiesRequiringResolutionReset(); } - public void transform(long priority, Context context, java.util.List<JCCompilationUnit> compilationUnitsRaw) { + public void transform(long priority, Context context, java.util.List<JCCompilationUnit> compilationUnitsRaw, CleanupRegistry cleanup) { List<JCCompilationUnit> compilationUnits; if (compilationUnitsRaw instanceof List<?>) { compilationUnits = (List<JCCompilationUnit>) compilationUnitsRaw; @@ -70,7 +71,7 @@ public class JavacTransformer { for (JCCompilationUnit unit : compilationUnits) { if (!Boolean.TRUE.equals(LombokConfiguration.read(ConfigurationKeys.LOMBOK_DISABLE, JavacAST.getAbsoluteFileLocation(unit)))) { - asts.add(new JavacAST(messager, context, unit)); + asts.add(new JavacAST(messager, context, unit, cleanup)); } } diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index a3d1dfcf..d4f3504a 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2019 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 @@ -50,6 +50,7 @@ import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import lombok.Lombok; +import lombok.core.CleanupRegistry; import lombok.core.DiagnosticsReceiver; import lombok.javac.JavacTransformer; import lombok.permit.Permit; @@ -288,11 +289,15 @@ public class LombokProcessor extends AbstractProcessor { private final IdentityHashMap<JCCompilationUnit, Long> roots = new IdentityHashMap<JCCompilationUnit, Long>(); private long[] priorityLevels; private Set<Long> priorityLevelsRequiringResolutionReset; + private CleanupRegistry cleanup = new CleanupRegistry(); /** {@inheritDoc} */ @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (lombokDisabled) return false; - if (roundEnv.processingOver()) return false; + if (roundEnv.processingOver()) { + cleanup.run(); + return false; + } // We have: A sorted set of all priority levels: 'priorityLevels' @@ -318,7 +323,7 @@ public class LombokProcessor extends AbstractProcessor { if (prioOfCu == null || prioOfCu != prio) continue; cusForThisRound.add(entry.getKey()); } - transformer.transform(prio, javacProcessingEnv.getContext(), cusForThisRound); + transformer.transform(prio, javacProcessingEnv.getContext(), cusForThisRound, cleanup); } // Step 3: Push up all CUs to the next level. Set level to null if there is no next level. diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index d7fae8e6..5fd17388 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2019 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 @@ -48,6 +48,7 @@ import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.LombokImmutableList; import lombok.core.AnnotationValues.AnnotationValue; +import lombok.core.CleanupTask; import lombok.core.TypeResolver; import lombok.core.configuration.NullCheckExceptionType; import lombok.core.configuration.TypeName; @@ -70,8 +71,6 @@ import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Type.MethodType; -import com.sun.tools.javac.parser.Tokens.Comment; -import com.sun.tools.javac.tree.DocCommentTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; @@ -277,7 +276,7 @@ public class JavacHandlerUtil { */ public static boolean annotationTypeMatches(String type, JavacNode node) { if (node.getKind() != Kind.ANNOTATION) return false; - return typeMatches(type, node, ((JCAnnotation)node.get()).annotationType); + return typeMatches(type, node, ((JCAnnotation) node.get()).annotationType); } /** @@ -1165,7 +1164,7 @@ public class JavacHandlerUtil { JavacNode tossMe = typeNode.getNodeFor(def); if (tossMe != null) tossMe.up().removeChild(tossMe); type.defs = addAllButOne(type.defs, idx); - ClassSymbolMembersField.remove(type.sym, ((JCMethodDecl)def).sym); + ClassSymbolMembersField.remove(type.sym, ((JCMethodDecl) def).sym); break; } } @@ -1812,72 +1811,90 @@ public class JavacHandlerUtil { return javadoc.substring(0, m.start()); } - public static String[] splitJavadocOnSectionIfPresent(String javadoc, String sectionName) { + public static String getJavadocSection(String javadoc, String sectionName) { Matcher m = SECTION_FINDER.matcher(javadoc); - int getterSectionHeaderStart = -1; - int getterSectionStart = -1; - int getterSectionEnd = -1; + int sectionStart = -1; + int sectionEnd = -1; while (m.find()) { if (m.group(1).equalsIgnoreCase(sectionName)) { - getterSectionStart = m.end() + 1; - getterSectionHeaderStart = m.start(); - } else if (getterSectionStart != -1) { - getterSectionEnd = m.start(); + sectionStart = m.end() + 1; + } else if (sectionStart != -1) { + sectionEnd = m.start(); } } - if (getterSectionStart != -1) { - if (getterSectionEnd != -1) { - return new String[] {javadoc.substring(getterSectionStart, getterSectionEnd), javadoc.substring(0, getterSectionHeaderStart) + javadoc.substring(getterSectionEnd)}; - } else { - return new String[] {javadoc.substring(getterSectionStart), javadoc.substring(0, getterSectionHeaderStart)}; - } + if (sectionStart != -1) { + if (sectionEnd != -1) return javadoc.substring(sectionStart, sectionEnd); + return javadoc.substring(sectionStart); } return null; } public static enum CopyJavadoc { - VERBATIM, + VERBATIM { + @Override public String apply(final JCCompilationUnit cu, final JavacNode node) { + return Javac.getDocComment(cu, node.get()); + } + }, GETTER { - @Override public String[] split(String javadoc) { - // step 1: Check if there is a 'GETTER' section. If yes, that becomes the new method's javadoc and we strip that from the original. - String[] out = splitJavadocOnSectionIfPresent(javadoc, "GETTER"); - if (out != null) return out; - // failing that, create a copy, but strip @return from the original and @param from the copy, as well as other sections. - String copy = javadoc; - javadoc = stripLinesWithTagFromJavadoc(javadoc, "@returns?\\s+.*"); - copy = stripLinesWithTagFromJavadoc(copy, "@param(?:eter)?\\s+.*"); - copy = stripSectionsFromJavadoc(copy); - return new String[] {copy, javadoc}; + @Override public String apply(final JCCompilationUnit cu, final JavacNode node) { + final JCTree n = node.get(); + String javadoc = Javac.getDocComment(cu, n); + // step 1: Check if there is a 'GETTER' section. If yes, that becomes the new method's javadoc. + String out = getJavadocSection(javadoc, "GETTER"); + final boolean sectionBased = out != null; + if (!sectionBased) { + out = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), "@param(?:eter)?\\s+.*"); + } + node.getAst().cleanupTask("javadocfilter-getter", n, new CleanupTask() { + @Override public void cleanup() { + String javadoc = Javac.getDocComment(cu, n); + if (javadoc == null || javadoc.isEmpty()) return; + javadoc = stripSectionsFromJavadoc(javadoc); + if (!sectionBased) { + javadoc = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), "@returns?\\s+.*"); + } + Javac.setDocComment(cu, n, javadoc); + } + }); + return out; } }, SETTER { - @Override public String[] split(String javadoc) { - return splitForSetters(javadoc, "SETTER"); + @Override public String apply(final JCCompilationUnit cu, final JavacNode node) { + return applySetter(cu, node, "SETTER"); } }, WITHER { - @Override public String[] split(String javadoc) { - return splitForSetters(javadoc, "WITHER"); + @Override public String apply(final JCCompilationUnit cu, final JavacNode node) { + return applySetter(cu, node, "WITHER"); } }; - private static String[] splitForSetters(String javadoc, String sectionName) { - // step 1: Check if there is a 'SETTER' section. If yes, that becomes the new one and we strip that from the original. - String[] out = splitJavadocOnSectionIfPresent(javadoc, sectionName); - if (out != null) return out; - // failing that, create a copy, but strip @param from the original and @return from the copy. - String copy = javadoc; - javadoc = stripLinesWithTagFromJavadoc(javadoc, "@param(?:eter)?\\s+.*"); - copy = stripLinesWithTagFromJavadoc(copy, "@returns?\\s+.*"); - copy = stripSectionsFromJavadoc(copy); - return new String[] {copy, javadoc}; - } + public abstract String apply(final JCCompilationUnit cu, final JavacNode node); - /** Splits the javadoc into the section to be copied (ret[0]) and the section to replace the original with (ret[1]) */ - public String[] split(String javadoc) { - return new String[] {javadoc, javadoc}; + private static String applySetter(final JCCompilationUnit cu, JavacNode node, String sectionName) { + final JCTree n = node.get(); + String javadoc = Javac.getDocComment(cu, n); + // step 1: Check if there is a 'SETTER' section. If yes, that becomes the new method's javadoc. + String out = getJavadocSection(javadoc, sectionName); + final boolean sectionBased = out != null; + if (!sectionBased) { + out = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), "@returns?\\s+.*"); + } + node.getAst().cleanupTask("javadocfilter-setter", n, new CleanupTask() { + @Override public void cleanup() { + String javadoc = Javac.getDocComment(cu, n); + if (javadoc == null || javadoc.isEmpty()) return; + javadoc = stripSectionsFromJavadoc(javadoc); + if (!sectionBased) { + javadoc = stripLinesWithTagFromJavadoc(stripSectionsFromJavadoc(javadoc), "@param(?:eter)?\\s+.*"); + } + Javac.setDocComment(cu, n, javadoc); + } + }); + return shouldReturnThis(node) ? addReturnsThisIfNeeded(out) : out; } } @@ -1894,12 +1911,8 @@ public class JavacHandlerUtil { if (copyMode == null) copyMode = CopyJavadoc.VERBATIM; try { JCCompilationUnit cu = ((JCCompilationUnit) from.top().get()); - Object dc = Javac.getDocComments(cu); - if (dc instanceof Map) { - copyJavadoc_jdk6_7(from, to, copyMode, dc); - } else if (Javac.instanceOfDocCommentTable(dc)) { - CopyJavadoc_8.copyJavadoc(from, to, copyMode, dc); - } + String newJavadoc = copyMode.apply(cu, from); + if (newJavadoc != null) Javac.setDocComment(cu, to, newJavadoc); } catch (Exception ignore) {} } @@ -1915,57 +1928,6 @@ public class JavacHandlerUtil { return in + "\n" + line; } - private static class CopyJavadoc_8 { - static void copyJavadoc(JavacNode from, JCTree to, CopyJavadoc copyMode, Object dc) { - DocCommentTable dct = (DocCommentTable) dc; - Comment javadoc = dct.getComment(from.get()); - - if (javadoc != null) { - String[] filtered = copyMode.split(javadoc.getText()); - if (copyMode == CopyJavadoc.SETTER && shouldReturnThis(from)) { - filtered[0] = addReturnsThisIfNeeded(filtered[0]); - } - dct.putComment(to, createJavadocComment(filtered[0], from)); - dct.putComment(from.get(), createJavadocComment(filtered[1], from)); - } - } - - private static Comment createJavadocComment(final String text, final JavacNode field) { - return new Comment() { - @Override public String getText() { - return text; - } - - @Override public int getSourcePos(int index) { - return -1; - } - - @Override public CommentStyle getStyle() { - return CommentStyle.JAVADOC; - } - - @Override public boolean isDeprecated() { - return text.contains("@deprecated") && field.getKind() == Kind.FIELD && isFieldDeprecated(field); - } - }; - } - } - - @SuppressWarnings({"unchecked", "all"}) - private static void copyJavadoc_jdk6_7(JavacNode from, JCTree to, CopyJavadoc copyMode, Object dc) { - Map<JCTree, String> docComments = (Map<JCTree, String>) dc; - String javadoc = docComments.get(from.get()); - - if (javadoc != null) { - String[] filtered = copyMode.split(javadoc); - if (copyMode == CopyJavadoc.SETTER && shouldReturnThis(from)) { - filtered[0] = addReturnsThisIfNeeded(filtered[0]); - } - docComments.put(to, filtered[0]); - docComments.put(from.get(), filtered[1]); - } - } - public static boolean isDirectDescendantOfObject(JavacNode typeNode) { if (!(typeNode.get() instanceof JCClassDecl)) throw new IllegalArgumentException("not a type node"); JCTree extending = Javac.getExtendsClause((JCClassDecl) typeNode.get()); diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index a2cb32c6..7a264e39 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2019 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 @@ -28,6 +28,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -42,17 +43,22 @@ import lombok.javac.JavacTreeMaker.TreeTag; import lombok.javac.JavacTreeMaker.TypeTag; import lombok.permit.Permit; +import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.main.JavaCompiler; +import com.sun.tools.javac.parser.Tokens.Comment; +import com.sun.tools.javac.tree.DocCommentTable; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCLiteral; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; /** @@ -269,6 +275,73 @@ public class Javac { } } + public static String getDocComment(JCCompilationUnit cu, JCTree node) { + Object dc = getDocComments(cu); + if (dc instanceof Map) return (String) ((Map<?, ?>) dc).get(node); + if (instanceOfDocCommentTable(dc)) return JavadocOps_8.getJavadoc(dc, node); + return null; + } + + @SuppressWarnings("unchecked") + public static void setDocComment(JCCompilationUnit cu, JCTree node, String javadoc) { + Object dc = getDocComments(cu); + if (dc instanceof Map) { + ((Map<JCTree, String>) dc).put(node, javadoc); + return; + } + + if (instanceOfDocCommentTable(dc)) { + JavadocOps_8.setJavadoc(dc, node, javadoc); + return; + } + } + + private static class JavadocOps_8 { + static String getJavadoc(Object dc, JCTree node) { + DocCommentTable dct = (DocCommentTable) dc; + Comment javadoc = dct.getComment(node); + if (javadoc == null) return null; + return javadoc.getText(); + } + + static void setJavadoc(Object dc, JCTree node, String javadoc) { + DocCommentTable dct = (DocCommentTable) dc; + Comment newCmt = createJavadocComment(javadoc, node); + dct.putComment(node, newCmt); + } + + private static Comment createJavadocComment(final String text, final JCTree field) { + return new Comment() { + @Override public String getText() { + return text; + } + + @Override public int getSourcePos(int index) { + return -1; + } + + @Override public CommentStyle getStyle() { + return CommentStyle.JAVADOC; + } + + @Override public boolean isDeprecated() { + return text.contains("@deprecated") && field instanceof JCVariableDecl && isFieldDeprecated(field); + } + }; + } + } + + public static boolean isFieldDeprecated(JCTree field) { + if (!(field instanceof JCVariableDecl)) return false; + JCVariableDecl fieldNode = (JCVariableDecl) field; + if ((fieldNode.mods.flags & Flags.DEPRECATED) != 0) return true; + if (fieldNode.mods.annotations != null) for (JCAnnotation ann : fieldNode.mods.annotations) { + String at = ann.getAnnotationType().toString(); + return at.equals("Deprecated") || at.endsWith(".Deprecated"); + } + return false; + } + public static void initDocComments(JCCompilationUnit cu) { try { JCCOMPILATIONUNIT_DOCCOMMENTS.set(cu, new HashMap<Object, String>()); diff --git a/test/transform/resource/after-delombok/SetterWitherJavadocParamCopy.java b/test/transform/resource/after-delombok/SetterWitherJavadocParamCopy.java new file mode 100644 index 00000000..e6f5ab75 --- /dev/null +++ b/test/transform/resource/after-delombok/SetterWitherJavadocParamCopy.java @@ -0,0 +1,28 @@ +class SetterWitherJavadocParamCopy { + /** + * Some text + */ + private int fieldName; + + public SetterWitherJavadocParamCopy(int f) { + this.fieldName = f; + } + /** + * Some text + * + * @param fieldName Hello, World1 + */ + @java.lang.SuppressWarnings("all") + public void setFieldName(final int fieldName) { + this.fieldName = fieldName; + } + /** + * Some text + * + * @param fieldName Hello, World1 + */ + @java.lang.SuppressWarnings("all") + public SetterWitherJavadocParamCopy withFieldName(final int fieldName) { + return this.fieldName == fieldName ? this : new SetterWitherJavadocParamCopy(fieldName); + } +}
\ No newline at end of file diff --git a/test/transform/resource/after-ecj/SetterWitherJavadocParamCopy.java b/test/transform/resource/after-ecj/SetterWitherJavadocParamCopy.java new file mode 100644 index 00000000..741342f7 --- /dev/null +++ b/test/transform/resource/after-ecj/SetterWitherJavadocParamCopy.java @@ -0,0 +1,13 @@ +class SetterWitherJavadocParamCopy { + private @lombok.Setter @lombok.experimental.Wither int fieldName; + public SetterWitherJavadocParamCopy(int f) { + super(); + this.fieldName = f; + } + public @java.lang.SuppressWarnings("all") void setFieldName(final int fieldName) { + this.fieldName = fieldName; + } + public @java.lang.SuppressWarnings("all") SetterWitherJavadocParamCopy withFieldName(final int fieldName) { + return ((this.fieldName == fieldName) ? this : new SetterWitherJavadocParamCopy(fieldName)); + } +} diff --git a/test/transform/resource/before/SetterWitherJavadocParamCopy.java b/test/transform/resource/before/SetterWitherJavadocParamCopy.java new file mode 100644 index 00000000..4de091e2 --- /dev/null +++ b/test/transform/resource/before/SetterWitherJavadocParamCopy.java @@ -0,0 +1,16 @@ +class SetterWitherJavadocParamCopy { + /** + * Some text + * + * @param fieldName Hello, World1 + * --- GETTER --- + * Getter section + * + * @return Sky is blue1 + */ + @lombok.Setter @lombok.experimental.Wither private int fieldName; + + public SetterWitherJavadocParamCopy(int f) { + this.fieldName = f; + } +} |