diff --git a/src/delombok/lombok/delombok/DocCommentIntegrator.java b/src/delombok/lombok/delombok/DocCommentIntegrator.java index 945f4fa4d6..f74ea249c5 100644 --- a/src/delombok/lombok/delombok/DocCommentIntegrator.java +++ b/src/delombok/lombok/delombok/DocCommentIntegrator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2024 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 @@ -22,16 +22,13 @@ package lombok.delombok; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.NavigableMap; +import java.util.TreeMap; import java.util.regex.Pattern; -import lombok.javac.CommentInfo; -import lombok.javac.Javac; -import lombok.javac.PackageName; -import lombok.javac.handlers.JavacHandlerUtil; - import com.sun.tools.javac.parser.Tokens.Comment; import com.sun.tools.javac.tree.DocCommentTable; import com.sun.tools.javac.tree.JCTree; @@ -39,6 +36,11 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.TreeScanner; + +import lombok.javac.CommentInfo; +import lombok.javac.Javac; +import lombok.javac.handlers.JavacHandlerUtil; public class DocCommentIntegrator { /** @@ -49,18 +51,21 @@ public List integrate(List comments, JCCompilationUnit CommentInfo lastExcisedComment = null; JCTree lastNode = null; + NavigableMap positionMap = buildNodePositionMap(unit); + for (CommentInfo cmt : comments) { if (!cmt.isJavadoc()) { out.add(cmt); continue; } - JCTree node = findJavadocableNodeOnOrAfter(unit, cmt.endPos); - if (node == null) { + Entry entry = positionMap.ceilingEntry(cmt.endPos); + if (entry == null) { out.add(cmt); continue; } + JCTree node = entry.getValue(); if (node == lastNode) { out.add(lastExcisedComment); } @@ -73,6 +78,28 @@ public List integrate(List comments, JCCompilationUnit } return out; } + + private NavigableMap buildNodePositionMap(JCCompilationUnit unit) { + final NavigableMap positionMap = new TreeMap(); + unit.accept(new TreeScanner() { + @Override + public void visitClassDef(JCClassDecl tree) { + positionMap.put(tree.pos, tree); + super.visitClassDef(tree); + } + @Override + public void visitMethodDef(JCMethodDecl tree) { + positionMap.put(tree.pos, tree); + super.visitMethodDef(tree); + } + @Override + public void visitVarDef(JCVariableDecl tree) { + positionMap.put(tree.pos, tree); + super.visitVarDef(tree); + } + }); + return positionMap; + } private static final Pattern CONTENT_STRIPPER = Pattern.compile("^(?:\\s*\\*)?(.*?)$", Pattern.MULTILINE); @SuppressWarnings("unchecked") private boolean attach(JCCompilationUnit top, final JCTree node, CommentInfo cmt) { @@ -119,32 +146,4 @@ static void attach(final JCTree node, String docCommentContent, final int pos, O }); } } - - private JCTree findJavadocableNodeOnOrAfter(JCCompilationUnit unit, int endPos) { - JCTree pid = PackageName.getPackageNode(unit); - if (pid != null && endPos <= pid.pos) return null; - Iterator it = unit.defs.iterator(); - - while (it.hasNext()) { - JCTree node = it.next(); - if (node.pos < endPos) { - if (node instanceof JCClassDecl) { - com.sun.tools.javac.util.List defs = ((JCClassDecl) node).defs; - if (!defs.isEmpty()) while (!defs.tail.isEmpty()) defs = defs.tail; - if (defs.head != null && defs.head.pos >= endPos) { - // The associated node is IN this class declaration, so, replace the iterator. - // There's no point looking beyond this member in the current iteration 'context' - // so we don't need to save the old ref. Just start over inside this type declaration. - it = ((JCClassDecl) node).defs.iterator(); - } - } - continue; - } - - if (node instanceof JCMethodDecl || node instanceof JCClassDecl || node instanceof JCVariableDecl) return node; - return null; - } - - return null; - } } diff --git a/test/transform/resource/after-delombok/BuilderNestedJavadoc.java b/test/transform/resource/after-delombok/BuilderNestedJavadoc.java new file mode 100644 index 0000000000..eb45e87f0a --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderNestedJavadoc.java @@ -0,0 +1,78 @@ +public class BuilderNestedJavadoc { + public static class NestedClass { + /** + * Example javadoc + */ + String name; + @java.lang.SuppressWarnings("all") + @lombok.Generated + NestedClass(final String name) { + this.name = name; + } + @java.lang.SuppressWarnings("all") + @lombok.Generated + public static class NestedClassBuilder { + @java.lang.SuppressWarnings("all") + @lombok.Generated + private String name; + @java.lang.SuppressWarnings("all") + @lombok.Generated + NestedClassBuilder() { + } + /** + * Example javadoc + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + @lombok.Generated + public BuilderNestedJavadoc.NestedClass.NestedClassBuilder name(final String name) { + this.name = name; + return this; + } + @java.lang.SuppressWarnings("all") + @lombok.Generated + public BuilderNestedJavadoc.NestedClass build() { + return new BuilderNestedJavadoc.NestedClass(this.name); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + @lombok.Generated + public java.lang.String toString() { + return "BuilderNestedJavadoc.NestedClass.NestedClassBuilder(name=" + this.name + ")"; + } + } + @java.lang.SuppressWarnings("all") + @lombok.Generated + public static BuilderNestedJavadoc.NestedClass.NestedClassBuilder builder() { + return new BuilderNestedJavadoc.NestedClass.NestedClassBuilder(); + } + } + @java.lang.SuppressWarnings("all") + @lombok.Generated + BuilderNestedJavadoc() { + } + @java.lang.SuppressWarnings("all") + @lombok.Generated + public static class BuilderNestedJavadocBuilder { + @java.lang.SuppressWarnings("all") + @lombok.Generated + BuilderNestedJavadocBuilder() { + } + @java.lang.SuppressWarnings("all") + @lombok.Generated + public BuilderNestedJavadoc build() { + return new BuilderNestedJavadoc(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + @lombok.Generated + public java.lang.String toString() { + return "BuilderNestedJavadoc.BuilderNestedJavadocBuilder()"; + } + } + @java.lang.SuppressWarnings("all") + @lombok.Generated + public static BuilderNestedJavadoc.BuilderNestedJavadocBuilder builder() { + return new BuilderNestedJavadoc.BuilderNestedJavadocBuilder(); + } +} diff --git a/test/transform/resource/after-ecj/BuilderNestedJavadoc.java b/test/transform/resource/after-ecj/BuilderNestedJavadoc.java new file mode 100644 index 0000000000..a9d67fde54 --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderNestedJavadoc.java @@ -0,0 +1,49 @@ +public @lombok.Builder class BuilderNestedJavadoc { + public static @lombok.Builder class NestedClass { + public static @java.lang.SuppressWarnings("all") @lombok.Generated class NestedClassBuilder { + private @java.lang.SuppressWarnings("all") @lombok.Generated String name; + @java.lang.SuppressWarnings("all") @lombok.Generated NestedClassBuilder() { + super(); + } + /** + * Example javadoc + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") @lombok.Generated BuilderNestedJavadoc.NestedClass.NestedClassBuilder name(final String name) { + this.name = name; + return this; + } + public @java.lang.SuppressWarnings("all") @lombok.Generated BuilderNestedJavadoc.NestedClass build() { + return new BuilderNestedJavadoc.NestedClass(this.name); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") @lombok.Generated java.lang.String toString() { + return (("BuilderNestedJavadoc.NestedClass.NestedClassBuilder(name=" + this.name) + ")"); + } + } + String name; + @java.lang.SuppressWarnings("all") @lombok.Generated NestedClass(final String name) { + super(); + this.name = name; + } + public static @java.lang.SuppressWarnings("all") @lombok.Generated BuilderNestedJavadoc.NestedClass.NestedClassBuilder builder() { + return new BuilderNestedJavadoc.NestedClass.NestedClassBuilder(); + } + } + public static @java.lang.SuppressWarnings("all") @lombok.Generated class BuilderNestedJavadocBuilder { + @java.lang.SuppressWarnings("all") @lombok.Generated BuilderNestedJavadocBuilder() { + super(); + } + public @java.lang.SuppressWarnings("all") @lombok.Generated BuilderNestedJavadoc build() { + return new BuilderNestedJavadoc(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") @lombok.Generated java.lang.String toString() { + return "BuilderNestedJavadoc.BuilderNestedJavadocBuilder()"; + } + } + @java.lang.SuppressWarnings("all") @lombok.Generated BuilderNestedJavadoc() { + super(); + } + public static @java.lang.SuppressWarnings("all") @lombok.Generated BuilderNestedJavadoc.BuilderNestedJavadocBuilder builder() { + return new BuilderNestedJavadoc.BuilderNestedJavadocBuilder(); + } +} diff --git a/test/transform/resource/before/BuilderNestedJavadoc.java b/test/transform/resource/before/BuilderNestedJavadoc.java new file mode 100644 index 0000000000..92e1277c26 --- /dev/null +++ b/test/transform/resource/before/BuilderNestedJavadoc.java @@ -0,0 +1,10 @@ +@lombok.Builder +public class BuilderNestedJavadoc { + @lombok.Builder + public static class NestedClass { + /** + * Example javadoc + */ + String name; + } +}