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 2022/09/03 03:58:22 UTC

[groovy] branch GROOVY_3_0_X updated (d66a8a4d2d -> 91e9cfcfcb)

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

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


    from d66a8a4d2d GROOVY-10744: STC: assignment of primitives to wrapper-type interfaces
     new 85209d7ea2 GROOVY-10739: Improve error message for malformed grab coordinate (port to 3_0_X)
     new 6b04a734a6 GROOVY-10743: The use method for Category classes can't take an interface with static methods due to a NPE (port to 3_0_X)
     new 91e9cfcfcb GROOVY-10737: Groovydoc deprecation list page is always empty even if @deprecated is used in groovydoc comments on some elements (port to 3_0_X)

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/main/groovy/groovy/grape/GrapeIvy.groovy       | 33 ++++++++++----
 .../groovy/runtime/GroovyCategorySupport.java      |  4 +-
 src/test/groovy/CategoryTest.groovy                | 13 ++++++
 src/test/groovy/grape/GrapeIvyTest.groovy          | 26 +++++++++++
 .../groovy/tools/groovydoc/SimpleGroovyDoc.java    |  6 +--
 .../groovy/tools/groovydoc/GroovyDocToolTest.java  | 51 ++++++++++++++--------
 .../groovydoc/testfiles/DeprecatedClass.groovy     |  2 +
 .../groovydoc/testfiles/DeprecatedField.groovy     |  6 ++-
 8 files changed, 107 insertions(+), 34 deletions(-)


[groovy] 01/03: GROOVY-10739: Improve error message for malformed grab coordinate (port to 3_0_X)

Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 85209d7ea23fdb953488c5f037695f962fff0480
Author: Paul King <pa...@asert.com.au>
AuthorDate: Thu Sep 1 23:41:44 2022 +1000

    GROOVY-10739: Improve error message for malformed grab coordinate (port to 3_0_X)
---
 src/main/groovy/groovy/grape/GrapeIvy.groovy | 33 ++++++++++++++++++++--------
 src/test/groovy/grape/GrapeIvyTest.groovy    | 26 ++++++++++++++++++++++
 2 files changed, 50 insertions(+), 9 deletions(-)

diff --git a/src/main/groovy/groovy/grape/GrapeIvy.groovy b/src/main/groovy/groovy/grape/GrapeIvy.groovy
index 4bb79509ac..18d6a32804 100644
--- a/src/main/groovy/groovy/grape/GrapeIvy.groovy
+++ b/src/main/groovy/groovy/grape/GrapeIvy.groovy
@@ -198,6 +198,30 @@ class GrapeIvy implements GrapeEngine {
             throw new RuntimeException('grab requires at least a module: or artifactId: or artifact: argument')
         }
 
+        // check for malformed components of the coordinates
+        dep.each { k, v ->
+            if (v instanceof CharSequence) {
+                if (k.toString().contains('v')) { // revision, version, rev
+                    if (!(v ==~ '[^\\/:"<>|]*')) {
+                        throw new RuntimeException("Grab: invalid value of '$v' for $k: should not contain any of / \\ : \" < > |")
+                    }
+                } else {
+                    if (!(v ==~ '[-._a-zA-Z0-9]*')) {
+                        throw new RuntimeException("Grab: invalid value of '$v' for $k: should only contain - . _ a-z A-Z 0-9")
+                    }
+                }
+            }
+        }
+
+        // check for mutually exclusive arguments
+        Set<String> keys = (Set<String>) dep.keySet()
+        keys.each { key ->
+            Set<String> badArgs = MUTUALLY_EXCLUSIVE_KEYS[key]
+            if (badArgs && !badArgs.disjoint(keys)) {
+                throw new RuntimeException("Grab: mutually exclusive arguments: ${keys.intersect(badArgs) + key}")
+            }
+        }
+
         String groupId = dep.group ?: dep.groupId ?: dep.organisation ?: dep.organization ?: dep.org ?: ''
         // TODO: accept ranges and decode them?  except '1.0.0'..<'2.0.0' won't work in groovy
         String version = dep.version ?: dep.revision ?: dep.rev ?: '*'
@@ -593,15 +617,6 @@ class GrapeIvy implements GrapeEngine {
     }
 
     URI[] resolve(ClassLoader loader, Map args, List depsInfo, Map... dependencies) {
-        // check for mutually exclusive arguments
-        Set<String> keys = args.keySet()
-        keys.each { key ->
-            Set<String> badArgs = MUTUALLY_EXCLUSIVE_KEYS[key]
-            if (badArgs && !badArgs.disjoint(keys)) {
-                throw new RuntimeException("Mutually exclusive arguments passed into grab: ${keys.intersect(badArgs) + key}")
-            }
-        }
-
         // check the kill switch
         if (!enableGrapes) {
             return new URI[0]
diff --git a/src/test/groovy/grape/GrapeIvyTest.groovy b/src/test/groovy/grape/GrapeIvyTest.groovy
index 32104084c3..8117d4afdf 100644
--- a/src/test/groovy/grape/GrapeIvyTest.groovy
+++ b/src/test/groovy/grape/GrapeIvyTest.groovy
@@ -374,6 +374,32 @@ final class GrapeIvyTest {
         '''
     }
 
+    @Test
+    void testInvalidGroup() {
+        def ex = shouldFail '''
+            @Grab('org/ejml:ejml-simple:0.41')
+            import org.ejml.simple.SimpleMatrix
+        '''
+        assert ex.message.contains("Grab: invalid value of 'org/ejml' for group")
+    }
+
+    @Test
+    void testInvalidVersion() {
+        def ex = shouldFail '''
+            @Grab('org.ejml:ejml-simple:0.41|')
+            import org.ejml.simple.SimpleMatrix
+        '''
+        assert ex.message.contains("Grab: invalid value of '0.41|' for version")
+    }
+
+    @Test
+    void testInvalidMutuallyExclusiveArgs() {
+        def ex = shouldFail '''
+            groovy.grape.Grape.grab(group: 'org.ejml', groupId: 'org.ejml', module: 'ejml-simple', version: '0.41')
+        '''
+        assert ex.message.contains('Grab: mutually exclusive arguments: [groupId, group]')
+    }
+
     @Test
     void testTransitiveShorthandExpectFailure() {
         shouldFail MissingPropertyException, '''


[groovy] 02/03: GROOVY-10743: The use method for Category classes can't take an interface with static methods due to a NPE (port to 3_0_X)

Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 6b04a734a645a0fb27f907e0567acef3f5362a4e
Author: Paul King <pa...@asert.com.au>
AuthorDate: Fri Sep 2 12:55:40 2022 +1000

    GROOVY-10743: The use method for Category classes can't take an interface with static methods due to a NPE (port to 3_0_X)
---
 .../org/codehaus/groovy/runtime/GroovyCategorySupport.java  |  4 ++--
 src/test/groovy/CategoryTest.groovy                         | 13 +++++++++++++
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java b/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
index ff872fc56f..8a05c8e0e5 100644
--- a/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
+++ b/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
@@ -184,8 +184,8 @@ public class GroovyCategorySupport {
 
         private void use(Class categoryClass) {
             CachedClass cachedClass = ReflectionCache.getCachedClass(categoryClass);
-            LinkedList<CachedClass> classStack = new LinkedList<CachedClass>();
-            for (CachedClass superClass = cachedClass; superClass.getTheClass()!=Object.class; superClass = superClass.getCachedSuperClass()) {
+            LinkedList<CachedClass> classStack = new LinkedList<>();
+            for (CachedClass superClass = cachedClass; superClass != null && superClass.getTheClass() != Object.class; superClass = superClass.getCachedSuperClass()) {
                 classStack.add(superClass);
             }
 
diff --git a/src/test/groovy/CategoryTest.groovy b/src/test/groovy/CategoryTest.groovy
index 2a7f73f276..32d53f1af5 100644
--- a/src/test/groovy/CategoryTest.groovy
+++ b/src/test/groovy/CategoryTest.groovy
@@ -20,6 +20,8 @@ package groovy
 
 import groovy.test.GroovyTestCase
 
+import static groovy.test.GroovyAssert.isAtLeastJdk
+
 final class CategoryTest extends GroovyTestCase {
 
     void setUp() {
@@ -262,6 +264,17 @@ final class CategoryTest extends GroovyTestCase {
         '''
     }
 
+    // GROOVY-10743
+    void testStaticMethodOnInterface() {
+        if(!isAtLeastJdk('9.0')) return
+        assertScript '''
+        use(java.util.stream.Stream) {
+            assert [1, 1].iterate(f -> [f[1], f.sum()]).limit(8).toList()*.head() == [1, 1, 2, 3, 5, 8, 13, 21]
+            assert 16.iterate(n -> n < 500, n -> n * 2).toList() == [16, 32, 64, 128, 256]
+        }
+        '''
+    }
+
     // GROOVY-3867
     void testPropertyMissing() {
         def x = new X()


[groovy] 03/03: GROOVY-10737: Groovydoc deprecation list page is always empty even if @deprecated is used in groovydoc comments on some elements (port to 3_0_X)

Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 91e9cfcfcb27e5490d527eb33fd5615e0b323fa9
Author: Paul King <pa...@asert.com.au>
AuthorDate: Fri Sep 2 21:29:23 2022 +1000

    GROOVY-10737: Groovydoc deprecation list page is always empty even if @deprecated is used in groovydoc comments on some elements (port to 3_0_X)
---
 .../groovy/tools/groovydoc/SimpleGroovyDoc.java    |  6 +--
 .../groovy/tools/groovydoc/GroovyDocToolTest.java  | 51 ++++++++++++++--------
 .../groovydoc/testfiles/DeprecatedClass.groovy     |  2 +
 .../groovydoc/testfiles/DeprecatedField.groovy     |  6 ++-
 4 files changed, 42 insertions(+), 23 deletions(-)

diff --git a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyDoc.java b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyDoc.java
index d47e2083f1..d29ab5bb2d 100644
--- a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyDoc.java
+++ b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyDoc.java
@@ -37,7 +37,7 @@ public class SimpleGroovyDoc implements GroovyDoc/*, GroovyTokenTypes*/ {
     public static final int ENUM_DEF = 61;
     private static final Pattern TAG2_PATTERN = Pattern.compile("(?s)([a-z]+)\\s+(.*)");
     private static final Pattern TAG3_PATTERN = Pattern.compile("(?s)([a-z]+)\\s+(\\S*)\\s+(.*)");
-    private static final Pattern RAW_COMMENT_PATTERN = Pattern.compile("\"(?s).*?\\\\*\\\\s*@\"");
+    private static final Pattern RAW_COMMENT_PATTERN = Pattern.compile("(?s).*?\\*\\s*@");
     private static final Pattern TRIMMED_COMMENT_PATTERN = Pattern.compile("(?m)^\\s*\\*\\s*([^*]*)$");
     private static final GroovyTag[] EMPTY_GROOVYTAG_ARRAY = new GroovyTag[0];
     private final String name;
@@ -95,8 +95,8 @@ public class SimpleGroovyDoc implements GroovyDoc/*, GroovyTokenTypes*/ {
         String trimmed = RAW_COMMENT_PATTERN.matcher(rawCommentText).replaceFirst("@");
         if (trimmed.equals(rawCommentText)) return;
         String cleaned = TRIMMED_COMMENT_PATTERN.matcher(trimmed).replaceAll("$1").trim();
-        String[] split = cleaned.split("(?m)^@");
-        List<GroovyTag> result = new ArrayList<GroovyTag>();
+        String[] split = cleaned.split("(?m)^@", -1);
+        List<GroovyTag> result = new ArrayList<>();
         for (String s : split) {
             String tagname = null;
             if (s.startsWith("param") || s.startsWith("throws")) {
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 b7a4005ae6..ec38f37443 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
@@ -757,7 +757,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
     public void testGroovyExtendsImportedClassWithNameWhichExistInDefaultPackages() throws Exception {
         // Groovy interface b.Test imports a.List and extends List.
-        // List should be recognized as a.List and not java.util.List 
+        // List should be recognized as a.List and not java.util.List
         htmlTool.add(Arrays.asList(
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/a/List.java",
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/b/Test.groovy"
@@ -769,7 +769,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
         // Test should etends a.List
         final Matcher extendedClass = Pattern.compile("extends\\s+<a[^>]*href='[^']*(((java/util/)|(a/))List)\\.html'[^>]*>List</a>").matcher(testAdapterDoc);
-        
+
         assertTrue("Test interface should extends List", extendedClass.find());
 
         assertEquals("Classes from imported packages should shadow classes from default packages", "a/List", extendedClass.group(1));
@@ -777,7 +777,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
     public void testJavaExtendsImportedClassWithNameWhichExistInDefaultPackages() throws Exception {
         // Java interface b.Test imports a.List and extends List.
-        // List should be recognized as a.List and not java.util.List 
+        // List should be recognized as a.List and not java.util.List
         htmlTool.add(Arrays.asList(
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/a/List.java",
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/b/Test.java"
@@ -789,7 +789,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
         // Test should etends a.List
         final Matcher extendedClass = Pattern.compile("extends\\s+<a[^>]*href='[^']*(((java/util/)|(a/))List)\\.html'[^>]*>List</a>").matcher(testAdapterDoc);
-        
+
         assertTrue("Test interface should extends List", extendedClass.find());
 
         assertEquals("Classes from imported packages should shadow classes from default packages", "a/List", extendedClass.group(1));
@@ -797,7 +797,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
     public void testGroovyExtendsStarImportedClassWithNameWhichExistInDefaultPackages() throws Exception {
         // Groovy interface b.TestStar imports a.* and extends List.
-        // List should be recognized as a.List and not java.util.List 
+        // List should be recognized as a.List and not java.util.List
         htmlTool.add(Arrays.asList(
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/a/List.java",
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/b/TestStar.groovy"
@@ -809,7 +809,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
         // TestStar should etends a.List
         final Matcher extendedClass = Pattern.compile("extends\\s+<a[^>]*href='[^']*(((java/util/)|(a/))List)\\.html'[^>]*>List</a>").matcher(testAdapterDoc);
-        
+
         assertTrue("TestStar interface should extends List", extendedClass.find());
 
         assertEquals("Classes from imported packages should shadow classes from default packages", "a/List", extendedClass.group(1));
@@ -817,7 +817,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
     public void testJavaExtendsStarImportedClassWithNameWhichExistInDefaultPackages() throws Exception {
         // Java interface b.TestStar imports a.* and extends List.
-        // List should be recognized as a.List and not java.util.List 
+        // List should be recognized as a.List and not java.util.List
         htmlTool.add(Arrays.asList(
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/a/List.java",
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/b/TestStar.java"
@@ -829,7 +829,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
         // TestStar should etends a.List
         final Matcher extendedClass = Pattern.compile("extends\\s+<a[^>]*href='[^']*(((java/util/)|(a/))List)\\.html'[^>]*>List</a>").matcher(testAdapterDoc);
-        
+
         assertTrue("TestStar interface should extends List", extendedClass.find());
 
         assertEquals("Classes from imported packages should shadow classes from default packages", "a/List", extendedClass.group(1));
@@ -837,7 +837,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
     public void testGroovyExtendsStaticImportedClassWithNameWhichExistInDefaultPackages() throws Exception {
         // Groovy interface b.TestStatic imports a.StaticList.List and extends List.
-        // List should be recognized as a.StaticList.List and not java.util.List 
+        // List should be recognized as a.StaticList.List and not java.util.List
         htmlTool.add(Arrays.asList(
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/a/StaticList.java",
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/b/TestStatic.groovy"
@@ -849,7 +849,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
         // TestStatic should etends a.StaticList.List
         final Matcher extendedClass = Pattern.compile("extends\\s+<a[^>]*href='[^']*(((java/util/)|(a/StaticList\\.))List)\\.html'[^>]*>((StaticList\\.)?List)</a>").matcher(testAdapterDoc);
-        
+
         assertTrue("TestStatic interface should extends List", extendedClass.find());
 
         assertEquals("Classes from imported packages should shadow classes from default packages", "a/StaticList.List", extendedClass.group(1));
@@ -858,7 +858,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
     public void testJavaExtendsStaticImportedClassWithNameWhichExistInDefaultPackages() throws Exception {
         // Java interface b.TestStatic imports a.StaticList.List and extends List.
-        // List should be recognized as a.StaticList.List and not java.util.List 
+        // List should be recognized as a.StaticList.List and not java.util.List
         htmlTool.add(Arrays.asList(
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/a/StaticList.java",
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/b/TestStatic.java"
@@ -870,7 +870,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
         // TestStatic should etends a.StaticList.List".
         final Matcher extendedClass = Pattern.compile("extends\\s+<a[^>]*href='[^']*(((java/util/)|(a/StaticList\\.))List)\\.html'[^>]*>((StaticList\\.)?List)</a>").matcher(testAdapterDoc);
-        
+
         assertTrue("TestStatic interface should extends List", extendedClass.find());
 
         assertEquals("Classes from imported packages should shadow classes from default packages", "a/StaticList.List", extendedClass.group(1));
@@ -879,7 +879,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
     public void testGroovyExtendsStaticImportedAliasesClassWithNameWhichExistInDefaultPackages() throws Exception {
         // Groovy interface b.TestStatic imports a.StaticList.ListAlias as List and extends List.
-        // List should be recognized as a.StaticList.List and not java.util.List 
+        // List should be recognized as a.StaticList.List and not java.util.List
         htmlTool.add(Arrays.asList(
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/a/StaticList.java",
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/b/TestStaticAlias.groovy"
@@ -891,7 +891,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
         // TestStatic should etends a.StaticList.List
         final Matcher extendedClass = Pattern.compile("extends\\s+<a[^>]*href='[^']*(((java/util/)|(a/StaticList\\.))List(Alias)?)\\.html'[^>]*>((StaticList\\.)?List(Alias)?)</a>").matcher(testAdapterDoc);
-        
+
         assertTrue("TestStatic interface should extends List", extendedClass.find());
 
         assertEquals("Classes from imported packages should shadow classes from default packages", "a/StaticList.ListAlias", extendedClass.group(1));
@@ -900,7 +900,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
     public void testGroovyExtendsStaticStarImportedClassWithNameWhichExistInDefaultPackages() throws Exception {
         // Groovy interface b.TestStaticStar imports a.StaticList.* and extends List.
-        // List should be recognized as a.StaticList.List and not java.util.List 
+        // List should be recognized as a.StaticList.List and not java.util.List
         htmlTool.add(Arrays.asList(
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/a/StaticList.java",
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/b/TestStaticStar.groovy"
@@ -912,7 +912,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
         // TestStatic should etends a.StaticList.List
         final Matcher extendedClass = Pattern.compile("extends\\s+<a[^>]*href='[^']*(((java/util/)|(a/StaticList\\.))List)\\.html'[^>]*>((StaticList\\.)?List)</a>").matcher(testAdapterDoc);
-        
+
         assertTrue("TestStaticStar interface should extends List", extendedClass.find());
 
         assertEquals("Classes from imported packages should shadow classes from default packages", "a/StaticList.List", extendedClass.group(1));
@@ -921,7 +921,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
     public void testJavaExtendsStaticStarImportedClassWithNameWhichExistInDefaultPackages() throws Exception {
         // Java interface b.TestStaticStar imports a.StaticList.* and extends List.
-        // List should be recognized as a.StaticList.List and not java.util.List 
+        // List should be recognized as a.StaticList.List and not java.util.List
         htmlTool.add(Arrays.asList(
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/a/StaticList.java",
                 "org/codehaus/groovy/tools/groovydoc/testfiles/groovy_10593/b/TestStaticStar.groovy"
@@ -933,7 +933,7 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
         // TestStatic should etends a.StaticList.List
         final Matcher extendedClass = Pattern.compile("extends\\s+<a[^>]*href='[^']*(((java/util/)|(a/StaticList\\.))List)\\.html'[^>]*>((StaticList\\.)?List)</a>").matcher(testAdapterDoc);
-        
+
         assertTrue("TestStaticStar interface should extends List", extendedClass.find());
 
         assertEquals("Classes from imported packages should shadow classes from default packages", "a/StaticList.List", extendedClass.group(1));
@@ -1289,6 +1289,21 @@ public class GroovyDocToolTest extends GroovyTestCase {
         assertFalse("Private ctor should not be listed", matcher.find());
     }
 
+    public void testDeprecated() throws Exception {
+        final String base = "org/codehaus/groovy/tools/groovydoc/testfiles";
+        htmlTool.add(Arrays.asList(
+            base + "/DeprecatedClass.groovy",
+            base + "/DeprecatedField.groovy"
+        ));
+
+        final MockOutputTool output = new MockOutputTool();
+        htmlTool.renderToOutput(output, MOCK_DIR);
+
+        final String groovydoc = output.getText(MOCK_DIR + "/deprecated-list.html");
+        assertTrue(groovydoc, groovydoc.contains("summary=\"Deprecated Classes table, listing deprecated classes, and an explanation\""));
+        assertTrue(groovydoc, groovydoc.contains("<a href=\"org/codehaus/groovy/tools/groovydoc/testfiles/DeprecatedClass.html\">DeprecatedClass</a>"));
+    }
+
     public void testProperty() throws Exception {
         final String base = "org/codehaus/groovy/tools/groovydoc/testfiles";
         htmlTool.add(Arrays.asList(
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/DeprecatedClass.groovy b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/DeprecatedClass.groovy
index 87dd2e0dc8..11c37ea7ed 100644
--- a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/DeprecatedClass.groovy
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/DeprecatedClass.groovy
@@ -20,6 +20,8 @@ package org.codehaus.groovy.tools.groovydoc.testfiles
 
 /**
  * Meow!
+ *
+ * @deprecated Use something else
  */
 @Deprecated
 class DeprecatedClass {
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/DeprecatedField.groovy b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/DeprecatedField.groovy
index ab47de6731..1cdda21b91 100644
--- a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/DeprecatedField.groovy
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/DeprecatedField.groovy
@@ -21,11 +21,13 @@ package org.codehaus.groovy.tools.groovydoc.testfiles
 class DeprecatedField {
     @Deprecated
     /**
-     * @deprecated Use my ass instead
+     * A public deprecated field
+     *
+     * @deprecated Use something else
      */
     public String field
 
-    public boolean isHandlesNodeChildren() {
+    boolean isHandlesNodeChildren() {
         return true
     }