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 2019/04/08 12:59:01 UTC

[groovy] 09/20: Support class::staticMethod, instance::instanceMethod and instance::staticMethod

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

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

commit 091c349a175e50a51fd26741d8dfe9fa015226b6
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sat Mar 9 20:50:49 2019 +0800

    Support class::staticMethod, instance::instanceMethod and instance::staticMethod
---
 .../codehaus/groovy/ast/tools/ParameterUtils.java  |  21 ++++-
 .../asm/sc/AbstractFunctionInterfaceWriter.java    |  16 +++-
 .../classgen/asm/sc/StaticTypesLambdaWriter.java   |  19 +---
 ...StaticTypesMethodReferenceExpressionWriter.java | 101 ++++++++++++++++-----
 .../transform/stc/StaticTypeCheckingSupport.java   |  71 +++++++++++++++
 .../transform/stc/StaticTypeCheckingVisitor.java   |  63 +------------
 .../transform/stc/MethodReferenceTest.groovy       |  73 ++++++++++++++-
 7 files changed, 261 insertions(+), 103 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/tools/ParameterUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/ParameterUtils.java
index 4edf92e..e9245bf 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/ParameterUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/ParameterUtils.java
@@ -20,14 +20,33 @@
 
 package org.codehaus.groovy.ast.tools;
 
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.Parameter;
 
 public class ParameterUtils {
     public static boolean parametersEqual(Parameter[] a, Parameter[] b) {
+        return parametersEqual(a, b, false);
+    }
+
+
+    public static boolean parametersEqualWithWrapperType(Parameter[] a, Parameter[] b) {
+        return parametersEqual(a, b, true);
+    }
+
+    private static boolean parametersEqual(Parameter[] a, Parameter[] b, boolean wrapType) {
         if (a.length == b.length) {
             boolean answer = true;
             for (int i = 0; i < a.length; i++) {
-                if (!a[i].getType().equals(b[i].getType())) {
+                ClassNode aType = a[i].getType();
+                ClassNode bType = b[i].getType();
+
+                if (wrapType) {
+                    aType = ClassHelper.getWrapper(aType);
+                    bType = ClassHelper.getWrapper(bType);
+                }
+
+                if (!aType.equals(bType)) {
                     answer = false;
                     break;
                 }
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/AbstractFunctionInterfaceWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/AbstractFunctionInterfaceWriter.java
index e74eea3..4cfeef9 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/AbstractFunctionInterfaceWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/AbstractFunctionInterfaceWriter.java
@@ -28,6 +28,7 @@ import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 
 import java.util.Arrays;
+import java.util.List;
 
 import static org.codehaus.groovy.transform.stc.StaticTypesMarker.INFERRED_FUNCTIONAL_INTERFACE_TYPE;
 import static org.codehaus.groovy.transform.stc.StaticTypesMarker.PARAMETER_TYPE;
@@ -66,13 +67,13 @@ public interface AbstractFunctionInterfaceWriter {
         );
     }
 
-    default Object[] createBootstrapMethodArguments(String abstractMethodDesc, ClassNode methodOwnerClassNode, MethodNode methodNode) {
+    default Object[] createBootstrapMethodArguments(String abstractMethodDesc, int insn, ClassNode methodOwnerClassNode, MethodNode methodNode) {
         Parameter[] parameters = methodNode.getNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE);
 
         return new Object[]{
                 Type.getType(abstractMethodDesc),
                 new Handle(
-                        Opcodes.H_INVOKEVIRTUAL,
+                        insn,
                         BytecodeHelper.getClassInternalName(methodOwnerClassNode.getName()),
                         methodNode.getName(),
                         BytecodeHelper.getMethodDescriptor(methodNode),
@@ -81,4 +82,15 @@ public interface AbstractFunctionInterfaceWriter {
                 Type.getType(BytecodeHelper.getMethodDescriptor(methodNode.getReturnType(), parameters))
         };
     }
+
+    default Parameter prependParameter(List<Parameter> methodParameterList, String parameterName, ClassNode parameterType) {
+        Parameter parameter = new Parameter(parameterType, parameterName);
+
+        parameter.setOriginType(parameterType);
+        parameter.setClosureSharedVariable(false);
+
+        methodParameterList.add(0, parameter);
+
+        return parameter;
+    }
 }
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
index 75949ad..8978061 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
@@ -42,10 +42,8 @@ import org.codehaus.groovy.classgen.asm.WriterControllerFactory;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
 import org.codehaus.groovy.transform.stc.StaticTypesMarker;
-import org.objectweb.asm.Handle;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
 
 import java.util.Arrays;
 import java.util.HashMap;
@@ -117,7 +115,7 @@ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFun
                 abstractMethodNode.getName(),
                 createAbstractMethodDesc(functionalInterfaceType, lambdaWrapperClassNode),
                 createBootstrapMethod(isInterface),
-                createBootstrapMethodArguments(abstractMethodDesc, lambdaWrapperClassNode, syntheticLambdaMethodNode)
+                createBootstrapMethodArguments(abstractMethodDesc, Opcodes.H_INVOKEVIRTUAL, lambdaWrapperClassNode, syntheticLambdaMethodNode)
         );
         operandStack.replace(redirect, 2);
     }
@@ -175,13 +173,13 @@ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFun
         return lambdaSharedVariableParameters;
     }
 
-    private String createAbstractMethodDesc(ClassNode parameterType, ClassNode lambdaClassNode) {
+    private String createAbstractMethodDesc(ClassNode functionalInterfaceType, ClassNode lambdaClassNode) {
         List<Parameter> lambdaSharedVariableList = new LinkedList<>();
 
         prependEnclosingThis(lambdaSharedVariableList);
         prependParameter(lambdaSharedVariableList, LAMBDA_THIS, lambdaClassNode);
 
-        return BytecodeHelper.getMethodDescriptor(parameterType.redirect(), lambdaSharedVariableList.toArray(Parameter.EMPTY_ARRAY));
+        return BytecodeHelper.getMethodDescriptor(functionalInterfaceType.redirect(), lambdaSharedVariableList.toArray(Parameter.EMPTY_ARRAY));
     }
 
     public ClassNode getOrAddLambdaClass(LambdaExpression expression, int mods, MethodNode abstractMethodNode) {
@@ -267,17 +265,6 @@ public class StaticTypesLambdaWriter extends LambdaWriter implements AbstractFun
         return prependParameter(methodParameterList, ENCLOSING_THIS, controller.getClassNode().getPlainNodeReference());
     }
 
-    private Parameter prependParameter(List<Parameter> methodParameterList, String parameterName, ClassNode parameterType) {
-        Parameter parameter = new Parameter(parameterType, parameterName);
-
-        parameter.setOriginType(parameterType);
-        parameter.setClosureSharedVariable(false);
-
-        methodParameterList.add(0, parameter);
-
-        return parameter;
-    }
-
     private Parameter[] createParametersWithExactType(LambdaExpression expression) {
         Parameter[] parameters = expression.getParameters();
         if (parameters == null) {
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
index a64b604..8ccc619 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
@@ -19,23 +19,33 @@
 package org.codehaus.groovy.classgen.asm.sc;
 
 import groovy.lang.GroovyRuntimeException;
+import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MethodReferenceExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.ast.tools.GeneralUtils;
 import org.codehaus.groovy.ast.tools.ParameterUtils;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
+import org.codehaus.groovy.classgen.asm.BytecodeVariable;
+import org.codehaus.groovy.classgen.asm.CompileStack;
 import org.codehaus.groovy.classgen.asm.MethodReferenceExpressionWriter;
+import org.codehaus.groovy.classgen.asm.OperandStack;
 import org.codehaus.groovy.classgen.asm.WriterController;
 import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
 
 import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
+import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.filterMethodsByVisibility;
 import static org.codehaus.groovy.transform.stc.StaticTypesMarker.CLOSURE_ARGUMENTS;
 
 /**
@@ -43,6 +53,8 @@ import static org.codehaus.groovy.transform.stc.StaticTypesMarker.CLOSURE_ARGUME
  * @since 3.0.0
  */
 public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceExpressionWriter implements AbstractFunctionInterfaceWriter {
+    private static final String MR_EXPR_INSTANCE = "__MR_EXPR_INSTANCE";
+
     public StaticTypesMethodReferenceExpressionWriter(WriterController controller) {
         super(controller);
     }
@@ -59,28 +71,72 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
         ClassNode classNode = controller.getClassNode();
         boolean isInterface = classNode.isInterface();
 
-        ClassNode mrExpressionType = methodReferenceExpression.getExpression().getType();
+        Expression mrExpr = methodReferenceExpression.getExpression();
+        ClassNode mrExprType = mrExpr.getType();
         String mrMethodName = methodReferenceExpression.getMethodName().getText();
 
 
         ClassNode[] methodReferenceParamTypes = methodReferenceExpression.getNodeMetaData(CLOSURE_ARGUMENTS);
         Parameter[] parametersWithExactType = createParametersWithExactType(abstractMethodNode, methodReferenceParamTypes);
-        MethodNode mrMethodNode = findMrMethodNode(mrMethodName, parametersWithExactType, mrExpressionType);
+        MethodNode mrMethodNode = findMrMethodNode(mrMethodName, parametersWithExactType, mrExpr);
 
         if (null == mrMethodNode) {
-            throw new GroovyRuntimeException("Failed to find the expected method[" + mrMethodName + "] in type[" + mrExpressionType.getName() + "]");
+            throw new GroovyRuntimeException("Failed to find the expected method["
+                    + mrMethodName + "(" + Arrays.asList(parametersWithExactType) + ")] in type[" + mrExprType.getName() + "]");
         }
 
         mrMethodNode.putNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE, parametersWithExactType);
-
         MethodVisitor mv = controller.getMethodVisitor();
+
+        boolean isClassExpr = isClassExpr(mrExpr);
+        if (!isClassExpr) {
+            if (mrMethodNode.isStatic()) {
+                ClassExpression classExpression = new ClassExpression(mrExprType);
+                classExpression.setSourcePosition(mrExpr);
+                mrExpr = classExpression;
+            }
+
+            if (mrExpr instanceof VariableExpression) {
+                VariableExpression variableExpression = (VariableExpression) mrExpr;
+
+                OperandStack operandStack = controller.getOperandStack();
+                CompileStack compileStack = controller.getCompileStack();
+                BytecodeVariable variable = compileStack.getVariable(variableExpression.getName(), true);
+
+                operandStack.loadOrStoreVariable(variable, variableExpression.isUseReferenceDirectly());
+            } else if (mrExpr instanceof ClassExpression) {
+                // DO NOTHING
+            } else {
+                throw new GroovyBugError("TODO: " + mrExpr.getClass());
+            }
+        }
+
         mv.visitInvokeDynamicInsn(
                 abstractMethodNode.getName(),
-                BytecodeHelper.getMethodDescriptor(redirect, Parameter.EMPTY_ARRAY),
+                createAbstractMethodDesc(functionalInterfaceType, mrExpr),
                 createBootstrapMethod(isInterface),
-                createBootstrapMethodArguments(abstractMethodDesc, mrExpressionType, mrMethodNode));
+                createBootstrapMethodArguments(abstractMethodDesc, mrMethodNode.isStatic() ? Opcodes.H_INVOKESTATIC : Opcodes.H_INVOKEVIRTUAL, mrExprType, mrMethodNode));
+
+        if (isClassExpr) {
+            controller.getOperandStack().push(redirect);
+        } else {
+            controller.getOperandStack().replace(redirect, 1);
+        }
+    }
 
-        controller.getOperandStack().push(redirect);
+    private boolean isClassExpr(Expression mrExpr) {
+        return mrExpr instanceof ClassExpression;
+    }
+
+    private String createAbstractMethodDesc(ClassNode functionalInterfaceType, Expression mrExpr) {
+        List<Parameter> methodReferenceSharedVariableList = new LinkedList<>();
+
+        if (!(isClassExpr(mrExpr))) {
+            ClassNode mrExprInstanceType = mrExpr.getType();
+            prependParameter(methodReferenceSharedVariableList, MR_EXPR_INSTANCE, mrExprInstanceType);
+        }
+
+        return BytecodeHelper.getMethodDescriptor(functionalInterfaceType.redirect(), methodReferenceSharedVariableList.toArray(Parameter.EMPTY_ARRAY));
     }
 
     private Parameter[] createParametersWithExactType(MethodNode abstractMethodNode, ClassNode[] inferredParameterTypes) {
@@ -111,24 +167,16 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
         return parameters;
     }
 
-    private MethodNode findMrMethodNode(String mrMethodName, Parameter[] abstractMethodParameters, ClassNode mrExpressionType) {
-        List<MethodNode> methodNodeList = mrExpressionType.getMethods(mrMethodName);
+    private MethodNode findMrMethodNode(String mrMethodName, Parameter[] abstractMethodParameters, Expression mrExpr) {
+        ClassNode mrExprType = mrExpr.getType();
+        List<MethodNode> methodNodeList = mrExprType.getMethods(mrMethodName);
         ClassNode classNode = controller.getClassNode();
 
         MethodNode mrMethodNode = null;
-        for (MethodNode mn : methodNodeList) {
-            if (mn.isPrivate() && !mrExpressionType.getName().equals(classNode.getName())) {
-                continue;
-            }
-            if ((mn.isPackageScope() || mn.isProtected()) && !mrExpressionType.getPackageName().equals(classNode.getPackageName())) {
-                continue;
-            }
-            if (mn.isProtected() && !classNode.isDerivedFrom(mrExpressionType)) {
-                continue;
-            }
+        for (MethodNode mn : filterMethodsByVisibility(methodNodeList, classNode)) {
 
             if (mn.isStatic()) {
-                if (ParameterUtils.parametersEqual(mn.getParameters(), abstractMethodParameters)) {
+                if (ParameterUtils.parametersEqualWithWrapperType(mn.getParameters(), abstractMethodParameters)) {
                     mrMethodNode = mn;
                     break;
                 }
@@ -136,7 +184,18 @@ public class StaticTypesMethodReferenceExpressionWriter extends MethodReferenceE
                 if (0 == abstractMethodParameters.length) {
                     break;
                 }
-                if (ParameterUtils.parametersEqual(mn.getParameters(), new ArrayList<>(Arrays.asList(abstractMethodParameters)).subList(1, abstractMethodParameters.length).toArray(Parameter.EMPTY_ARRAY))) {
+
+                Parameter[] parameters;
+                if (isClassExpr(mrExpr)) {
+                    parameters =
+                            new ArrayList<>(Arrays.asList(abstractMethodParameters))
+                                    .subList(1, abstractMethodParameters.length)
+                                    .toArray(Parameter.EMPTY_ARRAY);
+                } else {
+                    parameters = abstractMethodParameters;
+                }
+
+                if (ParameterUtils.parametersEqualWithWrapperType(mn.getParameters(), parameters)) {
                     mrMethodNode = mn;
                     break;
                 }
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index d6ba828..d4df7be 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -23,6 +23,7 @@ import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.Variable;
@@ -75,6 +76,7 @@ import java.util.regex.Matcher;
 
 import static java.lang.Math.min;
 import static org.apache.groovy.ast.tools.ClassNodeUtils.addGeneratedMethod;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.samePackageName;
 import static org.codehaus.groovy.ast.ClassHelper.BigDecimal_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.BigInteger_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.Boolean_TYPE;
@@ -111,6 +113,7 @@ import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.void_WRAPPER_TYPE;
 import static org.codehaus.groovy.ast.GenericsType.GenericsTypeName;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.getSuperClass;
+import static org.codehaus.groovy.runtime.DefaultGroovyMethods.asBoolean;
 import static org.codehaus.groovy.syntax.Types.ASSIGN;
 import static org.codehaus.groovy.syntax.Types.BITWISE_AND;
 import static org.codehaus.groovy.syntax.Types.BITWISE_AND_EQUAL;
@@ -2084,6 +2087,74 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     /**
+     * Filter methods according to visibility
+     *
+     * @param methodNodeList method nodes to filter
+     * @param enclosingClassNode the enclosing class
+     * @return filtered method nodes
+     * @since 3.0.0
+     */
+    public static List<MethodNode> filterMethodsByVisibility(List<MethodNode> methodNodeList, ClassNode enclosingClassNode) {
+        if (!asBoolean(methodNodeList)) {
+            return StaticTypeCheckingVisitor.EMPTY_METHODNODE_LIST;
+        }
+
+        List<MethodNode> result = new LinkedList<>();
+
+        boolean isEnclosingInnerClass = enclosingClassNode instanceof InnerClassNode;
+        List<ClassNode> outerClasses = enclosingClassNode.getOuterClasses();
+
+        outer:
+        for (MethodNode methodNode : methodNodeList) {
+            if (methodNode instanceof ExtensionMethodNode) {
+                result.add(methodNode);
+                continue;
+            }
+
+            ClassNode declaringClass = methodNode.getDeclaringClass();
+
+            if (isEnclosingInnerClass) {
+                for (ClassNode outerClass : outerClasses) {
+                    if (outerClass.isDerivedFrom(declaringClass)) {
+                        if (outerClass.equals(declaringClass)) {
+                            result.add(methodNode);
+                            continue outer;
+                        } else {
+                            if (methodNode.isPublic() || methodNode.isProtected()) {
+                                result.add(methodNode);
+                                continue outer;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (declaringClass instanceof InnerClassNode) {
+                if (declaringClass.getOuterClasses().contains(enclosingClassNode)) {
+                    result.add(methodNode);
+                    continue;
+                }
+            }
+
+            if (methodNode.isPrivate() && !enclosingClassNode.equals(declaringClass)) {
+                continue;
+            }
+            if (methodNode.isProtected()
+                    && !enclosingClassNode.isDerivedFrom(declaringClass)
+                    && !samePackageName(enclosingClassNode, declaringClass)) {
+                continue;
+            }
+            if (methodNode.isPackageScope() && !samePackageName(enclosingClassNode, declaringClass)) {
+                continue;
+            }
+
+            result.add(methodNode);
+        }
+
+        return result;
+    }
+
+    /**
      * A DGM-like method which adds support for method calls which are handled
      * specifically by the Groovy compiler.
      */
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 4deb064..25f6e5f 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -130,7 +130,6 @@ import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 
-import static org.apache.groovy.ast.tools.ClassNodeUtils.samePackageName;
 import static org.apache.groovy.util.BeanUtils.capitalize;
 import static org.apache.groovy.util.BeanUtils.decapitalize;
 import static org.codehaus.groovy.ast.ClassHelper.BigDecimal_TYPE;
@@ -197,7 +196,6 @@ import static org.codehaus.groovy.ast.tools.WideningCategories.isLongCategory;
 import static org.codehaus.groovy.ast.tools.WideningCategories.isNumberCategory;
 import static org.codehaus.groovy.ast.tools.WideningCategories.lowestUpperBound;
 import static org.codehaus.groovy.classgen.AsmClassGenerator.MINIMUM_BYTECODE_VERSION;
-import static org.codehaus.groovy.runtime.DefaultGroovyMethods.asBoolean;
 import static org.codehaus.groovy.syntax.Types.ASSIGN;
 import static org.codehaus.groovy.syntax.Types.ASSIGNMENT_OPERATOR;
 import static org.codehaus.groovy.syntax.Types.COMPARE_EQUAL;
@@ -4850,65 +4848,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return EMPTY_METHODNODE_LIST;
     }
 
-    private List<MethodNode> filterMethodsByVisibility(List<MethodNode> methods) {
-        if (!asBoolean(methods)) {
-            return EMPTY_METHODNODE_LIST;
-        }
-
-        List<MethodNode> result = new LinkedList<>();
-
-        ClassNode enclosingClassNode = typeCheckingContext.getEnclosingClassNode();
-        boolean isEnclosingInnerClass = enclosingClassNode instanceof InnerClassNode;
-        List<ClassNode> outerClasses = enclosingClassNode.getOuterClasses();
-
-        outer:
-        for (MethodNode methodNode : methods) {
-            if (methodNode instanceof ExtensionMethodNode) {
-                result.add(methodNode);
-                continue;
-            }
-
-            ClassNode declaringClass = methodNode.getDeclaringClass();
-
-            if (isEnclosingInnerClass) {
-                for (ClassNode outerClass : outerClasses) {
-                    if (outerClass.isDerivedFrom(declaringClass)) {
-                        if (outerClass.equals(declaringClass)) {
-                            result.add(methodNode);
-                            continue outer;
-                        } else {
-                            if (methodNode.isPublic() || methodNode.isProtected()) {
-                                result.add(methodNode);
-                                continue outer;
-                            }
-                        }
-                    }
-                }
-            }
-
-            if (declaringClass instanceof InnerClassNode) {
-                if (declaringClass.getOuterClasses().contains(enclosingClassNode)) {
-                    result.add(methodNode);
-                    continue;
-                }
-            }
-
-            if (methodNode.isPrivate() && !enclosingClassNode.equals(declaringClass)) {
-                continue;
-            }
-            if (methodNode.isProtected()
-                    && !enclosingClassNode.isDerivedFrom(declaringClass)
-                    && !samePackageName(enclosingClassNode, declaringClass)) {
-                continue;
-            }
-            if (methodNode.isPackageScope() && !samePackageName(enclosingClassNode, declaringClass)) {
-                continue;
-            }
-
-            result.add(methodNode);
-        }
-
-        return result;
+    private List<MethodNode> filterMethodsByVisibility(List<MethodNode> methodNodeList) {
+        return StaticTypeCheckingSupport.filterMethodsByVisibility(methodNodeList, typeCheckingContext.getEnclosingClassNode());
     }
 
     /**
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index 3985f62..8614b9c 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -19,7 +19,8 @@
 package groovy.transform.stc
 
 class MethodReferenceTest extends GroovyTestCase {
-    void testMethodReferenceFunction() {
+    // class::instanceMethod
+    void testFunctionCI() {
         assertScript '''
             import java.util.stream.Collectors
             
@@ -34,7 +35,8 @@ class MethodReferenceTest extends GroovyTestCase {
         '''
     }
 
-    void testMethodReferenceBinaryOperator() {
+    // class::instanceMethod
+    void testBinaryOperatorCI() {
         assertScript '''
             import java.util.stream.Stream
 
@@ -48,4 +50,71 @@ class MethodReferenceTest extends GroovyTestCase {
             p()
         '''
     }
+
+    // class::staticMethod
+    void testFunctionCS() {
+        assertScript '''
+            import java.util.stream.Stream
+            import java.util.stream.Collectors
+
+            @groovy.transform.CompileStatic
+            void p() {
+                def result = [1, -2, 3].stream().map(Math::abs).collect(Collectors.toList())
+
+                assert [1, 2, 3] == result
+            }
+            
+            p()
+        '''
+    }
+
+    // instance::instanceMethod
+    void testBinaryOperatorII() {
+        assertScript '''
+            import java.util.stream.Stream
+            import java.util.stream.Collectors
+
+            @groovy.transform.CompileStatic
+            void p() {
+                Adder adder = new Adder()
+                def result = [new BigDecimal(1), new BigDecimal(2), new BigDecimal(3)].stream().reduce(new BigDecimal(0), adder::add)
+
+                assert new BigDecimal(6) == result
+            }
+            
+            p()
+            
+            @groovy.transform.CompileStatic
+            class Adder {
+                public BigDecimal add(BigDecimal a, BigDecimal b) {
+                    return a.add(b)
+                }
+            }
+        '''
+    }
+
+    // instance::staticMethod
+    void testBinaryOperatorIS() {
+        assertScript '''
+            import java.util.stream.Stream
+            import java.util.stream.Collectors
+
+            @groovy.transform.CompileStatic
+            void p() {
+                Adder adder = new Adder()
+                def result = [new BigDecimal(1), new BigDecimal(2), new BigDecimal(3)].stream().reduce(new BigDecimal(0), adder::add)
+
+                assert new BigDecimal(6) == result
+            }
+            
+            p()
+            
+            @groovy.transform.CompileStatic
+            class Adder {
+                public static BigDecimal add(BigDecimal a, BigDecimal b) {
+                    return a.add(b)
+                }
+            }
+        '''
+    }
 }