| Index: sdk/lib/_internal/lib/js_mirrors.dart
|
| diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
|
| deleted file mode 100644
|
| index 70f37ea7214b51fba374511f1ac68b3fc030490d..0000000000000000000000000000000000000000
|
| --- a/sdk/lib/_internal/lib/js_mirrors.dart
|
| +++ /dev/null
|
| @@ -1,2931 +0,0 @@
|
| -// 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.
|
| -
|
| -library dart._js_mirrors;
|
| -
|
| -import '../compiler/implementation/runtime_data.dart' as encoding;
|
| -
|
| -import 'dart:collection' show
|
| - UnmodifiableListView,
|
| - UnmodifiableMapView;
|
| -
|
| -import 'dart:mirrors';
|
| -
|
| -import 'dart:_foreign_helper' show
|
| - JS,
|
| - JS_CURRENT_ISOLATE,
|
| - JS_CURRENT_ISOLATE_CONTEXT,
|
| - JS_GET_NAME;
|
| -
|
| -import 'dart:_internal' as _symbol_dev;
|
| -
|
| -import 'dart:_js_helper' show
|
| - BoundClosure,
|
| - CachedInvocation,
|
| - Closure,
|
| - JSInvocationMirror,
|
| - JsCache,
|
| - Null,
|
| - Primitives,
|
| - ReflectionInfo,
|
| - RuntimeError,
|
| - TearOffClosure,
|
| - TypeVariable,
|
| - UnimplementedNoSuchMethodError,
|
| - createRuntimeType,
|
| - createUnmangledInvocationMirror,
|
| - getMangledTypeName,
|
| - getMetadata,
|
| - getRuntimeType,
|
| - runtimeTypeToString,
|
| - setRuntimeTypeInfo,
|
| - throwInvalidReflectionError;
|
| -
|
| -import 'dart:_interceptors' show
|
| - Interceptor,
|
| - JSArray,
|
| - JSExtendableArray,
|
| - getInterceptor;
|
| -
|
| -import 'dart:_js_names';
|
| -
|
| -const String METHODS_WITH_OPTIONAL_ARGUMENTS = r'$methodsWithOptionalArguments';
|
| -
|
| -bool hasReflectableProperty(var jsFunction) {
|
| - return JS('bool', '# in #', JS_GET_NAME("REFLECTABLE"), jsFunction);
|
| -}
|
| -
|
| -/// No-op method that is called to inform the compiler that tree-shaking needs
|
| -/// to be disabled.
|
| -disableTreeShaking() => preserveNames();
|
| -
|
| -/// No-op method that is called to inform the compiler that metadata must be
|
| -/// preserved at runtime.
|
| -preserveMetadata() {}
|
| -
|
| -/// No-op method that is called to inform the compiler that the compiler must
|
| -/// preserve the URIs.
|
| -preserveUris() {}
|
| -
|
| -/// No-op method that is called to inform the compiler that the compiler must
|
| -/// preserve the library names.
|
| -preserveLibraryNames() {}
|
| -
|
| -String getName(Symbol symbol) {
|
| - preserveNames();
|
| - return n(symbol);
|
| -}
|
| -
|
| -class JsMirrorSystem implements MirrorSystem {
|
| - UnmodifiableMapView<Uri, LibraryMirror> _cachedLibraries;
|
| -
|
| - final IsolateMirror isolate = new JsIsolateMirror();
|
| -
|
| - JsTypeMirror get dynamicType => _dynamicType;
|
| - JsTypeMirror get voidType => _voidType;
|
| -
|
| - static final JsTypeMirror _dynamicType =
|
| - new JsTypeMirror(const Symbol('dynamic'));
|
| - static final JsTypeMirror _voidType = new JsTypeMirror(const Symbol('void'));
|
| -
|
| - static final Map<String, List<LibraryMirror>> librariesByName =
|
| - computeLibrariesByName();
|
| -
|
| - Map<Uri, LibraryMirror> get libraries {
|
| - if (_cachedLibraries != null) return _cachedLibraries;
|
| - Map<Uri, LibraryMirror> result = new Map();
|
| - for (List<LibraryMirror> list in librariesByName.values) {
|
| - for (LibraryMirror library in list) {
|
| - result[library.uri] = library;
|
| - }
|
| - }
|
| - return _cachedLibraries =
|
| - new UnmodifiableMapView<Uri, LibraryMirror>(result);
|
| - }
|
| -
|
| - LibraryMirror findLibrary(Symbol libraryName) {
|
| - return librariesByName[n(libraryName)].single;
|
| - }
|
| -
|
| - static Map<String, List<LibraryMirror>> computeLibrariesByName() {
|
| - disableTreeShaking();
|
| - var result = new Map<String, List<LibraryMirror>>();
|
| - var jsLibraries = JS('JSExtendableArray|Null', 'init.libraries');
|
| - if (jsLibraries == null) return result;
|
| - for (List data in jsLibraries) {
|
| - String name = data[0];
|
| - Uri uri = Uri.parse(data[1]);
|
| - List<String> classes = data[2];
|
| - List<String> functions = data[3];
|
| - var metadataFunction = data[4];
|
| - var fields = data[5];
|
| - bool isRoot = data[6];
|
| - var globalObject = data[7];
|
| - List metadata = (metadataFunction == null)
|
| - ? const [] : JS('List', '#()', metadataFunction);
|
| - var libraries = result.putIfAbsent(name, () => <LibraryMirror>[]);
|
| - libraries.add(
|
| - new JsLibraryMirror(
|
| - s(name), uri, classes, functions, metadata, fields, isRoot,
|
| - globalObject));
|
| - }
|
| - return result;
|
| - }
|
| -}
|
| -
|
| -abstract class JsMirror implements Mirror {
|
| - const JsMirror();
|
| -
|
| - String get _prettyName;
|
| -
|
| - String toString() => _prettyName;
|
| -
|
| - // TODO(ahe): Remove this method from the API.
|
| - MirrorSystem get mirrors => currentJsMirrorSystem;
|
| -
|
| - _getField(JsMirror receiver) {
|
| - throw new UnimplementedError();
|
| - }
|
| -
|
| - void _setField(JsMirror receiver, Object arg) {
|
| - throw new UnimplementedError();
|
| - }
|
| -
|
| - _loadField(String name) {
|
| - throw new UnimplementedError();
|
| - }
|
| -
|
| - void _storeField(String name, Object arg) {
|
| - throw new UnimplementedError();
|
| - }
|
| -}
|
| -
|
| -// This class is somewhat silly in the current implementation.
|
| -class JsIsolateMirror extends JsMirror implements IsolateMirror {
|
| - final _isolateContext = JS_CURRENT_ISOLATE_CONTEXT();
|
| -
|
| - String get _prettyName => 'Isolate';
|
| -
|
| - String get debugName {
|
| - String id = _isolateContext == null ? 'X' : _isolateContext.id.toString();
|
| - // Using name similar to what the VM uses.
|
| - return '${n(rootLibrary.simpleName)}-$id';
|
| - }
|
| -
|
| - bool get isCurrent => JS_CURRENT_ISOLATE_CONTEXT() == _isolateContext;
|
| -
|
| - LibraryMirror get rootLibrary {
|
| - return currentJsMirrorSystem.libraries.values.firstWhere(
|
| - (JsLibraryMirror library) => library._isRoot);
|
| - }
|
| -}
|
| -
|
| -abstract class JsDeclarationMirror extends JsMirror
|
| - implements DeclarationMirror {
|
| - final Symbol simpleName;
|
| -
|
| - const JsDeclarationMirror(this.simpleName);
|
| -
|
| - Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
|
| -
|
| - bool get isPrivate => n(simpleName).startsWith('_');
|
| -
|
| - bool get isTopLevel => owner != null && owner is LibraryMirror;
|
| -
|
| - // TODO(ahe): This should use qualifiedName.
|
| - String toString() => "$_prettyName on '${n(simpleName)}'";
|
| -
|
| - List<JsMethodMirror> get _methods {
|
| - throw new RuntimeError('Should not call _methods');
|
| - }
|
| -
|
| - _invoke(List positionalArguments, Map<Symbol, dynamic> namedArguments) {
|
| - throw new RuntimeError('Should not call _invoke');
|
| - }
|
| -
|
| - // TODO(ahe): Implement this.
|
| - SourceLocation get location => throw new UnimplementedError();
|
| -}
|
| -
|
| -class JsTypeVariableMirror extends JsTypeMirror implements TypeVariableMirror {
|
| - final DeclarationMirror owner;
|
| - final TypeVariable _typeVariable;
|
| - final int _metadataIndex;
|
| - TypeMirror _cachedUpperBound;
|
| -
|
| - JsTypeVariableMirror(TypeVariable typeVariable, this.owner,
|
| - this._metadataIndex)
|
| - : this._typeVariable = typeVariable,
|
| - super(s(typeVariable.name));
|
| -
|
| - bool operator ==(other) {
|
| - return (other is JsTypeVariableMirror &&
|
| - simpleName == other.simpleName &&
|
| - owner == other.owner);
|
| - }
|
| -
|
| - int get hashCode {
|
| - int code = 0x3FFFFFFF & (JsTypeVariableMirror).hashCode;
|
| - code ^= 17 * simpleName.hashCode;
|
| - code ^= 19 * owner.hashCode;
|
| - return code;
|
| - }
|
| -
|
| - String get _prettyName => 'TypeVariableMirror';
|
| -
|
| - bool get isTopLevel => false;
|
| - bool get isStatic => false;
|
| -
|
| - TypeMirror get upperBound {
|
| - if (_cachedUpperBound != null) return _cachedUpperBound;
|
| - return _cachedUpperBound = typeMirrorFromRuntimeTypeRepresentation(
|
| - owner, getMetadata(_typeVariable.bound));
|
| - }
|
| -
|
| - bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError();
|
| - bool isAssignableTo(TypeMirror other) => throw new UnimplementedError();
|
| -
|
| - _asRuntimeType() => _metadataIndex;
|
| -}
|
| -
|
| -class JsTypeMirror extends JsDeclarationMirror implements TypeMirror {
|
| - JsTypeMirror(Symbol simpleName)
|
| - : super(simpleName);
|
| -
|
| - String get _prettyName => 'TypeMirror';
|
| -
|
| - DeclarationMirror get owner => null;
|
| -
|
| - // TODO(ahe): Doesn't match the specification, see http://dartbug.com/11569.
|
| - bool get isTopLevel => true;
|
| -
|
| - // TODO(ahe): Implement these.
|
| - List<InstanceMirror> get metadata => throw new UnimplementedError();
|
| -
|
| - bool get hasReflectedType => false;
|
| - Type get reflectedType {
|
| - throw new UnsupportedError("This type does not support reflectedType");
|
| - }
|
| -
|
| - List<TypeVariableMirror> get typeVariables => const <TypeVariableMirror>[];
|
| - List<TypeMirror> get typeArguments => const <TypeMirror>[];
|
| -
|
| - bool get isOriginalDeclaration => true;
|
| - TypeMirror get originalDeclaration => this;
|
| -
|
| - bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError();
|
| - bool isAssignableTo(TypeMirror other) => throw new UnimplementedError();
|
| -
|
| - _asRuntimeType() {
|
| - if (this == JsMirrorSystem._dynamicType) return null;
|
| - if (this == JsMirrorSystem._voidType) return null;
|
| - throw new RuntimeError('Should not call _asRuntimeType');
|
| - }
|
| -}
|
| -
|
| -class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror
|
| - implements LibraryMirror {
|
| - final Uri _uri;
|
| - final List<String> _classes;
|
| - final List<String> _functions;
|
| - final List _metadata;
|
| - final String _compactFieldSpecification;
|
| - final bool _isRoot;
|
| - final _globalObject;
|
| - List<JsMethodMirror> _cachedFunctionMirrors;
|
| - List<VariableMirror> _cachedFields;
|
| - UnmodifiableMapView<Symbol, ClassMirror> _cachedClasses;
|
| - UnmodifiableMapView<Symbol, MethodMirror> _cachedFunctions;
|
| - UnmodifiableMapView<Symbol, MethodMirror> _cachedGetters;
|
| - UnmodifiableMapView<Symbol, MethodMirror> _cachedSetters;
|
| - UnmodifiableMapView<Symbol, VariableMirror> _cachedVariables;
|
| - UnmodifiableMapView<Symbol, Mirror> _cachedMembers;
|
| - UnmodifiableMapView<Symbol, DeclarationMirror> _cachedDeclarations;
|
| - UnmodifiableListView<InstanceMirror> _cachedMetadata;
|
| -
|
| - JsLibraryMirror(Symbol simpleName,
|
| - this._uri,
|
| - this._classes,
|
| - this._functions,
|
| - this._metadata,
|
| - this._compactFieldSpecification,
|
| - this._isRoot,
|
| - this._globalObject)
|
| - : super(simpleName) {
|
| - preserveLibraryNames();
|
| - }
|
| -
|
| - String get _prettyName => 'LibraryMirror';
|
| -
|
| - Uri get uri {
|
| - preserveUris();
|
| - return _uri;
|
| - }
|
| -
|
| - Symbol get qualifiedName => simpleName;
|
| -
|
| - List<JsMethodMirror> get _methods => _functionMirrors;
|
| -
|
| - Map<Symbol, ClassMirror> get __classes {
|
| - if (_cachedClasses != null) return _cachedClasses;
|
| - var result = new Map();
|
| - for (String className in _classes) {
|
| - var cls = reflectClassByMangledName(className);
|
| - if (cls is ClassMirror) {
|
| - cls = cls.originalDeclaration;
|
| - }
|
| - if (cls is JsClassMirror) {
|
| - result[cls.simpleName] = cls;
|
| - cls._owner = this;
|
| - } else if (cls is JsTypedefMirror) {
|
| - result[cls.simpleName] = cls;
|
| - }
|
| - }
|
| - return _cachedClasses =
|
| - new UnmodifiableMapView<Symbol, ClassMirror>(result);
|
| - }
|
| -
|
| - InstanceMirror setField(Symbol fieldName, Object arg) {
|
| - String name = n(fieldName);
|
| - if (name.endsWith('=')) throw new ArgumentError('');
|
| - var mirror = __functions[s('$name=')];
|
| - if (mirror == null) mirror = __variables[fieldName];
|
| - if (mirror == null) {
|
| - throw new NoSuchStaticMethodError.method(
|
| - null, setterSymbol(fieldName), [arg], null);
|
| - }
|
| - mirror._setField(this, arg);
|
| - return reflect(arg);
|
| - }
|
| -
|
| - InstanceMirror getField(Symbol fieldName) {
|
| - JsMirror mirror = __members[fieldName];
|
| - if (mirror == null) {
|
| - throw new NoSuchStaticMethodError.method(null, fieldName, [], null);
|
| - }
|
| - if (mirror is! MethodMirror) return reflect(mirror._getField(this));
|
| - JsMethodMirror methodMirror = mirror;
|
| - if (methodMirror.isGetter) return reflect(mirror._getField(this));
|
| - assert(methodMirror.isRegularMethod);
|
| - var getter = JS("", "#['\$getter']", methodMirror._jsFunction);
|
| - if (getter == null) throw new UnimplementedError();
|
| - return reflect(JS("", "#()", getter));
|
| - }
|
| -
|
| - InstanceMirror invoke(Symbol memberName,
|
| - List positionalArguments,
|
| - [Map<Symbol, dynamic> namedArguments]) {
|
| - if (namedArguments != null && !namedArguments.isEmpty) {
|
| - throw new UnsupportedError('Named arguments are not implemented.');
|
| - }
|
| - JsDeclarationMirror mirror = __members[memberName];
|
| -
|
| - if (mirror is JsMethodMirror && !mirror.canInvokeReflectively()) {
|
| - throwInvalidReflectionError(n(memberName));
|
| - }
|
| - if (mirror == null || mirror is JsMethodMirror && mirror.isSetter) {
|
| - throw new NoSuchStaticMethodError.method(
|
| - null, memberName, positionalArguments, namedArguments);
|
| - }
|
| - if (mirror is JsMethodMirror && !mirror.isGetter) {
|
| - return reflect(mirror._invoke(positionalArguments, namedArguments));
|
| - }
|
| - return getField(memberName)
|
| - .invoke(#call, positionalArguments, namedArguments);
|
| - }
|
| -
|
| - _loadField(String name) {
|
| - // TODO(ahe): What about lazily initialized fields? See
|
| - // [JsClassMirror.getField].
|
| -
|
| - // '$' (JS_CURRENT_ISOLATE()) stores state which is read directly, so we
|
| - // shouldn't use [_globalObject] here.
|
| - assert(JS('bool', '# in #', name, JS_CURRENT_ISOLATE()));
|
| - return JS('', '#[#]', JS_CURRENT_ISOLATE(), name);
|
| - }
|
| -
|
| - void _storeField(String name, Object arg) {
|
| - // '$' (JS_CURRENT_ISOLATE()) stores state which is stored directly, so we
|
| - // shouldn't use [_globalObject] here.
|
| - assert(JS('bool', '# in #', name, JS_CURRENT_ISOLATE()));
|
| - JS('void', '#[#] = #', JS_CURRENT_ISOLATE(), name, arg);
|
| - }
|
| -
|
| - List<JsMethodMirror> get _functionMirrors {
|
| - if (_cachedFunctionMirrors != null) return _cachedFunctionMirrors;
|
| - var result = new List<JsMethodMirror>();
|
| - for (int i = 0; i < _functions.length; i++) {
|
| - String name = _functions[i];
|
| - var jsFunction = JS('', '#[#]', _globalObject, name);
|
| - String unmangledName = mangledGlobalNames[name];
|
| - if (unmangledName == null ||
|
| - JS('bool', "!!#['\$getterStub']", jsFunction)) {
|
| - // If there is no unmangledName, [jsFunction] is either a synthetic
|
| - // implementation detail, or something that is excluded
|
| - // by @MirrorsUsed.
|
| - // If it has a getterStub property it is a synthetic stub.
|
| - // TODO(floitsch): Remove the getterStub hack.
|
| - continue;
|
| - }
|
| - bool isConstructor = unmangledName.startsWith('new ');
|
| - bool isStatic = !isConstructor; // Top-level functions are static, but
|
| - // constructors are not.
|
| - if (isConstructor) {
|
| - unmangledName = unmangledName.substring(4).replaceAll(r'$', '.');
|
| - }
|
| - JsMethodMirror mirror =
|
| - new JsMethodMirror.fromUnmangledName(
|
| - unmangledName, jsFunction, isStatic, isConstructor);
|
| - result.add(mirror);
|
| - mirror._owner = this;
|
| - }
|
| - return _cachedFunctionMirrors = result;
|
| - }
|
| -
|
| - List<VariableMirror> get _fields {
|
| - if (_cachedFields != null) return _cachedFields;
|
| - var result = <VariableMirror>[];
|
| - parseCompactFieldSpecification(
|
| - this, _compactFieldSpecification, true, result);
|
| - return _cachedFields = result;
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get __functions {
|
| - if (_cachedFunctions != null) return _cachedFunctions;
|
| - var result = new Map();
|
| - for (JsMethodMirror mirror in _functionMirrors) {
|
| - if (!mirror.isConstructor) result[mirror.simpleName] = mirror;
|
| - }
|
| - return _cachedFunctions =
|
| - new UnmodifiableMapView<Symbol, MethodMirror>(result);
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get __getters {
|
| - if (_cachedGetters != null) return _cachedGetters;
|
| - var result = new Map();
|
| - // TODO(ahe): Implement this.
|
| - return _cachedGetters =
|
| - new UnmodifiableMapView<Symbol, MethodMirror>(result);
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get __setters {
|
| - if (_cachedSetters != null) return _cachedSetters;
|
| - var result = new Map();
|
| - // TODO(ahe): Implement this.
|
| - return _cachedSetters =
|
| - new UnmodifiableMapView<Symbol, MethodMirror>(result);
|
| - }
|
| -
|
| - Map<Symbol, VariableMirror> get __variables {
|
| - if (_cachedVariables != null) return _cachedVariables;
|
| - var result = new Map();
|
| - for (JsVariableMirror mirror in _fields) {
|
| - result[mirror.simpleName] = mirror;
|
| - }
|
| - return _cachedVariables =
|
| - new UnmodifiableMapView<Symbol, VariableMirror>(result);
|
| - }
|
| -
|
| - Map<Symbol, Mirror> get __members {
|
| - if (_cachedMembers != null) return _cachedMembers;
|
| - Map<Symbol, Mirror> result = new Map.from(__classes);
|
| - addToResult(Symbol key, Mirror value) {
|
| - result[key] = value;
|
| - }
|
| - __functions.forEach(addToResult);
|
| - __getters.forEach(addToResult);
|
| - __setters.forEach(addToResult);
|
| - __variables.forEach(addToResult);
|
| - return _cachedMembers = new UnmodifiableMapView<Symbol, Mirror>(result);
|
| - }
|
| -
|
| - Map<Symbol, DeclarationMirror> get declarations {
|
| - if (_cachedDeclarations != null) return _cachedDeclarations;
|
| - var result = new Map<Symbol, DeclarationMirror>();
|
| - addToResult(Symbol key, Mirror value) {
|
| - result[key] = value;
|
| - }
|
| - __members.forEach(addToResult);
|
| - return _cachedDeclarations =
|
| - new UnmodifiableMapView<Symbol, DeclarationMirror>(result);
|
| - }
|
| -
|
| - List<InstanceMirror> get metadata {
|
| - if (_cachedMetadata != null) return _cachedMetadata;
|
| - preserveMetadata();
|
| - return _cachedMetadata =
|
| - new UnmodifiableListView<InstanceMirror>(_metadata.map(reflect));
|
| - }
|
| -
|
| - // TODO(ahe): Test this getter.
|
| - DeclarationMirror get owner => null;
|
| -
|
| - List<LibraryDependencyMirror> get libraryDependencies
|
| - => throw new UnimplementedError();
|
| -}
|
| -
|
| -String n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
|
| -
|
| -Symbol s(String name) {
|
| - if (name == null) return null;
|
| - return new _symbol_dev.Symbol.unvalidated(name);
|
| -}
|
| -
|
| -Symbol setterSymbol(Symbol symbol) => s("${n(symbol)}=");
|
| -
|
| -final JsMirrorSystem currentJsMirrorSystem = new JsMirrorSystem();
|
| -
|
| -InstanceMirror reflect(Object reflectee) {
|
| - if (reflectee is Closure) {
|
| - return new JsClosureMirror(reflectee);
|
| - } else {
|
| - return new JsInstanceMirror(reflectee);
|
| - }
|
| -}
|
| -
|
| -TypeMirror reflectType(Type key) {
|
| - return reflectClassByMangledName(getMangledTypeName(key));
|
| -}
|
| -
|
| -TypeMirror reflectClassByMangledName(String mangledName) {
|
| - String unmangledName = mangledGlobalNames[mangledName];
|
| - if (mangledName == 'dynamic') return JsMirrorSystem._dynamicType;
|
| - if (mangledName == 'void') return JsMirrorSystem._voidType;
|
| - if (unmangledName == null) unmangledName = mangledName;
|
| - return reflectClassByName(s(unmangledName), mangledName);
|
| -}
|
| -
|
| -var classMirrors;
|
| -
|
| -TypeMirror reflectClassByName(Symbol symbol, String mangledName) {
|
| - if (classMirrors == null) classMirrors = JsCache.allocate();
|
| - var mirror = JsCache.fetch(classMirrors, mangledName);
|
| - if (mirror != null) return mirror;
|
| - disableTreeShaking();
|
| - int typeArgIndex = mangledName.indexOf("<");
|
| - if (typeArgIndex != -1) {
|
| - mirror = new JsTypeBoundClassMirror(reflectClassByMangledName(
|
| - mangledName.substring(0, typeArgIndex)).originalDeclaration,
|
| - // Remove the angle brackets enclosing the type arguments.
|
| - mangledName.substring(typeArgIndex + 1, mangledName.length - 1));
|
| - JsCache.update(classMirrors, mangledName, mirror);
|
| - return mirror;
|
| - }
|
| - var constructor = JS('var', 'init.allClasses[#]', mangledName);
|
| - if (constructor == null) {
|
| - // Probably an intercepted class.
|
| - // TODO(ahe): How to handle intercepted classes?
|
| - throw new UnsupportedError('Cannot find class for: ${n(symbol)}');
|
| - }
|
| - var descriptor = JS('', '#["@"]', constructor);
|
| - var fields;
|
| - var fieldsMetadata;
|
| - if (descriptor == null) {
|
| - // This is a native class, or an intercepted class.
|
| - // TODO(ahe): Preserve descriptor for such classes.
|
| - } else {
|
| - fields = JS('', '#[#]', descriptor,
|
| - JS_GET_NAME('CLASS_DESCRIPTOR_PROPERTY'));
|
| - if (fields is List) {
|
| - fieldsMetadata = fields.getRange(1, fields.length).toList();
|
| - fields = fields[0];
|
| - }
|
| - if (fields is! String) {
|
| - // TODO(ahe): This is CSP mode. Find a way to determine the
|
| - // fields of this class.
|
| - fields = '';
|
| - }
|
| - }
|
| -
|
| - if (encoding.isTypedefDescriptor(fields)) {
|
| - int index = encoding.getTypeFromTypedef(fields);
|
| - mirror = new JsTypedefMirror(symbol, mangledName, getMetadata(index));
|
| - } else {
|
| - var superclassName = fields.split(';')[0];
|
| - var mixins = superclassName.split('+');
|
| - if (mixins.length > 1 && mangledGlobalNames[mangledName] == null) {
|
| - mirror = reflectMixinApplication(mixins, mangledName);
|
| - } else {
|
| - ClassMirror classMirror = new JsClassMirror(
|
| - symbol, mangledName, constructor, fields, fieldsMetadata);
|
| - List typeVariables =
|
| - JS('JSExtendableArray|Null', '#.prototype["<>"]', constructor);
|
| - if (typeVariables == null || typeVariables.length == 0) {
|
| - mirror = classMirror;
|
| - } else {
|
| - String typeArguments = 'dynamic';
|
| - for (int i = 1; i < typeVariables.length; i++) {
|
| - typeArguments += ',dynamic';
|
| - }
|
| - mirror = new JsTypeBoundClassMirror(classMirror, typeArguments);
|
| - }
|
| - }
|
| - }
|
| -
|
| - JsCache.update(classMirrors, mangledName, mirror);
|
| - return mirror;
|
| -}
|
| -
|
| -Map<Symbol, MethodMirror> filterMethods(List<MethodMirror> methods) {
|
| - var result = new Map();
|
| - for (JsMethodMirror method in methods) {
|
| - if (!method.isConstructor && !method.isGetter && !method.isSetter) {
|
| - result[method.simpleName] = method;
|
| - }
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -Map<Symbol, MethodMirror> filterConstructors(methods) {
|
| - var result = new Map();
|
| - for (JsMethodMirror method in methods) {
|
| - if (method.isConstructor) {
|
| - result[method.simpleName] = method;
|
| - }
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -Map<Symbol, MethodMirror> filterGetters(List<MethodMirror> methods,
|
| - Map<Symbol, VariableMirror> fields) {
|
| - var result = new Map();
|
| - for (JsMethodMirror method in methods) {
|
| - if (method.isGetter) {
|
| -
|
| - // TODO(ahe): This is a hack to remove getters corresponding to a field.
|
| - if (fields[method.simpleName] != null) continue;
|
| -
|
| - result[method.simpleName] = method;
|
| - }
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -Map<Symbol, MethodMirror> filterSetters(List<MethodMirror> methods,
|
| - Map<Symbol, VariableMirror> fields) {
|
| - var result = new Map();
|
| - for (JsMethodMirror method in methods) {
|
| - if (method.isSetter) {
|
| -
|
| - // TODO(ahe): This is a hack to remove setters corresponding to a field.
|
| - String name = n(method.simpleName);
|
| - name = name.substring(0, name.length - 1); // Remove '='.
|
| - if (fields[s(name)] != null) continue;
|
| -
|
| - result[method.simpleName] = method;
|
| - }
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -Map<Symbol, Mirror> filterMembers(List<MethodMirror> methods,
|
| - Map<Symbol, VariableMirror> variables) {
|
| - Map<Symbol, Mirror> result = new Map.from(variables);
|
| - for (JsMethodMirror method in methods) {
|
| - if (method.isSetter) {
|
| - String name = n(method.simpleName);
|
| - name = name.substring(0, name.length - 1);
|
| - // Filter-out setters corresponding to variables.
|
| - if (result[s(name)] is VariableMirror) continue;
|
| - }
|
| - // Constructors aren't 'members'.
|
| - if (method.isConstructor) continue;
|
| - // Use putIfAbsent to filter-out getters corresponding to variables.
|
| - result.putIfAbsent(method.simpleName, () => method);
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -int counter = 0;
|
| -
|
| -ClassMirror reflectMixinApplication(mixinNames, String mangledName) {
|
| - disableTreeShaking();
|
| - var mixins = [];
|
| - for (String mangledName in mixinNames) {
|
| - mixins.add(reflectClassByMangledName(mangledName));
|
| - }
|
| - var it = mixins.iterator;
|
| - it.moveNext();
|
| - var superclass = it.current;
|
| - while (it.moveNext()) {
|
| - superclass = new JsMixinApplication(superclass, it.current, mangledName);
|
| - }
|
| - return superclass;
|
| -}
|
| -
|
| -class JsMixinApplication extends JsTypeMirror with JsObjectMirror
|
| - implements ClassMirror {
|
| - final ClassMirror superclass;
|
| - final ClassMirror mixin;
|
| - Symbol _cachedSimpleName;
|
| - Map<Symbol, MethodMirror> _cachedInstanceMembers;
|
| -
|
| - JsMixinApplication(ClassMirror superclass, ClassMirror mixin,
|
| - String mangledName)
|
| - : this.superclass = superclass,
|
| - this.mixin = mixin,
|
| - super(s(mangledName));
|
| -
|
| - String get _prettyName => 'ClassMirror';
|
| -
|
| - Symbol get simpleName {
|
| - if (_cachedSimpleName != null) return _cachedSimpleName;
|
| - String superName = n(superclass.qualifiedName);
|
| - return _cachedSimpleName = (superName.contains(' with '))
|
| - ? s('$superName, ${n(mixin.qualifiedName)}')
|
| - : s('$superName with ${n(mixin.qualifiedName)}');
|
| - }
|
| -
|
| - Symbol get qualifiedName => simpleName;
|
| -
|
| - // TODO(ahe): Remove this method, only here to silence warning.
|
| - get _mixin => mixin;
|
| -
|
| - Map<Symbol, Mirror> get __members => _mixin.__members;
|
| -
|
| - Map<Symbol, MethodMirror> get __methods => _mixin.__methods;
|
| -
|
| - Map<Symbol, MethodMirror> get __getters => _mixin.__getters;
|
| -
|
| - Map<Symbol, MethodMirror> get __setters => _mixin.__setters;
|
| -
|
| - Map<Symbol, VariableMirror> get __variables => _mixin.__variables;
|
| -
|
| - Map<Symbol, DeclarationMirror> get declarations => mixin.declarations;
|
| -
|
| - Map<Symbol, MethodMirror> get instanceMembers {
|
| - if (_cachedInstanceMembers == null) {
|
| - var result = new Map<Symbol, MethodMirror>();
|
| - if (superclass != null) {
|
| - result.addAll(superclass.instanceMembers);
|
| - }
|
| - result.addAll(mixin.instanceMembers);
|
| - _cachedInstanceMembers = result;
|
| - }
|
| - return _cachedInstanceMembers;
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get staticMembers => mixin.staticMembers;
|
| -
|
| - _asRuntimeType() => null;
|
| -
|
| - InstanceMirror invoke(
|
| - Symbol memberName,
|
| - List positionalArguments,
|
| - [Map<Symbol,dynamic> namedArguments]) {
|
| - throw new NoSuchStaticMethodError.method(
|
| - null, memberName, positionalArguments, namedArguments);
|
| - }
|
| -
|
| - InstanceMirror getField(Symbol fieldName) {
|
| - throw new NoSuchStaticMethodError.method(null, fieldName, null, null);
|
| - }
|
| -
|
| - InstanceMirror setField(Symbol fieldName, Object arg) {
|
| - throw new NoSuchStaticMethodError.method(
|
| - null, setterSymbol(fieldName), [arg], null);
|
| - }
|
| -
|
| - List<ClassMirror> get superinterfaces => [mixin];
|
| -
|
| - Map<Symbol, MethodMirror> get __constructors => _mixin.__constructors;
|
| -
|
| - InstanceMirror newInstance(
|
| - Symbol constructorName,
|
| - List positionalArguments,
|
| - [Map<Symbol,dynamic> namedArguments]) {
|
| - throw new UnsupportedError(
|
| - "Can't instantiate mixin application '${n(qualifiedName)}'");
|
| - }
|
| -
|
| - bool get isOriginalDeclaration => true;
|
| -
|
| - ClassMirror get originalDeclaration => this;
|
| -
|
| - // TODO(ahe): Implement this.
|
| - List<TypeVariableMirror> get typeVariables {
|
| - throw new UnimplementedError();
|
| - }
|
| -
|
| - List<TypeMirror> get typeArguments => const <TypeMirror>[];
|
| -
|
| - bool get isAbstract => throw new UnimplementedError();
|
| -
|
| - bool isSubclassOf(ClassMirror other) {
|
| - superclass.isSubclassOf(other) || mixin.isSubclassOf(other);
|
| - }
|
| -
|
| - bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError();
|
| -
|
| - bool isAssignableTo(TypeMirror other) => throw new UnimplementedError();
|
| -}
|
| -
|
| -abstract class JsObjectMirror implements ObjectMirror {
|
| -}
|
| -
|
| -class JsInstanceMirror extends JsObjectMirror implements InstanceMirror {
|
| - final reflectee;
|
| -
|
| - JsInstanceMirror(this.reflectee);
|
| -
|
| - bool get hasReflectee => true;
|
| -
|
| - ClassMirror get type {
|
| - // The spec guarantees that `null` is the singleton instance of the `Null`
|
| - // class.
|
| - if (reflectee == null) return reflectClass(Null);
|
| - return reflectType(getRuntimeType(reflectee));
|
| - }
|
| -
|
| - InstanceMirror invoke(Symbol memberName,
|
| - List positionalArguments,
|
| - [Map<Symbol,dynamic> namedArguments]) {
|
| - if (namedArguments == null) namedArguments = const {};
|
| - // We can safely pass positionalArguments to _invoke as it will wrap it in
|
| - // a JSArray if needed.
|
| - return _invoke(memberName, JSInvocationMirror.METHOD,
|
| - positionalArguments, namedArguments);
|
| - }
|
| -
|
| - InstanceMirror _invokeMethodWithNamedArguments(
|
| - String reflectiveName,
|
| - List positionalArguments, Map<Symbol,dynamic> namedArguments) {
|
| - assert(namedArguments.isNotEmpty);
|
| - var interceptor = getInterceptor(reflectee);
|
| -
|
| - var jsFunction = JS('', '#[#]', interceptor, reflectiveName);
|
| - if (jsFunction == null) {
|
| - // TODO(ahe): Invoke noSuchMethod.
|
| - throw new UnimplementedNoSuchMethodError(
|
| - 'Invoking noSuchMethod with named arguments not implemented');
|
| - }
|
| - ReflectionInfo info = new ReflectionInfo(jsFunction);
|
| - if (jsFunction == null) {
|
| - // TODO(ahe): Invoke noSuchMethod.
|
| - throw new UnimplementedNoSuchMethodError(
|
| - 'Invoking noSuchMethod with named arguments not implemented');
|
| - }
|
| -
|
| - positionalArguments = new List.from(positionalArguments);
|
| - // Check the number of positional arguments is valid.
|
| - if (info.requiredParameterCount != positionalArguments.length) {
|
| - // TODO(ahe): Invoke noSuchMethod.
|
| - throw new UnimplementedNoSuchMethodError(
|
| - 'Invoking noSuchMethod with named arguments not implemented');
|
| - }
|
| - var defaultArguments = new Map();
|
| - for (int i = 0; i < info.optionalParameterCount; i++) {
|
| - var parameterName = info.parameterName(i + info.requiredParameterCount);
|
| - var defaultValue =
|
| - getMetadata(info.defaultValue(i + info.requiredParameterCount));
|
| - defaultArguments[parameterName] = defaultValue;
|
| - }
|
| - namedArguments.forEach((Symbol symbol, value) {
|
| - String parameter = n(symbol);
|
| - if (defaultArguments.containsKey(parameter)) {
|
| - defaultArguments[parameter] = value;
|
| - } else {
|
| - // Extraneous named argument.
|
| - // TODO(ahe): Invoke noSuchMethod.
|
| - throw new UnimplementedNoSuchMethodError(
|
| - 'Invoking noSuchMethod with named arguments not implemented');
|
| - }
|
| - });
|
| - positionalArguments.addAll(defaultArguments.values);
|
| - // TODO(ahe): Handle intercepted methods.
|
| - return reflect(
|
| - JS('', '#.apply(#, #)', jsFunction, reflectee, positionalArguments));
|
| - }
|
| -
|
| - /// Grabs hold of the class-specific invocation cache for the reflectee.
|
| - /// All reflectees with the same class share the same cache. The cache
|
| - /// maps reflective names to cached invocation objects with enough decoded
|
| - /// reflective information to know how to to invoke a specific member.
|
| - get _classInvocationCache {
|
| - String cacheName = Primitives.mirrorInvokeCacheName;
|
| - var cacheHolder = (reflectee == null) ? getInterceptor(null) : reflectee;
|
| - var cache = JS('', r'#.constructor[#]', cacheHolder, cacheName);
|
| - if (cache == null) {
|
| - cache = JsCache.allocate();
|
| - JS('void', r'#.constructor[#] = #', cacheHolder, cacheName, cache);
|
| - }
|
| - return cache;
|
| - }
|
| -
|
| - String _computeReflectiveName(Symbol symbolName, int type,
|
| - List positionalArguments,
|
| - Map<Symbol, dynamic> namedArguments) {
|
| - String name = n(symbolName);
|
| - switch (type) {
|
| - case JSInvocationMirror.GETTER: return name;
|
| - case JSInvocationMirror.SETTER: return '$name=';
|
| - case JSInvocationMirror.METHOD:
|
| - if (namedArguments.isNotEmpty) return '$name*';
|
| - int nbArgs = positionalArguments.length as int;
|
| - return "$name:$nbArgs:0";
|
| - }
|
| - throw new RuntimeError("Could not compute reflective name for $name");
|
| - }
|
| -
|
| - /**
|
| - * Returns a `CachedInvocation` or `CachedNoSuchMethodInvocation` for the
|
| - * given member.
|
| - *
|
| - * Caches the result.
|
| - */
|
| - _getCachedInvocation(Symbol name, int type, String reflectiveName,
|
| - List positionalArguments, Map<Symbol,dynamic> namedArguments) {
|
| -
|
| - var cache = _classInvocationCache;
|
| - var cacheEntry = JsCache.fetch(cache, reflectiveName);
|
| - var result;
|
| - if (cacheEntry == null) {
|
| - disableTreeShaking();
|
| - String mangledName = reflectiveNames[reflectiveName];
|
| - List<String> argumentNames = const [];
|
| -
|
| - // TODO(ahe): We don't need to create an invocation mirror here. The
|
| - // logic from JSInvocationMirror.getCachedInvocation could easily be
|
| - // inlined here.
|
| - Invocation invocation = createUnmangledInvocationMirror(
|
| - name, mangledName, type, positionalArguments, argumentNames);
|
| -
|
| - cacheEntry =
|
| - JSInvocationMirror.getCachedInvocation(invocation, reflectee);
|
| - JsCache.update(cache, reflectiveName, cacheEntry);
|
| - }
|
| - return cacheEntry;
|
| - }
|
| -
|
| - bool _isReflectable(CachedInvocation cachedInvocation) {
|
| - // TODO(floitsch): tear-off closure does not guarantee that the
|
| - // function is reflectable.
|
| - var method = cachedInvocation.jsFunction;
|
| - return hasReflectableProperty(method) || reflectee is TearOffClosure;
|
| - }
|
| -
|
| - /// Invoke the member specified through name and type on the reflectee.
|
| - /// As a side-effect, this populates the class-specific invocation cache
|
| - /// for the reflectee.
|
| - InstanceMirror _invoke(Symbol name,
|
| - int type,
|
| - List positionalArguments,
|
| - Map<Symbol,dynamic> namedArguments) {
|
| - String reflectiveName =
|
| - _computeReflectiveName(name, type, positionalArguments, namedArguments);
|
| -
|
| - if (namedArguments.isNotEmpty) {
|
| - // TODO(floitsch): first, make sure it's not a getter.
|
| - return _invokeMethodWithNamedArguments(
|
| - reflectiveName, positionalArguments, namedArguments);
|
| - }
|
| - var cacheEntry = _getCachedInvocation(
|
| - name, type, reflectiveName, positionalArguments, namedArguments);
|
| -
|
| - if (cacheEntry.isNoSuchMethod || !_isReflectable(cacheEntry)) {
|
| - // Could be that we want to invoke a getter, or get a method.
|
| - if (type == JSInvocationMirror.METHOD && _instanceFieldExists(name)) {
|
| - return getField(name).invoke(
|
| - #call, positionalArguments, namedArguments);
|
| - }
|
| -
|
| - if (type == JSInvocationMirror.SETTER) {
|
| - // For setters we report the setter name "field=".
|
| - name = s("${n(name)}=");
|
| - }
|
| -
|
| - if (!cacheEntry.isNoSuchMethod) {
|
| - // Not reflectable.
|
| - throwInvalidReflectionError(reflectiveName);
|
| - }
|
| -
|
| - String mangledName = reflectiveNames[reflectiveName];
|
| - // TODO(ahe): Get the argument names.
|
| - List<String> argumentNames = [];
|
| - Invocation invocation = createUnmangledInvocationMirror(
|
| - name, mangledName, type, positionalArguments, argumentNames);
|
| - return reflect(cacheEntry.invokeOn(reflectee, invocation));
|
| - } else {
|
| - return reflect(cacheEntry.invokeOn(reflectee, positionalArguments));
|
| - }
|
| - }
|
| -
|
| - InstanceMirror setField(Symbol fieldName, Object arg) {
|
| - _invoke(fieldName, JSInvocationMirror.SETTER, [arg], const {});
|
| - return reflect(arg);
|
| - }
|
| -
|
| - // JS helpers for getField optimizations.
|
| - static bool isUndefined(x)
|
| - => JS('bool', 'typeof # == "undefined"', x);
|
| - static bool isMissingCache(x)
|
| - => JS('bool', 'typeof # == "number"', x);
|
| - static bool isMissingProbe(Symbol symbol)
|
| - => JS('bool', 'typeof #.\$p == "undefined"', symbol);
|
| - static bool isEvalAllowed()
|
| - => JS('bool', 'typeof dart_precompiled != "function"');
|
| -
|
| -
|
| - /// The getter cache is lazily allocated after a couple
|
| - /// of invocations of [InstanceMirror.getField]. The delay is
|
| - /// used to avoid too aggressive caching and dynamic function
|
| - /// generation for rarely used mirrors. The cache is specific to
|
| - /// this [InstanceMirror] and maps reflective names to functions
|
| - /// that will invoke the corresponding getter on the reflectee.
|
| - /// The reflectee is passed to the function as the first argument
|
| - /// to avoid the overhead of fetching it from this mirror repeatedly.
|
| - /// The cache is lazily initialized to a JS object so we can
|
| - /// benefit from "map transitions" in the underlying JavaScript
|
| - /// engine to speed up cache probing.
|
| - var _getterCache = 4;
|
| -
|
| - bool _instanceFieldExists(Symbol name) {
|
| - int getterType = JSInvocationMirror.GETTER;
|
| - String getterName =
|
| - _computeReflectiveName(name, getterType, const [], const {});
|
| - var getterCacheEntry = _getCachedInvocation(
|
| - name, getterType, getterName, const [], const {});
|
| - return !getterCacheEntry.isNoSuchMethod && !getterCacheEntry.isGetterStub;
|
| - }
|
| -
|
| - InstanceMirror getField(Symbol fieldName) {
|
| - FASTPATH: {
|
| - var cache = _getterCache;
|
| - if (isMissingCache(cache) || isMissingProbe(fieldName)) break FASTPATH;
|
| - // If the [fieldName] has an associated probe function, we can use
|
| - // it to read from the getter cache specific to this [InstanceMirror].
|
| - var getter = JS('', '#.\$p(#)', fieldName, cache);
|
| - if (isUndefined(getter)) break FASTPATH;
|
| - // Call the getter passing the reflectee as the first argument.
|
| - var value = JS('', '#(#)', getter, reflectee);
|
| - // The getter has an associate cache of the last [InstanceMirror]
|
| - // returned to avoid repeated invocations of [reflect]. To validate
|
| - // the cache, we check that the value returned by the getter is the
|
| - // same value as last time.
|
| - if (JS('bool', '# === #.v', value, getter)) {
|
| - return JS('InstanceMirror', '#.m', getter);
|
| - } else {
|
| - var result = reflect(value);
|
| - JS('void', '#.v = #', getter, value);
|
| - JS('void', '#.m = #', getter, result);
|
| - return result;
|
| - }
|
| - }
|
| - return _getFieldSlow(fieldName);
|
| - }
|
| -
|
| - InstanceMirror _getFieldSlow(Symbol fieldName) {
|
| - // First do the slow-case getter invocation. As a side-effect of this,
|
| - // the invocation cache is filled in so we can query it afterwards.
|
| - var result =
|
| - _invoke(fieldName, JSInvocationMirror.GETTER, const [], const {});
|
| - String name = n(fieldName);
|
| - var cacheEntry = JsCache.fetch(_classInvocationCache, name);
|
| - if (cacheEntry.isNoSuchMethod) {
|
| - return result;
|
| - }
|
| -
|
| - // Make sure we have a getter cache in this [InstanceMirror].
|
| - var cache = _getterCache;
|
| - if (isMissingCache(cache)) {
|
| - if ((_getterCache = --cache) != 0) return result;
|
| - cache = _getterCache = JS('=Object', 'Object.create(null)');
|
| - }
|
| -
|
| - // Make sure that symbol [fieldName] has a cache probing function ($p).
|
| - bool useEval = isEvalAllowed();
|
| - if (isMissingProbe(fieldName)) {
|
| - var probe = _newProbeFn(name, useEval);
|
| - JS('void', '#.\$p = #', fieldName, probe);
|
| - }
|
| -
|
| - // Create a new getter function and install it in the cache.
|
| - var mangledName = cacheEntry.mangledName;
|
| - var getter = (cacheEntry.isIntercepted)
|
| - ? _newInterceptedGetterFn(mangledName, useEval)
|
| - : _newGetterFn(mangledName, useEval);
|
| - JS('void', '#[#] = #', cache, name, getter);
|
| -
|
| - // Initialize the last value (v) and last mirror (m) on the
|
| - // newly generated getter to be a sentinel value that is hard
|
| - // to get hold of through user code.
|
| - JS('void', '#.v = #.m = #', getter, getter, cache);
|
| -
|
| - // Return the result of the slow-path getter invocation.
|
| - return result;
|
| - }
|
| -
|
| - _newProbeFn(String id, bool useEval) {
|
| - if (useEval) {
|
| - // We give the probe function a name to make it appear nicely in
|
| - // profiles and when debugging. The name also makes the source code
|
| - // for the function more "unique" so the underlying JavaScript
|
| - // engine is less likely to re-use an existing piece of generated
|
| - // code as the result of calling eval. In return, this leads to
|
| - // less polymorphic access in the probe function.
|
| - var body = "(function probe\$$id(c){return c.$id})";
|
| - return JS('', '(function(b){return eval(b)})(#)', body);
|
| - } else {
|
| - return JS('', '(function(n){return(function(c){return c[n]})})(#)', id);
|
| - }
|
| - }
|
| -
|
| - _newGetterFn(String name, bool useEval) {
|
| - if (!useEval) return _newGetterNoEvalFn(name);
|
| - // We give the getter function a name that associates it with the
|
| - // class of the reflectee. This makes it easier to spot in profiles
|
| - // and when debugging, but it also means that the underlying JavaScript
|
| - // engine will only share the generated code for accessors on the
|
| - // same class (through caching of eval'ed code). This makes the
|
| - // generated call to the getter - e.g. o.get$foo() - much more likely
|
| - // to be monomorphic and inlineable.
|
| - String className = JS('String', '#.constructor.name', reflectee);
|
| - var body = "(function $className\$$name(o){return o.$name()})";
|
| - return JS('', '(function(b){return eval(b)})(#)', body);
|
| - }
|
| -
|
| - _newGetterNoEvalFn(n) => JS('',
|
| - '(function(n){return(function(o){return o[n]()})})(#)', n);
|
| -
|
| - _newInterceptedGetterFn(String name, bool useEval) {
|
| - var object = reflectee;
|
| - // It is possible that the interceptor for a given object is the object
|
| - // itself, so it is important not to share the code that captures the
|
| - // interceptor between multiple different instances of [InstanceMirror].
|
| - var interceptor = getInterceptor(object);
|
| - if (!useEval) return _newInterceptGetterNoEvalFn(name, interceptor);
|
| - String className = JS('String', '#.constructor.name', interceptor);
|
| - String functionName = '$className\$$name';
|
| - var body =
|
| - '(function(i) {'
|
| - ' function $functionName(o){return i.$name(o)}'
|
| - ' return $functionName;'
|
| - '})';
|
| - return JS('', '(function(b){return eval(b)})(#)(#)', body, interceptor);
|
| - }
|
| -
|
| - _newInterceptGetterNoEvalFn(n, i) => JS('',
|
| - '(function(n,i){return(function(o){return i[n](o)})})(#,#)', n, i);
|
| -
|
| - delegate(Invocation invocation) {
|
| - return JSInvocationMirror.invokeFromMirror(invocation, reflectee);
|
| - }
|
| -
|
| - operator ==(other) {
|
| - return other is JsInstanceMirror &&
|
| - identical(reflectee, other.reflectee);
|
| - }
|
| -
|
| - int get hashCode {
|
| - // Avoid hash collisions with the reflectee. This constant is in Smi range
|
| - // and happens to be the inner padding from RFC 2104.
|
| - return identityHashCode(reflectee) ^ 0x36363636;
|
| - }
|
| -
|
| - String toString() => 'InstanceMirror on ${Error.safeToString(reflectee)}';
|
| -
|
| - // TODO(ahe): Remove this method from the API.
|
| - MirrorSystem get mirrors => currentJsMirrorSystem;
|
| -}
|
| -
|
| -/**
|
| - * ClassMirror for generic classes where the type parameters are bound.
|
| - *
|
| - * [typeArguments] will return a list of the type arguments, in constrast
|
| - * to JsCLassMirror that returns an empty list since it represents original
|
| - * declarations and classes that are not generic.
|
| - */
|
| -class JsTypeBoundClassMirror extends JsDeclarationMirror
|
| - implements ClassMirror {
|
| - final JsClassMirror _class;
|
| -
|
| - /**
|
| - * When instantiated this field will hold a string representing the list of
|
| - * type arguments for the class, i.e. what is inside the outermost angle
|
| - * brackets. Then, when get typeArguments is called the first time, the string
|
| - * is parsed into the actual list of TypeMirrors, and stored in
|
| - * [_cachedTypeArguments]. Due to type substitution of, for instance,
|
| - * superclasses the mangled name of the class and hence this string is needed
|
| - * after [_cachedTypeArguments] has been computed.
|
| - *
|
| - * If an integer is encountered as a type argument, it represents the type
|
| - * variable at the corresponding entry in [emitter.globalMetadata].
|
| - */
|
| - String _typeArguments;
|
| -
|
| - UnmodifiableListView<TypeMirror> _cachedTypeArguments;
|
| - UnmodifiableMapView<Symbol, DeclarationMirror> _cachedDeclarations;
|
| - UnmodifiableMapView<Symbol, DeclarationMirror> _cachedMembers;
|
| - UnmodifiableMapView<Symbol, MethodMirror> _cachedConstructors;
|
| - Map<Symbol, VariableMirror> _cachedVariables;
|
| - Map<Symbol, MethodMirror> _cachedGetters;
|
| - Map<Symbol, MethodMirror> _cachedSetters;
|
| - Map<Symbol, MethodMirror> _cachedMethodsMap;
|
| - List<JsMethodMirror> _cachedMethods;
|
| - ClassMirror _superclass;
|
| - List<ClassMirror> _cachedSuperinterfaces;
|
| - Map<Symbol, MethodMirror> _cachedInstanceMembers;
|
| - Map<Symbol, MethodMirror> _cachedStaticMembers;
|
| -
|
| - JsTypeBoundClassMirror(JsClassMirror originalDeclaration, this._typeArguments)
|
| - : _class = originalDeclaration,
|
| - super(originalDeclaration.simpleName);
|
| -
|
| - String get _prettyName => 'ClassMirror';
|
| -
|
| - String toString() {
|
| - String result = '$_prettyName on ${n(simpleName)}';
|
| - if (typeArguments != null) {
|
| - result = "$result<${typeArguments.join(', ')}>";
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - String get _mangledName {
|
| - for (TypeMirror typeArgument in typeArguments) {
|
| - if (typeArgument != JsMirrorSystem._dynamicType) {
|
| - return '${_class._mangledName}<$_typeArguments>';
|
| - }
|
| - }
|
| - // When all type arguments are dynamic, the canonical representation is to
|
| - // drop them.
|
| - return _class._mangledName;
|
| - }
|
| -
|
| - List<TypeVariableMirror> get typeVariables => _class.typeVariables;
|
| -
|
| - List<TypeMirror> get typeArguments {
|
| - if (_cachedTypeArguments != null) return _cachedTypeArguments;
|
| - List result = new List();
|
| -
|
| - addTypeArgument(String typeArgument) {
|
| - int parsedIndex = int.parse(typeArgument, onError: (_) => -1);
|
| - if (parsedIndex == -1) {
|
| - result.add(reflectClassByMangledName(typeArgument.trim()));
|
| - } else {
|
| - TypeVariable typeVariable = getMetadata(parsedIndex);
|
| - TypeMirror owner = reflectClass(typeVariable.owner);
|
| - TypeVariableMirror typeMirror =
|
| - new JsTypeVariableMirror(typeVariable, owner, parsedIndex);
|
| - result.add(typeMirror);
|
| - }
|
| - }
|
| -
|
| - if (_typeArguments.indexOf('<') == -1) {
|
| - _typeArguments.split(',').forEach((t) => addTypeArgument(t));
|
| - } else {
|
| - int level = 0;
|
| - String currentTypeArgument = '';
|
| -
|
| - for (int i = 0; i < _typeArguments.length; i++) {
|
| - var character = _typeArguments[i];
|
| - if (character == ' ') {
|
| - continue;
|
| - } else if (character == '<') {
|
| - currentTypeArgument += character;
|
| - level++;
|
| - } else if (character == '>') {
|
| - currentTypeArgument += character;
|
| - level--;
|
| - } else if (character == ',') {
|
| - if (level > 0) {
|
| - currentTypeArgument += character;
|
| - } else {
|
| - addTypeArgument(currentTypeArgument);
|
| - currentTypeArgument = '';
|
| - }
|
| - } else {
|
| - currentTypeArgument += character;
|
| - }
|
| - }
|
| - addTypeArgument(currentTypeArgument);
|
| - }
|
| - return _cachedTypeArguments = new UnmodifiableListView(result);
|
| - }
|
| -
|
| - List<JsMethodMirror> get _methods {
|
| - if (_cachedMethods != null) return _cachedMethods;
|
| - return _cachedMethods =_class._getMethodsWithOwner(this);
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get __methods {
|
| - if (_cachedMethodsMap != null) return _cachedMethodsMap;
|
| - return _cachedMethodsMap = new UnmodifiableMapView<Symbol, MethodMirror>(
|
| - filterMethods(_methods));
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get __constructors {
|
| - if (_cachedConstructors != null) return _cachedConstructors;
|
| - return _cachedConstructors =
|
| - new UnmodifiableMapView<Symbol, MethodMirror>(
|
| - filterConstructors(_methods));
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get __getters {
|
| - if (_cachedGetters != null) return _cachedGetters;
|
| - return _cachedGetters = new UnmodifiableMapView<Symbol, MethodMirror>(
|
| - filterGetters(_methods, __variables));
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get __setters {
|
| - if (_cachedSetters != null) return _cachedSetters;
|
| - return _cachedSetters = new UnmodifiableMapView<Symbol, MethodMirror>(
|
| - filterSetters(_methods, __variables));
|
| - }
|
| -
|
| - Map<Symbol, VariableMirror> get __variables {
|
| - if (_cachedVariables != null) return _cachedVariables;
|
| - var result = new Map();
|
| - for (JsVariableMirror mirror in _class._getFieldsWithOwner(this)) {
|
| - result[mirror.simpleName] = mirror;
|
| - }
|
| - return _cachedVariables =
|
| - new UnmodifiableMapView<Symbol, VariableMirror>(result);
|
| - }
|
| -
|
| - Map<Symbol, DeclarationMirror> get __members {
|
| - if (_cachedMembers != null) return _cachedMembers;
|
| - return _cachedMembers = new UnmodifiableMapView<Symbol, DeclarationMirror>(
|
| - filterMembers(_methods, __variables));
|
| - }
|
| -
|
| - Map<Symbol, DeclarationMirror> get declarations {
|
| - if (_cachedDeclarations != null) return _cachedDeclarations;
|
| - Map<Symbol, DeclarationMirror> result =
|
| - new Map<Symbol, DeclarationMirror>();
|
| - result.addAll(__members);
|
| - result.addAll(__constructors);
|
| - typeVariables.forEach((tv) => result[tv.simpleName] = tv);
|
| - return _cachedDeclarations =
|
| - new UnmodifiableMapView<Symbol, DeclarationMirror>(result);
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get staticMembers {
|
| - if (_cachedStaticMembers == null) {
|
| - var result = new Map<Symbol, MethodMirror>();
|
| - declarations.values.forEach((decl) {
|
| - if (decl is MethodMirror && decl.isStatic && !decl.isConstructor) {
|
| - result[decl.simpleName] = decl;
|
| - }
|
| - if (decl is VariableMirror && decl.isStatic) {
|
| - var getterName = decl.simpleName;
|
| - result[getterName] = new JsSyntheticAccessor(
|
| - this, getterName, true, true, false, decl);
|
| - if (!decl.isFinal) {
|
| - var setterName = setterSymbol(decl.simpleName);
|
| - result[setterName] = new JsSyntheticAccessor(
|
| - this, setterName, false, true, false, decl);
|
| - }
|
| - }
|
| - });
|
| - _cachedStaticMembers = result;
|
| - }
|
| - return _cachedStaticMembers;
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get instanceMembers {
|
| - if (_cachedInstanceMembers == null) {
|
| - var result = new Map<Symbol, MethodMirror>();
|
| - if (superclass != null) {
|
| - result.addAll(superclass.instanceMembers);
|
| - }
|
| - declarations.values.forEach((decl) {
|
| - if (decl is MethodMirror && !decl.isStatic &&
|
| - !decl.isConstructor && !decl.isAbstract) {
|
| - result[decl.simpleName] = decl;
|
| - }
|
| - if (decl is VariableMirror && !decl.isStatic) {
|
| - var getterName = decl.simpleName;
|
| - result[getterName] = new JsSyntheticAccessor(
|
| - this, getterName, true, false, false, decl);
|
| - if (!decl.isFinal) {
|
| - var setterName = setterSymbol(decl.simpleName);
|
| - result[setterName] = new JsSyntheticAccessor(
|
| - this, setterName, false, false, false, decl);
|
| - }
|
| - }
|
| - });
|
| - _cachedInstanceMembers = result;
|
| - }
|
| - return _cachedInstanceMembers;
|
| - }
|
| -
|
| - InstanceMirror setField(Symbol fieldName, Object arg) {
|
| - return _class.setField(fieldName, arg);
|
| - }
|
| -
|
| - InstanceMirror getField(Symbol fieldName) => _class.getField(fieldName);
|
| -
|
| - InstanceMirror newInstance(Symbol constructorName,
|
| - List positionalArguments,
|
| - [Map<Symbol, dynamic> namedArguments]) {
|
| - var instance = _class._getInvokedInstance(constructorName,
|
| - positionalArguments,
|
| - namedArguments);
|
| - return reflect(setRuntimeTypeInfo(
|
| - instance, typeArguments.map((t) => t._asRuntimeType()).toList()));
|
| - }
|
| -
|
| - _asRuntimeType() {
|
| - return [_class._jsConstructor].addAll(
|
| - typeArguments.map((t) => t._asRuntimeType()));
|
| - }
|
| -
|
| - JsLibraryMirror get owner => _class.owner;
|
| -
|
| - List<InstanceMirror> get metadata => _class.metadata;
|
| -
|
| - ClassMirror get superclass {
|
| - if (_superclass != null) return _superclass;
|
| -
|
| - List<int> typeInformation =
|
| - JS('List|Null', 'init.typeInformation[#]', _class._mangledName);
|
| - assert(typeInformation != null);
|
| - var type = getMetadata(typeInformation[0]);
|
| - return _superclass = typeMirrorFromRuntimeTypeRepresentation(this, type);
|
| - }
|
| -
|
| - InstanceMirror invoke(Symbol memberName,
|
| - List positionalArguments,
|
| - [Map<Symbol,dynamic> namedArguments]) {
|
| - return _class.invoke(memberName, positionalArguments, namedArguments);
|
| - }
|
| -
|
| - bool get isOriginalDeclaration => false;
|
| -
|
| - ClassMirror get originalDeclaration => _class;
|
| -
|
| - List<ClassMirror> get superinterfaces {
|
| - if (_cachedSuperinterfaces != null) return _cachedSuperinterfaces;
|
| - return _cachedSuperinterfaces = _class._getSuperinterfacesWithOwner(this);
|
| - }
|
| -
|
| - bool get isPrivate => _class.isPrivate;
|
| -
|
| - bool get isTopLevel => _class.isTopLevel;
|
| -
|
| - bool get isAbstract => _class.isAbstract;
|
| -
|
| - bool isSubclassOf(ClassMirror other) => _class.isSubclassOf(other);
|
| -
|
| - SourceLocation get location => _class.location;
|
| -
|
| - MirrorSystem get mirrors => _class.mirrors;
|
| -
|
| - Symbol get qualifiedName => _class.qualifiedName;
|
| -
|
| - bool get hasReflectedType => true;
|
| -
|
| - Type get reflectedType => createRuntimeType(_mangledName);
|
| -
|
| - Symbol get simpleName => _class.simpleName;
|
| -
|
| - // TODO(ahe): Implement this.
|
| - ClassMirror get mixin => throw new UnimplementedError();
|
| -
|
| - bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError();
|
| -
|
| - bool isAssignableTo(TypeMirror other) => throw new UnimplementedError();
|
| -}
|
| -
|
| -class JsSyntheticAccessor implements MethodMirror {
|
| - final DeclarationMirror owner;
|
| - final Symbol simpleName;
|
| - final bool isGetter;
|
| - final bool isStatic;
|
| - final bool isTopLevel;
|
| - final _target; /// The field or type that introduces the synthetic accessor.
|
| -
|
| - JsSyntheticAccessor(this.owner,
|
| - this.simpleName,
|
| - this.isGetter,
|
| - this.isStatic,
|
| - this.isTopLevel,
|
| - this._target);
|
| -
|
| - bool get isSynthetic => true;
|
| - bool get isRegularMethod => false;
|
| - bool get isOperator => false;
|
| - bool get isConstructor => false;
|
| - bool get isConstConstructor => false;
|
| - bool get isGenerativeConstructor => false;
|
| - bool get isFactoryConstructor => false;
|
| - bool get isRedirectingConstructor => false;
|
| - bool get isAbstract => false;
|
| -
|
| - bool get isSetter => !isGetter;
|
| - bool get isPrivate => n(simpleName).startsWith('_');
|
| -
|
| - Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
|
| - Symbol get constructorName => const Symbol('');
|
| -
|
| - TypeMirror get returnType => _target.type;
|
| - List<ParameterMirror> get parameters {
|
| - if (isGetter) return const [];
|
| - return new UnmodifiableListView(
|
| - [new JsSyntheticSetterParameter(this, this._target)]);
|
| - }
|
| -
|
| - List<InstanceMirror> get metadata => const [];
|
| - String get source => null;
|
| - SourceLocation get location => throw new UnimplementedError();
|
| -}
|
| -
|
| -class JsSyntheticSetterParameter implements ParameterMirror {
|
| - final DeclarationMirror owner;
|
| - final VariableMirror _target;
|
| -
|
| - JsSyntheticSetterParameter(this.owner, this._target);
|
| -
|
| - Symbol get simpleName => _target.simpleName;
|
| - Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
|
| - TypeMirror get type => _target.type;
|
| -
|
| - bool get isOptional => false;
|
| - bool get isNamed => false;
|
| - bool get isStatic => false;
|
| - bool get isTopLevel => false;
|
| - bool get isConst => false;
|
| - bool get isFinal => true;
|
| - bool get isPrivate => false;
|
| - bool get hasDefaultValue => false;
|
| - InstanceMirror get defaultValue => null;
|
| - List<InstanceMirror> get metadata => const [];
|
| - SourceLocation get location => throw new UnimplementedError();
|
| -}
|
| -
|
| -class JsClassMirror extends JsTypeMirror with JsObjectMirror
|
| - implements ClassMirror {
|
| - final String _mangledName;
|
| - final _jsConstructor;
|
| - final String _fieldsDescriptor;
|
| - final List _fieldsMetadata;
|
| - final _jsConstructorCache = JsCache.allocate();
|
| - List _metadata;
|
| - ClassMirror _superclass;
|
| - List<JsMethodMirror> _cachedMethods;
|
| - List<VariableMirror> _cachedFields;
|
| - UnmodifiableMapView<Symbol, MethodMirror> _cachedConstructors;
|
| - UnmodifiableMapView<Symbol, MethodMirror> _cachedMethodsMap;
|
| - UnmodifiableMapView<Symbol, MethodMirror> _cachedGetters;
|
| - UnmodifiableMapView<Symbol, MethodMirror> _cachedSetters;
|
| - UnmodifiableMapView<Symbol, VariableMirror> _cachedVariables;
|
| - UnmodifiableMapView<Symbol, Mirror> _cachedMembers;
|
| - UnmodifiableMapView<Symbol, DeclarationMirror> _cachedDeclarations;
|
| - UnmodifiableListView<InstanceMirror> _cachedMetadata;
|
| - UnmodifiableListView<ClassMirror> _cachedSuperinterfaces;
|
| - UnmodifiableListView<TypeVariableMirror> _cachedTypeVariables;
|
| - Map<Symbol, MethodMirror> _cachedInstanceMembers;
|
| - Map<Symbol, MethodMirror> _cachedStaticMembers;
|
| -
|
| - // Set as side-effect of accessing JsLibraryMirror.classes.
|
| - JsLibraryMirror _owner;
|
| -
|
| - JsClassMirror(Symbol simpleName,
|
| - this._mangledName,
|
| - this._jsConstructor,
|
| - this._fieldsDescriptor,
|
| - this._fieldsMetadata)
|
| - : super(simpleName);
|
| -
|
| - String get _prettyName => 'ClassMirror';
|
| -
|
| - Map<Symbol, MethodMirror> get __constructors {
|
| - if (_cachedConstructors != null) return _cachedConstructors;
|
| - return _cachedConstructors =
|
| - new UnmodifiableMapView<Symbol, MethodMirror>(
|
| - filterConstructors(_methods));
|
| - }
|
| -
|
| - _asRuntimeType() {
|
| - if (typeVariables.isEmpty) return _jsConstructor;
|
| - var type = [_jsConstructor];
|
| - for (int i = 0; i < typeVariables.length; i ++) {
|
| - type.add(JsMirrorSystem._dynamicType._asRuntimeType);
|
| - }
|
| - return type;
|
| - }
|
| -
|
| - List<JsMethodMirror> _getMethodsWithOwner(DeclarationMirror methodOwner) {
|
| - var prototype = JS('', '#.prototype', _jsConstructor);
|
| - List<String> keys = extractKeys(prototype);
|
| - var result = <JsMethodMirror>[];
|
| - for (String key in keys) {
|
| - if (isReflectiveDataInPrototype(key)) continue;
|
| - String simpleName = mangledNames[key];
|
| - // [simpleName] can be null if [key] represents an implementation
|
| - // detail, for example, a bailout method, or runtime type support.
|
| - // It might also be null if the user has limited what is reified for
|
| - // reflection with metadata.
|
| - if (simpleName == null) continue;
|
| - var function = JS('', '#[#]', prototype, key);
|
| - if (isNoSuchMethodStub(function)) continue;
|
| - var mirror =
|
| - new JsMethodMirror.fromUnmangledName(
|
| - simpleName, function, false, false);
|
| - result.add(mirror);
|
| - mirror._owner = methodOwner;
|
| - }
|
| -
|
| - keys = extractKeys(JS('', 'init.statics[#]', _mangledName));
|
| - for (String mangledName in keys) {
|
| - if (isReflectiveDataInPrototype(mangledName)) continue;
|
| - String unmangledName = mangledName;
|
| - var jsFunction = JS('', '#[#]', owner._globalObject, mangledName);
|
| -
|
| - bool isConstructor = false;
|
| - if (hasReflectableProperty(jsFunction)) {
|
| - String reflectionName =
|
| - JS('String|Null', r'#.$reflectionName', jsFunction);
|
| - if (reflectionName == null) continue;
|
| - isConstructor = reflectionName.startsWith('new ');
|
| - if (isConstructor) {
|
| - reflectionName = reflectionName.substring(4).replaceAll(r'$', '.');
|
| - }
|
| - unmangledName = reflectionName;
|
| - } else {
|
| - continue;
|
| - }
|
| - bool isStatic = !isConstructor; // Constructors are not static.
|
| - JsMethodMirror mirror =
|
| - new JsMethodMirror.fromUnmangledName(
|
| - unmangledName, jsFunction, isStatic, isConstructor);
|
| - result.add(mirror);
|
| - mirror._owner = methodOwner;
|
| - }
|
| -
|
| - return result;
|
| - }
|
| -
|
| - List<JsMethodMirror> get _methods {
|
| - if (_cachedMethods != null) return _cachedMethods;
|
| - return _cachedMethods = _getMethodsWithOwner(this);
|
| - }
|
| -
|
| - List<VariableMirror> _getFieldsWithOwner(DeclarationMirror fieldOwner) {
|
| - var result = <VariableMirror>[];
|
| -
|
| - var instanceFieldSpecfication = _fieldsDescriptor.split(';')[1];
|
| - if (_fieldsMetadata != null) {
|
| - instanceFieldSpecfication =
|
| - [instanceFieldSpecfication]..addAll(_fieldsMetadata);
|
| - }
|
| - parseCompactFieldSpecification(
|
| - fieldOwner, instanceFieldSpecfication, false, result);
|
| -
|
| - var staticDescriptor = JS('', 'init.statics[#]', _mangledName);
|
| - if (staticDescriptor != null) {
|
| - parseCompactFieldSpecification(
|
| - fieldOwner,
|
| - JS('', '#[#]',
|
| - staticDescriptor, JS_GET_NAME('CLASS_DESCRIPTOR_PROPERTY')),
|
| - true, result);
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - List<VariableMirror> get _fields {
|
| - if (_cachedFields != null) return _cachedFields;
|
| - return _cachedFields = _getFieldsWithOwner(this);
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get __methods {
|
| - if (_cachedMethodsMap != null) return _cachedMethodsMap;
|
| - return _cachedMethodsMap =
|
| - new UnmodifiableMapView<Symbol, MethodMirror>(filterMethods(_methods));
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get __getters {
|
| - if (_cachedGetters != null) return _cachedGetters;
|
| - return _cachedGetters = new UnmodifiableMapView<Symbol, MethodMirror>(
|
| - filterGetters(_methods, __variables));
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get __setters {
|
| - if (_cachedSetters != null) return _cachedSetters;
|
| - return _cachedSetters = new UnmodifiableMapView<Symbol, MethodMirror>(
|
| - filterSetters(_methods, __variables));
|
| - }
|
| -
|
| - Map<Symbol, VariableMirror> get __variables {
|
| - if (_cachedVariables != null) return _cachedVariables;
|
| - var result = new Map();
|
| - for (JsVariableMirror mirror in _fields) {
|
| - result[mirror.simpleName] = mirror;
|
| - }
|
| - return _cachedVariables =
|
| - new UnmodifiableMapView<Symbol, VariableMirror>(result);
|
| - }
|
| -
|
| - Map<Symbol, Mirror> get __members {
|
| - if (_cachedMembers != null) return _cachedMembers;
|
| - return _cachedMembers = new UnmodifiableMapView<Symbol, Mirror>(
|
| - filterMembers(_methods, __variables));
|
| - }
|
| -
|
| - Map<Symbol, DeclarationMirror> get declarations {
|
| - if (_cachedDeclarations != null) return _cachedDeclarations;
|
| - var result = new Map<Symbol, DeclarationMirror>();
|
| - addToResult(Symbol key, Mirror value) {
|
| - result[key] = value;
|
| - }
|
| - __members.forEach(addToResult);
|
| - __constructors.forEach(addToResult);
|
| - typeVariables.forEach((tv) => result[tv.simpleName] = tv);
|
| - return _cachedDeclarations =
|
| - new UnmodifiableMapView<Symbol, DeclarationMirror>(result);
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get staticMembers {
|
| - if (_cachedStaticMembers == null) {
|
| - var result = new Map<Symbol, MethodMirror>();
|
| - declarations.values.forEach((decl) {
|
| - if (decl is MethodMirror && decl.isStatic && !decl.isConstructor) {
|
| - result[decl.simpleName] = decl;
|
| - }
|
| - if (decl is VariableMirror && decl.isStatic) {
|
| - var getterName = decl.simpleName;
|
| - result[getterName] = new JsSyntheticAccessor(
|
| - this, getterName, true, true, false, decl);
|
| - if (!decl.isFinal) {
|
| - var setterName = setterSymbol(decl.simpleName);
|
| - result[setterName] = new JsSyntheticAccessor(
|
| - this, setterName, false, true, false, decl);
|
| - }
|
| - }
|
| - });
|
| - _cachedStaticMembers = result;
|
| - }
|
| - return _cachedStaticMembers;
|
| - }
|
| -
|
| - Map<Symbol, MethodMirror> get instanceMembers {
|
| - if (_cachedInstanceMembers == null) {
|
| - var result = new Map<Symbol, MethodMirror>();
|
| - if (superclass != null) {
|
| - result.addAll(superclass.instanceMembers);
|
| - }
|
| - declarations.values.forEach((decl) {
|
| - if (decl is MethodMirror && !decl.isStatic &&
|
| - !decl.isConstructor && !decl.isAbstract) {
|
| - result[decl.simpleName] = decl;
|
| - }
|
| - if (decl is VariableMirror && !decl.isStatic) {
|
| - var getterName = decl.simpleName;
|
| - result[getterName] = new JsSyntheticAccessor(
|
| - this, getterName, true, false, false, decl);
|
| - if (!decl.isFinal) {
|
| - var setterName = setterSymbol(decl.simpleName);
|
| - result[setterName] = new JsSyntheticAccessor(
|
| - this, setterName, false, false, false, decl);
|
| - }
|
| - }
|
| - });
|
| - _cachedInstanceMembers = result;
|
| - }
|
| - return _cachedInstanceMembers;
|
| - }
|
| -
|
| - InstanceMirror setField(Symbol fieldName, Object arg) {
|
| - JsVariableMirror mirror = __variables[fieldName];
|
| - if (mirror != null && mirror.isStatic && !mirror.isFinal) {
|
| - // '$' (JS_CURRENT_ISOLATE()) stores state which is stored directly, so
|
| - // we shouldn't use [JsLibraryMirror._globalObject] here.
|
| - String jsName = mirror._jsName;
|
| - if (!JS('bool', '# in #', jsName, JS_CURRENT_ISOLATE())) {
|
| - throw new RuntimeError('Cannot find "$jsName" in current isolate.');
|
| - }
|
| - JS('void', '#[#] = #', JS_CURRENT_ISOLATE(), jsName, arg);
|
| - return reflect(arg);
|
| - }
|
| - Symbol setterName = setterSymbol(fieldName);
|
| - if (mirror == null) {
|
| - JsMethodMirror setter = __setters[setterName];
|
| - if (setter != null) {
|
| - setter._invoke([arg], const {});
|
| - return reflect(arg);
|
| - }
|
| - }
|
| - throw new NoSuchStaticMethodError.method(null, setterName, [arg], null);
|
| - }
|
| -
|
| - bool _staticFieldExists(Symbol fieldName) {
|
| - JsVariableMirror mirror = __variables[fieldName];
|
| - if (mirror != null) return mirror.isStatic;
|
| - JsMethodMirror getter = __getters[fieldName];
|
| - return getter != null && getter.isStatic;
|
| - }
|
| -
|
| - InstanceMirror getField(Symbol fieldName) {
|
| - JsVariableMirror mirror = __variables[fieldName];
|
| - if (mirror != null && mirror.isStatic) {
|
| - String jsName = mirror._jsName;
|
| - // '$' (JS_CURRENT_ISOLATE()) stores state which is read directly, so
|
| - // we shouldn't use [JsLibraryMirror._globalObject] here.
|
| - if (!JS('bool', '# in #', jsName, JS_CURRENT_ISOLATE())) {
|
| - throw new RuntimeError('Cannot find "$jsName" in current isolate.');
|
| - }
|
| - if (JS('bool', '# in init.lazies', jsName)) {
|
| - String getterName = JS('String', 'init.lazies[#]', jsName);
|
| - return reflect(JS('', '#[#]()', JS_CURRENT_ISOLATE(), getterName));
|
| - } else {
|
| - return reflect(JS('', '#[#]', JS_CURRENT_ISOLATE(), jsName));
|
| - }
|
| - }
|
| - JsMethodMirror getter = __getters[fieldName];
|
| - if (getter != null && getter.isStatic) {
|
| - return reflect(getter._invoke(const [], const {}));
|
| - }
|
| - // If the fieldName designates a static function we have to return
|
| - // its closure.
|
| - JsMethodMirror method = __methods[fieldName];
|
| - if (method != null && method.isStatic) {
|
| - // We invoke the same getter that Dart code would execute. During
|
| - // initialization we have stored that getter on the function (so that
|
| - // we can find it more easily here).
|
| - var getter = JS("", "#['\$getter']", method._jsFunction);
|
| - if (getter == null) throw new UnimplementedError();
|
| - return reflect(JS("", "#()", getter));
|
| - }
|
| - throw new NoSuchStaticMethodError.method(null, fieldName, null, null);
|
| - }
|
| -
|
| - _getInvokedInstance(Symbol constructorName,
|
| - List positionalArguments,
|
| - [Map<Symbol, dynamic> namedArguments]) {
|
| - if (namedArguments != null && !namedArguments.isEmpty) {
|
| - throw new UnsupportedError('Named arguments are not implemented.');
|
| - }
|
| - JsMethodMirror mirror =
|
| - JsCache.fetch(_jsConstructorCache, n(constructorName));
|
| - if (mirror == null) {
|
| - mirror = __constructors.values.firstWhere(
|
| - (m) => m.constructorName == constructorName,
|
| - orElse: () {
|
| - throw new NoSuchStaticMethodError.method(
|
| - null, constructorName, positionalArguments, namedArguments);
|
| - });
|
| - JsCache.update(_jsConstructorCache, n(constructorName), mirror);
|
| - }
|
| - return mirror._invoke(positionalArguments, namedArguments);
|
| - }
|
| -
|
| - InstanceMirror newInstance(Symbol constructorName,
|
| - List positionalArguments,
|
| - [Map<Symbol, dynamic> namedArguments]) {
|
| - return reflect(_getInvokedInstance(constructorName,
|
| - positionalArguments,
|
| - namedArguments));
|
| - }
|
| -
|
| - JsLibraryMirror get owner {
|
| - if (_owner == null) {
|
| - for (var list in JsMirrorSystem.librariesByName.values) {
|
| - for (JsLibraryMirror library in list) {
|
| - // This will set _owner field on all classes as a side
|
| - // effect. This gives us a fast path to reflect on a
|
| - // class without parsing reflection data.
|
| - library.__classes;
|
| - }
|
| - }
|
| - if (_owner == null) {
|
| - throw new StateError('Class "${n(simpleName)}" has no owner');
|
| - }
|
| - }
|
| - return _owner;
|
| - }
|
| -
|
| - List<InstanceMirror> get metadata {
|
| - if (_cachedMetadata != null) return _cachedMetadata;
|
| - if (_metadata == null) {
|
| - _metadata = extractMetadata(JS('', '#.prototype', _jsConstructor));
|
| - }
|
| - return _cachedMetadata =
|
| - new UnmodifiableListView<InstanceMirror>(_metadata.map(reflect));
|
| - }
|
| -
|
| - ClassMirror get superclass {
|
| - if (_superclass == null) {
|
| - List<int> typeInformation =
|
| - JS('List|Null', 'init.typeInformation[#]', _mangledName);
|
| - if (typeInformation != null) {
|
| - var type = getMetadata(typeInformation[0]);
|
| - _superclass = typeMirrorFromRuntimeTypeRepresentation(this, type);
|
| - } else {
|
| - var superclassName = _fieldsDescriptor.split(';')[0];
|
| - // TODO(zarah): Remove special handing of mixins.
|
| - var mixins = superclassName.split('+');
|
| - if (mixins.length > 1) {
|
| - if (mixins.length != 2) {
|
| - throw new RuntimeError('Strange mixin: $_fieldsDescriptor');
|
| - }
|
| - _superclass = reflectClassByMangledName(mixins[0]);
|
| - } else {
|
| - // Use _superclass == this to represent class with no superclass
|
| - // (Object).
|
| - _superclass = (superclassName == '')
|
| - ? this : reflectClassByMangledName(superclassName);
|
| - }
|
| - }
|
| - }
|
| - return _superclass == this ? null : _superclass;
|
| - }
|
| -
|
| - InstanceMirror invoke(Symbol memberName,
|
| - List positionalArguments,
|
| - [Map<Symbol,dynamic> namedArguments]) {
|
| - // Mirror API gotcha: Calling [invoke] on a ClassMirror means invoke a
|
| - // static method.
|
| -
|
| - if (namedArguments != null && !namedArguments.isEmpty) {
|
| - throw new UnsupportedError('Named arguments are not implemented.');
|
| - }
|
| - JsMethodMirror mirror = __methods[memberName];
|
| -
|
| - if (mirror == null && _staticFieldExists(memberName)) {
|
| - return getField(memberName)
|
| - .invoke(#call, positionalArguments, namedArguments);
|
| - }
|
| - if (mirror == null || !mirror.isStatic) {
|
| - throw new NoSuchStaticMethodError.method(
|
| - null, memberName, positionalArguments, namedArguments);
|
| - }
|
| - if (!mirror.canInvokeReflectively()) {
|
| - throwInvalidReflectionError(n(memberName));
|
| - }
|
| - return reflect(mirror._invoke(positionalArguments, namedArguments));
|
| - }
|
| -
|
| - bool get isOriginalDeclaration => true;
|
| -
|
| - ClassMirror get originalDeclaration => this;
|
| -
|
| - List<ClassMirror> _getSuperinterfacesWithOwner(DeclarationMirror owner) {
|
| - List<int> typeInformation =
|
| - JS('List|Null', 'init.typeInformation[#]', _mangledName);
|
| - List<ClassMirror> result = const <ClassMirror>[];
|
| - if (typeInformation != null) {
|
| - ClassMirror lookupType(int i) {
|
| - var type = getMetadata(i);
|
| - return typeMirrorFromRuntimeTypeRepresentation(owner, type);
|
| - }
|
| -
|
| - //We skip the first since it is the supertype.
|
| - result = typeInformation.skip(1).map(lookupType).toList();
|
| - }
|
| -
|
| - return new UnmodifiableListView<ClassMirror>(result);
|
| - }
|
| -
|
| - List<ClassMirror> get superinterfaces {
|
| - if (_cachedSuperinterfaces != null) return _cachedSuperinterfaces;
|
| - return _cachedSuperinterfaces = _getSuperinterfacesWithOwner(this);
|
| - }
|
| -
|
| - List<TypeVariableMirror> get typeVariables {
|
| - if (_cachedTypeVariables != null) return _cachedTypeVariables;
|
| - List result = new List();
|
| - List typeVariables =
|
| - JS('JSExtendableArray|Null', '#.prototype["<>"]', _jsConstructor);
|
| - if (typeVariables == null) return result;
|
| - for (int i = 0; i < typeVariables.length; i++) {
|
| - TypeVariable typeVariable = getMetadata(typeVariables[i]);
|
| - result.add(new JsTypeVariableMirror(typeVariable, this,
|
| - typeVariables[i]));
|
| - }
|
| - return _cachedTypeVariables = new UnmodifiableListView(result);
|
| - }
|
| -
|
| - List<TypeMirror> get typeArguments => const <TypeMirror>[];
|
| -
|
| - bool get hasReflectedType => typeVariables.length == 0;
|
| -
|
| - Type get reflectedType {
|
| - if (!hasReflectedType) {
|
| - throw new UnsupportedError(
|
| - "Declarations of generics have no reflected type");
|
| - }
|
| - return createRuntimeType(_mangledName);
|
| - }
|
| -
|
| - // TODO(ahe): Implement this.
|
| - ClassMirror get mixin => throw new UnimplementedError();
|
| -
|
| - bool get isAbstract => throw new UnimplementedError();
|
| -
|
| - bool isSubclassOf(ClassMirror other) {
|
| - if (other is! ClassMirror) {
|
| - throw new ArgumentError(other);
|
| - }
|
| - if (other is JsFunctionTypeMirror) {
|
| - return false;
|
| - } if (other is JsClassMirror &&
|
| - JS('bool', '# == #', other._jsConstructor, _jsConstructor)) {
|
| - return true;
|
| - } else if (superclass == null) {
|
| - return false;
|
| - } else {
|
| - return superclass.isSubclassOf(other);
|
| - }
|
| - }
|
| -}
|
| -
|
| -class JsVariableMirror extends JsDeclarationMirror implements VariableMirror {
|
| -
|
| - // TODO(ahe): The values in these fields are virtually untested.
|
| - final String _jsName;
|
| - final bool isFinal;
|
| - final bool isStatic;
|
| - final _metadataFunction;
|
| - final DeclarationMirror _owner;
|
| - final int _type;
|
| - List _metadata;
|
| -
|
| - JsVariableMirror(Symbol simpleName,
|
| - this._jsName,
|
| - this._type,
|
| - this.isFinal,
|
| - this.isStatic,
|
| - this._metadataFunction,
|
| - this._owner)
|
| - : super(simpleName);
|
| -
|
| - factory JsVariableMirror.from(String descriptor,
|
| - metadataFunction,
|
| - JsDeclarationMirror owner,
|
| - bool isStatic) {
|
| - List<String> fieldInformation = descriptor.split('-');
|
| - if (fieldInformation.length == 1) {
|
| - // The field is not available for reflection.
|
| - // TODO(ahe): Should return an unreflectable field.
|
| - return null;
|
| - }
|
| -
|
| - String field = fieldInformation[0];
|
| - int length = field.length;
|
| - var code = fieldCode(field.codeUnitAt(length - 1));
|
| - bool isFinal = false;
|
| - if (code == 0) return null; // Inherited field.
|
| - bool hasGetter = (code & 3) != 0;
|
| - bool hasSetter = (code >> 2) != 0;
|
| - isFinal = !hasSetter;
|
| - length--;
|
| - String jsName;
|
| - String accessorName = jsName = field.substring(0, length);
|
| - int divider = field.indexOf(':');
|
| - if (divider > 0) {
|
| - accessorName = accessorName.substring(0, divider);
|
| - jsName = field.substring(divider + 1);
|
| - }
|
| - var unmangledName;
|
| - if (isStatic) {
|
| - unmangledName = mangledGlobalNames[accessorName];
|
| - } else {
|
| - String getterPrefix = JS_GET_NAME('GETTER_PREFIX');
|
| - unmangledName = mangledNames['$getterPrefix$accessorName'];
|
| - }
|
| - if (unmangledName == null) unmangledName = accessorName;
|
| - if (!hasSetter) {
|
| - // TODO(ahe): This is a hack to handle checked setters in checked mode.
|
| - var setterName = s('$unmangledName=');
|
| - for (JsMethodMirror method in owner._methods) {
|
| - if (method.simpleName == setterName) {
|
| - isFinal = false;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - int type = int.parse(fieldInformation[1]);
|
| - return new JsVariableMirror(s(unmangledName),
|
| - jsName,
|
| - type,
|
| - isFinal,
|
| - isStatic,
|
| - metadataFunction,
|
| - owner);
|
| - }
|
| -
|
| - String get _prettyName => 'VariableMirror';
|
| -
|
| - TypeMirror get type {
|
| - return typeMirrorFromRuntimeTypeRepresentation(owner, getMetadata(_type));
|
| - }
|
| -
|
| - DeclarationMirror get owner => _owner;
|
| -
|
| - List<InstanceMirror> get metadata {
|
| - preserveMetadata();
|
| - if (_metadata == null) {
|
| - _metadata = (_metadataFunction == null)
|
| - ? const [] : JS('', '#()', _metadataFunction);
|
| - }
|
| - return _metadata.map(reflect).toList();
|
| - }
|
| -
|
| - static int fieldCode(int code) {
|
| - if (code >= 60 && code <= 64) return code - 59;
|
| - if (code >= 123 && code <= 126) return code - 117;
|
| - if (code >= 37 && code <= 43) return code - 27;
|
| - return 0;
|
| - }
|
| -
|
| - _getField(JsMirror receiver) => receiver._loadField(_jsName);
|
| -
|
| - void _setField(JsMirror receiver, Object arg) {
|
| - if (isFinal) {
|
| - // TODO(floitsch): when the field is non-static we don't want to have
|
| - // a mirror as receiver.
|
| - if (isStatic) {
|
| - throw new NoSuchStaticMethodError.method(
|
| - null, setterSymbol(simpleName), [arg], null);
|
| - }
|
| - throw new NoSuchMethodError(this, setterSymbol(simpleName), [arg], null);
|
| - }
|
| - receiver._storeField(_jsName, arg);
|
| - }
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - bool get isConst => throw new UnimplementedError();
|
| -}
|
| -
|
| -class JsClosureMirror extends JsInstanceMirror implements ClosureMirror {
|
| - JsClosureMirror(reflectee)
|
| - : super(reflectee);
|
| -
|
| - MethodMirror get function {
|
| - String cacheName = Primitives.mirrorFunctionCacheName;
|
| - JsMethodMirror cachedFunction;
|
| - // TODO(ahe): Restore caching.
|
| - //= JS('JsMethodMirror|Null', r'#.constructor[#]', reflectee, cacheName);
|
| - if (cachedFunction != null) return cachedFunction;
|
| - disableTreeShaking();
|
| - // TODO(ahe): What about optional parameters (named or not).
|
| - String callPrefix = "${JS_GET_NAME("CALL_PREFIX")}\$";
|
| - var extractCallName = JS('', r'''
|
| -function(reflectee) {
|
| - for (var property in reflectee) {
|
| - if (# == property.substring(0, #) &&
|
| - property[#] >= '0' &&
|
| - property[#] <= '9') return property;
|
| - }
|
| - return null;
|
| -}
|
| -''', callPrefix, callPrefix.length, callPrefix.length, callPrefix.length);
|
| - String callName = JS('String|Null', '#(#)', extractCallName, reflectee);
|
| - if (callName == null) {
|
| - throw new RuntimeError('Cannot find callName on "$reflectee"');
|
| - }
|
| - // TODO(floitsch): What about optional parameters?
|
| - int parameterCount = int.parse(callName.split(r'$')[1]);
|
| - if (reflectee is BoundClosure) {
|
| - var target = BoundClosure.targetOf(reflectee);
|
| - var self = BoundClosure.selfOf(reflectee);
|
| - var name = mangledNames[BoundClosure.nameOf(reflectee)];
|
| - if (name == null) {
|
| - throwInvalidReflectionError(name);
|
| - }
|
| - cachedFunction = new JsMethodMirror.fromUnmangledName(
|
| - name, target, false, false);
|
| - } else {
|
| - bool isStatic = true; // TODO(ahe): Compute isStatic correctly.
|
| - var jsFunction = JS('', '#[#]', reflectee, callName);
|
| - var dummyOptionalParameterCount = 0;
|
| - cachedFunction = new JsMethodMirror(
|
| - s(callName), jsFunction, parameterCount, dummyOptionalParameterCount,
|
| - false, false, isStatic, false, false);
|
| - }
|
| - JS('void', r'#.constructor[#] = #', reflectee, cacheName, cachedFunction);
|
| - return cachedFunction;
|
| - }
|
| -
|
| - InstanceMirror apply(List positionalArguments,
|
| - [Map<Symbol, dynamic> namedArguments]) {
|
| - return reflect(
|
| - Function.apply(reflectee, positionalArguments, namedArguments));
|
| - }
|
| -
|
| - String toString() => "ClosureMirror on '${Error.safeToString(reflectee)}'";
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - String get source => throw new UnimplementedError();
|
| -}
|
| -
|
| -class JsMethodMirror extends JsDeclarationMirror implements MethodMirror {
|
| - final _jsFunction;
|
| - final int _requiredParameterCount;
|
| - final int _optionalParameterCount;
|
| - final bool isGetter;
|
| - final bool isSetter;
|
| - final bool isStatic;
|
| - final bool isConstructor;
|
| - final bool isOperator;
|
| - DeclarationMirror _owner;
|
| - List _metadata;
|
| - TypeMirror _returnType;
|
| - UnmodifiableListView<ParameterMirror> _parameters;
|
| -
|
| - JsMethodMirror(Symbol simpleName,
|
| - this._jsFunction,
|
| - this._requiredParameterCount,
|
| - this._optionalParameterCount,
|
| - this.isGetter,
|
| - this.isSetter,
|
| - this.isStatic,
|
| - this.isConstructor,
|
| - this.isOperator)
|
| - : super(simpleName);
|
| -
|
| - factory JsMethodMirror.fromUnmangledName(String name,
|
| - jsFunction,
|
| - bool isStatic,
|
| - bool isConstructor) {
|
| - List<String> info = name.split(':');
|
| - name = info[0];
|
| - bool isOperator = isOperatorName(name);
|
| - bool isSetter = !isOperator && name.endsWith('=');
|
| - int requiredParameterCount = 0;
|
| - int optionalParameterCount = 0;
|
| - bool isGetter = false;
|
| - if (info.length == 1) {
|
| - if (isSetter) {
|
| - requiredParameterCount = 1;
|
| - } else {
|
| - isGetter = true;
|
| - requiredParameterCount = 0;
|
| - }
|
| - } else {
|
| - requiredParameterCount = int.parse(info[1]);
|
| - optionalParameterCount = int.parse(info[2]);
|
| - }
|
| - return new JsMethodMirror(
|
| - s(name), jsFunction, requiredParameterCount, optionalParameterCount,
|
| - isGetter, isSetter, isStatic, isConstructor, isOperator);
|
| - }
|
| -
|
| - String get _prettyName => 'MethodMirror';
|
| -
|
| - int get _parameterCount => _requiredParameterCount + _optionalParameterCount;
|
| -
|
| - List<ParameterMirror> get parameters {
|
| - if (_parameters != null) return _parameters;
|
| - metadata; // Compute _parameters as a side-effect of extracting metadata.
|
| - return _parameters;
|
| - }
|
| -
|
| - bool canInvokeReflectively() {
|
| - return hasReflectableProperty(_jsFunction);
|
| - }
|
| -
|
| - DeclarationMirror get owner => _owner;
|
| -
|
| - TypeMirror get returnType {
|
| - metadata; // Compute _returnType as a side-effect of extracting metadata.
|
| - return _returnType;
|
| - }
|
| -
|
| - List<InstanceMirror> get metadata {
|
| - if (_metadata == null) {
|
| - var raw = extractMetadata(_jsFunction);
|
| - var formals = new List(_parameterCount);
|
| - ReflectionInfo info = new ReflectionInfo(_jsFunction);
|
| - if (info != null) {
|
| - assert(_parameterCount
|
| - == info.requiredParameterCount + info.optionalParameterCount);
|
| - var functionType = info.functionType;
|
| - var type;
|
| - if (functionType is int) {
|
| - type = new JsFunctionTypeMirror(info.computeFunctionRti(null), this);
|
| - assert(_parameterCount == type.parameters.length);
|
| - } else if (isTopLevel) {
|
| - type = new JsFunctionTypeMirror(info.computeFunctionRti(null), owner);
|
| - } else {
|
| - TypeMirror ownerType = owner;
|
| - JsClassMirror ownerClass = ownerType.originalDeclaration;
|
| - type = new JsFunctionTypeMirror(
|
| - info.computeFunctionRti(ownerClass._jsConstructor),
|
| - owner);
|
| - }
|
| - // Constructors aren't reified with their return type.
|
| - if (isConstructor) {
|
| - _returnType = owner;
|
| - } else {
|
| - _returnType = type.returnType;
|
| - }
|
| - int i = 0;
|
| - bool isNamed = info.areOptionalParametersNamed;
|
| - for (JsParameterMirror parameter in type.parameters) {
|
| - var name = info.parameterName(i);
|
| - List<int> annotations = info.parameterMetadataAnnotations(i);
|
| - var p;
|
| - if (i < info.requiredParameterCount) {
|
| - p = new JsParameterMirror(name, this, parameter._type,
|
| - metadataList: annotations);
|
| - } else {
|
| - var defaultValue = info.defaultValue(i);
|
| - p = new JsParameterMirror(
|
| - name, this, parameter._type, metadataList: annotations,
|
| - isOptional: true, isNamed: isNamed, defaultValue: defaultValue);
|
| - }
|
| - formals[i++] = p;
|
| - }
|
| - }
|
| - _parameters = new UnmodifiableListView<ParameterMirror>(formals);
|
| - _metadata = new UnmodifiableListView(raw.map(reflect));
|
| - }
|
| - return _metadata;
|
| - }
|
| -
|
| - Symbol get constructorName {
|
| - // TODO(ahe): I believe it is more appropriate to throw an exception or
|
| - // return null.
|
| - if (!isConstructor) return const Symbol('');
|
| - String name = n(simpleName);
|
| - int index = name.indexOf('.');
|
| - if (index == -1) return const Symbol('');
|
| - return s(name.substring(index + 1));
|
| - }
|
| -
|
| - _invoke(List positionalArguments, Map<Symbol, dynamic> namedArguments) {
|
| - if (namedArguments != null && !namedArguments.isEmpty) {
|
| - throw new UnsupportedError('Named arguments are not implemented.');
|
| - }
|
| - if (!isStatic && !isConstructor) {
|
| - throw new RuntimeError('Cannot invoke instance method without receiver.');
|
| - }
|
| - int positionalLength = positionalArguments.length;
|
| - if (positionalLength < _requiredParameterCount ||
|
| - positionalLength > _parameterCount ||
|
| - _jsFunction == null) {
|
| - // TODO(ahe): What receiver to use?
|
| - throw new NoSuchMethodError(
|
| - owner, simpleName, positionalArguments, namedArguments);
|
| - }
|
| - if (positionalLength < _parameterCount) {
|
| - // Fill up with default values.
|
| - // Make a copy so we don't modify the input.
|
| - positionalArguments = positionalArguments.toList();
|
| - for (int i = positionalLength; i < parameters.length; i++) {
|
| - JsParameterMirror parameter = parameters[i];
|
| - positionalArguments.add(parameter.defaultValue.reflectee);
|
| - }
|
| - }
|
| - // Using JS_CURRENT_ISOLATE() ('$') here is actually correct, although
|
| - // _jsFunction may not be a property of '$', most static functions do not
|
| - // care who their receiver is. But to lazy getters, it is important that
|
| - // 'this' is '$'.
|
| - return JS('', r'#.apply(#, #)', _jsFunction, JS_CURRENT_ISOLATE(),
|
| - new List.from(positionalArguments));
|
| - }
|
| -
|
| - _getField(JsMirror receiver) {
|
| - if (isGetter) {
|
| - return _invoke([], null);
|
| - } else {
|
| - // TODO(ahe): Closurize method.
|
| - throw new UnimplementedError('getField on $receiver');
|
| - }
|
| - }
|
| -
|
| - _setField(JsMirror receiver, Object arg) {
|
| - if (isSetter) {
|
| - return _invoke([arg], null);
|
| - } else {
|
| - throw new NoSuchMethodError(this, setterSymbol(simpleName), [], null);
|
| - }
|
| - }
|
| -
|
| - // Abstract methods are tree-shaken away.
|
| - bool get isAbstract => false;
|
| -
|
| - // TODO(ahe, 14633): This might not be true for all cases.
|
| - bool get isSynthetic => false;
|
| -
|
| - // TODO(ahe): Test this.
|
| - bool get isRegularMethod => !isGetter && !isSetter && !isConstructor;
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - bool get isConstConstructor => throw new UnimplementedError();
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - bool get isGenerativeConstructor => throw new UnimplementedError();
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - bool get isRedirectingConstructor => throw new UnimplementedError();
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - bool get isFactoryConstructor => throw new UnimplementedError();
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - String get source => throw new UnimplementedError();
|
| -}
|
| -
|
| -class JsParameterMirror extends JsDeclarationMirror implements ParameterMirror {
|
| - final DeclarationMirror owner;
|
| - // A JS object representing the type.
|
| - final _type;
|
| -
|
| - final bool isOptional;
|
| -
|
| - final bool isNamed;
|
| -
|
| - final int _defaultValue;
|
| -
|
| - final List<int> metadataList;
|
| -
|
| - JsParameterMirror(String unmangledName,
|
| - this.owner,
|
| - this._type,
|
| - {this.metadataList: const <int>[],
|
| - this.isOptional: false,
|
| - this.isNamed: false,
|
| - defaultValue})
|
| - : _defaultValue = defaultValue,
|
| - super(s(unmangledName));
|
| -
|
| - String get _prettyName => 'ParameterMirror';
|
| -
|
| - TypeMirror get type {
|
| - return typeMirrorFromRuntimeTypeRepresentation(owner, _type);
|
| - }
|
| -
|
| - // Only true for static fields, never for a parameter.
|
| - bool get isStatic => false;
|
| -
|
| - // TODO(ahe): Implement this.
|
| - bool get isFinal => false;
|
| -
|
| - // TODO(ahe): Implement this.
|
| - bool get isConst => false;
|
| -
|
| - bool get hasDefaultValue => _defaultValue != null;
|
| -
|
| - get defaultValue {
|
| - return hasDefaultValue ? reflect(getMetadata(_defaultValue)) : null;
|
| - }
|
| -
|
| - List<InstanceMirror> get metadata {
|
| - preserveMetadata();
|
| - return metadataList.map((int i) => reflect(getMetadata(i))).toList();
|
| - }
|
| -}
|
| -
|
| -class JsTypedefMirror extends JsDeclarationMirror implements TypedefMirror {
|
| - final String _mangledName;
|
| - JsFunctionTypeMirror referent;
|
| -
|
| - JsTypedefMirror(Symbol simpleName, this._mangledName, _typeData)
|
| - : super(simpleName) {
|
| - referent = new JsFunctionTypeMirror(_typeData, this);
|
| - }
|
| -
|
| - JsFunctionTypeMirror get value => referent;
|
| -
|
| - String get _prettyName => 'TypedefMirror';
|
| -
|
| - bool get hasReflectedType => throw new UnimplementedError();
|
| -
|
| - Type get reflectedType => throw new UnimplementedError();
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - List<TypeVariableMirror> get typeVariables => throw new UnimplementedError();
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - List<TypeMirror> get typeArguments => throw new UnimplementedError();
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - bool get isOriginalDeclaration => throw new UnimplementedError();
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - TypeMirror get originalDeclaration => throw new UnimplementedError();
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - DeclarationMirror get owner => throw new UnimplementedError();
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - List<InstanceMirror> get metadata => throw new UnimplementedError();
|
| -
|
| - bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError();
|
| - bool isAssignableTo(TypeMirror other) => throw new UnimplementedError();
|
| -}
|
| -
|
| -// TODO(ahe): Remove this class when API is updated.
|
| -class BrokenClassMirror {
|
| - bool get hasReflectedType => throw new UnimplementedError();
|
| - Type get reflectedType => throw new UnimplementedError();
|
| - ClassMirror get superclass => throw new UnimplementedError();
|
| - List<ClassMirror> get superinterfaces => throw new UnimplementedError();
|
| - Map<Symbol, DeclarationMirror> get declarations
|
| - => throw new UnimplementedError();
|
| - Map<Symbol, MethodMirror> get instanceMembers
|
| - => throw new UnimplementedError();
|
| - Map<Symbol, MethodMirror> get staticMembers => throw new UnimplementedError();
|
| - ClassMirror get mixin => throw new UnimplementedError();
|
| - InstanceMirror newInstance(
|
| - Symbol constructorName,
|
| - List positionalArguments,
|
| - [Map<Symbol, dynamic> namedArguments]) => throw new UnimplementedError();
|
| - InstanceMirror invoke(Symbol memberName,
|
| - List positionalArguments,
|
| - [Map<Symbol, dynamic> namedArguments])
|
| - => throw new UnimplementedError();
|
| - InstanceMirror getField(Symbol fieldName) => throw new UnimplementedError();
|
| - InstanceMirror setField(Symbol fieldName, Object value)
|
| - => throw new UnimplementedError();
|
| - List<TypeVariableMirror> get typeVariables => throw new UnimplementedError();
|
| - List<TypeMirror> get typeArguments => throw new UnimplementedError();
|
| - TypeMirror get originalDeclaration => throw new UnimplementedError();
|
| - Symbol get simpleName => throw new UnimplementedError();
|
| - Symbol get qualifiedName => throw new UnimplementedError();
|
| - bool get isPrivate => throw new UnimplementedError();
|
| - bool get isTopLevel => throw new UnimplementedError();
|
| - SourceLocation get location => throw new UnimplementedError();
|
| - List<InstanceMirror> get metadata => throw new UnimplementedError();
|
| -}
|
| -
|
| -class JsFunctionTypeMirror extends BrokenClassMirror
|
| - implements FunctionTypeMirror {
|
| - final _typeData;
|
| - String _cachedToString;
|
| - TypeMirror _cachedReturnType;
|
| - UnmodifiableListView<ParameterMirror> _cachedParameters;
|
| - DeclarationMirror owner;
|
| -
|
| - JsFunctionTypeMirror(this._typeData, this.owner);
|
| -
|
| - bool get _hasReturnType => JS('bool', '"ret" in #', _typeData);
|
| - get _returnType => JS('', '#.ret', _typeData);
|
| -
|
| - bool get _isVoid => JS('bool', '!!#.void', _typeData);
|
| -
|
| - bool get _hasArguments => JS('bool', '"args" in #', _typeData);
|
| - List get _arguments => JS('JSExtendableArray', '#.args', _typeData);
|
| -
|
| - bool get _hasOptionalArguments => JS('bool', '"opt" in #', _typeData);
|
| - List get _optionalArguments => JS('JSExtendableArray', '#.opt', _typeData);
|
| -
|
| - bool get _hasNamedArguments => JS('bool', '"named" in #', _typeData);
|
| - get _namedArguments => JS('=Object', '#.named', _typeData);
|
| - bool get isOriginalDeclaration => true;
|
| -
|
| - bool get isAbstract => false;
|
| -
|
| - TypeMirror get returnType {
|
| - if (_cachedReturnType != null) return _cachedReturnType;
|
| - if (_isVoid) return _cachedReturnType = JsMirrorSystem._voidType;
|
| - if (!_hasReturnType) return _cachedReturnType = JsMirrorSystem._dynamicType;
|
| - return _cachedReturnType =
|
| - typeMirrorFromRuntimeTypeRepresentation(owner, _returnType);
|
| - }
|
| -
|
| - List<ParameterMirror> get parameters {
|
| - if (_cachedParameters != null) return _cachedParameters;
|
| - List result = [];
|
| - int parameterCount = 0;
|
| - if (_hasArguments) {
|
| - for (var type in _arguments) {
|
| - result.add(
|
| - new JsParameterMirror('argument${parameterCount++}', this, type));
|
| - }
|
| - }
|
| - if (_hasOptionalArguments) {
|
| - for (var type in _optionalArguments) {
|
| - result.add(
|
| - new JsParameterMirror('argument${parameterCount++}', this, type));
|
| - }
|
| - }
|
| - if (_hasNamedArguments) {
|
| - for (var name in extractKeys(_namedArguments)) {
|
| - var type = JS('', '#[#]', _namedArguments, name);
|
| - result.add(new JsParameterMirror(name, this, type));
|
| - }
|
| - }
|
| - return _cachedParameters = new UnmodifiableListView<ParameterMirror>(
|
| - result);
|
| - }
|
| -
|
| - String _unmangleIfPreserved(String mangled) {
|
| - String result = unmangleGlobalNameIfPreservedAnyways(mangled);
|
| - if (result != null) return result;
|
| - return mangled;
|
| - }
|
| -
|
| - String toString() {
|
| - if (_cachedToString != null) return _cachedToString;
|
| - var s = "FunctionTypeMirror on '(";
|
| - var sep = '';
|
| - if (_hasArguments) {
|
| - for (var argument in _arguments) {
|
| - s += sep;
|
| - s += _unmangleIfPreserved(runtimeTypeToString(argument));
|
| - sep = ', ';
|
| - }
|
| - }
|
| - if (_hasOptionalArguments) {
|
| - s += '$sep[';
|
| - sep = '';
|
| - for (var argument in _optionalArguments) {
|
| - s += sep;
|
| - s += _unmangleIfPreserved(runtimeTypeToString(argument));
|
| - sep = ', ';
|
| - }
|
| - s += ']';
|
| - }
|
| - if (_hasNamedArguments) {
|
| - s += '$sep{';
|
| - sep = '';
|
| - for (var name in extractKeys(_namedArguments)) {
|
| - s += sep;
|
| - s += '$name: ';
|
| - s += _unmangleIfPreserved(
|
| - runtimeTypeToString(JS('', '#[#]', _namedArguments, name)));
|
| - sep = ', ';
|
| - }
|
| - s += '}';
|
| - }
|
| - s += ') -> ';
|
| - if (_isVoid) {
|
| - s += 'void';
|
| - } else if (_hasReturnType) {
|
| - s += _unmangleIfPreserved(runtimeTypeToString(_returnType));
|
| - } else {
|
| - s += 'dynamic';
|
| - }
|
| - return _cachedToString = "$s'";
|
| - }
|
| -
|
| - bool isSubclassOf(ClassMirror other) => false;
|
| -
|
| - bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError();
|
| -
|
| - bool isAssignableTo(TypeMirror other) => throw new UnimplementedError();
|
| -
|
| - // TODO(ahe): Implement this method.
|
| - MethodMirror get callMethod => throw new UnimplementedError();
|
| -}
|
| -
|
| -int findTypeVariableIndex(List<TypeVariableMirror> typeVariables, String name) {
|
| - for (int i = 0; i < typeVariables.length; i++) {
|
| - if (typeVariables[i].simpleName == s(name)) {
|
| - return i;
|
| - }
|
| - }
|
| - throw new ArgumentError('Type variable not present in list.');
|
| -}
|
| -
|
| -TypeMirror typeMirrorFromRuntimeTypeRepresentation(
|
| - DeclarationMirror owner,
|
| - var /*int|List|JsFunction*/ type) {
|
| - // TODO(ahe): This method might benefit from using convertRtiToRuntimeType
|
| - // instead of working on strings.
|
| - ClassMirror ownerClass;
|
| - DeclarationMirror context = owner;
|
| - while (context != null) {
|
| - if (context is ClassMirror) {
|
| - ownerClass = context;
|
| - break;
|
| - }
|
| - // TODO(ahe): Get type parameters and arguments from typedefs.
|
| - if (context is TypedefMirror) break;
|
| - context = context.owner;
|
| - }
|
| -
|
| - String representation;
|
| - if (type == null) {
|
| - return JsMirrorSystem._dynamicType;
|
| - } else if (type is Type) {
|
| - return reflectType(type);
|
| - } else if (ownerClass == null) {
|
| - representation = runtimeTypeToString(type);
|
| - } else if (ownerClass.isOriginalDeclaration) {
|
| - if (type is num) {
|
| - // [type] represents a type variable so in the context of an original
|
| - // declaration the corresponding type variable should be returned.
|
| - TypeVariable typeVariable = getMetadata(type);
|
| - List<TypeVariableMirror> typeVariables = ownerClass.typeVariables;
|
| - int index = findTypeVariableIndex(typeVariables, typeVariable.name);
|
| - return typeVariables[index];
|
| - } else {
|
| - // Nested type variables will be retrieved lazily (the integer
|
| - // representation is kept in the string) so they are not processed here.
|
| - representation = runtimeTypeToString(type);
|
| - }
|
| - } else {
|
| - TypeMirror getTypeArgument(int index) {
|
| - TypeVariable typeVariable = getMetadata(index);
|
| - int variableIndex =
|
| - findTypeVariableIndex(ownerClass.typeVariables, typeVariable.name);
|
| - return ownerClass.typeArguments[variableIndex];
|
| - }
|
| -
|
| - if (type is num) {
|
| - // [type] represents a type variable used as type argument for example
|
| - // the type argument of Bar: class Foo<T> extends Bar<T> {}
|
| - TypeMirror typeArgument = getTypeArgument(type);
|
| - if (typeArgument is JsTypeVariableMirror)
|
| - return typeArgument;
|
| - }
|
| - String substituteTypeVariable(int index) {
|
| - var typeArgument = getTypeArgument(index);
|
| - if (typeArgument is JsTypeVariableMirror) {
|
| - return '${typeArgument._metadataIndex}';
|
| - }
|
| - if (typeArgument is! JsClassMirror &&
|
| - typeArgument is! JsTypeBoundClassMirror) {
|
| - if (typeArgument == JsMirrorSystem._dynamicType) {
|
| - return 'dynamic';
|
| - } else if (typeArgument == JsMirrorSystem._voidType) {
|
| - return 'void';
|
| - } else {
|
| - // TODO(ahe): This case shouldn't happen.
|
| - return 'dynamic';
|
| - }
|
| - }
|
| - return typeArgument._mangledName;
|
| - }
|
| - representation =
|
| - runtimeTypeToString(type, onTypeVariable: substituteTypeVariable);
|
| - }
|
| - if (representation != null) {
|
| - return reflectClassByMangledName(
|
| - getMangledTypeName(createRuntimeType(representation)));
|
| - }
|
| - if (type != null && JS('Object|Null', '#.typedef', type) != null) {
|
| - return typeMirrorFromRuntimeTypeRepresentation(
|
| - owner, JS('Object', '#.typedef', type));
|
| - } else if (type != null && JS('Object|Null', '#.func', type) != null) {
|
| - return new JsFunctionTypeMirror(type, owner);
|
| - }
|
| - return reflectClass(Function);
|
| -}
|
| -
|
| -Symbol computeQualifiedName(DeclarationMirror owner, Symbol simpleName) {
|
| - if (owner == null) return simpleName;
|
| - String ownerName = n(owner.qualifiedName);
|
| - return s('$ownerName.${n(simpleName)}');
|
| -}
|
| -
|
| -List extractMetadata(victim) {
|
| - preserveMetadata();
|
| - var metadataFunction;
|
| - if (JS('bool', 'Object.prototype.hasOwnProperty.call(#, "@")', victim)) {
|
| - metadataFunction = JS('', '#["@"]', victim);
|
| - }
|
| - if (metadataFunction != null) return JS('', '#()', metadataFunction);
|
| - if (JS('bool', 'typeof # != "function"', victim)) return const [];
|
| - if (JS('bool', '# in #', r'$metadataIndex', victim)) {
|
| - return JSArray.markFixedList(
|
| - JS('JSExtendableArray',
|
| - r'#.$reflectionInfo.splice(#.$metadataIndex)', victim, victim))
|
| - .map((int i) => getMetadata(i)).toList();
|
| - }
|
| - return const [];
|
| -}
|
| -
|
| -void parseCompactFieldSpecification(
|
| - JsDeclarationMirror owner,
|
| - fieldSpecification,
|
| - bool isStatic,
|
| - List<Mirror> result) {
|
| - List fieldsMetadata = null;
|
| - List<String> fields;
|
| - if (fieldSpecification is List) {
|
| - fields = splitFields(fieldSpecification[0], ',');
|
| - fieldsMetadata = fieldSpecification.sublist(1);
|
| - } else if (fieldSpecification is String) {
|
| - fields = splitFields(fieldSpecification, ',');
|
| - } else {
|
| - fields = [];
|
| - }
|
| - int fieldNumber = 0;
|
| - for (String field in fields) {
|
| - var metadata;
|
| - if (fieldsMetadata != null) {
|
| - metadata = fieldsMetadata[fieldNumber++];
|
| - }
|
| - var mirror = new JsVariableMirror.from(field, metadata, owner, isStatic);
|
| - if (mirror != null) {
|
| - result.add(mirror);
|
| - }
|
| - }
|
| -}
|
| -
|
| -/// Similar to [String.split], but returns an empty list if [string] is empty.
|
| -List<String> splitFields(String string, Pattern pattern) {
|
| - if (string.isEmpty) return <String>[];
|
| - return string.split(pattern);
|
| -}
|
| -
|
| -bool isOperatorName(String name) {
|
| - switch (name) {
|
| - case '==':
|
| - case '[]':
|
| - case '*':
|
| - case '/':
|
| - case '%':
|
| - case '~/':
|
| - case '+':
|
| - case '<<':
|
| - case '>>':
|
| - case '>=':
|
| - case '>':
|
| - case '<=':
|
| - case '<':
|
| - case '&':
|
| - case '^':
|
| - case '|':
|
| - case '-':
|
| - case 'unary-':
|
| - case '[]=':
|
| - case '~':
|
| - return true;
|
| - default:
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -/// Returns true if the key represent ancillary reflection data, that is, not a
|
| -/// method.
|
| -bool isReflectiveDataInPrototype(String key) {
|
| - if (key == JS_GET_NAME('CLASS_DESCRIPTOR_PROPERTY') ||
|
| - key == METHODS_WITH_OPTIONAL_ARGUMENTS) {
|
| - return true;
|
| - }
|
| - String firstChar = key[0];
|
| - return firstChar == '*' || firstChar == '+';
|
| -}
|
| -
|
| -bool isNoSuchMethodStub(var jsFunction) {
|
| - return JS('bool', r'#.$reflectable == 2', jsFunction);
|
| -}
|
| -
|
| -class NoSuchStaticMethodError extends Error implements NoSuchMethodError {
|
| - static const int MISSING_CONSTRUCTOR = 0;
|
| - static const int MISSING_METHOD = 1;
|
| - final ClassMirror _cls;
|
| - final Symbol _name;
|
| - final List _positionalArguments;
|
| - final Map<Symbol, dynamic> _namedArguments;
|
| - final int _kind;
|
| -
|
| - NoSuchStaticMethodError.missingConstructor(
|
| - this._cls,
|
| - this._name,
|
| - this._positionalArguments,
|
| - this._namedArguments)
|
| - : _kind = MISSING_CONSTRUCTOR;
|
| -
|
| - /// If the given class is `null` the static method/getter/setter is top-level.
|
| - NoSuchStaticMethodError.method(
|
| - this._cls,
|
| - this._name,
|
| - this._positionalArguments,
|
| - this._namedArguments)
|
| - : _kind = MISSING_METHOD;
|
| -
|
| - String toString() {
|
| - // TODO(floitsch): show arguments.
|
| - switch(_kind) {
|
| - case MISSING_CONSTRUCTOR:
|
| - return
|
| - "NoSuchMethodError: No constructor named '${n(_name)}' in class"
|
| - " '${n(_cls.qualifiedName)}'.";
|
| - case MISSING_METHOD:
|
| - if (_cls == null) {
|
| - return "NoSuchMethodError: No top-level method named '${n(_name)}'.";
|
| - }
|
| - return "NoSuchMethodError: No static method named '${n(_name)}' in"
|
| - " class '${n(_cls.qualifiedName)}'";
|
| - default:
|
| - return 'NoSuchMethodError';
|
| - }
|
| - }
|
| -}
|
| -
|
| -Symbol getSymbol(String name, LibraryMirror library) {
|
| - if (_isPublicSymbol(name)) {
|
| - return new _symbol_dev.Symbol.validated(name);
|
| - }
|
| - if (library == null) {
|
| - throw new ArgumentError(
|
| - "Library required for private symbol name: $name");
|
| - }
|
| - if (!_symbol_dev.Symbol.isValidSymbol(name)) {
|
| - throw new ArgumentError("Not a valid symbol name: $name");
|
| - }
|
| - throw new UnimplementedError(
|
| - "MirrorSystem.getSymbol not implemented for private names");
|
| -}
|
| -
|
| -bool _isPublicSymbol(String name) {
|
| - // A symbol is public if it doesn't start with '_' and it doesn't
|
| - // have a part (following a '.') that starts with '_'.
|
| - const int UNDERSCORE = 0x5f;
|
| - if (name.isEmpty) return true;
|
| - int index = -1;
|
| - do {
|
| - if (name.codeUnitAt(index + 1) == UNDERSCORE) return false;
|
| - index = name.indexOf('.', index + 1);
|
| - } while (index >= 0 && index + 1 < name.length);
|
| - return true;
|
| -}
|
|
|