[ffigen] Fix `sort: true` not working, remove //+ from full comments. (#187)

diff --git a/pkgs/ffigen/CHANGELOG.md b/pkgs/ffigen/CHANGELOG.md
index 4a849f3..abc7d7b 100644
--- a/pkgs/ffigen/CHANGELOG.md
+++ b/pkgs/ffigen/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 2.2.4
+- Fix `sort: true` not working.
+- Fix extra `//` or `///` in comments when using `comments -> style`: `full`.
+
 # 2.2.3
 - Added new subkey `dependency-only` (options - `full (default) | opaque`) under `structs`.
 When set to `opaque`, ffigen will generate empty `Opaque` structs if structs
diff --git a/pkgs/ffigen/example/libclang-example/pubspec.yaml b/pkgs/ffigen/example/libclang-example/pubspec.yaml
index 9c67f6b..fe0f30b 100644
--- a/pkgs/ffigen/example/libclang-example/pubspec.yaml
+++ b/pkgs/ffigen/example/libclang-example/pubspec.yaml
@@ -13,7 +13,9 @@
 
 ffigen:
   output: 'generated_bindings.dart'
-  sort: true
+
+  # This will sort the bindings alphabetically.
+  # sort: true
 
   # This is required if LLVM can't be found in default locations by ffigen.
   # llvm-lib: '/usr/local/opt/llvm/lib'
diff --git a/pkgs/ffigen/lib/src/code_generator/library.dart b/pkgs/ffigen/lib/src/code_generator/library.dart
index 893289d..d83a19d 100644
--- a/pkgs/ffigen/lib/src/code_generator/library.dart
+++ b/pkgs/ffigen/lib/src/code_generator/library.dart
@@ -27,7 +27,10 @@
     required this.bindings,
     String? header,
     bool dartBool = true,
+    bool sort = false,
   }) {
+    if (sort) _sort();
+
     // Seperate bindings which require lookup.
     final lookUpBindings = bindings.whereType<LookUpBinding>().toList();
     final noLookUpBindings = bindings.whereType<NoLookUpBinding>().toList();
@@ -79,7 +82,7 @@
   }
 
   /// Sort all bindings in alphabetical order.
-  void sort() {
+  void _sort() {
     bindings.sort((b1, b2) => b1.name.compareTo(b2.name));
   }
 
diff --git a/pkgs/ffigen/lib/src/header_parser/parser.dart b/pkgs/ffigen/lib/src/header_parser/parser.dart
index 3d4c5f0..a8473af 100644
--- a/pkgs/ffigen/lib/src/header_parser/parser.dart
+++ b/pkgs/ffigen/lib/src/header_parser/parser.dart
@@ -29,11 +29,9 @@
     description: config.wrapperDocComment,
     header: config.preamble,
     dartBool: config.dartBool,
+    sort: config.sort,
   );
 
-  if (config.sort) {
-    library.sort();
-  }
   return library;
 }
 
diff --git a/pkgs/ffigen/lib/src/header_parser/utils.dart b/pkgs/ffigen/lib/src/header_parser/utils.dart
index ef91924..e1b205c 100644
--- a/pkgs/ffigen/lib/src/header_parser/utils.dart
+++ b/pkgs/ffigen/lib/src/header_parser/utils.dart
@@ -193,15 +193,21 @@
   }
   final sb = StringBuffer();
 
-  // Remove comment identifiers.
-  string = string.replaceAll('/*', '');
-  string = string.replaceAll('*/', '');
+  // Remove comment identifiers (`/** * */`, `///`, `//`) from lines.
+  if (string.contains(RegExp(r'^\s*\/\*+'))) {
+    string = string.replaceFirst(RegExp(r'^\s*\/\*+\s*'), '');
+    string = string.replaceFirst(RegExp(r'\s*\*+\/$'), '');
+    string.split('\n').forEach((element) {
+      element = element.replaceFirst(RegExp(r'^\s*\**\s*'), '');
+      sb.writeln(element);
+    });
+  } else if (string.contains(RegExp(r'^\s*\/\/\/?\s*'))) {
+    string.split('\n').forEach((element) {
+      element = element.replaceFirst(RegExp(r'^\s*\/\/\/?\s*'), '');
+      sb.writeln(element);
+    });
+  }
 
-  // Remove any *'s in the beginning of a every line.
-  string.split('\n').forEach((element) {
-    element = element.trim().replaceFirst(RegExp(r'\**'), '').trim();
-    sb.writeln(element);
-  });
   return sb.toString().trim();
 }
 
diff --git a/pkgs/ffigen/pubspec.yaml b/pkgs/ffigen/pubspec.yaml
index 21c65c3..e986dfd 100644
--- a/pkgs/ffigen/pubspec.yaml
+++ b/pkgs/ffigen/pubspec.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE file.
 
 name: ffigen
-version: 2.2.3
+version: 2.2.4
 homepage: https://github.com/dart-lang/ffigen
 description: Generator for FFI bindings, using LibClang to parse C header files.
 
diff --git a/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart b/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart
index 350b799..806ae22 100644
--- a/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart
+++ b/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart
@@ -365,6 +365,19 @@
     );
     _matchLib(library, 'boolean_no_dartbool');
   });
+  test('sort bindings', () {
+    final library = Library(
+      name: 'Bindings',
+      sort: true,
+      bindings: [
+        Func(name: 'b', returnType: Type.nativeType(SupportedNativeType.Void)),
+        Func(name: 'a', returnType: Type.nativeType(SupportedNativeType.Void)),
+        Struc(name: 'd'),
+        Struc(name: 'c'),
+      ],
+    );
+    _matchLib(library, 'sort_bindings');
+  });
 }
 
 /// Utility to match expected bindings to the generated bindings.
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_sort_bindings_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_sort_bindings_bindings.dart
new file mode 100644
index 0000000..aaa8f2d
--- /dev/null
+++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_sort_bindings_bindings.dart
@@ -0,0 +1,45 @@
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+class Bindings {
+  /// Holds the symbol lookup function.
+  final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
+      _lookup;
+
+  /// The symbols are looked up in [dynamicLibrary].
+  Bindings(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup;
+
+  /// The symbols are looked up with [lookup].
+  Bindings.fromLookup(
+      ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
+          lookup)
+      : _lookup = lookup;
+
+  void a() {
+    return _a();
+  }
+
+  late final _a_ptr = _lookup<ffi.NativeFunction<_c_a>>('a');
+  late final _dart_a _a = _a_ptr.asFunction<_dart_a>();
+
+  void b() {
+    return _b();
+  }
+
+  late final _b_ptr = _lookup<ffi.NativeFunction<_c_b>>('b');
+  late final _dart_b _b = _b_ptr.asFunction<_dart_b>();
+}
+
+class c extends ffi.Opaque {}
+
+class d extends ffi.Opaque {}
+
+typedef _c_a = ffi.Void Function();
+
+typedef _dart_a = void Function();
+
+typedef _c_b = ffi.Void Function();
+
+typedef _dart_b = void Function();
diff --git a/pkgs/ffigen/test/example_tests/libclang_example_test.dart b/pkgs/ffigen/test/example_tests/libclang_example_test.dart
index e7cbc56..f385b00 100644
--- a/pkgs/ffigen/test/example_tests/libclang_example_test.dart
+++ b/pkgs/ffigen/test/example_tests/libclang_example_test.dart
@@ -19,7 +19,6 @@
     test('libclang-example', () {
       final config = Config.fromYaml(loadYaml('''
 ${strings.output}: 'generated_bindings.dart'
-${strings.sort}: true
 ${strings.headers}:
   ${strings.entryPoints}:
     - third_party/libclang/include/clang-c/Index.h
diff --git a/pkgs/ffigen/test/header_parser_tests/comment_markup.h b/pkgs/ffigen/test/header_parser_tests/comment_markup.h
new file mode 100644
index 0000000..1201e87
--- /dev/null
+++ b/pkgs/ffigen/test/header_parser_tests/comment_markup.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This is a single line test comment.
+void com1();
+
+/// This is a multi-line
+/// test comment.
+void com2();
+
+/** This is a multi-line
+ * doxygen style
+ * test comment.
+ */
+void com3();
+
+// Test comment for struct.
+struct com4{
+    /// Muli-line test comment for struct field
+    // With multiple line and both // and ///.
+    int a;
+
+    /* Single line field comment. */
+    float b;
+};
diff --git a/pkgs/ffigen/test/header_parser_tests/comment_markup_test.dart b/pkgs/ffigen/test/header_parser_tests/comment_markup_test.dart
new file mode 100644
index 0000000..6d3f8ba
--- /dev/null
+++ b/pkgs/ffigen/test/header_parser_tests/comment_markup_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:ffigen/src/code_generator.dart';
+import 'package:ffigen/src/header_parser.dart' as parser;
+import 'package:ffigen/src/config_provider.dart';
+import 'package:logging/logging.dart';
+import 'package:test/test.dart';
+import 'package:yaml/yaml.dart' as yaml;
+import 'package:ffigen/src/strings.dart' as strings;
+
+import '../test_utils.dart';
+
+late Library actual;
+void main() {
+  group('comment_markup_test', () {
+    setUpAll(() {
+      logWarnings(Level.SEVERE);
+      actual = parser.parse(
+        Config.fromYaml(yaml.loadYaml('''
+${strings.name}: 'NativeLibrary'
+${strings.description}: 'Comment Markup Test'
+${strings.output}: 'unused'
+${strings.headers}:
+  ${strings.entryPoints}:
+    - 'test/header_parser_tests/comment_markup.h'
+${strings.comments}:
+  ${strings.style}: ${strings.any}
+  ${strings.length}: ${strings.full}
+        ''') as yaml.YamlMap),
+      );
+    });
+
+    test('Expected bindings', () {
+      matchLibraryWithExpected(actual, [
+        'test',
+        'debug_generated',
+        'comment_markup_test_output.dart'
+      ], [
+        'test',
+        'header_parser_tests',
+        'expected_bindings',
+        '_expected_comment_markup_bindings.dart'
+      ]);
+    });
+  });
+}
diff --git a/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_comment_markup_bindings.dart b/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_comment_markup_bindings.dart
new file mode 100644
index 0000000..75bc7c7
--- /dev/null
+++ b/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_comment_markup_bindings.dart
@@ -0,0 +1,72 @@
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+/// Comment Markup Test
+class NativeLibrary {
+  /// Holds the symbol lookup function.
+  final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
+      _lookup;
+
+  /// The symbols are looked up in [dynamicLibrary].
+  NativeLibrary(ffi.DynamicLibrary dynamicLibrary)
+      : _lookup = dynamicLibrary.lookup;
+
+  /// The symbols are looked up with [lookup].
+  NativeLibrary.fromLookup(
+      ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
+          lookup)
+      : _lookup = lookup;
+
+  /// This is a single line test comment.
+  void com1() {
+    return _com1();
+  }
+
+  late final _com1_ptr = _lookup<ffi.NativeFunction<_c_com1>>('com1');
+  late final _dart_com1 _com1 = _com1_ptr.asFunction<_dart_com1>();
+
+  /// This is a multi-line
+  /// test comment.
+  void com2() {
+    return _com2();
+  }
+
+  late final _com2_ptr = _lookup<ffi.NativeFunction<_c_com2>>('com2');
+  late final _dart_com2 _com2 = _com2_ptr.asFunction<_dart_com2>();
+
+  /// This is a multi-line
+  /// doxygen style
+  /// test comment.
+  void com3() {
+    return _com3();
+  }
+
+  late final _com3_ptr = _lookup<ffi.NativeFunction<_c_com3>>('com3');
+  late final _dart_com3 _com3 = _com3_ptr.asFunction<_dart_com3>();
+}
+
+/// Test comment for struct.
+class com4 extends ffi.Struct {
+  /// Muli-line test comment for struct field
+  /// With multiple line and both // and ///.
+  @ffi.Int32()
+  external int a;
+
+  /// Single line field comment.
+  @ffi.Float()
+  external double b;
+}
+
+typedef _c_com1 = ffi.Void Function();
+
+typedef _dart_com1 = void Function();
+
+typedef _c_com2 = ffi.Void Function();
+
+typedef _dart_com2 = void Function();
+
+typedef _c_com3 = ffi.Void Function();
+
+typedef _dart_com3 = void Function();
diff --git a/pkgs/ffigen/test/native_test/config.yaml b/pkgs/ffigen/test/native_test/config.yaml
index 3933518..7abdce4 100644
--- a/pkgs/ffigen/test/native_test/config.yaml
+++ b/pkgs/ffigen/test/native_test/config.yaml
@@ -9,7 +9,6 @@
 name: NativeLibrary
 description: 'Native tests.'
 output: 'test/native_test/native_test_bindings.dart'
-sort: true
 headers:
   entry-points:
     - 'test/native_test/native_test.c'