[analyzer] Consider VarArgs in @Native check

Methods and functions annotated with `@FfiNative` and `@Native` are
validated to ensure their Dart signature matches the one from the
annotation.
For those functions, the lengths of the parameters is compared two
times: In `_validateCompatibleFunctionTypes` and in `_checkFfiNative`,
with the latter being responsible for emitting a more-specific error
message. However, it fails to consider that a single `VarArg` reference
in the native function type would get expanded to multiple formals in
Dart. This fixes the problem by properly expanding variadic types in
`_checkFfiNative` as well.

Closes https://github.com/dart-lang/sdk/issues/53680

Bug: 53680
Change-Id: Ifb93eba8ac9f39697dc415dc337110109449e366
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/329360
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Simon Binder 2023-10-04 01:35:38 +00:00 committed by Commit Queue
parent a46ac84206
commit 1aa8232308
2 changed files with 34 additions and 5 deletions

View file

@ -338,7 +338,8 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
FfiCode.FFI_NATIVE_MUST_BE_EXTERNAL, errorNode);
}
var ffiParameterTypes = ffiSignature.normalParameterTypes;
var ffiParameterTypes =
ffiSignature.normalParameterTypes.flattenVarArgs();
var ffiParameters = ffiSignature.parameters;
if ((declarationElement is MethodElement ||
@ -346,11 +347,11 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
!declarationElement.isStatic) {
// Instance methods must have the receiver as an extra parameter in the
// FfiNative annotation.
if (formalParameters.length + 1 != ffiSignature.parameters.length) {
if (formalParameters.length + 1 != ffiParameterTypes.length) {
_errorReporter.reportErrorForNode(
FfiCode.FFI_NATIVE_UNEXPECTED_NUMBER_OF_PARAMETERS_WITH_RECEIVER,
errorNode,
[formalParameters.length + 1, ffiSignature.parameters.length]);
[formalParameters.length + 1, ffiParameterTypes.length]);
return;
}
@ -371,11 +372,11 @@ class FfiVerifier extends RecursiveAstVisitor<void> {
} else {
// Number of parameters in the FfiNative annotation must match the
// annotated declaration.
if (formalParameters.length != ffiSignature.parameters.length) {
if (formalParameters.length != ffiParameterTypes.length) {
_errorReporter.reportErrorForNode(
FfiCode.FFI_NATIVE_UNEXPECTED_NUMBER_OF_PARAMETERS,
errorNode,
[ffiSignature.parameters.length, formalParameters.length]);
[ffiParameterTypes.length, formalParameters.length]);
return;
}
}

View file

@ -313,6 +313,34 @@ external void doesntMatter(double x);
]);
}
test_NativeVarArgs() async {
await assertNoErrorsInCode(r'''
import 'dart:ffi';
@Native<Int8 Function(Int64, VarArgs<(Int32, Double)>)>()
external int doesntMatter(int x, int y, double z);
''');
}
test_NativeVarArgsTooFew() async {
await assertErrorsInCode(r'''
import 'dart:ffi';
@Native<Int8 Function(Int64, VarArgs<(Int32, Double)>)>()
external int doesntMatter(int x, int y);
''', [
error(FfiCode.FFI_NATIVE_UNEXPECTED_NUMBER_OF_PARAMETERS, 19, 98),
]);
}
test_NativeVarArgsTooMany() async {
await assertErrorsInCode(r'''
import 'dart:ffi';
@Native<Int8 Function(Int64, VarArgs<(Int32, Double)>)>()
external int doesntMatter(int x, int y, double z, int superfluous);
''', [
error(FfiCode.FFI_NATIVE_UNEXPECTED_NUMBER_OF_PARAMETERS, 19, 125),
]);
}
test_NativeVoidReturn() async {
await assertErrorsInCode(r'''
import 'dart:ffi';