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 02:17:48 UTC

[groovy] branch GROOVY_4_0_X updated (c9462cb261 -> 400e039219)

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

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


    from c9462cb261 GROOVY-10744: STC: assignment of primitives to wrapper-type interfaces
     new 52662654a7 GROOVY-10739: Improve error message for malformed grab coordinate
     new 9c6d6cbb6a GROOVY-10743: The use method for Category classes can't take an interface with static methods due to a NPE
     new 400e039219 GROOVY-10737: Groovydoc deprecation list page is always empty even if @deprecated is used in groovydoc comments on some elements

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                | 14 ++++++
 src/test/groovy/grape/GrapeIvyTest.groovy          | 26 +++++++++++
 .../groovy/tools/groovydoc/SimpleGroovyDoc.java    |  4 +-
 .../groovy/tools/groovydoc/GroovyDocToolTest.java  | 51 ++++++++++++++--------
 .../groovydoc/testfiles/DeprecatedClass.groovy     |  2 +
 .../groovydoc/testfiles/DeprecatedField.groovy     |  6 ++-
 8 files changed, 107 insertions(+), 33 deletions(-)


[groovy] 01/03: GROOVY-10739: Improve error message for malformed grab coordinate

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

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

commit 52662654a7edd89e89958cd4856c054286c1fe3f
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
---
 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 bfc00258f1..f942fc84de 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 = (Set<String>) 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 1fc93c30b2..9096ab2fab 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] 03/03: GROOVY-10737: Groovydoc deprecation list page is always empty even if @deprecated is used in groovydoc comments on some elements

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

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

commit 400e039219669c8451c5d15410f2f904f7437a7d
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
---
 .../groovy/tools/groovydoc/SimpleGroovyDoc.java    |  4 +-
 .../groovy/tools/groovydoc/GroovyDocToolTest.java  | 51 ++++++++++++++--------
 .../groovydoc/testfiles/DeprecatedClass.groovy     |  2 +
 .../groovydoc/testfiles/DeprecatedField.groovy     |  6 ++-
 4 files changed, 41 insertions(+), 22 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 58b79be0a8..f519b3e87d 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
@@ -39,7 +39,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;
@@ -104,7 +104,7 @@ public class SimpleGroovyDoc implements GroovyDoc/*, GroovyTokenTypes*/ {
         if (trimmed.equals(rawCommentText)) return;
         String cleaned = TRIMMED_COMMENT_PATTERN.matcher(trimmed).replaceAll("$1").trim();
         String[] split = cleaned.split("(?m)^@", -1);
-        List<GroovyTag> result = new ArrayList<GroovyTag>();
+        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 2fcc35e6cb..86eb165b50 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));
@@ -1307,6 +1307,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
     }
 


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

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

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

commit 9c6d6cbb6a8e2e4e8abe03b28500dea4ae8b319b
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
---
 .../org/codehaus/groovy/runtime/GroovyCategorySupport.java |  4 ++--
 src/test/groovy/CategoryTest.groovy                        | 14 ++++++++++++++
 2 files changed, 16 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 bc1493a12e..000bfc252a 100644
--- a/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
+++ b/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
@@ -188,8 +188,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 92a734668c..f8c0a0f2a7 100644
--- a/src/test/groovy/CategoryTest.groovy
+++ b/src/test/groovy/CategoryTest.groovy
@@ -20,6 +20,9 @@ package groovy
 
 import groovy.test.GroovyTestCase
 
+import static groovy.test.GroovyAssert.isAtLeastJdk
+import static org.junit.Assume.assumeTrue
+
 final class CategoryTest extends GroovyTestCase {
 
     @Override
@@ -327,6 +330,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()