@SuppressWarnings("unchecked")
 static <E extends Element> E cleanClone(E e) {
   E c = (E) e.clone();
   c.setCommentBefore(null);
   c.setCommentAfter(null);
   if (c instanceof Declaration) {
     Declaration d = (Declaration) c;
     d.setAnnotations(null);
   }
   return c;
 }
  protected void outputEnumItemsAsConstants(
      List<EnumItemResult> results,
      DeclarationsHolder out,
      Signatures signatures,
      Identifier libraryClassName,
      boolean hasEnumClass) {

    for (EnumItemResult er : results) {
      try {
        if (er.errorElement != null) {
          out.addDeclaration(er.errorElement);
          continue;
        }
        String itemName =
            result.typeConverter.getValidJavaIdentifierString(ident(er.originalItem.getName()));
        Declaration ct =
            outputConstant(
                itemName,
                result.typeConverter.convertExpressionToJava(
                    er.unconvertedValue, libraryClassName, true),
                signatures,
                er.originalItem,
                "enum item",
                libraryClassName,
                hasEnumClass,
                true,
                true,
                true);
        if (!result.config.noComments)
          if (ct != null && hasEnumClass) {
            String c = ct.getCommentBefore();
            ct.setCommentBefore(er.originalItem.getCommentBefore());
            ct.addToCommentBefore(c);
          }
        out.addDeclaration(ct);
      } catch (Exception ex) {
        out.addDeclaration(skipDeclaration(er.originalItem, ex.toString()));
      }
    }
  }
  public void convertFunction(
      Function function,
      Signatures signatures,
      boolean isCallback,
      final DeclarationsHolder out,
      final Identifier libraryClassName,
      int iConstructor) {
    if (result.config.functionsAccepter != null && !result.config.functionsAccepter.adapt(function))
      return;

    // if (function.findParentOfType(Template))
    String library = result.getLibrary(function);
    Identifier functionName = function.getName();
    boolean isMethod = function.getParentElement() instanceof Struct;
    if (functionName == null || isCallback) {
      if (function.getParentElement() instanceof FunctionSignature)
        functionName = ident(result.config.callbackInvokeMethodName);
      else return;
    }
    if (function.getParentElement() instanceof FriendDeclaration) return;

    String n = functionName.toString();
    if (n.contains("<") || n.startsWith("~")) return;

    if (result.config.beautifyNames) functionName = ident(result.typeConverter.beautify(n, false));

    functionName = result.typeConverter.getValidJavaMethodName(functionName);
    if (functionName == null) return;

    // if (functionName.equals("operator"))
    //    functionName

    String sig = function.computeSignature(SignatureType.JavaStyle);

    DeclarationsHolder objOut =
        result.config.reification && !isCallback && !isMethod
            ? new DeclarationsHolder() {

              @Override
              public void addDeclaration(Declaration d) {
                out.addDeclaration(d);
                if (d instanceof Function) {
                  Function f = (Function) d;
                  List<Arg> args = f.getArgs();
                  List<TypeRef> trs = new ArrayList<TypeRef>(2);
                  trs.add(f.getValueType());
                  if (!args.isEmpty()) trs.add(args.get(0).getValueType());

                  for (TypeRef tr : trs) {
                    if (tr instanceof SimpleTypeRef) {
                      Identifier id = ((SimpleTypeRef) tr).getName();
                      if (result.isFakePointer(id)) {
                        result.addFunctionReifiableInFakePointer(id, libraryClassName, f);
                      }
                    }
                  }
                }
              }

              @Override
              public List<Declaration> getDeclarations() {
                return out.getDeclarations();
              }
            }
            : out;

    try {
      convertFunction(
          function,
          signatures,
          isCallback,
          objOut,
          libraryClassName,
          sig,
          functionName,
          library,
          iConstructor);
    } catch (UnsupportedConversionException ex) {
      Declaration d = skipDeclaration(function);
      if (d != null) {
        d.addToCommentBefore(ex.toString());
        out.addDeclaration(d);
      }
    }
  }
  @SuppressWarnings("static-access")
  protected Declaration outputConstant(
      String name,
      Pair<Expression, TypeRef> x,
      Signatures signatures,
      Element element,
      String elementTypeDescription,
      Identifier libraryClassName,
      boolean addFileComment,
      boolean signalErrors,
      boolean forceInteger,
      boolean alreadyConverted)
      throws UnsupportedConversionException {
    try {
      if (result.typeConverter.isJavaKeyword(name))
        throw new UnsupportedConversionException(
            element, "The name '" + name + "' is invalid for a Java field.");

      Pair<Expression, TypeRef> converted =
          alreadyConverted
              ? x
              : result.typeConverter.convertExpressionToJava(x.getFirst(), libraryClassName, true);
      // TypeRef tr = result.typeConverter.inferJavaType(converted);
      JavaPrim prim = result.typeConverter.getPrimitive(converted.getValue(), libraryClassName);

      if (forceInteger && prim == JavaPrim.Boolean) {
        prim = JavaPrim.Int;
        // tr = typeRef("int");
        converted =
            pair(
                expr("true".equals(String.valueOf(converted.toString())) ? 1 : 0),
                typeRef(Integer.TYPE));
      }

      if ((prim == null || converted.getValue() == null) && signalErrors) {
        if (result.config.limitComments) return null;

        return new EmptyDeclaration("Failed to infer type of " + converted);
      } else if (prim != JavaPrim.Void && converted.getValue() != null) {
        //				if (prim == JavaPrim.Int)
        //					tr = typeRef("long");

        if (signatures.addVariable(name)) {
          String t = converted.toString();
          if (t.contains("sizeof")) {
            converted =
                alreadyConverted
                    ? x
                    : result.typeConverter.convertExpressionToJava(
                        x.getFirst(), libraryClassName, false);
          }
          // TypeRef tr = new TypeRef.SimpleTypeRef(result.typeConverter.typeToJNA(type, vs,
          // TypeConversion.TypeConversionMode.FieldType, callerLibraryClass));
          TypeRef tr = converted.getValue();
          Expression value = converted.getFirst();
          if (result.config.castConstants) {
            if (!(value instanceof Constant) && !(value instanceof VariableRef))
              value.setParenthesis(true);
            value = new Cast(tr, value);
          }

          Declaration declaration = new VariablesDeclaration(tr, new DirectDeclarator(name, value));
          declaration.addModifiers(ModifierType.Public, ModifierType.Static, ModifierType.Final);
          if (!result.config.noComments)
            declaration.importComments(
                element, addFileComment ? getFileCommentContent(element) : null);
          return declaration;
        }
      }
      return skipDeclaration(element, elementTypeDescription);
    } catch (UnsupportedConversionException e) {
      return skipDeclaration(element, elementTypeDescription, e.toString());
    }
  }