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 ":"")
}
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 class Java"
+ )).matcher(javadoc).find());
+
+ assertTrue("The Groovy field details should have the annotation", Pattern.compile(Pattern.quote(
+ "<h4>@groovy.transform.Internal\n" +
+ "public <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 <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 <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 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) {}
+}