| 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 import "package:async_helper/async_helper.dart"; | 
|   11  |   11  | 
|   12 import 'memory_compiler.dart' show |   12 import 'memory_compiler.dart' show runCompiler; | 
|   13     runCompiler; |  | 
|   14  |   13  | 
|   15 import 'package:compiler/src/apiimpl.dart' show |   14 import 'package:compiler/src/apiimpl.dart' show CompilerImpl; | 
|   16     CompilerImpl; |  | 
|   17  |   15  | 
|   18 import 'package:compiler/src/constants/values.dart' show |   16 import 'package:compiler/src/constants/values.dart' | 
|   19     ConstantValue, |   17     show ConstantValue, TypeConstantValue; | 
|   20     TypeConstantValue; |  | 
|   21  |   18  | 
|   22 import 'package:compiler/src/elements/elements.dart' show |   19 import 'package:compiler/src/elements/elements.dart' show Element, Elements; | 
|   23     Element, |  | 
|   24     Elements; |  | 
|   25  |   20  | 
|   26 import 'package:compiler/src/js_backend/js_backend.dart' show |   21 import 'package:compiler/src/js_backend/js_backend.dart' show JavaScriptBackend; | 
|   27     JavaScriptBackend; |  | 
|   28  |   22  | 
|   29 import 'package:compiler/src/js_emitter/full_emitter/emitter.dart' |   23 import 'package:compiler/src/js_emitter/full_emitter/emitter.dart' as full | 
|   30     as full show Emitter; |   24     show Emitter; | 
|   31  |   25  | 
|   32 import 'package:compiler/src/old_to_new_api.dart' show |   26 import 'package:compiler/src/old_to_new_api.dart' | 
|   33     LegacyCompilerDiagnostics; |   27     show LegacyCompilerDiagnostics; | 
|   34  |   28  | 
|   35 void expectOnlyVerboseInfo(Uri uri, int begin, int end, String message, kind) { |   29 void expectOnlyVerboseInfo(Uri uri, int begin, int end, String message, kind) { | 
|   36   if (kind.name == 'verbose info') { |   30   if (kind.name == 'verbose info') { | 
|   37     print(message); |   31     print(message); | 
|   38     return; |   32     return; | 
|   39   } |   33   } | 
|   40   if (message.contains('methods retained for use by dart:mirrors out of')) { |   34   if (message.contains('methods retained for use by dart:mirrors out of')) { | 
|   41     print(message); |   35     print(message); | 
|   42     return; |   36     return; | 
|   43   } |   37   } | 
|   44   if (kind.name == 'info') return; |   38   if (kind.name == 'info') return; | 
|   45  |   39  | 
|   46   // TODO(aprelev@gmail.com): Remove once dartbug.com/13907 is fixed. |   40   // TODO(aprelev@gmail.com): Remove once dartbug.com/13907 is fixed. | 
|   47   if (message.contains("Warning: 'typedef' not allowed here")) return; |   41   if (message.contains("Warning: 'typedef' not allowed here")) return; | 
|   48  |   42  | 
|   49   throw '$uri:$begin:$end: $kind: $message'; |   43   throw '$uri:$begin:$end: $kind: $message'; | 
|   50 } |   44 } | 
|   51  |   45  | 
|   52 void main() { |   46 void main() { | 
|   53   asyncTest(() async { |   47   asyncTest(() async { | 
|   54     var result = await runCompiler( |   48     var result = await runCompiler( | 
|   55       memorySourceFiles: MEMORY_SOURCE_FILES, |   49         memorySourceFiles: MEMORY_SOURCE_FILES, | 
|   56       diagnosticHandler: new LegacyCompilerDiagnostics(expectOnlyVerboseInfo), |   50         diagnosticHandler: new LegacyCompilerDiagnostics(expectOnlyVerboseInfo), | 
|   57       options: ['--enable-experimental-mirrors']); |   51         options: ['--enable-experimental-mirrors']); | 
|   58     CompilerImpl compiler = result.compiler; |   52     CompilerImpl compiler = result.compiler; | 
|   59     print(''); |   53     print(''); | 
|   60     List generatedCode = |   54     List generatedCode = | 
|   61         Elements.sortedByPosition(compiler.enqueuer.codegen.processedEntities); |   55         Elements.sortedByPosition(compiler.enqueuer.codegen.processedEntities); | 
|   62     for (var element in generatedCode) { |   56     for (var element in generatedCode) { | 
|   63       print(element); |   57       print(element); | 
|   64     } |   58     } | 
|   65     print(''); |   59     print(''); | 
|   66  |   60  | 
|   67     // This assertion can fail for two reasons: |   61     // This assertion can fail for two reasons: | 
|   68     // 1. Too many elements retained for reflection. |   62     // 1. Too many elements retained for reflection. | 
|   69     // 2. Some code was refactored, and there are more methods. |   63     // 2. Some code was refactored, and there are more methods. | 
|   70     // Either situation could be problematic, but in situation 2, it is often |   64     // Either situation could be problematic, but in situation 2, it is often | 
|   71     // acceptable to increase [expectedMethodCount] a little. |   65     // acceptable to increase [expectedMethodCount] a little. | 
|   72     int expectedMethodCount = 466; |   66     int expectedMethodCount = 466; | 
|   73     Expect.isTrue( |   67     Expect.isTrue( | 
|   74         generatedCode.length <= expectedMethodCount, |   68         generatedCode.length <= expectedMethodCount, | 
|   75         'Too many compiled methods: ' |   69         'Too many compiled methods: ' | 
|   76         '${generatedCode.length} > $expectedMethodCount'); |   70         '${generatedCode.length} > $expectedMethodCount'); | 
|   77  |   71  | 
|   78     // The following names should be retained: |   72     // The following names should be retained: | 
|   79     List expectedNames = [ |   73     List expectedNames = [ | 
|   80         'Foo', // The name of class Foo. |   74       'Foo', // The name of class Foo. | 
|   81         r'Foo$', // The name of class Foo's constructor. |   75       r'Foo$', // The name of class Foo's constructor. | 
|   82         r'get$field']; // The (getter) name of Foo.field. |   76       r'get$field' | 
 |   77     ]; // The (getter) name of Foo.field. | 
|   83     // TODO(ahe): Check for the following names, currently they are not being |   78     // TODO(ahe): Check for the following names, currently they are not being | 
|   84     // recorded correctly, but are being emitted. |   79     // recorded correctly, but are being emitted. | 
|   85     [ |   80     [ | 
|   86         'Foo_staticMethod', // The name of Foo.staticMethod. |   81       'Foo_staticMethod', // The name of Foo.staticMethod. | 
|   87         r'instanceMethod$0']; // The name of Foo.instanceMethod. |   82       r'instanceMethod$0' | 
 |   83     ]; // The name of Foo.instanceMethod. | 
|   88  |   84  | 
|   89     // We always include the names of some native classes. |   85     // We always include the names of some native classes. | 
|   90     List<Element> nativeClasses = [ |   86     List<Element> nativeClasses = [ | 
|   91           compiler.coreClasses.intClass, |   87       compiler.coreClasses.intClass, | 
|   92           compiler.coreClasses.doubleClass, |   88       compiler.coreClasses.doubleClass, | 
|   93           compiler.coreClasses.numClass, |   89       compiler.coreClasses.numClass, | 
|   94           compiler.coreClasses.stringClass, |   90       compiler.coreClasses.stringClass, | 
|   95           compiler.coreClasses.boolClass, |   91       compiler.coreClasses.boolClass, | 
|   96           compiler.coreClasses.nullClass, |   92       compiler.coreClasses.nullClass, | 
|   97           compiler.coreClasses.listClass |   93       compiler.coreClasses.listClass | 
|   98         ]; |   94     ]; | 
|   99     JavaScriptBackend backend = compiler.backend; |   95     JavaScriptBackend backend = compiler.backend; | 
|  100     Iterable<String> nativeNames = nativeClasses.map(backend.namer.className); |   96     Iterable<String> nativeNames = nativeClasses.map(backend.namer.className); | 
|  101     expectedNames = expectedNames.map(backend.namer.asName).toList(); |   97     expectedNames = expectedNames.map(backend.namer.asName).toList(); | 
|  102     expectedNames.addAll(nativeNames); |   98     expectedNames.addAll(nativeNames); | 
|  103  |   99  | 
|  104     // Mirrors only work in the full emitter. We can thus be certain that the |  100     // Mirrors only work in the full emitter. We can thus be certain that the | 
|  105     // emitter is the full emitter. |  101     // emitter is the full emitter. | 
|  106     full.Emitter fullEmitter = backend.emitter.emitter; |  102     full.Emitter fullEmitter = backend.emitter.emitter; | 
|  107     Set recordedNames = new Set() |  103     Set recordedNames = new Set() | 
|  108         ..addAll(fullEmitter.recordedMangledNames) |  104       ..addAll(fullEmitter.recordedMangledNames) | 
|  109         ..addAll(fullEmitter.mangledFieldNames.keys) |  105       ..addAll(fullEmitter.mangledFieldNames.keys) | 
|  110         ..addAll(fullEmitter.mangledGlobalFieldNames.keys); |  106       ..addAll(fullEmitter.mangledGlobalFieldNames.keys); | 
|  111     Expect.setEquals(new Set.from(expectedNames), recordedNames); |  107     Expect.setEquals(new Set.from(expectedNames), recordedNames); | 
|  112  |  108  | 
|  113     for (var library in compiler.libraryLoader.libraries) { |  109     for (var library in compiler.libraryLoader.libraries) { | 
|  114       library.forEachLocalMember((member) { |  110       library.forEachLocalMember((member) { | 
|  115         if (library == compiler.mainApp && member.name == 'Foo') { |  111         if (library == compiler.mainApp && member.name == 'Foo') { | 
|  116           Expect.isTrue( |  112           Expect.isTrue( | 
|  117               compiler.backend.isAccessibleByReflection(member), '$member'); |  113               compiler.backend.isAccessibleByReflection(member), '$member'); | 
|  118           member.forEachLocalMember((classMember) { |  114           member.forEachLocalMember((classMember) { | 
|  119             Expect.isTrue( |  115             Expect.isTrue( | 
|  120                 compiler.backend.isAccessibleByReflection(classMember), |  116                 compiler.backend.isAccessibleByReflection(classMember), | 
|  121                 '$classMember'); |  117                 '$classMember'); | 
|  122           }); |  118           }); | 
|  123         } else { |  119         } else { | 
|  124           Expect.isFalse( |  120           Expect.isFalse( | 
|  125               compiler.backend.isAccessibleByReflection(member), '$member'); |  121               compiler.backend.isAccessibleByReflection(member), '$member'); | 
|  126         } |  122         } | 
|  127       }); |  123       }); | 
|  128     } |  124     } | 
|  129  |  125  | 
|  130     int metadataCount = 0; |  126     int metadataCount = 0; | 
|  131     Set<ConstantValue> compiledConstants = backend.constants.compiledConstants; |  127     Set<ConstantValue> compiledConstants = backend.constants.compiledConstants; | 
|  132     // Make sure that most of the metadata constants aren't included in the |  128     // Make sure that most of the metadata constants aren't included in the | 
|  133     // generated code. |  129     // generated code. | 
|  134     backend.processMetadata( |  130     backend.processMetadata(compiler.enqueuer.resolution.processedElements, | 
|  135         compiler.enqueuer.resolution.processedElements, (metadata) { |  131         (metadata) { | 
|  136       ConstantValue constant = |  132       ConstantValue constant = | 
|  137           backend.constants.getConstantValueForMetadata(metadata); |  133           backend.constants.getConstantValueForMetadata(metadata); | 
|  138       Expect.isFalse(compiledConstants.contains(constant), |  134       Expect.isFalse( | 
|  139                      constant.toStructuredText()); |  135           compiledConstants.contains(constant), constant.toStructuredText()); | 
|  140       metadataCount++; |  136       metadataCount++; | 
|  141     }); |  137     }); | 
|  142  |  138  | 
|  143     // There should at least be one metadata constant: |  139     // There should at least be one metadata constant: | 
|  144     // 1. The constructed constant for 'MirrorsUsed'. |  140     // 1. The constructed constant for 'MirrorsUsed'. | 
|  145     Expect.isTrue(metadataCount >= 1); |  141     Expect.isTrue(metadataCount >= 1); | 
|  146  |  142  | 
|  147     // The type literal 'Foo' is both used as metadata, and as a plain value in |  143     // The type literal 'Foo' is both used as metadata, and as a plain value in | 
|  148     // the program. Make sure that it isn't duplicated. |  144     // the program. Make sure that it isn't duplicated. | 
|  149     int fooConstantCount = 0; |  145     int fooConstantCount = 0; | 
|  150     for (ConstantValue constant in compiledConstants) { |  146     for (ConstantValue constant in compiledConstants) { | 
|  151       if (constant is TypeConstantValue && |  147       if (constant is TypeConstantValue && | 
|  152           '${constant.representedType}' == 'Foo') { |  148           '${constant.representedType}' == 'Foo') { | 
|  153         fooConstantCount++; |  149         fooConstantCount++; | 
|  154       } |  150       } | 
|  155     } |  151     } | 
|  156     Expect.equals( |  152     Expect.equals(1, fooConstantCount, | 
|  157         1, fooConstantCount, |  | 
|  158         "The type literal 'Foo' is duplicated or missing."); |  153         "The type literal 'Foo' is duplicated or missing."); | 
|  159   }); |  154   }); | 
|  160 } |  155 } | 
|  161  |  156  | 
|  162 const MEMORY_SOURCE_FILES = const <String, String> { |  157 const MEMORY_SOURCE_FILES = const <String, String>{ | 
|  163   'main.dart': """ |  158   'main.dart': """ | 
|  164 // The repeated constant value for symbols and targets used to crash dart2js in |  159 // The repeated constant value for symbols and targets used to crash dart2js in | 
|  165 // host-checked mode, and could potentially lead to other problems. |  160 // host-checked mode, and could potentially lead to other problems. | 
|  166 @MirrorsUsed(symbols: 'Foo', targets: 'Foo', override: '*') |  161 @MirrorsUsed(symbols: 'Foo', targets: 'Foo', override: '*') | 
|  167 import 'dart:mirrors'; |  162 import 'dart:mirrors'; | 
|  168  |  163  | 
|  169 import 'library.dart'; |  164 import 'library.dart'; | 
|  170  |  165  | 
|  171 class Foo { |  166 class Foo { | 
|  172   int field; |  167   int field; | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
|  185 library lib; |  180 library lib; | 
|  186  |  181  | 
|  187 import 'dart:mirrors'; |  182 import 'dart:mirrors'; | 
|  188  |  183  | 
|  189 useReflect(type) { |  184 useReflect(type) { | 
|  190   print(new Symbol('Foo')); |  185   print(new Symbol('Foo')); | 
|  191   print(MirrorSystem.getName(reflectClass(type).owner.qualifiedName)); |  186   print(MirrorSystem.getName(reflectClass(type).owner.qualifiedName)); | 
|  192 } |  187 } | 
|  193 """, |  188 """, | 
|  194 }; |  189 }; | 
| OLD | NEW |