[analyzer/ffi] Fix analyzer crash

TEST=tests/ffi/static_checks/regress_62716_test.dart

Fixes: https://github.com/dart-lang/sdk/issues/62716
Change-Id: I8abc006cd1e7274089ea618c970aacd0bc2267e4
Cq-Include-Trybots: luci.dart.try:analyzer-linux-release-try,analyzer-mac-release-try,analyzer-win-release-try,front-end-linux-release-x64-try,front-end-nnbd-linux-release-x64-try,front-end-nnbd-mac-release-x64-try,front-end-nnbd-win-release-x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/483241
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Auto-Submit: Daco Harkes <dacoharkes@google.com>
This commit is contained in:
Daco Harkes
2026-02-24 05:01:40 -08:00
committed by Commit Queue
parent 33e6df1fe9
commit 8852aa5c19
2 changed files with 50 additions and 2 deletions
@@ -674,8 +674,13 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
// Receiver can only be Pointer if the class extends
// NativeFieldWrapperClass1.
if (ffiSignature.normalParameterTypes[0].isPointer) {
var cls = declarationElement.enclosingElement as InterfaceElement;
if (!_extendsNativeFieldWrapperClass1(cls.thisType)) {
var enclosingElement = declarationElement.enclosingElement;
var receiverType = switch (enclosingElement) {
InterfaceElement() => enclosingElement.thisType,
ExtensionElement(extendedType: InterfaceType type) => type,
_ => null,
};
if (!_extendsNativeFieldWrapperClass1(receiverType)) {
_diagnosticReporter.report(
diag.ffiNativeOnlyClassesExtendingNativefieldwrapperclass1CanBePointer
.at(errorToken),
@@ -0,0 +1,43 @@
// Copyright (c) 2026, 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.
// Regression test for https://github.com/dart-lang/sdk/issues/62716
import 'dart:ffi';
import 'dart:nativewrappers';
extension on int {
@Native<Void Function(Pointer<Void>)>(symbol: 'x')
// [error column 4]
// [cfe] Only classes extending NativeFieldWrapperClass1 can be passed as Pointer.
external void x();
// ^
// [analyzer] COMPILE_TIME_ERROR.FFI_NATIVE_ONLY_CLASSES_EXTENDING_NATIVEFIELDWRAPPERCLASS1_CAN_BE_POINTER
}
extension on dynamic {
@Native<Void Function(Pointer<Void>)>(symbol: 'z')
external void z();
// ^
// [analyzer] COMPILE_TIME_ERROR.FFI_NATIVE_ONLY_CLASSES_EXTENDING_NATIVEFIELDWRAPPERCLASS1_CAN_BE_POINTER
// [cfe] Expected type 'void Function(dynamic)' to be 'void Function(Pointer<Void>)', which is the Dart type corresponding to 'NativeFunction<Void Function(Pointer<Void>)>'.
}
extension on void Function() {
@Native<Void Function(Pointer<Void>)>(symbol: 'f')
external void f();
// ^
// [analyzer] COMPILE_TIME_ERROR.FFI_NATIVE_ONLY_CLASSES_EXTENDING_NATIVEFIELDWRAPPERCLASS1_CAN_BE_POINTER
// [cfe] Expected type 'void Function(void Function())' to be 'void Function(Pointer<Void>)', which is the Dart type corresponding to 'NativeFunction<Void Function(Pointer<Void>)>'.
@Native<Void Function(Handle)>(symbol: 'f2')
external void f2();
}
extension on NativeFieldWrapperClass1 {
@Native<Void Function(Pointer<Void>)>(symbol: 'y')
external void y();
}
void main() {}