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 + ").");
}
}