Version 2.17.0-54.0.dev
Merge commit '627326aec14f52f9fc9015ad22bd2810635e006d' into 'dev'
diff --git a/DEPS b/DEPS
index cfd0829..2d8c940 100644
--- a/DEPS
+++ b/DEPS
@@ -133,7 +133,7 @@
"mime_rev": "c931f4bed87221beaece356494b43731445ce7b8",
"mockito_rev": "d39ac507483b9891165e422ec98d9fb480037c8b",
"oauth2_rev": "7cd3284049fe5badbec9f2bea2afc41d14c01057",
- "package_config_rev": "fb736aa12316dd2d882b202a438a6946a4b4bea0",
+ "package_config_rev": "8731bf10b5375542792a32a0f7c8a6f370583d96",
"path_rev": "baedce9d2ca11ea2cdf54395a74eb038087777a4",
"pedantic_rev": "66f2f6c27581c7936482e83be80b27be2719901c",
"platform_rev": "1ffad63428bbd1b3ecaa15926bacfb724023648c",
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart b/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
index 1c50b6a..5841315 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
@@ -79,6 +79,10 @@
var request = new ExecuteDefinitionsPhaseRequest.deserialize(deserializer, zoneId);
(await _executeDefinitionsPhase(request, sendRequest)).serialize(serializer);
break;
+ case MessageType.executeTypesPhaseRequest:
+ var request = new ExecuteTypesPhaseRequest.deserialize(deserializer, zoneId);
+ (await _executeTypesPhase(request, sendRequest)).serialize(serializer);
+ break;
case MessageType.response:
var response = new SerializableResponse.deserialize(deserializer, zoneId);
_responseCompleters.remove(response.requestId)!.complete(response);
@@ -135,6 +139,32 @@
}
}
+Future<SerializableResponse> _executeTypesPhase(
+ ExecuteTypesPhaseRequest request,
+ Future<Response> Function(Request request) sendRequest) async {
+ try {
+ Macro? instance = _macroInstances[request.macro];
+ if (instance == null) {
+ throw new StateError('Unrecognized macro instance \${request.macro}\\n'
+ 'Known instances: \$_macroInstances)');
+ }
+
+ var result = await executeTypesMacro(instance, request.declaration);
+ return new SerializableResponse(
+ responseType: MessageType.macroExecutionResult,
+ response: result,
+ requestId: request.id,
+ serializationZoneId: request.serializationZoneId);
+ } catch (e, s) {
+ return new SerializableResponse(
+ responseType: MessageType.error,
+ error: e.toString(),
+ stackTrace: s.toString(),
+ requestId: request.id,
+ serializationZoneId: request.serializationZoneId);
+ }
+}
+
Future<SerializableResponse> _executeDeclarationsPhase(
ExecuteDeclarationsPhaseRequest request,
Future<Response> Function(Request request) sendRequest) async {
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/builder_impls.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/builder_impls.dart
index 59a6376..577e7bf 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/builder_impls.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/builder_impls.dart
@@ -24,6 +24,13 @@
: _augmentations = parentAugmentations ?? [];
}
+class TypeBuilderImpl extends TypeBuilderBase implements TypeBuilder {
+ @override
+ void declareType(DeclarationCode typeDeclaration) {
+ _augmentations.add(typeDeclaration);
+ }
+}
+
/// Base class for all [DeclarationBuilder]s.
class DeclarationBuilderBase extends TypeBuilderBase
implements ClassIntrospector, TypeResolver {
@@ -66,10 +73,8 @@
class DeclarationBuilderImpl extends DeclarationBuilderBase
implements DeclarationBuilder {
DeclarationBuilderImpl(
- ClassIntrospector classIntrospector, TypeResolver typeResolver,
- {List<DeclarationCode>? parentAugmentations})
- : super(classIntrospector, typeResolver,
- parentAugmentations: parentAugmentations);
+ ClassIntrospector classIntrospector, TypeResolver typeResolver)
+ : super(classIntrospector, typeResolver);
@override
void declareInLibrary(DeclarationCode declaration) {
@@ -82,10 +87,8 @@
final TypeAnnotation definingClass;
ClassMemberDeclarationBuilderImpl(this.definingClass,
- ClassIntrospector classIntrospector, TypeResolver typeResolver,
- {List<DeclarationCode>? parentAugmentations})
- : super(classIntrospector, typeResolver,
- parentAugmentations: parentAugmentations);
+ ClassIntrospector classIntrospector, TypeResolver typeResolver)
+ : super(classIntrospector, typeResolver);
@override
void declareInClass(DeclarationCode declaration) {
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/execute_macro.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/execute_macro.dart
index f94470d..4448b1e 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/execute_macro.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/execute_macro.dart
@@ -6,6 +6,38 @@
import 'package:_fe_analyzer_shared/src/macros/executor_shared/builder_impls.dart';
import 'package:_fe_analyzer_shared/src/macros/api.dart';
+/// Runs [macro] in the types phase and returns a [MacroExecutionResult].
+Future<MacroExecutionResult> executeTypesMacro(
+ Macro macro, Declaration declaration) async {
+ TypeBuilderImpl builder = new TypeBuilderImpl();
+ if (declaration is FunctionDeclaration) {
+ if (macro is ConstructorTypesMacro &&
+ declaration is ConstructorDeclaration) {
+ await macro.buildTypesForConstructor(declaration, builder);
+ return builder.result;
+ } else if (macro is MethodTypesMacro && declaration is MethodDeclaration) {
+ await macro.buildTypesForMethod(declaration, builder);
+ return builder.result;
+ } else if (macro is FunctionTypesMacro) {
+ await macro.buildTypesForFunction(declaration, builder);
+ return builder.result;
+ }
+ } else if (declaration is VariableDeclaration) {
+ if (macro is FieldTypesMacro && declaration is FieldDeclaration) {
+ await macro.buildTypesForField(declaration, builder);
+ return builder.result;
+ } else if (macro is VariableTypesMacro) {
+ await macro.buildTypesForVariable(declaration, builder);
+ return builder.result;
+ }
+ } else if (macro is ClassTypesMacro && declaration is ClassDeclaration) {
+ await macro.buildTypesForClass(declaration, builder);
+ return builder.result;
+ }
+ throw new UnsupportedError('Unsupported macro type or invalid declaration:\n'
+ 'macro: $macro\ndeclaration: $declaration');
+}
+
/// Runs [macro] in the declaration phase and returns a [MacroExecutionResult].
Future<MacroExecutionResult> executeDeclarationsMacro(
Macro macro,
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/protocol.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/protocol.dart
index 3eae69c..00b3787 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/protocol.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/protocol.dart
@@ -237,6 +237,32 @@
}
}
+/// A request to execute a macro on a particular declaration in the types phase.
+class ExecuteTypesPhaseRequest extends Request {
+ final MacroInstanceIdentifier macro;
+ final DeclarationImpl declaration;
+
+ ExecuteTypesPhaseRequest(this.macro, this.declaration,
+ {required int serializationZoneId})
+ : super(serializationZoneId: serializationZoneId);
+
+ /// When deserializing we have already consumed the message type, so we don't
+ /// consume it again.
+ ExecuteTypesPhaseRequest.deserialize(
+ Deserializer deserializer, int serializationZoneId)
+ : macro = new MacroInstanceIdentifierImpl.deserialize(deserializer),
+ declaration = RemoteInstance.deserialize(deserializer),
+ super.deserialize(deserializer, serializationZoneId);
+
+ void serialize(Serializer serializer) {
+ serializer.addNum(MessageType.executeTypesPhaseRequest.index);
+ macro.serialize(serializer);
+ declaration.serialize(serializer);
+
+ super.serialize(serializer);
+ }
+}
+
/// A request to execute a macro on a particular declaration in the definition
/// phase.
class ExecuteDeclarationsPhaseRequest extends Request {
@@ -664,6 +690,7 @@
error,
executeDeclarationsPhaseRequest,
executeDefinitionsPhaseRequest,
+ executeTypesPhaseRequest,
instantiateMacroRequest,
isExactlyTypeRequest,
isSubtypeOfRequest,
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart b/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart
index 9194c7f..210469e 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart
@@ -420,10 +420,9 @@
@override
Future<MacroExecutionResult> executeTypesPhase(
- MacroInstanceIdentifier macro, Declaration declaration) {
- // TODO: implement executeTypesPhase
- throw new UnimplementedError();
- }
+ MacroInstanceIdentifier macro, DeclarationImpl declaration) =>
+ _sendRequest((zoneId) => new ExecuteTypesPhaseRequest(macro, declaration,
+ serializationZoneId: zoneId));
@override
Future<MacroInstanceIdentifier> instantiateMacro(
diff --git a/pkg/_fe_analyzer_shared/test/macros/isolated_executor/isolated_executor_test.dart b/pkg/_fe_analyzer_shared/test/macros/isolated_executor/isolated_executor_test.dart
index 81aa97f..ce7d844 100644
--- a/pkg/_fe_analyzer_shared/test/macros/isolated_executor/isolated_executor_test.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/isolated_executor/isolated_executor_test.dart
@@ -212,6 +212,35 @@
var testTypeDeclarationResolver =
TestTypeDeclarationResolver({myClassStaticType: myClass});
+ group('in the types phase', () {
+ test('on methods', () async {
+ var result = await executor.executeTypesPhase(instanceId, myMethod);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('class GeneratedByMyMethod {}'));
+ });
+
+ test('on constructors', () async {
+ var result =
+ await executor.executeTypesPhase(instanceId, myConstructor);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('class GeneratedByMyConstructor {}'));
+ });
+
+ test('on fields', () async {
+ var result = await executor.executeTypesPhase(instanceId, myField);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('class GeneratedByMyField {}'));
+ });
+
+ test('on classes', () async {
+ var result = await executor.executeTypesPhase(instanceId, myClass);
+ expect(
+ result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace(
+ 'class MyClassBuilder implements Builder<MyClass> {}'));
+ });
+ });
+
group('in the declaration phase', () {
test('on methods', () async {
var result = await executor.executeDeclarationsPhase(
diff --git a/pkg/_fe_analyzer_shared/test/macros/isolated_executor/simple_macro.dart b/pkg/_fe_analyzer_shared/test/macros/isolated_executor/simple_macro.dart
index b5681aa..222e1cd 100644
--- a/pkg/_fe_analyzer_shared/test/macros/isolated_executor/simple_macro.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/isolated_executor/simple_macro.dart
@@ -14,16 +14,22 @@
/// to validate the introspection APIs work as expected.
class SimpleMacro
implements
+ ClassTypesMacro,
ClassDeclarationsMacro,
ClassDefinitionMacro,
+ ConstructorTypesMacro,
ConstructorDeclarationsMacro,
ConstructorDefinitionMacro,
+ FieldTypesMacro,
FieldDeclarationsMacro,
FieldDefinitionMacro,
+ FunctionTypesMacro,
FunctionDeclarationsMacro,
FunctionDefinitionMacro,
+ MethodTypesMacro,
MethodDeclarationsMacro,
MethodDefinitionMacro,
+ VariableTypesMacro,
VariableDeclarationsMacro,
VariableDefinitionMacro {
final int? x;
@@ -236,6 +242,77 @@
initializer: variable.initializer,
);
}
+
+ @override
+ FutureOr<void> buildTypesForClass(
+ ClassDeclaration clazz, TypeBuilder builder) {
+ List<Object> _buildTypeParam(
+ TypeParameterDeclaration typeParam, bool isFirst) {
+ return [
+ if (!isFirst) ', ',
+ typeParam.name,
+ if (typeParam.bounds != null) ...[
+ ' extends ',
+ typeParam.bounds!,
+ ]
+ ];
+ }
+
+ builder.declareType(DeclarationCode.fromParts([
+ 'class ${clazz.name}Builder',
+ if (clazz.typeParameters.isNotEmpty) ...[
+ '<',
+ ..._buildTypeParam(clazz.typeParameters.first, true),
+ for (var typeParam in clazz.typeParameters.skip(1))
+ ..._buildTypeParam(typeParam, false),
+ '>',
+ ],
+ ' implements Builder<',
+ clazz.type,
+ if (clazz.typeParameters.isNotEmpty) ...[
+ '<',
+ clazz.typeParameters.first,
+ for (var typeParam in clazz.typeParameters) ', ${typeParam.name}',
+ '>',
+ ],
+ '> {}'
+ ]));
+ }
+
+ @override
+ FutureOr<void> buildTypesForConstructor(
+ ConstructorDeclaration constructor, TypeBuilder builder) {
+ builder.declareType(DeclarationCode.fromString(
+ 'class GeneratedBy${constructor.name.capitalize()} {}'));
+ }
+
+ @override
+ FutureOr<void> buildTypesForField(
+ FieldDeclaration field, TypeBuilder builder) {
+ builder.declareType(DeclarationCode.fromString(
+ 'class GeneratedBy${field.name.capitalize()} {}'));
+ }
+
+ @override
+ FutureOr<void> buildTypesForFunction(
+ FunctionDeclaration function, TypeBuilder builder) {
+ builder.declareType(DeclarationCode.fromString(
+ 'class GeneratedBy${function.name.capitalize()} {}'));
+ }
+
+ @override
+ FutureOr<void> buildTypesForMethod(
+ MethodDeclaration method, TypeBuilder builder) {
+ builder.declareType(DeclarationCode.fromString(
+ 'class GeneratedBy${method.name.capitalize()} {}'));
+ }
+
+ @override
+ FutureOr<void> buildTypesForVariable(
+ VariableDeclaration variable, TypeBuilder builder) {
+ builder.declareType(DeclarationCode.fromString(
+ 'class GeneratedBy${variable.name.capitalize()} {}'));
+ }
}
FunctionBodyCode _buildFunctionAugmentation(FunctionDeclaration function) =>
diff --git a/pkg/analyzer/lib/src/dart/error/ffi_code.g.dart b/pkg/analyzer/lib/src/dart/error/ffi_code.g.dart
index fc3a932..873531a 100644
--- a/pkg/analyzer/lib/src/dart/error/ffi_code.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/ffi_code.g.dart
@@ -64,9 +64,43 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a field that's declared in a
+ // subclass of `Struct` and has the type `Pointer` also has an annotation
+ // associated with it.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the field `p`, which
+ // has the type `Pointer` and is declared in a subclass of `Struct`, has the
+ // annotation `@Double()`:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // [!@Double()!]
+ // external Pointer<Int8> p;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Remove the annotations from the field:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // external Pointer<Int8> p;
+ // }
+ // ```
static const FfiCode ANNOTATION_ON_POINTER_FIELD = FfiCode(
'ANNOTATION_ON_POINTER_FIELD',
- "Fields in a struct class whose type is 'Pointer' should not have any "
+ "Fields in a struct class whose type is 'Pointer' shouldn't have any "
"annotations.",
correctionMessage: "Try removing the annotation.",
);
@@ -75,6 +109,56 @@
* Parameters:
* 0: the name of the argument
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when an invocation of either
+ // `Pointer.asFunction` or `DynamicLibrary.lookupFunction` has an `isLeaf`
+ // argument whose value isn't a constant expression.
+ //
+ // The analyzer also produces this diagnostic when the value of the
+ // `exceptionalReturn` argument of `Pointer.fromFunction`.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the value of the
+ // `isLeaf` argument is a parameter, and hence isn't a constant:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // int Function(int) fromPointer(
+ // Pointer<NativeFunction<Int8 Function(Int8)>> p, bool isLeaf) {
+ // return p.asFunction(isLeaf: [!isLeaf!]);
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If there's a suitable constant that can be used, then replace the argument
+ // with a constant:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // const isLeaf = false;
+ //
+ // int Function(int) fromPointer(Pointer<NativeFunction<Int8 Function(Int8)>> p) {
+ // return p.asFunction(isLeaf: isLeaf);
+ // }
+ // ```
+ //
+ // If there isn't a suitable constant, then replace the argument with a
+ // boolean literal:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // int Function(int) fromPointer(Pointer<NativeFunction<Int8 Function(Int8)>> p) {
+ // return p.asFunction(isLeaf: true);
+ // }
+ // ```
static const FfiCode ARGUMENT_MUST_BE_A_CONSTANT = FfiCode(
'ARGUMENT_MUST_BE_A_CONSTANT',
"Argument '{0}' must be a constant.",
@@ -84,6 +168,52 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a subclass of either `Struct`
+ // or `Union` is instantiated using a generative constructor.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the class `C` is being
+ // instantiated using a generative constructor:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Int32()
+ // external int a;
+ // }
+ //
+ // void f() {
+ // [!C!]();
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If you need to allocate the structure described by the class, then use the
+ // `ffi` package to do so:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ // import 'package:ffi/ffi.dart';
+ //
+ // class C extends Struct {
+ // @Int32()
+ // external int a;
+ // }
+ //
+ // void f() {
+ // final pointer = calloc.allocate<C>(4);
+ // final c = pointer.ref;
+ // print(c);
+ // calloc.free(pointer);
+ // }
+ // ```
static const FfiCode CREATION_OF_STRUCT_OR_UNION = FfiCode(
'CREATION_OF_STRUCT_OR_UNION',
"Subclasses of 'Struct' and 'Union' are backed by native memory, and can't "
@@ -97,9 +227,56 @@
* 0: the name of the subclass
* 1: the name of the superclass
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a subclass of `Struct` or
+ // `Union` doesn't have any fields. Having an empty `Struct` or `Union`
+ // isn't supported.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the class `C`, which
+ // extends `Struct`, doesn't declare any fields:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class [!C!] extends Struct {}
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If the class is intended to be a struct, then declare one or more fields:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Int32()
+ // external int x;
+ // }
+ // ```
+ //
+ // If the class is intended to be used as a type argument to `Pointer`, then
+ // make it a subclass of `Opaque`:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Opaque {}
+ // ```
+ //
+ // If the class isn't intended to be a struct, then remove or change the
+ // extends clause:
+ //
+ // ```dart
+ // class C {}
+ // ```
static const FfiCode EMPTY_STRUCT = FfiCode(
'EMPTY_STRUCT',
- "The class '{0}' can’t be empty because it's a subclass of '{1}'.",
+ "The class '{0}' can't be empty because it's a subclass of '{1}'.",
correctionMessage:
"Try adding a field to '{0}' or use a different superclass.",
);
@@ -107,6 +284,40 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a field in a subclass of
+ // `Struct` has more than one annotation describing the native type of the
+ // field.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the field `x` has two
+ // annotations describing the native type of the field:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Int32()
+ // [!@Int16()!]
+ // external int x;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Remove all but one of the annotations:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ // class C extends Struct {
+ // @Int32()
+ // external int x;
+ // }
+ // ```
static const FfiCode EXTRA_ANNOTATION_ON_STRUCT_FIELD = FfiCode(
'EXTRA_ANNOTATION_ON_STRUCT_FIELD',
"Fields in a struct class must have exactly one annotation indicating the "
@@ -117,6 +328,41 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a field in a subclass of
+ // `Struct` has more than one annotation describing the size of the native
+ // array.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the field `a0` has two
+ // annotations that specify the size of the native array:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Array(4)
+ // [!@Array(8)!]
+ // external Array<Uint8> a0;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Remove all but one of the annotations:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Array(8)
+ // external Array<Uint8> a0;
+ // }
+ // ```
static const FfiCode EXTRA_SIZE_ANNOTATION_CARRAY = FfiCode(
'EXTRA_SIZE_ANNOTATION_CARRAY',
"'Array's must have exactly one 'Array' annotation.",
@@ -174,6 +420,45 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a constructor in a subclass of
+ // either `Struct` or `Union` has one or more field initializers.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the class `C` has a
+ // constructor with an initializer for the field `f`:
+ //
+ // ```dart
+ // // @dart = 2.9
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Int32()
+ // int f;
+ //
+ // C() : [!f = 0!];
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Remove the field initializer:
+ //
+ // ```dart
+ // // @dart = 2.9
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Int32()
+ // int f;
+ //
+ // C();
+ // }
+ // ```
static const FfiCode FIELD_INITIALIZER_IN_STRUCT = FfiCode(
'FIELD_INITIALIZER_IN_STRUCT',
"Constructors in subclasses of 'Struct' and 'Union' can't have field "
@@ -185,6 +470,39 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a field in a subclass of
+ // `Struct` has an initializer.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the field `p` has an
+ // initializer:
+ //
+ // ```dart
+ // // @dart = 2.9
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // Pointer [!p!] = nullptr;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Remove the initializer:
+ //
+ // ```dart
+ // // @dart = 2.9
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // Pointer p;
+ // }
+ // ```
static const FfiCode FIELD_IN_STRUCT_WITH_INITIALIZER = FfiCode(
'FIELD_IN_STRUCT_WITH_INITIALIZER',
"Fields in subclasses of 'Struct' and 'Union' can't have initializers.",
@@ -195,6 +513,39 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a field in a subclass of either
+ // `Struct` or `Union` isn't marked as being `external`.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the field `a` isn't
+ // marked as being `external`:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Int16()
+ // int [!a!];
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Add the required `external` modifier:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Int16()
+ // external int a;
+ // }
+ // ```
static const FfiCode FIELD_MUST_BE_EXTERNAL_IN_STRUCT = FfiCode(
'FIELD_MUST_BE_EXTERNAL_IN_STRUCT',
"Fields of 'Struct' and 'Union' subclasses must be marked external.",
@@ -205,20 +556,93 @@
* Parameters:
* 0: the name of the struct class
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a subclass of either `Struct`
+ // or `Union` has a type parameter.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the class `S` defines
+ // the type parameter `T`:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class [!S!]<T> extends Struct {
+ // external Pointer notEmpty;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Remove the type parameters from the class:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class S extends Struct {
+ // external Pointer notEmpty;
+ // }
+ // ```
static const FfiCode GENERIC_STRUCT_SUBCLASS = FfiCode(
'GENERIC_STRUCT_SUBCLASS',
- "The class '{0}' can't extend 'Struct' or 'Union' because it is generic.",
+ "The class '{0}' can't extend 'Struct' or 'Union' because '{0}' is "
+ "generic.",
correctionMessage: "Try removing the type parameters from '{0}'.",
);
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when an invocation of the method
+ // `Pointer.fromFunction` has a second argument (the exceptional return
+ // value) and the type to be returned from the invocation is either `void`,
+ // `Handle` or `Pointer`.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because a second argument is
+ // provided when the return type of `f` is `void`:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // typedef T = Void Function(Int8);
+ //
+ // void f(int i) {}
+ //
+ // void g() {
+ // Pointer.fromFunction<T>(f, [!42!]);
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Remove the exception value:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // typedef T = Void Function(Int8);
+ //
+ // void f(int i) {}
+ //
+ // void g() {
+ // Pointer.fromFunction<T>(f);
+ // }
+ // ```
static const FfiCode INVALID_EXCEPTION_VALUE = FfiCode(
'INVALID_EXCEPTION_VALUE',
- "The method 'Pointer.fromFunction' must not have an exceptional return "
- "value (the second argument) when the return type of the function is "
- "either 'void', 'Handle' or 'Pointer'.",
+ "The method 'Pointer.fromFunction' can't have an exceptional return value "
+ "(the second argument) when the return type of the function is either "
+ "'void', 'Handle' or 'Pointer'.",
correctionMessage: "Try removing the exceptional return value.",
);
@@ -226,6 +650,46 @@
* Parameters:
* 0: the type of the field
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a field in a subclass of
+ // `Struct` has a type other than `int`, `double`, `Array`, `Pointer`, or
+ // subtype of `Struct` or `Union`.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the field `str` has
+ // the type `String`, which isn't one of the allowed types for fields in a
+ // subclass of `Struct`:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // external [!String!] s;
+ //
+ // @Int32()
+ // external int i;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Use one of the allowed types for the field:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ // import 'package:ffi/ffi.dart';
+ //
+ // class C extends Struct {
+ // external Pointer<Utf8> s;
+ //
+ // @Int32()
+ // external int i;
+ // }
+ // ```
static const FfiCode INVALID_FIELD_TYPE_IN_STRUCT = FfiCode(
'INVALID_FIELD_TYPE_IN_STRUCT',
"Fields in struct classes can't have the type '{0}'. They can only be "
@@ -239,27 +703,167 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when the value of the `isLeaf`
+ // argument in an invocation of either `Pointer.asFunction` or
+ // `DynamicLibrary.lookupFunction` is `true` and the function that would be
+ // returned would have a return type of `Handle`.
+ //
+ // The analyzer also produces this diagnostic when the value of the `isLeaf`
+ // argument in an `FfiNative` annotation is `true` and the type argument on
+ // the annotation is a function type whose return type is `Handle`.
+ //
+ // In all of these cases, leaf calls are only supported for the types `bool`,
+ // `int`, `float`, `double`, and, as a return type `void`.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the function `p`
+ // returns a `Handle`, but the `isLeaf` argument is `true`:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // void f(Pointer<NativeFunction<Handle Function()>> p) {
+ // [!p.asFunction<Object Function()>(isLeaf: true)!];
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If the function returns a handle, then remove the `isLeaf` argument:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // void f(Pointer<NativeFunction<Handle Function()>> p) {
+ // p.asFunction<Object Function()>();
+ // }
+ // ```
+ //
+ // If the function returns one of the supported types, then correct the type
+ // information:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // void f(Pointer<NativeFunction<Int32 Function()>> p) {
+ // p.asFunction<int Function()>(isLeaf: true);
+ // }
+ // ```
static const FfiCode LEAF_CALL_MUST_NOT_RETURN_HANDLE = FfiCode(
'LEAF_CALL_MUST_NOT_RETURN_HANDLE',
- "FFI leaf call must not return a Handle.",
+ "FFI leaf call can't return a 'Handle'.",
correctionMessage: "Try changing the return type to primitive or struct.",
);
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when the value of the `isLeaf`
+ // argument in an invocation of either `Pointer.asFunction` or
+ // `DynamicLibrary.lookupFunction` is `true` and the function that would be
+ // returned would have a parameter of type `Handle`.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the function `p` has a
+ // parameter of type `Handle`, but the `isLeaf` argument is `true`:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // void f(Pointer<NativeFunction<Void Function(Handle)>> p) {
+ // [!p.asFunction<void Function(Object)>(isLeaf: true)!];
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If the function has at least one parameter of type `Handle`, then remove
+ // the `isLeaf` argument:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // void f(Pointer<NativeFunction<Void Function(Handle)>> p) {
+ // p.asFunction<void Function(Object)>();
+ // }
+ // ```
+ //
+ // If none of the function's parameters are `Handle`s, then correct the type
+ // information:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // void f(Pointer<NativeFunction<Void Function(Int8)>> p) {
+ // p.asFunction<void Function(int)>(isLeaf: true);
+ // }
+ // ```
static const FfiCode LEAF_CALL_MUST_NOT_TAKE_HANDLE = FfiCode(
'LEAF_CALL_MUST_NOT_TAKE_HANDLE',
- "FFI leaf call must not take arguments of type Handle.",
+ "FFI leaf call can't take arguments of type 'Handle'.",
correctionMessage: "Try changing the argument type to primitive or struct.",
);
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when the annotation on a field in a
+ // subclass of `Struct` or `Union` doesn't match the Dart type of the field.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the annotation
+ // `Double` doesn't match the Dart type `int`:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // [!@Double()!]
+ // external int x;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If the type of the field is correct, then change the annotation to match:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Int32()
+ // external int x;
+ // }
+ // ```
+ //
+ // If the annotation is correct, then change the type of the field to match:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Double()
+ // external double x;
+ // }
+ // ```
static const FfiCode MISMATCHED_ANNOTATION_ON_STRUCT_FIELD = FfiCode(
'MISMATCHED_ANNOTATION_ON_STRUCT_FIELD',
- "The annotation does not match the declared type of the field.",
+ "The annotation doesn't match the declared type of the field.",
correctionMessage:
"Try using a different annotation or changing the declared type to "
"match.",
@@ -268,6 +872,41 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a field in a subclass of
+ // `Struct` or `Union` whose type requires an annotation doesn't have one.
+ // The Dart types `int`, `double`, and `Array` are used to represent multiple
+ // C types, and the annotation specifies which of the compatible C types the
+ // field represents.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the field `x` doesn't
+ // have an annotation indicating the underlying width of the integer value:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // external [!int!] x;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Add an appropriate annotation to the field:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Int64()
+ // external int x;
+ // }
+ // ```
static const FfiCode MISSING_ANNOTATION_ON_STRUCT_FIELD = FfiCode(
'MISSING_ANNOTATION_ON_STRUCT_FIELD',
"Fields in a struct class must either have the type 'Pointer' or an "
@@ -278,11 +917,49 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when an invocation of the method
+ // `Pointer.fromFunction` doesn't have a second argument (the exceptional
+ // return value) when the type to be returned from the invocation is neither
+ // `void`, `Handle`, nor `Pointer`.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the type returned by
+ // `f` is expected to be an 8-bit integer but the call to `fromFunction`
+ // doesn't include an exceptional return argument:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // int f(int i) => i * 2;
+ //
+ // void g() {
+ // Pointer.[!fromFunction!]<Int8 Function(Int8)>(f);
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Add an exceptional return type:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // int f(int i) => i * 2;
+ //
+ // void g() {
+ // Pointer.fromFunction<Int8 Function(Int8)>(f, 0);
+ // }
+ // ```
static const FfiCode MISSING_EXCEPTION_VALUE = FfiCode(
'MISSING_EXCEPTION_VALUE',
"The method 'Pointer.fromFunction' must have an exceptional return value "
"(the second argument) when the return type of the function is neither "
- "'void', 'Handle' or 'Pointer'.",
+ "'void', 'Handle', nor 'Pointer'.",
correctionMessage: "Try adding an exceptional return value.",
);
@@ -290,6 +967,46 @@
* Parameters:
* 0: the type of the field
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a field in a subclass of
+ // `Struct` or `Union` doesn't have a type annotation. Every field must have
+ // an explicit type, and the type must either be `int`, `double`, `Pointer`,
+ // or a subclass of either `Struct` or `Union`.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the field `str`
+ // doesn't have a type annotation:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // external var [!str!];
+ //
+ // @Int32()
+ // external int i;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Explicitly specify the type of the field:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ // import 'package:ffi/ffi.dart';
+ //
+ // class C extends Struct {
+ // external Pointer<Utf8> str;
+ //
+ // @Int32()
+ // external int i;
+ // }
+ // ```
static const FfiCode MISSING_FIELD_TYPE_IN_STRUCT = FfiCode(
'MISSING_FIELD_TYPE_IN_STRUCT',
"Fields in struct classes must have an explicitly declared type of 'int', "
@@ -300,10 +1017,45 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a field in a subclass of either
+ // `Struct` or `Union` has a type of `Array` but doesn't have a single
+ // `Array` annotation indicating the dimensions of the array.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the field `a0` doesn't
+ // have an `Array` annotation:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // external [!Array<Uint8>!] a0;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Ensure that there's exactly one `Array` annotation on the field:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Array(8)
+ // external Array<Uint8> a0;
+ // }
+ // ```
static const FfiCode MISSING_SIZE_ANNOTATION_CARRAY = FfiCode(
'MISSING_SIZE_ANNOTATION_CARRAY',
- "'Array's must have exactly one 'Array' annotation.",
- correctionMessage: "Try adding a 'Array' annotation.",
+ "Fields of type 'Array' must have exactly one 'Array' annotation.",
+ correctionMessage:
+ "Try adding an 'Array' annotation, or removing all but one of the "
+ "annotations.",
);
/**
@@ -311,6 +1063,47 @@
* 0: the type that should be a valid dart:ffi native type.
* 1: the name of the function whose invocation depends on this relationship
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when an invocation of either
+ // `Pointer.fromFunction` or `DynamicLibrary.lookupFunction` has a type
+ // argument(whether explicit or inferred) that isn't a native function type.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the type `T` can be
+ // any subclass of `Function` but the type argument for `fromFunction` is
+ // required to be a native function type:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // int f(int i) => i * 2;
+ //
+ // class C<T extends Function> {
+ // void g() {
+ // Pointer.fromFunction<[!T!]>(f, 0);
+ // }
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Use a native function type as the type argument to the invocation:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // int f(int i) => i * 2;
+ //
+ // class C<T extends Function> {
+ // void g() {
+ // Pointer.fromFunction<Int32 Function(Int32)>(f, 0);
+ // }
+ // }
+ // ```
static const FfiCode MUST_BE_A_NATIVE_FUNCTION_TYPE = FfiCode(
'MUST_BE_A_NATIVE_FUNCTION_TYPE',
"The type '{0}' given to '{1}' must be a valid 'dart:ffi' native function "
@@ -325,6 +1118,64 @@
* 1: the supertype that the subtype is compared to
* 2: the name of the function whose invocation depends on this relationship
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic in two cases:
+ // - In an invocation of `Pointer.fromFunction` where the type argument
+ // (whether explicit or inferred) isn't a supertype of the type of the
+ // function passed as the first argument to the method.
+ // - In an invocation of `DynamicLibrary.lookupFunction` where the first type
+ // argument isn't a supertype of the second type argument.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the type of the
+ // function `f` (`String Function(int)`) isn't a subtype of the type
+ // argument `T` (`Int8 Function(Int8)`):
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // typedef T = Int8 Function(Int8);
+ //
+ // double f(double i) => i;
+ //
+ // void g() {
+ // Pointer.fromFunction<T>([!f!], 5.0);
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If the function is correct, then change the type argument to match:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // typedef T = Float Function(Float);
+ //
+ // double f(double i) => i;
+ //
+ // void g() {
+ // Pointer.fromFunction<T>(f, 5.0);
+ // }
+ // ```
+ //
+ // If the type argument is correct, then change the function to match:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // typedef T = Int8 Function(Int8);
+ //
+ // int f(int i) => i;
+ //
+ // void g() {
+ // Pointer.fromFunction<T>(f, 5);
+ // }
+ // ```
static const FfiCode MUST_BE_A_SUBTYPE = FfiCode(
'MUST_BE_A_SUBTYPE',
"The type '{0}' must be a subtype of '{1}' for '{2}'.",
@@ -335,10 +1186,50 @@
* Parameters:
* 0: the name of the function, method, or constructor having type arguments
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when the type arguments to a method
+ // are required to be known at compile time, but a type parameter, whose
+ // value can't be known at compile time, is used as a type argument.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the type argument to
+ // `Pointer.asFunction` must be known at compile time, but the type parameter
+ // `R`, which isn't known at compile time, is being used as the type
+ // argument:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // typedef T = int Function(int);
+ //
+ // class C<R extends T> {
+ // void m(Pointer<NativeFunction<T>> p) {
+ // p.asFunction<[!R!]>();
+ // }
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Remove any uses of type parameters:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C {
+ // void m(Pointer<NativeFunction<Int64 Function(Int64)>> p) {
+ // p.asFunction<int Function(int)>();
+ // }
+ // }
+ // ```
static const FfiCode NON_CONSTANT_TYPE_ARGUMENT = FfiCode(
'NON_CONSTANT_TYPE_ARGUMENT',
- "The type arguments to '{0}' must be compile time constants but type "
- "parameters are not constants.",
+ "The type arguments to '{0}' must be known at compile time, so they can't "
+ "be type parameters.",
correctionMessage: "Try changing the type argument to be a constant type.",
);
@@ -346,10 +1237,53 @@
* Parameters:
* 0: the type that should be a valid dart:ffi native type.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when the method `asFunction` is
+ // invoked on a pointer to a native function, but the signature of the native
+ // function isn't a valid C function signature.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because function signature
+ // associated with the pointer `p` (`FNative`) isn't a valid C function
+ // signature:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // typedef FNative = int Function(int);
+ // typedef F = int Function(int);
+ //
+ // class C {
+ // void f(Pointer<NativeFunction<FNative>> p) {
+ // p.asFunction<[!F!]>();
+ // }
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Make the `NativeFunction` signature a valid C signature:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // typedef FNative = Int8 Function(Int8);
+ // typedef F = int Function(int);
+ //
+ // class C {
+ // void f(Pointer<NativeFunction<FNative>> p) {
+ // p.asFunction<F>();
+ // }
+ // }
+ // ```
static const FfiCode NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER = FfiCode(
'NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER',
- "The type argument for the pointer '{0}' must be a valid 'NativeFunction' "
- "in order to use 'asFunction'.",
+ "Can't invoke 'asFunction' because the function signature '{0}' for the "
+ "pointer isn't a valid C function signature.",
correctionMessage:
"Try changing the function argument in 'NativeFunction' to only use "
"NativeTypes.",
@@ -358,6 +1292,39 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a dimension given in an `Array`
+ // annotation is less than or equal to zero (`0`).
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because an array dimension of
+ // `-1` was provided:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class MyStruct extends Struct {
+ // @Array([!-8!])
+ // external Array<Uint8> a0;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Change the dimension to be a positive integer:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class MyStruct extends Struct {
+ // @Array(8)
+ // external Array<Uint8> a0;
+ // }
+ // ```
static const FfiCode NON_POSITIVE_ARRAY_DIMENSION = FfiCode(
'NON_POSITIVE_ARRAY_DIMENSION',
"Array dimensions must be positive numbers.",
@@ -368,11 +1335,46 @@
* Parameters:
* 0: the type of the field
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when the type argument for the class
+ // `Array` isn't one of the valid types: either a native integer, `Float`,
+ // `Double`, `Pointer`, or subtype of `Struct`, `Union`, or
+ // `AbiSpecificInteger`.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the type argument to
+ // `Array` is `Void`, and `Void` isn't one of the valid types:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Array(8)
+ // external Array<[!Void!]> a0;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Change the type argument to one of the valid types:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Array(8)
+ // external Array<Uint8> a0;
+ // }
+ // ```
static const FfiCode NON_SIZED_TYPE_ARGUMENT = FfiCode(
'NON_SIZED_TYPE_ARGUMENT',
- "Type arguments to '{0}' can't have the type '{1}'. They can only be "
- "declared as native integer, 'Float', 'Double', 'Pointer', or subtype "
- "of 'Struct', 'Union', or 'AbiSpecificInteger'.",
+ "The type '{1}' isn't a valid type argument for '{0}'. The type argument "
+ "must be a native integer, 'Float', 'Double', 'Pointer', or subtype of "
+ "'Struct', 'Union', or 'AbiSpecificInteger'.",
correctionMessage:
"Try using a native integer, 'Float', 'Double', 'Pointer', or subtype "
"of 'Struct', 'Union', or 'AbiSpecificInteger'.",
@@ -381,6 +1383,40 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a subclass of `Struct` has more
+ // than one `Packed` annotation.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the class `C`, which
+ // is a subclass of `Struct`, has two `Packed` annotations:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // @Packed(1)
+ // [!@Packed(1)!]
+ // class C extends Struct {
+ // external Pointer<Uint8> notEmpty;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Remove all but one of the annotations:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // @Packed(1)
+ // class C extends Struct {
+ // external Pointer<Uint8> notEmpty;
+ // }
+ // ```
static const FfiCode PACKED_ANNOTATION = FfiCode(
'PACKED_ANNOTATION',
"Structs must have at most one 'Packed' annotation.",
@@ -390,6 +1426,39 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when the argument to the `Packed`
+ // annotation isn't one of the allowed values: 1, 2, 4, 8, or 16.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the argument to the
+ // `Packed` annotation (`3`) isn't one of the allowed values:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // @Packed([!3!])
+ // class C extends Struct {
+ // external Pointer<Uint8> notEmpty;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // Change the alignment to be one of the allowed values:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // @Packed(4)
+ // class C extends Struct {
+ // external Pointer<Uint8> notEmpty;
+ // }
+ // ```
static const FfiCode PACKED_ANNOTATION_ALIGNMENT = FfiCode(
'PACKED_ANNOTATION_ALIGNMENT',
"Only packing to 1, 2, 4, 8, and 16 bytes is supported.",
@@ -402,10 +1471,86 @@
* 0: the name of the outer struct
* 1: the name of the struct being nested
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a subclass of `Struct` that is
+ // annotated as being `Packed` declares a field whose type is also a subclass
+ // of `Struct` and the field's type is either not packed or is packed less
+ // tightly.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the class `Outer`,
+ // which is a subclass of `Struct` and is packed on 1-byte boundaries,
+ // declared a field whose type (`Inner`) is packed on 8-byte boundaries:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // @Packed(8)
+ // class Inner extends Struct {
+ // external Pointer<Uint8> notEmpty;
+ // }
+ //
+ // @Packed(1)
+ // class Outer extends Struct {
+ // external Pointer<Uint8> notEmpty;
+ //
+ // external [!Inner!] nestedLooselyPacked;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If the inner struct should be packed more tightly, then change the
+ // argument to the inner struct's `Packed` annotation:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // @Packed(1)
+ // class Inner extends Struct {
+ // external Pointer<Uint8> notEmpty;
+ // }
+ //
+ // @Packed(1)
+ // class Outer extends Struct {
+ // external Pointer<Uint8> notEmpty;
+ //
+ // external Inner nestedLooselyPacked;
+ // }
+ // ```
+ //
+ // If the outer struct should be packed less tightly, then change the
+ // argument to the outer struct's `Packed` annotation:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // @Packed(8)
+ // class Inner extends Struct {
+ // external Pointer<Uint8> notEmpty;
+ // }
+ //
+ // @Packed(8)
+ // class Outer extends Struct {
+ // external Pointer<Uint8> notEmpty;
+ //
+ // external Inner nestedLooselyPacked;
+ // }
+ // ```
+ //
+ // If the inner struct doesn't have an annotation and should be packed, then
+ // add an annotation.
+ //
+ // If the inner struct doesn't have an annotation and the outer struct
+ // shouldn't be packed, then remove its annotation.
static const FfiCode PACKED_NESTING_NON_PACKED = FfiCode(
'PACKED_NESTING_NON_PACKED',
"Nesting the non-packed or less tightly packed struct '{0}' in a packed "
- "struct '{1}' is not supported.",
+ "struct '{1}' isn't supported.",
correctionMessage:
"Try packing the nested struct or packing the nested struct more "
"tightly.",
@@ -414,6 +1559,53 @@
/**
* No parameters.
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when the number of dimensions
+ // specified in an `Array` annotation doesn't match the number of nested
+ // arrays specified by the type of a field.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the field `a0` has a
+ // type with three nested arrays, but only two dimensions are given in the
+ // `Array` annotation:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // [!@Array(8, 8)!]
+ // external Array<Array<Array<Uint8>>> a0;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If the type of the field is correct, then fix the annotation to have the
+ // required number of dimensions:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Array(8, 8, 4)
+ // external Array<Array<Array<Uint8>>> a0;
+ // }
+ // ```
+ //
+ // If the type of the field is wrong, then fix the type of the field:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Array(8, 8)
+ // external Array<Array<Uint8>> a0;
+ // }
+ // ```
static const FfiCode SIZE_ANNOTATION_DIMENSIONS = FfiCode(
'SIZE_ANNOTATION_DIMENSIONS',
"'Array's must have an 'Array' annotation that matches the dimensions.",
@@ -425,6 +1617,46 @@
* 0: the name of the subclass
* 1: the name of the class being extended, implemented, or mixed in
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a class extends any FFI class
+ // other than `Struct` or `Union`, or implements or mixes in any FFI class.
+ // `Struct` and `Union` are the only FFI classes that can be subtyped, and
+ // then only by extending them.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the class `C` extends
+ // `Double`:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends [!Double!] {}
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If the class should extend either `Struct` or `Union`, then change the
+ // declaration of the class:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class C extends Struct {
+ // @Int32()
+ // external int i;
+ // }
+ // ```
+ //
+ // If the class shouldn't extend either `Struct` or `Union`, then remove any
+ // references to FFI classes:
+ //
+ // ```dart
+ // class C {}
+ // ```
static const FfiCode SUBTYPE_OF_FFI_CLASS_IN_EXTENDS = FfiCode(
'SUBTYPE_OF_FFI_CLASS',
"The class '{0}' can't extend '{1}'.",
@@ -461,6 +1693,50 @@
* 0: the name of the subclass
* 1: the name of the class being extended, implemented, or mixed in
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a class extends, implements, or
+ // mixes in a class that extends either `Struct` or `Union`. Classes can only
+ // extend either `Struct` or `Union` directly.
+ //
+ // For more information about FFI, see [C interop using dart:ffi][].
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic because the class `C` extends
+ // `S`, and `S` extends `Struct`:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class S extends Struct {
+ // external Pointer f;
+ // }
+ //
+ // class C extends [!S!] {
+ // external Pointer g;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If you're trying to define a struct or union that shares some fields
+ // declared by a different struct or union, then extend `Struct` or `Union`
+ // directly and copy the shared fields:
+ //
+ // ```dart
+ // import 'dart:ffi';
+ //
+ // class S extends Struct {
+ // external Pointer f;
+ // }
+ //
+ // class C extends Struct {
+ // external Pointer f;
+ //
+ // external Pointer g;
+ // }
+ // ```
static const FfiCode SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS = FfiCode(
'SUBTYPE_OF_STRUCT_CLASS',
"The class '{0}' can't extend '{1}' because '{1}' is a subtype of "
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
index 84ee9ef..9c4b72b 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
@@ -6,6 +6,33 @@
/// Helper for creating mock packages.
class MockPackages {
+ /// Create a fake 'ffi' package that can be used by tests.
+ static void addFfiPackageFiles(Folder rootFolder) {
+ var libFolder = rootFolder.getChildAssumingFolder('lib');
+ libFolder.getChildAssumingFile('ffi.dart').writeAsStringSync(r'''
+import 'dart:ffi';
+
+const Allocator calloc = _CallocAllocator();
+
+abstract class Allocator {
+ Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment});
+
+ void free(Pointer pointer);
+}
+
+class Utf8 extends Opaque {}
+
+class _CallocAllocator implements Allocator {
+ @override
+ Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment})
+ => throw '';
+
+ @override
+ void free(Pointer pointer) => throw '';
+}
+''');
+ }
+
/// Create a fake 'js' package that can be used by tests.
static void addJsPackageFiles(Folder rootFolder) {
var libFolder = rootFolder.getChildAssumingFolder('lib');
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index e373a74..84784c3 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -662,6 +662,8 @@
class Handle extends NativeType {}
+abstract class Opaque extends NativeType {}
+
class Void extends NativeType {}
class Int8 extends NativeType {
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 1e292cc..f3dcc6d 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -13822,34 +13822,286 @@
correctionMessage: Try changing the value to 'Int8', 'Int16', 'Int32', 'Int64', 'Uint8', 'Uint16', 'UInt32', or 'Uint64'.
comment: No parameters.
ANNOTATION_ON_POINTER_FIELD:
- problemMessage: "Fields in a struct class whose type is 'Pointer' should not have any annotations."
+ problemMessage: "Fields in a struct class whose type is 'Pointer' shouldn't have any annotations."
correctionMessage: Try removing the annotation.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a field that's declared in a
+ subclass of `Struct` and has the type `Pointer` also has an annotation
+ associated with it.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the field `p`, which
+ has the type `Pointer` and is declared in a subclass of `Struct`, has the
+ annotation `@Double()`:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ [!@Double()!]
+ external Pointer<Int8> p;
+ }
+ ```
+
+ #### Common fixes
+
+ Remove the annotations from the field:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ external Pointer<Int8> p;
+ }
+ ```
ARGUMENT_MUST_BE_A_CONSTANT:
problemMessage: "Argument '{0}' must be a constant."
correctionMessage: Try replacing the value with a literal or const.
comment: |-
Parameters:
0: the name of the argument
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when an invocation of either
+ `Pointer.asFunction` or `DynamicLibrary.lookupFunction` has an `isLeaf`
+ argument whose value isn't a constant expression.
+
+ The analyzer also produces this diagnostic when the value of the
+ `exceptionalReturn` argument of `Pointer.fromFunction`.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the value of the
+ `isLeaf` argument is a parameter, and hence isn't a constant:
+
+ ```dart
+ import 'dart:ffi';
+
+ int Function(int) fromPointer(
+ Pointer<NativeFunction<Int8 Function(Int8)>> p, bool isLeaf) {
+ return p.asFunction(isLeaf: [!isLeaf!]);
+ }
+ ```
+
+ #### Common fixes
+
+ If there's a suitable constant that can be used, then replace the argument
+ with a constant:
+
+ ```dart
+ import 'dart:ffi';
+
+ const isLeaf = false;
+
+ int Function(int) fromPointer(Pointer<NativeFunction<Int8 Function(Int8)>> p) {
+ return p.asFunction(isLeaf: isLeaf);
+ }
+ ```
+
+ If there isn't a suitable constant, then replace the argument with a
+ boolean literal:
+
+ ```dart
+ import 'dart:ffi';
+
+ int Function(int) fromPointer(Pointer<NativeFunction<Int8 Function(Int8)>> p) {
+ return p.asFunction(isLeaf: true);
+ }
+ ```
CREATION_OF_STRUCT_OR_UNION:
problemMessage: "Subclasses of 'Struct' and 'Union' are backed by native memory, and can't be instantiated by a generative constructor."
correctionMessage: "Try allocating it via allocation, or load from a 'Pointer'."
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a subclass of either `Struct`
+ or `Union` is instantiated using a generative constructor.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the class `C` is being
+ instantiated using a generative constructor:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Int32()
+ external int a;
+ }
+
+ void f() {
+ [!C!]();
+ }
+ ```
+
+ #### Common fixes
+
+ If you need to allocate the structure described by the class, then use the
+ `ffi` package to do so:
+
+ ```dart
+ import 'dart:ffi';
+ import 'package:ffi/ffi.dart';
+
+ class C extends Struct {
+ @Int32()
+ external int a;
+ }
+
+ void f() {
+ final pointer = calloc.allocate<C>(4);
+ final c = pointer.ref;
+ print(c);
+ calloc.free(pointer);
+ }
+ ```
EMPTY_STRUCT:
- problemMessage: "The class '{0}' can’t be empty because it's a subclass of '{1}'."
+ problemMessage: "The class '{0}' can't be empty because it's a subclass of '{1}'."
correctionMessage: "Try adding a field to '{0}' or use a different superclass."
comment: |-
Parameters:
0: the name of the subclass
1: the name of the superclass
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a subclass of `Struct` or
+ `Union` doesn't have any fields. Having an empty `Struct` or `Union`
+ isn't supported.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the class `C`, which
+ extends `Struct`, doesn't declare any fields:
+
+ ```dart
+ import 'dart:ffi';
+
+ class [!C!] extends Struct {}
+ ```
+
+ #### Common fixes
+
+ If the class is intended to be a struct, then declare one or more fields:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Int32()
+ external int x;
+ }
+ ```
+
+ If the class is intended to be used as a type argument to `Pointer`, then
+ make it a subclass of `Opaque`:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Opaque {}
+ ```
+
+ If the class isn't intended to be a struct, then remove or change the
+ extends clause:
+
+ ```dart
+ class C {}
+ ```
EXTRA_ANNOTATION_ON_STRUCT_FIELD:
problemMessage: Fields in a struct class must have exactly one annotation indicating the native type.
correctionMessage: Try removing the extra annotation.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a field in a subclass of
+ `Struct` has more than one annotation describing the native type of the
+ field.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the field `x` has two
+ annotations describing the native type of the field:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Int32()
+ [!@Int16()!]
+ external int x;
+ }
+ ```
+
+ #### Common fixes
+
+ Remove all but one of the annotations:
+
+ ```dart
+ import 'dart:ffi';
+ class C extends Struct {
+ @Int32()
+ external int x;
+ }
+ ```
EXTRA_SIZE_ANNOTATION_CARRAY:
problemMessage: "'Array's must have exactly one 'Array' annotation."
correctionMessage: Try removing the extra annotation.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a field in a subclass of
+ `Struct` has more than one annotation describing the size of the native
+ array.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the field `a0` has two
+ annotations that specify the size of the native array:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Array(4)
+ [!@Array(8)!]
+ external Array<Uint8> a0;
+ }
+ ```
+
+ #### Common fixes
+
+ Remove all but one of the annotations:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Array(8)
+ external Array<Uint8> a0;
+ }
+ ```
FFI_NATIVE_MUST_BE_EXTERNAL:
problemMessage: FfiNative functions must be declared external.
correctionMessage: Add the `external` keyword to the function.
@@ -13876,60 +14128,576 @@
problemMessage: "Constructors in subclasses of 'Struct' and 'Union' can't have field initializers."
correctionMessage: Try removing the field initializer and marking the field as external.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a constructor in a subclass of
+ either `Struct` or `Union` has one or more field initializers.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the class `C` has a
+ constructor with an initializer for the field `f`:
+
+ ```dart
+ // @dart = 2.9
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Int32()
+ int f;
+
+ C() : [!f = 0!];
+ }
+ ```
+
+ #### Common fixes
+
+ Remove the field initializer:
+
+ ```dart
+ // @dart = 2.9
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Int32()
+ int f;
+
+ C();
+ }
+ ```
FIELD_IN_STRUCT_WITH_INITIALIZER:
problemMessage: "Fields in subclasses of 'Struct' and 'Union' can't have initializers."
correctionMessage: Try removing the initializer and marking the field as external.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a field in a subclass of
+ `Struct` has an initializer.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the field `p` has an
+ initializer:
+
+ ```dart
+ // @dart = 2.9
+ import 'dart:ffi';
+
+ class C extends Struct {
+ Pointer [!p!] = nullptr;
+ }
+ ```
+
+ #### Common fixes
+
+ Remove the initializer:
+
+ ```dart
+ // @dart = 2.9
+ import 'dart:ffi';
+
+ class C extends Struct {
+ Pointer p;
+ }
+ ```
FIELD_MUST_BE_EXTERNAL_IN_STRUCT:
problemMessage: "Fields of 'Struct' and 'Union' subclasses must be marked external."
correctionMessage: "Try adding the 'external' modifier."
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a field in a subclass of either
+ `Struct` or `Union` isn't marked as being `external`.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the field `a` isn't
+ marked as being `external`:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Int16()
+ int [!a!];
+ }
+ ```
+
+ #### Common fixes
+
+ Add the required `external` modifier:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Int16()
+ external int a;
+ }
+ ```
GENERIC_STRUCT_SUBCLASS:
- problemMessage: "The class '{0}' can't extend 'Struct' or 'Union' because it is generic."
+ problemMessage: "The class '{0}' can't extend 'Struct' or 'Union' because '{0}' is generic."
correctionMessage: "Try removing the type parameters from '{0}'."
comment: |-
Parameters:
0: the name of the struct class
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a subclass of either `Struct`
+ or `Union` has a type parameter.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the class `S` defines
+ the type parameter `T`:
+
+ ```dart
+ import 'dart:ffi';
+
+ class [!S!]<T> extends Struct {
+ external Pointer notEmpty;
+ }
+ ```
+
+ #### Common fixes
+
+ Remove the type parameters from the class:
+
+ ```dart
+ import 'dart:ffi';
+
+ class S extends Struct {
+ external Pointer notEmpty;
+ }
+ ```
INVALID_EXCEPTION_VALUE:
- problemMessage: "The method 'Pointer.fromFunction' must not have an exceptional return value (the second argument) when the return type of the function is either 'void', 'Handle' or 'Pointer'."
+ problemMessage: "The method 'Pointer.fromFunction' can't have an exceptional return value (the second argument) when the return type of the function is either 'void', 'Handle' or 'Pointer'."
correctionMessage: Try removing the exceptional return value.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when an invocation of the method
+ `Pointer.fromFunction` has a second argument (the exceptional return
+ value) and the type to be returned from the invocation is either `void`,
+ `Handle` or `Pointer`.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because a second argument is
+ provided when the return type of `f` is `void`:
+
+ ```dart
+ import 'dart:ffi';
+
+ typedef T = Void Function(Int8);
+
+ void f(int i) {}
+
+ void g() {
+ Pointer.fromFunction<T>(f, [!42!]);
+ }
+ ```
+
+ #### Common fixes
+
+ Remove the exception value:
+
+ ```dart
+ import 'dart:ffi';
+
+ typedef T = Void Function(Int8);
+
+ void f(int i) {}
+
+ void g() {
+ Pointer.fromFunction<T>(f);
+ }
+ ```
INVALID_FIELD_TYPE_IN_STRUCT:
problemMessage: "Fields in struct classes can't have the type '{0}'. They can only be declared as 'int', 'double', 'Array', 'Pointer', or subtype of 'Struct' or 'Union'."
correctionMessage: "Try using 'int', 'double', 'Array', 'Pointer', or subtype of 'Struct' or 'Union'."
comment: |-
Parameters:
0: the type of the field
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a field in a subclass of
+ `Struct` has a type other than `int`, `double`, `Array`, `Pointer`, or
+ subtype of `Struct` or `Union`.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the field `str` has
+ the type `String`, which isn't one of the allowed types for fields in a
+ subclass of `Struct`:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ external [!String!] s;
+
+ @Int32()
+ external int i;
+ }
+ ```
+
+ #### Common fixes
+
+ Use one of the allowed types for the field:
+
+ ```dart
+ import 'dart:ffi';
+ import 'package:ffi/ffi.dart';
+
+ class C extends Struct {
+ external Pointer<Utf8> s;
+
+ @Int32()
+ external int i;
+ }
+ ```
LEAF_CALL_MUST_NOT_RETURN_HANDLE:
- problemMessage: FFI leaf call must not return a Handle.
+ problemMessage: "FFI leaf call can't return a 'Handle'."
correctionMessage: Try changing the return type to primitive or struct.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when the value of the `isLeaf`
+ argument in an invocation of either `Pointer.asFunction` or
+ `DynamicLibrary.lookupFunction` is `true` and the function that would be
+ returned would have a return type of `Handle`.
+
+ The analyzer also produces this diagnostic when the value of the `isLeaf`
+ argument in an `FfiNative` annotation is `true` and the type argument on
+ the annotation is a function type whose return type is `Handle`.
+
+ In all of these cases, leaf calls are only supported for the types `bool`,
+ `int`, `float`, `double`, and, as a return type `void`.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the function `p`
+ returns a `Handle`, but the `isLeaf` argument is `true`:
+
+ ```dart
+ import 'dart:ffi';
+
+ void f(Pointer<NativeFunction<Handle Function()>> p) {
+ [!p.asFunction<Object Function()>(isLeaf: true)!];
+ }
+ ```
+
+ #### Common fixes
+
+ If the function returns a handle, then remove the `isLeaf` argument:
+
+ ```dart
+ import 'dart:ffi';
+
+ void f(Pointer<NativeFunction<Handle Function()>> p) {
+ p.asFunction<Object Function()>();
+ }
+ ```
+
+ If the function returns one of the supported types, then correct the type
+ information:
+
+ ```dart
+ import 'dart:ffi';
+
+ void f(Pointer<NativeFunction<Int32 Function()>> p) {
+ p.asFunction<int Function()>(isLeaf: true);
+ }
+ ```
LEAF_CALL_MUST_NOT_TAKE_HANDLE:
- problemMessage: FFI leaf call must not take arguments of type Handle.
+ problemMessage: "FFI leaf call can't take arguments of type 'Handle'."
correctionMessage: Try changing the argument type to primitive or struct.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when the value of the `isLeaf`
+ argument in an invocation of either `Pointer.asFunction` or
+ `DynamicLibrary.lookupFunction` is `true` and the function that would be
+ returned would have a parameter of type `Handle`.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the function `p` has a
+ parameter of type `Handle`, but the `isLeaf` argument is `true`:
+
+ ```dart
+ import 'dart:ffi';
+
+ void f(Pointer<NativeFunction<Void Function(Handle)>> p) {
+ [!p.asFunction<void Function(Object)>(isLeaf: true)!];
+ }
+ ```
+
+ #### Common fixes
+
+ If the function has at least one parameter of type `Handle`, then remove
+ the `isLeaf` argument:
+
+ ```dart
+ import 'dart:ffi';
+
+ void f(Pointer<NativeFunction<Void Function(Handle)>> p) {
+ p.asFunction<void Function(Object)>();
+ }
+ ```
+
+ If none of the function's parameters are `Handle`s, then correct the type
+ information:
+
+ ```dart
+ import 'dart:ffi';
+
+ void f(Pointer<NativeFunction<Void Function(Int8)>> p) {
+ p.asFunction<void Function(int)>(isLeaf: true);
+ }
+ ```
MISMATCHED_ANNOTATION_ON_STRUCT_FIELD:
- problemMessage: The annotation does not match the declared type of the field.
+ problemMessage: "The annotation doesn't match the declared type of the field."
correctionMessage: Try using a different annotation or changing the declared type to match.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when the annotation on a field in a
+ subclass of `Struct` or `Union` doesn't match the Dart type of the field.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the annotation
+ `Double` doesn't match the Dart type `int`:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ [!@Double()!]
+ external int x;
+ }
+ ```
+
+ #### Common fixes
+
+ If the type of the field is correct, then change the annotation to match:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Int32()
+ external int x;
+ }
+ ```
+
+ If the annotation is correct, then change the type of the field to match:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Double()
+ external double x;
+ }
+ ```
MISSING_ANNOTATION_ON_STRUCT_FIELD:
problemMessage: "Fields in a struct class must either have the type 'Pointer' or an annotation indicating the native type."
correctionMessage: Try adding an annotation.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a field in a subclass of
+ `Struct` or `Union` whose type requires an annotation doesn't have one.
+ The Dart types `int`, `double`, and `Array` are used to represent multiple
+ C types, and the annotation specifies which of the compatible C types the
+ field represents.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the field `x` doesn't
+ have an annotation indicating the underlying width of the integer value:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ external [!int!] x;
+ }
+ ```
+
+ #### Common fixes
+
+ Add an appropriate annotation to the field:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Int64()
+ external int x;
+ }
+ ```
MISSING_EXCEPTION_VALUE:
- problemMessage: "The method 'Pointer.fromFunction' must have an exceptional return value (the second argument) when the return type of the function is neither 'void', 'Handle' or 'Pointer'."
+ problemMessage: "The method 'Pointer.fromFunction' must have an exceptional return value (the second argument) when the return type of the function is neither 'void', 'Handle', nor 'Pointer'."
correctionMessage: Try adding an exceptional return value.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when an invocation of the method
+ `Pointer.fromFunction` doesn't have a second argument (the exceptional
+ return value) when the type to be returned from the invocation is neither
+ `void`, `Handle`, nor `Pointer`.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the type returned by
+ `f` is expected to be an 8-bit integer but the call to `fromFunction`
+ doesn't include an exceptional return argument:
+
+ ```dart
+ import 'dart:ffi';
+
+ int f(int i) => i * 2;
+
+ void g() {
+ Pointer.[!fromFunction!]<Int8 Function(Int8)>(f);
+ }
+ ```
+
+ #### Common fixes
+
+ Add an exceptional return type:
+
+ ```dart
+ import 'dart:ffi';
+
+ int f(int i) => i * 2;
+
+ void g() {
+ Pointer.fromFunction<Int8 Function(Int8)>(f, 0);
+ }
+ ```
MISSING_FIELD_TYPE_IN_STRUCT:
problemMessage: "Fields in struct classes must have an explicitly declared type of 'int', 'double' or 'Pointer'."
correctionMessage: "Try using 'int', 'double' or 'Pointer'."
comment: |-
Parameters:
0: the type of the field
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a field in a subclass of
+ `Struct` or `Union` doesn't have a type annotation. Every field must have
+ an explicit type, and the type must either be `int`, `double`, `Pointer`,
+ or a subclass of either `Struct` or `Union`.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the field `str`
+ doesn't have a type annotation:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ external var [!str!];
+
+ @Int32()
+ external int i;
+ }
+ ```
+
+ #### Common fixes
+
+ Explicitly specify the type of the field:
+
+ ```dart
+ import 'dart:ffi';
+ import 'package:ffi/ffi.dart';
+
+ class C extends Struct {
+ external Pointer<Utf8> str;
+
+ @Int32()
+ external int i;
+ }
+ ```
MISSING_SIZE_ANNOTATION_CARRAY:
- problemMessage: "'Array's must have exactly one 'Array' annotation."
- correctionMessage: "Try adding a 'Array' annotation."
+ problemMessage: "Fields of type 'Array' must have exactly one 'Array' annotation."
+ correctionMessage: "Try adding an 'Array' annotation, or removing all but one of the annotations."
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a field in a subclass of either
+ `Struct` or `Union` has a type of `Array` but doesn't have a single
+ `Array` annotation indicating the dimensions of the array.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the field `a0` doesn't
+ have an `Array` annotation:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ external [!Array<Uint8>!] a0;
+ }
+ ```
+
+ #### Common fixes
+
+ Ensure that there's exactly one `Array` annotation on the field:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Array(8)
+ external Array<Uint8> a0;
+ }
+ ```
MUST_BE_A_NATIVE_FUNCTION_TYPE:
problemMessage: "The type '{0}' given to '{1}' must be a valid 'dart:ffi' native function type."
correctionMessage: "Try changing the type to only use members for 'dart:ffi'."
@@ -13937,6 +14705,48 @@
Parameters:
0: the type that should be a valid dart:ffi native type.
1: the name of the function whose invocation depends on this relationship
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when an invocation of either
+ `Pointer.fromFunction` or `DynamicLibrary.lookupFunction` has a type
+ argument(whether explicit or inferred) that isn't a native function type.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the type `T` can be
+ any subclass of `Function` but the type argument for `fromFunction` is
+ required to be a native function type:
+
+ ```dart
+ import 'dart:ffi';
+
+ int f(int i) => i * 2;
+
+ class C<T extends Function> {
+ void g() {
+ Pointer.fromFunction<[!T!]>(f, 0);
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ Use a native function type as the type argument to the invocation:
+
+ ```dart
+ import 'dart:ffi';
+
+ int f(int i) => i * 2;
+
+ class C<T extends Function> {
+ void g() {
+ Pointer.fromFunction<Int32 Function(Int32)>(f, 0);
+ }
+ }
+ ```
MUST_BE_A_SUBTYPE:
problemMessage: "The type '{0}' must be a subtype of '{1}' for '{2}'."
correctionMessage: Try changing one or both of the type arguments.
@@ -13945,47 +14755,455 @@
0: the type that should be a subtype
1: the supertype that the subtype is compared to
2: the name of the function whose invocation depends on this relationship
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic in two cases:
+ - In an invocation of `Pointer.fromFunction` where the type argument
+ (whether explicit or inferred) isn't a supertype of the type of the
+ function passed as the first argument to the method.
+ - In an invocation of `DynamicLibrary.lookupFunction` where the first type
+ argument isn't a supertype of the second type argument.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the type of the
+ function `f` (`String Function(int)`) isn't a subtype of the type
+ argument `T` (`Int8 Function(Int8)`):
+
+ ```dart
+ import 'dart:ffi';
+
+ typedef T = Int8 Function(Int8);
+
+ double f(double i) => i;
+
+ void g() {
+ Pointer.fromFunction<T>([!f!], 5.0);
+ }
+ ```
+
+ #### Common fixes
+
+ If the function is correct, then change the type argument to match:
+
+ ```dart
+ import 'dart:ffi';
+
+ typedef T = Float Function(Float);
+
+ double f(double i) => i;
+
+ void g() {
+ Pointer.fromFunction<T>(f, 5.0);
+ }
+ ```
+
+ If the type argument is correct, then change the function to match:
+
+ ```dart
+ import 'dart:ffi';
+
+ typedef T = Int8 Function(Int8);
+
+ int f(int i) => i;
+
+ void g() {
+ Pointer.fromFunction<T>(f, 5);
+ }
+ ```
NON_CONSTANT_TYPE_ARGUMENT:
- problemMessage: "The type arguments to '{0}' must be compile time constants but type parameters are not constants."
+ problemMessage: "The type arguments to '{0}' must be known at compile time, so they can't be type parameters."
correctionMessage: Try changing the type argument to be a constant type.
comment: |-
Parameters:
0: the name of the function, method, or constructor having type arguments
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when the type arguments to a method
+ are required to be known at compile time, but a type parameter, whose
+ value can't be known at compile time, is used as a type argument.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the type argument to
+ `Pointer.asFunction` must be known at compile time, but the type parameter
+ `R`, which isn't known at compile time, is being used as the type
+ argument:
+
+ ```dart
+ import 'dart:ffi';
+
+ typedef T = int Function(int);
+
+ class C<R extends T> {
+ void m(Pointer<NativeFunction<T>> p) {
+ p.asFunction<[!R!]>();
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ Remove any uses of type parameters:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C {
+ void m(Pointer<NativeFunction<Int64 Function(Int64)>> p) {
+ p.asFunction<int Function(int)>();
+ }
+ }
+ ```
NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER:
- problemMessage: "The type argument for the pointer '{0}' must be a valid 'NativeFunction' in order to use 'asFunction'."
+ problemMessage: "Can't invoke 'asFunction' because the function signature '{0}' for the pointer isn't a valid C function signature."
correctionMessage: "Try changing the function argument in 'NativeFunction' to only use NativeTypes."
comment: |-
Parameters:
0: the type that should be a valid dart:ffi native type.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when the method `asFunction` is
+ invoked on a pointer to a native function, but the signature of the native
+ function isn't a valid C function signature.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because function signature
+ associated with the pointer `p` (`FNative`) isn't a valid C function
+ signature:
+
+ ```dart
+ import 'dart:ffi';
+
+ typedef FNative = int Function(int);
+ typedef F = int Function(int);
+
+ class C {
+ void f(Pointer<NativeFunction<FNative>> p) {
+ p.asFunction<[!F!]>();
+ }
+ }
+ ```
+
+ #### Common fixes
+
+ Make the `NativeFunction` signature a valid C signature:
+
+ ```dart
+ import 'dart:ffi';
+
+ typedef FNative = Int8 Function(Int8);
+ typedef F = int Function(int);
+
+ class C {
+ void f(Pointer<NativeFunction<FNative>> p) {
+ p.asFunction<F>();
+ }
+ }
+ ```
NON_POSITIVE_ARRAY_DIMENSION:
problemMessage: Array dimensions must be positive numbers.
correctionMessage: Try changing the input to a positive number.
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a dimension given in an `Array`
+ annotation is less than or equal to zero (`0`).
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because an array dimension of
+ `-1` was provided:
+
+ ```dart
+ import 'dart:ffi';
+
+ class MyStruct extends Struct {
+ @Array([!-8!])
+ external Array<Uint8> a0;
+ }
+ ```
+
+ #### Common fixes
+
+ Change the dimension to be a positive integer:
+
+ ```dart
+ import 'dart:ffi';
+
+ class MyStruct extends Struct {
+ @Array(8)
+ external Array<Uint8> a0;
+ }
+ ```
NON_SIZED_TYPE_ARGUMENT:
- problemMessage: "Type arguments to '{0}' can't have the type '{1}'. They can only be declared as native integer, 'Float', 'Double', 'Pointer', or subtype of 'Struct', 'Union', or 'AbiSpecificInteger'."
+ problemMessage: "The type '{1}' isn't a valid type argument for '{0}'. The type argument must be a native integer, 'Float', 'Double', 'Pointer', or subtype of 'Struct', 'Union', or 'AbiSpecificInteger'."
correctionMessage: "Try using a native integer, 'Float', 'Double', 'Pointer', or subtype of 'Struct', 'Union', or 'AbiSpecificInteger'."
comment: |-
Parameters:
0: the type of the field
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when the type argument for the class
+ `Array` isn't one of the valid types: either a native integer, `Float`,
+ `Double`, `Pointer`, or subtype of `Struct`, `Union`, or
+ `AbiSpecificInteger`.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the type argument to
+ `Array` is `Void`, and `Void` isn't one of the valid types:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Array(8)
+ external Array<[!Void!]> a0;
+ }
+ ```
+
+ #### Common fixes
+
+ Change the type argument to one of the valid types:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Array(8)
+ external Array<Uint8> a0;
+ }
+ ```
PACKED_ANNOTATION:
problemMessage: "Structs must have at most one 'Packed' annotation."
correctionMessage: "Try removing extra 'Packed' annotations."
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a subclass of `Struct` has more
+ than one `Packed` annotation.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the class `C`, which
+ is a subclass of `Struct`, has two `Packed` annotations:
+
+ ```dart
+ import 'dart:ffi';
+
+ @Packed(1)
+ [!@Packed(1)!]
+ class C extends Struct {
+ external Pointer<Uint8> notEmpty;
+ }
+ ```
+
+ #### Common fixes
+
+ Remove all but one of the annotations:
+
+ ```dart
+ import 'dart:ffi';
+
+ @Packed(1)
+ class C extends Struct {
+ external Pointer<Uint8> notEmpty;
+ }
+ ```
PACKED_ANNOTATION_ALIGNMENT:
problemMessage: Only packing to 1, 2, 4, 8, and 16 bytes is supported.
correctionMessage: "Try changing the 'Packed' annotation alignment to 1, 2, 4, 8, or 16."
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when the argument to the `Packed`
+ annotation isn't one of the allowed values: 1, 2, 4, 8, or 16.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the argument to the
+ `Packed` annotation (`3`) isn't one of the allowed values:
+
+ ```dart
+ import 'dart:ffi';
+
+ @Packed([!3!])
+ class C extends Struct {
+ external Pointer<Uint8> notEmpty;
+ }
+ ```
+
+ #### Common fixes
+
+ Change the alignment to be one of the allowed values:
+
+ ```dart
+ import 'dart:ffi';
+
+ @Packed(4)
+ class C extends Struct {
+ external Pointer<Uint8> notEmpty;
+ }
+ ```
PACKED_NESTING_NON_PACKED:
- problemMessage: "Nesting the non-packed or less tightly packed struct '{0}' in a packed struct '{1}' is not supported."
+ problemMessage: "Nesting the non-packed or less tightly packed struct '{0}' in a packed struct '{1}' isn't supported."
correctionMessage: Try packing the nested struct or packing the nested struct more tightly.
comment: |-
Parameters:
0: the name of the outer struct
1: the name of the struct being nested
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a subclass of `Struct` that is
+ annotated as being `Packed` declares a field whose type is also a subclass
+ of `Struct` and the field's type is either not packed or is packed less
+ tightly.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the class `Outer`,
+ which is a subclass of `Struct` and is packed on 1-byte boundaries,
+ declared a field whose type (`Inner`) is packed on 8-byte boundaries:
+
+ ```dart
+ import 'dart:ffi';
+
+ @Packed(8)
+ class Inner extends Struct {
+ external Pointer<Uint8> notEmpty;
+ }
+
+ @Packed(1)
+ class Outer extends Struct {
+ external Pointer<Uint8> notEmpty;
+
+ external [!Inner!] nestedLooselyPacked;
+ }
+ ```
+
+ #### Common fixes
+
+ If the inner struct should be packed more tightly, then change the
+ argument to the inner struct's `Packed` annotation:
+
+ ```dart
+ import 'dart:ffi';
+
+ @Packed(1)
+ class Inner extends Struct {
+ external Pointer<Uint8> notEmpty;
+ }
+
+ @Packed(1)
+ class Outer extends Struct {
+ external Pointer<Uint8> notEmpty;
+
+ external Inner nestedLooselyPacked;
+ }
+ ```
+
+ If the outer struct should be packed less tightly, then change the
+ argument to the outer struct's `Packed` annotation:
+
+ ```dart
+ import 'dart:ffi';
+
+ @Packed(8)
+ class Inner extends Struct {
+ external Pointer<Uint8> notEmpty;
+ }
+
+ @Packed(8)
+ class Outer extends Struct {
+ external Pointer<Uint8> notEmpty;
+
+ external Inner nestedLooselyPacked;
+ }
+ ```
+
+ If the inner struct doesn't have an annotation and should be packed, then
+ add an annotation.
+
+ If the inner struct doesn't have an annotation and the outer struct
+ shouldn't be packed, then remove its annotation.
SIZE_ANNOTATION_DIMENSIONS:
problemMessage: "'Array's must have an 'Array' annotation that matches the dimensions."
correctionMessage: "Try adjusting the arguments in the 'Array' annotation."
comment: No parameters.
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when the number of dimensions
+ specified in an `Array` annotation doesn't match the number of nested
+ arrays specified by the type of a field.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the field `a0` has a
+ type with three nested arrays, but only two dimensions are given in the
+ `Array` annotation:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ [!@Array(8, 8)!]
+ external Array<Array<Array<Uint8>>> a0;
+ }
+ ```
+
+ #### Common fixes
+
+ If the type of the field is correct, then fix the annotation to have the
+ required number of dimensions:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Array(8, 8, 4)
+ external Array<Array<Array<Uint8>>> a0;
+ }
+ ```
+
+ If the type of the field is wrong, then fix the type of the field:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Array(8, 8)
+ external Array<Array<Uint8>> a0;
+ }
+ ```
SUBTYPE_OF_FFI_CLASS_IN_EXTENDS:
sharedName: SUBTYPE_OF_FFI_CLASS
problemMessage: "The class '{0}' can't extend '{1}'."
@@ -13994,6 +15212,47 @@
Parameters:
0: the name of the subclass
1: the name of the class being extended, implemented, or mixed in
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a class extends any FFI class
+ other than `Struct` or `Union`, or implements or mixes in any FFI class.
+ `Struct` and `Union` are the only FFI classes that can be subtyped, and
+ then only by extending them.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the class `C` extends
+ `Double`:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends [!Double!] {}
+ ```
+
+ #### Common fixes
+
+ If the class should extend either `Struct` or `Union`, then change the
+ declaration of the class:
+
+ ```dart
+ import 'dart:ffi';
+
+ class C extends Struct {
+ @Int32()
+ external int i;
+ }
+ ```
+
+ If the class shouldn't extend either `Struct` or `Union`, then remove any
+ references to FFI classes:
+
+ ```dart
+ class C {}
+ ```
SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS:
sharedName: SUBTYPE_OF_FFI_CLASS
problemMessage: "The class '{0}' can't implement '{1}'."
@@ -14018,6 +15277,51 @@
Parameters:
0: the name of the subclass
1: the name of the class being extended, implemented, or mixed in
+ documentation: |-
+ #### Description
+
+ The analyzer produces this diagnostic when a class extends, implements, or
+ mixes in a class that extends either `Struct` or `Union`. Classes can only
+ extend either `Struct` or `Union` directly.
+
+ For more information about FFI, see [C interop using dart:ffi][].
+
+ #### Example
+
+ The following code produces this diagnostic because the class `C` extends
+ `S`, and `S` extends `Struct`:
+
+ ```dart
+ import 'dart:ffi';
+
+ class S extends Struct {
+ external Pointer f;
+ }
+
+ class C extends [!S!] {
+ external Pointer g;
+ }
+ ```
+
+ #### Common fixes
+
+ If you're trying to define a struct or union that shares some fields
+ declared by a different struct or union, then extend `Struct` or `Union`
+ directly and copy the shared fields:
+
+ ```dart
+ import 'dart:ffi';
+
+ class S extends Struct {
+ external Pointer f;
+ }
+
+ class C extends Struct {
+ external Pointer f;
+
+ external Pointer g;
+ }
+ ```
SUBTYPE_OF_STRUCT_CLASS_IN_IMPLEMENTS:
sharedName: SUBTYPE_OF_STRUCT_CLASS
problemMessage: "The class '{0}' can't implement '{1}' because '{1}' is a subtype of 'Struct', 'Union', or 'AbiSpecificInteger'."
diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
index 89c6d3f..3f5a183 100644
--- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
@@ -313,6 +313,7 @@
void writeTestPackageConfig(
PackageConfigFileBuilder config, {
String? languageVersion,
+ bool ffi = false,
bool js = false,
bool meta = false,
}) {
@@ -324,6 +325,14 @@
languageVersion: languageVersion ?? testPackageLanguageVersion,
);
+ if (ffi) {
+ var ffiPath = '/packages/ffi';
+ MockPackages.addFfiPackageFiles(
+ getFolder(ffiPath),
+ );
+ config.add(name: 'ffi', rootPath: ffiPath);
+ }
+
if (js) {
var jsPath = '/packages/js';
MockPackages.addJsPackageFiles(
diff --git a/pkg/analyzer/test/verify_diagnostics_test.dart b/pkg/analyzer/test/verify_diagnostics_test.dart
index d5ee1bf..873f700 100644
--- a/pkg/analyzer/test/verify_diagnostics_test.dart
+++ b/pkg/analyzer/test/verify_diagnostics_test.dart
@@ -451,6 +451,6 @@
);
}
}
- writeTestPackageConfig(packageConfigBuilder, meta: true);
+ writeTestPackageConfig(packageConfigBuilder, ffi: true, meta: true);
}
}
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 282257c..c8454b0 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -649,6 +649,101 @@
}
{% endprettify %}
+### annotation_on_pointer_field
+
+_Fields in a struct class whose type is 'Pointer' shouldn't have any
+annotations._
+
+#### Description
+
+The analyzer produces this diagnostic when a field that's declared in a
+subclass of `Struct` and has the type `Pointer` also has an annotation
+associated with it.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the field `p`, which
+has the type `Pointer` and is declared in a subclass of `Struct`, has the
+annotation `@Double()`:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ [!@Double()!]
+ external Pointer<Int8> p;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove the annotations from the field:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ external Pointer<Int8> p;
+}
+{% endprettify %}
+
+### argument_must_be_a_constant
+
+_Argument '{0}' must be a constant._
+
+#### Description
+
+The analyzer produces this diagnostic when an invocation of either
+`Pointer.asFunction` or `DynamicLibrary.lookupFunction` has an `isLeaf`
+argument whose value isn't a constant expression.
+
+The analyzer also produces this diagnostic when the value of the
+`exceptionalReturn` argument of `Pointer.fromFunction`.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the value of the
+`isLeaf` argument is a parameter, and hence isn't a constant:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+int Function(int) fromPointer(
+ Pointer<NativeFunction<Int8 Function(Int8)>> p, bool isLeaf) {
+ return p.asFunction(isLeaf: [!isLeaf!]);
+}
+{% endprettify %}
+
+#### Common fixes
+
+If there's a suitable constant that can be used, then replace the argument
+with a constant:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+const isLeaf = false;
+
+int Function(int) fromPointer(Pointer<NativeFunction<Int8 Function(Int8)>> p) {
+ return p.asFunction(isLeaf: isLeaf);
+}
+{% endprettify %}
+
+If there isn't a suitable constant, then replace the argument with a
+boolean literal:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+int Function(int) fromPointer(Pointer<NativeFunction<Int8 Function(Int8)>> p) {
+ return p.asFunction(isLeaf: true);
+}
+{% endprettify %}
+
### argument_type_not_assignable
_The argument type '{0}' can't be assigned to the parameter type '{1}'._
@@ -2696,6 +2791,58 @@
C<T> newC<T>() => C<T>();
{% endprettify %}
+### creation_of_struct_or_union
+
+_Subclasses of 'Struct' and 'Union' are backed by native memory, and can't be
+instantiated by a generative constructor._
+
+#### Description
+
+The analyzer produces this diagnostic when a subclass of either `Struct`
+or `Union` is instantiated using a generative constructor.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the class `C` is being
+instantiated using a generative constructor:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Int32()
+ external int a;
+}
+
+void f() {
+ [!C!]();
+}
+{% endprettify %}
+
+#### Common fixes
+
+If you need to allocate the structure described by the class, then use the
+`ffi` package to do so:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+import 'package:ffi/ffi.dart';
+
+class C extends Struct {
+ @Int32()
+ external int a;
+}
+
+void f() {
+ final pointer = calloc.allocate<C>(4);
+ final c = pointer.ref;
+ print(c);
+ calloc.free(pointer);
+}
+{% endprettify %}
+
### creation_with_non_type
_The name '{0}' isn't a class._
@@ -3777,6 +3924,58 @@
var x = min(2, min(0, 1));
{% endprettify %}
+### empty_struct
+
+_The class '{0}' can't be empty because it's a subclass of '{1}'._
+
+#### Description
+
+The analyzer produces this diagnostic when a subclass of `Struct` or
+`Union` doesn't have any fields. Having an empty `Struct` or `Union`
+isn't supported.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the class `C`, which
+extends `Struct`, doesn't declare any fields:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class [!C!] extends Struct {}
+{% endprettify %}
+
+#### Common fixes
+
+If the class is intended to be a struct, then declare one or more fields:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Int32()
+ external int x;
+}
+{% endprettify %}
+
+If the class is intended to be used as a type argument to `Pointer`, then
+make it a subclass of `Opaque`:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Opaque {}
+{% endprettify %}
+
+If the class isn't intended to be a struct, then remove or change the
+extends clause:
+
+{% prettify dart tag=pre+code %}
+class C {}
+{% endprettify %}
+
### equal_elements_in_const_set
_Two elements in a constant set literal can't be equal._
@@ -4548,6 +4747,46 @@
If there are multiple cascaded accesses, you'll need to duplicate the
extension override for each one.
+### extra_annotation_on_struct_field
+
+_Fields in a struct class must have exactly one annotation indicating the native
+type._
+
+#### Description
+
+The analyzer produces this diagnostic when a field in a subclass of
+`Struct` has more than one annotation describing the native type of the
+field.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the field `x` has two
+annotations describing the native type of the field:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Int32()
+ [!@Int16()!]
+ external int x;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove all but one of the annotations:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+class C extends Struct {
+ @Int32()
+ external int x;
+}
+{% endprettify %}
+
### extra_positional_arguments
_Too many positional arguments: {0} expected, but {1} found._
@@ -4625,6 +4864,46 @@
}
{% endprettify %}
+### extra_size_annotation_carray
+
+_'Array's must have exactly one 'Array' annotation._
+
+#### Description
+
+The analyzer produces this diagnostic when a field in a subclass of
+`Struct` has more than one annotation describing the size of the native
+array.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the field `a0` has two
+annotations that specify the size of the native array:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Array(4)
+ [!@Array(8)!]
+ external Array<Uint8> a0;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove all but one of the annotations:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Array(8)
+ external Array<Uint8> a0;
+}
+{% endprettify %}
+
### field_initialized_by_multiple_initializers
_The field '{0}' can't be initialized twice in the same constructor._
@@ -4800,6 +5079,51 @@
}
{% endprettify %}
+### field_initializer_in_struct
+
+_Constructors in subclasses of 'Struct' and 'Union' can't have field
+initializers._
+
+#### Description
+
+The analyzer produces this diagnostic when a constructor in a subclass of
+either `Struct` or `Union` has one or more field initializers.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the class `C` has a
+constructor with an initializer for the field `f`:
+
+{% prettify dart tag=pre+code %}
+// @dart = 2.9
+import 'dart:ffi';
+
+class C extends Struct {
+ @Int32()
+ int f;
+
+ C() : [!f = 0!];
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove the field initializer:
+
+{% prettify dart tag=pre+code %}
+// @dart = 2.9
+import 'dart:ffi';
+
+class C extends Struct {
+ @Int32()
+ int f;
+
+ C();
+}
+{% endprettify %}
+
### field_initializer_not_assignable
_The initializer type '{0}' can't be assigned to the field type '{1}' in a const
@@ -4981,6 +5305,82 @@
}
{% endprettify %}
+### field_in_struct_with_initializer
+
+_Fields in subclasses of 'Struct' and 'Union' can't have initializers._
+
+#### Description
+
+The analyzer produces this diagnostic when a field in a subclass of
+`Struct` has an initializer.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the field `p` has an
+initializer:
+
+{% prettify dart tag=pre+code %}
+// @dart = 2.9
+import 'dart:ffi';
+
+class C extends Struct {
+ Pointer [!p!] = nullptr;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove the initializer:
+
+{% prettify dart tag=pre+code %}
+// @dart = 2.9
+import 'dart:ffi';
+
+class C extends Struct {
+ Pointer p;
+}
+{% endprettify %}
+
+### field_must_be_external_in_struct
+
+_Fields of 'Struct' and 'Union' subclasses must be marked external._
+
+#### Description
+
+The analyzer produces this diagnostic when a field in a subclass of either
+`Struct` or `Union` isn't marked as being `external`.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the field `a` isn't
+marked as being `external`:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Int16()
+ int [!a!];
+}
+{% endprettify %}
+
+#### Common fixes
+
+Add the required `external` modifier:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Int16()
+ external int a;
+}
+{% endprettify %}
+
### final_initialized_in_declaration_and_constructor
_'{0}' is final and was given a value when it was declared, so it can't be set
@@ -5369,6 +5769,42 @@
}
{% endprettify %}
+### generic_struct_subclass
+
+_The class '{0}' can't extend 'Struct' or 'Union' because '{0}' is generic._
+
+#### Description
+
+The analyzer produces this diagnostic when a subclass of either `Struct`
+or `Union` has a type parameter.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the class `S` defines
+the type parameter `T`:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class [!S!]<T> extends Struct {
+ external Pointer notEmpty;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove the type parameters from the class:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class S extends Struct {
+ external Pointer notEmpty;
+}
+{% endprettify %}
+
### getter_not_subtype_setter_types
_The return type of getter '{0}' is '{1}' which isn't a subtype of the type
@@ -6565,6 +7001,53 @@
version: ^1.4.0
```
+### invalid_exception_value
+
+_The method 'Pointer.fromFunction' can't have an exceptional return value (the
+second argument) when the return type of the function is either 'void', 'Handle' or 'Pointer'._
+
+#### Description
+
+The analyzer produces this diagnostic when an invocation of the method
+`Pointer.fromFunction` has a second argument (the exceptional return
+value) and the type to be returned from the invocation is either `void`,
+`Handle` or `Pointer`.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because a second argument is
+provided when the return type of `f` is `void`:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+typedef T = Void Function(Int8);
+
+void f(int i) {}
+
+void g() {
+ Pointer.fromFunction<T>(f, [!42!]);
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove the exception value:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+typedef T = Void Function(Int8);
+
+void f(int i) {}
+
+void g() {
+ Pointer.fromFunction<T>(f);
+}
+{% endprettify %}
+
### invalid_extension_argument_count
_Extension overrides must have exactly one argument: the value of 'this' in the
@@ -6677,6 +7160,52 @@
}
{% endprettify %}
+### invalid_field_type_in_struct
+
+_Fields in struct classes can't have the type '{0}'. They can only be declared
+as 'int', 'double', 'Array', 'Pointer', or subtype of 'Struct' or 'Union'._
+
+#### Description
+
+The analyzer produces this diagnostic when a field in a subclass of
+`Struct` has a type other than `int`, `double`, `Array`, `Pointer`, or
+subtype of `Struct` or `Union`.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the field `str` has
+the type `String`, which isn't one of the allowed types for fields in a
+subclass of `Struct`:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ external [!String!] s;
+
+ @Int32()
+ external int i;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Use one of the allowed types for the field:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+import 'package:ffi/ffi.dart';
+
+class C extends Struct {
+ external Pointer<Utf8> s;
+
+ @Int32()
+ external int i;
+}
+{% endprettify %}
+
### invalid_implementation_override
_'{1}.{0}' ('{2}') isn't a valid concrete implementation of '{3}.{0}' ('{4}')._
@@ -7748,6 +8277,112 @@
}
{% endprettify %}
+### leaf_call_must_not_return_handle
+
+_FFI leaf call can't return a 'Handle'._
+
+#### Description
+
+The analyzer produces this diagnostic when the value of the `isLeaf`
+argument in an invocation of either `Pointer.asFunction` or
+`DynamicLibrary.lookupFunction` is `true` and the function that would be
+returned would have a return type of `Handle`.
+
+The analyzer also produces this diagnostic when the value of the `isLeaf`
+argument in an `FfiNative` annotation is `true` and the type argument on
+the annotation is a function type whose return type is `Handle`.
+
+In all of these cases, leaf calls are only supported for the types `bool`,
+`int`, `float`, `double`, and, as a return type `void`.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the function `p`
+returns a `Handle`, but the `isLeaf` argument is `true`:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+void f(Pointer<NativeFunction<Handle Function()>> p) {
+ [!p.asFunction<Object Function()>(isLeaf: true)!];
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the function returns a handle, then remove the `isLeaf` argument:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+void f(Pointer<NativeFunction<Handle Function()>> p) {
+ p.asFunction<Object Function()>();
+}
+{% endprettify %}
+
+If the function returns one of the supported types, then correct the type
+information:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+void f(Pointer<NativeFunction<Int32 Function()>> p) {
+ p.asFunction<int Function()>(isLeaf: true);
+}
+{% endprettify %}
+
+### leaf_call_must_not_take_handle
+
+_FFI leaf call can't take arguments of type 'Handle'._
+
+#### Description
+
+The analyzer produces this diagnostic when the value of the `isLeaf`
+argument in an invocation of either `Pointer.asFunction` or
+`DynamicLibrary.lookupFunction` is `true` and the function that would be
+returned would have a parameter of type `Handle`.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the function `p` has a
+parameter of type `Handle`, but the `isLeaf` argument is `true`:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+void f(Pointer<NativeFunction<Void Function(Handle)>> p) {
+ [!p.asFunction<void Function(Object)>(isLeaf: true)!];
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the function has at least one parameter of type `Handle`, then remove
+the `isLeaf` argument:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+void f(Pointer<NativeFunction<Void Function(Handle)>> p) {
+ p.asFunction<void Function(Object)>();
+}
+{% endprettify %}
+
+If none of the function's parameters are `Handle`s, then correct the type
+information:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+void f(Pointer<NativeFunction<Void Function(Int8)>> p) {
+ p.asFunction<void Function(int)>(isLeaf: true);
+}
+{% endprettify %}
+
### list_element_type_not_assignable
_The element type '{0}' can't be assigned to the list type '{1}'._
@@ -8027,6 +8662,96 @@
var m = <String, int>{'a' : 2};
{% endprettify %}
+### mismatched_annotation_on_struct_field
+
+_The annotation doesn't match the declared type of the field._
+
+#### Description
+
+The analyzer produces this diagnostic when the annotation on a field in a
+subclass of `Struct` or `Union` doesn't match the Dart type of the field.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the annotation
+`Double` doesn't match the Dart type `int`:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ [!@Double()!]
+ external int x;
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the type of the field is correct, then change the annotation to match:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Int32()
+ external int x;
+}
+{% endprettify %}
+
+If the annotation is correct, then change the type of the field to match:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Double()
+ external double x;
+}
+{% endprettify %}
+
+### missing_annotation_on_struct_field
+
+_Fields in a struct class must either have the type 'Pointer' or an annotation
+indicating the native type._
+
+#### Description
+
+The analyzer produces this diagnostic when a field in a subclass of
+`Struct` or `Union` whose type requires an annotation doesn't have one.
+The Dart types `int`, `double`, and `Array` are used to represent multiple
+C types, and the annotation specifies which of the compatible C types the
+field represents.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the field `x` doesn't
+have an annotation indicating the underlying width of the integer value:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ external [!int!] x;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Add an appropriate annotation to the field:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Int64()
+ external int x;
+}
+{% endprettify %}
+
### missing_dart_library
_Required library '{0}' is missing._
@@ -8158,6 +8883,96 @@
}
{% endprettify %}
+### missing_exception_value
+
+_The method 'Pointer.fromFunction' must have an exceptional return value (the
+second argument) when the return type of the function is neither 'void', 'Handle', nor 'Pointer'._
+
+#### Description
+
+The analyzer produces this diagnostic when an invocation of the method
+`Pointer.fromFunction` doesn't have a second argument (the exceptional
+return value) when the type to be returned from the invocation is neither
+`void`, `Handle`, nor `Pointer`.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the type returned by
+`f` is expected to be an 8-bit integer but the call to `fromFunction`
+doesn't include an exceptional return argument:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+int f(int i) => i * 2;
+
+void g() {
+ Pointer.[!fromFunction!]<Int8 Function(Int8)>(f);
+}
+{% endprettify %}
+
+#### Common fixes
+
+Add an exceptional return type:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+int f(int i) => i * 2;
+
+void g() {
+ Pointer.fromFunction<Int8 Function(Int8)>(f, 0);
+}
+{% endprettify %}
+
+### missing_field_type_in_struct
+
+_Fields in struct classes must have an explicitly declared type of 'int',
+'double' or 'Pointer'._
+
+#### Description
+
+The analyzer produces this diagnostic when a field in a subclass of
+`Struct` or `Union` doesn't have a type annotation. Every field must have
+an explicit type, and the type must either be `int`, `double`, `Pointer`,
+or a subclass of either `Struct` or `Union`.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the field `str`
+doesn't have a type annotation:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ external var [!str!];
+
+ @Int32()
+ external int i;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Explicitly specify the type of the field:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+import 'package:ffi/ffi.dart';
+
+class C extends Struct {
+ external Pointer<Utf8> str;
+
+ @Int32()
+ external int i;
+}
+{% endprettify %}
+
### missing_name
_The 'name' field is required but missing._
@@ -8289,6 +9104,44 @@
Add a `return` statement that makes the return value explicit, even if
`null` is the appropriate value.
+### missing_size_annotation_carray
+
+_Fields of type 'Array' must have exactly one 'Array' annotation._
+
+#### Description
+
+The analyzer produces this diagnostic when a field in a subclass of either
+`Struct` or `Union` has a type of `Array` but doesn't have a single
+`Array` annotation indicating the dimensions of the array.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the field `a0` doesn't
+have an `Array` annotation:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ external [!Array<Uint8>!] a0;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Ensure that there's exactly one `Array` annotation on the field:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Array(8)
+ external Array<Uint8> a0;
+}
+{% endprettify %}
+
### mixin_application_concrete_super_invoked_member_type
_The super-invoked member '{0}' has the type '{1}', and the concrete member in
@@ -8820,6 +9673,115 @@
}
{% endprettify %}
+### must_be_a_native_function_type
+
+_The type '{0}' given to '{1}' must be a valid 'dart:ffi' native function type._
+
+#### Description
+
+The analyzer produces this diagnostic when an invocation of either
+`Pointer.fromFunction` or `DynamicLibrary.lookupFunction` has a type
+argument(whether explicit or inferred) that isn't a native function type.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the type `T` can be
+any subclass of `Function` but the type argument for `fromFunction` is
+required to be a native function type:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+int f(int i) => i * 2;
+
+class C<T extends Function> {
+ void g() {
+ Pointer.fromFunction<[!T!]>(f, 0);
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+Use a native function type as the type argument to the invocation:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+int f(int i) => i * 2;
+
+class C<T extends Function> {
+ void g() {
+ Pointer.fromFunction<Int32 Function(Int32)>(f, 0);
+ }
+}
+{% endprettify %}
+
+### must_be_a_subtype
+
+_The type '{0}' must be a subtype of '{1}' for '{2}'._
+
+#### Description
+
+The analyzer produces this diagnostic in two cases:
+- In an invocation of `Pointer.fromFunction` where the type argument
+ (whether explicit or inferred) isn't a supertype of the type of the
+ function passed as the first argument to the method.
+- In an invocation of `DynamicLibrary.lookupFunction` where the first type
+ argument isn't a supertype of the second type argument.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the type of the
+function `f` (`String Function(int)`) isn't a subtype of the type
+argument `T` (`Int8 Function(Int8)`):
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+typedef T = Int8 Function(Int8);
+
+double f(double i) => i;
+
+void g() {
+ Pointer.fromFunction<T>([!f!], 5.0);
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the function is correct, then change the type argument to match:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+typedef T = Float Function(Float);
+
+double f(double i) => i;
+
+void g() {
+ Pointer.fromFunction<T>(f, 5.0);
+}
+{% endprettify %}
+
+If the type argument is correct, then change the function to match:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+typedef T = Int8 Function(Int8);
+
+int f(int i) => i;
+
+void g() {
+ Pointer.fromFunction<T>(f, 5);
+}
+{% endprettify %}
+
### must_be_immutable
_This class (or a class that this class inherits from) is marked as
@@ -9640,6 +10602,52 @@
var s = {i};
{% endprettify %}
+### non_constant_type_argument
+
+_The type arguments to '{0}' must be known at compile time, so they can't be
+type parameters._
+
+#### Description
+
+The analyzer produces this diagnostic when the type arguments to a method
+are required to be known at compile time, but a type parameter, whose
+value can't be known at compile time, is used as a type argument.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the type argument to
+`Pointer.asFunction` must be known at compile time, but the type parameter
+`R`, which isn't known at compile time, is being used as the type
+argument:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+typedef T = int Function(int);
+
+class C<R extends T> {
+ void m(Pointer<NativeFunction<T>> p) {
+ p.asFunction<[!R!]>();
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove any uses of type parameters:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C {
+ void m(Pointer<NativeFunction<Int64 Function(Int64)>> p) {
+ p.asFunction<int Function(int)>();
+ }
+}
+{% endprettify %}
+
### non_const_call_to_literal_constructor
_This instance creation must be 'const', because the {0} constructor is marked
@@ -9728,6 +10736,134 @@
If the generative constructor is the unnamed constructor, and if there are
no arguments being passed to it, then you can remove the super invocation.
+### non_native_function_type_argument_to_pointer
+
+_Can't invoke 'asFunction' because the function signature '{0}' for the pointer
+isn't a valid C function signature._
+
+#### Description
+
+The analyzer produces this diagnostic when the method `asFunction` is
+invoked on a pointer to a native function, but the signature of the native
+function isn't a valid C function signature.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because function signature
+associated with the pointer `p` (`FNative`) isn't a valid C function
+signature:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+typedef FNative = int Function(int);
+typedef F = int Function(int);
+
+class C {
+ void f(Pointer<NativeFunction<FNative>> p) {
+ p.asFunction<[!F!]>();
+ }
+}
+{% endprettify %}
+
+#### Common fixes
+
+Make the `NativeFunction` signature a valid C signature:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+typedef FNative = Int8 Function(Int8);
+typedef F = int Function(int);
+
+class C {
+ void f(Pointer<NativeFunction<FNative>> p) {
+ p.asFunction<F>();
+ }
+}
+{% endprettify %}
+
+### non_positive_array_dimension
+
+_Array dimensions must be positive numbers._
+
+#### Description
+
+The analyzer produces this diagnostic when a dimension given in an `Array`
+annotation is less than or equal to zero (`0`).
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because an array dimension of
+`-1` was provided:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class MyStruct extends Struct {
+ @Array([!-8!])
+ external Array<Uint8> a0;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Change the dimension to be a positive integer:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class MyStruct extends Struct {
+ @Array(8)
+ external Array<Uint8> a0;
+}
+{% endprettify %}
+
+### non_sized_type_argument
+
+_The type '{1}' isn't a valid type argument for '{0}'. The type argument must be
+a native integer, 'Float', 'Double', 'Pointer', or subtype of 'Struct', 'Union', or 'AbiSpecificInteger'._
+
+#### Description
+
+The analyzer produces this diagnostic when the type argument for the class
+`Array` isn't one of the valid types: either a native integer, `Float`,
+`Double`, `Pointer`, or subtype of `Struct`, `Union`, or
+`AbiSpecificInteger`.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the type argument to
+`Array` is `Void`, and `Void` isn't one of the valid types:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Array(8)
+ external Array<[!Void!]> a0;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Change the type argument to one of the valid types:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Array(8)
+ external Array<Uint8> a0;
+}
+{% endprettify %}
+
### non_sync_factory
_Factory bodies can't use 'async', 'async*', or 'sync*'._
@@ -10720,6 +11856,165 @@
If the member can't be removed, then remove the annotation.
+### packed_annotation
+
+_Structs must have at most one 'Packed' annotation._
+
+#### Description
+
+The analyzer produces this diagnostic when a subclass of `Struct` has more
+than one `Packed` annotation.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the class `C`, which
+is a subclass of `Struct`, has two `Packed` annotations:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+@Packed(1)
+[!@Packed(1)!]
+class C extends Struct {
+ external Pointer<Uint8> notEmpty;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Remove all but one of the annotations:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+@Packed(1)
+class C extends Struct {
+ external Pointer<Uint8> notEmpty;
+}
+{% endprettify %}
+
+### packed_annotation_alignment
+
+_Only packing to 1, 2, 4, 8, and 16 bytes is supported._
+
+#### Description
+
+The analyzer produces this diagnostic when the argument to the `Packed`
+annotation isn't one of the allowed values: 1, 2, 4, 8, or 16.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the argument to the
+`Packed` annotation (`3`) isn't one of the allowed values:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+@Packed([!3!])
+class C extends Struct {
+ external Pointer<Uint8> notEmpty;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Change the alignment to be one of the allowed values:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+@Packed(4)
+class C extends Struct {
+ external Pointer<Uint8> notEmpty;
+}
+{% endprettify %}
+
+### packed_nesting_non_packed
+
+_Nesting the non-packed or less tightly packed struct '{0}' in a packed struct
+'{1}' isn't supported._
+
+#### Description
+
+The analyzer produces this diagnostic when a subclass of `Struct` that is
+annotated as being `Packed` declares a field whose type is also a subclass
+of `Struct` and the field's type is either not packed or is packed less
+tightly.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the class `Outer`,
+which is a subclass of `Struct` and is packed on 1-byte boundaries,
+declared a field whose type (`Inner`) is packed on 8-byte boundaries:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+@Packed(8)
+class Inner extends Struct {
+ external Pointer<Uint8> notEmpty;
+}
+
+@Packed(1)
+class Outer extends Struct {
+ external Pointer<Uint8> notEmpty;
+
+ external [!Inner!] nestedLooselyPacked;
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the inner struct should be packed more tightly, then change the
+argument to the inner struct's `Packed` annotation:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+@Packed(1)
+class Inner extends Struct {
+ external Pointer<Uint8> notEmpty;
+}
+
+@Packed(1)
+class Outer extends Struct {
+ external Pointer<Uint8> notEmpty;
+
+ external Inner nestedLooselyPacked;
+}
+{% endprettify %}
+
+If the outer struct should be packed less tightly, then change the
+argument to the outer struct's `Packed` annotation:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+@Packed(8)
+class Inner extends Struct {
+ external Pointer<Uint8> notEmpty;
+}
+
+@Packed(8)
+class Outer extends Struct {
+ external Pointer<Uint8> notEmpty;
+
+ external Inner nestedLooselyPacked;
+}
+{% endprettify %}
+
+If the inner struct doesn't have an annotation and should be packed, then
+add an annotation.
+
+If the inner struct doesn't have an annotation and the outer struct
+shouldn't be packed, then remove its annotation.
+
### part_of_different_library
_Expected this library to be part of '{0}', not '{1}'._
@@ -12561,6 +13856,58 @@
var y = convert.json.encode(x.min(0, 1));
{% endprettify %}
+### size_annotation_dimensions
+
+_'Array's must have an 'Array' annotation that matches the dimensions._
+
+#### Description
+
+The analyzer produces this diagnostic when the number of dimensions
+specified in an `Array` annotation doesn't match the number of nested
+arrays specified by the type of a field.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the field `a0` has a
+type with three nested arrays, but only two dimensions are given in the
+`Array` annotation:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ [!@Array(8, 8)!]
+ external Array<Array<Array<Uint8>>> a0;
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the type of the field is correct, then fix the annotation to have the
+required number of dimensions:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Array(8, 8, 4)
+ external Array<Array<Array<Uint8>>> a0;
+}
+{% endprettify %}
+
+If the type of the field is wrong, then fix the type of the field:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Array(8, 8)
+ external Array<Array<Uint8>> a0;
+}
+{% endprettify %}
+
### static_access_to_instance_member
_Instance member '{0}' can't be accessed using static access._
@@ -12724,6 +14071,55 @@
class B {}
{% endprettify %}
+### subtype_of_ffi_class
+
+_The class '{0}' can't extend '{1}'._
+
+_The class '{0}' can't implement '{1}'._
+
+_The class '{0}' can't mix in '{1}'._
+
+#### Description
+
+The analyzer produces this diagnostic when a class extends any FFI class
+other than `Struct` or `Union`, or implements or mixes in any FFI class.
+`Struct` and `Union` are the only FFI classes that can be subtyped, and
+then only by extending them.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the class `C` extends
+`Double`:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends [!Double!] {}
+{% endprettify %}
+
+#### Common fixes
+
+If the class should extend either `Struct` or `Union`, then change the
+declaration of the class:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class C extends Struct {
+ @Int32()
+ external int i;
+}
+{% endprettify %}
+
+If the class shouldn't extend either `Struct` or `Union`, then remove any
+references to FFI classes:
+
+{% prettify dart tag=pre+code %}
+class C {}
+{% endprettify %}
+
### subtype_of_sealed_class
_The class '{0}' shouldn't be extended, mixed in, or implemented because it's
@@ -12775,6 +14171,62 @@
the sealed class so that it's no longer sealed or move the subclass into
the same package as the sealed class.
+### subtype_of_struct_class
+
+_The class '{0}' can't extend '{1}' because '{1}' is a subtype of 'Struct',
+'Union', or 'AbiSpecificInteger'._
+
+_The class '{0}' can't implement '{1}' because '{1}' is a subtype of 'Struct',
+'Union', or 'AbiSpecificInteger'._
+
+_The class '{0}' can't mix in '{1}' because '{1}' is a subtype of 'Struct',
+'Union', or 'AbiSpecificInteger'._
+
+#### Description
+
+The analyzer produces this diagnostic when a class extends, implements, or
+mixes in a class that extends either `Struct` or `Union`. Classes can only
+extend either `Struct` or `Union` directly.
+
+For more information about FFI, see [C interop using dart:ffi][].
+
+#### Example
+
+The following code produces this diagnostic because the class `C` extends
+`S`, and `S` extends `Struct`:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class S extends Struct {
+ external Pointer f;
+}
+
+class C extends [!S!] {
+ external Pointer g;
+}
+{% endprettify %}
+
+#### Common fixes
+
+If you're trying to define a struct or union that shares some fields
+declared by a different struct or union, then extend `Struct` or `Union`
+directly and copy the shared fields:
+
+{% prettify dart tag=pre+code %}
+import 'dart:ffi';
+
+class S extends Struct {
+ external Pointer f;
+}
+
+class C extends Struct {
+ external Pointer f;
+
+ external Pointer g;
+}
+{% endprettify %}
+
### supertype_expands_to_type_parameter
_A type alias that expands to a type parameter can't be implemented._
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 1f0baa6..9e8ab9a 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -4129,10 +4129,22 @@
}
}
if (FLAG_verify_acquired_data) {
- if (external) {
- ASSERT(!T->heap()->Contains(reinterpret_cast<uword>(data_tmp)));
- } else {
- ASSERT(T->heap()->Contains(reinterpret_cast<uword>(data_tmp)));
+ {
+ NoSafepointScope no_safepoint(T);
+ bool sweep_in_progress;
+ {
+ PageSpace* old_space = T->heap()->old_space();
+ MonitorLocker ml(old_space->tasks_lock());
+ sweep_in_progress = (old_space->phase() == PageSpace::kSweepingLarge) ||
+ (old_space->phase() == PageSpace::kSweepingRegular);
+ }
+ if (!sweep_in_progress) {
+ if (external) {
+ ASSERT(!T->heap()->Contains(reinterpret_cast<uword>(data_tmp)));
+ } else {
+ ASSERT(T->heap()->Contains(reinterpret_cast<uword>(data_tmp)));
+ }
+ }
}
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
WeakTable* table = I->group()->api_state()->acquired_table();
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 39b1603..476ad6b 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -1247,16 +1247,39 @@
bool has_reservation = MarkReservation();
+ {
+ // Move pages to sweeper work lists.
+ MutexLocker ml(&pages_lock_);
+ ASSERT(sweep_large_ == nullptr);
+ sweep_large_ = large_pages_;
+ large_pages_ = large_pages_tail_ = nullptr;
+ ASSERT(sweep_regular_ == nullptr);
+ if (!compact) {
+ sweep_regular_ = pages_;
+ pages_ = pages_tail_ = nullptr;
+ }
+ }
+
+ bool can_verify;
if (compact) {
SweepLarge();
Compact(thread);
set_phase(kDone);
+ can_verify = true;
} else if (FLAG_concurrent_sweep && has_reservation) {
ConcurrentSweep(isolate_group);
+ can_verify = false;
} else {
SweepLarge();
- Sweep();
+ Sweep(/*exclusive*/ true);
set_phase(kDone);
+ can_verify = true;
+ }
+
+ if (FLAG_verify_after_gc && can_verify) {
+ OS::PrintErr("Verifying after sweeping...");
+ heap_->VerifyGC(kForbidMarked);
+ OS::PrintErr(" done.\n");
}
TryReserveForOOM();
@@ -1294,65 +1317,82 @@
TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "SweepLarge");
GCSweeper sweeper;
- OldPage* prev_page = nullptr;
- OldPage* page = large_pages_;
- while (page != nullptr) {
- OldPage* next_page = page->next();
- const intptr_t words_to_end = sweeper.SweepLargePage(page);
+ MutexLocker ml(&pages_lock_);
+ while (sweep_large_ != nullptr) {
+ OldPage* page = sweep_large_;
+ sweep_large_ = page->next();
+ page->set_next(nullptr);
+ ASSERT(page->type() == OldPage::kData);
+
+ ml.Unlock();
+ intptr_t words_to_end = sweeper.SweepLargePage(page);
+ intptr_t size;
if (words_to_end == 0) {
- FreeLargePage(page, prev_page);
+ size = page->memory_->size();
+ page->Deallocate();
} else {
TruncateLargePage(page, words_to_end << kWordSizeLog2);
- prev_page = page;
}
- // Advance to the next page.
- page = next_page;
+ ml.Lock();
+
+ if (words_to_end == 0) {
+ IncreaseCapacityInWordsLocked(-(size >> kWordSizeLog2));
+ } else {
+ AddLargePageLocked(page);
+ }
}
}
-void PageSpace::Sweep() {
+void PageSpace::Sweep(bool exclusive) {
TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "Sweep");
GCSweeper sweeper;
intptr_t shard = 0;
const intptr_t num_shards = Utils::Maximum(FLAG_scavenger_tasks, 1);
- for (intptr_t i = 0; i < num_shards; i++) {
- DataFreeList(i)->mutex()->Lock();
- }
-
- OldPage* prev_page = nullptr;
- OldPage* page = pages_;
- while (page != nullptr) {
- OldPage* next_page = page->next();
- ASSERT(page->type() == OldPage::kData);
- shard = (shard + 1) % num_shards;
- bool page_in_use =
- sweeper.SweepPage(page, DataFreeList(shard), true /*is_locked*/);
- if (page_in_use) {
- prev_page = page;
- } else {
- FreePage(page, prev_page);
+ if (exclusive) {
+ for (intptr_t i = 0; i < num_shards; i++) {
+ DataFreeList(i)->mutex()->Lock();
}
- // Advance to the next page.
- page = next_page;
}
- for (intptr_t i = 0; i < num_shards; i++) {
- DataFreeList(i)->mutex()->Unlock();
+ MutexLocker ml(&pages_lock_);
+ while (sweep_regular_ != nullptr) {
+ OldPage* page = sweep_regular_;
+ sweep_regular_ = page->next();
+ page->set_next(nullptr);
+ ASSERT(page->type() == OldPage::kData);
+
+ ml.Unlock();
+ // Cycle through the shards round-robin so that free space is roughly
+ // evenly distributed among the freelists and so roughly evenly available
+ // to each scavenger worker.
+ shard = (shard + 1) % num_shards;
+ bool page_in_use = sweeper.SweepPage(page, DataFreeList(shard), exclusive);
+ intptr_t size;
+ if (!page_in_use) {
+ size = page->memory_->size();
+ page->Deallocate();
+ }
+ ml.Lock();
+
+ if (page_in_use) {
+ AddPageLocked(page);
+ } else {
+ IncreaseCapacityInWordsLocked(-(size >> kWordSizeLog2));
+ }
}
- if (FLAG_verify_after_gc) {
- OS::PrintErr("Verifying after sweeping...");
- heap_->VerifyGC(kForbidMarked);
- OS::PrintErr(" done.\n");
+ if (exclusive) {
+ for (intptr_t i = 0; i < num_shards; i++) {
+ DataFreeList(i)->mutex()->Unlock();
+ }
}
}
void PageSpace::ConcurrentSweep(IsolateGroup* isolate_group) {
// Start the concurrent sweeper task now.
- GCSweeper::SweepConcurrent(isolate_group, pages_, pages_tail_, large_pages_,
- large_pages_tail_, &freelists_[OldPage::kData]);
+ GCSweeper::SweepConcurrent(isolate_group);
}
void PageSpace::Compact(Thread* thread) {
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index b8e209b..11a4cc2 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -576,7 +576,7 @@
int64_t pre_wait_for_sweepers,
int64_t pre_safe_point);
void SweepLarge();
- void Sweep();
+ void Sweep(bool exclusive);
void ConcurrentSweep(IsolateGroup* isolate_group);
void Compact(Thread* thread);
@@ -614,6 +614,8 @@
OldPage* large_pages_ = nullptr;
OldPage* large_pages_tail_ = nullptr;
OldPage* image_pages_ = nullptr;
+ OldPage* sweep_regular_ = nullptr;
+ OldPage* sweep_large_ = nullptr;
// Various sizes being tracked for this generation.
intptr_t max_capacity_in_words_;
diff --git a/runtime/vm/heap/sweeper.cc b/runtime/vm/heap/sweeper.cc
index d814521..11900bb 100644
--- a/runtime/vm/heap/sweeper.cc
+++ b/runtime/vm/heap/sweeper.cc
@@ -109,127 +109,54 @@
class ConcurrentSweeperTask : public ThreadPool::Task {
public:
- ConcurrentSweeperTask(IsolateGroup* isolate_group,
- PageSpace* old_space,
- OldPage* first,
- OldPage* last,
- OldPage* large_first,
- OldPage* large_last)
- : task_isolate_group_(isolate_group),
- old_space_(old_space),
- first_(first),
- last_(last),
- large_first_(large_first),
- large_last_(large_last) {
- ASSERT(task_isolate_group_ != NULL);
- ASSERT(first_ != NULL);
- ASSERT(old_space_ != NULL);
- ASSERT(last_ != NULL);
- MonitorLocker ml(old_space_->tasks_lock());
- old_space_->set_tasks(old_space_->tasks() + 1);
- old_space_->set_phase(PageSpace::kSweepingLarge);
+ explicit ConcurrentSweeperTask(IsolateGroup* isolate_group)
+ : isolate_group_(isolate_group) {
+ ASSERT(isolate_group != nullptr);
+ PageSpace* old_space = isolate_group->heap()->old_space();
+ MonitorLocker ml(old_space->tasks_lock());
+ old_space->set_tasks(old_space->tasks() + 1);
+ old_space->set_phase(PageSpace::kSweepingLarge);
}
virtual void Run() {
bool result = Thread::EnterIsolateGroupAsHelper(
- task_isolate_group_, Thread::kSweeperTask, /*bypass_safepoint=*/true);
+ isolate_group_, Thread::kSweeperTask, /*bypass_safepoint=*/true);
ASSERT(result);
+ PageSpace* old_space = isolate_group_->heap()->old_space();
{
Thread* thread = Thread::Current();
ASSERT(thread->BypassSafepoints()); // Or we should be checking in.
TIMELINE_FUNCTION_GC_DURATION(thread, "ConcurrentSweep");
- GCSweeper sweeper;
- OldPage* page = large_first_;
- OldPage* prev_page = NULL;
- while (page != NULL) {
- OldPage* next_page;
- if (page == large_last_) {
- // Don't access page->next(), which would be a race with mutator
- // allocating new pages.
- next_page = NULL;
- } else {
- next_page = page->next();
- }
- ASSERT(page->type() == OldPage::kData);
- const intptr_t words_to_end = sweeper.SweepLargePage(page);
- if (words_to_end == 0) {
- old_space_->FreeLargePage(page, prev_page);
- } else {
- old_space_->TruncateLargePage(page, words_to_end << kWordSizeLog2);
- prev_page = page;
- }
- page = next_page;
- }
+ old_space->SweepLarge();
{
- MonitorLocker ml(old_space_->tasks_lock());
- ASSERT(old_space_->phase() == PageSpace::kSweepingLarge);
- old_space_->set_phase(PageSpace::kSweepingRegular);
+ MonitorLocker ml(old_space->tasks_lock());
+ ASSERT(old_space->phase() == PageSpace::kSweepingLarge);
+ old_space->set_phase(PageSpace::kSweepingRegular);
ml.NotifyAll();
}
- intptr_t shard = 0;
- const intptr_t num_shards = Utils::Maximum(FLAG_scavenger_tasks, 1);
- page = first_;
- prev_page = NULL;
- while (page != NULL) {
- OldPage* next_page;
- if (page == last_) {
- // Don't access page->next(), which would be a race with mutator
- // allocating new pages.
- next_page = NULL;
- } else {
- next_page = page->next();
- }
- ASSERT(page->type() == OldPage::kData);
- shard = (shard + 1) % num_shards;
- bool page_in_use =
- sweeper.SweepPage(page, old_space_->DataFreeList(shard), false);
- if (page_in_use) {
- prev_page = page;
- } else {
- old_space_->FreePage(page, prev_page);
- }
- {
- // Notify the mutator thread that we have added elements to the free
- // list or that more capacity is available.
- MonitorLocker ml(old_space_->tasks_lock());
- ml.Notify();
- }
- page = next_page;
- }
+ old_space->Sweep(/*exclusive*/ false);
}
// Exit isolate cleanly *before* notifying it, to avoid shutdown race.
Thread::ExitIsolateGroupAsHelper(/*bypass_safepoint=*/true);
// This sweeper task is done. Notify the original isolate.
{
- MonitorLocker ml(old_space_->tasks_lock());
- old_space_->set_tasks(old_space_->tasks() - 1);
- ASSERT(old_space_->phase() == PageSpace::kSweepingRegular);
- old_space_->set_phase(PageSpace::kDone);
+ MonitorLocker ml(old_space->tasks_lock());
+ old_space->set_tasks(old_space->tasks() - 1);
+ ASSERT(old_space->phase() == PageSpace::kSweepingRegular);
+ old_space->set_phase(PageSpace::kDone);
ml.NotifyAll();
}
}
private:
- IsolateGroup* task_isolate_group_;
- PageSpace* old_space_;
- OldPage* first_;
- OldPage* last_;
- OldPage* large_first_;
- OldPage* large_last_;
+ IsolateGroup* isolate_group_;
};
-void GCSweeper::SweepConcurrent(IsolateGroup* isolate_group,
- OldPage* first,
- OldPage* last,
- OldPage* large_first,
- OldPage* large_last,
- FreeList* freelist) {
- bool result = Dart::thread_pool()->Run<ConcurrentSweeperTask>(
- isolate_group, isolate_group->heap()->old_space(), first, last,
- large_first, large_last);
+void GCSweeper::SweepConcurrent(IsolateGroup* isolate_group) {
+ bool result = Dart::thread_pool()->Run<ConcurrentSweeperTask>(isolate_group);
ASSERT(result);
}
diff --git a/runtime/vm/heap/sweeper.h b/runtime/vm/heap/sweeper.h
index ca9b6c4..8b781d4 100644
--- a/runtime/vm/heap/sweeper.h
+++ b/runtime/vm/heap/sweeper.h
@@ -34,13 +34,8 @@
// last marked object.
intptr_t SweepLargePage(OldPage* page);
- // Sweep the regular sized data pages between first and last inclusive.
- static void SweepConcurrent(IsolateGroup* isolate_group,
- OldPage* first,
- OldPage* last,
- OldPage* large_first,
- OldPage* large_last,
- FreeList* freelist);
+ // Sweep the large and regular sized data pages.
+ static void SweepConcurrent(IsolateGroup* isolate_group);
};
} // namespace dart
diff --git a/tools/VERSION b/tools/VERSION
index 97705ad..3a2798d 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 17
PATCH 0
-PRERELEASE 53
+PRERELEASE 54
PRERELEASE_PATCH 0
\ No newline at end of file