docs: @SuppressWarnings("unchecked")
      private void processToString(ClassTraceInfo info) {
          for (MethodNode mn : (List<MethodNode>) info.classNode.methods) {
              if (!mn.name.equals("toString") || !mn.desc.equals("()Ljava/lang/String;")) {
                  continue;
              }
              Iterator<? extends AbstractInsnNode> instructionIterator = mn.instructions.iterator();
              INSN_LOOP: while (instructionIterator.hasNext()) {
                  AbstractInsnNode insnNode = instructionIterator.next();
                  if (insnNode.getType() == AbstractInsnNode.METHOD_INSN) {
                      MethodInsnNode methodInsn = (MethodInsnNode) insnNode;
  
                      // Skip static methods
                      if (methodInsn.getOpcode() == Opcodes.INVOKESTATIC) {
                          continue;
                      }
  
                      // Skip methods that aren't part of this class
                      if (!methodInsn.owner.equals(info.classNode.name)) {
                          continue;
                      }
  
                      // Skip explicitly trivial methods from this file class
                      MethodNode m = getMethod(methodInsn.name, methodInsn.desc, info.classNode.methods);
                      if (m != null && getAnnotation(TRIVIAL_TYPE.getDescriptor(), m.visibleAnnotations) != null) {
                          continue;
                      }
  
                      // If the target method is not found on this class and the super class
                      // is in the set of files being instrumented, see if it's trivial
                      String superName = info.classNode.superName;
                      while (m == null && superName != null && !"java/lang/Object".equals(superName)) {
                          if (superName.startsWith("java/") || superName.startsWith("javax/")) {
                              continue INSN_LOOP;
                          }
                          InputStream superClassInputStream = getClassInputStream(superName);
                          if (superClassInputStream == null) {
                              StringBuilder sb = new StringBuilder();
                              sb.append("INFO: ").append(info.classNode.name.replaceAll("/", "\\."));
                              sb.append(" extends class ").append(superName.replaceAll("/", "\\."));
                              sb.append(" and is calling ").append(methodInsn.name);
                              sb.append(" from toString()");
                              info.warnings.add(sb.toString());
                              continue INSN_LOOP;
                          }
                          ClassNode cn = getClassNode(superClassInputStream, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG);
                          m = getMethod(methodInsn.name, methodInsn.desc, cn.methods);
                          superName = cn.superName;
                      }
  
                      // Found a method declaration on the super class that's marked as trivial
                      if (m != null && getAnnotation(TRIVIAL_TYPE.getDescriptor(), m.visibleAnnotations) != null) {
                          continue;
                      }
  
                      // Add a warning
                      StringBuilder sb = new StringBuilder();
                      sb.append("WARNING: ").append(info.classNode.name.replaceAll("/", "\\."));
                      sb.append(" is calling traceable methods from toString(); this may result in infinite recursion.  ");
                      sb.append("Consider referencing class fields or marking the called methods trivial to avoid trace.");
                      info.warnings.add(sb.toString());
                      break;
                  }
              }
          }
      }