Version 2.15.0-236.0.dev
Merge commit '93370cb8b6bdecf2e00170be477ad96c742a1d6a' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_comparison.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_comparison.dart
index d0d1f5f..b7e5f96 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/remove_comparison.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_comparison.dart
@@ -16,12 +16,10 @@
class RemoveComparison extends CorrectionProducer {
@override
- bool canBeAppliedInBulk;
+ bool get canBeAppliedInBulk => true;
@override
- bool canBeAppliedToFile;
-
- RemoveComparison(this.canBeAppliedInBulk, this.canBeAppliedToFile);
+ bool get canBeAppliedToFile => true;
@override
FixKind get fixKind => DartFixKind.REMOVE_COMPARISON;
@@ -122,10 +120,5 @@
}
/// Return an instance of this class. Used as a tear-off in `FixProcessor`.
- static RemoveComparison newInstance() => RemoveComparison(false, false);
-
- /// Return an instance of this class that can apply bulk and in-file fixes.
- /// Used as a tear-off in `FixProcessor`.
- static RemoveComparison newInstanceBulkFixable() =>
- RemoveComparison(true, true);
+ static RemoveComparison newInstance() => RemoveComparison();
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/use_effective_integer_division.dart b/pkg/analysis_server/lib/src/services/correction/dart/use_effective_integer_division.dart
index 5a0839d..56c4583 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/use_effective_integer_division.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/use_effective_integer_division.dart
@@ -12,9 +12,18 @@
class UseEffectiveIntegerDivision extends CorrectionProducer {
@override
+ bool get canBeAppliedInBulk => true;
+
+ @override
+ bool get canBeAppliedToFile => true;
+
+ @override
FixKind get fixKind => DartFixKind.USE_EFFECTIVE_INTEGER_DIVISION;
@override
+ FixKind get multiFixKind => DartFixKind.USE_EFFECTIVE_INTEGER_DIVISION_MULTI;
+
+ @override
Future<void> compute(ChangeBuilder builder) async {
for (var n in node.withParents) {
if (n is MethodInvocation) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/use_eq_eq_null.dart b/pkg/analysis_server/lib/src/services/correction/dart/use_eq_eq_null.dart
index ff863ed..075f326 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/use_eq_eq_null.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/use_eq_eq_null.dart
@@ -11,7 +11,7 @@
class UseEqEqNull extends CorrectionProducer {
@override
- bool get canBeAppliedInBulk => false;
+ bool get canBeAppliedInBulk => true;
@override
bool get canBeAppliedToFile => true;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/use_not_eq_null.dart b/pkg/analysis_server/lib/src/services/correction/dart/use_not_eq_null.dart
index 3ae6b45..e7f633c 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/use_not_eq_null.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/use_not_eq_null.dart
@@ -11,7 +11,7 @@
class UseNotEqNull extends CorrectionProducer {
@override
- bool get canBeAppliedInBulk => false;
+ bool get canBeAppliedInBulk => true;
@override
bool get canBeAppliedToFile => true;
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 7dd6fff..c0f4fbb 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -1386,6 +1386,11 @@
DartFixKindPriority.DEFAULT,
'Use effective integer division ~/',
);
+ static const USE_EFFECTIVE_INTEGER_DIVISION_MULTI = FixKind(
+ 'dart.fix.use.effectiveIntegerDivision.multi',
+ DartFixKindPriority.IN_FILE,
+ 'Use effective integer division ~/ everywhere in file',
+ );
static const USE_EQ_EQ_NULL = FixKind(
'dart.fix.use.eqEqNull',
DartFixKindPriority.DEFAULT,
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 3b5ed58..e6be85e 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -355,7 +355,7 @@
RemoveInitializer.newInstance,
],
LintNames.avoid_null_checks_in_equality_operators: [
- RemoveComparison.newInstanceBulkFixable,
+ RemoveComparison.newInstance,
],
LintNames.avoid_print: [
MakeConditionalOnDebugMode.newInstance,
diff --git a/pkg/analysis_server/test/src/services/correction/fix/use_effective_integer_division_test.dart b/pkg/analysis_server/test/src/services/correction/fix/use_effective_integer_division_test.dart
index d8a6c78..b8b788d 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/use_effective_integer_division_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/use_effective_integer_division_test.dart
@@ -11,10 +11,31 @@
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(UseEffectiveIntegerDivisionTest);
+ defineReflectiveTests(UseEffectiveIntegerDivisionMultiTest);
});
}
@reflectiveTest
+class UseEffectiveIntegerDivisionMultiTest extends BulkFixProcessorTest {
+ Future<void> test_singleFile() async {
+ await resolveTestCode('''
+main() {
+ var a = 5;
+ var b = 2;
+ print((a / ((a / b).toInt())).toInt());
+}
+''');
+ await assertHasFix('''
+main() {
+ var a = 5;
+ var b = 2;
+ print(a ~/ (a ~/ b));
+}
+''');
+ }
+}
+
+@reflectiveTest
class UseEffectiveIntegerDivisionTest extends FixProcessorTest {
@override
FixKind get kind => DartFixKind.USE_EFFECTIVE_INTEGER_DIVISION;
diff --git a/pkg/vm/lib/transformations/ffi/native.dart b/pkg/vm/lib/transformations/ffi/native.dart
index bf8a531..dd28967 100644
--- a/pkg/vm/lib/transformations/ffi/native.dart
+++ b/pkg/vm/lib/transformations/ffi/native.dart
@@ -99,24 +99,43 @@
// Replaces parameters with Pointer if:
// 1) they extend NativeFieldWrapperClass1, and
- // 2) the corresponding native parameter is Pointer.
- FunctionType _pointerizeFunctionType(
- FunctionType dartType, FunctionType nativeType) {
- final parameters = <DartType>[];
- for (var i = 0; i < dartType.positionalParameters.length; i++) {
- final parameter = dartType.positionalParameters[i];
- if (parameter is InterfaceType) {
- final nativeParameter = nativeType.positionalParameters[i];
- if (_extendsNativeFieldWrapperClass1(parameter) &&
- env.isSubtypeOf(nativeParameter, pointerVoidType,
- SubtypeCheckMode.ignoringNullabilities)) {
- parameters.add(pointerVoidType);
- continue;
- }
+ // 2) the corresponding FFI parameter is Pointer.
+ DartType _wrapArgumentType(
+ DartType dartParameterType, DartType ffiParameterType) {
+ if (dartParameterType is InterfaceType) {
+ if (_extendsNativeFieldWrapperClass1(dartParameterType) &&
+ env.isSubtypeOf(ffiParameterType, pointerVoidType,
+ SubtypeCheckMode.ignoringNullabilities)) {
+ return pointerVoidType;
}
- parameters.add(parameter);
}
- return FunctionType(parameters, dartType.returnType, dartType.nullability);
+ return dartParameterType;
+ }
+
+ // Replaces return type with Object if it is Handle.
+ DartType _wrapReturnType(DartType dartReturnType, DartType ffiReturnType) {
+ if (env.isSubtypeOf(
+ ffiReturnType,
+ handleClass.getThisType(coreTypes, Nullability.nonNullable),
+ SubtypeCheckMode.ignoringNullabilities)) {
+ return objectClass.getThisType(coreTypes, Nullability.nonNullable);
+ }
+ return dartReturnType;
+ }
+
+ // Compute synthetic FFI function type, accounting for Objects passed as
+ // Pointer, and Objects returned as Handles.
+ FunctionType _wrapFunctionType(
+ FunctionType dartFunctionType, FunctionType ffiFunctionType) {
+ return FunctionType(
+ [
+ for (var i = 0; i < dartFunctionType.positionalParameters.length; i++)
+ _wrapArgumentType(dartFunctionType.positionalParameters[i],
+ ffiFunctionType.positionalParameters[i]),
+ ],
+ _wrapReturnType(dartFunctionType.returnType, ffiFunctionType.returnType),
+ dartFunctionType.nullability,
+ );
}
// Create field holding the resolved native function pointer.
@@ -131,22 +150,15 @@
// .fromAddress(_ffi_resolver('..', 'DoXYZ', 1))
// .asFunction<int Function(Pointer<Void>)>(isLeaf:true);
Field _createResolvedFfiNativeField(
- InstanceConstant annotationConst,
String dartFunctionName,
- FunctionType dartType,
- FunctionType nativeType,
- TreeNode? parent,
- int fileOffset) {
- final nativeFunctionName = annotationConst
- .fieldValues[ffiNativeNameField.fieldReference] as StringConstant;
- final isLeaf = annotationConst
- .fieldValues[ffiNativeIsLeafField.fieldReference] as BoolConstant;
-
- // int Function(Pointer<Void>)
- final dartTypePointerized = _pointerizeFunctionType(dartType, nativeType);
-
+ StringConstant nativeFunctionName,
+ bool isLeaf,
+ FunctionType dartFunctionType,
+ FunctionType ffiFunctionType,
+ int fileOffset,
+ Uri fileUri) {
// Derive number of arguments from the native function signature.
- final numberNativeArgs = nativeType.positionalParameters.length;
+ final numberNativeArgs = ffiFunctionType.positionalParameters.length;
// _ffi_resolver('...', 'DoXYZ', 1)
final resolverInvocation = FunctionInvocation(
@@ -167,7 +179,8 @@
Arguments([
resolverInvocation
], types: [
- InterfaceType(nativeFunctionClass, Nullability.legacy, [nativeType])
+ InterfaceType(
+ nativeFunctionClass, Nullability.legacy, [ffiFunctionType])
]))
..fileOffset = fileOffset;
@@ -176,22 +189,15 @@
final asFunctionInvocation = StaticInvocation(
asFunctionMethod,
Arguments([fromAddressInvocation],
- types: [nativeType, dartTypePointerized],
- named: [NamedExpression('isLeaf', BoolLiteral(isLeaf.value))]))
+ types: [ffiFunctionType, dartFunctionType],
+ named: [NamedExpression('isLeaf', BoolLiteral(isLeaf))]))
..fileOffset = fileOffset;
- var fileUri = currentLibrary.fileUri;
- if (parent is Class) {
- fileUri = parent.fileUri;
- } else if (parent is Library) {
- fileUri = parent.fileUri;
- }
-
// static final _doXyz$FfiNative$Ptr = ...
final fieldName =
Name('_$dartFunctionName\$FfiNative\$Ptr', currentLibrary);
final functionPointerField = Field.immutable(fieldName,
- type: dartTypePointerized,
+ type: dartFunctionType,
initializer: asFunctionInvocation,
isStatic: true,
isFinal: true,
@@ -199,19 +205,45 @@
getterReference: currentLibraryIndex?.lookupGetterReference(fieldName))
..fileOffset = fileOffset;
- // Add field to the parent the FfiNative function belongs to.
- if (parent is Class) {
- parent.addField(functionPointerField);
- } else if (parent is Library) {
- parent.addField(functionPointerField);
- } else {
- throw 'Unexpected parent of @FfiNative function. '
- 'Expected Class or Library, but found ${parent}.';
- }
-
return functionPointerField;
}
+ // Whether a parameter of [dartParameterType], passed as [ffiParameterType],
+ // needs to be converted to Pointer.
+ bool _requiresPointerConversion(
+ DartType dartParameterType, DartType ffiParameterType) {
+ return (env.isSubtypeOf(ffiParameterType, pointerVoidType,
+ SubtypeCheckMode.ignoringNullabilities) &&
+ !env.isSubtypeOf(dartParameterType, pointerVoidType,
+ SubtypeCheckMode.ignoringNullabilities));
+ }
+
+ VariableDeclaration _declareTemporary(Expression initializer,
+ DartType dartParameterType, DartType ffiParameterType) {
+ final wrappedType =
+ (_requiresPointerConversion(dartParameterType, ffiParameterType)
+ ? nativeFieldWrapperClass1Type
+ : dartParameterType);
+ return VariableDeclaration(variableDeclarationTemporaryName,
+ initializer: initializer, type: wrappedType, isFinal: true);
+ }
+
+ Expression _getTemporary(VariableDeclaration temporary,
+ DartType dartParameterType, DartType ffiParameterType) {
+ if (_requiresPointerConversion(dartParameterType, ffiParameterType)) {
+ // Pointer.fromAddress(_getNativeField(#t0))
+ return StaticInvocation(
+ fromAddressInternal,
+ Arguments([
+ StaticInvocation(
+ getNativeFieldFunction, Arguments([VariableGet(temporary)]))
+ ], types: [
+ voidType
+ ]));
+ }
+ return VariableGet(temporary);
+ }
+
// FfiNative calls that pass objects extending NativeFieldWrapperClass1
// should be passed as Pointer instead so we don't have the overhead of
// converting Handles.
@@ -228,80 +260,51 @@
// final #t1 = passAsPointer(Pointer.fromAddress(_getNativeField(#t0)));
// reachabilityFence(#t0);
// } => #t1
- Expression _convertArgumentsNativeFieldWrapperClass1ToPointer(
- FunctionInvocation invocation,
- List<DartType> ffiParameters,
- List<VariableDeclaration> dartParameters) {
+ Expression _wrapArgumentsAndReturn(FunctionInvocation invocation,
+ FunctionType dartFunctionType, FunctionType ffiFunctionType) {
+ List<DartType> ffiParameters = ffiFunctionType.positionalParameters;
+ List<DartType> dartParameters = dartFunctionType.positionalParameters;
// Create lists of temporary variables for arguments potentially being
// wrapped, and the (potentially) wrapped arguments to be passed.
final temporariesForArguments = [];
final callArguments = <Expression>[];
final fencedArguments = [];
- bool hasPointer = false;
for (int i = 0; i < invocation.arguments.positional.length; i++) {
- if (env.isSubtypeOf(ffiParameters[i], pointerVoidType,
- SubtypeCheckMode.ignoringNullabilities) &&
- !env.isSubtypeOf(dartParameters[i].type, pointerVoidType,
- SubtypeCheckMode.ignoringNullabilities)) {
- // Only NativeFieldWrapperClass1 instances can be passed as pointer.
- if (!_extendsNativeFieldWrapperClass1(dartParameters[i].type)) {
- diagnosticReporter.report(
- messageFfiNativeOnlyNativeFieldWrapperClassCanBePointer,
- dartParameters[i].fileOffset,
- 1,
- invocation.location?.file);
- }
-
- hasPointer = true;
-
- // final NativeFieldWrapperClass1 #t0 = ClassWithNativeField();
- final argument = VariableDeclaration(variableDeclarationTemporaryName,
- initializer: invocation.arguments.positional[i],
- type: nativeFieldWrapperClass1Type,
- isFinal: true);
- temporariesForArguments.add(argument);
- fencedArguments.add(argument);
-
- // Pointer.fromAddress(_getNativeField(#t0))
- final ptr = StaticInvocation(
- fromAddressInternal,
- Arguments([
- StaticInvocation(
- getNativeFieldFunction, Arguments([VariableGet(argument)]))
- ], types: [
- voidType
- ]));
- callArguments.add(ptr);
-
- continue;
- }
+ final temporary = _declareTemporary(invocation.arguments.positional[i],
+ dartParameters[i], ffiParameters[i]);
// Note: We also evaluate, and assign temporaries for, non-wrapped
// arguments as we need to preserve the original evaluation order.
- final argument = VariableDeclaration(variableDeclarationTemporaryName,
- initializer: invocation.arguments.positional[i],
- type: dartParameters[i].type,
- isFinal: true);
- temporariesForArguments.add(argument);
- callArguments.add(VariableGet(argument));
+ temporariesForArguments.add(temporary);
+ callArguments
+ .add(_getTemporary(temporary, dartParameters[i], ffiParameters[i]));
+ if (_requiresPointerConversion(dartParameters[i], ffiParameters[i])) {
+ fencedArguments.add(temporary);
+ continue;
+ }
}
- // If there are no arguments to convert then we can drop the whole wrap.
- if (!hasPointer) {
- return invocation;
+ Expression resultInitializer = invocation;
+ if (env.isSubtypeOf(
+ ffiFunctionType.returnType,
+ handleClass.getThisType(coreTypes, Nullability.nonNullable),
+ SubtypeCheckMode.ignoringNullabilities)) {
+ resultInitializer = AsExpression(invocation, dartFunctionType.returnType);
}
+ // final T #t1 = foo(Pointer.fromAddress(_getNativeField(#t0)));
+ final result = VariableDeclaration(variableDeclarationTemporaryName,
+ initializer: resultInitializer,
+ type: dartFunctionType.returnType,
+ isFinal: true);
+
invocation.arguments = Arguments(callArguments);
// {
// final NativeFieldWrapperClass1 #t0 = ClassWithNativeField();
- // final T #t1 = foo(Pointer.fromAddress(_getNativeField(#t0)));
+ // .. #t1 ..
// reachabilityFence(#t0);
// } => #t1
- final result = VariableDeclaration(variableDeclarationTemporaryName,
- initializer: invocation,
- type: invocation.functionType!.returnType,
- isFinal: true);
- return BlockExpression(
+ final resultBlock = BlockExpression(
Block([
...temporariesForArguments,
result,
@@ -311,6 +314,125 @@
]),
VariableGet(result),
);
+
+ return resultBlock;
+ }
+
+ // Verify the Dart and FFI parameter types are compatible.
+ bool _verifyParameter(DartType dartParameterType, DartType ffiParameterType,
+ int annotationOffset, Uri? file) {
+ // Only NativeFieldWrapperClass1 instances can be passed as pointer.
+ if (_requiresPointerConversion(dartParameterType, ffiParameterType) &&
+ !_extendsNativeFieldWrapperClass1(dartParameterType)) {
+ diagnosticReporter.report(
+ messageFfiNativeOnlyNativeFieldWrapperClassCanBePointer,
+ annotationOffset,
+ 1,
+ file);
+ return false;
+ }
+ return true;
+ }
+
+ // Verify the signatures of the Dart function and the accompanying FfiNative
+ // annotation matches.
+ bool _verifySignatures(Procedure node, FunctionType dartFunctionType,
+ FunctionType ffiFunctionType, int annotationOffset) {
+ if (dartFunctionType.positionalParameters.length !=
+ ffiFunctionType.positionalParameters.length) {
+ final template = (node.isStatic
+ ? templateFfiNativeUnexpectedNumberOfParameters
+ : templateFfiNativeUnexpectedNumberOfParametersWithReceiver);
+ diagnosticReporter.report(
+ template.withArguments(dartFunctionType.positionalParameters.length,
+ ffiFunctionType.positionalParameters.length),
+ annotationOffset,
+ 1,
+ node.location?.file);
+ return false;
+ }
+
+ var validSignature = true;
+ for (var i = 0; i < dartFunctionType.positionalParameters.length; i++) {
+ final dartParameterType = dartFunctionType.positionalParameters[i];
+ if (dartParameterType is InterfaceType) {
+ if (!_verifyParameter(
+ dartParameterType,
+ ffiFunctionType.positionalParameters[i],
+ annotationOffset,
+ node.location?.file)) {
+ validSignature = false;
+ }
+ }
+ }
+
+ return validSignature;
+ }
+
+ Procedure _transformProcedure(
+ Procedure node,
+ StringConstant nativeFunctionName,
+ bool isLeaf,
+ int annotationOffset,
+ FunctionType dartFunctionType,
+ FunctionType ffiFunctionType,
+ List<Expression> argumentList) {
+ if (!_verifySignatures(
+ node, ffiFunctionType, dartFunctionType, annotationOffset)) {
+ return node;
+ }
+
+ // int Function(Pointer<Void>)
+ final wrappedDartFunctionType =
+ _wrapFunctionType(dartFunctionType, ffiFunctionType);
+
+ final parent = node.parent;
+
+ var fileUri = currentLibrary.fileUri;
+ if (parent is Class) {
+ fileUri = parent.fileUri;
+ } else if (parent is Library) {
+ fileUri = parent.fileUri;
+ }
+
+ // static final _myMethod$FfiNative$Ptr = ..
+ final resolvedField = _createResolvedFfiNativeField(
+ node.name.text,
+ nativeFunctionName,
+ isLeaf,
+ wrappedDartFunctionType,
+ ffiFunctionType,
+ node.fileOffset,
+ fileUri);
+
+ // Add field to the parent the FfiNative function belongs to.
+ if (parent is Class) {
+ parent.addField(resolvedField);
+ } else if (parent is Library) {
+ parent.addField(resolvedField);
+ } else {
+ throw 'Unexpected parent of @FfiNative function. '
+ 'Expected Class or Library, but found ${parent}.';
+ }
+
+ // _myFunction$FfiNative$Ptr(obj, x)
+ final functionPointerInvocation = FunctionInvocation(
+ FunctionAccessKind.FunctionType,
+ StaticGet(resolvedField),
+ Arguments(argumentList),
+ functionType: wrappedDartFunctionType)
+ ..fileOffset = node.fileOffset;
+
+ Expression result = (wrappedDartFunctionType == dartFunctionType
+ ? functionPointerInvocation
+ : _wrapArgumentsAndReturn(
+ functionPointerInvocation, dartFunctionType, ffiFunctionType));
+
+ // => _myFunction$FfiNative$Ptr(
+ // Pointer<Void>.fromAddress(_getNativeField(obj)), x)
+ node.function.body = ReturnStatement(result)..parent = node.function;
+
+ return node;
}
// Transform FfiNative instance methods.
@@ -327,84 +449,32 @@
// Pointer<Void>.fromAddress(_getNativeField(self)), x);
// int myMethod(int x) => _myMethod$FfiNative(this, x);
// }
+ //
+ // ... {
+ // static final _myMethod$FfiNative$Ptr = ...
+ // int myMethod(int x)
+ // => _myMethod$FfiNative$Ptr(
+ // Pointer<Void>.fromAddress(_getNativeField(this)), x);
+ // }
Procedure _transformInstanceMethod(
- Procedure node, InstanceConstant ffiConstant, int annotationOffset) {
- final ffiSignature = ffiConstant.typeArguments[0] as FunctionType;
+ Procedure node,
+ FunctionType ffiFunctionType,
+ StringConstant nativeFunctionName,
+ bool isLeaf,
+ int annotationOffset) {
+ final dartFunctionType = FunctionType([
+ (node.parent as Class).getThisType(coreTypes, Nullability.nonNullable),
+ for (final parameter in node.function.positionalParameters) parameter.type
+ ], node.function.returnType, Nullability.nonNullable);
- // The FfiNative annotation should have an extra parameter for `self`.
- if (node.function.positionalParameters.length + 1 !=
- ffiSignature.positionalParameters.length) {
- diagnosticReporter.report(
- templateFfiNativeUnexpectedNumberOfParametersWithReceiver
- .withArguments(node.function.positionalParameters.length + 1,
- ffiSignature.positionalParameters.length),
- annotationOffset,
- 1,
- node.location?.file);
- return node;
- }
-
- final cls = node.parent as Class;
-
- final staticParameters = [
- // Add the implicit `self` for the inner glue functions.
- VariableDeclaration('self',
- type: cls.getThisType(coreTypes, Nullability.nonNullable)),
+ final argumentList = [
+ ThisExpression(),
for (final parameter in node.function.positionalParameters)
- VariableDeclaration(parameter.name, type: parameter.type)
+ VariableGet(parameter)
];
- final staticFunctionType = FunctionType(
- staticParameters.map((e) => e.type).toList(),
- node.function.returnType,
- Nullability.nonNullable);
-
- // static final _myMethod$FfiNative$Ptr = ..
- final resolvedField = _createResolvedFfiNativeField(
- ffiConstant,
- node.name.text,
- staticFunctionType,
- ffiSignature,
- node.parent,
- node.fileOffset);
-
- // _myMethod$FfiNative$Ptr(self, x)
- final functionPointerInvocation = FunctionInvocation(
- FunctionAccessKind.FunctionType,
- StaticGet(resolvedField),
- Arguments(
- [for (final parameter in staticParameters) VariableGet(parameter)]),
- functionType: staticFunctionType)
- ..fileOffset = node.fileOffset;
-
- // static _myMethod$FfiNative(MyNativeClass self, int x)
- // => _myMethod$FfiNative$Ptr(
- // Pointer<Void>.fromAddress(_getNativeField(self)), x)
- final ffiProcedure = Procedure(
- Name('_${node.name.text}\$FfiNative', currentLibrary),
- ProcedureKind.Method,
- FunctionNode(
- ReturnStatement(_convertArgumentsNativeFieldWrapperClass1ToPointer(
- functionPointerInvocation,
- ffiSignature.positionalParameters,
- staticParameters)),
- positionalParameters: staticParameters),
- isStatic: true,
- fileUri: node.fileUri)
- ..fileOffset = node.fileOffset;
- cls.addProcedure(ffiProcedure);
-
- // => _myMethod$FfiNative(this, x)
- node.function.body = ReturnStatement(StaticInvocation(
- ffiProcedure,
- Arguments([
- ThisExpression(),
- for (var parameter in node.function.positionalParameters)
- VariableGet(parameter)
- ])))
- ..parent = node.function;
-
- return node;
+ return _transformProcedure(node, nativeFunctionName, isLeaf,
+ annotationOffset, dartFunctionType, ffiFunctionType, argumentList);
}
// Transform FfiNative static functions.
@@ -417,51 +487,21 @@
// => myFunction$FfiNative$Ptr(
// Pointer<Void>.fromAddress(_getNativeField(obj)), x);
Procedure _transformStaticFunction(
- Procedure node, InstanceConstant ffiConstant, int annotationOffset) {
- final ffiSignature = ffiConstant.typeArguments[0] as FunctionType;
+ Procedure node,
+ FunctionType ffiFunctionType,
+ StringConstant nativeFunctionName,
+ bool isLeaf,
+ int annotationOffset) {
+ final dartFunctionType =
+ node.function.computeThisFunctionType(Nullability.nonNullable);
- if (node.function.positionalParameters.length !=
- ffiSignature.positionalParameters.length) {
- diagnosticReporter.report(
- templateFfiNativeUnexpectedNumberOfParameters.withArguments(
- node.function.positionalParameters.length,
- ffiSignature.positionalParameters.length),
- annotationOffset,
- 1,
- node.location?.file);
- return node;
- }
+ final argumentList = [
+ for (final parameter in node.function.positionalParameters)
+ VariableGet(parameter)
+ ];
- // _myFunction$FfiNative$Ptr = ..
- final resolvedField = _createResolvedFfiNativeField(
- ffiConstant,
- node.name.text,
- node.function.computeThisFunctionType(Nullability.nonNullable),
- ffiSignature,
- node.parent,
- node.fileOffset);
-
- // _myFunction$FfiNative$Ptr(obj, x)
- final functionPointerInvocation = FunctionInvocation(
- FunctionAccessKind.FunctionType,
- StaticGet(resolvedField),
- Arguments([
- for (final parameter in node.function.positionalParameters)
- VariableGet(parameter)
- ]),
- functionType: resolvedField.type as FunctionType)
- ..fileOffset = node.fileOffset;
-
- // => _myFunction$FfiNative$Ptr(
- // Pointer<Void>.fromAddress(_getNativeField(obj)), x)
- node.function.body = ReturnStatement(
- _convertArgumentsNativeFieldWrapperClass1ToPointer(
- functionPointerInvocation,
- ffiSignature.positionalParameters,
- node.function.positionalParameters))
- ..parent = node.function;
-
- return node;
+ return _transformProcedure(node, nativeFunctionName, isLeaf,
+ annotationOffset, dartFunctionType, ffiFunctionType, argumentList);
}
@override
@@ -483,16 +523,20 @@
node.annotations.remove(ffiNativeAnnotation);
+ final ffiConstant = ffiNativeAnnotation.constant as InstanceConstant;
+ final ffiFunctionType = ffiConstant.typeArguments[0] as FunctionType;
+ final nativeFunctionName = ffiConstant
+ .fieldValues[ffiNativeNameField.fieldReference] as StringConstant;
+ final isLeaf = (ffiConstant.fieldValues[ffiNativeIsLeafField.fieldReference]
+ as BoolConstant)
+ .value;
+
if (!node.isStatic) {
- return _transformInstanceMethod(
- node,
- ffiNativeAnnotation.constant as InstanceConstant,
- ffiNativeAnnotation.fileOffset);
+ return _transformInstanceMethod(node, ffiFunctionType, nativeFunctionName,
+ isLeaf, ffiNativeAnnotation.fileOffset);
}
- return _transformStaticFunction(
- node,
- ffiNativeAnnotation.constant as InstanceConstant,
- ffiNativeAnnotation.fileOffset);
+ return _transformStaticFunction(node, ffiFunctionType, nativeFunctionName,
+ isLeaf, ffiNativeAnnotation.fileOffset);
}
}
diff --git a/pkg/vm/testcases/transformations/ffi/ffinative.dart b/pkg/vm/testcases/transformations/ffi/ffinative.dart
index c611214..347ba00 100644
--- a/pkg/vm/testcases/transformations/ffi/ffinative.dart
+++ b/pkg/vm/testcases/transformations/ffi/ffinative.dart
@@ -35,6 +35,12 @@
@FfiNative<Void Function(Pointer<Void>, Handle)>('doesntmatter')
external void goodHasReceiverPtrAndHandle(NativeClassy v);
+
+ @FfiNative<Handle Function(Pointer<Void>, Bool)>('doesntmatter')
+ external String? meh(bool blah);
+
+ @FfiNative<Bool Function(Pointer<Void>)>('doesntmatter')
+ external bool blah();
}
void main() {
@@ -46,4 +52,6 @@
NativeClassy().goodHasReceiverHandleAndPtr(NativeClassy());
NativeClassy().goodHasReceiverHandleAndHandle(NativeClassy());
NativeClassy().goodHasReceiverPtrAndHandle(NativeClassy());
+ NativeClassy().meh(true);
+ NativeClassy().blah();
}
diff --git a/pkg/vm/testcases/transformations/ffi/ffinative.dart.expect b/pkg/vm/testcases/transformations/ffi/ffinative.dart.expect
index eec7f88..557aa76 100644
--- a/pkg/vm/testcases/transformations/ffi/ffinative.dart.expect
+++ b/pkg/vm/testcases/transformations/ffi/ffinative.dart.expect
@@ -22,44 +22,49 @@
static final field (self::NativeClassy, ffi::Pointer<ffi::Void>) → void _goodHasReceiverHandleAndPtr$FfiNative$Ptr = ffi::_asFunctionInternal<(self::NativeClassy, ffi::Pointer<ffi::Void>) → void, (ffi::Handle*, ffi::Pointer<ffi::Void*>*) →* ffi::Void*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Handle*, ffi::Pointer<ffi::Void*>*) →* ffi::Void*>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
static final field (self::NativeClassy, self::NativeClassy) → void _goodHasReceiverHandleAndHandle$FfiNative$Ptr = ffi::_asFunctionInternal<(self::NativeClassy, self::NativeClassy) → void, (ffi::Handle*, ffi::Handle*) →* ffi::Void*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Handle*, ffi::Handle*) →* ffi::Void*>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
static final field (ffi::Pointer<ffi::Void>, self::NativeClassy) → void _goodHasReceiverPtrAndHandle$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, self::NativeClassy) → void, (ffi::Pointer<ffi::Void*>*, ffi::Handle*) →* ffi::Void*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void*>*, ffi::Handle*) →* ffi::Void*>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
+ static final field (ffi::Pointer<ffi::Void>, core::bool) → core::Object _meh$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>, core::bool) → core::Object, (ffi::Pointer<ffi::Void*>*, ffi::Bool*) →* ffi::Handle*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void*>*, ffi::Bool*) →* ffi::Handle*>*>(ffi::_ffi_resolver(#C1, #C4, #C5){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
+ static final field (ffi::Pointer<ffi::Void>) → core::bool _blah$FfiNative$Ptr = ffi::_asFunctionInternal<(ffi::Pointer<ffi::Void>) → core::bool, (ffi::Pointer<ffi::Void*>*) →* ffi::Bool*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::Pointer<ffi::Void*>*) →* ffi::Bool*>*>(ffi::_ffi_resolver(#C1, #C4, #C3){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
synthetic constructor •() → self::NativeClassy
: super nat::NativeFieldWrapperClass1::•()
;
method goodHasReceiverPointer(core::int v) → void
- return self::NativeClassy::_goodHasReceiverPointer$FfiNative(this, v);
- method goodHasReceiverHandle(core::int v) → void
- return self::NativeClassy::_goodHasReceiverHandle$FfiNative(this, v);
- method goodHasReceiverHandleAndPtr(self::NativeClassy v) → void
- return self::NativeClassy::_goodHasReceiverHandleAndPtr$FfiNative(this, v);
- method goodHasReceiverHandleAndHandle(self::NativeClassy v) → void
- return self::NativeClassy::_goodHasReceiverHandleAndHandle$FfiNative(this, v);
- method goodHasReceiverPtrAndHandle(self::NativeClassy v) → void
- return self::NativeClassy::_goodHasReceiverPtrAndHandle$FfiNative(this, v);
- static method /*isLegacy*/ _goodHasReceiverPointer$FfiNative(self::NativeClassy self, core::int v) → dynamic
return block {
- final nat::NativeFieldWrapperClass1 #t1 = self;
+ final nat::NativeFieldWrapperClass1 #t1 = this;
final core::int #t2 = v;
- final void #t3 = self::NativeClassy::_goodHasReceiverPointer$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>(nat::_getNativeField(#t1)), #t2){(self::NativeClassy, core::int) → void};
+ final void #t3 = self::NativeClassy::_goodHasReceiverPointer$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>(nat::_getNativeField(#t1)), #t2){(ffi::Pointer<ffi::Void>, core::int) → void};
_in::reachabilityFence(#t1);
} =>#t3;
- static method /*isLegacy*/ _goodHasReceiverHandle$FfiNative(self::NativeClassy self, core::int v) → dynamic
- return self::NativeClassy::_goodHasReceiverHandle$FfiNative$Ptr(self, v){(self::NativeClassy, core::int) → void};
- static method /*isLegacy*/ _goodHasReceiverHandleAndPtr$FfiNative(self::NativeClassy self, self::NativeClassy v) → dynamic
+ method goodHasReceiverHandle(core::int v) → void
+ return self::NativeClassy::_goodHasReceiverHandle$FfiNative$Ptr(this, v){(self::NativeClassy, core::int) → void};
+ method goodHasReceiverHandleAndPtr(self::NativeClassy v) → void
return block {
- final self::NativeClassy #t4 = self;
+ final self::NativeClassy #t4 = this;
final nat::NativeFieldWrapperClass1 #t5 = v;
- final void #t6 = self::NativeClassy::_goodHasReceiverHandleAndPtr$FfiNative$Ptr(#t4, ffi::_fromAddress<ffi::Void>(nat::_getNativeField(#t5))){(self::NativeClassy, self::NativeClassy) → void};
+ final void #t6 = self::NativeClassy::_goodHasReceiverHandleAndPtr$FfiNative$Ptr(#t4, ffi::_fromAddress<ffi::Void>(nat::_getNativeField(#t5))){(self::NativeClassy, ffi::Pointer<ffi::Void>) → void};
_in::reachabilityFence(#t5);
} =>#t6;
- static method /*isLegacy*/ _goodHasReceiverHandleAndHandle$FfiNative(self::NativeClassy self, self::NativeClassy v) → dynamic
- return self::NativeClassy::_goodHasReceiverHandleAndHandle$FfiNative$Ptr(self, v){(self::NativeClassy, self::NativeClassy) → void};
- static method /*isLegacy*/ _goodHasReceiverPtrAndHandle$FfiNative(self::NativeClassy self, self::NativeClassy v) → dynamic
+ method goodHasReceiverHandleAndHandle(self::NativeClassy v) → void
+ return self::NativeClassy::_goodHasReceiverHandleAndHandle$FfiNative$Ptr(this, v){(self::NativeClassy, self::NativeClassy) → void};
+ method goodHasReceiverPtrAndHandle(self::NativeClassy v) → void
return block {
- final nat::NativeFieldWrapperClass1 #t7 = self;
+ final nat::NativeFieldWrapperClass1 #t7 = this;
final self::NativeClassy #t8 = v;
- final void #t9 = self::NativeClassy::_goodHasReceiverPtrAndHandle$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>(nat::_getNativeField(#t7)), #t8){(self::NativeClassy, self::NativeClassy) → void};
+ final void #t9 = self::NativeClassy::_goodHasReceiverPtrAndHandle$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>(nat::_getNativeField(#t7)), #t8){(ffi::Pointer<ffi::Void>, self::NativeClassy) → void};
_in::reachabilityFence(#t7);
} =>#t9;
+ method meh(core::bool blah) → core::String?
+ return block {
+ final nat::NativeFieldWrapperClass1 #t10 = this;
+ final core::bool #t11 = blah;
+ final core::String? #t12 = self::NativeClassy::_meh$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>(nat::_getNativeField(#t10)), #t11){(ffi::Pointer<ffi::Void>, core::bool) → core::Object} as core::String?;
+ _in::reachabilityFence(#t10);
+ } =>#t12;
+ method blah() → core::bool
+ return block {
+ final nat::NativeFieldWrapperClass1 #t13 = this;
+ final core::bool #t14 = self::NativeClassy::_blah$FfiNative$Ptr(ffi::_fromAddress<ffi::Void>(nat::_getNativeField(#t13))){(ffi::Pointer<ffi::Void>) → core::bool};
+ _in::reachabilityFence(#t13);
+ } =>#t14;
}
static final field (core::int) → core::int _returnIntPtr$FfiNative$Ptr = ffi::_asFunctionInternal<(core::int) → core::int, (ffi::IntPtr*) →* ffi::IntPtr*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::IntPtr*) →* ffi::IntPtr*>*>(ffi::_ffi_resolver(#C1, #C2, #C3){(core::Object, core::Object, core::int) → core::int}), false)/*isLegacy*/;
static final field (core::int) → core::int _returnIntPtrLeaf$FfiNative$Ptr = ffi::_asFunctionInternal<(core::int) → core::int, (ffi::IntPtr*) →* ffi::IntPtr*>(ffi::_fromAddress<ffi::NativeFunction<(ffi::IntPtr*) →* ffi::IntPtr*>*>(ffi::_ffi_resolver(#C1, #C2, #C3){(core::Object, core::Object, core::int) → core::int}), true)/*isLegacy*/;
@@ -76,6 +81,8 @@
new self::NativeClassy::•().{self::NativeClassy::goodHasReceiverHandleAndPtr}(new self::NativeClassy::•()){(self::NativeClassy) → void};
new self::NativeClassy::•().{self::NativeClassy::goodHasReceiverHandleAndHandle}(new self::NativeClassy::•()){(self::NativeClassy) → void};
new self::NativeClassy::•().{self::NativeClassy::goodHasReceiverPtrAndHandle}(new self::NativeClassy::•()){(self::NativeClassy) → void};
+ new self::NativeClassy::•().{self::NativeClassy::meh}(true){(core::bool) → core::String?};
+ new self::NativeClassy::•().{self::NativeClassy::blah}(){() → core::bool};
}
constants {
#C1 = "#lib"
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/math_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/math_patch.dart
index 288f66e..fe52156 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/math_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/math_patch.dart
@@ -67,14 +67,14 @@
@patch
class Random {
- static Random? _secureRandom;
+ static final Random _secureRandom = _JSSecureRandom();
@patch
factory Random([int? seed]) =>
(seed == null) ? const _JSRandom() : _Random(seed);
@patch
- factory Random.secure() => _secureRandom ??= _JSSecureRandom();
+ factory Random.secure() => _secureRandom;
}
class _JSRandom implements Random {
diff --git a/sdk/lib/_internal/js_runtime/lib/math_patch.dart b/sdk/lib/_internal/js_runtime/lib/math_patch.dart
index 585f4c5..64236b3 100644
--- a/sdk/lib/_internal/js_runtime/lib/math_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/math_patch.dart
@@ -63,14 +63,14 @@
@patch
class Random {
- static Random? _secureRandom;
+ static final Random _secureRandom = _JSSecureRandom();
@patch
factory Random([int? seed]) =>
- (seed == null) ? const _JSRandom() : new _Random(seed);
+ (seed == null) ? const _JSRandom() : _Random(seed);
@patch
- factory Random.secure() => _secureRandom ??= _JSSecureRandom();
+ factory Random.secure() => _secureRandom;
}
class _JSRandom implements Random {
diff --git a/tools/VERSION b/tools/VERSION
index d699e32..3c5112c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 235
+PRERELEASE 236
PRERELEASE_PATCH 0
\ No newline at end of file