Skip to content

Commit 7397c1e

Browse files
dcharkesCommit Queue
authored andcommitted
[ffi/anayzer] Docs error messages
Change-Id: I790ebffb2f2b868fcea85703e25cbe7a48bea2cd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/430181 Reviewed-by: Brian Wilkerson <[email protected]> Auto-Submit: Daco Harkes <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 3718baa commit 7397c1e

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

pkg/analyzer/lib/src/test_utilities/mock_sdk.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,11 @@ extension Int8ListAddress on Int8List {
10781078
extension ArrayAddress<T extends NativeType> on Array<T> {
10791079
external Pointer<T> get address;
10801080
}
1081+
1082+
@Since('3.5')
1083+
extension Uint8ListAddress on Uint8List {
1084+
external Pointer<Uint8> get address;
1085+
}
10811086
'''),
10821087
]);
10831088

pkg/analyzer/messages.yaml

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18951,11 +18951,127 @@ FfiCode:
1895118951
problemMessage: "The '.address' expression can only be used as argument to a leaf native external call."
1895218952
hasPublishedDocs: false
1895318953
comment: No parameters.
18954+
documentation: |-
18955+
#### Description
18956+
18957+
The analyzer produces this diagnostic when the `.address` getter is used
18958+
in a context other than as an argument to a native external call that is
18959+
marked as a leaf call (`isLeaf: true`).
18960+
18961+
#### Example
18962+
18963+
The following code produces this diagnostic because `.address` is used
18964+
incorrectly:
18965+
18966+
```dart
18967+
import 'dart:ffi';
18968+
import 'dart:typed_data';
18969+
18970+
@Native<Void Function(Pointer<Uint8>)>()
18971+
external void nonLeafCall(Pointer<Uint8> ptr);
18972+
18973+
void main() {
18974+
final data = Uint8List(10);
18975+
18976+
// Incorrect: Using '.address' as an argument to a non-leaf call.
18977+
nonLeafCall(data.[!address!]);
18978+
}
18979+
```
18980+
18981+
#### Common fixes
18982+
18983+
Ensure that the `.address` expression is used directly as an argument to a
18984+
native external call that is annotated with `@Native(...)` and has
18985+
`isLeaf: true` set in its annotation.
18986+
18987+
```dart
18988+
import 'dart:ffi';
18989+
import 'dart:typed_data';
18990+
18991+
@Native<Void Function(Pointer<Uint8>)>(isLeaf: true)
18992+
external void leafCall(Pointer<Uint8> ptr);
18993+
18994+
void main() {
18995+
final data = Uint8List(10);
18996+
18997+
// Correct: Using .address directly as an argument to a leaf call.
18998+
leafCall(data.address);
18999+
}
19000+
```
1895419001
ADDRESS_RECEIVER:
1895519002
problemMessage: "The receiver of '.address' must be a concrete 'TypedData', a concrete 'TypedData' '[]', an 'Array', an 'Array' '[]', a Struct field, or a Union field."
1895619003
correctionMessage: Change the receiver of '.address' to one of the allowed kinds.
1895719004
hasPublishedDocs: false
1895819005
comment: No parameters.
19006+
documentation: |-
19007+
#### Description
19008+
19009+
The analyzer produces this diagnostic when the `.address` getter is used
19010+
on a receiver whose static type isn't one of the allowed FFI types. The
19011+
`.address` getter is used to obtain a `Pointer` to the underlying memory
19012+
of an FFI data structure.
19013+
19014+
The receiver of `.address` must be one of the following:
19015+
- A concrete `TypedData` instance (e.g., `Uint8List`).
19016+
- An element of a concrete `TypedData` instance accessed via `[]`.
19017+
- An `Array<T>` instance (from `dart:ffi`).
19018+
- An element of an `Array<T>` instance accessed via `[]`.
19019+
- A field of a `Struct` or `Union` subclass, if that field's type is `Array<T>`, a nested `Struct`, or a nested `Union`.
19020+
- A `Struct` or `Union` instance.
19021+
19022+
#### Example
19023+
19024+
The following code produces this diagnostic for various incorrect receivers:
19025+
19026+
```dart
19027+
import 'dart:ffi';
19028+
19029+
final class MyStruct extends Struct {
19030+
@Uint8()
19031+
external int x;
19032+
19033+
@Uint8()
19034+
external int y;
19035+
}
19036+
19037+
@Native<Void Function(Pointer)>(isLeaf: true)
19038+
external void nativeLeafCall(Pointer ptr);
19039+
19040+
void main() {
19041+
final struct = Struct.create<MyStruct>();
19042+
final y = struct.y;
19043+
// Incorrect: The receiver is not a struct field, but some integer.
19044+
nativeLeafCall(y.[!address!]);
19045+
}
19046+
```
19047+
19048+
#### Common fixes
19049+
19050+
Ensure that the receiver of the `.address` getter is one of the allowed
19051+
types. The `.address` getter is for obtaining a `Pointer` to the memory
19052+
of `TypedData`, `Array`, `Struct`, or `Union` instances, or certain
19053+
fields/elements thereof.
19054+
19055+
```dart
19056+
import 'dart:ffi';
19057+
19058+
@Native<Void Function(Pointer)>(isLeaf: true)
19059+
external void nativeLeafCall(Pointer ptr);
19060+
19061+
final class MyStruct extends Struct {
19062+
@Uint8()
19063+
external int x;
19064+
19065+
@Uint8()
19066+
external int y;
19067+
}
19068+
19069+
void main() {
19070+
final struct = Struct.create<MyStruct>();
19071+
// Correct: The receiver is a struct field.
19072+
nativeLeafCall(struct.y.address);
19073+
}
19074+
```
1895919075
ANNOTATION_ON_POINTER_FIELD:
1896019076
problemMessage: "Fields in a struct class whose type is 'Pointer' shouldn't have any annotations."
1896119077
correctionMessage: Try removing the annotation.
@@ -19604,6 +19720,57 @@ FfiCode:
1960419720
correctionMessage: Pass as Handle instead.
1960519721
hasPublishedDocs: false
1960619722
comment: No parameters.
19723+
documentation: |-
19724+
#### Description
19725+
19726+
The analyzer produces this diagnostic when a function or method annotated
19727+
with `@Native` has a parameter in its FFI signature that is a `Pointer`,
19728+
but the corresponding Dart parameter type is a class instance that doesn't
19729+
extend `NativeFieldWrapperClass1` (or is a Pointer or TypedData).
19730+
19731+
#### Example
19732+
19733+
The following code produces this diagnostic because `MyService` doesn't
19734+
extend `NativeFieldWrapperClass1`, but the `@Native` signature for its
19735+
`process` method indicates the receiver should be passed as a `Pointer<Void>`:
19736+
19737+
```dart
19738+
import 'dart:ffi';
19739+
19740+
class MyService { // MyService does not extend NativeFieldWrapperClass1
19741+
@Native<Void Function(Pointer<Void>, Int8)>(symbol: 'MyService_process')
19742+
external void [!process!](int data);
19743+
}
19744+
```
19745+
19746+
#### Common fixes
19747+
19748+
1. **If the Dart class is intended to wrap a native object:**
19749+
Make the Dart class extend `NativeFieldWrapperClass1`. This is the
19750+
correct approach if the Dart class instance has a corresponding native
19751+
object whose pointer should be passed.
19752+
```dart
19753+
import 'dart:ffi';
19754+
19755+
class MyService extends NativeFieldWrapperClass1 {
19756+
@Native<Void Function(Pointer<Void>, Int8)>(symbol: 'MyService_process')
19757+
external void process(int data);
19758+
}
19759+
```
19760+
19761+
2. **If you intend to pass an opaque handle to the Dart object:**
19762+
Change the FFI signature in the `@Native` annotation to use `Handle`
19763+
instead of `Pointer` for the parameter. This allows passing a
19764+
reference to the Dart object itself, which native code can interact
19765+
with using the Dart C API.
19766+
```dart
19767+
import 'dart:ffi';
19768+
19769+
class MyService {
19770+
@Native<Void Function(Handle, Int8)>(symbol: 'MyService_process')
19771+
external void process(int data);
19772+
}
19773+
```
1960719774
FFI_NATIVE_UNEXPECTED_NUMBER_OF_PARAMETERS:
1960819775
problemMessage: Unexpected number of Native annotation parameters. Expected {0} but has {1}.
1960919776
correctionMessage: Make sure parameters match the function annotated.

0 commit comments

Comments
 (0)