[analyzer/ffi] Fix Unwrap typed data error messages

Fixes issues reported by:

TEST=pkg/analyzer/test/verify_diagnostics_test.dart

* Fixes error messages on asFunction.
* Fixes validation by introducing Uint8List to mock sdk.
* Removes unused typed_data import in example snippet.
* Fixes error locations in example snippets

Bug: https://github.com/dart-lang/sdk/issues/44589
Change-Id: I82261eea5e55cbafa686865a92131a449a7642f5
Cq-Include-Trybots: luci.dart.try:pkg-linux-debug-try,pkg-linux-release-try,pkg-mac-release-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340921
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Daco Harkes 2023-12-12 14:32:57 +00:00 committed by Commit Queue
parent d548c07996
commit 069e617ef4
5 changed files with 151 additions and 6 deletions

View file

@ -910,7 +910,7 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
}
_validateFfiTypedDataUnwrapping(
F,
T,
TPrime,
errorNode,
isLeaf: isLeaf,
isCall: true,
@ -1086,6 +1086,11 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
int i = 0;
final nativeParamTypes = nativeType.normalParameterTypes.flattenVarArgs();
for (final dartParam in dartType.normalParameterTypes) {
if (i >= nativeParamTypes.length) {
// Cascading error as not the same amount of arguments.
// Already results in an error earlier.
return;
}
final nativeParam = nativeParamTypes[i];
i++;
if (dartParam.isTypedData && nativeParam.isPointer) {

View file

@ -1378,6 +1378,10 @@ final MockSdkLibrary _LIB_TYPED_DATA = MockSdkLibrary(
'''
library dart.typed_data;
abstract final class Uint8List {
external factory Uint8List(int length);
}
abstract final class Int8List {
external factory Int8List(int length);
}

View file

@ -19859,7 +19859,7 @@ FfiCode:
import 'dart:typed_data';
void f(Pointer<NativeFunction<Void Function(Pointer<Uint8>)>> p) {
[!p.asFunction<void Function(Uint8List)>()!];
p.asFunction<[!void Function(Uint8List)!]>();
}
```
@ -19905,7 +19905,7 @@ FfiCode:
import 'dart:typed_data';
void f(Pointer<NativeFunction<Pointer<Uint8> Function()>> p) {
[!p.asFunction<Uint8List Function()>()!];
p.asFunction<[!Uint8List Function()!]>();
}
```
@ -19915,7 +19915,6 @@ FfiCode:
```dart
import 'dart:ffi';
import 'dart:typed_data';
void f(Pointer<NativeFunction<Pointer<Uint8> Function()>> p) {
p.asFunction<Pointer<Uint8> Function()>();
@ -19949,7 +19948,7 @@ FfiCode:
void f(Uint8List i) {}
void g() {
Pointer.fromFunction<Void Function(Pointer<Uint8>)>(f);
Pointer.fromFunction<Void Function(Pointer<Uint8>)>([!f!]);
}
```
@ -19959,7 +19958,6 @@ FfiCode:
```dart
import 'dart:ffi';
import 'dart:typed_data';
void f(Pointer<Uint8> i) {}

View file

@ -1918,6 +1918,90 @@ extension [!mixin!] on int {}
Choose a different name for the declaration.
### callback_must_not_use_typed_data
_FFI callbacks can't take typed data arguments or return value._
#### Description
The analyzer produces this diagnostic when an invocation of
`Pointer.fromFunction`, one of`NativeCallable`'s constructors has a
typed data argument or return value."
Typed data unwrapping is only supported on arguments for leaf FFI calls.
For more information about FFI, see [C interop using dart:ffi][ffi].
#### Example
The following code produces this diagnostic because the parameter type
of `g` is a typed data.
{% prettify dart tag=pre+code %}
import 'dart:ffi';
import 'dart:typed_data';
void f(Uint8List i) {}
void g() {
Pointer.fromFunction<Void Function(Pointer<Uint8>)>([!f!]);
}
{% endprettify %}
#### Common fixes
Use the `Pointer` type instead:
{% prettify dart tag=pre+code %}
import 'dart:ffi';
void f(Pointer<Uint8> i) {}
void g() {
Pointer.fromFunction<Void Function(Pointer<Uint8>)>(f);
}
{% endprettify %}
### call_must_not_return_typed_data
_FFI calls can't return typed data._
#### Description
The analyzer produces this diagnostic when the return type of
`Pointer.asFunction`, `DynamicLibrary.lookupFunction`, or
`@Native` is a typed data.
Typed data unwrapping is only supported on arguments for leaf FFI calls.
For more information about FFI, see [C interop using dart:ffi][ffi].
#### Example
The following code produces this diagnostic because the dart function
signature contains a typed data, but the `isLeaf` argument is `false`:
{% prettify dart tag=pre+code %}
import 'dart:ffi';
import 'dart:typed_data';
void f(Pointer<NativeFunction<Pointer<Uint8> Function()>> p) {
p.asFunction<[!Uint8List Function()!]>();
}
{% endprettify %}
#### Common fixes
Use the `Pointer` type instead:
{% prettify dart tag=pre+code %}
import 'dart:ffi';
void f(Pointer<NativeFunction<Pointer<Uint8> Function()>> p) {
p.asFunction<Pointer<Uint8> Function()>();
}
{% endprettify %}
### case_block_not_terminated
_The last statement of the 'case' should be 'break', 'continue', 'rethrow',
@ -15167,6 +15251,52 @@ class A {
class B implements A {}
{% endprettify %}
### non_leaf_call_must_not_take_typed_data
_FFI non-leaf calls can't take typed data arguments._
#### Description
The analyzer produces this diagnostic when the value of the `isLeaf`
argument of `Pointer.asFunction`, `DynamicLibrary.lookupFunction`, or
`@Native` is `false` and the Dart function signature contains a typed
data parameter.
Typed data unwrapping is only supported on arguments for leaf FFI calls.
For more information about FFI, see [C interop using dart:ffi][ffi].
#### Example
The following code produces this diagnostic because the dart function
signature contains a typed data, but the `isLeaf` argument is `false`:
{% prettify dart tag=pre+code %}
import 'dart:ffi';
import 'dart:typed_data';
void f(Pointer<NativeFunction<Void Function(Pointer<Uint8>)>> p) {
p.asFunction<[!void Function(Uint8List)!]>();
}
{% endprettify %}
#### Common fixes
If the function has at least one typed data parameter, then add
the `isLeaf` argument:
{% prettify dart tag=pre+code %}
import 'dart:ffi';
import 'dart:typed_data';
void f(Pointer<NativeFunction<Void Function(Pointer<Uint8>)>> p) {
p.asFunction<void Function(Uint8List)>(isLeaf: true);
}
{% endprettify %}
If the function also uses `Handle`s, then it must be non-leaf. In That
case use `Pointer`s instead of typed data.
### non_native_function_type_argument_to_pointer
_Can't invoke 'asFunction' because the function signature '{0}' for the pointer

View file

@ -90,4 +90,12 @@ void g2() {
// [analyzer] COMPILE_TIME_ERROR.CALLBACK_MUST_NOT_USE_TYPED_DATA
}
void foo1(Pointer<NativeFunction<Pointer<Uint8> Function()>> p) {
p.asFunction<Uint8List Function()>(isLeaf: true);
//^
// [cfe] FFI calls can't return typed data.
// ^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CALL_MUST_NOT_RETURN_TYPED_DATA
}
// TODO(https://dartbug.com/54181): Write negative tests for @Natives.