public MethodVisitor visitMethod()

in src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java [514:582]


    public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
        // do not generate bytecode for final, native, private or synthetic methods
        if ((access & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE | ACC_SYNTHETIC)) != 0) return null;

        Object key = Map.entry(name, desc);
        if (!visitedMethods.add(key)) return null;

        boolean objectDelegate = objectDelegateMethods.contains(name + desc);
        boolean closureDelegate = delegatedClosures.containsKey(name);
        boolean wildcardDelegate = hasWildcard && !"<init>".equals(name);

        if ((objectDelegate || closureDelegate || wildcardDelegate) && !Modifier.isStatic(access)) {
            if (!GROOVYOBJECT_METHOD_NAMES.contains(name)
                    // GROOVY-8244, GROOVY-10717: replace if abstract or no abstract overload exists
                    && (!Modifier.isAbstract(superClass.getModifiers()) || !isImplemented(superClass, name, desc)
                        || ((objectDelegate || closureDelegate) && Arrays.stream(superClass.getMethods()).filter(m -> m.getName().equals(name)).mapToInt(Method::getModifiers).noneMatch(Modifier::isAbstract)))) {

                if (closureDelegate || wildcardDelegate || !(objectDelegate && generateDelegateField)) {
                    delegatedClosures.put(name, Boolean.TRUE);
                    return makeDelegateToClosureCall(name, desc, signature, exceptions, access & ~ACC_ABSTRACT);
                }
                return makeDelegateCall(name, desc, signature, exceptions, access & ~ACC_ABSTRACT);
            }
        } else if ("getProxyTarget".equals(name) && "()Ljava/lang/Object;".equals(desc)) {
            return createGetProxyTargetMethod(access, name, desc, signature, exceptions);
        } else if ("<init>".equals(name) && (Modifier.isPublic(access) || Modifier.isProtected(access))) {
            return createConstructor(access, name, desc, signature, exceptions);
        } else if (Modifier.isAbstract(access) && !GROOVYOBJECT_METHOD_NAMES.contains(name) && !isImplemented(superClass, name, desc)) {
            MethodVisitor mv = super.visitMethod(access & ~ACC_ABSTRACT, name, desc, signature, exceptions);
            mv.visitCode();
            if (emptyBody) {
                Type returnType = Type.getReturnType(desc);
                if (returnType == Type.VOID_TYPE) {
                    mv.visitInsn(RETURN);
                } else {
                    int loadIns = getLoadInsn(returnType);
                    switch (loadIns) {
                        case ILOAD:
                            mv.visitInsn(ICONST_0);
                            break;
                        case LLOAD:
                            mv.visitInsn(LCONST_0);
                            break;
                        case FLOAD:
                            mv.visitInsn(FCONST_0);
                            break;
                        case DLOAD:
                            mv.visitInsn(DCONST_0);
                            break;
                        default:
                            mv.visitInsn(ACONST_NULL);
                    }
                    mv.visitInsn(getReturnInsn(returnType));
                    mv.visitMaxs(0, 0);
                }
            } else {
                // for compatibility with the legacy proxy generator, we should throw an UnsupportedOperationException
                // instead of an AbtractMethodException
                mv.visitTypeInsn(NEW, "java/lang/UnsupportedOperationException");
                mv.visitInsn(DUP);
                mv.visitMethodInsn(INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "()V", false);
                mv.visitInsn(ATHROW);
                mv.visitMaxs(0, 0);
            }
            mv.visitEnd();
        }

        return null;
    }