Support @Creates and @Returns from ir constants
Change-Id: I5afa43354f70e42dad93a568afabb14d2004cf52
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/96784
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/ir/annotations.dart b/pkg/compiler/lib/src/ir/annotations.dart
index 3119c2c..1cd8bcf 100644
--- a/pkg/compiler/lib/src/ir/annotations.dart
+++ b/pkg/compiler/lib/src/ir/annotations.dart
@@ -9,6 +9,8 @@
Map<ir.Class, String> _nativeClassNames = {};
Set<ir.Member> _nativeMembers = {};
Map<ir.Member, String> _nativeMemberNames = {};
+ Map<ir.Member, List<String>> _createsAnnotations = {};
+ Map<ir.Member, List<String>> _returnsAnnotations = {};
Map<ir.Library, String> _jsInteropLibraryNames = {};
Map<ir.Class, String> _jsInteropClassNames = {};
@@ -26,6 +28,16 @@
// Returns the text from the `@JSName(<text>)` annotation of [node], if any.
String getNativeMemberName(ir.Member node) => _nativeMemberNames[node];
+ // Returns a list of the text from the `@Creates(<text>)` annotation of
+ // [node].
+ List<String> getCreatesAnnotations(ir.Member node) =>
+ _createsAnnotations[node] ?? const [];
+
+ // Returns a list of the text from the `@Returns(<text>)` annotation of
+ // [node].
+ List<String> getReturnsAnnotations(ir.Member node) =>
+ _returnsAnnotations[node] ?? const [];
+
// Returns the text from the `@JS(<text>)` annotation of [node], if any.
String getJsInteropLibraryName(ir.Library node) =>
_jsInteropLibraryNames[node];
@@ -50,6 +62,8 @@
void processMember(ir.Member member) {
List<PragmaAnnotationData> pragmaAnnotations;
+ List<String> createsAnnotations;
+ List<String> returnsAnnotations;
for (ir.Expression annotation in member.annotations) {
if (annotation is ir.ConstantExpression) {
ir.Constant constant = annotation.constant;
@@ -69,6 +83,22 @@
data._nativeMemberNames[member] = nativeName;
}
+ String creates = _getCreatesAnnotation(constant);
+ if (creates != null) {
+ if (createsAnnotations == null) {
+ data._createsAnnotations[member] = createsAnnotations = [];
+ }
+ createsAnnotations.add(creates);
+ }
+
+ String returns = _getReturnsAnnotation(constant);
+ if (returns != null) {
+ if (returnsAnnotations == null) {
+ data._returnsAnnotations[member] = returnsAnnotations = [];
+ }
+ returnsAnnotations.add(returns);
+ }
+
PragmaAnnotationData pragmaAnnotation = _getPragmaAnnotation(constant);
if (pragmaAnnotation != null) {
if (pragmaAnnotations == null) {
@@ -163,6 +193,32 @@
return null;
}
+String _getCreatesAnnotation(ir.Constant constant) {
+ if (constant is ir.InstanceConstant &&
+ constant.classNode.name == 'Creates' &&
+ constant.classNode.enclosingLibrary.importUri == Uris.dart__js_helper) {
+ assert(constant.fieldValues.length == 1);
+ ir.Constant fieldValue = constant.fieldValues.values.single;
+ if (fieldValue is ir.StringConstant) {
+ return fieldValue.value;
+ }
+ }
+ return null;
+}
+
+String _getReturnsAnnotation(ir.Constant constant) {
+ if (constant is ir.InstanceConstant &&
+ constant.classNode.name == 'Returns' &&
+ constant.classNode.enclosingLibrary.importUri == Uris.dart__js_helper) {
+ assert(constant.fieldValues.length == 1);
+ ir.Constant fieldValue = constant.fieldValues.values.single;
+ if (fieldValue is ir.StringConstant) {
+ return fieldValue.value;
+ }
+ }
+ return null;
+}
+
String _getJsInteropName(ir.Constant constant) {
if (constant is ir.InstanceConstant &&
constant.classNode.name == 'JS' &&
diff --git a/pkg/compiler/lib/src/kernel/element_map.dart b/pkg/compiler/lib/src/kernel/element_map.dart
index 3a22be9..d69ff52 100644
--- a/pkg/compiler/lib/src/kernel/element_map.dart
+++ b/pkg/compiler/lib/src/kernel/element_map.dart
@@ -147,6 +147,7 @@
/// Computes the native behavior for reading the native [field].
NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field,
+ Iterable<String> createsAnnotations, Iterable<String> returnsAnnotations,
{bool isJsInterop});
/// Computes the native behavior for writing to the native [field].
@@ -155,6 +156,7 @@
/// Computes the native behavior for calling the function or constructor
/// [member].
NativeBehavior getNativeBehaviorForMethod(ir.Member member,
+ Iterable<String> createsAnnotations, Iterable<String> returnsAnnotations,
{bool isJsInterop});
/// Compute the kind of foreign helper function called by [node], if any.
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index b289b50..6f2491d 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -1525,14 +1525,11 @@
// TODO(johnniwinther): Cache this for later use.
@override
NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field,
+ Iterable<String> createsAnnotations, Iterable<String> returnsAnnotations,
{bool isJsInterop}) {
DartType type = getDartType(field.type);
- List<ConstantValue> metadata = getMetadata(field.annotations);
- return nativeBehaviorBuilder.buildFieldLoadBehavior(
- type,
- getCreatesAnnotations(reporter, commonElements, metadata),
- getReturnsAnnotations(reporter, commonElements, metadata),
- typeLookup(resolveAsRaw: false),
+ return nativeBehaviorBuilder.buildFieldLoadBehavior(type,
+ createsAnnotations, returnsAnnotations, typeLookup(resolveAsRaw: false),
isJsInterop: isJsInterop);
}
@@ -1548,6 +1545,7 @@
// TODO(johnniwinther): Cache this for later use.
@override
NativeBehavior getNativeBehaviorForMethod(ir.Member member,
+ Iterable<String> createsAnnotations, Iterable<String> returnsAnnotations,
{bool isJsInterop}) {
DartType type;
if (member is ir.Procedure) {
@@ -1557,12 +1555,8 @@
} else {
failedAt(CURRENT_ELEMENT_SPANNABLE, "Unexpected method node $member.");
}
- List<ConstantValue> metadata = getMetadata(member.annotations);
- return nativeBehaviorBuilder.buildMethodBehavior(
- type,
- getCreatesAnnotations(reporter, commonElements, metadata),
- getReturnsAnnotations(reporter, commonElements, metadata),
- typeLookup(resolveAsRaw: false),
+ return nativeBehaviorBuilder.buildMethodBehavior(type, createsAnnotations,
+ returnsAnnotations, typeLookup(resolveAsRaw: false),
isJsInterop: isJsInterop);
}
@@ -1974,7 +1968,7 @@
class KernelNativeMemberResolver implements NativeMemberResolver {
static final RegExp _identifier = new RegExp(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$');
- final KernelToElementMap _elementMap;
+ final KernelToElementMapImpl _elementMap;
final NativeBasicData _nativeBasicData;
final NativeDataBuilder _nativeDataBuilder;
@@ -1996,16 +1990,18 @@
FunctionEntity method = element;
bool isNative = _processMethodAnnotations(method, annotationData);
if (isNative || isJsInterop) {
- NativeBehavior behavior =
- _computeNativeMethodBehavior(method, isJsInterop: isJsInterop);
+ NativeBehavior behavior = _computeNativeMethodBehavior(
+ method, annotationData,
+ isJsInterop: isJsInterop);
_nativeDataBuilder.setNativeMethodBehavior(method, behavior);
}
} else if (element.isField) {
FieldEntity field = element;
bool isNative = _processFieldAnnotations(field, annotationData);
if (isNative || isJsInterop) {
- NativeBehavior fieldLoadBehavior =
- _computeNativeFieldLoadBehavior(field, isJsInterop: isJsInterop);
+ NativeBehavior fieldLoadBehavior = _computeNativeFieldLoadBehavior(
+ field, annotationData,
+ isJsInterop: isJsInterop);
NativeBehavior fieldStoreBehavior =
_computeNativeFieldStoreBehavior(field);
_nativeDataBuilder.setNativeFieldLoadBehavior(field, fieldLoadBehavior);
@@ -2096,9 +2092,11 @@
/// present.
String _findJsNameFromAnnotation(
MemberEntity element, IrAnnotationData annotationData) {
- String jsName =
- annotationData.getNativeMemberName(_elementMap.getMemberNode(element));
- if (jsName == null) {
+ String jsName;
+ if (annotationData != null) {
+ jsName = annotationData
+ .getNativeMemberName(_elementMap.getMemberNode(element));
+ } else {
for (ConstantValue value
in _elementEnvironment.getMemberMetadata(element)) {
String name = readAnnotationName(
@@ -2119,17 +2117,47 @@
return _elementMap.getNativeBehaviorForFieldStore(node);
}
- NativeBehavior _computeNativeFieldLoadBehavior(covariant KField field,
+ NativeBehavior _computeNativeFieldLoadBehavior(
+ KField field, IrAnnotationData annotationData,
{bool isJsInterop}) {
ir.Field node = _elementMap.getMemberNode(field);
- return _elementMap.getNativeBehaviorForFieldLoad(node,
+ Iterable<String> createsAnnotations;
+ Iterable<String> returnsAnnotations;
+ if (annotationData != null) {
+ createsAnnotations = annotationData.getCreatesAnnotations(node);
+ returnsAnnotations = annotationData.getReturnsAnnotations(node);
+ } else {
+ List<ConstantValue> metadata =
+ _elementEnvironment.getMemberMetadata(field);
+ createsAnnotations = getCreatesAnnotations(
+ _elementMap.reporter, _elementMap.commonElements, metadata);
+ returnsAnnotations = getReturnsAnnotations(
+ _elementMap.reporter, _elementMap.commonElements, metadata);
+ }
+ return _elementMap.getNativeBehaviorForFieldLoad(
+ node, createsAnnotations, returnsAnnotations,
isJsInterop: isJsInterop);
}
- NativeBehavior _computeNativeMethodBehavior(covariant KFunction function,
+ NativeBehavior _computeNativeMethodBehavior(
+ KFunction function, IrAnnotationData annotationData,
{bool isJsInterop}) {
ir.Member node = _elementMap.getMemberNode(function);
- return _elementMap.getNativeBehaviorForMethod(node,
+ Iterable<String> createsAnnotations;
+ Iterable<String> returnsAnnotations;
+ if (annotationData != null) {
+ createsAnnotations = annotationData.getCreatesAnnotations(node);
+ returnsAnnotations = annotationData.getReturnsAnnotations(node);
+ } else {
+ List<ConstantValue> metadata =
+ _elementEnvironment.getMemberMetadata(function);
+ createsAnnotations = getCreatesAnnotations(
+ _elementMap.reporter, _elementMap.commonElements, metadata);
+ returnsAnnotations = getReturnsAnnotations(
+ _elementMap.reporter, _elementMap.commonElements, metadata);
+ }
+ return _elementMap.getNativeBehaviorForMethod(
+ node, createsAnnotations, returnsAnnotations,
isJsInterop: isJsInterop);
}
@@ -2137,12 +2165,15 @@
covariant KFunction function, IrAnnotationData annotationData) {
if (!maybeEnableNative(function.library.canonicalUri)) return false;
ir.Member node = _elementMap.getMemberNode(function);
- if (annotationData.hasNativeBody(node)) return true;
- return node.annotations.any((ir.Expression expression) {
- return expression is ir.ConstructorInvocation &&
- _elementMap.getInterfaceType(expression.constructedType) ==
- _commonElements.externalNameType;
- });
+ if (annotationData != null) {
+ return annotationData.hasNativeBody(node);
+ } else {
+ return node.annotations.any((ir.Expression expression) {
+ return expression is ir.ConstructorInvocation &&
+ _elementMap.getInterfaceType(expression.constructedType) ==
+ _commonElements.externalNameType;
+ });
+ }
}
bool _isJsInteropMember(MemberEntity element) {
diff --git a/pkg/compiler/lib/src/kernel/kernel_impact.dart b/pkg/compiler/lib/src/kernel/kernel_impact.dart
index f32c305..7fe6670 100644
--- a/pkg/compiler/lib/src/kernel/kernel_impact.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_impact.dart
@@ -21,6 +21,7 @@
import '../ir/util.dart';
import '../js_backend/annotations.dart';
import '../js_backend/native_data.dart';
+import '../native/behavior.dart';
import '../options.dart';
import '../resolution/registry.dart' show ResolutionWorldImpactBuilder;
import '../universe/call_structure.dart';
@@ -150,9 +151,18 @@
if (field.isInstanceMember &&
elementMap.isNativeClass(field.enclosingClass)) {
MemberEntity member = elementMap.getMember(field);
+ // TODO(johnniwinther): NativeDataBuilder already has the native behavior
+ // at this point. Use that instead.
bool isJsInterop = _nativeBasicData.isJsInteropMember(member);
- impactBuilder.registerNativeData(elementMap
- .getNativeBehaviorForFieldLoad(field, isJsInterop: isJsInterop));
+ List<ConstantValue> metadata =
+ elementMap.elementEnvironment.getMemberMetadata(member);
+ Iterable<String> createsAnnotations =
+ getCreatesAnnotations(reporter, commonElements, metadata);
+ Iterable<String> returnsAnnotations =
+ getReturnsAnnotations(reporter, commonElements, metadata);
+ impactBuilder.registerNativeData(elementMap.getNativeBehaviorForFieldLoad(
+ field, createsAnnotations, returnsAnnotations,
+ isJsInterop: isJsInterop));
impactBuilder
.registerNativeData(elementMap.getNativeBehaviorForFieldStore(field));
}
@@ -162,9 +172,18 @@
void registerConstructorNode(ir.Constructor constructor) {
MemberEntity member = elementMap.getMember(constructor);
if (constructor.isExternal && !commonElements.isForeignHelper(member)) {
+ // TODO(johnniwinther): NativeDataBuilder already has the native behavior
+ // at this point. Use that instead.
bool isJsInterop = _nativeBasicData.isJsInteropMember(member);
- impactBuilder.registerNativeData(elementMap
- .getNativeBehaviorForMethod(constructor, isJsInterop: isJsInterop));
+ List<ConstantValue> metadata =
+ elementMap.elementEnvironment.getMemberMetadata(member);
+ Iterable<String> createsAnnotations =
+ getCreatesAnnotations(reporter, commonElements, metadata);
+ Iterable<String> returnsAnnotations =
+ getReturnsAnnotations(reporter, commonElements, metadata);
+ impactBuilder.registerNativeData(elementMap.getNativeBehaviorForMethod(
+ constructor, createsAnnotations, returnsAnnotations,
+ isJsInterop: isJsInterop));
}
}
@@ -199,9 +218,18 @@
void registerProcedureNode(ir.Procedure procedure) {
MemberEntity member = elementMap.getMember(procedure);
if (procedure.isExternal && !commonElements.isForeignHelper(member)) {
+ // TODO(johnniwinther): NativeDataBuilder already has the native behavior
+ // at this point. Use that instead.
bool isJsInterop = _nativeBasicData.isJsInteropMember(member);
- impactBuilder.registerNativeData(elementMap
- .getNativeBehaviorForMethod(procedure, isJsInterop: isJsInterop));
+ List<ConstantValue> metadata =
+ elementMap.elementEnvironment.getMemberMetadata(member);
+ Iterable<String> createsAnnotations =
+ getCreatesAnnotations(reporter, commonElements, metadata);
+ Iterable<String> returnsAnnotations =
+ getReturnsAnnotations(reporter, commonElements, metadata);
+ impactBuilder.registerNativeData(elementMap.getNativeBehaviorForMethod(
+ procedure, createsAnnotations, returnsAnnotations,
+ isJsInterop: isJsInterop));
}
}
diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
index 1f265d9..46f5293 100644
--- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
@@ -70,11 +70,15 @@
@override
void registerLoadedLibraries(KernelResult kernelResult) {
_elementMap.addComponent(kernelResult.component);
- _irAnnotationData = processAnnotations(kernelResult.component);
+ if (useIrAnnotationsDataForTesting) {
+ _irAnnotationData = processAnnotations(kernelResult.component);
+ }
_annotationProcessor = new KernelAnnotationProcessor(
elementMap, nativeBasicDataBuilder, _irAnnotationData);
}
+ IrAnnotationData get irAnnotationDataForTesting => _irAnnotationData;
+
ModularStrategy get modularStrategyForTesting => _modularStrategy;
@override
diff --git a/pkg/compiler/lib/src/kernel/native_basic_data.dart b/pkg/compiler/lib/src/kernel/native_basic_data.dart
index 7aeda4d..745afa5 100644
--- a/pkg/compiler/lib/src/kernel/native_basic_data.dart
+++ b/pkg/compiler/lib/src/kernel/native_basic_data.dart
@@ -20,8 +20,10 @@
elementEnvironment.forEachClass(library, (ClassEntity cls) {
ir.Class node = elementMap.getClassNode(cls);
- String annotationName = annotationData.getNativeClassName(node);
- if (annotationName == null) {
+ String annotationName;
+ if (annotationData != null) {
+ annotationName = annotationData.getNativeClassName(node);
+ } else {
// TODO(johnniwinther): Remove this branch when we use constants from
// CFE.
for (ConstantValue value in elementEnvironment.getClassMetadata(cls)) {
@@ -74,19 +76,27 @@
KCommonElements commonElements = elementMap.commonElements;
ir.Library libraryNode = elementMap.getLibraryNode(library);
- String libraryName = annotationData.getJsInteropLibraryName(libraryNode);
- // TODO(johnniwinther): Remove this when we use constants from CFE.
- libraryName ??= getJsInteropName(
- library, elementEnvironment.getLibraryMetadata(library));
+ String libraryName;
+ if (annotationData != null) {
+ libraryName = annotationData.getJsInteropLibraryName(libraryNode);
+ } else {
+ // TODO(johnniwinther): Remove this when we use constants from CFE.
+ libraryName = getJsInteropName(
+ library, elementEnvironment.getLibraryMetadata(library));
+ }
final bool isExplicitlylyJsLibrary = libraryName != null;
bool isJsLibrary = isExplicitlylyJsLibrary;
elementEnvironment.forEachLibraryMember(library, (MemberEntity member) {
ir.Member memberNode = elementMap.getMemberNode(member);
- String memberName = annotationData.getJsInteropMemberName(memberNode);
- // TODO(johnniwinther): Remove this when we use constants from CFE.
- memberName ??= getJsInteropName(
- library, elementEnvironment.getMemberMetadata(member));
+ String memberName;
+ if (annotationData != null) {
+ memberName = annotationData.getJsInteropMemberName(memberNode);
+ } else {
+ // TODO(johnniwinther): Remove this when we use constants from CFE.
+ memberName = getJsInteropName(
+ library, elementEnvironment.getMemberMetadata(member));
+ }
if (member.isField) {
if (memberName != null) {
// TODO(34174): Disallow js-interop fields.
@@ -121,15 +131,22 @@
});
elementEnvironment.forEachClass(library, (ClassEntity cls) {
+ Iterable<ConstantValue> metadata;
ir.Class classNode = elementMap.getClassNode(cls);
- String className = annotationData.getJsInteropClassName(classNode);
- Iterable<ConstantValue> metadata =
- elementEnvironment.getClassMetadata(cls);
- // TODO(johnniwinther): Remove this when we use constants from CFE.
- className ??= getJsInteropName(cls, metadata);
+ String className;
+ if (annotationData != null) {
+ className = annotationData.getJsInteropClassName(classNode);
+ } else {
+ metadata = elementEnvironment.getClassMetadata(cls);
+ // TODO(johnniwinther): Remove this when we use constants from CFE.
+ className = getJsInteropName(cls, metadata);
+ }
if (className != null) {
- bool isAnonymous = annotationData.isAnonymousJsInteropClass(classNode);
- if (!isAnonymous) {
+ bool isAnonymous;
+ if (annotationData != null) {
+ isAnonymous = annotationData.isAnonymousJsInteropClass(classNode);
+ } else {
+ isAnonymous = false;
// TODO(johnniwinther): Remove this branch when we use constants from
// CFE.
for (ConstantValue value in metadata) {
@@ -155,12 +172,14 @@
} else {
FunctionEntity function = member;
ir.Member memberNode = elementMap.getMemberNode(member);
- String memberName =
- annotationData.getJsInteropMemberName(memberNode);
- // TODO(johnniwinther): Remove this when we use constants from CFE.
- memberName ??= getJsInteropName(
- library, elementEnvironment.getMemberMetadata(function));
-
+ String memberName;
+ if (annotationData != null) {
+ memberName = annotationData.getJsInteropMemberName(memberNode);
+ } else {
+ // TODO(johnniwinther): Remove this when we use constants from CFE.
+ memberName = getJsInteropName(
+ library, elementEnvironment.getMemberMetadata(function));
+ }
if (function.isExternal) {
memberName ??= function.name;
}
@@ -280,10 +299,14 @@
// it.
elementEnvironment.forEachClass(library, (ClassEntity cls) {
ir.Class classNode = elementMap.getClassNode(cls);
- String className = annotationData.getJsInteropClassName(classNode);
- // TODO(johnniwinther): Remove this when we use constants from CFE.
- className ??=
- getJsInteropName(cls, elementEnvironment.getClassMetadata(cls));
+ String className;
+ if (annotationData != null) {
+ className = annotationData.getJsInteropClassName(classNode);
+ } else {
+ // TODO(johnniwinther): Remove this when we use constants from CFE.
+ className ??=
+ getJsInteropName(cls, elementEnvironment.getClassMetadata(cls));
+ }
if (className != null) {
bool implementsJsJavaScriptObjectClass = false;
elementEnvironment.forEachSupertype(cls, (InterfaceType supertype) {
diff --git a/tests/compiler/dart2js/model/cfe_annotations_test.dart b/tests/compiler/dart2js/model/cfe_annotations_test.dart
index ac7a720..4f8c619 100644
--- a/tests/compiler/dart2js/model/cfe_annotations_test.dart
+++ b/tests/compiler/dart2js/model/cfe_annotations_test.dart
@@ -52,7 +52,7 @@
jsMethod3();
new NativeClass1()..nativeMethod()..nativeField;
new NativeClass2()..nativeField;
- new NativeClass3()..nativeGetter;
+ new NativeClass3()..nativeMethod()..nativeGetter;
nativeMethod();
}
''',
@@ -112,6 +112,10 @@
@JSName('method2')
get nativeGetter native;
+
+ @Creates('String')
+ @Returns('int')
+ nativeMethod() native;
}
@JSName('method3')
@@ -133,6 +137,14 @@
'$pathPrefix/nativelib.dart::nativeMethod': 'method3',
};
+const Map<String, String> expectedCreates = {
+ '$pathPrefix/nativelib.dart::NativeClass3::nativeMethod': 'String',
+};
+
+const Map<String, String> expectedReturns = {
+ '$pathPrefix/nativelib.dart::NativeClass3::nativeMethod': 'int',
+};
+
const Map<String, String> expectedJsInteropLibraryNames = {
'$pathPrefix/jslib1.dart': 'lib1',
'$pathPrefix/jslib2.dart': '',
@@ -189,10 +201,8 @@
NativeData nativeData =
compiler.resolutionWorldBuilder.closedWorldForTesting.nativeData;
ir.Component component = elementMap.env.mainComponent;
- IrAnnotationData annotationData;
- if (useIr) {
- annotationData = processAnnotations(component);
- }
+ IrAnnotationData annotationData =
+ frontendStrategy.irAnnotationDataForTesting;
void testMember(String idPrefix, ir.Member member,
{bool implicitJsInteropMember, bool implicitNativeMember}) {
@@ -209,23 +219,45 @@
if (expectedTryInlineMethods.contains(memberId)) {
expectedPragmaNames.add('dart2js:tryInline');
}
+
+ String expectedCreatesText = expectedCreates[memberId];
+ String expectedReturnsText = expectedReturns[memberId];
+
if (useIr) {
Expect.equals(
expectedJsInteropMemberName,
annotationData.getJsInteropMemberName(member),
- "Unexpected js interop member name from IR for $member");
+ "Unexpected js interop member name from IR for $member, "
+ "id: $memberId");
Expect.equals(
expectedNativeMemberName,
annotationData.getNativeMemberName(member),
- "Unexpected js interop member name from IR for $member");
+ "Unexpected js interop member name from IR for $member, "
+ "id: $memberId");
List<PragmaAnnotationData> pragmaAnnotations =
annotationData.getMemberPragmaAnnotationData(member);
Set<String> pragmaNames =
pragmaAnnotations.map((d) => d.name).toSet();
Expect.setEquals(expectedPragmaNames, pragmaNames,
- "Unexpected pragmas from IR for $member");
+ "Unexpected pragmas from IR for $member, " "id: $memberId");
+
+ List<String> createsAnnotations =
+ annotationData.getCreatesAnnotations(member);
+ Expect.equals(
+ expectedCreatesText,
+ createsAnnotations.isEmpty ? null : createsAnnotations.join(','),
+ "Unexpected create annotations from IR for $member, "
+ "id: $memberId");
+
+ List<String> returnsAnnotations =
+ annotationData.getReturnsAnnotations(member);
+ Expect.equals(
+ expectedReturnsText,
+ returnsAnnotations.isEmpty ? null : returnsAnnotations.join(','),
+ "Unexpected returns annotations from IR for $member, "
+ "id: $memberId");
}
bool isJsInteropMember =
(implicitJsInteropMember && member.isExternal) ||
@@ -233,20 +265,23 @@
Expect.equals(
isJsInteropMember,
nativeData.isJsInteropMember(memberEntity),
- "Unexpected js interop member result from native data for $member");
+ "Unexpected js interop member result from native data for $member, "
+ "id: $memberId");
Expect.equals(
isJsInteropMember
? expectedJsInteropMemberName ?? memberEntity.name
: null,
nativeData.getJsInteropMemberName(memberEntity),
- "Unexpected js interop member name from native data for $member");
+ "Unexpected js interop member name from native data for $member, "
+ "id: $memberId");
bool isNativeMember =
implicitNativeMember || expectedNativeMemberName != null;
Expect.equals(
isNativeMember || isJsInteropMember,
nativeData.isNativeMember(memberEntity),
- "Unexpected native member result from native data for $member");
+ "Unexpected native member result from native data for $member, "
+ "id: $memberId");
Expect.equals(
isNativeMember
? expectedNativeMemberName ?? memberEntity.name
@@ -254,14 +289,58 @@
? expectedJsInteropMemberName ?? memberEntity.name
: null),
nativeData.getFixedBackendName(memberEntity),
- "Unexpected fixed backend name from native data for $member");
+ "Unexpected fixed backend name from native data for $member, "
+ "id: $memberId");
+
+ if (expectedCreatesText != null) {
+ String createsText;
+ if (memberEntity.isField) {
+ createsText = nativeData
+ .getNativeFieldLoadBehavior(memberEntity)
+ .typesInstantiated
+ .join(',');
+ } else {
+ createsText = nativeData
+ .getNativeMethodBehavior(memberEntity)
+ .typesInstantiated
+ .join(',');
+ }
+ Expect.equals(
+ expectedCreatesText,
+ createsText,
+ "Unexpected create annotations from native data for $member, "
+ "id: $memberId");
+ }
+
+ if (expectedReturnsText != null) {
+ String returnsText;
+ if (memberEntity.isField) {
+ returnsText = nativeData
+ .getNativeFieldLoadBehavior(memberEntity)
+ .typesReturned
+ .join(',');
+ } else {
+ returnsText = nativeData
+ .getNativeMethodBehavior(memberEntity)
+ .typesReturned
+ .join(',');
+ }
+ Expect.equals(
+ expectedReturnsText,
+ returnsText,
+ "Unexpected returns annotations from native data for $member, "
+ "id: $memberId");
+ }
List<PragmaAnnotationData> pragmaAnnotations = frontendStrategy
.modularStrategyForTesting
.getPragmaAnnotationData(member);
Set<String> pragmaNames = pragmaAnnotations.map((d) => d.name).toSet();
- Expect.setEquals(expectedPragmaNames, pragmaNames,
- "Unexpected pragmas from modular strategy for $member");
+ Expect.setEquals(
+ expectedPragmaNames,
+ pragmaNames,
+ "Unexpected pragmas from modular strategy for $member, "
+ "id: $memberId");
}
for (ir.Library library in component.libraries) {