use of org.codehaus.groovy.transform.stc.ExtensionMethodNode in project groovy by apache.
the class StaticTypesMethodReferenceExpressionWriter method writeMethodReferenceExpression.
@Override
public void writeMethodReferenceExpression(final MethodReferenceExpression methodReferenceExpression) {
ClassNode functionalInterfaceType = getFunctionalInterfaceType(methodReferenceExpression);
if (!ClassHelper.isFunctionalInterface(functionalInterfaceType)) {
// generate the default bytecode; most likely a method closure
super.writeMethodReferenceExpression(methodReferenceExpression);
return;
}
ClassNode redirect = functionalInterfaceType.redirect();
MethodNode abstractMethod = ClassHelper.findSAM(redirect);
String abstractMethodDesc = createMethodDescriptor(abstractMethod);
ClassNode classNode = controller.getClassNode();
Expression typeOrTargetRef = methodReferenceExpression.getExpression();
boolean isClassExpression = (typeOrTargetRef instanceof ClassExpression);
ClassNode typeOrTargetRefType = isClassExpression ? typeOrTargetRef.getType() : controller.getTypeChooser().resolveType(typeOrTargetRef, classNode);
ClassNode[] methodReferenceParamTypes = methodReferenceExpression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
Parameter[] parametersWithExactType = createParametersWithExactType(abstractMethod, methodReferenceParamTypes);
String methodRefName = methodReferenceExpression.getMethodName().getText();
boolean isConstructorReference = isConstructorReference(methodRefName);
MethodNode methodRefMethod;
if (isConstructorReference) {
methodRefName = controller.getContext().getNextConstructorReferenceSyntheticMethodName(controller.getMethodNode());
methodRefMethod = addSyntheticMethodForConstructorReference(methodRefName, typeOrTargetRefType, parametersWithExactType);
} else {
// TODO: move the findMethodRefMethod and checking to StaticTypeCheckingVisitor
methodRefMethod = findMethodRefMethod(methodRefName, parametersWithExactType, typeOrTargetRef, typeOrTargetRefType);
}
validate(methodReferenceExpression, typeOrTargetRef, typeOrTargetRefType, methodRefName, parametersWithExactType, methodRefMethod);
if (isExtensionMethod(methodRefMethod)) {
ExtensionMethodNode extensionMethodNode = (ExtensionMethodNode) methodRefMethod;
methodRefMethod = extensionMethodNode.getExtensionMethodNode();
if (extensionMethodNode.isStaticExtension()) {
methodRefMethod = addSyntheticMethodForDGSM(methodRefMethod);
}
typeOrTargetRefType = methodRefMethod.getDeclaringClass();
Expression classExpression = classX(typeOrTargetRefType);
classExpression.setSourcePosition(typeOrTargetRef);
typeOrTargetRef = classExpression;
}
methodRefMethod.putNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE, parametersWithExactType);
if (!isClassExpression) {
if (isConstructorReference) {
// TODO: move the checking code to the parser
addFatalError("Constructor reference must be className::new", methodReferenceExpression);
} else if (methodRefMethod.isStatic()) {
ClassExpression classExpression = classX(typeOrTargetRefType);
classExpression.setSourcePosition(typeOrTargetRef);
typeOrTargetRef = classExpression;
isClassExpression = true;
} else {
typeOrTargetRef.visit(controller.getAcg());
}
}
controller.getMethodVisitor().visitInvokeDynamicInsn(abstractMethod.getName(), createAbstractMethodDesc(functionalInterfaceType, typeOrTargetRef), createBootstrapMethod(classNode.isInterface(), false), createBootstrapMethodArguments(abstractMethodDesc, methodRefMethod.isStatic() || isConstructorReference ? Opcodes.H_INVOKESTATIC : Opcodes.H_INVOKEVIRTUAL, isConstructorReference ? controller.getClassNode() : typeOrTargetRefType, methodRefMethod, false));
if (isClassExpression) {
controller.getOperandStack().push(redirect);
} else {
controller.getOperandStack().replace(redirect, 1);
}
}
Aggregations