You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2020/05/11 10:48:51 UTC

[groovy] 01/03: GROOVY-9546: groovydoc: fix annotation rendering (closes #1243)

This is an automated email from the ASF dual-hosted git repository.

paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 302bf2bf27b28fe6ffc86171b408698490229c17
Author: Mikko Värri <vm...@linuxbox.fi>
AuthorDate: Mon May 11 05:42:16 2020 +0300

    GROOVY-9546: groovydoc: fix annotation rendering (closes #1243)
---
 .../org/apache/groovy/antlr/GroovydocVisitor.java  |  4 +-
 .../tools/groovydoc/SimpleGroovyAnnotationRef.java |  4 +-
 .../groovydoc/antlr4/GroovydocJavaVisitor.java     | 11 +++-
 .../gstringTemplates/classLevel/classDocName.html  |  2 +-
 .../groovy/tools/groovydoc/GroovyDocToolTest.java  | 69 ++++++++++++++++++++++
 .../tools/groovydoc/testfiles/anno/Groovy.groovy   | 39 ++++++++++++
 .../tools/groovydoc/testfiles/anno/Java.java       | 40 +++++++++++++
 7 files changed, 163 insertions(+), 6 deletions(-)

diff --git a/subprojects/groovy-groovydoc/src/main/java/org/apache/groovy/antlr/GroovydocVisitor.java b/subprojects/groovy-groovydoc/src/main/java/org/apache/groovy/antlr/GroovydocVisitor.java
index 4275e03..a89b7e7 100644
--- a/subprojects/groovy-groovydoc/src/main/java/org/apache/groovy/antlr/GroovydocVisitor.java
+++ b/subprojects/groovy-groovydoc/src/main/java/org/apache/groovy/antlr/GroovydocVisitor.java
@@ -185,14 +185,14 @@ public class GroovydocVisitor extends ClassCodeVisitorSupport {
     private void processAnnotations(SimpleGroovyProgramElementDoc element, AnnotatedNode node) {
         for (AnnotationNode an : node.getAnnotations()) {
             String name = an.getClassNode().getName();
-            element.addAnnotationRef(new SimpleGroovyAnnotationRef(name, name));
+            element.addAnnotationRef(new SimpleGroovyAnnotationRef(name, an.getText()));
         }
     }
 
     private void processAnnotations(SimpleGroovyParameter param, AnnotatedNode node) {
         for (AnnotationNode an : node.getAnnotations()) {
             String name = an.getClassNode().getName();
-            param.addAnnotationRef(new SimpleGroovyAnnotationRef(name, name));
+            param.addAnnotationRef(new SimpleGroovyAnnotationRef(name, an.getText()));
         }
     }
 
diff --git a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyAnnotationRef.java b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyAnnotationRef.java
index 07bdda0..9540bda 100644
--- a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyAnnotationRef.java
+++ b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyAnnotationRef.java
@@ -20,6 +20,7 @@ package org.codehaus.groovy.tools.groovydoc;
 
 import org.codehaus.groovy.groovydoc.GroovyAnnotationRef;
 import org.codehaus.groovy.groovydoc.GroovyClassDoc;
+import org.codehaus.groovy.runtime.StringGroovyMethods;
 
 public class SimpleGroovyAnnotationRef implements GroovyAnnotationRef {
     private GroovyClassDoc type;
@@ -27,8 +28,9 @@ public class SimpleGroovyAnnotationRef implements GroovyAnnotationRef {
     private String name;
 
     public SimpleGroovyAnnotationRef(String name, String desc) {
-        this.desc = desc;
         this.name = name;
+        final String params = StringGroovyMethods.minus(desc, "@" + name);
+        this.desc = "()".equals(params) ? "" : params;
     }
 
     public void setType(GroovyClassDoc type) {
diff --git a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/antlr4/GroovydocJavaVisitor.java b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/antlr4/GroovydocJavaVisitor.java
index 834c068..1848631 100644
--- a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/antlr4/GroovydocJavaVisitor.java
+++ b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/antlr4/GroovydocJavaVisitor.java
@@ -218,16 +218,23 @@ public class GroovydocJavaVisitor extends VoidVisitorAdapter<Object> {
 
     private void processAnnotations(SimpleGroovyProgramElementDoc element, NodeWithAnnotations<?> n) {
         for (AnnotationExpr an : n.getAnnotations()) {
-            element.addAnnotationRef(new SimpleGroovyAnnotationRef(an.getClass().getName(), an.getNameAsString()));
+            element.addAnnotationRef(new SimpleGroovyAnnotationRef(an.getNameAsString(), getAnnotationText(an)));
         }
     }
 
     private void processAnnotations(SimpleGroovyParameter param, NodeWithAnnotations<?> n) {
         for (AnnotationExpr an : n.getAnnotations()) {
-            param.addAnnotationRef(new SimpleGroovyAnnotationRef(an.getClass().getName(), an.getNameAsString()));
+            param.addAnnotationRef(new SimpleGroovyAnnotationRef(an.getNameAsString(), getAnnotationText(an)));
         }
     }
 
+    private String getAnnotationText(final AnnotationExpr an) {
+        if (an != null && an.getTokenRange().isPresent()) {
+            return an.getTokenRange().get().toString();
+        }
+        return "";
+    }
+
     private void setModifiers(NodeList<Modifier> modifiers, SimpleGroovyAbstractableElementDoc elementDoc) {
         if (modifiers.contains(Modifier.publicModifier())) {
             elementDoc.setPublic(true);
diff --git a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/classLevel/classDocName.html b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/classLevel/classDocName.html
index 2b8f5ea..0091217 100644
--- a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/classLevel/classDocName.html
+++ b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/classLevel/classDocName.html
@@ -71,7 +71,7 @@
         (t.isStatic()?"static&nbsp;":"")
     }
     def annotations = { t, sepChar ->
-        t.annotations() ? t.annotations().collect{ it.isTypeAvailable()?'@'+linkable(it.type().typeName())+(it.description()-('@'+it.type().typeName())):it.description()}.join(sepChar) + sepChar : ''
+        t.annotations() ? t.annotations().collect{ it.isTypeAvailable()?'@'+linkable(it.type().typeName())+it.description():it.description()}.join(sepChar) + sepChar : ''
     }
     def elementTypes = [
         "required":"true",
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java
index 6fcec54..581c795 100644
--- a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java
@@ -850,6 +850,75 @@ public class GroovyDocToolTest extends GroovyTestCase {
         assertTrue("The Groovy method detail title should include type parameters", methodDetailTitle.matcher(groovydoc).find());
     }
 
+    public void testAnnotations() throws Exception {
+        final String base = "org/codehaus/groovy/tools/groovydoc/testfiles/anno";
+        htmlTool.add(Arrays.asList(
+                base + "/Groovy.groovy",
+                base + "/Java.java"
+        ));
+
+        final MockOutputTool output = new MockOutputTool();
+        htmlTool.renderToOutput(output, MOCK_DIR);
+
+        final String groovydoc = output.getText(MOCK_DIR + "/" + base + "/Groovy.html");
+        final String javadoc = output.getText(MOCK_DIR + "/" + base + "/Java.html");
+
+        assertTrue("The Groovy class declaration header should have the annotation", Pattern.compile(Pattern.quote(
+                "<pre>@groovy.transform.EqualsAndHashCode(cache: true)\n" +
+                        "class Groovy"
+        )).matcher(groovydoc).find());
+
+        assertTrue("The Java class declaration header should have the annotation", Pattern.compile(Pattern.quote(
+                "<pre>@<a href='https://docs.oracle.com/javase/8/docs/api/java/lang/Deprecated.html' title='Deprecated'>Deprecated</a>\n" +
+                        "@<a href='https://docs.oracle.com/javase/8/docs/api/java/lang/SuppressWarnings.html' title='SuppressWarnings'>SuppressWarnings</a>(\"foo\")\n" +
+                        "public&nbsp;class Java"
+        )).matcher(javadoc).find());
+
+        assertTrue("The Groovy field details should have the annotation", Pattern.compile(Pattern.quote(
+                "<h4>@groovy.transform.Internal\n" +
+                        "public&nbsp;<a href='https://docs.oracle.com/javase/8/docs/api/java/lang/String.html' title='String'>String</a> " +
+                        "<strong>annotatedField</strong></h4>"
+        )).matcher(groovydoc).find());
+
+        assertTrue("The Java field details should have the annotation", Pattern.compile(Pattern.quote(
+                "<h4>@<a href='https://docs.oracle.com/javase/8/docs/api/java/lang/Deprecated.html' title='Deprecated'>Deprecated</a>\n" +
+                        "public&nbsp;<a href='https://docs.oracle.com/javase/8/docs/api/java/lang/String.html' title='String'>String</a> " +
+                        "<strong>annotatedField</strong></h4>"
+        )).matcher(javadoc).find());
+
+        // TODO: Annotations for properties are missing, for some reason.
+
+        assertTrue("The Groovy ctor details should have the annotation", Pattern.compile(Pattern.quote(
+                "<h4>@groovy.transform.NamedVariant\n" +
+                        "<strong>Groovy</strong>(" +
+                        "@groovy.transform.NamedParam " +
+                        "<a href='https://docs.oracle.com/javase/8/docs/api/java/util/List.html' title='List'>List</a> ctorParam" +
+                        ")</h4>"
+        )).matcher(groovydoc).find());
+
+        assertTrue("The Java ctor details should have the annotation", Pattern.compile(Pattern.quote(
+                "<h4>@<a href='https://docs.oracle.com/javase/8/docs/api/java/lang/Deprecated.html' title='Deprecated'>Deprecated</a>\n" +
+                        "public&nbsp;<strong>Java</strong>()</h4>"
+        )).matcher(javadoc).find());
+
+        // Note also the param annotation
+        assertTrue("The Groovy method details should have the annotations", Pattern.compile(Pattern.quote(
+                "<h4>@groovy.transform.NamedVariant\n" +
+                        "void <strong>annotatedMethod</strong>(" +
+                        "@groovy.transform.NamedParam(required: true) " +
+                        "<a href='https://docs.oracle.com/javase/8/docs/api/java/lang/String.html' title='String'>String</a> methodParam" +
+                        ")</h4>"
+        )).matcher(groovydoc).find());
+
+        assertTrue("The Java method details should have the annotations", Pattern.compile(Pattern.quote(
+                "<h4>@<a href='https://docs.oracle.com/javase/8/docs/api/java/lang/Deprecated.html' title='Deprecated'>Deprecated</a>\n" +
+                        "public&nbsp;void <strong>annotatedMethod</strong>(" +
+                        "@CommandLine.Parameters(hidden = true) " +
+                        "<a href='https://docs.oracle.com/javase/8/docs/api/java/lang/String.html' title='String'>String</a> annotatedParam" +
+                        ")</h4>"
+        )).matcher(javadoc).find());
+    }
+
     public void testScript() throws Exception {
         List<String> srcList = new ArrayList<String>();
         srcList.add("org/codehaus/groovy/tools/groovydoc/testfiles/Script.groovy");
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/anno/Groovy.groovy b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/anno/Groovy.groovy
new file mode 100644
index 0000000..1362c88
--- /dev/null
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/anno/Groovy.groovy
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.tools.groovydoc.testfiles.anno
+
+import groovy.transform.EqualsAndHashCode
+import groovy.transform.NamedParam
+import groovy.transform.NamedVariant
+
+// The annotations that are used here don't really matter,
+// since groovydoc shows all annotations, not just @Documented ones.
+@EqualsAndHashCode(cache = true)
+class Groovy implements Serializable {
+    @groovy.transform.Internal
+    public String annotatedField
+
+    @Deprecated List annotatedProperty
+
+    @NamedVariant
+    Groovy(@NamedParam List ctorParam) {}
+
+    @NamedVariant
+    void annotatedMethod(@NamedParam(required = true) String methodParam) {}
+}
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/anno/Java.java b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/anno/Java.java
new file mode 100644
index 0000000..d18db63
--- /dev/null
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/anno/Java.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.tools.groovydoc.testfiles.anno;
+
+
+import org.junit.runners.Parameterized;
+import picocli.CommandLine;
+
+import java.io.Serializable;
+
+// The annotations that are used here don't really matter,
+// since groovydoc shows all annotations, not just @Documented ones.
+@Deprecated
+@SuppressWarnings("foo")
+public class Java implements Serializable {
+    @Deprecated
+    public String annotatedField;
+
+    @Deprecated
+    public Java() {}
+
+    @Deprecated
+    public void annotatedMethod(@CommandLine.Parameters(hidden = true) String annotatedParam) {}
+}