| // Copyright (c) 2018, 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 |
| |
| import 'package:expect/expect.dart'; |
| import 'package:async_helper/async_helper.dart'; |
| import 'package:compiler/src/compiler.dart'; |
| import 'package:compiler/src/common_elements.dart'; |
| import 'package:compiler/src/elements/entities.dart'; |
| import 'package:compiler/src/world.dart'; |
| import '../helpers/memory_compiler.dart'; |
| |
| main() { |
| asyncTest(() async { |
| await runTest(); |
| }); |
| } |
| |
| runTest() async { |
| // Pretend this is a web_2/native test to allow use of 'native' keyword |
| // and import of private libraries. |
| String main = 'sdk/tests/web_2/native/main.dart'; |
| Uri entryPoint = Uri.parse('memory:$main'); |
| |
| CompilationResult result = |
| await runCompiler(entryPoint: entryPoint, memorySourceFiles: { |
| main: ''' |
| class A { |
| method1() {} |
| method2() {} |
| method4() {} |
| get getter => 42; |
| set setter(_) {} |
| } |
| |
| class B { |
| method1() {} |
| method2() {} |
| method5() {} |
| get getter => 42; |
| set setter(_) {} |
| } |
| |
| class C extends A { |
| method1() {} |
| method2() {} |
| method4() {} |
| get getter => 42; |
| set setter(_) {} |
| } |
| |
| class D implements B { |
| method1() {} |
| method2() {} |
| method5() {} |
| get getter => 42; |
| set setter(_) {} |
| } |
| |
| class E implements A { |
| method1() {} |
| method2() {} |
| method4() {} |
| get getter => 42; |
| set setter(_) {} |
| } |
| |
| class F extends B { |
| method1() {} |
| method2() {} |
| method5() {} |
| get getter => 42; |
| set setter(_) {} |
| } |
| |
| class G { |
| method1() {} |
| method2() {} |
| method4() {} |
| get getter => 42; |
| set setter(_) {} |
| } |
| |
| class H extends Object with G implements A {} |
| |
| class I { |
| method1() {} |
| method2() {} |
| method4() {} |
| get getter => 42; |
| set setter(_) {} |
| } |
| |
| class J extends I implements A {} |
| |
| class K { |
| method1() {} |
| method2() {} |
| get getter => 42; |
| set setter(_) {} |
| } |
| |
| class L = Object with K; |
| class L2 = Object with L; |
| class M extends L {} |
| class M2 extends L2 {} |
| |
| class N { |
| method1() {} |
| get getter => 42; |
| set setter(_) {} |
| } |
| |
| abstract class O extends N {} |
| |
| class P implements O { |
| method1() {} |
| get getter => 42; |
| set setter(_) {} |
| } |
| |
| class Q { |
| method3() {} |
| } |
| |
| class R extends Q {} |
| |
| class Class1a { |
| call(a, b, c) {} // Call structure only used in Class1a and Class2b. |
| } |
| |
| class Class1b { |
| call(a, b, c) {} |
| } |
| |
| class Class2 { |
| Class1a c; |
| } |
| |
| main() { |
| method1(); |
| method2(); |
| } |
| |
| @pragma('dart2js:disableFinal') |
| method1() { |
| A a = new A(); |
| B b = new B(); |
| a.method1(); |
| a.getter; |
| b.method2(); |
| b.setter = 42; |
| new C(); |
| new D(); |
| new H(); |
| new J(); |
| new M().method1(); |
| new M2().getter; |
| new N(); |
| O o = new P(); |
| o.method1(); |
| o.getter; |
| o.setter = 42; |
| R r; |
| r.method3(); |
| r = new R(); // Create R after call. |
| new Class1a(); |
| new Class1b(); |
| new Class2().c(0, 1, 2); |
| } |
| |
| method2() { |
| A a = new A(); |
| B b = new B(); |
| a.method4(); |
| b.method5(); |
| } |
| ''' |
| }); |
| Expect.isTrue(result.isSuccess); |
| Compiler compiler = result.compiler; |
| |
| Map<String, List<String>> expectedLiveMembersMap = <String, List<String>>{ |
| 'A': ['method1', 'getter', 'method4'], |
| 'B': ['method2', 'setter', 'method5'], |
| 'C': ['method1', 'getter'], |
| 'D': ['method2', 'setter'], |
| 'G': ['method1', 'getter'], |
| 'I': ['method1', 'getter'], |
| 'K': ['method1', 'getter'], |
| 'N': [], |
| 'P': ['method1', 'getter', 'setter'], |
| 'Q': ['method3'], |
| 'Class1a': ['call'], |
| 'Class1b': [], |
| 'Class2': ['c'], |
| }; |
| |
| KClosedWorld closedWorld = compiler.frontendClosedWorldForTesting; |
| ElementEnvironment elementEnvironment = closedWorld.elementEnvironment; |
| |
| elementEnvironment.forEachClass(elementEnvironment.mainLibrary, |
| (ClassEntity cls) { |
| List<String> expectedLiveMembers = |
| expectedLiveMembersMap[cls.name] ?? const <String>[]; |
| List<String> actualLiveMembers = <String>[]; |
| closedWorld.liveMemberUsage.forEach((MemberEntity member, _) { |
| if (member.enclosingClass != cls) return; |
| if (member.isConstructor) return; |
| actualLiveMembers.add(member.name); |
| }); |
| Expect.setEquals( |
| expectedLiveMembers, |
| actualLiveMembers, |
| "Unexpected live members for $cls. \n" |
| "Expected members for ${cls.name}: $expectedLiveMembers\n" |
| "Actual members for ${cls.name} : $actualLiveMembers"); |
| }); |
| } |