checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
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);
String sig = ((ConstantUtf8) (cp.getConstant(obj.getSignatureIndex()))).getBytes(); // Method's signature(=descriptor)
Type t;
Type[] ts; // needed below the try block.
try{
t = Type.getReturnType(sig);
ts = Type.getArgumentTypes(sig);
}
catch (ClassFormatError cfe){
// Well, BCEL sometimes is a little harsh describing exceptional situations.
throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by Method '"+tostring(obj)+"'.");
}
// Check if referenced objects exist.
Type act = t;
if (act instanceof ArrayType) act = ((ArrayType) act).getBasicType();
if (act instanceof ObjectType){
Verifier v = VerifierFactory.getVerifier( ((ObjectType) act).getClassName() );
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 (int i=0; i<ts.length; i++){
act = ts[i];
if (act instanceof ArrayType) act = ((ArrayType) act).getBasicType();
if (act instanceof ObjectType){
Verifier v = VerifierFactory.getVerifier( ((ObjectType) act).getClassName() );
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(STATIC_INITIALIZER_NAME) && (ts.length != 0)){
throw new ClassConstraintException("Method '"+tostring(obj)+"' has illegal name '"+name+"'. It's 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.");
}
}
else{ // isInterface!
if (!name.equals(STATIC_INITIALIZER_NAME)){//vmspec2, p.116, 2nd paragraph
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_STATIC 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.");
}
}
}
// A specific instance initialization method... (vmspec2,Page 116).
if (name.equals(CONSTRUCTOR_NAME)){
//..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 ( 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.");
}
}
// Class and interface initialization methods...
if (name.equals(STATIC_INITIALIZER_NAME)){
if ((obj.getAccessFlags() & (~ACC_STRICT)) > 0){
addMessage("Class or interface initialization method '"+tostring(obj)+"' has superfluous access modifier(s) set: everything but ACC_STRICT is ignored.");
}
if (obj.isAbstract()){
throw new ClassConstraintException("Class or interface initialization method '"+tostring(obj)+"' must not be abstract. This contradicts the Java Language Specification, Second Edition (which omits this constraint) but is common practice of existing verifiers.");
}
}
if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|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).");
}
String nameanddesc = (name+sig);
if (method_names_and_desc.contains(nameanddesc)){
throw new ClassConstraintException("No two methods (like '"+tostring(obj)+"') are allowed have same names and desciptors!");
}
method_names_and_desc.add(nameanddesc);
Attribute[] atts = obj.getAttributes();
int num_code_atts = 0;
for (int i=0; i<atts.length; i++){
if ((! (atts[i] instanceof Code)) &&
(! (atts[i] instanceof ExceptionTable)) &&
(! (atts[i] instanceof Synthetic)) &&
(! (atts[i] instanceof Deprecated))){
addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Method '"+tostring(obj)+"' is unknown and will therefore be ignored.");
}
if ((! (atts[i] instanceof Code)) &&
(! (atts[i] instanceof ExceptionTable))){
addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Method '"+tostring(obj)+"' is neither Code nor Exceptions and is therefore only of use for debuggers and such.");
}
if ((atts[i] instanceof Code) && (obj.isNative() || obj.isAbstract())){
throw new ClassConstraintException("Native or abstract methods like '"+tostring(obj)+"' must not have a Code attribute like '"+tostring(atts[i])+"'."); //vmspec2 page120, 4.7.3
}
if (atts[i] instanceof Code) num_code_atts++;
}
if ( !obj.isNative() && !obj.isAbstract() && num_code_atts != 1){
throw new ClassConstraintException("Non-native, non-abstract methods like '"+tostring(obj)+"' must have exactly one Code attribute (found: "+num_code_atts+").");
}
}