blob: f3b6b1753c5c9839ce0654852816f939eb734b4f [file]
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(AddressOfTest);
defineReflectiveTests(DefaultAssetTest);
defineReflectiveTests(FfiNativeTest);
defineReflectiveTests(NativeFieldTest);
defineReflectiveTests(NativeTest);
});
}
@reflectiveTest
class AddressOfTest extends PubPackageResolutionTest {
test_invalid_Lambda() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
void main() => print(Native.addressOf(() => 3));
// ^^^^^^^
// [diag.argumentMustBeNative] Argument to 'Native.addressOf' must be annotated with @Native
''');
}
test_invalid_MismatchedInferredType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external Pointer<IntPtr> global;
void main() => print(Native.addressOf<Pointer<Double>>(global));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.mustBeASubtype] The type 'Pointer<IntPtr>' must be a subtype of 'Pointer<Double>' for 'Native.addressOf'.
''');
}
test_invalid_MismatchingType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function()>()
external void foo();
void main() {
print(Native.addressOf<NativeFunction<Int8 Function()>>(foo));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.mustBeASubtype] The type 'Void Function()' must be a subtype of 'Int8 Function()' for 'Native.addressOf'.
}
''');
}
test_invalid_MissingType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function()>()
external void foo();
void main() {
print(Native.addressOf(foo));
// ^^^^^^^^^^^^^^^^^^^^^
// [diag.mustBeANativeFunctionType] The type 'NativeType' given to 'Native.addressOf' must be a valid 'dart:ffi' native function type.
}
''');
}
test_invalid_MissingType2() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external void foo();
void main() {
print(Native.addressOf(foo));
// ^^^^^^^^^^^^^^^^^^^^^
// [diag.mustBeANativeFunctionType] The type 'NativeType' given to 'Native.addressOf' must be a valid 'dart:ffi' native function type.
}
''');
}
test_invalid_MissingType3() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external Pointer<IntPtr> global;
void main() => print(Native.addressOf(global));
// ^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.mustBeASubtype] The type 'Pointer<IntPtr>' must be a subtype of 'NativeType' for 'Native.addressOf'.
''');
}
test_invalid_NotAConstant() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function()>()
external void foo();
@Native<Void Function()>()
external void bar();
void entry(bool condition) {
print(Native.addressOf(condition ? foo : bar));
// ^^^^^^^^^^^^^^^^^^^^^
// [diag.argumentMustBeNative] Argument to 'Native.addressOf' must be annotated with @Native
}
''');
}
test_invalid_NotAPreciseType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function()>()
external void foo();
void main() => print(Native.addressOf<NativeFunction>(foo));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.mustBeASubtype] The type 'Void Function()' must be a subtype of 'Function' for 'Native.addressOf'.
''');
}
test_invalid_NotAPreciseType2() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external void foo();
void main() => print(Native.addressOf<NativeFunction>(foo));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.mustBeASubtype] The type 'Void Function()' must be a subtype of 'Function' for 'Native.addressOf'.
''');
}
test_invalid_String() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
void main() => print(Native.addressOf('malloc'));
// ^^^^^^^^
// [diag.argumentMustBeNative] Argument to 'Native.addressOf' must be annotated with @Native
''');
}
test_valid() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function()>()
external void foo();
@Native()
external void foo2();
@Native()
external Pointer<IntPtr> global;
void main() {
print(Native.addressOf<NativeFunction<Void Function()>>(foo));
print(Native.addressOf<NativeFunction<Void Function()>>(foo2));
print(Native.addressOf<Pointer<IntPtr>>(global));
}
''');
}
}
@reflectiveTest
class DefaultAssetTest extends PubPackageResolutionTest {
test_invalid_duplicate() async {
await resolveTestCodeWithDiagnostics(r'''
@DefaultAsset('foo')
@DefaultAsset('bar')
// [diag.ffiNativeInvalidDuplicateDefaultAsset][column 2][length 12] There may be at most one @DefaultAsset annotation on a library.
library;
import 'dart:ffi';
''');
}
test_invalid_duplicateFromConst() async {
await resolveTestCodeWithDiagnostics(r'''
@DefaultAsset('bar')
@defaults
// [diag.ffiNativeInvalidDuplicateDefaultAsset][column 2][length 8] There may be at most one @DefaultAsset annotation on a library.
library;
import 'dart:ffi';
const defaults = DefaultAsset('foo');
''');
}
test_valid() async {
await resolveTestCodeWithDiagnostics(r'''
@DefaultAsset('bar')
library;
import 'dart:ffi';
@Native<Void Function()>()
external void foo();
''');
}
test_validFromConst() async {
await resolveTestCodeWithDiagnostics(r'''
@defaults
library;
import 'dart:ffi';
const defaults = DefaultAsset('foo');
@Native<Void Function()>()
external void foo();
''');
}
}
@reflectiveTest
class FfiNativeTest extends PubPackageResolutionTest {
test_annotation_FfiNative_getters() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
base class NativeFieldWrapperClass1 {}
base class Paragraph extends NativeFieldWrapperClass1 {
@Native<Double Function(Pointer<Void>)>(symbol: 'Paragraph::ideographicBaseline', isLeaf: true)
external double get ideographicBaseline;
@Native<Void Function(Pointer<Void>, Double)>(symbol: 'Paragraph::ideographicBaseline', isLeaf: true)
external set ideographicBaseline(double d);
}
''');
}
test_annotation_FfiNative_noArguments() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native
// [diag.noAnnotationConstructorArguments][column 1][length 7] Annotation creation must have arguments.
external int foo();
''');
}
test_annotation_FfiNative_noTypeArguments() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external int foo();
// ^^^
// [diag.nativeFunctionMissingType] The native type of this function couldn't be inferred so it must be specified in the annotation.
''');
}
test_FfiNativeCanUseHandles() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Handle Function(Handle)>(symbol: 'DoesntMatter')
external Object doesntMatter(Object);
''');
}
test_FfiNativeCanUseLeaf() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Int8 Function(Int64)>(symbol: 'DoesntMatter', isLeaf:true)
external int doesntMatter(int x);
''');
}
test_FfiNativeInstanceMethodsMustHaveReceiver() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
class K {
@Native<Void Function(Double)>(symbol: 'DoesntMatter')
external void doesntMatter(double x);
// ^^^^^^^^^^^^
// [diag.ffiNativeUnexpectedNumberOfParametersWithReceiver] Unexpected number of Native annotation parameters. Expected 2 but has 1. Native instance method annotation must have receiver as first argument.
}
''');
}
test_FfiNativeLeafMustNotReturnHandle() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Handle Function()>(symbol: 'DoesntMatter', isLeaf:true)
external Object doesntMatter();
// ^^^^^^^^^^^^
// [diag.leafCallMustNotReturnHandle] FFI leaf call can't return a 'Handle'.
''');
}
test_FfiNativeLeafMustNotTakeHandles() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function(Handle)>(symbol: 'DoesntMatter', isLeaf:true)
external void doesntMatter(Object o);
// ^^^^^^^^^^^^
// [diag.leafCallMustNotTakeHandle] FFI leaf call can't take arguments of type 'Handle'.
''');
}
test_FfiNativeNonFfiParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<IntPtr Function(int)>(symbol: 'doesntmatter')
external int nonFfiParameter(int v);
// ^^^^^^^^^^^^^^^
// [diag.mustBeANativeFunctionType] The type 'IntPtr Function(int)' given to 'Native' must be a valid 'dart:ffi' native function type.
''');
}
test_FfiNativeNonFfiReturnType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<double Function(IntPtr)>(symbol: 'doesntmatter')
external double nonFfiReturnType(int v);
// ^^^^^^^^^^^^^^^^
// [diag.mustBeANativeFunctionType] The type 'double Function(IntPtr)' given to 'Native' must be a valid 'dart:ffi' native function type.
''');
}
test_FfiNativeOnExtension_valid() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
extension on int {
@Native<Bool Function(Int64, Int64)>(symbol: 'x')
external bool f(int m);
}
void g() {
0.f(0);
}
''');
}
test_FfiNativeOnExtension_wrongNumberOfParameters() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
extension on int {
@Native<Bool Function(Int64)>(symbol: 'x')
external bool f(int m);
// ^
// [diag.ffiNativeUnexpectedNumberOfParameters] Unexpected number of Native annotation parameters. Expected 2 but has 1.
}
void g() {
0.f(0);
}
''');
}
test_FfiNativeOnExtension_wrongReceiverType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
extension on double {
@Native<Bool Function(Int64, Int64)>(symbol: 'Dart_PostInteger')
external bool postInteger(int message);
// ^^^^^^^^^^^
// [diag.mustBeASubtype] The type 'Bool Function(Int64, Int64)' must be a subtype of 'bool Function(double, int)' for 'Native'.
}
void f() {
0.0.postInteger(0);
}
''');
}
test_FfiNativeOnExtensionType_wrongReceiverType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
extension type NativeSendPort(int id) {
@Native<Bool Function(Int64, Int64)>(symbol: 'Dart_PostInteger')
external bool postInteger(int message);
// ^^^^^^^^^^^
// [diag.mustBeASubtype] The type 'Bool Function(Int64, Int64)' must be a subtype of 'bool Function(NativeSendPort, int)' for 'Native'.
}
''');
}
test_FfiNativeOnExtensionType_wrongRepresentationType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
extension type InvalidNativeSendPort._(double id) {
@Native<Bool Function(Int64, Int64)>(symbol: 'Dart_PostInteger')
external bool postInteger(int message);
// ^^^^^^^^^^^
// [diag.mustBeASubtype] The type 'Bool Function(Int64, Int64)' must be a subtype of 'bool Function(InvalidNativeSendPort, int)' for 'Native'.
}
''');
}
test_FfiNativePointerParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function(Pointer)>(symbol: 'free')
external void posixFree(Pointer pointer);
''');
}
test_FfiNativeTooFewParameters() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function(Double)>(symbol: 'DoesntMatter')
external void doesntMatter(double x, double y);
// ^^^^^^^^^^^^
// [diag.ffiNativeUnexpectedNumberOfParameters] Unexpected number of Native annotation parameters. Expected 1 but has 2.
''');
}
test_FfiNativeTooManyParameters() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function(Double, Double)>(symbol: 'DoesntMatter')
external void doesntMatter(double x);
// ^^^^^^^^^^^^
// [diag.ffiNativeUnexpectedNumberOfParameters] Unexpected number of Native annotation parameters. Expected 2 but has 1.
''');
}
test_FfiNativeVoidReturn() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Handle Function(Uint32, Uint32, Handle)>(symbol: 'doesntmatter')
external void voidReturn(int width, int height, Object outImage);
// ^^^^^^^^^^
// [diag.mustBeASubtype] The type 'Handle Function(Uint32, Uint32, Handle)' must be a subtype of 'void Function(int, int, Object)' for 'Native'.
''');
}
test_FfiNativeWrongFfiParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<IntPtr Function(Double)>(symbol: 'doesntmatter')
external int wrongFfiParameter(int v);
// ^^^^^^^^^^^^^^^^^
// [diag.mustBeASubtype] The type 'IntPtr Function(Double)' must be a subtype of 'int Function(int)' for 'Native'.
''');
}
test_FfiNativeWrongFfiReturnType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<IntPtr Function(IntPtr)>(symbol: 'doesntmatter')
external double wrongFfiReturnType(int v);
// ^^^^^^^^^^^^^^^^^^
// [diag.mustBeASubtype] The type 'IntPtr Function(IntPtr)' must be a subtype of 'double Function(int)' for 'Native'.
''');
}
}
@reflectiveTest
class NativeFieldTest extends PubPackageResolutionTest {
test_AbiSpecific() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Int>()
external int foo;
''');
}
test_Accessors() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<IntPtr>()
external int get foo;
@Native<IntPtr>()
external set foo(int value);
''');
}
test_Array_InvalidDimension() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
@Array(0)
// ^
// [diag.nonPositiveArrayDimension] Array dimensions must be positive numbers.
external Array<IntPtr> field;
''');
}
test_Array_InvalidDimensionCount() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
@Array(10, 20)
// [diag.sizeAnnotationDimensions][column 1][length 14] 'Array's must have an 'Array' annotation that matches the dimensions.
external Array<IntPtr> field;
''');
}
test_Array_MissingAnnotation() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external Array<IntPtr> field;
// ^^^^^
// [diag.missingSizeAnnotationCarray] Fields of type 'Array' must have exactly one 'Array' annotation.
''');
}
test_Array_Valid() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
@Array(12)
external Array<IntPtr> field0;
@Array(10, 20)
@Native()
external Array<Array<IntPtr>> field1;
''');
}
test_Infer() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
final class MyStruct extends Struct {
external Pointer<MyStruct> next;
}
@Native()
external MyStruct first;
@Native()
external Pointer<MyStruct> last;
''');
}
test_InvalidFunctionType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<IntPtr Function(IntPtr)>()
external int field;
// ^^^^^
// [diag.nativeFieldInvalidType] 'IntPtr Function(IntPtr)' is an unsupported type for native fields. Native fields only support pointers, arrays or numeric and compound types.
''');
}
test_InvalidInstanceMember() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
class Foo {
@Native<IntPtr>()
external int field;
// ^^^^^
// [diag.nativeFieldNotStatic] Native fields must be static.
}
''');
}
test_InvalidNotExternal() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<IntPtr>()
int field;
// ^^^^^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'field' must be initialized.
// [diag.ffiNativeMustBeExternal] Native functions must be declared external.
''');
}
test_MismatchingFunctionType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<NativeFunction<Double Function()>>()
external int Function() field;
// ^^^^^
// [diag.mustBeASubtype] The type 'int Function()' must be a subtype of 'NativeFunction<Double Function()>' for 'Native'.
''');
}
test_MismatchingType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Double>()
external int field;
// ^^^^^
// [diag.mustBeASubtype] The type 'int' must be a subtype of 'Double' for 'Native'.
''');
}
test_MissingType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external int invalid;
// ^^^^^^^
// [diag.nativeFieldMissingType] The native type of this field could not be inferred and must be specified in the annotation.
@Native()
external Pointer<IntPtr> valid;
''');
}
test_Unsupported_Function() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<NativeFunction<Void Function()>>()
external void Function() field;
// ^^^^^
// [diag.nativeFieldInvalidType] 'NativeFunction<Void Function()>' is an unsupported type for native fields. Native fields only support pointers, arrays or numeric and compound types.
''');
}
test_Unsupported_Handle() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Handle>()
external Object field;
// ^^^^^
// [diag.nativeFieldInvalidType] 'Handle' is an unsupported type for native fields. Native fields only support pointers, arrays or numeric and compound types.
''');
}
}
@reflectiveTest
class NativeTest extends PubPackageResolutionTest {
test_annotation_InvalidFieldType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<IntPtr>()
external int foo();
// ^^^
// [diag.mustBeANativeFunctionType] The type 'IntPtr' given to 'Native' must be a valid 'dart:ffi' native function type.
''');
}
test_annotation_MissingType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external int foo();
// ^^^
// [diag.nativeFunctionMissingType] The native type of this function couldn't be inferred so it must be specified in the annotation.
''');
}
test_annotation_MissingTypeConst() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
const a = Native();
@a
external int foo();
// ^^^
// [diag.nativeFunctionMissingType] The native type of this function couldn't be inferred so it must be specified in the annotation.
''');
}
test_annotation_Native_getters() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
base class NativeFieldWrapperClass1 {}
base class Paragraph extends NativeFieldWrapperClass1 {
@Native<Double Function(Pointer<Void>)>(isLeaf: true)
external double get ideographicBaseline;
@Native<Void Function(Pointer<Void>, Double)>(isLeaf: true)
external set ideographicBaseline(double d);
}
''');
}
test_annotation_Native_noArguments() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native
// [diag.noAnnotationConstructorArguments][column 1][length 7] Annotation creation must have arguments.
external int foo();
''');
}
test_InferPointerReturnNoParameters() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external Pointer foo();
''');
}
test_InferPointerReturnPointerParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external Pointer foo(Pointer x);
''');
}
test_InferPointerReturnStructParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external Pointer foo(MyStruct x);
final class MyStruct extends Struct {
@Int8()
external int value;
}
''');
}
test_InferPointerReturnUnionParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external Pointer foo(MyUnion x);
final class MyUnion extends Union {
@Int8()
external int a;
@Int8()
external int b;
}
''');
}
test_InferStructReturnNoParameters() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external MyStruct foo();
final class MyStruct extends Struct {
@Int8()
external int value;
}
''');
}
test_InferStructReturnPointerParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external MyStruct foo(Pointer x);
final class MyStruct extends Struct {
@Int8()
external int value;
}
''');
}
test_InferStructReturnStructParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external MyStruct foo(MyStruct x);
final class MyStruct extends Struct {
@Int8()
external int value;
}
''');
}
test_InferStructReturnUnionParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external MyStruct foo(MyUnion x);
final class MyStruct extends Struct {
@Int8()
external int value;
}
final class MyUnion extends Union {
@Int8()
external int a;
@Int8()
external int b;
}
''');
}
test_InferUnionReturnNoParameters() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external MyUnion foo();
final class MyUnion extends Union {
@Int8()
external int a;
@Int8()
external int b;
}
''');
}
test_InferUnionReturnPointerParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external MyUnion foo(Pointer x);
final class MyUnion extends Union {
@Int8()
external int a;
@Int8()
external int b;
}
''');
}
test_InferUnionReturnStructParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external MyUnion foo(MyStruct x);
final class MyStruct extends Struct {
@Int8()
external int value;
}
final class MyUnion extends Union {
@Int8()
external int a;
@Int8()
external int b;
}
''');
}
test_InferUnionReturnUnionParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external MyUnion foo(MyUnion x);
final class MyUnion extends Union {
@Int8()
external int a;
@Int8()
external int b;
}
''');
}
test_InferVoidReturnNoParameters() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external void foo();
''');
}
test_InferVoidReturnPointerParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external void foo(Pointer x);
''');
}
test_InferVoidReturnStructParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external void foo(MyStruct x);
final class MyStruct extends Struct {
@Int8()
external int value;
}
''');
}
test_InferVoidReturnUnionParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native()
external void foo(MyUnion x);
final class MyUnion extends Union {
@Int8()
external int a;
@Int8()
external int b;
}
''');
}
test_NativeCanUseHandles() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Handle Function(Handle)>()
external Object doesntMatter(Object);
''');
}
test_NativeCanUseLeaf() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Int8 Function(Int64)>(isLeaf:true)
external int doesntMatter(int x);
''');
}
test_NativeDuplicateAnnotation() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Int32 Function(Int32)>()
@Native<Int32 Function(Int32)>(isLeaf: true)
// [diag.ffiNativeInvalidMultipleAnnotations][column 2][length 6] Native functions and fields must have exactly one `@Native` annotation.
external int foo(int v);
''');
}
test_NativeDuplicateAnnotationConst() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
const duplicate = Native<Int32 Function(Int32)>(isLeaf: true);
@Native<Int32 Function(Int32)>()
@duplicate
// [diag.ffiNativeInvalidMultipleAnnotations][column 2][length 9] Native functions and fields must have exactly one `@Native` annotation.
external int foo(int v);
''');
}
test_NativeFromConst() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
const annotation = Native<Int32 Function(Int32)>();
@annotation
external int wrongFfiReturnType(int v);
''');
}
test_NativeInstanceMethodsMustHaveReceiver() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
class K {
@Native<Void Function(Double)>()
external void doesntMatter(double x);
// ^^^^^^^^^^^^
// [diag.ffiNativeUnexpectedNumberOfParametersWithReceiver] Unexpected number of Native annotation parameters. Expected 2 but has 1. Native instance method annotation must have receiver as first argument.
}
''');
}
test_NativeLeafMustNotReturnHandle() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Handle Function()>(isLeaf:true)
external Object doesntMatter();
// ^^^^^^^^^^^^
// [diag.leafCallMustNotReturnHandle] FFI leaf call can't return a 'Handle'.
''');
}
test_NativeLeafMustNotReturnHandleConst() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
const annotation = Native<Handle Function()>(isLeaf:true);
@annotation
external Object doesntMatter();
// ^^^^^^^^^^^^
// [diag.leafCallMustNotReturnHandle] FFI leaf call can't return a 'Handle'.
''');
}
test_NativeLeafMustNotTakeHandles() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function(Handle)>(symbol: 'DoesntMatter', isLeaf:true)
external void doesntMatter(Object o);
// ^^^^^^^^^^^^
// [diag.leafCallMustNotTakeHandle] FFI leaf call can't take arguments of type 'Handle'.
''');
}
test_NativeLeafMustNotTakeHandlesConst() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
const annotation = Native<Void Function(Handle)>(symbol: 'DoesntMatter', isLeaf:true);
@annotation
external void doesntMatter(Object o);
// ^^^^^^^^^^^^
// [diag.leafCallMustNotTakeHandle] FFI leaf call can't take arguments of type 'Handle'.
''');
}
test_NativeNonFfiParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<IntPtr Function(int)>()
external int nonFfiParameter(int v);
// ^^^^^^^^^^^^^^^
// [diag.mustBeANativeFunctionType] The type 'IntPtr Function(int)' given to 'Native' must be a valid 'dart:ffi' native function type.
''');
}
test_NativeNonFfiReturnType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<double Function(IntPtr)>()
external double nonFfiReturnType(int v);
// ^^^^^^^^^^^^^^^^
// [diag.mustBeANativeFunctionType] The type 'double Function(IntPtr)' given to 'Native' must be a valid 'dart:ffi' native function type.
''');
}
test_NativePointerParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function(Pointer)>()
external void free(Pointer pointer);
''');
}
test_NativeTooFewParameters() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function(Double)>()
external void doesntMatter(double x, double y);
// ^^^^^^^^^^^^
// [diag.ffiNativeUnexpectedNumberOfParameters] Unexpected number of Native annotation parameters. Expected 1 but has 2.
''');
}
test_NativeTooManyParameters() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Void Function(Double, Double)>()
external void doesntMatter(double x);
// ^^^^^^^^^^^^
// [diag.ffiNativeUnexpectedNumberOfParameters] Unexpected number of Native annotation parameters. Expected 2 but has 1.
''');
}
test_NativeVarArgs() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Int8 Function(Int64, VarArgs<(Int32, Double)>)>()
external int doesntMatter(int x, int y, double z);
''');
}
test_NativeVarArgsTooFew() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Int8 Function(Int64, VarArgs<(Int32, Double)>)>()
external int doesntMatter(int x, int y);
// ^^^^^^^^^^^^
// [diag.ffiNativeUnexpectedNumberOfParameters] Unexpected number of Native annotation parameters. Expected 3 but has 2.
''');
}
test_NativeVarArgsTooMany() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Int8 Function(Int64, VarArgs<(Int32, Double)>)>()
external int doesntMatter(int x, int y, double z, int superfluous);
// ^^^^^^^^^^^^
// [diag.ffiNativeUnexpectedNumberOfParameters] Unexpected number of Native annotation parameters. Expected 3 but has 4.
''');
}
test_NativeVoidReturn() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<Handle Function(Uint32, Uint32, Handle)>()
external void voidReturn(int width, int height, Object outImage);
// ^^^^^^^^^^
// [diag.mustBeASubtype] The type 'Handle Function(Uint32, Uint32, Handle)' must be a subtype of 'void Function(int, int, Object)' for 'Native'.
''');
}
test_NativeWrongFfiParameter() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<IntPtr Function(Double)>()
external int wrongFfiParameter(int v);
// ^^^^^^^^^^^^^^^^^
// [diag.mustBeASubtype] The type 'IntPtr Function(Double)' must be a subtype of 'int Function(int)' for 'Native'.
''');
}
test_NativeWrongFfiReturnType() async {
await resolveTestCodeWithDiagnostics(r'''
import 'dart:ffi';
@Native<IntPtr Function(IntPtr)>()
external double wrongFfiReturnType(int v);
// ^^^^^^^^^^^^^^^^^^
// [diag.mustBeASubtype] The type 'IntPtr Function(IntPtr)' must be a subtype of 'double Function(int)' for 'Native'.
''');
}
}