Support `@Native` fields and `addressOf` (#860)

diff --git a/.github/workflows/ffigen.yml b/.github/workflows/ffigen.yml
index 945cca2..4c290e7 100644
--- a/.github/workflows/ffigen.yml
+++ b/.github/workflows/ffigen.yml
@@ -28,7 +28,8 @@
     strategy:
       fail-fast: false
       matrix:
-        sdk: [3.2.0]
+        sdk: [dev]
+#        sdk: [3.3.0]
     steps:
       - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
       - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d
@@ -56,7 +57,7 @@
       - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
       - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d
         with:
-          sdk: 3.2.0
+          sdk: dev  #3.3.0
       - name: Install dependencies
         run: dart pub get
       - name: Install libclang-14-dev
@@ -77,7 +78,7 @@
       - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
       - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d
         with:
-          sdk: 3.2.0
+          sdk: dev #3.3.0
       - name: Install dependencies
         run: dart pub get
       - name: Build test dylib and bindings
@@ -110,7 +111,7 @@
       - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
       - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d
         with:
-          sdk: 3.2.0
+          sdk: dev #3.3.0
       - name: Install dependencies
         run: dart pub get
       - name: Build test dylib and bindings
diff --git a/.github/workflows/ffigen_weekly.yml b/.github/workflows/ffigen_weekly.yml
index 4d8d106..80488b7 100644
--- a/.github/workflows/ffigen_weekly.yml
+++ b/.github/workflows/ffigen_weekly.yml
@@ -22,7 +22,7 @@
       - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
       - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d
         with:
-          sdk: 3.2.0
+          sdk: dev #3.3.0
       - name: Install dependencies
         run: dart pub get
       - name: Build test dylib and bindings
diff --git a/.github/workflows/health.yaml b/.github/workflows/health.yaml
index 0e0c194..72e04d2 100644
--- a/.github/workflows/health.yaml
+++ b/.github/workflows/health.yaml
@@ -10,5 +10,6 @@
       coverage_web: false
       checks: "version,changelog,license,do-not-submit,breaking"
       use-flutter: true
+      sdk: master
     permissions:
       pull-requests: write
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
index 4c00b14..c7f1d2c 100644
--- a/.github/workflows/publish.yaml
+++ b/.github/workflows/publish.yaml
@@ -17,4 +17,4 @@
       pull-requests: write # Required for writing the pull request note
     with:
       write-comments: false
-      sdk: beta
+      sdk: dev # use beta/stable after 3.3.0
diff --git a/pkgs/ffigen/CHANGELOG.md b/pkgs/ffigen/CHANGELOG.md
index cc50b1d..c65a61a 100644
--- a/pkgs/ffigen/CHANGELOG.md
+++ b/pkgs/ffigen/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 12.0.0-dev
+
+- Global variables are now compatible with the `ffi-native` option.
+- Exposing symbol addresses of functions and globals is now compatible with the
+  `ffi-native` option.
+
 ## 11.0.0
 
 - Any compiler errors/warnings in source header files will now result in
diff --git a/pkgs/ffigen/example/ffinative/config.yaml b/pkgs/ffigen/example/ffinative/config.yaml
index 1bb3dac..002d7fe 100644
--- a/pkgs/ffigen/example/ffinative/config.yaml
+++ b/pkgs/ffigen/example/ffinative/config.yaml
@@ -9,4 +9,16 @@
   entry-points:
     - 'headers/example.h'
 preamble: |
+  // Copyright (c) 2020, 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.
+
   // ignore_for_file: deprecated_member_use
+functions:
+  symbol-address:
+    include:
+      - sum
+globals:
+  symbol-address:
+    include:
+      - library_version
diff --git a/pkgs/ffigen/example/ffinative/headers/example.h b/pkgs/ffigen/example/ffinative/headers/example.h
index 44056dd..82df9c7 100644
--- a/pkgs/ffigen/example/ffinative/headers/example.h
+++ b/pkgs/ffigen/example/ffinative/headers/example.h
@@ -16,3 +16,10 @@
 
 /** Divides 2 floats, returns a pointer to double. */
 double *dividePrecision(float a, float b);
+
+int log_level = -1;
+
+const int array[5] = {0, 1, 2, 3, 4};
+
+/** Version of the native C library */
+const char* const library_version = "1.0.0-native";
diff --git a/pkgs/ffigen/example/ffinative/lib/generated_bindings.dart b/pkgs/ffigen/example/ffinative/lib/generated_bindings.dart
index 13c7d2b..39e0984 100644
--- a/pkgs/ffigen/example/ffinative/lib/generated_bindings.dart
+++ b/pkgs/ffigen/example/ffinative/lib/generated_bindings.dart
@@ -1,51 +1,71 @@
+// Copyright (c) 2020, 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.
+
 // ignore_for_file: deprecated_member_use
 
 // AUTO GENERATED FILE, DO NOT EDIT.
 //
 // Generated by `package:ffigen`.
 // ignore_for_file: type=lint
+@ffi.DefaultAsset('package:ffinative_example/generated_bindings.dart')
+library;
+
 import 'dart:ffi' as ffi;
+import '' as self;
 
 /// Adds 2 integers.
-@ffi.Native<ffi.Int Function(ffi.Int, ffi.Int)>(
-    symbol: 'sum', assetId: 'package:ffinative_example/generated_bindings.dart')
+@ffi.Native<ffi.Int Function(ffi.Int, ffi.Int)>()
 external int sum(
   int a,
   int b,
 );
 
 /// Subtracts 2 integers.
-@ffi.Native<ffi.Int Function(ffi.Int, ffi.Int)>(
-    symbol: 'subtract',
-    assetId: 'package:ffinative_example/generated_bindings.dart')
+@ffi.Native<ffi.Int Function(ffi.Int, ffi.Int)>()
 external int subtract(
   int a,
   int b,
 );
 
 /// Multiplies 2 integers, returns pointer to an integer,.
-@ffi.Native<ffi.Pointer<ffi.Int> Function(ffi.Int, ffi.Int)>(
-    symbol: 'multiply',
-    assetId: 'package:ffinative_example/generated_bindings.dart')
+@ffi.Native<ffi.Pointer<ffi.Int> Function(ffi.Int, ffi.Int)>()
 external ffi.Pointer<ffi.Int> multiply(
   int a,
   int b,
 );
 
 /// Divides 2 integers, returns pointer to a float.
-@ffi.Native<ffi.Pointer<ffi.Float> Function(ffi.Int, ffi.Int)>(
-    symbol: 'divide',
-    assetId: 'package:ffinative_example/generated_bindings.dart')
+@ffi.Native<ffi.Pointer<ffi.Float> Function(ffi.Int, ffi.Int)>()
 external ffi.Pointer<ffi.Float> divide(
   int a,
   int b,
 );
 
 /// Divides 2 floats, returns a pointer to double.
-@ffi.Native<ffi.Pointer<ffi.Double> Function(ffi.Float, ffi.Float)>(
-    symbol: 'dividePrecision',
-    assetId: 'package:ffinative_example/generated_bindings.dart')
+@ffi.Native<ffi.Pointer<ffi.Double> Function(ffi.Float, ffi.Float)>()
 external ffi.Pointer<ffi.Double> dividePrecision(
   double a,
   double b,
 );
+
+@ffi.Native<ffi.Int>()
+external int log_level;
+
+@ffi.Array.multi([5])
+@ffi.Native<ffi.Array<ffi.Int>>()
+external ffi.Array<ffi.Int> array;
+
+/// Version of the native C library
+@ffi.Native<ffi.Pointer<ffi.Char>>()
+external final ffi.Pointer<ffi.Char> library_version;
+
+const addresses = _SymbolAddresses();
+
+class _SymbolAddresses {
+  const _SymbolAddresses();
+  ffi.Pointer<ffi.NativeFunction<ffi.Int Function(ffi.Int, ffi.Int)>> get sum =>
+      ffi.Native.addressOf(self.sum);
+  ffi.Pointer<ffi.Pointer<ffi.Char>> get library_version =>
+      ffi.Native.addressOf(self.library_version);
+}
diff --git a/pkgs/ffigen/example/ffinative/pubspec.yaml b/pkgs/ffigen/example/ffinative/pubspec.yaml
index e971031..226c26c 100644
--- a/pkgs/ffigen/example/ffinative/pubspec.yaml
+++ b/pkgs/ffigen/example/ffinative/pubspec.yaml
@@ -5,7 +5,7 @@
 name: ffinative_example
 
 environment:
-  sdk: '>=3.2.0 <4.0.0'
+  sdk: '>=3.3.0-252.0.dev <4.0.0'
 
 dependencies:
   ffi: ^2.0.1
diff --git a/pkgs/ffigen/lib/src/code_generator/compound.dart b/pkgs/ffigen/lib/src/code_generator/compound.dart
index 1f9706e..1cc3697 100644
--- a/pkgs/ffigen/lib/src/code_generator/compound.dart
+++ b/pkgs/ffigen/lib/src/code_generator/compound.dart
@@ -80,16 +80,6 @@
     }
   }
 
-  List<int> _getArrayDimensionLengths(Type type) {
-    final array = <int>[];
-    var startType = type;
-    while (startType is ConstantArray) {
-      array.add(startType.length);
-      startType = startType.child;
-    }
-    return array;
-  }
-
   String _getInlineArrayTypeString(Type type, Writer w) {
     if (type is ConstantArray) {
       return '${w.ffiLibraryPrefix}.Array<'
@@ -132,9 +122,8 @@
         s.writeAll(m.dartDoc!.split('\n'), '\n$depth/// ');
         s.write('\n');
       }
-      if (m.type is ConstantArray) {
-        s.write('$depth@${w.ffiLibraryPrefix}.Array.multi(');
-        s.write('${_getArrayDimensionLengths(m.type)})\n');
+      if (m.type case final ConstantArray arrayType) {
+        s.writeln(makeArrayAnnotation(w, arrayType));
         s.write('${depth}external ${_getInlineArrayTypeString(m.type, w)} ');
         s.write('${m.name};\n\n');
       } else {
diff --git a/pkgs/ffigen/lib/src/code_generator/func.dart b/pkgs/ffigen/lib/src/code_generator/func.dart
index 43f17eb..1c518f9 100644
--- a/pkgs/ffigen/lib/src/code_generator/func.dart
+++ b/pkgs/ffigen/lib/src/code_generator/func.dart
@@ -145,13 +145,15 @@
     }
 
     if (ffiNativeConfig.enabled) {
-      final assetString = ffiNativeConfig.assetId != null
-          ? ", assetId: '${ffiNativeConfig.assetId}'"
-          : '';
-      final isLeafString = isLeaf ? ', isLeaf:true' : '';
       final nativeFuncName = needsWrapper ? funcVarName : enclosingFuncName;
       s.write('''
-@${w.ffiLibraryPrefix}.Native<$cType>(symbol: '$originalName'$assetString$isLeafString)
+${makeNativeAnnotation(
+        w,
+        nativeType: cType,
+        dartName: nativeFuncName,
+        nativeSymbolName: originalName,
+        isLeaf: isLeaf,
+      )}
 external $ffiReturnType $nativeFuncName($ffiArgDeclString);
 
 ''');
@@ -164,6 +166,15 @@
 
 ''');
       }
+
+      if (exposeSymbolAddress) {
+        // Add to SymbolAddress in writer.
+        w.symbolAddressWriter.addNativeSymbol(
+          type:
+              '${w.ffiLibraryPrefix}.Pointer<${w.ffiLibraryPrefix}.NativeFunction<$cType>>',
+          name: name,
+        );
+      }
     } else {
       funcPointerName = w.wrapperLevelUniqueNamer.makeUnique('_${name}Ptr');
       final isLeafString = isLeaf ? 'isLeaf:true' : '';
diff --git a/pkgs/ffigen/lib/src/code_generator/global.dart b/pkgs/ffigen/lib/src/code_generator/global.dart
index 47aee0d..439a2f3 100644
--- a/pkgs/ffigen/lib/src/code_generator/global.dart
+++ b/pkgs/ffigen/lib/src/code_generator/global.dart
@@ -2,9 +2,11 @@
 // 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 '../config_provider/config_types.dart';
 import 'binding.dart';
 import 'binding_string.dart';
 import 'compound.dart';
+import 'pointer.dart';
 import 'type.dart';
 import 'utils.dart';
 import 'writer.dart';
@@ -22,6 +24,7 @@
 class Global extends LookUpBinding {
   final Type type;
   final bool exposeSymbolAddress;
+  final FfiNativeConfig nativeConfig;
   final bool constant;
 
   Global({
@@ -32,6 +35,7 @@
     super.dartDoc,
     this.exposeSymbolAddress = false,
     this.constant = false,
+    this.nativeConfig = const FfiNativeConfig(enabled: false),
   });
 
   @override
@@ -41,35 +45,63 @@
     if (dartDoc != null) {
       s.write(makeDartDoc(dartDoc!));
     }
-    final pointerName = w.wrapperLevelUniqueNamer.makeUnique('_$globalVarName');
     final dartType = type.getFfiDartType(w);
     final cType = type.getCType(w);
 
-    s.write(
-        "late final ${w.ffiLibraryPrefix}.Pointer<$cType> $pointerName = ${w.lookupFuncIdentifier}<$cType>('$originalName');\n\n");
-    final baseTypealiasType = type.typealiasType;
-    if (baseTypealiasType is Compound) {
-      if (baseTypealiasType.isOpaque) {
-        s.write(
-            '${w.ffiLibraryPrefix}.Pointer<$cType> get $globalVarName => $pointerName;\n\n');
-      } else {
-        s.write('$dartType get $globalVarName => $pointerName.ref;\n\n');
+    if (nativeConfig.enabled) {
+      if (type case final ConstantArray arr) {
+        s.writeln(makeArrayAnnotation(w, arr));
+      }
+
+      s
+        ..writeln(makeNativeAnnotation(
+          w,
+          nativeType: cType,
+          dartName: globalVarName,
+          nativeSymbolName: originalName,
+          isLeaf: false,
+        ))
+        ..write('external ');
+      if (constant) {
+        s.write('final ');
+      }
+
+      s.writeln('$dartType $globalVarName;\n');
+
+      if (exposeSymbolAddress) {
+        w.symbolAddressWriter.addNativeSymbol(
+            type: '${w.ffiLibraryPrefix}.Pointer<$cType>', name: name);
       }
     } else {
-      s.write('$dartType get $globalVarName => $pointerName.value;\n\n');
-      if (!constant) {
-        s.write(
-            'set $globalVarName($dartType value) => $pointerName.value = value;\n\n');
-      }
-    }
+      final pointerName =
+          w.wrapperLevelUniqueNamer.makeUnique('_$globalVarName');
 
-    if (exposeSymbolAddress) {
-      // Add to SymbolAddress in writer.
-      w.symbolAddressWriter.addSymbol(
-        type: '${w.ffiLibraryPrefix}.Pointer<$cType>',
-        name: name,
-        ptrName: pointerName,
-      );
+      s.write(
+          "late final ${w.ffiLibraryPrefix}.Pointer<$cType> $pointerName = ${w.lookupFuncIdentifier}<$cType>('$originalName');\n\n");
+      final baseTypealiasType = type.typealiasType;
+      if (baseTypealiasType is Compound) {
+        if (baseTypealiasType.isOpaque) {
+          s.write(
+              '${w.ffiLibraryPrefix}.Pointer<$cType> get $globalVarName => $pointerName;\n\n');
+        } else {
+          s.write('$dartType get $globalVarName => $pointerName.ref;\n\n');
+        }
+      } else {
+        s.write('$dartType get $globalVarName => $pointerName.value;\n\n');
+        if (!constant) {
+          s.write(
+              'set $globalVarName($dartType value) => $pointerName.value = value;\n\n');
+        }
+      }
+
+      if (exposeSymbolAddress) {
+        // Add to SymbolAddress in writer.
+        w.symbolAddressWriter.addSymbol(
+          type: '${w.ffiLibraryPrefix}.Pointer<$cType>',
+          name: name,
+          ptrName: pointerName,
+        );
+      }
     }
 
     return BindingString(type: BindingStringType.global, string: s.toString());
diff --git a/pkgs/ffigen/lib/src/code_generator/imports.dart b/pkgs/ffigen/lib/src/code_generator/imports.dart
index e9dda1c..f620909 100644
--- a/pkgs/ffigen/lib/src/code_generator/imports.dart
+++ b/pkgs/ffigen/lib/src/code_generator/imports.dart
@@ -76,6 +76,7 @@
 
 final ffiImport = LibraryImport('ffi', 'dart:ffi');
 final ffiPkgImport = LibraryImport('pkg_ffi', 'package:ffi/ffi.dart');
+final self = LibraryImport('self', '');
 
 final voidType = ImportedType(ffiImport, 'Void', 'void');
 
diff --git a/pkgs/ffigen/lib/src/code_generator/library.dart b/pkgs/ffigen/lib/src/code_generator/library.dart
index 75cbdeb..60ad7c3 100644
--- a/pkgs/ffigen/lib/src/code_generator/library.dart
+++ b/pkgs/ffigen/lib/src/code_generator/library.dart
@@ -5,13 +5,13 @@
 import 'dart:io';
 
 import 'package:cli_util/cli_util.dart';
+import 'package:collection/collection.dart';
 import 'package:ffigen/src/code_generator.dart';
 import 'package:ffigen/src/config_provider/config_types.dart';
 import 'package:logging/logging.dart';
 import 'package:path/path.dart' as p;
 import 'package:yaml_edit/yaml_edit.dart';
 
-import '../strings.dart' as strings;
 import 'utils.dart';
 import 'writer.dart';
 
@@ -34,25 +34,13 @@
     StructPackingOverride? packingOverride,
     Set<LibraryImport>? libraryImports,
   }) {
-    /// Get all dependencies (includes itself).
-    final dependencies = <Binding>{};
-    for (final b in bindings) {
-      b.addDependencies(dependencies);
-    }
-
-    /// Save bindings.
-    this.bindings = dependencies.toList();
-
-    if (sort) {
-      _sort();
-    }
+    _findBindings(bindings, sort);
 
     /// Handle any declaration-declaration name conflicts and emit warnings.
     final declConflictHandler = UniqueNamer({});
     for (final b in this.bindings) {
       _warnIfPrivateDeclaration(b);
       _resolveIfNameConflicts(declConflictHandler, b);
-      _warnIfExposeSymbolAddressAndFfiNative(b);
     }
 
     // Override pack values according to config. We do this after declaration
@@ -66,23 +54,31 @@
     }
 
     // Seperate bindings which require lookup.
-    final lookUpBindings = this.bindings.whereType<LookUpBinding>().where((e) {
-      if (e is Func) {
-        return !e.ffiNativeConfig.enabled;
-      }
-      return true;
-    }).toList();
-    final ffiNativeBindings = this
-        .bindings
-        .whereType<Func>()
-        .where((e) => e.ffiNativeConfig.enabled)
-        .toList();
+    final lookupBindings = <LookUpBinding>[];
+    final nativeBindings = <LookUpBinding>[];
+    FfiNativeConfig? nativeConfig;
+
+    for (final binding in this.bindings.whereType<LookUpBinding>()) {
+      final nativeConfigForBinding = switch (binding) {
+        Func() => binding.ffiNativeConfig,
+        Global() => binding.nativeConfig,
+        _ => null,
+      };
+
+      // At the moment, all bindings share their native config.
+      nativeConfig ??= nativeConfigForBinding;
+
+      final usesLookup =
+          nativeConfigForBinding == null || !nativeConfigForBinding.enabled;
+      (usesLookup ? lookupBindings : nativeBindings).add(binding);
+    }
     final noLookUpBindings =
         this.bindings.whereType<NoLookUpBinding>().toList();
 
     _writer = Writer(
-      lookUpBindings: lookUpBindings,
-      ffiNativeBindings: ffiNativeBindings,
+      lookUpBindings: lookupBindings,
+      ffiNativeBindings: nativeBindings,
+      nativeAssetId: nativeConfig?.assetId,
       noLookUpBindings: noLookUpBindings,
       className: name,
       classDocComment: description,
@@ -91,6 +87,20 @@
     );
   }
 
+  void _findBindings(List<Binding> original, bool sort) {
+    /// Get all dependencies (includes itself).
+    final dependencies = <Binding>{};
+    for (final b in original) {
+      b.addDependencies(dependencies);
+    }
+
+    /// Save bindings.
+    bindings = dependencies.toList();
+    if (sort) {
+      bindings.sortBy((b) => b.name);
+    }
+  }
+
   /// Logs a warning if generated declaration will be private.
   void _warnIfPrivateDeclaration(Binding b) {
     if (b.name.startsWith('_') && !b.isInternal) {
@@ -113,21 +123,6 @@
     }
   }
 
-  /// Logs a warning if generated declaration will be private.
-  void _warnIfExposeSymbolAddressAndFfiNative(Binding b) {
-    if (b is Func) {
-      if (b.exposeSymbolAddress && b.ffiNativeConfig.enabled) {
-        _logger.warning(
-            "Ignoring ${strings.symbolAddress} for '${b.name}' because it is generated as FfiNative.");
-      }
-    }
-  }
-
-  /// Sort all bindings in alphabetical order.
-  void _sort() {
-    bindings.sort((b1, b2) => b1.name.compareTo(b2.name));
-  }
-
   /// Generates [file] by generating C bindings.
   ///
   /// If format is true(default), the formatter will be called to format the generated file.
diff --git a/pkgs/ffigen/lib/src/code_generator/pointer.dart b/pkgs/ffigen/lib/src/code_generator/pointer.dart
index 30e2e6b..b3f6cfb 100644
--- a/pkgs/ffigen/lib/src/code_generator/pointer.dart
+++ b/pkgs/ffigen/lib/src/code_generator/pointer.dart
@@ -45,7 +45,10 @@
 /// Represents a constant array, which has a fixed size.
 class ConstantArray extends PointerType {
   final int length;
-  ConstantArray(this.length, Type child) : super._(child);
+  final bool useArrayType;
+
+  ConstantArray(this.length, Type child, {required this.useArrayType})
+      : super._(child);
 
   @override
   Type get baseArrayType => child.baseArrayType;
@@ -58,6 +61,15 @@
 
   @override
   String cacheKey() => '${child.cacheKey()}[$length]';
+
+  @override
+  String getCType(Writer w) {
+    if (useArrayType) {
+      return '${w.ffiLibraryPrefix}.Array<${child.getCType(w)}>';
+    }
+
+    return super.getCType(w);
+  }
 }
 
 /// Represents an incomplete array, which has an unknown size.
diff --git a/pkgs/ffigen/lib/src/code_generator/utils.dart b/pkgs/ffigen/lib/src/code_generator/utils.dart
index 5c18c7f..4bad8e3 100644
--- a/pkgs/ffigen/lib/src/code_generator/utils.dart
+++ b/pkgs/ffigen/lib/src/code_generator/utils.dart
@@ -1,4 +1,11 @@
+// Copyright (c) 2023, 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 'dart_keywords.dart';
+import 'pointer.dart';
+import 'type.dart';
+import 'writer.dart';
 
 class UniqueNamer {
   final Set<String> _usedUpNames;
@@ -75,3 +82,33 @@
 
   return s.toString();
 }
+
+String makeNativeAnnotation(
+  Writer w, {
+  required String? nativeType,
+  required String dartName,
+  required String nativeSymbolName,
+  bool isLeaf = false,
+}) {
+  final args = <(String, String)>[];
+  if (dartName != nativeSymbolName) {
+    args.add(('symbol', '"$nativeSymbolName"'));
+  }
+  if (isLeaf) {
+    args.add(('isLeaf', 'true'));
+  }
+
+  final combinedArgs = args.map((e) => '${e.$1}: ${e.$2}').join(', ');
+  return '@${w.ffiLibraryPrefix}.Native<$nativeType>($combinedArgs)';
+}
+
+String makeArrayAnnotation(Writer w, ConstantArray arrayType) {
+  final dimensions = <int>[];
+  Type type = arrayType;
+  while (type is ConstantArray) {
+    dimensions.add(type.length);
+    type = type.child;
+  }
+
+  return '@${w.ffiLibraryPrefix}.Array.multi([${dimensions.join(', ')}])';
+}
diff --git a/pkgs/ffigen/lib/src/code_generator/writer.dart b/pkgs/ffigen/lib/src/code_generator/writer.dart
index d20db66..8193de1 100644
--- a/pkgs/ffigen/lib/src/code_generator/writer.dart
+++ b/pkgs/ffigen/lib/src/code_generator/writer.dart
@@ -23,6 +23,9 @@
   /// Holds bindings which don't lookup symbols.
   final List<Binding> noLookUpBindings;
 
+  /// The default asset id to use for [ffiNativeBindings].
+  final String? nativeAssetId;
+
   /// Manages the `_SymbolAddress` class.
   final symbolAddressWriter = SymbolAddressWriter();
 
@@ -57,6 +60,13 @@
     return _ffiPkgLibraryPrefix = import.prefix;
   }
 
+  late String selfImportPrefix = () {
+    final import = _usedImports
+        .firstWhere((element) => element.name == self.name, orElse: () => self);
+    _usedImports.add(import);
+    return import.prefix;
+  }();
+
   final Set<LibraryImport> _usedImports = {};
 
   late String _lookupFuncIdentifier;
@@ -92,6 +102,7 @@
     required this.ffiNativeBindings,
     required this.noLookUpBindings,
     required String className,
+    required this.nativeAssetId,
     Set<LibraryImport>? additionalImports,
     this.classDocComment,
     this.header,
@@ -217,6 +228,17 @@
       result.write(makeDoc('ignore_for_file: type=lint'));
     }
 
+    // If there are any @Native bindings, the file needs to have an
+    // `@DefaultAsset` annotation for the symbols to resolve properly. This
+    // avoids duplicating the asset on every element.
+    // Since the annotation goes on a `library;` directive, it needs to appear
+    // before other definitions in the file.
+    if (ffiNativeBindings.isNotEmpty && nativeAssetId != null) {
+      result
+        ..writeln("@$ffiLibraryPrefix.DefaultAsset('$nativeAssetId')")
+        ..writeln('library;\n');
+    }
+
     /// Write [lookUpBindings].
     if (lookUpBindings.isNotEmpty) {
       // Write doc comment for wrapper class.
@@ -250,8 +272,14 @@
       s.write('}\n\n');
     }
 
-    for (final b in ffiNativeBindings) {
-      s.write(b.toBindingString(this).string);
+    if (ffiNativeBindings.isNotEmpty) {
+      for (final b in ffiNativeBindings) {
+        s.write(b.toBindingString(this).string);
+      }
+
+      if (symbolAddressWriter.shouldGenerate) {
+        s.write(symbolAddressWriter.writeObject(this));
+      }
     }
 
     if (symbolAddressWriter.shouldGenerate) {
@@ -329,29 +357,61 @@
   /// Used to check if we need to generate `_SymbolAddress` class.
   bool get shouldGenerate => _addresses.isNotEmpty;
 
+  bool get hasNonNativeAddress => _addresses.any((e) => !e.native);
+
   void addSymbol({
     required String type,
     required String name,
     required String ptrName,
   }) {
-    _addresses.add(_SymbolAddressUnit(type, name, ptrName));
+    _addresses.add(_SymbolAddressUnit(type, name, ptrName, false));
+  }
+
+  void addNativeSymbol({required String type, required String name}) {
+    _addresses.add(_SymbolAddressUnit(type, name, '', true));
   }
 
   String writeObject(Writer w) {
-    return 'late final ${w._symbolAddressVariableName} = ${w._symbolAddressClassName}(this);';
+    final className = w._symbolAddressClassName;
+    final fieldName = w._symbolAddressVariableName;
+
+    if (hasNonNativeAddress) {
+      return 'late final $fieldName = $className(this);';
+    } else {
+      return 'const $fieldName = $className();';
+    }
   }
 
   String writeClass(Writer w) {
     final sb = StringBuffer();
     sb.write('class ${w._symbolAddressClassName} {\n');
-    // Write Library object.
-    sb.write('final ${w._className} ${w._symbolAddressLibraryVarName};\n');
-    // Write Constructor.
-    sb.write(
-        '${w._symbolAddressClassName}(this.${w._symbolAddressLibraryVarName});\n');
-    for (final address in _addresses) {
+
+    if (hasNonNativeAddress) {
+      // Write Library object.
+      sb.write('final ${w._className} ${w._symbolAddressLibraryVarName};\n');
+      // Write Constructor.
       sb.write(
-          '${address.type} get ${address.name} => ${w._symbolAddressLibraryVarName}.${address.ptrName};\n');
+          '${w._symbolAddressClassName}(this.${w._symbolAddressLibraryVarName});\n');
+    } else {
+      // Native bindings are top-level, so we don't need a field here.
+      sb.write('const ${w._symbolAddressClassName}();');
+    }
+
+    for (final address in _addresses) {
+      sb.write('${address.type} get ${address.name} => ');
+
+      if (address.native) {
+        // For native fields and functions, we can use Native.addressOf to look
+        // up their address.
+        // The name of address getter shadows the actual element in the library,
+        // so we need to use a self-import.
+        final arg = '${w.selfImportPrefix}.${address.name}';
+        sb.writeln('${w.ffiLibraryPrefix}.Native.addressOf($arg);');
+      } else {
+        // For other elements, the generator will write a private field of type
+        // Pointer which we can reference here.
+        sb.writeln('${w._symbolAddressLibraryVarName}.${address.ptrName};');
+      }
     }
     sb.write('}\n');
     return sb.toString();
@@ -362,5 +422,8 @@
 class _SymbolAddressUnit {
   final String type, name, ptrName;
 
-  _SymbolAddressUnit(this.type, this.name, this.ptrName);
+  /// Whether the symbol we're looking up has been declared with `@Native`.
+  final bool native;
+
+  _SymbolAddressUnit(this.type, this.name, this.ptrName, this.native);
 }
diff --git a/pkgs/ffigen/lib/src/header_parser/sub_parsers/var_parser.dart b/pkgs/ffigen/lib/src/header_parser/sub_parsers/var_parser.dart
index bea3e80..e77ff76 100644
--- a/pkgs/ffigen/lib/src/header_parser/sub_parsers/var_parser.dart
+++ b/pkgs/ffigen/lib/src/header_parser/sub_parsers/var_parser.dart
@@ -26,7 +26,11 @@
   _logger.fine('++++ Adding Global: ${cursor.completeStringRepr()}');
 
   final cType = cursor.type();
-  final type = cType.toCodeGenType();
+
+  final type = cType.toCodeGenType(
+      // Native fields can be arrays, but if we use the lookup based method of
+      // reading fields there's no way to turn a Pointer into an array.
+      supportNonInlineArray: config.ffiNativeConfig.enabled);
   if (type.baseType is UnimplementedType) {
     _logger.fine('---- Removed Global, reason: unsupported type: '
         '${cursor.completeStringRepr()}');
@@ -34,21 +38,17 @@
     return null;
   }
 
-  if (config.ffiNativeConfig.enabled) {
-    _logger
-        .warning("Skipped global variable '$name', not supported in Natives.");
-    return null;
-  }
-
   final global = Global(
     originalName: name,
     name: config.globals.renameUsingConfig(name),
     usr: usr,
     type: type,
     dartDoc: getCursorDocComment(cursor),
-    exposeSymbolAddress: config.functionDecl.shouldIncludeSymbolAddress(name),
+    exposeSymbolAddress: config.globals.shouldIncludeSymbolAddress(name),
     constant: cType.isConstQualified,
+    nativeConfig: config.ffiNativeConfig,
   );
   bindingsIndex.addGlobalVarToSeen(usr, global);
+
   return global;
 }
diff --git a/pkgs/ffigen/lib/src/header_parser/type_extractor/extractor.dart b/pkgs/ffigen/lib/src/header_parser/type_extractor/extractor.dart
index 5eb7a02..079e657 100644
--- a/pkgs/ffigen/lib/src/header_parser/type_extractor/extractor.dart
+++ b/pkgs/ffigen/lib/src/header_parser/type_extractor/extractor.dart
@@ -39,6 +39,7 @@
   /// Cursor of the declaration, currently this is useful only to extract
   /// parameter names in function types.
   clang_types.CXCursor? originalCursor,
+  bool supportNonInlineArray = false,
 }) {
   _logger.fine('${_padding}getCodeGenType ${cxtype.completeStringRepr()}');
 
@@ -121,12 +122,17 @@
     case clang_types.CXTypeKind.CXType_ConstantArray:
       // Primarily used for constant array in struct members.
       final numElements = clang.clang_getNumElements(cxtype);
-      final elementType =
-          clang.clang_getArrayElementType(cxtype).toCodeGenType();
+      final elementType = clang
+          .clang_getArrayElementType(cxtype)
+          .toCodeGenType(supportNonInlineArray: supportNonInlineArray);
       // Handle numElements being 0 as an incomplete array.
       return numElements == 0
           ? IncompleteArray(elementType)
-          : ConstantArray(numElements, elementType);
+          : ConstantArray(
+              numElements,
+              elementType,
+              useArrayType: supportNonInlineArray,
+            );
     case clang_types.CXTypeKind.CXType_IncompleteArray:
       // Primarily used for incomplete array in function parameters.
       return IncompleteArray(
diff --git a/pkgs/ffigen/lib/src/header_parser/utils.dart b/pkgs/ffigen/lib/src/header_parser/utils.dart
index d142370..9e80414 100644
--- a/pkgs/ffigen/lib/src/header_parser/utils.dart
+++ b/pkgs/ffigen/lib/src/header_parser/utils.dart
@@ -273,8 +273,8 @@
 
 extension CXTypeExt on clang_types.CXType {
   /// Get code_gen [Type] representation of [clang_types.CXType].
-  Type toCodeGenType() {
-    return getCodeGenType(this);
+  Type toCodeGenType({bool supportNonInlineArray = false}) {
+    return getCodeGenType(this, supportNonInlineArray: supportNonInlineArray);
   }
 
   /// Spelling for a [clang_types.CXTypeKind], useful for debug purposes.
diff --git a/pkgs/ffigen/pubspec.yaml b/pkgs/ffigen/pubspec.yaml
index d0bea76..20703e3 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: 11.0.0
+version: 12.0.0-dev
 description: >
   Generator for FFI bindings, using LibClang to parse C, Objective-C, and Swift
   files.
@@ -14,7 +14,7 @@
   - codegen
 
 environment:
-  sdk: ">=3.2.0 <4.0.0"
+  sdk: '>=3.3.0-252.0.dev <4.0.0'
 
 dependencies:
   ffi: ^2.0.1
@@ -28,8 +28,10 @@
   file: ^7.0.0
   package_config: ^2.1.0
   yaml_edit: ^2.0.3
+  collection: ^1.18.0
 
 dev_dependencies:
   lints: ^2.0.1
   test: ^1.16.2
   json_schema: ^5.1.1
+  meta: ^1.11.0
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 c4dd1a1..c9de2e1 100644
--- a/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart
+++ b/pkgs/ffigen/test/code_generator_tests/code_generator_test.dart
@@ -4,7 +4,9 @@
 
 import 'package:ffigen/src/code_generator.dart';
 import 'package:ffigen/src/config_provider/config_types.dart';
+import 'package:meta/meta.dart';
 import 'package:test/test.dart';
+
 import '../test_utils.dart';
 
 void main() {
@@ -15,13 +17,24 @@
 ''';
 
   group('code_generator: ', () {
-    void functionBindings(bool enableFfiNative) {
+    @isTestGroup
+    void withAndWithoutNative(
+        String description, void Function(FfiNativeConfig) runTest) {
+      group(description, () {
+        test('without Native', () => runTest(FfiNativeConfig(enabled: false)));
+        test('with Native',
+            () => runTest(FfiNativeConfig(enabled: true, assetId: 'test')));
+      });
+    }
+
+    withAndWithoutNative('Function Binding (primitives, pointers)',
+        (nativeConfig) {
       final library = Library(
         name: 'Bindings',
         header: licenseHeader,
         bindings: [
           Func(
-            ffiNativeConfig: FfiNativeConfig(enabled: enableFfiNative),
+            ffiNativeConfig: nativeConfig,
             name: 'noParam',
             dartDoc: 'Just a test function\nheres another line',
             returnType: NativeType(
@@ -29,7 +42,7 @@
             ),
           ),
           Func(
-            ffiNativeConfig: FfiNativeConfig(enabled: enableFfiNative),
+            ffiNativeConfig: nativeConfig,
             name: 'withPrimitiveParam',
             parameters: [
               Parameter(
@@ -50,7 +63,7 @@
             ),
           ),
           Func(
-            ffiNativeConfig: FfiNativeConfig(enabled: enableFfiNative),
+            ffiNativeConfig: nativeConfig,
             name: 'withPointerParam',
             parameters: [
               Parameter(
@@ -79,7 +92,7 @@
             ),
           ),
           Func(
-            ffiNativeConfig: FfiNativeConfig(enabled: enableFfiNative),
+            ffiNativeConfig: nativeConfig,
             isLeaf: true,
             name: 'leafFunc',
             dartDoc: 'A function with isLeaf: true',
@@ -98,15 +111,8 @@
         ],
       );
 
-      _matchLib(library, enableFfiNative ? 'function_ffiNative' : 'function');
-    }
-
-    test('Function Binding (primitives, pointers)', () {
-      functionBindings(false);
-    });
-
-    test('Function Binding (primitives, pointers) (ffiNative)', () {
-      functionBindings(true);
+      _matchLib(
+          library, nativeConfig.enabled ? 'function_ffiNative' : 'function');
     });
 
     test('Struct Binding (primitives, pointers)', () {
@@ -250,7 +256,8 @@
       _matchLib(library, 'function_n_struct');
     });
 
-    test('global (primitives, pointers, pointer to struct)', () {
+    withAndWithoutNative('global (primitives, pointers, pointer to struct)',
+        (nativeConfig) {
       final structSome = Struct(
         name: 'Some',
       );
@@ -261,12 +268,14 @@
         header: licenseHeader,
         bindings: [
           Global(
+            nativeConfig: nativeConfig,
             name: 'test1',
             type: NativeType(
               SupportedNativeType.Int32,
             ),
           ),
           Global(
+            nativeConfig: nativeConfig,
             name: 'test2',
             type: PointerType(
               NativeType(
@@ -275,18 +284,35 @@
             ),
             constant: true,
           ),
+          Global(
+            nativeConfig: nativeConfig,
+            name: 'test3',
+            type: ConstantArray(
+              10,
+              NativeType(
+                SupportedNativeType.Float,
+              ),
+              useArrayType: nativeConfig.enabled,
+            ),
+            constant: true,
+          ),
           structSome,
           Global(
+            nativeConfig: nativeConfig,
             name: 'test5',
             type: PointerType(
               structSome,
             ),
           ),
           emptyGlobalStruct,
-          Global(name: 'globalStruct', type: emptyGlobalStruct),
+          Global(
+            nativeConfig: nativeConfig,
+            name: 'globalStruct',
+            type: emptyGlobalStruct,
+          ),
         ],
       );
-      _matchLib(library, 'global');
+      _matchLib(library, nativeConfig.enabled ? 'global_native' : 'global');
     });
 
     test('constant', () {
@@ -329,6 +355,7 @@
       );
       _matchLib(library, 'enumclass');
     });
+
     test('Internal conflict resolution', () {
       final library = Library(
         name: 'init_dylib',
@@ -361,6 +388,9 @@
                   NativeType(
                     SupportedNativeType.Int8,
                   ),
+                  // This flag is ignored for struct fields, which always use
+                  // inline arrays.
+                  useArrayType: true,
                 ),
               ),
             ],
@@ -376,6 +406,30 @@
       );
       _matchLib(library, 'internal_conflict_resolution');
     });
+
+    test('Adds Native symbol on mismatch', () {
+      final nativeConfig = FfiNativeConfig(enabled: true);
+      final library = Library(
+        name: 'init_dylib',
+        header:
+            '$licenseHeader\n// ignore_for_file: unused_element, camel_case_types, non_constant_identifier_names\n',
+        bindings: [
+          Func(
+            ffiNativeConfig: nativeConfig,
+            name: 'test',
+            originalName: '_test',
+            returnType: NativeType(SupportedNativeType.Void),
+          ),
+          Global(
+            nativeConfig: nativeConfig,
+            name: 'testField',
+            originalName: '_testField',
+            type: NativeType(SupportedNativeType.Int16),
+          ),
+        ],
+      );
+      _matchLib(library, 'native_symbol');
+    });
   });
   test('boolean_dartBool', () {
     final library = Library(
@@ -467,10 +521,22 @@
           Member(name: 'd', type: PointerType(struct1)),
         ]),
         Union(name: 'WithArray', members: [
-          Member(name: 'a', type: ConstantArray(10, charType)),
-          Member(name: 'b', type: ConstantArray(10, union1)),
-          Member(name: 'b', type: ConstantArray(10, struct1)),
-          Member(name: 'c', type: ConstantArray(10, PointerType(union1))),
+          Member(
+            name: 'a',
+            type: ConstantArray(10, charType, useArrayType: true),
+          ),
+          Member(
+            name: 'b',
+            type: ConstantArray(10, union1, useArrayType: true),
+          ),
+          Member(
+            name: 'b',
+            type: ConstantArray(10, struct1, useArrayType: true),
+          ),
+          Member(
+            name: 'c',
+            type: ConstantArray(10, PointerType(union1), useArrayType: true),
+          ),
         ]),
       ],
     );
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_ffiNative_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_ffiNative_bindings.dart
index 9b4ebf4..e77b714 100644
--- a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_ffiNative_bindings.dart
+++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_function_ffiNative_bindings.dart
@@ -6,30 +6,32 @@
 //
 // Generated by `package:ffigen`.
 // ignore_for_file: type=lint
+@ffi.DefaultAsset('test')
+library;
+
 import 'dart:ffi' as ffi;
 
 /// Just a test function
 /// heres another line
-@ffi.Native<ffi.Int32 Function()>(symbol: 'noParam')
+@ffi.Native<ffi.Int32 Function()>()
 external int noParam();
 
-@ffi.Native<ffi.Uint8 Function(ffi.Int32, ffi.Uint8)>(
-    symbol: 'withPrimitiveParam')
+@ffi.Native<ffi.Uint8 Function(ffi.Int32, ffi.Uint8)>()
 external int withPrimitiveParam(
   int a,
   int b,
 );
 
 @ffi.Native<
-    ffi.Pointer<ffi.Double> Function(ffi.Pointer<ffi.Int32>,
-        ffi.Pointer<ffi.Pointer<ffi.Uint8>>)>(symbol: 'withPointerParam')
+    ffi.Pointer<ffi.Double> Function(
+        ffi.Pointer<ffi.Int32>, ffi.Pointer<ffi.Pointer<ffi.Uint8>>)>()
 external ffi.Pointer<ffi.Double> withPointerParam(
   ffi.Pointer<ffi.Int32> a,
   ffi.Pointer<ffi.Pointer<ffi.Uint8>> b,
 );
 
 /// A function with isLeaf: true
-@ffi.Native<ffi.Int32 Function(ffi.Int32)>(symbol: 'leafFunc', isLeaf: true)
+@ffi.Native<ffi.Int32 Function(ffi.Int32)>(isLeaf: true)
 external int leafFunc(
   int a,
 );
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_global_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_global_bindings.dart
index 85b3b18..066f9ee 100644
--- a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_global_bindings.dart
+++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_global_bindings.dart
@@ -33,6 +33,11 @@
 
   ffi.Pointer<ffi.Float> get test2 => _test2.value;
 
+  late final ffi.Pointer<ffi.Pointer<ffi.Float>> _test3 =
+      _lookup<ffi.Pointer<ffi.Float>>('test3');
+
+  ffi.Pointer<ffi.Float> get test3 => _test3.value;
+
   late final ffi.Pointer<ffi.Pointer<Some>> _test5 =
       _lookup<ffi.Pointer<Some>>('test5');
 
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_global_native_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_global_native_bindings.dart
new file mode 100644
index 0000000..601c079
--- /dev/null
+++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_global_native_bindings.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2023, 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.
+
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+// ignore_for_file: type=lint
+@ffi.DefaultAsset('test')
+library;
+
+import 'dart:ffi' as ffi;
+
+@ffi.Native<ffi.Int32>()
+external int test1;
+
+@ffi.Native<ffi.Pointer<ffi.Float>>()
+external final ffi.Pointer<ffi.Float> test2;
+
+@ffi.Array.multi([10])
+@ffi.Native<ffi.Array<ffi.Float>>()
+external final ffi.Array<ffi.Float> test3;
+
+@ffi.Native<ffi.Pointer<Some>>()
+external ffi.Pointer<Some> test5;
+
+@ffi.Native<EmptyStruct>()
+external EmptyStruct globalStruct;
+
+final class Some extends ffi.Opaque {}
+
+final class EmptyStruct extends ffi.Opaque {}
diff --git a/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_native_symbol_bindings.dart b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_native_symbol_bindings.dart
new file mode 100644
index 0000000..234cf2c
--- /dev/null
+++ b/pkgs/ffigen/test/code_generator_tests/expected_bindings/_expected_native_symbol_bindings.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2023, 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.
+
+// ignore_for_file: unused_element, camel_case_types, non_constant_identifier_names
+
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+// ignore_for_file: type=lint
+import 'dart:ffi' as ffi;
+
+@ffi.Native<ffi.Void Function()>(symbol: "_test")
+external void test();
+
+@ffi.Native<ffi.Int16>(symbol: "_testField")
+external int testField;
diff --git a/pkgs/ffigen/test/header_parser_tests/function_n_struct_test.dart b/pkgs/ffigen/test/header_parser_tests/function_n_struct_test.dart
index 5ddd58a..028da3d 100644
--- a/pkgs/ffigen/test/header_parser_tests/function_n_struct_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/function_n_struct_test.dart
@@ -118,7 +118,14 @@
       Struct(name: 'Struct4'),
       Struct(name: 'Struct5'),
       Struct(name: 'Struct6', members: [
-        Member(name: 'a', type: ConstantArray(2, ConstantArray(10, intType)))
+        Member(
+          name: 'a',
+          type: ConstantArray(
+            2,
+            ConstantArray(10, intType, useArrayType: false),
+            useArrayType: false,
+          ),
+        )
       ]),
       Struct(name: 'Struct7'),
     ],