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)
+ }
+ }
+ '''
+ }
}