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/07/14 11:51:00 UTC

[groovy] branch GROOVY_2_4_X updated: GROOVY-7549: STC: if "=" RHS type is inaccessible, revert to origin type (port to 2_4_X)

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

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


The following commit(s) were added to refs/heads/GROOVY_2_4_X by this push:
     new 6ef55ae  GROOVY-7549: STC: if "=" RHS type is inaccessible, revert to origin type (port to 2_4_X)
6ef55ae is described below

commit 6ef55aef8f8d7878a88d71fd1e3612b949da1735
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Jun 10 12:22:45 2020 -0500

    GROOVY-7549: STC: if "=" RHS type is inaccessible, revert to origin type (port to 2_4_X)
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 22 ++++++++
 .../transform/stc/TypeInferenceSTCTest.groovy      | 59 ++++++++++++++++++++++
 2 files changed, 81 insertions(+)

diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 2b2f6ab..140feba 100644
--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -683,6 +683,19 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
+    private static ClassNode getOutermost(ClassNode cn) {
+        while (cn.getOuterClass() != null) {
+            cn = cn.getOuterClass();
+        }
+        return cn;
+    }
+
+    private static boolean equalPackageNames(ClassNode a, ClassNode b) {
+        String pkgA = a.getPackageName();
+        String pkgB = b.getPackageName();
+        return (pkgA == pkgB) || (pkgA != null && pkgA.equals(pkgB));
+    }
+
     @Override
     public void visitBinaryExpression(BinaryExpression expression) {
         int op = expression.getOperation().getType();
@@ -784,6 +797,15 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 } else if (lType.isUsingGenerics() && !lType.isEnum() && hasRHSIncompleteGenericTypeInfo(resultType)) {
                     // for example, LHS is List<ConcreteClass> and RHS is List<T> where T is a placeholder
                     resultType = lType;
+                } else {
+                    // GROOVY-7549: RHS type may not be accessible to enclosing class
+                    int modifiers = resultType.getModifiers();
+                    ClassNode enclosingType = typeCheckingContext.getEnclosingClassNode();
+                    if (!Modifier.isPublic(modifiers) && !enclosingType.equals(resultType)
+                            && !getOutermost(enclosingType).equals(getOutermost(resultType))
+                            && (Modifier.isPrivate(modifiers) || !equalPackageNames(enclosingType, resultType))) {
+                        resultType = originType; // TODO: Find accesible type in hierarchy of resultType?
+                    }
                 }
 
                 // make sure we keep primitive types
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index d1f61d8..afe34b8 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -20,6 +20,7 @@ package groovy.transform.stc
 
 import org.codehaus.groovy.ast.MethodNode
 import org.codehaus.groovy.control.customizers.CompilationCustomizer
+import org.codehaus.groovy.control.CompilationUnit
 import org.codehaus.groovy.control.CompilePhase
 import org.codehaus.groovy.control.SourceUnit
 import org.codehaus.groovy.classgen.GeneratorContext
@@ -766,6 +767,64 @@ Thing.run()
         '''
     }
 
+    // GROOVY-7549
+    void testShouldKeepDeclTypeWhenAssignedInaccessibleT() {
+        config.targetDirectory = File.createTempDir()
+        def parentDir = File.createTempDir()
+        try {
+            new File(parentDir, 'a').mkdir()
+            new File(parentDir, 'b').mkdir()
+
+            def a = new File(parentDir, 'a/Main.groovy')
+            a.write '''
+                package a
+                class Main {
+                  static main(args) {
+                    Face f = b.Maker.make() // returns b.Impl
+                    assert f.meth() == 1234
+                  }
+                }
+            '''
+            def b = new File(parentDir, 'a/Face.groovy')
+            b.write '''
+                package a
+                interface Face {
+                  int meth()
+                }
+            '''
+            def c = new File(parentDir, 'b/Impl.groovy')
+            c.write '''
+                package b
+                @groovy.transform.PackageScope
+                class Impl implements a.Face {
+                  int meth() {
+                    1234
+                  }
+                }
+            '''
+            def d = new File(parentDir, 'b/Maker.groovy')
+            d.write '''
+                package b
+                class Maker {
+                  static Impl make() { // probably should return a.Face
+                    new Impl()
+                  }
+                }
+            '''
+
+            def loader = new GroovyClassLoader(this.class.classLoader)
+            def cu = new CompilationUnit(config, null, loader)
+            cu.addSources(a, b, c, d)
+            cu.compile()
+
+            loader.addClasspath(config.targetDirectory.absolutePath)
+            loader.loadClass('a.Main', true).main()
+        } finally {
+            config.targetDirectory.deleteDir()
+            parentDir.deleteDir()
+        }
+    }
+
     // GROOVY-6574
     void testShouldInferPrimitiveBoolean() {
         assertScript '''