OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// Test that the @MirrorsUsed annotation suppress hints and that only | 5 /// Test that the @MirrorsUsed annotation suppress hints and that only |
6 /// requested elements are retained for reflection. | 6 /// requested elements are retained for reflection. |
7 library dart2js.test.mirrors_used_test; | 7 library dart2js.test.mirrors_used_test; |
8 | 8 |
9 import 'package:expect/expect.dart'; | 9 import 'package:expect/expect.dart'; |
| 10 import "package:async_helper/async_helper.dart"; |
10 | 11 |
11 import 'memory_compiler.dart' show | 12 import 'memory_compiler.dart' show |
12 compilerFor; | 13 compilerFor; |
13 | 14 |
14 import '../../../sdk/lib/_internal/compiler/implementation/apiimpl.dart' show | 15 import '../../../sdk/lib/_internal/compiler/implementation/apiimpl.dart' show |
15 Compiler; | 16 Compiler; |
16 | 17 |
17 import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart' show | 18 import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart' show |
18 Constant, | 19 Constant, |
19 SourceString, | 20 SourceString, |
20 TypeConstant; | 21 TypeConstant; |
21 | 22 |
22 import | 23 import |
23 '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart' | 24 '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart' |
24 show | 25 show |
25 Elements; | 26 Elements; |
26 | 27 |
27 void expectOnlyVerboseInfo(Uri uri, int begin, int end, String message, kind) { | 28 void expectOnlyVerboseInfo(Uri uri, int begin, int end, String message, kind) { |
28 if (kind.name == 'verbose info') { | 29 if (kind.name == 'verbose info') { |
29 print(message); | 30 print(message); |
30 return; | 31 return; |
31 } | 32 } |
32 throw '$uri:$begin:$end: $kind: $message'; | 33 throw '$uri:$begin:$end: $kind: $message'; |
33 } | 34 } |
34 | 35 |
35 void main() { | 36 void main() { |
36 Compiler compiler = compilerFor( | 37 Compiler compiler = compilerFor( |
37 MEMORY_SOURCE_FILES, diagnosticHandler: expectOnlyVerboseInfo); | 38 MEMORY_SOURCE_FILES, diagnosticHandler: expectOnlyVerboseInfo); |
38 compiler.runCompiler(Uri.parse('memory:main.dart')); | 39 asyncTest(() => compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) { |
| 40 print(''); |
| 41 List generatedCode = |
| 42 Elements.sortedByPosition(compiler.enqueuer.codegen.generatedCode.keys); |
| 43 for (var element in generatedCode) { |
| 44 print(element); |
| 45 } |
| 46 print(''); |
39 | 47 |
40 print(''); | 48 // This assertion can fail for two reasons: |
41 List generatedCode = | 49 // 1. Too many elements retained for reflection. |
42 Elements.sortedByPosition(compiler.enqueuer.codegen.generatedCode.keys); | 50 // 2. Some code was refactored, and there are more methods. |
43 for (var element in generatedCode) { | 51 // Either situation could be problematic, but in situation 2, it is often |
44 print(element); | 52 // acceptable to increase [expectedMethodCount] a little. |
45 } | 53 int expectedMethodCount = 322; |
46 print(''); | 54 Expect.isTrue( |
| 55 generatedCode.length <= expectedMethodCount, |
| 56 'Too many compiled methods: ' |
| 57 '${generatedCode.length} > $expectedMethodCount'); |
47 | 58 |
48 // This assertion can fail for two reasons: | 59 // The following names should be retained: |
49 // 1. Too many elements retained for reflection. | 60 List expectedNames = [ |
50 // 2. Some code was refactored, and there are more methods. | 61 'Foo', // The name of class Foo. |
51 // Either situation could be problematic, but in situation 2, it is often | 62 r'Foo$', // The name of class Foo's constructor. |
52 // acceptable to increase [expectedMethodCount] a little. | 63 'Foo_staticMethod', // The name of Foo.staticMethod. |
53 int expectedMethodCount = 322; | 64 r'get$field', // The (getter) name of Foo.field. |
54 Expect.isTrue( | 65 r'instanceMethod$0']; // The name of Foo.instanceMethod. |
55 generatedCode.length <= expectedMethodCount, | 66 Set recordedNames = new Set() |
56 'Too many compiled methods: ' | 67 ..addAll(compiler.backend.emitter.recordedMangledNames) |
57 '${generatedCode.length} > $expectedMethodCount'); | 68 ..addAll(compiler.backend.emitter.mangledFieldNames.keys) |
| 69 ..addAll(compiler.backend.emitter.mangledGlobalFieldNames.keys); |
| 70 Expect.setEquals(new Set.from(expectedNames), recordedNames); |
58 | 71 |
59 // The following names should be retained: | 72 for (var library in compiler.libraries.values) { |
60 List expectedNames = [ | 73 library.forEachLocalMember((member) { |
61 'Foo', // The name of class Foo. | 74 if (library == compiler.mainApp |
62 r'Foo$', // The name of class Foo's constructor. | 75 && member.name == const SourceString('Foo')) { |
63 'Foo_staticMethod', // The name of Foo.staticMethod. | 76 Expect.isTrue( |
64 r'get$field', // The (getter) name of Foo.field. | 77 compiler.backend.isNeededForReflection(member), '$member'); |
65 r'instanceMethod$0']; // The name of Foo.instanceMethod. | 78 member.forEachLocalMember((classMember) { |
66 Set recordedNames = new Set() | 79 Expect.isTrue( |
67 ..addAll(compiler.backend.emitter.recordedMangledNames) | 80 compiler.backend.isNeededForReflection(classMember), |
68 ..addAll(compiler.backend.emitter.mangledFieldNames.keys) | 81 '$classMember'); |
69 ..addAll(compiler.backend.emitter.mangledGlobalFieldNames.keys); | 82 }); |
70 Expect.setEquals(new Set.from(expectedNames), recordedNames); | 83 } else { |
| 84 Expect.isFalse( |
| 85 compiler.backend.isNeededForReflection(member), '$member'); |
| 86 } |
| 87 }); |
| 88 } |
71 | 89 |
72 for (var library in compiler.libraries.values) { | 90 // There should at least be three metadata constants: |
73 library.forEachLocalMember((member) { | 91 // 1. The type literal 'Foo'. |
74 if (library == compiler.mainApp | 92 // 2. The list 'const [Foo]'. |
75 && member.name == const SourceString('Foo')) { | 93 // 3. The constructed constant for 'MirrorsUsed'. |
76 Expect.isTrue( | 94 Expect.isTrue(compiler.metadataHandler.compiledConstants.length >= 3); |
77 compiler.backend.isNeededForReflection(member), '$member'); | 95 |
78 member.forEachLocalMember((classMember) { | 96 // Make sure that most of the metadata constants aren't included in the |
79 Expect.isTrue( | 97 // generated code. |
80 compiler.backend.isNeededForReflection(classMember), | 98 for (Constant constant in compiler.metadataHandler.compiledConstants) { |
81 '$classMember'); | 99 if (constant is TypeConstant && '${constant.representedType}' == 'Foo') { |
82 }); | 100 // The type literal 'Foo' is retained as a constant because it is being |
83 } else { | 101 // passed to reflectClass. |
84 Expect.isFalse( | 102 continue; |
85 compiler.backend.isNeededForReflection(member), '$member'); | |
86 } | 103 } |
87 }); | 104 Expect.isFalse( |
88 } | 105 compiler.constantHandler.compiledConstants.contains(constant), |
| 106 '$constant'); |
| 107 } |
89 | 108 |
90 // There should at least be three metadata constants: | 109 // The type literal 'Foo' is both used as metadata, and as a plain value in |
91 // 1. The type literal 'Foo'. | 110 // the program. Make sure that it isn't duplicated. |
92 // 2. The list 'const [Foo]'. | 111 int fooConstantCount = 0; |
93 // 3. The constructed constant for 'MirrorsUsed'. | 112 for (Constant constant in compiler.metadataHandler.compiledConstants) { |
94 Expect.isTrue(compiler.metadataHandler.compiledConstants.length >= 3); | 113 if (constant is TypeConstant && '${constant.representedType}' == 'Foo') { |
95 | 114 fooConstantCount++; |
96 // Make sure that most of the metadata constants aren't included in the | 115 } |
97 // generated code. | |
98 for (Constant constant in compiler.metadataHandler.compiledConstants) { | |
99 if (constant is TypeConstant && '${constant.representedType}' == 'Foo') { | |
100 // The type literal 'Foo' is retained as a constant because it is being | |
101 // passed to reflectClass. | |
102 continue; | |
103 } | 116 } |
104 Expect.isFalse( | 117 Expect.equals( |
105 compiler.constantHandler.compiledConstants.contains(constant), | 118 1, fooConstantCount, |
106 '$constant'); | 119 "The type literal 'Foo' is duplicated or missing."); |
107 } | 120 })); |
108 | |
109 // The type literal 'Foo' is both used as metadata, and as a plain value in | |
110 // the program. Make sure that it isn't duplicated. | |
111 int fooConstantCount = 0; | |
112 for (Constant constant in compiler.metadataHandler.compiledConstants) { | |
113 if (constant is TypeConstant && '${constant.representedType}' == 'Foo') { | |
114 fooConstantCount++; | |
115 } | |
116 } | |
117 Expect.equals( | |
118 1, fooConstantCount, "The type literal 'Foo' is duplicated or missing."); | |
119 } | 121 } |
120 | 122 |
121 const MEMORY_SOURCE_FILES = const <String, String> { | 123 const MEMORY_SOURCE_FILES = const <String, String> { |
122 'main.dart': """ | 124 'main.dart': """ |
123 @MirrorsUsed(targets: const [Foo], override: '*') | 125 @MirrorsUsed(targets: const [Foo], override: '*') |
124 import 'dart:mirrors'; | 126 import 'dart:mirrors'; |
125 | 127 |
126 import 'library.dart'; | 128 import 'library.dart'; |
127 | 129 |
128 class Foo { | 130 class Foo { |
(...skipping 13 matching lines...) Expand all Loading... |
142 library lib; | 144 library lib; |
143 | 145 |
144 import 'dart:mirrors'; | 146 import 'dart:mirrors'; |
145 | 147 |
146 useReflect(type) { | 148 useReflect(type) { |
147 print(new Symbol('Foo')); | 149 print(new Symbol('Foo')); |
148 print(MirrorSystem.getName(reflectClass(type).owner.qualifiedName)); | 150 print(MirrorSystem.getName(reflectClass(type).owner.qualifiedName)); |
149 } | 151 } |
150 """, | 152 """, |
151 }; | 153 }; |
OLD | NEW |