public void visitMethod()

in src/main/java/org/apache/bcel/verifier/statics/Pass2Verifier.java [784:949]


        public void visitMethod(final Method obj) {

            checkIndex(obj, obj.getNameIndex(), CONST_Utf8);

            final String name = obj.getName();
            if (!validMethodName(name, true)) {
                throw new ClassConstraintException("Method '" + tostring(obj) + "' has illegal name '" + name + "'.");
            }

            // A descriptor is often named signature in BCEL
            checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8);

            final String sig = ((ConstantUtf8) cp.getConstant(obj.getSignatureIndex())).getBytes(); // Method's signature(=descriptor)

            final Type t;
            final Type[] ts; // needed below the try block.
            try {
                t = Type.getReturnType(sig);
                ts = Type.getArgumentTypes(sig);
            } catch (final ClassFormatException cfe) {
                throw new ClassConstraintException("Illegal descriptor (==signature) '" + sig + "' used by Method '" + tostring(obj) + "'.", cfe);
            }

            // Check if referenced objects exist.
            Type act = t;
            if (act instanceof ArrayType) {
                act = ((ArrayType) act).getBasicType();
            }
            if (act instanceof ObjectType) {
                final Verifier v = VerifierFactory.getVerifier(((ObjectType) act).getClassName());
                final VerificationResult vr = v.doPass1();
                if (vr != VerificationResult.VR_OK) {
                    throw new ClassConstraintException(
                        "Method '" + tostring(obj) + "' has a return type that does not pass verification pass 1: '" + vr + "'.");
                }
            }

            for (final Type element : ts) {
                act = element;
                if (act instanceof ArrayType) {
                    act = ((ArrayType) act).getBasicType();
                }
                if (act instanceof ObjectType) {
                    final Verifier v = VerifierFactory.getVerifier(((ObjectType) act).getClassName());
                    final VerificationResult vr = v.doPass1();
                    if (vr != VerificationResult.VR_OK) {
                        throw new ClassConstraintException(
                            "Method '" + tostring(obj) + "' has an argument type that does not pass verification pass 1: '" + vr + "'.");
                    }
                }
            }

            // Nearly forgot this! Funny return values are allowed, but a non-empty arguments list makes a different method out of
            // it!
            if (name.equals(Const.STATIC_INITIALIZER_NAME) && ts.length != 0) {
                throw new ClassConstraintException("Method '" + tostring(obj) + "' has illegal name '" + name + "'."
                    + " Its name resembles the class or interface initialization method" + " which it isn't because of its arguments (==descriptor).");
            }

            if (jc.isClass()) {
                int maxone = 0;
                if (obj.isPrivate()) {
                    maxone++;
                }
                if (obj.isProtected()) {
                    maxone++;
                }
                if (obj.isPublic()) {
                    maxone++;
                }
                if (maxone > 1) {
                    throw new ClassConstraintException(
                        "Method '" + tostring(obj) + "' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set.");
                }

                if (obj.isAbstract()) {
                    if (obj.isFinal()) {
                        throw new ClassConstraintException("Abstract method '" + tostring(obj) + "' must not have the ACC_FINAL modifier set.");
                    }
                    if (obj.isNative()) {
                        throw new ClassConstraintException("Abstract method '" + tostring(obj) + "' must not have the ACC_NATIVE modifier set.");
                    }
                    if (obj.isPrivate()) {
                        throw new ClassConstraintException("Abstract method '" + tostring(obj) + "' must not have the ACC_PRIVATE modifier set.");
                    }
                    if (obj.isStatic()) {
                        throw new ClassConstraintException("Abstract method '" + tostring(obj) + "' must not have the ACC_STATIC modifier set.");
                    }
                    if (obj.isStrictfp()) {
                        throw new ClassConstraintException("Abstract method '" + tostring(obj) + "' must not have the ACC_STRICT modifier set.");
                    }
                    if (obj.isSynchronized()) {
                        throw new ClassConstraintException("Abstract method '" + tostring(obj) + "' must not have the ACC_SYNCHRONIZED modifier set.");
                    }
                }

                // A specific instance initialization method... (vmspec2,Page 116).
                // ..may have at most one of ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC set: is checked above.
                // ..may also have ACC_STRICT set, but none of the other flags in table 4.5 (vmspec2, page 115)
                if (name.equals(Const.CONSTRUCTOR_NAME) && (obj.isStatic() || obj.isFinal() || obj.isSynchronized() || obj.isNative() || obj.isAbstract())) {
                    throw new ClassConstraintException("Instance initialization method '" + tostring(obj) + "' must not have"
                            + " any of the ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT modifiers set.");
                }
            } else if (!name.equals(Const.STATIC_INITIALIZER_NAME)) { // vmspec2, p.116, 2nd paragraph
                if (jc.getMajor() >= Const.MAJOR_1_8) {
                    if (obj.isPublic() == obj.isPrivate()) {
                        throw new ClassConstraintException(
                            "Interface method '" + tostring(obj) + "' must have" + " exactly one of its ACC_PUBLIC and ACC_PRIVATE modifiers set.");
                    }
                    if (obj.isProtected() || obj.isFinal() || obj.isSynchronized() || obj.isNative()) {
                        throw new ClassConstraintException("Interface method '" + tostring(obj) + "' must not have"
                            + " any of the ACC_PROTECTED, ACC_FINAL, ACC_SYNCHRONIZED, or ACC_NATIVE modifiers set.");
                    }

                } else {
                    if (!obj.isPublic()) {
                        throw new ClassConstraintException("Interface method '" + tostring(obj) + "' must have the ACC_PUBLIC modifier set but hasn't!");
                    }
                    if (!obj.isAbstract()) {
                        throw new ClassConstraintException("Interface method '" + tostring(obj) + "' must have the ACC_ABSTRACT modifier set but hasn't!");
                    }
                    if (obj.isPrivate() || obj.isProtected() || obj.isStatic() || obj.isFinal() || obj.isSynchronized() || obj.isNative() || obj.isStrictfp()) {
                        throw new ClassConstraintException("Interface method '" + tostring(obj) + "' must not have"
                            + " any of the ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED,"
                            + " ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT modifiers set.");
                    }
                }
            }

            if ((obj.getAccessFlags() & ~(Const.ACC_PUBLIC | Const.ACC_PRIVATE | Const.ACC_PROTECTED | Const.ACC_STATIC | Const.ACC_FINAL |
                Const.ACC_SYNCHRONIZED | Const.ACC_NATIVE | Const.ACC_ABSTRACT | Const.ACC_STRICT)) > 0) {
                addMessage("Method '" + tostring(obj) + "' has access flag(s) other than" + " ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL,"
                    + " ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT set (ignored).");
            }

            final String nameanddesc = name + sig;
            if (methodNamesAndDesc.contains(nameanddesc)) {
                throw new ClassConstraintException("No two methods (like '" + tostring(obj) + "') are allowed have same names and desciptors!");
            }
            methodNamesAndDesc.add(nameanddesc);

            final Attribute[] atts = obj.getAttributes();
            int numCodeAtts = 0;
            for (final Attribute att : atts) {
                if (!(att instanceof Code) && !(att instanceof ExceptionTable) && !(att instanceof Synthetic) && !(att instanceof Deprecated)) {
                    addMessage("Attribute '" + tostring(att) + "' as an attribute of Method '" + tostring(obj) + "' is unknown and will therefore be ignored.");
                }
                if (!(att instanceof Code) && !(att instanceof ExceptionTable)) {
                    addMessage("Attribute '" + tostring(att) + "' as an attribute of Method '" + tostring(obj)
                        + "' is neither Code nor Exceptions and is therefore only of use for debuggers and such.");
                }
                if (att instanceof Code && (obj.isNative() || obj.isAbstract())) {
                    throw new ClassConstraintException(
                        "Native or abstract methods like '" + tostring(obj) + "' must not have a Code attribute like '" + tostring(att) + "'."); // vmspec2
                                                                                                                                                 // page120,
                                                                                                                                                 // 4.7.3
                }
                if (att instanceof Code) {
                    numCodeAtts++;
                }
            }
            if (!obj.isNative() && !obj.isAbstract() && numCodeAtts != 1) {
                throw new ClassConstraintException(
                    "Non-native, non-abstract methods like '" + tostring(obj) + "' must have exactly one Code attribute (found: " + numCodeAtts + ").");
            }
        }