You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2023/04/13 16:42:04 UTC

[groovy] 02/02: GROOVY-11011: SC: apply array flow type

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

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

commit a4dac87444935ec5c2f96ca0cd42cb84cf1ce4f6
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Apr 13 10:51:09 2023 -0500

    GROOVY-11011: SC: apply array flow type
---
 src/main/groovy/groovy/util/FileTreeBuilder.groovy | 44 +++++------
 .../classgen/asm/sc/StaticTypesCallSiteWriter.java |  4 +-
 src/spec/test/builder/FileTreeBuilderTest.groovy   | 13 +++-
 src/test/groovy/util/FileTreeBuilderTest.groovy    | 85 +++++++++++++---------
 4 files changed, 82 insertions(+), 64 deletions(-)

diff --git a/src/main/groovy/groovy/util/FileTreeBuilder.groovy b/src/main/groovy/groovy/util/FileTreeBuilder.groovy
index af41a6ce28..b96a2a6287 100644
--- a/src/main/groovy/groovy/util/FileTreeBuilder.groovy
+++ b/src/main/groovy/groovy/util/FileTreeBuilder.groovy
@@ -18,7 +18,10 @@
  */
 package groovy.util
 
+import groovy.transform.AutoFinal
 import groovy.transform.CompileStatic
+import groovy.transform.stc.ClosureParams
+import groovy.transform.stc.FromString
 
 /**
  * A builder dedicated at generating a file directory structure from a
@@ -70,6 +73,7 @@ import groovy.transform.CompileStatic
  *
  * @since 2.4.2
  */
+@AutoFinal
 @CompileStatic
 class FileTreeBuilder {
 
@@ -117,13 +121,9 @@ class FileTreeBuilder {
      * @param spec closure for generating the file contents
      * @return the created file
      */
-    File file(String name, @DelegatesTo(value = File, strategy = Closure.DELEGATE_FIRST) Closure spec) {
+    File file(String name, @ClosureParams(value = FromString, options = 'File') @DelegatesTo(value = File, strategy = Closure.DELEGATE_FIRST) Closure spec) {
         def file = new File(baseDir, name)
-        def clone = (Closure) spec.clone()
-        clone.delegate = file
-        clone.resolveStrategy = Closure.DELEGATE_FIRST
-        clone(file)
-        file
+        file.tap(spec)
     }
 
     /**
@@ -132,25 +132,26 @@ class FileTreeBuilder {
      * @return the created directory
      */
     File dir(String name) {
-        def f = new File(baseDir, name)
-        f.mkdirs()
-        f
+        def file = new File(baseDir, name)
+        file.mkdirs()
+        file
     }
 
     /**
      * Creates a new directory and allows to specify a subdirectory structure using the closure as a specification
      * @param name name of the directory to be created
-     * @param cl specification of the subdirectory structure
+     * @param spec specification of the subdirectory structure
      * @return the created directory
      */
-    File dir(String name, @DelegatesTo(value = FileTreeBuilder, strategy = Closure.DELEGATE_FIRST) Closure cl) {
+    File dir(String name, @DelegatesTo(value = FileTreeBuilder, strategy = Closure.DELEGATE_FIRST) Closure spec) {
         def oldBase = baseDir
         def newBase = dir(name)
         try {
             baseDir = newBase
-            cl.delegate = this
-            cl.resolveStrategy = Closure.DELEGATE_FIRST
-            cl()
+            def clone = (Closure) spec.clone()
+            clone.delegate = this
+            clone.resolveStrategy = Closure.DELEGATE_FIRST
+            clone()
         } finally {
             baseDir = oldBase
         }
@@ -165,19 +166,18 @@ class FileTreeBuilder {
         baseDir
     }
 
-    @SuppressWarnings('Instanceof')
-    def methodMissing(String name, args) {
-        if (args instanceof Object[] && ((Object[]) args).length == 1) {
-            def arg = ((Object[]) args)[0]
+    def methodMissing(String name, Object args) {
+        if (args instanceof Object[] && args.length == 1) {
+            def arg = args[0]
             if (arg instanceof Closure) {
-                dir(name, arg)
+                dir(name, (Closure<?>) arg)
             } else if (arg instanceof CharSequence) {
                 file(name, arg.toString())
             } else if (arg instanceof byte[]) {
-                file(name, arg)
+                file(name, (byte[]) arg)
             } else if (arg instanceof File) {
-                file(name, arg)
+                file(name, (File) arg)
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
index e6b8923d13..2e28616b07 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -161,8 +161,7 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter {
         ClassNode receiverType = getPropertyOwnerType(receiver, isClassReceiver);
         if (receiverType.isArray() && "length".equals(propertyName)) {
             receiver.visit(controller.getAcg());
-            ClassNode arrayGetReturnType = controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
-            controller.getOperandStack().doGroovyCast(arrayGetReturnType);
+            controller.getOperandStack().doGroovyCast(receiverType); // GROOVY-5683, GROOVY-11011
             controller.getMethodVisitor().visitInsn(ARRAYLENGTH);
             controller.getOperandStack().replace(int_TYPE);
             return;
@@ -685,6 +684,7 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter {
         int m1 = operandStack.getStackLength();
         // visit receiver
         receiver.visit(controller.getAcg());
+        operandStack.doGroovyCast(rType); // GROOVY-11011
         // visit arguments as array index
         arguments.visit(controller.getAcg());
         operandStack.doGroovyCast(int_TYPE);
diff --git a/src/spec/test/builder/FileTreeBuilderTest.groovy b/src/spec/test/builder/FileTreeBuilderTest.groovy
index 83b29a9e95..323a051524 100644
--- a/src/spec/test/builder/FileTreeBuilderTest.groovy
+++ b/src/spec/test/builder/FileTreeBuilderTest.groovy
@@ -18,15 +18,19 @@
  */
 package builder
 
-import groovy.test.GroovyTestCase
+import org.junit.After
+import org.junit.Test
+
+final class FileTreeBuilderTest {
 
-class FileTreeBuilderTest extends GroovyTestCase {
     File tmpDir
 
+    @After
     void tearDown() {
         tmpDir.deleteDir()
     }
 
+    @Test
     void testFileTreeBuilder() {
         // tag::example[]
         tmpDir = File.createTempDir()
@@ -51,6 +55,7 @@ class FileTreeBuilderTest extends GroovyTestCase {
          // end::example_assert[]
     }
 
+    @Test
     void testFileTreeBuilderShortHandSyntax() {
         // tag::shorthand_syntax[]
         tmpDir = File.createTempDir()
@@ -73,5 +78,5 @@ class FileTreeBuilderTest extends GroovyTestCase {
          assert new File(tmpDir, '/src/main/groovy/Foo.groovy').text == 'println "Hello"'
          assert new File(tmpDir, '/src/test/groovy/FooTest.groovy').text == 'class FooTest extends groovy.test.GroovyTestCase {}'
          // end::shorthand_syntax_assert[]
-    }    
- }
+    }
+}
diff --git a/src/test/groovy/util/FileTreeBuilderTest.groovy b/src/test/groovy/util/FileTreeBuilderTest.groovy
index ebbd7f436c..ed40a7ab45 100644
--- a/src/test/groovy/util/FileTreeBuilderTest.groovy
+++ b/src/test/groovy/util/FileTreeBuilderTest.groovy
@@ -18,50 +18,57 @@
  */
 package groovy.util
 
-import groovy.test.GroovyTestCase
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
 
-class FileTreeBuilderTest extends GroovyTestCase {
-    File tmpDir
-    FileTreeBuilder builder
+final class FileTreeBuilderTest {
 
+    private File tmpDir
+    private FileTreeBuilder root
+
+    @Before
     void setUp() {
-        super.setUp()
         tmpDir = File.createTempDir()
-        builder = new FileTreeBuilder(tmpDir)
+        root = new FileTreeBuilder(tmpDir)
     }
 
+    @After
     void tearDown() {
         tmpDir.deleteDir()
-        builder = null
-        tmpDir = null
     }
 
+    @Test
     void testFileWithText() {
-        def file = builder.file('foo.txt','foo')
+        def file = root.file('foo.txt','foo')
         assert file.exists()
         assert file.text == 'foo'
     }
 
+    @Test
     void testFileWithBytes() {
-        def file = builder.file('foo.txt','foo'.getBytes('utf-8'))
+        def file = root.file('foo.txt','foo'.getBytes('utf-8'))
         assert file.exists()
         assert file.getText('utf-8') == 'foo'
     }
 
+    @Test
     void testFileWithFile() {
-        def f1 = builder.file('foo.txt', 'foo')
-        def f2 = builder.file('bar.txt', f1)
+        def f1 = root.file('foo.txt', 'foo')
+        def f2 = root.file('bar.txt', f1)
         assert f2.exists()
         assert f2.text == 'foo'
     }
 
+    @Test
     void testFileWithClosureSpec() {
-        def file = builder.file('foo.txt') { file ->
-            file << 'foo'
+        def file = root.file('foo.txt') { foo_txt ->
+            foo_txt << 'foo'
         }
         assert file.exists()
         assert file.text == 'foo'
-        def file2 = builder.file('foo.txt') {
+
+        def file2 = root.file('foo.txt') {
             withWriter('utf-8') {
                 it.write('foo')
             }
@@ -70,53 +77,59 @@ class FileTreeBuilderTest extends GroovyTestCase {
         assert file2.text == 'foo'
     }
 
+    @Test
     void testDir() {
-        def dir = builder.dir('sub')
-        assert dir.directory
-        assert dir.parentFile == builder.baseDir
+        def dir = root.dir('sub')
+        assert dir.isDirectory()
+        assert dir.name == 'sub'
+        assert dir.parentFile == root.baseDir
     }
 
+    @Test
     void testDirWithClosure() {
         File f = null
-        def dir = builder.dir('sub') {
+        def dir = root.dir('sub') {
             f = file('foo.txt','foo')
         }
-        assert dir.directory
-        assert dir.parentFile == builder.baseDir
+        assert dir.isDirectory()
+        assert dir.parentFile == root.baseDir
         assert f.text == 'foo'
         assert f.parentFile == dir
     }
 
+    @Test
     void testCall() {
-        File s1=null,s2=null,f1=null,f2=null
-        builder {
-            s1=dir('sub1') {
-                f1=file('foo.txt','foo')
+        File s1, s2, f1, f2
+        root {
+            s1 = dir('sub1') {
+                f1 = file('foo.txt','foo')
             }
-            s2=dir('sub2') {
-                f2=file('bar.txt', 'bar')
+            s2 = dir('sub2') {
+                f2 = file('bar.txt', 'bar')
             }
         }
         assert f1.text == 'foo'
         assert f2.text == 'bar'
         assert f1.parentFile == s1
         assert f2.parentFile == s2
-        assert s1.parentFile == builder.baseDir
-        assert s2.parentFile == builder.baseDir
+        assert s1.parentFile == root.baseDir
+        assert s2.parentFile == root.baseDir
     }
 
+    @Test
     void testCreateDirWithMethodMissing() {
-        File dir = builder.dir {}
-        assert dir.directory
+        File dir = root.dir({}) // not dir(String) or dir(String,Closure)
+        assert dir.isDirectory()
         assert dir.name == 'dir'
-        assert dir.parentFile == builder.baseDir
+        assert dir.parentFile == root.baseDir
     }
 
+    @Test
     void testCreateFileWithMethodMissing() {
-        File f1 = builder.'foo.txt'('foo')
-        File f2 = builder.'bar.txt'('foo'.getBytes('utf-8'))
-        File f3 = builder.'baz.txt'(f2)
-        [f1,f2,f3].each {
+        File f1 = root.'foo.txt'('foo')
+        File f2 = root.'bar.txt'('foo'.getBytes('utf-8'))
+        File f3 = root.'baz.txt'(f2)
+        [f1, f2, f3].each {
             assert it.exists()
             assert it.getText('utf-8') == 'foo'
         }