public SyntheticAnalyzer(MethodInfo method, boolean checkName) {
   this.method = method;
   if (method.getBytecode() == null) return;
   if (!checkName || method.getName().equals("class$")) if (checkGetClass()) return;
   if (!checkName || method.getName().startsWith("access$")) if (checkAccess()) return;
   if (method.getName().equals("<init>")) if (checkConstructorAccess()) return;
 }
  boolean checkGetClass() {
    if (!method.isStatic() || !(method.getType().equals("(Ljava/lang/String;)Ljava/lang/Class;")))
      return false;

    BytecodeInfo bytecode = method.getBytecode();

    Handler[] excHandlers = bytecode.getExceptionHandlers();
    if (excHandlers.length != 1 || !"java.lang.ClassNotFoundException".equals(excHandlers[0].type))
      return false;

    int excSlot = -1;
    int i = 0;
    for (Iterator iter = bytecode.getInstructions().iterator(); iter.hasNext(); i++) {
      Instruction instr = (Instruction) iter.next();
      while (instr.getOpcode() == opc_nop && iter.hasNext()) instr = (Instruction) iter.next();
      if (i == getClassOpcodes.length || instr.getOpcode() != getClassOpcodes[i]) return false;
      if (i == 0 && (instr.getLocalSlot() != 0 || excHandlers[0].start != instr)) return false;
      if (i == 2 && excHandlers[0].end != instr) return false;
      if (i == 3) {
        if (excHandlers[0].catcher != instr) return false;
        excSlot = instr.getLocalSlot();
      }
      if (i == 4 && !instr.getClazzType().equals("Ljava/lang/NoClassDefFoundError;")) return false;
      if (i == 6 && instr.getLocalSlot() != excSlot) return false;
      if (getClassRefs[i] != null && !getClassRefs[i].equals(instr.getReference())) return false;
    }
    this.kind = GETCLASS;
    return true;
  }
  public boolean checkConstructorAccess() {
    ClassInfo clazzInfo = method.getClazzInfo();
    BytecodeInfo bytecode = method.getBytecode();
    String[] paramTypes = TypeSignature.getParameterTypes(method.getType());
    Handler[] excHandlers = bytecode.getExceptionHandlers();
    if (excHandlers != null && excHandlers.length != 0) return false;
    Iterator iter = bytecode.getInstructions().iterator();

    Instruction instr = (Instruction) iter.next();
    while (instr.getOpcode() == opc_nop && iter.hasNext()) instr = (Instruction) iter.next();
    int params = 0, slot = 0;
    while (instr.getOpcode() >= opc_iload && instr.getOpcode() <= opc_aload) {

      if (instr.getLocalSlot() > slot
          && unifyParam == -1
          && params > 0
          && paramTypes[params - 1].charAt(0) == 'L') {
        unifyParam = params;
        params++;
        slot++;
      }
      if (instr.getLocalSlot() != slot) return false;

      params++;
      slot += (instr.getOpcode() == opc_lload || instr.getOpcode() == opc_dload) ? 2 : 1;
      instr = (Instruction) iter.next();
    }
    if (params > 0 && instr.getOpcode() == opc_invokespecial) {

      if (unifyParam == -1
          && params <= paramTypes.length
          && paramTypes[params - 1].charAt(0) == 'L') unifyParam = params++;

      Reference ref = instr.getReference();
      ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
      if (refClazz != clazzInfo) return false;
      MethodInfo refMethod = refClazz.findMethod(ref.getName(), ref.getType());
      MethodType refType = Type.tMethod(ref.getType());
      if ((refMethod.getModifiers() & modifierMask) != 0
          || !refMethod.getName().equals("<init>")
          || unifyParam == -1
          || refType.getParameterTypes().length != params - 2) return false;

      instr = (Instruction) iter.next();
      if (instr.getOpcode() != opc_return) return false;

      /*
       * We don't check if types matches. No problem since we only need to
       * make sure, this constructor doesn't do anything more than relay
       * to the real one.
       */
      reference = ref;
      kind = ACCESSCONSTRUCTOR;
      return true;
    }
    return false;
  }
  public boolean checkAccess() {
    ClassInfo clazzInfo = method.getClazzInfo();
    BytecodeInfo bytecode = method.getBytecode();
    Handler[] excHandlers = bytecode.getExceptionHandlers();
    boolean dupSeen = false;
    if (excHandlers != null && excHandlers.length != 0) return false;

    if (method.isStatic()) {
      if (checkStaticAccess()) return true;
    }

    Iterator iter = bytecode.getInstructions().iterator();
    Instruction instr = (Instruction) iter.next();
    while (instr.getOpcode() == opc_nop && iter.hasNext()) instr = (Instruction) iter.next();
    if (instr.getOpcode() != opc_aload || instr.getLocalSlot() != 0) return false;
    instr = (Instruction) iter.next();
    while (instr.getOpcode() == opc_nop && iter.hasNext()) instr = (Instruction) iter.next();

    if (instr.getOpcode() == opc_getfield) {
      Reference ref = instr.getReference();
      ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
      if (!refClazz.superClassOf(clazzInfo)) return false;
      FieldInfo refField = refClazz.findField(ref.getName(), ref.getType());
      if ((refField.getModifiers() & modifierMask) != 0) return false;
      instr = (Instruction) iter.next();
      while (instr.getOpcode() == opc_nop && iter.hasNext()) instr = (Instruction) iter.next();
      if (instr.getOpcode() < opc_ireturn || instr.getOpcode() > opc_areturn) return false;
      /* For valid bytecode the type matches automatically */
      reference = ref;
      kind = ACCESSGETFIELD;
      return true;
    }
    int params = 0, slot = 1;
    while (instr.getOpcode() >= opc_iload
        && instr.getOpcode() <= opc_aload
        && instr.getLocalSlot() == slot) {
      params++;
      slot += (instr.getOpcode() == opc_lload || instr.getOpcode() == opc_dload) ? 2 : 1;
      instr = (Instruction) iter.next();
      while (instr.getOpcode() == opc_nop && iter.hasNext()) instr = (Instruction) iter.next();
    }
    if (instr.getOpcode() == (opc_dup_x1 - 6) + 3 * slot) {
      /*
       * This is probably a opc_dup_x1 or opc_dup2_x1, preceding a
       * opc_putfield
       */
      instr = (Instruction) iter.next();
      while (instr.getOpcode() == opc_nop && iter.hasNext()) instr = (Instruction) iter.next();
      if (instr.getOpcode() != opc_putfield) return false;
      dupSeen = true;
    }
    if (instr.getOpcode() == opc_putfield) {
      if (params != 1) return false;
      /* For valid bytecode the type of param matches automatically */
      Reference ref = instr.getReference();
      ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
      if (!refClazz.superClassOf(clazzInfo)) return false;
      FieldInfo refField = refClazz.findField(ref.getName(), ref.getType());
      if ((refField.getModifiers() & modifierMask) != 0) return false;

      instr = (Instruction) iter.next();
      while (instr.getOpcode() == opc_nop && iter.hasNext()) instr = (Instruction) iter.next();
      if (dupSeen) {
        if (instr.getOpcode() < opc_ireturn || instr.getOpcode() > opc_areturn) return false;
        kind = ACCESSDUPPUTFIELD;
      } else {
        if (instr.getOpcode() != opc_return) return false;
        kind = ACCESSPUTFIELD;
      }
      reference = ref;
      return true;
    }
    if (instr.getOpcode() == opc_invokespecial) {
      Reference ref = instr.getReference();
      ClassInfo refClazz = TypeSignature.getClassInfo(ref.getClazz());
      if (!refClazz.superClassOf(clazzInfo)) return false;
      MethodInfo refMethod = refClazz.findMethod(ref.getName(), ref.getType());
      MethodType refType = Type.tMethod(ref.getType());
      if ((refMethod.getModifiers() & modifierMask) != 0
          || refType.getParameterTypes().length != params) return false;
      instr = (Instruction) iter.next();
      while (instr.getOpcode() == opc_nop && iter.hasNext()) instr = (Instruction) iter.next();
      if (refType.getReturnType() == Type.tVoid) {
        if (instr.getOpcode() != opc_return) return false;
      } else {
        if (instr.getOpcode() < opc_ireturn || instr.getOpcode() > opc_areturn) return false;
      }

      /* For valid bytecode the types matches automatically */
      reference = ref;
      kind = ACCESSMETHOD;
      return true;
    }
    return false;
  }