blob: b6eed0b33607c83abc3b1970657d413c1d2b9c62 [file] [log] [blame]
// Copyright (c) 2019, 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.
import 'package:args/args.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/ir/annotations.dart';
import 'package:compiler/src/js_backend/native_data.dart';
import 'package:compiler/src/kernel/kernel_strategy.dart';
import 'package:compiler/src/kernel/element_map_impl.dart';
import 'package:expect/expect.dart';
import 'package:kernel/ast.dart' as ir;
import '../helpers/args_helper.dart';
import '../helpers/memory_compiler.dart';
const String pathPrefix = 'sdk/tests/compiler/dart2js_native/';
const Map<String, String> source = {
'$pathPrefix/main.dart': '''
library lib;
import 'jslib1.dart';
import 'jslib2.dart';
import 'nativelib.dart';
main() {
}
''',
'$pathPrefix/jslib1.dart': '''
@JS('lib1')
library lib1;
import 'package:js/js.dart';
@JS('JsInteropClass1')
class Class1 {
@JS('jsInteropMethod1')
external method1();
external method2();
}
''',
'$pathPrefix/jslib2.dart': '''
@JS()
library lib2;
import 'package:js/js.dart';
@JS()
@anonymous
class Class2 {
}
@JS('jsInteropMethod3')
external method3();
''',
'$pathPrefix/nativelib.dart': '''
import 'dart:_js_helper';
@Native('NativeClass1')
class Class1 {
}
@Native('NativeClass2,!nonleaf')
class Class2 {
}
@Native('NativeClass3a,NativeClass3b')
class Class3 {
}
''',
};
const Map<String, String> expectedNativeClassNames = {
'$pathPrefix/nativelib.dart::Class1': 'NativeClass1',
'$pathPrefix/nativelib.dart::Class2': 'NativeClass2,!nonleaf',
'$pathPrefix/nativelib.dart::Class3': 'NativeClass3a,NativeClass3b',
};
const Map<String, String> expectedJsInteropLibraryNames = {
'$pathPrefix/jslib1.dart': 'lib1',
'$pathPrefix/jslib2.dart': '',
};
const Map<String, String> expectedJsInteropClassNames = {
'$pathPrefix/jslib1.dart::Class1': 'JsInteropClass1',
'$pathPrefix/jslib2.dart::Class2': '',
};
const Map<String, String> expectedJsInteropMemberNames = {
'$pathPrefix/jslib1.dart::Class1::method1': 'jsInteropMethod1',
'$pathPrefix/jslib2.dart::method3': 'jsInteropMethod3',
};
const Set<String> expectedAnonymousJsInteropClasses = {
'$pathPrefix/jslib2.dart::Class2',
};
main(List<String> args) {
ArgParser argParser = createArgParser();
asyncTest(() async {
ArgResults argResults = argParser.parse(args);
Uri librariesSpecificationUri = getLibrariesSpec(argResults);
Uri packageConfig = getPackages(argResults);
List<String> options = getOptions(argResults);
runTest({bool useIr}) async {
CompilationResult result = await runCompiler(
entryPoint: Uri.parse('memory:$pathPrefix/main.dart'),
memorySourceFiles: source,
packageConfig: packageConfig,
librariesSpecificationUri: librariesSpecificationUri,
options: (useIr
? ['${Flags.enableLanguageExperiments}=constant-update-2018']
: [])
..addAll(options));
Expect.isTrue(result.isSuccess);
Compiler compiler = result.compiler;
KernelFrontEndStrategy frontendStrategy = compiler.frontendStrategy;
KernelToElementMapImpl elementMap = frontendStrategy.elementMap;
NativeData nativeData =
compiler.resolutionWorldBuilder.closedWorldForTesting.nativeData;
ir.Component component = elementMap.env.mainComponent;
IrAnnotationData annotationData;
if (useIr) {
annotationData = processAnnotations(component);
}
void testMember(String idPrefix, ir.Member member,
{bool implicitJsInteropMember}) {
String memberId = '$idPrefix::${member.name.name}';
MemberEntity memberEntity = elementMap.getMember(member);
String expectedJsInteropMemberName =
expectedJsInteropMemberNames[memberId];
if (useIr) {
Expect.equals(
expectedJsInteropMemberName,
annotationData.getJsInteropMemberName(member),
"Unexpected js interop member name from IR for $member");
}
bool isJsInteropMember =
(implicitJsInteropMember && member.isExternal) ||
expectedJsInteropMemberName != null;
Expect.equals(
isJsInteropMember,
nativeData.isJsInteropMember(memberEntity),
"Unexpected js interop member result from native data for $member");
Expect.equals(
isJsInteropMember
? expectedJsInteropMemberName ?? memberEntity.name
: null,
nativeData.getJsInteropMemberName(memberEntity),
"Unexpected js interop member name from native data for $member");
}
for (ir.Library library in component.libraries) {
if (library.importUri.scheme == 'memory') {
String libraryId = library.importUri.path;
LibraryEntity libraryEntity = elementMap.getLibrary(library);
String expectedJsInteropLibraryName =
expectedJsInteropLibraryNames[libraryId];
if (useIr) {
Expect.equals(
expectedJsInteropLibraryName,
annotationData.getJsInteropLibraryName(library),
"Unexpected js library name from IR for $library");
}
Expect.equals(
expectedJsInteropLibraryName != null,
nativeData.isJsInteropLibrary(libraryEntity),
"Unexpected js library result from native data for $library");
Expect.equals(
expectedJsInteropLibraryName,
nativeData.getJsInteropLibraryName(libraryEntity),
"Unexpected js library name from native data for $library");
for (ir.Class cls in library.classes) {
String clsId = '$libraryId::${cls.name}';
ClassEntity classEntity = elementMap.getClass(cls);
String expectedNativeClassName = expectedNativeClassNames[clsId];
if (useIr) {
Expect.equals(
expectedNativeClassName,
annotationData.getNativeClassName(cls),
"Unexpected native class name from IR for $cls");
}
bool isNativeClass = nativeData.isNativeClass(classEntity) &&
!nativeData.isJsInteropClass(classEntity);
String nativeDataClassName;
if (isNativeClass) {
nativeDataClassName =
nativeData.getNativeTagsOfClass(classEntity).join(',');
if (nativeData.hasNativeTagsForcedNonLeaf(classEntity)) {
nativeDataClassName += ',!nonleaf';
}
}
Expect.equals(expectedNativeClassName != null, isNativeClass,
"Unexpected native class result from native data for $cls");
Expect.equals(expectedNativeClassName, nativeDataClassName,
"Unexpected native class name from native data for $cls");
String expectedJsInteropClassName =
expectedJsInteropClassNames[clsId];
if (useIr) {
Expect.equals(
expectedJsInteropClassName,
annotationData.getJsInteropClassName(cls),
"Unexpected js class name from IR for $cls");
}
Expect.equals(
expectedJsInteropClassName != null,
nativeData.isJsInteropClass(classEntity),
"Unexpected js class result from native data for $cls");
Expect.equals(
expectedJsInteropClassName,
nativeData.getJsInteropClassName(classEntity),
"Unexpected js class name from native data for $cls");
bool expectedAnonymousJsInteropClass =
expectedAnonymousJsInteropClasses.contains(clsId);
if (useIr) {
Expect.equals(
expectedAnonymousJsInteropClass,
annotationData.isAnonymousJsInteropClass(cls),
"Unexpected js anonymous class result from IR for $cls");
}
Expect.equals(
expectedAnonymousJsInteropClass,
nativeData.isAnonymousJsInteropClass(classEntity),
"Unexpected js anonymousclass result from native data for "
"$cls");
for (ir.Member member in cls.members) {
testMember(clsId, member,
implicitJsInteropMember:
nativeData.isJsInteropClass(classEntity));
}
}
for (ir.Member member in library.members) {
testMember(libraryId, member, implicitJsInteropMember: false);
}
}
}
}
print('test annotations from IR');
await runTest(useIr: true);
print('test annotations from K-model');
await runTest(useIr: false);
});
}