private static boolean generateParameterJava(
     PrintWriter writer,
     VariableElement param,
     TypeInfo type_info,
     boolean native_stub,
     final boolean printTypes,
     boolean first_parameter,
     Mode mode) {
   Class buffer_type = Utils.getNIOBufferType(param.asType());
   if (!first_parameter) {
     writer.print(", ");
   }
   BufferObject bo_annotation = param.getAnnotation(BufferObject.class);
   if (bo_annotation != null && mode == Mode.BUFFEROBJECT) {
     if (buffer_type == null) {
       throw new RuntimeException(
           "type of "
               + param
               + " is not a nio Buffer parameter but is annotated as buffer object");
     }
     if (printTypes) {
       writer.print("long ");
     }
     writer.print(param.getSimpleName() + Utils.BUFFER_OBJECT_PARAMETER_POSTFIX);
   } else {
     if (native_stub && param.getAnnotation(PointerWrapper.class) != null) {
       writer.print("long ");
     } else {
       Class type = type_info.getType();
       if (native_stub
           && (type == CharSequence.class
               || type == CharSequence[].class
               || type == PointerBuffer.class
               || Buffer.class.isAssignableFrom(type))) {
         writer.print("long ");
       } else if (printTypes) {
         writer.print(type.getSimpleName() + " ");
       }
     }
     AutoSize auto_size_annotation = param.getAnnotation(AutoSize.class);
     if (auto_size_annotation != null) {
       writer.print(auto_size_annotation.value() + "_");
     }
     writer.print(param.getSimpleName());
   }
   return false;
 }
  private static void printParameterChecks(
      PrintWriter writer,
      ExecutableElement method,
      Map<VariableElement, TypeInfo> typeinfos,
      Mode mode,
      final boolean generate_error_checks) {
    if (mode == Mode.NORMAL) {
      final GenerateAutos gen_autos_annotation = method.getAnnotation(GenerateAutos.class);
      if (gen_autos_annotation != null && gen_autos_annotation.sizeVariables().length > 0) {
        // For the auto-generated parameters, declare and init a size variable (that can be reused
        // by @Code)
        for (final VariableElement param : method.getParameters()) {
          if (Arrays.binarySearch(
                  gen_autos_annotation.sizeVariables(), param.getSimpleName().toString())
              >= 0) {
            final int shifting = getBufferElementSizeExponent(typeinfos.get(param).getType());
            final Check check_annotation = param.getAnnotation(Check.class);

            writer.print("\t\tlong " + param.getSimpleName() + "_size = ");
            if (check_annotation == null || !check_annotation.canBeNull()) {
              writer.println(param.getSimpleName() + ".remaining() << " + shifting + ";");
            } else {
              writer.println(
                  param.getSimpleName()
                      + " == null ? 0 : "
                      + param.getSimpleName()
                      + ".remaining() << "
                      + shifting
                      + ";");
            }
          }
        }
      }
    }

    for (VariableElement param : method.getParameters()) {
      Class java_type = Utils.getJavaType(param.asType());
      if (java_type.isArray()
          || (Utils.isAddressableType(java_type)
              && (mode != Mode.BUFFEROBJECT || param.getAnnotation(BufferObject.class) == null)
              && (mode != Mode.AUTOS || getAutoTypeParameter(method, param) == null)
              && param.getAnnotation(Result.class) == null
              && !Utils.isReturnParameter(method, param))) {
        String check_value = null;
        boolean can_be_null = false;
        Check check_annotation = param.getAnnotation(Check.class);
        if (check_annotation != null) {
          check_value = check_annotation.value();
          can_be_null = check_annotation.canBeNull();
        }
        if ((Buffer.class.isAssignableFrom(java_type)
                || PointerBuffer.class.isAssignableFrom(java_type))
            && param.getAnnotation(Constant.class) == null) {
          TypeInfo typeinfo = typeinfos.get(param);
          printParameterCheck(
              writer,
              method,
              param.getSimpleName().toString(),
              typeinfo.getType().getSimpleName(),
              check_value,
              can_be_null,
              param.getAnnotation(NullTerminated.class),
              generate_error_checks);
        } else if (String.class.equals(java_type)) {
          if (!can_be_null) {
            writer.println("\t\tBufferChecks.checkNotNull(" + param.getSimpleName() + ");");
          }
        } else if (java_type.isArray()) {
          printArrayParameterCheck(
              writer, param.getSimpleName().toString(), check_value, can_be_null);
        }
      }
    }
    if (method.getAnnotation(CachedResult.class) != null) {
      printParameterCheck(
          writer, method, Utils.CACHED_BUFFER_NAME, null, null, true, null, generate_error_checks);
    }
  }
  private static boolean printMethodCallArgument(
      PrintWriter writer,
      ExecutableElement method,
      VariableElement param,
      Map<VariableElement, TypeInfo> typeinfos_instance,
      Mode mode,
      boolean first_parameter,
      TypeMap type_map) {
    if (!first_parameter) {
      writer.print(", ");
    }

    AnnotationMirror auto_annotation = Utils.getParameterAutoAnnotation(param);
    Constant constant_annotation = param.getAnnotation(Constant.class);
    if (constant_annotation != null) {
      writer.print(constant_annotation.value());
    } else if (auto_annotation != null && mode == Mode.NORMAL) {
      Class param_type = NativeTypeTranslator.getClassFromType(auto_annotation.getAnnotationType());
      if (AutoType.class.equals(param_type)) {
        final AutoType auto_type_annotation = param.getAnnotation(AutoType.class);
        final VariableElement auto_parameter =
            Utils.findParameter(method, auto_type_annotation.value());
        final String auto_type = typeinfos_instance.get(auto_parameter).getAutoType();
        if (auto_type == null) {
          throw new RuntimeException(
              "No auto type for parameter " + param.getSimpleName() + " in method " + method);
        }
        writer.print(auto_type);
      } else if (AutoSize.class.equals(param_type)) {
        final AutoSize auto_size_annotation = param.getAnnotation(AutoSize.class);
        if (!auto_size_annotation.useExpression()) {
          final String auto_parameter_name = auto_size_annotation.value();
          final VariableElement auto_target_param =
              Utils.findParameter(method, auto_parameter_name);
          final TypeInfo auto_target_type_info = typeinfos_instance.get(auto_target_param);
          final boolean shift_remaining =
              !hasAnyParameterAutoTypeAnnotation(method, auto_target_param)
                  && Utils.isParameterMultiTyped(auto_target_param);
          int shifting = 0;
          if (shift_remaining) {
            shifting = getBufferElementSizeExponent(auto_target_type_info.getType());
            if (shifting > 0) {
              writer.print("(");
            }
          }
          if (auto_size_annotation.canBeNull()) {
            writer.print(
                "("
                    + auto_parameter_name
                    + " == null ? 0 : "
                    + auto_parameter_name
                    + ".remaining())");
          } else {
            writer.print(auto_parameter_name + ".remaining()");
          }
          // Shift the remaining if the target parameter is multityped and there's no AutoType to
          // track type
          if (shift_remaining && shifting > 0) {
            writer.print(" << " + shifting);
            writer.print(")");
          }
        }
        writer.print(auto_size_annotation.expression());
      } else {
        throw new RuntimeException("Unknown auto annotation " + param_type);
      }
    } else {
      if (mode == Mode.BUFFEROBJECT && param.getAnnotation(BufferObject.class) != null) {
        writer.print(param.getSimpleName() + Utils.BUFFER_OBJECT_PARAMETER_POSTFIX);
      } else {
        Class type = typeinfos_instance.get(param).getType();
        Check check_annotation = param.getAnnotation(Check.class);
        boolean hide_buffer = mode == Mode.AUTOS && getAutoTypeParameter(method, param) != null;
        if (hide_buffer) {
          writer.print("0L");
        } else {
          if (type == CharSequence.class || type == CharSequence[].class) {
            final String offset = Utils.getStringOffset(method, param);

            writer.print("APIUtil.getBuffer");
            if (param.getAnnotation(NullTerminated.class) != null) {
              writer.print("NT");
            }
            writer.print('(');
            writer.print(type_map.getAPIUtilParam(true));
            writer.print(param.getSimpleName());
            if (offset != null) {
              writer.print(", " + offset);
            }
            writer.print(")");
          } else {
            final AutoSize auto_size_annotation = param.getAnnotation(AutoSize.class);
            if (auto_size_annotation != null) {
              writer.print(auto_size_annotation.value() + "_");
            }

            final Class buffer_type = Utils.getNIOBufferType(param.asType());
            if (buffer_type == null) {
              writer.print(param.getSimpleName());
            } else {
              writer.print("MemoryUtil.getAddress");
              if (check_annotation != null && check_annotation.canBeNull()) {
                writer.print("Safe");
              }
              writer.print("(");
              writer.print(param.getSimpleName());
              writer.print(")");
            }
          }
        }
        if (type != long.class) {
          PointerWrapper pointer_annotation = param.getAnnotation(PointerWrapper.class);
          if (pointer_annotation != null) {
            if (pointer_annotation.canBeNull()) {
              writer.print(" == null ? 0 : " + param.getSimpleName());
            }
            writer.print(".getPointer()");
          }
        }
      }
    }
    return false;
  }