Index: pkg/checked_mirrors/lib/checked_mirrors.dart |
diff --git a/pkg/checked_mirrors/lib/checked_mirrors.dart b/pkg/checked_mirrors/lib/checked_mirrors.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..91ccc30d7e7ce14363810b8ad7742344882116b9 |
--- /dev/null |
+++ b/pkg/checked_mirrors/lib/checked_mirrors.dart |
@@ -0,0 +1,443 @@ |
+// 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. |
+ |
+/// An implementation of dart:mirrors that checks if everything accessed through |
+/// reflection has been declared via the @MirrorUsed API. |
+/// |
+/// Usage: |
+/// |
+/// * Import `package:checked_mirrors/checked_mirrors.dart` instead of |
+/// `dart:mirrors`. |
+/// |
+/// * Move the @[MirrorsUsed] annotations to a top-level const symbol named |
+/// `checked_mirrors_workaround_for_10360`. This step is needed temporarily |
+/// until issue [10360](http://dartbug.com/10360) is fixed. |
+/// |
+/// * Add a transformer section to your pubspec to include a phase that will |
+/// remove the checks from this library when you deploy your application: |
+/// |
+/// transformers: |
+/// - checked_mirrors |
+ |
+library checked_mirrors; |
+ |
+// Except for top-level APIs, expose everything else. |
+export "dart:mirrors" hide currentMirrorSystem, reflect, reflectClass, |
+ reflectType, MirrorSystem; |
+ |
+import 'dart:async'; |
+import "dart:collection" show ListMixin; |
+import 'dart:isolate'; |
+import "dart:mirrors" as mirrors; |
+import "dart:mirrors" hide currentMirrorSystem, reflect, reflectClass, |
+ reflectType, MirrorSystem; |
+ |
+import 'src/checker.dart'; |
+ |
+/// An expando to store existing wrappers, since some APIs are expected to |
+/// return the same instance (at least according to the mirror tests). |
+Expando _wrappers = new Expando(); |
+ |
+/// Returns a wrapper for [original], an object from the base mirror system. We |
+/// internally try to store the wrapper in an expando to ensure we use the same |
+/// wrapper whenever it's possible. |
+_wrap(original) { |
+ if (original == null) return null; |
+ var value = _wrappers[original]; |
+ if (value != null) return value; |
+ value = _createWrapper(original); |
+ _wrappers[original] = value; |
+ return value; |
+} |
+ |
+/// Creates a wrapper for [original] assuming one doesn't exist already. The |
+/// wrapper will be a corresponding object in this library, for instance |
+/// _ClosureMirror for ClosureMirror. This function also wraps maps and lists |
+/// whose values are mirror system objects. |
+_createWrapper(original) { |
+ // Note: the order below is important to guarnatee we create the most precise |
+ // wrapper for a given type (e.g. FunctionTypeMirror is a ClassMirror too). |
+ |
+ if (original is Map) return new _MapWrapper(original); |
+ if (original is List) return new _ListWrapper(original); |
+ if (original is FunctionTypeMirror) return new _FunctionTypeMirror(original); |
+ if (original is ClassMirror) return new _ClassMirror(original); |
+ |
+ if (original is ClosureMirror) return new _ClosureMirror(original); |
+ if (original is InstanceMirror) return new _InstanceMirror(original); |
+ if (original is LibraryMirror) return new _LibraryMirror(original); |
+ if (original is ObjectMirror) return new _ObjectMirror(original); |
+ |
+ if (original is ParameterMirror) return new _ParameterMirror(original); |
+ if (original is VariableMirror) return new _VariableMirror(original); |
+ |
+ if (original is TypeVariableMirror) return new _TypeVariableMirror(original); |
+ if (original is IsolateMirror) return new _IsolateMirror(original); |
+ if (original is MethodMirror) return new _MethodMirror(original); |
+ if (original is mirrors.MirrorSystem) return new MirrorSystem(original); |
+ if (original is TypedefMirror) return new _TypedefMirror(original); |
+ |
+ if (original is TypeMirror) return new _TypeMirror(original); |
+ if (original is DeclarationMirror) return new _DeclarationMirror(original); |
+ throw "Unknown mirror type: ${original.runtimeType}"; |
+} |
+ |
+MirrorSystem _current = _wrap(mirrors.currentMirrorSystem()); |
+MirrorSystem currentMirrorSystem() => _current; |
+InstanceMirror reflect(Object reflectee) => _wrap(mirrors.reflect(reflectee)); |
+ClassMirror reflectClass(Type key) => _wrap(mirrors.reflectClass(key)); |
+TypeMirror reflectType(Type key) => _wrap(mirrors.reflectType(key)); |
+ |
+class _Mirror { |
+ dynamic _original; |
+ _Mirror(this._original); |
+ |
+ toString() => _original.toString(); |
+} |
+ |
+// We use the original name for this class because it exposes static methods |
+// that could be used externally. |
+// TODO(sigmund): technically the top-level symbols exposed here could be used |
+// too, like #LibraryMirror. Maybe we need to override the names of all these |
+// symbols? |
+class MirrorSystem extends _Mirror with mirrors.MirrorSystem { |
+ MirrorSystem(original) : super(original); |
+ |
+ Map<Uri, LibraryMirror> get libraries => _wrap(_original.libraries); |
+ |
+ IsolateMirror get isolate => _wrap(_original.isolate); |
+ |
+ TypeMirror get dynamicType => _wrap(_original.dynamicType); |
+ |
+ TypeMirror get voidType => _wrap(_original.voidType); |
+ |
+ static String getName(Symbol symbol) { |
+ checker.useSymbol(symbol); |
+ return mirrors.MirrorSystem.getName(symbol); |
+ } |
+ |
+ static Symbol getSymbol(String name, [LibraryMirror library]) { |
+ if (library == null) { |
+ var symbol = mirrors.MirrorSystem.getSymbol(name); |
+ checker.useSymbol(symbol); |
+ return symbol; |
+ } |
+ if (library is! _LibraryMirror) { |
+ throw new ArgumentError("$library is not a LibraryMirror"); |
+ } |
+ _LibraryMirror lib = library; // type-check |
+ var symbol = mirrors.MirrorSystem.getSymbol(name, lib._original); |
+ checker.useSymbol(symbol); |
+ return symbol; |
+ } |
+} |
+ |
+class _IsolateMirror extends _Mirror implements mirrors.IsolateMirror { |
+ _IsolateMirror(original) : super(original); |
+ |
+ String get debugName => _original.debugName; |
+ bool get isCurrent => _original.isCurrent; |
+ LibraryMirror get rootLibrary => _wrap(_original.rootLibrary); |
+ bool operator == (other) { |
+ if (other == null || other is! _IsolateMirror) return false; |
+ return _original == other._original; |
+ } |
+ int get hashCode => _original.hashCode; |
+} |
+ |
+abstract class _DeclarationMirrorMixin implements mirrors.DeclarationMirror { |
+ get _original; |
+ Symbol get simpleName => _original.simpleName; |
+ Symbol get qualifiedName => _original.qualifiedName; |
+ DeclarationMirror get owner => _wrap(_original.owner); |
+ bool get isPrivate => _original.isPrivate; |
+ bool get isTopLevel => _original.isTopLevel; |
+ SourceLocation get location => _original.location; |
+ List<InstanceMirror> get metadata => _wrap(_original.metadata); |
+} |
+ |
+class _DeclarationMirror extends _Mirror with _DeclarationMirrorMixin |
+ implements mirrors.DeclarationMirror { |
+ _DeclarationMirror(original) : super(original); |
+ get _original => super._original; // to get rid of static warnings |
+ |
+} |
+ |
+abstract class _ObjectMirrorMixin implements mirrors.ObjectMirror { |
+ get _original; |
+ |
+ InstanceMirror invoke(Symbol memberName, |
+ List positionalArguments, |
+ [Map<Symbol,dynamic> namedArguments]) => |
+ _wrap(_original.invoke(memberName, positionalArguments, namedArguments)); |
+ |
+ InstanceMirror getField(Symbol fieldName) { |
+ checker.access(_original, fieldName); |
+ return _wrap(_original.getField(fieldName)); |
+ } |
+ |
+ InstanceMirror setField(Symbol fieldName, Object value) { |
+ checker.access(_original, fieldName); |
+ return _wrap(_original.setField(fieldName, value)); |
+ } |
+} |
+ |
+class _ObjectMirror extends _Mirror with _ObjectMirrorMixin |
+ implements mirrors.ObjectMirror { |
+ _ObjectMirror(original) : super(original); |
+ get _original => super._original; // to get rid of static warnings |
+} |
+ |
+class _InstanceMirror extends _ObjectMirror implements mirrors.InstanceMirror { |
+ _InstanceMirror(original) : super(original); |
+ |
+ ClassMirror get type => _wrap(_original.type); |
+ bool get hasReflectee => _original.hasReflectee; |
+ get reflectee => _original.reflectee; |
+ bool operator == (other) { |
+ if (other == null || other is! _InstanceMirror) return false; |
+ return _original == other._original; |
+ } |
+ int get hashCode => _original.hashCode; |
+ |
+ delegate(Invocation invocation) => _original.delegate(invocation); |
+ Function operator [](Symbol name) { |
+ print('warning: this cannot be debugged: InstanceMirror.operator[]'); |
+ // TODO(sigmund): we'd like to wrap the result inside the function, but we |
+ // don't have a way to dynamically take arguments. |
+ return _original[name]; |
+ } |
+} |
+ |
+class _ClosureMirror extends _InstanceMirror implements mirrors.ClosureMirror { |
+ _ClosureMirror(original) : super(original); |
+ |
+ MethodMirror get function => _wrap(_original.function); |
+ InstanceMirror apply(List positionalArguments, |
+ [Map<Symbol, dynamic> namedArguments]) => |
+ _wrap(_original.apply(positionalArguments, namedArguments)); |
+ InstanceMirror findInContext(Symbol name, {ifAbsent: null}) => |
+ _wrap(_original.findInContext(name, ifAbsent: ifAbsent)); |
+} |
+ |
+class _LibraryMirror extends _DeclarationMirror with _ObjectMirrorMixin |
+ implements mirrors.LibraryMirror { |
+ _LibraryMirror(original) : super(original); |
+ get _original => super._original; // to get rid of static warnings |
+ |
+ Uri get uri => _original.uri; |
+ Map<Symbol, DeclarationMirror> get declarations => |
+ _wrap(_original.declarations); |
+ |
+ Map<Symbol, MethodMirror> get topLevelMembers => |
+ _wrap(_original.topLevelMembers); |
+ |
+ bool operator == (other) { |
+ if (other == null || other is! _LibraryMirror) return false; |
+ return _original == other._original; |
+ } |
+ int get hashCode => _original.hashCode; |
+ |
+ Function operator [](Symbol name) { |
+ print('warning: this cannot be debugged: LibraryMirror.operator[]'); |
+ // TODO(sigmund): we'd like to wrap the result inside the function, but we |
+ // don't have a way to dynamically take arguments. |
+ return _original[name]; |
+ } |
+} |
+ |
+class _TypeMirror extends _DeclarationMirror implements mirrors.TypeMirror { |
+ _TypeMirror(original) : super(original); |
+ |
+ List<TypeVariableMirror> get typeVariables => |
+ _wrap(_original.typeVariables); |
+ List<TypeMirror> get typeArguments => |
+ _wrap(_original.typeArguments); |
+ bool get isOriginalDeclaration => _original.isOriginalDeclaration; |
+ TypeMirror get originalDeclaration => |
+ _wrap(_original.originalDeclaration); |
+ |
+ bool operator == (other) { |
+ if (other == null || other is! _TypeMirror) return false; |
+ return _original == other._original; |
+ } |
+ int get hashCode => _original.hashCode; |
+} |
+ |
+class _ClassMirror extends _TypeMirror with _ObjectMirrorMixin |
+ implements ClassMirror { |
+ _ClassMirror(original) : super(original); |
+ |
+ bool get hasReflectedType => _original.hasReflectedType; |
+ Type get reflectedType => _original.reflectedType; |
+ ClassMirror get superclass => _wrap(_original.superclass); |
+ List<ClassMirror> get superinterfaces => |
+ _wrap(_original.superinterfaces); |
+ |
+ Map<Symbol, DeclarationMirror> get declarations => |
+ _wrap(_original.declarations); |
+ Map<Symbol, MethodMirror> get instanceMembers => |
+ _wrap(_original.instanceMembers); |
+ Map<Symbol, MethodMirror> get staticMembers => |
+ _wrap(_original.staticMembers); |
+ ClassMirror get mixin => _wrap(_original.mixin); |
+ InstanceMirror newInstance(Symbol constructorName, |
+ List positionalArguments, |
+ [Map<Symbol,dynamic> namedArguments]) => |
+ _wrap(_original.newInstance(constructorName, |
+ positionalArguments, namedArguments)); |
+ |
+ bool operator == (other) { |
+ if (other == null || other is! _ClassMirror) return false; |
+ return _original == other._original; |
+ } |
+ int get hashCode => _original.hashCode; |
+ |
+ Function operator [](Symbol name) { |
+ print('warning: this cannot be debugged: ClassMirror.operator[]'); |
+ // TODO(sigmund): we'd like to wrap the result inside the function, but we |
+ // don't have a way to dynamically take arguments. |
+ return _original[name]; |
+ } |
+} |
+ |
+class _FunctionTypeMirror extends _ClassMirror implements FunctionTypeMirror { |
+ _FunctionTypeMirror(original) : super(original); |
+ get _original => super._original; // to get rid of static warnings |
+ |
+ TypeMirror get returnType => _wrap(_original.returnType); |
+ List<ParameterMirror> get parameters => |
+ _wrap(_original.parameters); |
+ MethodMirror get callMethod => _wrap(_original.callMethod); |
+} |
+ |
+class _TypeVariableMirror extends _TypeMirror implements TypeVariableMirror { |
+ _TypeVariableMirror(original) : super(original); |
+ |
+ TypeMirror get upperBound => _wrap(_original.upperBound); |
+ bool get isStatic => _original.isStatic; |
+ bool operator == (other) { |
+ if (other == null || other is! _TypeVariableMirror) return false; |
+ return _original == other._original; |
+ } |
+ int get hashCode => _original.hashCode; |
+} |
+ |
+class _TypedefMirror extends _TypeMirror implements TypedefMirror { |
+ _TypedefMirror(original) : super(original); |
+ |
+ FunctionTypeMirror get referent => _wrap(_original.referent); |
+} |
+ |
+class _MethodMirror extends _DeclarationMirror implements MethodMirror { |
+ _MethodMirror(original) : super(original); |
+ |
+ TypeMirror get returnType => _wrap(_original.returnType); |
+ String get source => _original.source; |
+ List<ParameterMirror> get parameters => |
+ _wrap(_original.parameters); |
+ bool get isStatic => _original.isStatic; |
+ bool get isAbstract => _original.isAbstract; |
+ bool get isSynthetic => _original.isSynthetic; |
+ bool get isRegularMethod => _original.isRegularMethod; |
+ bool get isOperator => _original.isOperator; |
+ bool get isGetter => _original.isGetter; |
+ bool get isSetter => _original.isSetter; |
+ bool get isConstructor => _original.isConstructor; |
+ Symbol get constructorName => _original.constructorName; |
+ bool get isConstConstructor => _original.isConstConstructor; |
+ bool get isGenerativeConstructor => _original.isGenerativeConstructor; |
+ bool get isRedirectingConstructor => _original.isRedirectingConstructor; |
+ bool get isFactoryConstructor => _original.isFactoryConstructor; |
+ bool operator == (other) { |
+ if (other == null || other is! _MethodMirror) return false; |
+ return _original == other._original; |
+ } |
+ int get hashCode => _original.hashCode; |
+} |
+ |
+class _VariableMirror extends _DeclarationMirror implements VariableMirror { |
+ _VariableMirror(original) : super(original); |
+ TypeMirror get type => _wrap(_original.type); |
+ bool get isStatic => _original.isStatic; |
+ bool get isFinal => _original.isFinal; |
+ bool get isConst => _original.isConst; |
+ bool operator == (other) { |
+ if (other == null || other is! _VariableMirror) return false; |
+ return _original == other._original; |
+ } |
+ int get hashCode => _original.hashCode; |
+} |
+ |
+class _ParameterMirror extends _VariableMirror implements ParameterMirror { |
+ _ParameterMirror(original) : super(original); |
+ TypeMirror get type => _wrap(_original.type); |
+ bool get isOptional => _original.isOptional; |
+ bool get isNamed => _original.isNamed; |
+ bool get hasDefaultValue => _original.hasDefaultValue; |
+ InstanceMirror get defaultValue => _original.defaultValue; |
+} |
+ |
+/// Wraps a map that contains mirror values |
+class _MapWrapper<K, V extends _Mirror> implements Map<K, V> { |
+ Map<K, V> _original; |
+ _MapWrapper(Map<K, V> original) : _original = original; |
+ |
+ V operator [](Object key) => _wrap(_original[key]); |
+ |
+ void operator []=(K key, V value) { |
+ _original[key] = value._original; |
+ } |
+ |
+ void addAll(Map<K, V> other) { |
+ other.forEach((key, value) { _original[key] = value; }); |
+ } |
+ |
+ bool containsValue(Object value) => |
+ _original.containsValue(value != null && (value as dynamic)._original); |
+ |
+ V putIfAbsent(K key, V ifAbsent()) => |
+ _original.putIfAbsent(key, () => ifAbsent()._original); |
+ |
+ // Every other method is just delegated to the original |
+ |
+ Iterable<V> get values => _original.values.map(_wrap); |
+ |
+ void clear() => _original.clear(); |
+ |
+ bool containsKey(Object key) => _original.containsKey(key); |
+ |
+ void forEach(void f(K key, V value)) { |
+ _original.forEach(f); |
+ } |
+ |
+ bool get isEmpty => _original.isEmpty; |
+ |
+ bool get isNotEmpty => _original.isNotEmpty; |
+ |
+ Iterable<K> get keys => _original.keys; |
+ |
+ int get length => _original.length; |
+ |
+ V remove(Object key) => _original.remove(key); |
+} |
+ |
+/// Wraps a list of mirror values |
+class _ListWrapper<E extends _Mirror> extends Object with ListMixin<E> { |
+ List _original; |
+ |
+ _ListWrapper(this._original); |
+ |
+ E operator [](int index) => _wrap(_original[index]); |
+ |
+ void operator []=(int index, E value) { |
+ _original[index] = value._original; |
+ } |
+ |
+ int get length => _original.length; |
+ |
+ void set length(int newLength) { |
+ _original.length = newLength; |
+ } |
+} |