// Copyright (c) 2016, 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. // @dart = 2.7 library jsinterop.internal_annotations_test; import 'package:expect/expect.dart'; import 'package:async_helper/async_helper.dart'; import 'package:compiler/src/common_elements.dart'; import 'package:compiler/src/compiler.dart'; import 'package:compiler/src/elements/entities.dart' show ClassEntity; import 'package:compiler/src/elements/names.dart'; import 'package:compiler/src/universe/class_hierarchy.dart'; import 'package:compiler/src/universe/selector.dart'; import 'package:compiler/src/world.dart'; import '../helpers/element_lookup.dart'; import '../helpers/memory_compiler.dart'; void main() { asyncTest(() async { await testClasses('package:js/js.dart', 'dart:_js_annotations'); await testClasses('package:js/js.dart', 'package:js/js.dart'); await testClasses('dart:_js_annotations', 'dart:_js_annotations'); }); } testClasses(String import1, String import2) async { test(String mainSource, {List directlyInstantiated: const [], List abstractlyInstantiated: const [], List indirectlyInstantiated: const []}) async { String mainFile = 'sdk/tests/web_2/native/main.dart'; Uri entryPoint = Uri.parse('memory:$mainFile'); CompilationResult result = await runCompiler(entryPoint: entryPoint, memorySourceFiles: { mainFile: """ import '$import1' as js1; import '$import2' as js2; @js1.JS() class A { external get foo; external A(var foo); } @js2.JS('BClass') class B { external get foo; external B(var foo); } @js1.JS() @js1.anonymous class C { external get foo; external factory C({foo}); } @js2.JS() @js2.anonymous class D { external get foo; external factory D({foo}); } class E { final foo; E(this.foo); } class F { final foo; F(this.foo); } newA() => new A(0); newB() => new B(1); newC() => new C(foo: 2); newD() => new D(foo: 3); newE() => new E(4); newF() => new F(5); $mainSource """ }); Compiler compiler = result.compiler; Map classEnvironment = {}; ClassEntity registerClass(ClassEntity cls) { classEnvironment[cls.name] = cls; return cls; } JClosedWorld world = compiler.backendClosedWorldForTesting; ElementEnvironment elementEnvironment = world.elementEnvironment; ClassEntity Object_ = registerClass(world.commonElements.objectClass); ClassEntity Interceptor = registerClass(world.commonElements.jsInterceptorClass); ClassEntity JavaScriptObject = registerClass(world.commonElements.jsJavaScriptObjectClass); ClassEntity A = registerClass(findClass(world, 'A')); ClassEntity B = registerClass(findClass(world, 'B')); ClassEntity C = registerClass(findClass(world, 'C')); ClassEntity D = registerClass(findClass(world, 'D')); ClassEntity E = registerClass(findClass(world, 'E')); ClassEntity F = registerClass(findClass(world, 'F')); Selector nonExisting = new Selector.getter(const PublicName('nonExisting')); Expect.equals(elementEnvironment.getSuperClass(Interceptor), Object_); Expect.equals( elementEnvironment.getSuperClass(JavaScriptObject), Interceptor); Expect.equals(elementEnvironment.getSuperClass(A), JavaScriptObject); Expect.equals(elementEnvironment.getSuperClass(B), JavaScriptObject); Expect.equals(elementEnvironment.getSuperClass(C), JavaScriptObject); Expect.equals(elementEnvironment.getSuperClass(D), JavaScriptObject); Expect.equals(elementEnvironment.getSuperClass(E), Object_); Expect.equals(elementEnvironment.getSuperClass(F), Object_); Expect.isFalse(world.nativeData.isJsInteropClass(Object_)); Expect.isTrue(world.nativeData.isJsInteropClass(A)); Expect.isTrue(world.nativeData.isJsInteropClass(B)); Expect.isTrue(world.nativeData.isJsInteropClass(C)); Expect.isTrue(world.nativeData.isJsInteropClass(D)); Expect.isFalse(world.nativeData.isJsInteropClass(E)); Expect.isFalse(world.nativeData.isJsInteropClass(F)); Expect.isFalse(world.nativeData.isAnonymousJsInteropClass(Object_)); Expect.isFalse(world.nativeData.isAnonymousJsInteropClass(A)); Expect.isFalse(world.nativeData.isAnonymousJsInteropClass(B)); Expect.isTrue(world.nativeData.isAnonymousJsInteropClass(C)); Expect.isTrue(world.nativeData.isAnonymousJsInteropClass(D)); Expect.isFalse(world.nativeData.isAnonymousJsInteropClass(E)); Expect.isFalse(world.nativeData.isAnonymousJsInteropClass(F)); Expect.equals('', world.nativeData.getJsInteropClassName(A)); Expect.equals('BClass', world.nativeData.getJsInteropClassName(B)); Expect.equals('', world.nativeData.getJsInteropClassName(C)); Expect.equals('', world.nativeData.getJsInteropClassName(D)); for (String name in classEnvironment.keys) { ClassEntity cls = classEnvironment[name]; bool isInstantiated = false; if (directlyInstantiated.contains(name)) { isInstantiated = true; Expect.isTrue( world.classHierarchy.isDirectlyInstantiated(cls), "Expected $name to be directly instantiated in `${mainSource}`:" "\n${world.classHierarchy.dump(cls)}"); } if (abstractlyInstantiated.contains(name)) { isInstantiated = true; Expect.isTrue( world.classHierarchy.isAbstractlyInstantiated(cls), "Expected $name to be abstractly instantiated in `${mainSource}`:" "\n${world.classHierarchy.dump(cls)}"); Expect.isTrue( world.needsNoSuchMethod(cls, nonExisting, ClassQuery.EXACT), "Expected $name to need noSuchMethod for $nonExisting."); Expect.isTrue( world.needsNoSuchMethod(cls, nonExisting, ClassQuery.SUBCLASS), "Expected $name to need noSuchMethod for $nonExisting."); Expect.isTrue( world.needsNoSuchMethod(cls, nonExisting, ClassQuery.SUBTYPE), "Expected $name to need noSuchMethod for $nonExisting."); } if (indirectlyInstantiated.contains(name)) { isInstantiated = true; Expect.isTrue( world.classHierarchy.isIndirectlyInstantiated(cls), "Expected $name to be indirectly instantiated in `${mainSource}`:" "\n${world.classHierarchy.dump(cls)}"); } if (!isInstantiated && (name != 'Object' && name != 'Interceptor')) { Expect.isFalse( world.classHierarchy.isInstantiated(cls), "Expected $name to be uninstantiated in `${mainSource}`:" "\n${world.classHierarchy.dump(cls)}"); } } } await test('main() {}'); await test('main() => newA();', abstractlyInstantiated: ['A', 'B', 'C', 'D'], indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']); await test('main() => newB();', abstractlyInstantiated: ['A', 'B', 'C', 'D'], indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']); await test('main() => newC();', abstractlyInstantiated: ['A', 'B', 'C', 'D'], indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']); await test('main() => newD();', abstractlyInstantiated: ['A', 'B', 'C', 'D'], indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']); await test('main() => newE();', directlyInstantiated: ['E']); await test('main() => newF();', directlyInstantiated: ['F']); await test('main() => [newD(), newE()];', directlyInstantiated: ['E'], abstractlyInstantiated: ['A', 'B', 'C', 'D'], indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']); }