Index: smoke/lib/mirrors.dart |
diff --git a/smoke/lib/mirrors.dart b/smoke/lib/mirrors.dart |
deleted file mode 100644 |
index a84f08177c49925ece145930523cabf2275aa627..0000000000000000000000000000000000000000 |
--- a/smoke/lib/mirrors.dart |
+++ /dev/null |
@@ -1,324 +0,0 @@ |
-// Copyright (c) 2014, 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. |
- |
-/// Implementation of the smoke services using mirrors. |
-library smoke.mirrors; |
- |
-import 'dart:mirrors'; |
-import 'package:smoke/smoke.dart'; |
-import 'package:logging/logging.dart'; |
-import 'src/common.dart'; |
- |
-/// Set up the smoke package to use a mirror-based implementation. To tune what |
-/// is preserved by `dart:mirrors`, use a @MirrorsUsed annotation and include |
-/// 'smoke.mirrors' in your override arguments. |
-useMirrors() { |
- configure(new ReflectiveObjectAccessorService(), |
- new ReflectiveTypeInspectorService(), |
- new ReflectiveSymbolConverterService()); |
-} |
- |
-var _logger = new Logger('smoke.mirrors'); |
- |
-/// Implements [ObjectAccessorService] using mirrors. |
-class ReflectiveObjectAccessorService implements ObjectAccessorService { |
- read(Object object, Symbol name) => reflect(object).getField(name).reflectee; |
- |
- void write(Object object, Symbol name, value) { |
- reflect(object).setField(name, value); |
- } |
- |
- invoke(receiver, Symbol methodName, List args, |
- {Map namedArgs, bool adjust: false}) { |
- var receiverMirror; |
- var method; |
- if (receiver is Type && methodName != #toString) { |
- receiverMirror = reflectType(receiver); |
- method = receiverMirror.declarations[methodName]; |
- } else { |
- receiverMirror = reflect(receiver); |
- method = _findMethod(receiverMirror.type, methodName); |
- } |
- if (method != null && adjust) { |
- var required = 0; |
- var optional = 0; |
- for (var p in method.parameters) { |
- if (p.isOptional) { |
- if (!p.isNamed) optional++; |
- } else { |
- required++; |
- } |
- } |
- args = adjustList(args, required, required + optional); |
- } |
- return receiverMirror.invoke(methodName, args, namedArgs).reflectee; |
- } |
-} |
- |
-/// Implements [TypeInspectorService] using mirrors. |
-class ReflectiveTypeInspectorService implements TypeInspectorService { |
- bool isSubclassOf(Type type, Type supertype) { |
- if (type == supertype || supertype == Object) return true; |
- // TODO(sigmund): change to mirror.isSubclassOf when it gets implemented in |
- // dart2js. (dartbug.com/12439) |
- var mirror = reflectClass(type); |
- var top = reflectClass(supertype); |
- while (mirror != _objectType) { |
- mirror = _safeSuperclass(mirror); |
- if (mirror == top) return true; |
- } |
- return false; |
- } |
- |
- bool hasGetter(Type type, Symbol name) { |
- var mirror = reflectType(type); |
- if (mirror is! ClassMirror) return false; |
- while (mirror != _objectType) { |
- final members = mirror.declarations; |
- if (members.containsKey(name)) return true; |
- mirror = _safeSuperclass(mirror); |
- } |
- return false; |
- } |
- |
- bool hasSetter(Type type, Symbol name) { |
- var mirror = reflectType(type); |
- if (mirror is! ClassMirror) return false; |
- var setterName = _setterName(name); |
- while (mirror != _objectType) { |
- final members = mirror.declarations; |
- var declaration = members[name]; |
- if (declaration is VariableMirror && !declaration.isFinal) return true; |
- if (members.containsKey(setterName)) return true; |
- mirror = _safeSuperclass(mirror); |
- } |
- return false; |
- } |
- |
- bool hasInstanceMethod(Type type, Symbol name) { |
- var mirror = reflectType(type); |
- if (mirror is! ClassMirror) return false; |
- while (mirror != _objectType) { |
- final m = mirror.declarations[name]; |
- if (m is MethodMirror && m.isRegularMethod && !m.isStatic) return true; |
- mirror = _safeSuperclass(mirror); |
- } |
- return false; |
- } |
- |
- bool hasStaticMethod(Type type, Symbol name) { |
- var mirror = reflectType(type); |
- if (mirror is! ClassMirror) return false; |
- final m = mirror.declarations[name]; |
- return m is MethodMirror && m.isRegularMethod && m.isStatic; |
- } |
- |
- Declaration getDeclaration(Type type, Symbol name) { |
- var mirror = reflectType(type); |
- if (mirror is! ClassMirror) return null; |
- |
- var declaration; |
- while (mirror != _objectType) { |
- final members = mirror.declarations; |
- if (members.containsKey(name)) { |
- declaration = members[name]; |
- break; |
- } |
- mirror = _safeSuperclass(mirror); |
- } |
- if (declaration == null) { |
- _logger.severe("declaration doesn't exists ($type.$name)."); |
- return null; |
- } |
- return new _MirrorDeclaration(mirror, declaration); |
- } |
- |
- List<Declaration> query(Type type, QueryOptions options) { |
- var mirror = reflectType(type); |
- if (mirror is! ClassMirror) return null; |
- return _query(mirror, options); |
- } |
- |
- List<Declaration> _query(ClassMirror cls, QueryOptions options) { |
- final visitParent = options.includeInherited && cls.superclass != null && |
- // TODO(sigmund): use _toType(cls.superclass) != options.includeUpTo |
- // when dartbug.com/16925 gets fixed (_toType fails in dart2js if |
- // applied to classes with type-arguments). |
- cls.superclass != reflectClass(options.includeUpTo); |
- var result = visitParent ? _query(cls.superclass, options) : []; |
- for (var member in cls.declarations.values) { |
- if (member is! VariableMirror && member is! MethodMirror) continue; |
- if (member.isStatic || member.isPrivate) continue; |
- var name = member.simpleName; |
- if (member is VariableMirror) { |
- if (!options.includeFields) continue; |
- if (options.excludeFinal && member.isFinal) continue; |
- } |
- |
- // TODO(sigmund): what if we have a setter but no getter? |
- if (member is MethodMirror && member.isSetter) continue; |
- if (member is MethodMirror && member.isConstructor) continue; |
- |
- if (member is MethodMirror && member.isGetter) { |
- if (!options.includeProperties) continue; |
- if (options.excludeFinal && !_hasSetter(cls, member)) continue; |
- } |
- |
- if (member is MethodMirror && member.isRegularMethod) { |
- if (!options.includeMethods) continue; |
- } |
- |
- if (options.matches != null && !options.matches(name)) continue; |
- |
- var annotations = member.metadata.map((m) => m.reflectee).toList(); |
- if (options.withAnnotations != null && |
- !matchesAnnotation(annotations, options.withAnnotations)) { |
- continue; |
- } |
- |
- var declaration = new _MirrorDeclaration(cls, member); |
- |
- if (options.excludeOverriden) { |
- result.retainWhere((value) => declaration.name != value.name); |
- } |
- |
- // TODO(sigmund): should we cache parts of this declaration so we don't |
- // compute them twice? For example, this chould be `new Declaration(name, |
- // type, ...)` and we could reuse what we computed above to implement the |
- // query filtering. Note, when I tried to eagerly compute everything, I |
- // run into trouble with type (`type = _toType(member.type)`), dart2js |
- // failed when the underlying types had type-arguments (see |
- // dartbug.com/16925). |
- result.add(declaration); |
- } |
- |
- return result; |
- } |
-} |
- |
-/// Implements [SymbolConverterService] using mirrors. |
-class ReflectiveSymbolConverterService implements SymbolConverterService { |
- String symbolToName(Symbol symbol) => MirrorSystem.getName(symbol); |
- Symbol nameToSymbol(String name) => new Symbol(name); |
-} |
- |
-// TODO(jmesserly): workaround for: |
-// https://code.google.com/p/dart/issues/detail?id=10029 |
-Symbol _setterName(Symbol getter) => |
- new Symbol('${MirrorSystem.getName(getter)}='); |
- |
-ClassMirror _safeSuperclass(ClassMirror type) { |
- try { |
- var t = type.superclass; |
- // TODO(sigmund): workaround for darbug.com/17779. |
- // Interceptor is leaked by dart2js. It has the same methods as Object |
- // (including noSuchMethod), and our code above assumes that it doesn't |
- // exist. Most queries exclude Object, so they should exclude Interceptor |
- // too. We don't check for t.simpleName == #Interceptor because depending on |
- // dart2js optimizations it may be #Interceptor or #num/Interceptor. |
- // Checking for a private library seems to reliably filter this out. |
- if (t != null && t.owner != null && t.owner.isPrivate) { |
- t = _objectType; |
- } |
- return t; |
- } on UnsupportedError catch (e) { |
- // Note: dart2js throws UnsupportedError when the type is not reflectable. |
- return _objectType; |
- } |
-} |
- |
-MethodMirror _findMethod(ClassMirror type, Symbol name) { |
- do { |
- var member = type.declarations[name]; |
- if (member is MethodMirror) return member; |
- type = type.superclass; |
- } while (type != null); |
- return null; |
-} |
- |
-// When recursively looking for symbols up the type-hierarchy it's generally a |
-// good idea to stop at Object, since we know it doesn't have what we want. |
-// TODO(jmesserly): This is also a workaround for what appears to be a V8 |
-// bug introduced between Chrome 31 and 32. After 32 |
-// JsClassMirror.declarations on Object calls |
-// JsClassMirror.typeVariables, which tries to get the _jsConstructor's |
-// .prototype["<>"]. This ends up getting the "" property instead, maybe |
-// because "<>" doesn't exist, and gets ";" which then blows up because |
-// the code later on expects a List of ints. |
-final _objectType = reflectClass(Object); |
- |
-bool _hasSetter(ClassMirror cls, MethodMirror getter) { |
- var mirror = cls.declarations[_setterName(getter.simpleName)]; |
- return mirror is MethodMirror && mirror.isSetter; |
-} |
- |
-Type _toType(TypeMirror t) { |
- // TODO(sigmund): this line can go away after dartbug.com/16962 |
- if (t == _objectType) return Object; |
- if (t is ClassMirror) return t.reflectedType; |
- if (t == null || t.qualifiedName != #dynamic) { |
- _logger.warning('unknown type ($t).'); |
- } |
- return dynamic; |
-} |
- |
-class _MirrorDeclaration implements Declaration { |
- final ClassMirror _cls; |
- final _original; |
- |
- _MirrorDeclaration(this._cls, DeclarationMirror this._original); |
- |
- Symbol get name => _original.simpleName; |
- |
- DeclarationKind get kind => isField ? FIELD : isProperty ? PROPERTY : METHOD; |
- |
- bool get isField => _original is VariableMirror; |
- |
- bool get isProperty => |
- _original is MethodMirror && !_original.isRegularMethod; |
- |
- bool get isMethod => !isField && !isProperty; |
- |
- /// If this is a property, whether it's read only (final fields or properties |
- /// with no setter). |
- bool get isFinal => (_original is VariableMirror && _original.isFinal) || |
- (_original is MethodMirror && |
- _original.isGetter && |
- !_hasSetter(_cls, _original)); |
- |
- /// If this is a property, it's declared type (including dynamic if it's not |
- /// declared). For methods, the returned type. |
- Type get type { |
- if (_original is MethodMirror && _original.isRegularMethod) { |
- return Function; |
- } |
- var typeMirror = |
- _original is VariableMirror ? _original.type : _original.returnType; |
- return _toType(typeMirror); |
- } |
- |
- /// Whether this symbol is static. |
- bool get isStatic => _original.isStatic; |
- |
- /// List of annotations in this declaration. |
- List get annotations => _original.metadata.map((a) => a.reflectee).toList(); |
- |
- int get hashCode => name.hashCode; |
- operator ==(other) => other is Declaration && |
- name == other.name && |
- kind == other.kind && |
- isFinal == other.isFinal && |
- type == other.type && |
- isStatic == other.isStatic && |
- compareLists(annotations, other.annotations); |
- String toString() => (new StringBuffer() |
- ..write('(mirror-based-declaration ') |
- ..write(name) |
- ..write( |
- isField ? ' (field) ' : (isProperty ? ' (property) ' : ' (method) ')) |
- ..write(isFinal ? 'final ' : '') |
- ..write(isStatic ? 'static ' : '') |
- ..write(annotations) |
- ..write(')')).toString(); |
-} |