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 2020/07/17 19:25:49 UTC

[groovy] 01/01: GROOVY-8715: check array in ResolveVisitor.resolveToInner

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

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

commit 9c49a89e46ced56c34b48e6f6929aafe2c4932bb
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Jul 17 14:18:12 2020 -0500

    GROOVY-8715: check array in ResolveVisitor.resolveToInner
---
 .../codehaus/groovy/control/ResolveVisitor.java    | 61 ++++++++++---------
 src/test/gls/innerClass/InnerClassTest.groovy      | 68 ++++++++++++++++++++++
 2 files changed, 101 insertions(+), 28 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
index 4395dc8..bc526fc 100644
--- a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
@@ -322,34 +322,49 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         genericParameterNames = oldPNames;
     }
 
+    private void resolveOrFailPlus(final ClassNode type, final ASTNode node) {
+        resolveGenericsTypes(type.getGenericsTypes());
+        if (resolveAliasFromModule(type)) return;
+        resolveOrFail(type, node);
+    }
+
+    private void resolveOrFail(final ClassNode type, final ASTNode node) {
+        resolveOrFail(type, "", node);
+    }
+
+    private void resolveOrFail(final ClassNode type, final String msg, final ASTNode node) {
+        if (resolve(type)) return;
+        if (resolveToInner(type)) return;
+        if (resolveToOuterNested(type)) return;
+
+        addError("unable to resolve class " + type.toString(false) + msg, node);
+    }
+
     protected boolean resolveToInner(final ClassNode type) {
         // we do not do our name mangling to find an inner class
         // if the type is a ConstructedClassWithPackage, because in this case we
         // are resolving the name at a different place already
         if (type instanceof ConstructedClassWithPackage) return false;
         if (type instanceof ConstructedNestedClass) return false;
-        String name = type.getName();
-        String saved = name;
-        while (name.lastIndexOf('.') != -1) {
-            name = replaceLastPointWithDollar(name);
-            type.setName(name);
-            if (resolve(type)) {
+
+        // GROOVY-8715
+        ClassNode t = type;
+        while (t.isArray()) {
+            t = t.getComponentType();
+        }
+
+        String name = t.getName(), temp = name;
+        while (temp.lastIndexOf('.') != -1) {
+            temp = replaceLastPointWithDollar(temp);
+            t.setName(temp);
+            if (resolve(t, true, false, false)) {
                 return true;
             }
         }
-
-        type.setName(saved);
+        t.setName(name);
         return false;
     }
 
-    private void resolveOrFail(final ClassNode type, final String msg, final ASTNode node) {
-        if (resolve(type)) return;
-        if (resolveToInner(type)) return;
-        if (resolveToOuterNested(type)) return;
-
-        addError("unable to resolve class " + type.toString(false) + msg, node);
-    }
-
     // GROOVY-7812(#1): Static inner classes cannot be accessed from other files when running by 'groovy' command
     // if the type to resolve is an inner class and it is in an outer class which is not resolved,
     // we set the resolved type to a placeholder class node, i.e. a ConstructedOuterNestedClass instance
@@ -447,16 +462,6 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         return constructedOuterNestedClassNode;
     }
 
-    private void resolveOrFail(final ClassNode type, final ASTNode node, final boolean prefereImports) {
-        resolveGenericsTypes(type.getGenericsTypes());
-        if (prefereImports && resolveAliasFromModule(type)) return;
-        resolveOrFail(type, node);
-    }
-
-    private void resolveOrFail(final ClassNode type, final ASTNode node) {
-        resolveOrFail(type, "", node);
-    }
-
     protected boolean resolve(final ClassNode type) {
         return resolve(type, true, true, true);
     }
@@ -1467,10 +1472,10 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         }
 
         ClassNode sn = node.getUnresolvedSuperClass();
-        if (sn != null) resolveOrFail(sn, node, true);
+        if (sn != null) resolveOrFailPlus(sn, node);
 
         for (ClassNode anInterface : node.getInterfaces()) {
-            resolveOrFail(anInterface, node, true);
+            resolveOrFailPlus(anInterface, node);
         }
 
         checkCyclicInheritance(node, node.getUnresolvedSuperClass(), node.getInterfaces());
diff --git a/src/test/gls/innerClass/InnerClassTest.groovy b/src/test/gls/innerClass/InnerClassTest.groovy
index 81e51d9..f7a2bec 100644
--- a/src/test/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/gls/innerClass/InnerClassTest.groovy
@@ -1216,6 +1216,74 @@ final class InnerClassTest {
         '''
     }
 
+    @Test
+    void testResolveInnerOfSuperType9() {
+        assertScript '''
+            abstract class A {
+                static class B {}
+            }
+
+            def test(A.B[] bees) {
+                assert bees != null
+            }
+
+            test(new A.B[0])
+        '''
+    }
+
+    @Test
+    void testResolveInnerOfSuperType9a() {
+        assertScript '''
+            abstract class A {
+                static class B {}
+            }
+
+            def test(A.B... bees) {
+                assert bees != null
+            }
+
+            test()
+        '''
+    }
+
+    @CompileDynamic @Test // GROOVY-8715
+    void testResolveInnerOfSuperType9b() {
+        def config = new CompilerConfiguration(
+            targetDirectory: File.createTempDir(),
+            jointCompilationOptions: [memStub: true]
+        )
+        def parentDir = File.createTempDir()
+        try {
+            new File(parentDir, 'p').mkdir()
+
+            def a = new File(parentDir, 'p/A.Java')
+            a.write '''
+                package p;
+                public abstract class A {
+                    public interface I {}
+                }
+            '''
+            def b = new File(parentDir, 'p/B.groovy')
+            b.write '''
+                package p
+                def test(A.I... eyes) {
+                    assert eyes != null
+                }
+                test()
+            '''
+
+            def loader = new GroovyClassLoader(this.class.classLoader)
+            def cu = new JavaAwareCompilationUnit(config, loader)
+            cu.addSources(a, b)
+            cu.compile()
+
+            loader.loadClass('p.B').main()
+        } finally {
+            config.targetDirectory.deleteDir()
+            parentDir.deleteDir()
+        }
+    }
+
     @Test // GROOVY-5679, GROOVY-5681
     void testEnclosingMethodIsSet() {
         assertScript '''