| // Copyright (c) 2013, 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. |
| |
| /// Prints all information about all mirrors. This tests that it is possible to |
| /// enumerate all reflective information without crashing. |
| |
| // Note: Adding imports below is fine for regression tests. For example, |
| // 'crash_library_metadata.dart' is imported to ensure the compiler doesn't |
| // crash. |
| |
| // TODO(ahe): This test should be extended until we are sure all data is |
| // printed. |
| |
| library test.mirror_printer_test; |
| |
| @MirrorsUsed(targets: '*') |
| import 'dart:mirrors'; |
| |
| import 'crash_library_metadata.dart'; // This would crash dart2js. |
| |
| // Importing dart:html to make things interesting. |
| import 'dart:html'; |
| |
| class MirrorPrinter { |
| final StringBuffer buffer; |
| final TypeMirror dynamicType = currentMirrorSystem().dynamicType; |
| |
| int indentationLevel = 0; |
| |
| MirrorPrinter(this.buffer); |
| |
| void w(object) { |
| buffer.write(object); |
| } |
| |
| n(Symbol symbol) => MirrorSystem.getName(symbol); |
| |
| void indented(action) { |
| indentationLevel++; |
| action(); |
| indentationLevel--; |
| } |
| |
| get indent { |
| for (int i = 0; i < indentationLevel; i++) { |
| w(' '); |
| } |
| } |
| |
| String stringifyInstance(InstanceMirror mirror) { |
| var reflectee = mirror.reflectee; |
| if (reflectee is String) return '"${reflectee}"'; |
| if (reflectee is Null || |
| reflectee is bool || |
| reflectee is num || |
| reflectee is List || |
| reflectee is Map) { |
| return '$reflectee'; |
| } |
| StringBuffer buffer = new StringBuffer(); |
| Map<Symbol, DeclarationMirror> declarations = mirror.type.declarations; |
| buffer..write(n(mirror.type.simpleName))..write('('); |
| bool first = true; |
| declarations.forEach((Symbol name, DeclarationMirror declaration) { |
| if (declaration is! VariableMirror) return; |
| VariableMirror variable = declaration; |
| if (variable.isStatic) return; |
| // TODO(ahe): Include superclasses. |
| if (first) { |
| first = false; |
| } else { |
| buffer.write(', '); |
| } |
| buffer |
| ..write(n(name)) |
| ..write(': ') |
| ..write(stringifyInstance(mirror.getField(name))); |
| }); |
| buffer.write(')'); |
| return buffer.toString(); |
| } |
| |
| String stringifyMetadata(InstanceMirror mirror) { |
| return '@${stringifyInstance(mirror)}'; |
| } |
| |
| bool writeType(TypeMirror mirror) { |
| if (mirror == null || mirror == dynamicType) return false; |
| w('${n(mirror.simpleName)} '); |
| return true; |
| } |
| |
| writeVariable(VariableMirror mirror) { |
| bool needsVar = true; |
| if (mirror.isStatic) w('static '); |
| // TODO(ahe): What about const? |
| if (mirror.isFinal) { |
| w('final '); |
| needsVar = false; |
| } |
| |
| if (writeType(mirror.type)) needsVar = false; |
| |
| if (needsVar) { |
| w('var '); |
| } |
| w('${n(mirror.simpleName)};'); |
| } |
| |
| writeMethod(MethodMirror mirror) { |
| writeType(mirror.returnType); |
| if (mirror.isOperator) { |
| w('operator '); |
| } |
| if (mirror.isGetter) { |
| w('get '); |
| } |
| if (mirror.isSetter) { |
| w('set '); |
| } |
| w('${n(mirror.simpleName)}'); |
| if (!mirror.isGetter) { |
| w('()'); |
| } |
| w(';'); |
| } |
| |
| writeClass(ClassMirror mirror) { |
| // TODO(ahe): Write 'abstract' if [mirror] is abstract. |
| w('class ${n(mirror.simpleName)}'); |
| // TODO(ahe): Write superclass and interfaces. |
| w(' {'); |
| bool first = true; |
| indented(() { |
| for (DeclarationMirror declaration in mirror.declarations.values) { |
| if (first) { |
| first = false; |
| } else { |
| w('\n'); |
| } |
| writeDeclaration(declaration); |
| } |
| }); |
| w('\n}\n'); |
| } |
| |
| writeDeclaration(DeclarationMirror declaration) { |
| w('\n'); |
| var metadata = declaration.metadata; |
| if (!metadata.isEmpty) { |
| indent; |
| buffer.writeAll(metadata.map(stringifyMetadata), ' '); |
| w('\n'); |
| } |
| indent; |
| if (declaration is ClassMirror) { |
| writeClass(declaration); |
| } else if (declaration is VariableMirror) { |
| writeVariable(declaration); |
| } else if (declaration is MethodMirror) { |
| writeMethod(declaration); |
| } else { |
| // TODO(ahe): Test other subclasses of DeclarationMirror. |
| w('$declaration'); |
| } |
| } |
| |
| writeLibrary(LibraryMirror library) { |
| w('library ${n(library.simpleName)};\n\n'); |
| library.declarations.values |
| .where((d) => d is! TypeMirror) |
| .forEach(writeDeclaration); |
| w('\n'); |
| } |
| |
| static StringBuffer stringify(Map<Uri, LibraryMirror> libraries) { |
| StringBuffer buffer = new StringBuffer(); |
| libraries.values.forEach(new MirrorPrinter(buffer).writeLibrary); |
| return buffer; |
| } |
| } |
| |
| main() { |
| print(MirrorPrinter.stringify(currentMirrorSystem().libraries)); |
| // Clear the nodes to avoid confusing the fine test framework (by "fine" I |
| // mean something else) -- ahe. |
| document.body.nodes.clear(); |
| } |