Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve function parameter names in output #515

Closed
RdeWilde opened this issue Jul 25, 2020 · 8 comments
Closed

Preserve function parameter names in output #515

RdeWilde opened this issue Jul 25, 2020 · 8 comments

Comments

@RdeWilde
Copy link

RdeWilde commented Jul 25, 2020

When I parse the header files, all parameter names are being replace with arg0 arg1 arg2. It would be very usefull if the generator could keep the original name instead of the numbered arguments.

inline bool MyFunc(const CMyObject& myParam) { return 1; }

output

int MyFunc(
  int arg0,
) {
_MyFunc ??= _dylib.lookupFunction<_c_MyFunc,_dart_MyFunc>('MyFunc');
  return _MyFunc(
    arg0,
  );
}
_dart_MyFunc _MyFunc;

typedef _c_MyFunc = ffi.Int32 Function(
  ffi.Int64 arg0,
);

typedef _dart_MyFunc = int Function(
  int arg0,
);

to

int MyFunc(
  int myParam,
) {
_MyFunc ??= _dylib.lookupFunction<_c_MyFunc,_dart_MyFunc>('MyFunc');
  return _MyFunc(
    myParam,
  );
}
_dart_MyFunc _MyFunc;

typedef _c_MyFunc = ffi.Int32 Function(
  ffi.Int64 myParam,
);

typedef _dart_MyFunc = int Function(
  int myParam,
);
@mannprerak2
Copy link
Contributor

The generator should preserve the names, but only if the names are present in the header file you passed into it.
Can you check to see if the function declaration in the header file contain names for the argument?

@RdeWilde
Copy link
Author

RdeWilde commented Jul 25, 2020

All arguments are all arg0, arg1 etc.

This is from the header files:

inline bool MoneyRange(const CAmount& nValue) {
   // ..
}

In the output, nValue is changed to arg0 as in the example above

Btw, this is CAmount in the file, although it is not included in the output:

typedef int64_t CAmount;

This is my config:

ffigen:
  output: 'generated_bridge.dart'
  headers:
    - 'src/example/src/amount.h'
  header-filter:
    exclude:
      - 'stdint.h'
      - 'stdio.h'
      - 'stdlib.h'
      - 'assert.h'
  name: 'Bridge'
  description: 'Bridge to example'
  array-workaround: true

@mannprerak2
Copy link
Contributor

mannprerak2 commented Jul 25, 2020

That's strange, could you try running pub run ffigen --verbose all. It will print all kinds of AST related stuff, you should then be able to see there if clang actually sees the parameter's name
This could be a pretty big file.

@RdeWilde
Copy link
Author

RdeWilde commented Jul 25, 2020

Here's the output for the verbose ffigen:
https://gist.github.com/RdeWilde/e296ce86c77f71a3ba2a1d37f10b3ebb

Here's the source file:
https://github.com/bitcoin/bitcoin/blob/master/src/amount.h

Here's the actual dart output:

/// AUTO GENERATED FILE, DO NOT EDIT.
///
/// Generated by `package:ffigen`.
import 'dart:ffi' as ffi;

/// Bridge to example
class ExampleBridge {
  /// Holds the Dynamic library.
  final ffi.DynamicLibrary _dylib;

  /// The symbols are looked up in [dynamicLibrary].
  ExampleBridge(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary;

  int MoneyRange(
    int arg0,
  ) {
    _MoneyRange ??=
        _dylib.lookupFunction<_c_MoneyRange, _dart_MoneyRange>('MoneyRange');
    return _MoneyRange(
      arg0,
    );
  }

  _dart_MoneyRange _MoneyRange;
}

class __fsid_t extends ffi.Struct {
  @ffi.Int32()
  int _unique___val_item_0;
  @ffi.Int32()
  int _unique___val_item_1;

  /// Helper for array `__val`.
  ArrayHelper___fsid_t___val_level0 get __val =>
      ArrayHelper___fsid_t___val_level0(this, [2], 0, 0);
}

/// Helper for array `__val` in struct `__fsid_t`.
class ArrayHelper___fsid_t___val_level0 {
  final __fsid_t _struct;
  final List<int> dimensions;
  final int level;
  final int _absoluteIndex;
  int get length => dimensions[level];
  ArrayHelper___fsid_t___val_level0(
      this._struct, this.dimensions, this.level, this._absoluteIndex);
  void _checkBounds(int index) {
    if (index >= length || index < 0) {
      throw RangeError(
          'Dimension $level: index not in range 0..${length} exclusive.');
    }
  }

  int operator [](int index) {
    _checkBounds(index);
    switch (_absoluteIndex + index) {
      case 0:
        return _struct._unique___val_item_0;
      case 1:
        return _struct._unique___val_item_1;
      default:
        throw Exception('Invalid Array Helper generated.');
    }
  }

  void operator []=(int index, int value) {
    _checkBounds(index);
    switch (_absoluteIndex + index) {
      case 0:
        _struct._unique___val_item_0 = value;
        break;
      case 1:
        _struct._unique___val_item_1 = value;
        break;
      default:
        throw Exception('Invalid Array Helper generated.');
    }
  }
}

typedef _c_MoneyRange = ffi.Int32 Function(
  ffi.Int64 arg0,
);

typedef _dart_MoneyRange = int Function(
  int arg0,
);

(I replaced a few names here and there just to keep it generic)

@mannprerak2
Copy link
Contributor

Thanks.
Clang actually generated some warnings for this header file -

FINE    : Creating TranslationUnit for header: src/example/src/amount.h
WARNING : Header src/example/src/amount.h: Total errors/warnings: 3.
WARNING :     src/example/src/amount.h:26:8: error: unknown type name 'bool' [Semantic Issue]
WARNING :     src/example/src/amount.h:26:37: error: expected ')' [Parse Issue]
WARNING :     src/example/src/amount.h:26:37: error: parameter name omitted [Semantic Issue]

It tries to somehow fix the errors while parse the source, and during that process is not able to get the argument name
which is evident from this log (parameter: (Cursor) spelling: , spelling is empty)

FINE    : ++++ Adding Function: (Cursor) spelling: MoneyRange, kind: 8, kindSpelling: FunctionDecl, type: 111, typeSpelling: int (const CAmount)
FINE    :   getCodeGenType (Type) spelling: int, kind: 17, kindSpelling: Int
FINER   : ===== parameter: (Cursor) spelling: , kind: 10, kindSpelling: ParmDecl, type: 107, typeSpelling: const CAmount
FINE    :   getCodeGenType (Type) spelling: const CAmount, kind: 107, kindSpelling: Typedef
FINE    :   getCodeGenType (Type) spelling: const long, kind: 18, kindSpelling: Long

@mannprerak2
Copy link
Contributor

Tried parsing this as hpp file

typedef long long CAmount;
bool MoneyRange(const CAmount& nValue);

Tool cannot parse this (as of now )because

  • return type bool is not supported
  • const CAmount& is of type LValueReference which is also not supported

@RdeWilde
Copy link
Author

Oh yeah, cool. I removed the by reference (just for testing) and the param name shows up now.

Any reason why the return type bool isn't supported? Just curious.

@mannprerak2
Copy link
Contributor

I have filed these 2 issues - #500 and #501 for the missing features.
I'll close this one, feel free to open a new issue if you have any further issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants