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

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

commit 2930ead60a3e48977d02593d78242282dfc2ee9b
Author: Eric Milles <[email protected]>
AuthorDate: Thu Sep 19 14:04:14 2024 -0500

    add `getNestHost(ClassNode)`
---
 .../apache/groovy/ast/tools/ClassNodeUtils.java    | 103 +++++++++++++++++----
 .../groovy/classgen/AsmClassGenerator.java         |  13 +--
 .../codehaus/groovy/classgen/GeneratorContext.java |  31 +++----
 .../groovy/classgen/asm/WriterController.java      |   9 +-
 .../classgen/asm/sc/StaticInvocationWriter.java    |  12 +--
 ...icTypesBinaryExpressionMultiTypeDispatcher.java |   4 +-
 .../transform/stc/StaticTypeCheckingVisitor.java   |  12 +--
 7 files changed, 115 insertions(+), 69 deletions(-)

diff --git a/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java 
b/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
index 4020d3dd1a..03e0e9ffcb 100644
--- a/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
+++ b/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
@@ -71,6 +71,8 @@ public class ClassNodeUtils {
      *
      * @param cNode the type to format
      * @return a human-readable version of the type name (java.lang.String[] 
for example)
+     *
+     * @since 2.5.0
      */
     public static String formatTypeName(final ClassNode cNode) {
         if (cNode.isArray()) {
@@ -94,6 +96,8 @@ public class ClassNodeUtils {
      * Returns an existing method if one exists or else create a new method 
and mark it as {@code @Generated}.
      *
      * @see ClassNode#addMethod(String, int, ClassNode, Parameter[], 
ClassNode[], Statement)
+     *
+     * @since 2.5.3
      */
     public static MethodNode addGeneratedMethod(final ClassNode cNode, final 
String name, final int modifiers,
             final ClassNode returnType, final Parameter[] parameters, final 
ClassNode[] exceptions, final Statement code) {
@@ -109,6 +113,8 @@ public class ClassNodeUtils {
      * Adds a method and mark it as {@code @Generated}.
      *
      * @see ClassNode#addMethod(MethodNode)
+     *
+     * @since 2.5.3
      */
     public static void addGeneratedMethod(final ClassNode cNode, final 
MethodNode mNode) {
         cNode.addMethod(mNode);
@@ -119,6 +125,8 @@ public class ClassNodeUtils {
      * Adds a method and mark it as {@code @Generated}.
      *
      * @see ClassNode#addMethod(MethodNode)
+     *
+     * @since 3.0.8
      */
     public static void addGeneratedMethod(final ClassNode cNode, final 
MethodNode mNode, final boolean skipChecks) {
         cNode.addMethod(mNode);
@@ -129,6 +137,8 @@ public class ClassNodeUtils {
      * Adds an inner class that is marked as {@code @Generated}.
      *
      * @see org.codehaus.groovy.ast.ModuleNode#addClass(ClassNode)
+     *
+     * @since 2.5.7
      */
     public static void addGeneratedInnerClass(final ClassNode cNode, final 
ClassNode inner) {
         cNode.getModule().addClass(inner);
@@ -139,6 +149,8 @@ public class ClassNodeUtils {
      * Adds a method that is marked as {@code @Generated}.
      *
      * @see ClassNode#addConstructor(int, Parameter[], ClassNode[], Statement)
+     *
+     * @since 2.5.3
      */
     public static ConstructorNode addGeneratedConstructor(final ClassNode 
classNode, final int modifiers, final Parameter[] parameters, final ClassNode[] 
exceptions, final Statement code) {
         ConstructorNode ctorNode = new ConstructorNode(modifiers, parameters, 
exceptions, code);
@@ -150,6 +162,8 @@ public class ClassNodeUtils {
      * Adds a method that is marked as {@code @Generated}.
      *
      * @see ClassNode#addConstructor(ConstructorNode)
+     *
+     * @since 2.5.3
      */
     public static void addGeneratedConstructor(final ClassNode classNode, 
final ConstructorNode ctorNode) {
         classNode.addConstructor(ctorNode);
@@ -157,10 +171,9 @@ public class ClassNodeUtils {
     }
 
     /**
-     * Adds methods from the super class.
+     * Gets methods from the super class.
      *
-     * @param cNode The ClassNode
-     * @return A map of methods
+     * @since 2.5.0
      */
     public static Map<String, MethodNode> getDeclaredMethodsFromSuper(final 
ClassNode cNode) {
         ClassNode parent = cNode.getSuperClass();
@@ -177,6 +190,8 @@ public class ClassNodeUtils {
      *
      * @param cNode The ClassNode
      * @param methodsMap A map of existing methods to alter
+     *
+     * @since 2.5.0
      */
     public static void addDeclaredMethodsFromInterfaces(final ClassNode cNode, 
final Map<String, MethodNode> methodsMap) {
         for (ClassNode iface : cNode.getInterfaces()) {
@@ -195,6 +210,8 @@ public class ClassNodeUtils {
      *
      * @param cNode The ClassNode
      * @return A map of methods
+     *
+     * @since 2.5.0
      */
     public static Map<String, MethodNode> 
getDeclaredMethodsFromInterfaces(final ClassNode cNode) {
         Map<String, MethodNode> methodsMap = new LinkedHashMap<>();
@@ -208,6 +225,8 @@ public class ClassNodeUtils {
      *
      * @param cNode The ClassNode
      * @param methodsMap A map of existing methods to alter
+     *
+     * @since 2.5.0
      */
     public static void addDeclaredMethodsFromAllInterfaces(final ClassNode 
cNode, final Map<String, MethodNode> methodsMap) {
         List<ClassNode> cnInterfaces = Arrays.asList(cNode.getInterfaces());
@@ -221,14 +240,17 @@ public class ClassNodeUtils {
     }
 
     /**
-     * Returns true if the given method has a possibly matching static method 
with the given name and arguments.
-     * Handles default arguments and optionally spread expressions.
+     * Determines if the given method has a possibly matching static method 
with
+     * the given name and arguments. Handles default arguments and (optionally)
+     * spread expressions.
      *
      * @param cNode     the ClassNode of interest
      * @param name      the name of the method of interest
      * @param arguments the arguments to match against
      * @param trySpread whether to try to account for SpreadExpressions within 
the arguments
      * @return {@code true} if a matching method was found.
+     *
+     * @since 2.5.0
      */
     public static boolean hasPossibleStaticMethod(final ClassNode cNode, final 
String name, final Expression arguments, final boolean trySpread) {
         int count = 0; boolean foundSpread = false;
@@ -290,7 +312,9 @@ public class ClassNodeUtils {
     }
 
     /**
-     * Returns true if we have a static accessor
+     * Determines if the given class has the named static property.
+     *
+     * @since 2.5.0
      */
     public static boolean hasPossibleStaticProperty(final ClassNode cNode, 
final String methodName) {
         // assume explicit static method call checked first so we can assume a 
simple check here
@@ -308,6 +332,8 @@ public class ClassNodeUtils {
      *
      * @param accessorName the accessor name of interest, e.g. getAge
      * @return the property name, e.g. age, or original if not a valid 
property accessor name
+     *
+     * @since 2.5.0
      */
     public static String getPropNameForAccessor(final String accessorName) {
         if (!isValidAccessorName(accessorName)) return accessorName;
@@ -316,10 +342,13 @@ public class ClassNodeUtils {
     }
 
     /**
-     * Detects whether the given accessor name starts with "get", "set" or 
"is" followed by at least one character.
+     * Determines if the given accessor name starts with "get", "set" or "is"
+     * followed by at least one character.
      *
      * @param accessorName the accessor name of interest, e.g. getAge
      * @return true if a valid prefix is found
+     *
+     * @since 2.5.0
      */
     public static boolean isValidAccessorName(final String accessorName) {
         if (accessorName.startsWith("get") || accessorName.startsWith("is") || 
accessorName.startsWith("set")) {
@@ -330,10 +359,9 @@ public class ClassNodeUtils {
     }
 
     /**
-     * Check if the type is declared {@code non-sealed}
+     * Determines if the type is declared {@code non-sealed}.
      *
-     * @param cn the type
-     * @return the check result
+     * @since 5.0.0
      */
     public static boolean isNonSealed(final ClassNode cn) {
         if (cn instanceof DecompiledClassNode) {
@@ -355,6 +383,11 @@ public class ClassNodeUtils {
         return superClass.isSealed() && !(isFinal(cn.getModifiers()) || 
cn.isSealed());
     }
 
+    /**
+     * Determines if the given class has the named static property.
+     *
+     * @since 2.5.0
+     */
     public static boolean hasStaticProperty(final ClassNode cNode, final 
String propName) {
         PropertyNode found = getStaticProperty(cNode, propName);
         if (found == null) {
@@ -366,12 +399,13 @@ public class ClassNodeUtils {
     }
 
     /**
-     * Detects whether a static property with the given name is within the 
class
-     * or a super class.
+     * Finds static property within the class or super class.
      *
      * @param cNode the ClassNode of interest
      * @param propName the property name
      * @return the static property if found or else null
+     *
+     * @since 2.5.0
      */
     public static PropertyNode getStaticProperty(final ClassNode cNode, final 
String propName) {
         ClassNode classNode = cNode;
@@ -387,17 +421,33 @@ public class ClassNodeUtils {
     }
 
     /**
-     * Detects whether a given ClassNode is an inner class (non-static).
+     * Returns the nest host of the given class, which may be the class itself.
+     *
+     * @since 5.0.0
+     */
+    public static ClassNode getNestHost(ClassNode cNode) {
+        while (cNode.getOuterClass() != null) {
+            cNode = cNode.getOuterClass();
+        }
+        return cNode;
+    }
+
+    /**
+     * Determines if the given ClassNode is a non-static inner class.
      *
      * @param cNode the ClassNode of interest
      * @return true if the given node is a (non-static) inner class, else false
+     *
+     * @since 2.5.0
      */
     public static boolean isInnerClass(final ClassNode cNode) {
         return cNode.getOuterClass() != null && 
!Modifier.isStatic(cNode.getModifiers());
     }
 
     /**
-     * Checks if the source ClassNode is compatible with the target ClassNode
+     * Determines if the source ClassNode is compatible with the target 
ClassNode.
+     *
+     * @since 4.0.0
      */
     public static boolean isCompatibleWith(ClassNode source, ClassNode target) 
{
         if (source.equals(target)) return true;
@@ -411,6 +461,11 @@ public class ClassNodeUtils {
                 && (source.isDerivedFrom(target) || 
source.implementsInterface(target));
     }
 
+    /**
+     * Determines if the given ClassNode declares a zero argument constructor.
+     *
+     * @since 2.5.0
+     */
     public static boolean hasNoArgConstructor(final ClassNode cNode) {
         List<ConstructorNode> constructors = cNode.getDeclaredConstructors();
         for (ConstructorNode next : constructors) {
@@ -422,11 +477,13 @@ public class ClassNodeUtils {
     }
 
     /**
-     * Determines if an explicit (non-generated) constructor is in the class.
+     * Determines if the given ClassNode declares an explicit (non-generated) 
constructor.
      *
      * @param xform if non-null, add an error if an explicit constructor is 
found
      * @param cNode the type of the containing class
      * @return true if an explicit (non-generated) constructor was found
+     *
+     * @since 2.5.0
      */
     public static boolean hasExplicitConstructor(final 
AbstractASTTransformation xform, final ClassNode cNode) {
         List<ConstructorNode> declaredConstructors = 
cNode.getDeclaredConstructors();
@@ -451,7 +508,8 @@ public class ClassNodeUtils {
      * @param first a ClassNode
      * @param second a ClassNode
      * @return true if both given nodes have the same package name
-     * @throws NullPointerException if either of the given nodes are null
+     *
+     * @since 2.5.0
      */
     public static boolean samePackageName(final ClassNode first, final 
ClassNode second) {
         return Objects.equals(first.getPackageName(), second.getPackageName());
@@ -524,10 +582,15 @@ public class ClassNodeUtils {
         return null;
     }
 
-    public static boolean isSubtype(final ClassNode 
maybeSuperclassOrInterface, final ClassNode candidateChild) {
-        return maybeSuperclassOrInterface.isInterface() || 
candidateChild.isInterface()
-                ? isOrImplements(candidateChild, maybeSuperclassOrInterface)
-                : candidateChild.isDerivedFrom(maybeSuperclassOrInterface);
+    /**
+     * Determines if given class is, extends or implements a class or 
interface.
+     *
+     * @since 4.0.16
+     */
+    public static boolean isSubtype(final ClassNode 
maybeExtendedOrImplemented, final ClassNode cNode) {
+        return maybeExtendedOrImplemented.isInterface() || cNode.isInterface()
+                ? isOrImplements(cNode, maybeExtendedOrImplemented)
+                : cNode.isDerivedFrom(maybeExtendedOrImplemented);
     }
 
     
//--------------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java 
b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index b25c542500..da58703feb 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -134,6 +134,7 @@ import java.util.Optional;
 import java.util.function.Consumer;
 
 import static org.apache.groovy.ast.tools.ClassNodeUtils.getField;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.getNestHost;
 import static org.apache.groovy.ast.tools.ExpressionUtils.isNullConstant;
 import static org.apache.groovy.ast.tools.ExpressionUtils.isSuperExpression;
 import static org.codehaus.groovy.ast.ClassHelper.isClassType;
@@ -329,7 +330,7 @@ public class AsmClassGenerator extends ClassGenerator {
             if (classNode instanceof InnerClassNode && !(classNode instanceof 
InterfaceHelperClassNode)) {
                 makeInnerClassEntry(classNode); // GROOVY-4649, et al.
 
-                ClassNode nestHost = controller.getOutermostClass(); // 
GROOVY-10687
+                ClassNode nestHost = getNestHost(classNode); // GROOVY-10687
                 
classVisitor.visitNestHost(BytecodeHelper.getClassInternalName(nestHost));
 
                 MethodNode enclosingMethod = classNode.getEnclosingMethod();
@@ -379,7 +380,7 @@ public class AsmClassGenerator extends ClassGenerator {
             }
             // GROOVY-10687
             if (classNode.getOuterClass() == null && 
classNode.getInnerClasses().hasNext()) {
-                makeNestMatesEntries(classNode);
+                makeNestmateEntries(classNode);
             }
             // GROOVY-4649, GROOVY-6750, GROOVY-6808
             for (Iterator<InnerClassNode> it = classNode.getInnerClasses(); 
it.hasNext(); ) {
@@ -451,11 +452,11 @@ public class AsmClassGenerator extends ClassGenerator {
         classVisitor.visitInnerClass(innerClassInternalName, 
outerClassInternalName, innerClassName, modifiers);
     }
 
-    private void makeNestMatesEntries(final ClassNode classNode) {
+    private void makeNestmateEntries(final ClassNode classNode) {
         for (Iterator<InnerClassNode> it = classNode.getInnerClasses(); 
it.hasNext(); ) {
             ClassNode innerClass = it.next();
             
classVisitor.visitNestMember(BytecodeHelper.getClassInternalName(innerClass));
-            makeNestMatesEntries(innerClass);
+            makeNestmateEntries(innerClass);
         }
     }
 
@@ -1048,8 +1049,8 @@ public class AsmClassGenerator extends ClassGenerator {
     }
 
     /**
-     * Determines if the given class can directly access the given field (via
-     * {@code GETFIELD}, {@code GETSTATIC}, etc. bytecode instructions).
+     * Determines if the given field can be directly accessed by the given 
class
+     * (via {@code GETFIELD}, {@code GETSTATIC}, etc. bytecode instructions).
      */
     public static boolean isFieldDirectlyAccessible(final FieldNode field, 
final ClassNode accessingClass) {
         return field != null && 
isMemberDirectlyAccessible(field.getModifiers(), field.getDeclaringClass(), 
accessingClass);
diff --git a/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java 
b/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
index 72d6f485d6..fcd115a280 100644
--- a/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
+++ b/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
@@ -34,11 +34,11 @@ public class GeneratorContext {
     private int syntheticMethodIdx = 0;
     private final CompileUnit compileUnit;
 
-    public GeneratorContext(CompileUnit compileUnit) {
+    public GeneratorContext(final CompileUnit compileUnit) {
         this.compileUnit = compileUnit;
     }
 
-    public GeneratorContext(CompileUnit compileUnit, int innerClassOffset) {
+    public GeneratorContext(final CompileUnit compileUnit, final int 
innerClassOffset) {
         this.compileUnit = compileUnit;
         this.innerClassIdx = innerClassOffset;
     }
@@ -51,30 +51,23 @@ public class GeneratorContext {
         return compileUnit;
     }
 
-    public String getNextClosureInnerName(ClassNode owner, ClassNode 
enclosingClass, MethodNode enclosingMethod) {
-        return getNextInnerName(owner, enclosingClass, enclosingMethod, 
"closure");
+    public String getNextClosureInnerName(final ClassNode owner, final 
ClassNode enclosingClass, final MethodNode enclosingMethod) {
+        return getNextInnerName(enclosingClass, enclosingMethod, "closure");
     }
 
-    public String getNextLambdaInnerName(ClassNode owner, ClassNode 
enclosingClass, MethodNode enclosingMethod) {
-        return getNextInnerName(owner, enclosingClass, enclosingMethod, 
"lambda");
+    public String getNextLambdaInnerName(final ClassNode owner, final 
ClassNode enclosingClass, final MethodNode enclosingMethod) {
+        return getNextInnerName(enclosingClass, enclosingMethod, "lambda");
     }
 
-    private String getNextInnerName(ClassNode owner, ClassNode enclosingClass, 
MethodNode enclosingMethod, String classifier) {
-        String methodName = "";
-        if (enclosingMethod != null) {
-            methodName = enclosingMethod.getName();
-
-            if (enclosingClass.isDerivedFrom(ClassHelper.CLOSURE_TYPE)) {
-                methodName = "";
-            } else {
-                methodName = "_" + encodeAsValidClassName(methodName);
-            }
+    private String getNextInnerName(final ClassNode enclosingClass, final 
MethodNode enclosingMethod, final String classifier) {
+        String typeName = "_" + classifier + closureClassIdx++;
+        if (enclosingMethod != null && 
!ClassHelper.isGeneratedFunction(enclosingClass)) {
+            typeName = "_" + encodeAsValidClassName(enclosingMethod.getName()) 
+ typeName;
         }
-
-        return methodName + "_" + classifier + closureClassIdx++;
+        return typeName;
     }
 
-    public String getNextConstructorReferenceSyntheticMethodName(MethodNode 
enclosingMethodNode) {
+    public String getNextConstructorReferenceSyntheticMethodName(final 
MethodNode enclosingMethodNode) {
         return "ctorRef$"
                 + (null == enclosingMethodNode
                         ? ""
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java 
b/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java
index d81897aec2..dfa8b1ec53 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java
@@ -39,6 +39,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
+import static org.apache.groovy.ast.tools.ClassNodeUtils.getNestHost;
 import static org.codehaus.groovy.ast.ClassHelper.isGeneratedFunction;
 
 public class WriterController {
@@ -57,7 +58,6 @@ public class WriterController {
     private UnaryExpressionHelper unaryExpressionHelper, 
fastPathUnaryExpressionHelper;
     private AssertionWriter assertionWriter;
     private String internalBaseClassName;
-    private ClassNode outermostClass;
     private MethodNode methodNode;
     private ConstructorNode constructorNode;
     private GeneratorContext context;
@@ -91,7 +91,6 @@ public class WriterController {
         if (invokedynamic) this.optimizeForInt = false;
 
         this.classNode = cn;
-        this.outermostClass = null;
         this.internalClassName = BytecodeHelper.getClassInternalName(cn);
 
         this.bytecodeVersion = config.getBytecodeVersion();
@@ -288,11 +287,7 @@ public class WriterController {
     }
 
     public ClassNode getOutermostClass() {
-        if (outermostClass == null) {
-            List<ClassNode> outers = classNode.getOuterClasses();
-            outermostClass = !outers.isEmpty() ? outers.get(outers.size() - 1) 
: classNode;
-        }
-        return outermostClass;
+        return getNestHost(classNode);
     }
 
     public String getInternalClassName() {
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
index 8cf40bc7f8..e9198ca39e 100644
--- 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
+++ 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
@@ -74,6 +74,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
 import static org.apache.groovy.ast.tools.ClassNodeUtils.formatTypeName;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.isSubtype;
 import static org.apache.groovy.ast.tools.ClassNodeUtils.samePackageName;
 import static org.apache.groovy.ast.tools.ExpressionUtils.isNullConstant;
 import static org.apache.groovy.ast.tools.ExpressionUtils.isSuperExpression;
@@ -229,7 +230,7 @@ public class StaticInvocationWriter extends 
InvocationWriter {
         } else {
             thisExpr = varX("thisObject", thisType);
             // adjust for multiple levels of nesting
-            while (!thisType.isDerivedFrom(target) && 
!thisType.implementsInterface(target)) {
+            while (!isSubtype(target, thisType)) {
                 FieldNode thisZero = thisType.getDeclaredField("this$0");
                 if (thisZero != null) {
                     thisExpr = attrX(thisExpr, "this$0");
@@ -258,7 +259,7 @@ public class StaticInvocationWriter extends 
InvocationWriter {
         ClassNode lookupClassNode;
         if (target.isProtected()) {
             lookupClassNode = controller.getClassNode();
-            while (lookupClassNode != null && 
!lookupClassNode.isDerivedFrom(target.getDeclaringClass())) {
+            while (lookupClassNode != null && 
!isSubtype(target.getDeclaringClass(), lookupClassNode)) {
                 lookupClassNode = lookupClassNode.getOuterClass();
             }
             if (lookupClassNode == null) {
@@ -273,7 +274,7 @@ public class StaticInvocationWriter extends 
InvocationWriter {
             Expression newReceiver = receiver;
             if (implicitThis) {
                 if (!controller.isInGeneratedFunction()) {
-                    if (!thisClass.isDerivedFrom(lookupClassNode))
+                    if (!isSubtype(lookupClassNode, thisClass))
                         newReceiver = propX(classX(lookupClassNode), "this");
                 } else if (thisClass != null) {
                     newReceiver = thisObjectExpression(thisClass, 
lookupClassNode);
@@ -367,14 +368,13 @@ public class StaticInvocationWriter extends 
InvocationWriter {
             if (!implicitThis && !isThisOrSuper(receiver) && 
!samePackageName(node, classNode)
                     && 
StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(node, 
target.getDeclaringClass())) {
                 writeMethodAccessError(target, receiver != null ? receiver : 
args);
-            } else if (!node.isDerivedFrom(target.getDeclaringClass()) && 
tryBridgeMethod(target, receiver, implicitThis, args, classNode)) {
+            } else if (!isSubtype(target.getDeclaringClass(), node) && 
tryBridgeMethod(target, receiver, implicitThis, args, classNode)) {
                 return true;
             }
         } else if (target.isPublic() && receiver != null) {
             if (implicitThis
                     && controller.isInGeneratedFunction()
-                    && !classNode.isDerivedFrom(target.getDeclaringClass())
-                    && 
!classNode.implementsInterface(target.getDeclaringClass())) {
+                    && !isSubtype(target.getDeclaringClass(), classNode)) {
                 fixedReceiver = thisObjectExpression(classNode, 
target.getDeclaringClass());
                 if (!(fixedReceiver instanceof VariableExpression)) 
fixedImplicitThis = false;
             }
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
index 0a3d79666f..325c685814 100644
--- 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
+++ 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
@@ -352,8 +352,8 @@ public class StaticTypesBinaryExpressionMultiTypeDispatcher 
extends BinaryExpres
                 MethodCallExpression mce = callThisX("getThisObject");
                 mce.setImplicitThis(true);
                 mce.setMethodTarget(CLOSURE_GETTHISOBJECT_METHOD);
-                mce.putNodeMetaData(INFERRED_TYPE, 
controller.getOutermostClass());
-                pexp = castX(controller.getOutermostClass(), mce);
+                mce.putNodeMetaData(INFERRED_TYPE, controller.getThisType());
+                pexp = castX(controller.getThisType(), mce);
             } else {
                 pexp = propX(classX(outerClass), "this");
                 ((PropertyExpression) pexp).setImplicitThis(true);
diff --git 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index f2a9c0032c..2d46571a71 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -145,6 +145,7 @@ import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
+import static org.apache.groovy.ast.tools.ClassNodeUtils.getNestHost;
 import static 
org.apache.groovy.ast.tools.MethodNodeUtils.withDefaultArgumentMethods;
 import static org.apache.groovy.util.BeanUtils.capitalize;
 import static org.apache.groovy.util.BeanUtils.decapitalize;
@@ -578,13 +579,6 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         }
     }
 
-    private static ClassNode getOutermost(ClassNode cn) {
-        while (cn.getOuterClass() != null) {
-            cn = cn.getOuterClass();
-        }
-        return cn;
-    }
-
     private static void addPrivateFieldOrMethodAccess(final Expression source, 
final ClassNode cn, final StaticTypesMarker key, final ASTNode accessedMember) {
         cn.getNodeMetaData(key, x -> new 
LinkedHashSet<>()).add(accessedMember);
         source.putNodeMetaData(key, accessedMember);
@@ -597,7 +591,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         if (fn != null && fn.isPrivate() && !fn.isSynthetic()) {
             ClassNode declaringClass = fn.getDeclaringClass();
             ClassNode enclosingClass = 
typeCheckingContext.getEnclosingClassNode();
-            if (declaringClass == enclosingClass ? 
typeCheckingContext.getEnclosingClosure() != null : 
getOutermost(declaringClass) == getOutermost(enclosingClass)) {
+            if (declaringClass == enclosingClass ? 
typeCheckingContext.getEnclosingClosure() != null : getNestHost(declaringClass) 
== getNestHost(enclosingClass)) {
                 StaticTypesMarker accessKind = lhsOfAssignment ? 
PV_FIELDS_MUTATION : PV_FIELDS_ACCESS;
                 addPrivateFieldOrMethodAccess(source, declaringClass, 
accessKind, fn);
             }
@@ -920,7 +914,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                     int modifiers = resultType.getModifiers();
                     ClassNode enclosingType = 
typeCheckingContext.getEnclosingClassNode();
                     if (!Modifier.isPublic(modifiers) && 
!enclosingType.equals(resultType)
-                            && 
!getOutermost(enclosingType).equals(getOutermost(resultType))
+                            && 
!getNestHost(enclosingType).equals(getNestHost(resultType))
                             && (Modifier.isPrivate(modifiers) || 
!inSamePackage(enclosingType, resultType))) {
                         resultType = originType; // TODO: Find accessible type 
in hierarchy of resultType?
                     } else if 
(GenericsUtils.hasUnresolvedGenerics(resultType)) { // GROOVY-9033, 
GROOVY-10089, et al.

Reply via email to