| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library dart._js_mirrors; | |
| 6 | |
| 7 import 'dart:_js_embedded_names' show | |
| 8 JsGetName, | |
| 9 ALL_CLASSES, | |
| 10 LAZIES, | |
| 11 LIBRARIES, | |
| 12 STATICS, | |
| 13 TYPE_INFORMATION, | |
| 14 TYPEDEF_PREDICATE_PROPERTY_NAME, | |
| 15 TYPEDEF_TYPE_PROPERTY_NAME; | |
| 16 | |
| 17 import 'dart:collection' show | |
| 18 UnmodifiableListView, | |
| 19 UnmodifiableMapView; | |
| 20 | |
| 21 import 'dart:mirrors'; | |
| 22 | |
| 23 import 'dart:_foreign_helper' show | |
| 24 JS, | |
| 25 JS_GET_FLAG, | |
| 26 JS_CURRENT_ISOLATE, | |
| 27 JS_CURRENT_ISOLATE_CONTEXT, | |
| 28 JS_EMBEDDED_GLOBAL, | |
| 29 JS_GET_NAME, | |
| 30 JS_TYPEDEF_TAG, | |
| 31 JS_FUNCTION_TYPE_RETURN_TYPE_TAG, | |
| 32 JS_FUNCTION_TYPE_VOID_RETURN_TAG, | |
| 33 JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG, | |
| 34 JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG, | |
| 35 JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG; | |
| 36 | |
| 37 | |
| 38 import 'dart:_internal' as _symbol_dev; | |
| 39 | |
| 40 import 'dart:_js_helper' show | |
| 41 BoundClosure, | |
| 42 CachedInvocation, | |
| 43 Closure, | |
| 44 JSInvocationMirror, | |
| 45 JsCache, | |
| 46 Null, | |
| 47 Primitives, | |
| 48 ReflectionInfo, | |
| 49 RuntimeError, | |
| 50 TearOffClosure, | |
| 51 TypeVariable, | |
| 52 UnimplementedNoSuchMethodError, | |
| 53 createRuntimeType, | |
| 54 createUnmangledInvocationMirror, | |
| 55 getMangledTypeName, | |
| 56 getMetadata, | |
| 57 getType, | |
| 58 getRuntimeType, | |
| 59 isDartFunctionType, | |
| 60 runtimeTypeToString, | |
| 61 setRuntimeTypeInfo, | |
| 62 throwInvalidReflectionError, | |
| 63 TypeImpl, | |
| 64 deferredLoadHook; | |
| 65 | |
| 66 import 'dart:_interceptors' show | |
| 67 Interceptor, | |
| 68 JSArray, | |
| 69 JSExtendableArray, | |
| 70 getInterceptor; | |
| 71 | |
| 72 import 'dart:_js_names'; | |
| 73 | |
| 74 const String METHODS_WITH_OPTIONAL_ARGUMENTS = r'$methodsWithOptionalArguments'; | |
| 75 | |
| 76 bool hasReflectableProperty(var jsFunction) { | |
| 77 return JS('bool', '# in #', JS_GET_NAME(JsGetName.REFLECTABLE), jsFunction); | |
| 78 } | |
| 79 | |
| 80 /// No-op method that is called to inform the compiler that tree-shaking needs | |
| 81 /// to be disabled. | |
| 82 disableTreeShaking() => preserveNames(); | |
| 83 | |
| 84 /// No-op method that is called to inform the compiler that metadata must be | |
| 85 /// preserved at runtime. | |
| 86 preserveMetadata() {} | |
| 87 | |
| 88 /// No-op method that is called to inform the compiler that the compiler must | |
| 89 /// preserve the URIs. | |
| 90 preserveUris() {} | |
| 91 | |
| 92 /// No-op method that is called to inform the compiler that the compiler must | |
| 93 /// preserve the library names. | |
| 94 preserveLibraryNames() {} | |
| 95 | |
| 96 String getName(Symbol symbol) { | |
| 97 preserveNames(); | |
| 98 return n(symbol); | |
| 99 } | |
| 100 | |
| 101 class JsMirrorSystem implements MirrorSystem { | |
| 102 UnmodifiableMapView<Uri, LibraryMirror> _cachedLibraries; | |
| 103 | |
| 104 final IsolateMirror isolate = new JsIsolateMirror(); | |
| 105 | |
| 106 JsTypeMirror get dynamicType => _dynamicType; | |
| 107 JsTypeMirror get voidType => _voidType; | |
| 108 | |
| 109 static final JsTypeMirror _dynamicType = | |
| 110 new JsTypeMirror(const Symbol('dynamic')); | |
| 111 static final JsTypeMirror _voidType = new JsTypeMirror(const Symbol('void')); | |
| 112 | |
| 113 static Map<String, List<LibraryMirror>> _librariesByName; | |
| 114 | |
| 115 // Will be set to `true` when we have installed a hook on [deferredLoadHook] | |
| 116 // to avoid installing it multiple times. | |
| 117 static bool _hasInstalledDeferredLoadHook = false; | |
| 118 | |
| 119 static Map<String, List<LibraryMirror>> get librariesByName { | |
| 120 if (_librariesByName == null) { | |
| 121 _librariesByName = computeLibrariesByName(); | |
| 122 if (!_hasInstalledDeferredLoadHook) { | |
| 123 _hasInstalledDeferredLoadHook = true; | |
| 124 // After a deferred import has been loaded new libraries might have | |
| 125 // been created, so in the hook we erase _librariesByName, so it will be | |
| 126 // recomputed on the next access. | |
| 127 deferredLoadHook = () => _librariesByName = null; | |
| 128 } | |
| 129 } | |
| 130 return _librariesByName; | |
| 131 } | |
| 132 | |
| 133 Map<Uri, LibraryMirror> get libraries { | |
| 134 if (_cachedLibraries != null) return _cachedLibraries; | |
| 135 Map<Uri, LibraryMirror> result = new Map(); | |
| 136 for (List<LibraryMirror> list in librariesByName.values) { | |
| 137 for (LibraryMirror library in list) { | |
| 138 result[library.uri] = library; | |
| 139 } | |
| 140 } | |
| 141 return _cachedLibraries = | |
| 142 new UnmodifiableMapView<Uri, LibraryMirror>(result); | |
| 143 } | |
| 144 | |
| 145 LibraryMirror findLibrary(Symbol libraryName) { | |
| 146 return librariesByName[n(libraryName)].single; | |
| 147 } | |
| 148 | |
| 149 static Map<String, List<LibraryMirror>> computeLibrariesByName() { | |
| 150 disableTreeShaking(); | |
| 151 var result = new Map<String, List<LibraryMirror>>(); | |
| 152 var jsLibraries = JS_EMBEDDED_GLOBAL('JSExtendableArray|Null', LIBRARIES); | |
| 153 if (jsLibraries == null) return result; | |
| 154 for (List data in jsLibraries) { | |
| 155 String name = data[0]; | |
| 156 String uriString = data[1]; | |
| 157 Uri uri; | |
| 158 // The Uri has been compiled out. Create a URI from the simple name. | |
| 159 if (uriString != "") { | |
| 160 uri = Uri.parse(uriString); | |
| 161 } else { | |
| 162 uri = new Uri(scheme: 'https', | |
| 163 host: 'dartlang.org', | |
| 164 path: 'dart2js-stripped-uri', | |
| 165 queryParameters: { 'lib': name }); | |
| 166 } | |
| 167 List<String> classes = data[2]; | |
| 168 List<String> functions = data[3]; | |
| 169 var metadataFunction = data[4]; | |
| 170 var fields = data[5]; | |
| 171 bool isRoot = data[6]; | |
| 172 var globalObject = data[7]; | |
| 173 List metadata = (metadataFunction == null) | |
| 174 ? const [] : JS('List', '#()', metadataFunction); | |
| 175 var libraries = result.putIfAbsent(name, () => <LibraryMirror>[]); | |
| 176 libraries.add( | |
| 177 new JsLibraryMirror( | |
| 178 s(name), uri, classes, functions, metadata, fields, isRoot, | |
| 179 globalObject)); | |
| 180 } | |
| 181 return result; | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 abstract class JsMirror implements Mirror { | |
| 186 const JsMirror(); | |
| 187 | |
| 188 String get _prettyName; | |
| 189 | |
| 190 String toString() => _prettyName; | |
| 191 | |
| 192 // TODO(ahe): Remove this method from the API. | |
| 193 MirrorSystem get mirrors => currentJsMirrorSystem; | |
| 194 | |
| 195 _getField(JsMirror receiver) { | |
| 196 throw new UnimplementedError(); | |
| 197 } | |
| 198 | |
| 199 void _setField(JsMirror receiver, Object arg) { | |
| 200 throw new UnimplementedError(); | |
| 201 } | |
| 202 | |
| 203 _loadField(String name) { | |
| 204 throw new UnimplementedError(); | |
| 205 } | |
| 206 | |
| 207 void _storeField(String name, Object arg) { | |
| 208 throw new UnimplementedError(); | |
| 209 } | |
| 210 } | |
| 211 | |
| 212 // This class is somewhat silly in the current implementation. | |
| 213 class JsIsolateMirror extends JsMirror implements IsolateMirror { | |
| 214 final _isolateContext = JS_CURRENT_ISOLATE_CONTEXT(); | |
| 215 | |
| 216 String get _prettyName => 'Isolate'; | |
| 217 | |
| 218 String get debugName { | |
| 219 String id = _isolateContext == null ? 'X' : _isolateContext.id.toString(); | |
| 220 // Using name similar to what the VM uses. | |
| 221 return '${n(rootLibrary.simpleName)}-$id'; | |
| 222 } | |
| 223 | |
| 224 bool get isCurrent => JS_CURRENT_ISOLATE_CONTEXT() == _isolateContext; | |
| 225 | |
| 226 LibraryMirror get rootLibrary { | |
| 227 return currentJsMirrorSystem.libraries.values.firstWhere( | |
| 228 (JsLibraryMirror library) => library._isRoot); | |
| 229 } | |
| 230 } | |
| 231 | |
| 232 abstract class JsDeclarationMirror extends JsMirror | |
| 233 implements DeclarationMirror { | |
| 234 final Symbol simpleName; | |
| 235 | |
| 236 const JsDeclarationMirror(this.simpleName); | |
| 237 | |
| 238 Symbol get qualifiedName => computeQualifiedName(owner, simpleName); | |
| 239 | |
| 240 bool get isPrivate => n(simpleName).startsWith('_'); | |
| 241 | |
| 242 bool get isTopLevel => owner != null && owner is LibraryMirror; | |
| 243 | |
| 244 // TODO(ahe): This should use qualifiedName. | |
| 245 String toString() => "$_prettyName on '${n(simpleName)}'"; | |
| 246 | |
| 247 List<JsMethodMirror> get _methods { | |
| 248 throw new RuntimeError('Should not call _methods'); | |
| 249 } | |
| 250 | |
| 251 _invoke(List positionalArguments, Map<Symbol, dynamic> namedArguments) { | |
| 252 throw new RuntimeError('Should not call _invoke'); | |
| 253 } | |
| 254 | |
| 255 // TODO(ahe): Implement this. | |
| 256 SourceLocation get location => throw new UnimplementedError(); | |
| 257 } | |
| 258 | |
| 259 class JsTypeVariableMirror extends JsTypeMirror implements TypeVariableMirror { | |
| 260 final DeclarationMirror owner; | |
| 261 final TypeVariable _typeVariable; | |
| 262 final int _metadataIndex; | |
| 263 TypeMirror _cachedUpperBound; | |
| 264 | |
| 265 JsTypeVariableMirror(TypeVariable typeVariable, this.owner, | |
| 266 this._metadataIndex) | |
| 267 : this._typeVariable = typeVariable, | |
| 268 super(s(typeVariable.name)); | |
| 269 | |
| 270 bool operator ==(other) { | |
| 271 return (other is JsTypeVariableMirror && | |
| 272 simpleName == other.simpleName && | |
| 273 owner == other.owner); | |
| 274 } | |
| 275 | |
| 276 int get hashCode { | |
| 277 int code = 0x3FFFFFFF & (JsTypeVariableMirror).hashCode; | |
| 278 code ^= 17 * simpleName.hashCode; | |
| 279 code ^= 19 * owner.hashCode; | |
| 280 return code; | |
| 281 } | |
| 282 | |
| 283 String get _prettyName => 'TypeVariableMirror'; | |
| 284 | |
| 285 bool get isTopLevel => false; | |
| 286 bool get isStatic => false; | |
| 287 | |
| 288 TypeMirror get upperBound { | |
| 289 if (_cachedUpperBound != null) return _cachedUpperBound; | |
| 290 return _cachedUpperBound = typeMirrorFromRuntimeTypeRepresentation( | |
| 291 owner, getType(_typeVariable.bound)); | |
| 292 } | |
| 293 | |
| 294 bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError(); | |
| 295 bool isAssignableTo(TypeMirror other) => throw new UnimplementedError(); | |
| 296 | |
| 297 _asRuntimeType() => _metadataIndex; | |
| 298 } | |
| 299 | |
| 300 class JsTypeMirror extends JsDeclarationMirror implements TypeMirror { | |
| 301 JsTypeMirror(Symbol simpleName) | |
| 302 : super(simpleName); | |
| 303 | |
| 304 String get _prettyName => 'TypeMirror'; | |
| 305 | |
| 306 DeclarationMirror get owner => null; | |
| 307 | |
| 308 // TODO(ahe): Doesn't match the specification, see http://dartbug.com/11569. | |
| 309 bool get isTopLevel => true; | |
| 310 | |
| 311 // TODO(ahe): Implement these. | |
| 312 List<InstanceMirror> get metadata => throw new UnimplementedError(); | |
| 313 | |
| 314 bool get hasReflectedType => false; | |
| 315 Type get reflectedType { | |
| 316 throw new UnsupportedError("This type does not support reflectedType"); | |
| 317 } | |
| 318 | |
| 319 List<TypeVariableMirror> get typeVariables => const <TypeVariableMirror>[]; | |
| 320 List<TypeMirror> get typeArguments => const <TypeMirror>[]; | |
| 321 | |
| 322 bool get isOriginalDeclaration => true; | |
| 323 TypeMirror get originalDeclaration => this; | |
| 324 | |
| 325 bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError(); | |
| 326 bool isAssignableTo(TypeMirror other) => throw new UnimplementedError(); | |
| 327 | |
| 328 _asRuntimeType() { | |
| 329 if (this == JsMirrorSystem._dynamicType) return null; | |
| 330 if (this == JsMirrorSystem._voidType) return null; | |
| 331 throw new RuntimeError('Should not call _asRuntimeType'); | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror | |
| 336 implements LibraryMirror { | |
| 337 final Uri _uri; | |
| 338 final List<String> _classes; | |
| 339 final List<String> _functions; | |
| 340 final List _metadata; | |
| 341 final String _compactFieldSpecification; | |
| 342 final bool _isRoot; | |
| 343 final _globalObject; | |
| 344 List<JsMethodMirror> _cachedFunctionMirrors; | |
| 345 List<VariableMirror> _cachedFields; | |
| 346 UnmodifiableMapView<Symbol, ClassMirror> _cachedClasses; | |
| 347 UnmodifiableMapView<Symbol, MethodMirror> _cachedFunctions; | |
| 348 UnmodifiableMapView<Symbol, MethodMirror> _cachedGetters; | |
| 349 UnmodifiableMapView<Symbol, MethodMirror> _cachedSetters; | |
| 350 UnmodifiableMapView<Symbol, VariableMirror> _cachedVariables; | |
| 351 UnmodifiableMapView<Symbol, Mirror> _cachedMembers; | |
| 352 UnmodifiableMapView<Symbol, DeclarationMirror> _cachedDeclarations; | |
| 353 UnmodifiableListView<InstanceMirror> _cachedMetadata; | |
| 354 | |
| 355 JsLibraryMirror(Symbol simpleName, | |
| 356 this._uri, | |
| 357 this._classes, | |
| 358 this._functions, | |
| 359 this._metadata, | |
| 360 this._compactFieldSpecification, | |
| 361 this._isRoot, | |
| 362 this._globalObject) | |
| 363 : super(simpleName) { | |
| 364 preserveLibraryNames(); | |
| 365 } | |
| 366 | |
| 367 String get _prettyName => 'LibraryMirror'; | |
| 368 | |
| 369 Uri get uri { | |
| 370 preserveUris(); | |
| 371 return _uri; | |
| 372 } | |
| 373 | |
| 374 Symbol get qualifiedName => simpleName; | |
| 375 | |
| 376 List<JsMethodMirror> get _methods => _functionMirrors; | |
| 377 | |
| 378 Map<Symbol, ClassMirror> get __classes { | |
| 379 if (_cachedClasses != null) return _cachedClasses; | |
| 380 var result = new Map(); | |
| 381 for (String className in _classes) { | |
| 382 var cls = reflectClassByMangledName(className); | |
| 383 if (cls is ClassMirror) { | |
| 384 cls = cls.originalDeclaration; | |
| 385 } | |
| 386 if (cls is JsClassMirror) { | |
| 387 result[cls.simpleName] = cls; | |
| 388 cls._owner = this; | |
| 389 } else if (cls is JsTypedefMirror) { | |
| 390 result[cls.simpleName] = cls; | |
| 391 } | |
| 392 } | |
| 393 return _cachedClasses = | |
| 394 new UnmodifiableMapView<Symbol, ClassMirror>(result); | |
| 395 } | |
| 396 | |
| 397 InstanceMirror setField(Symbol fieldName, Object arg) { | |
| 398 String name = n(fieldName); | |
| 399 if (name.endsWith('=')) throw new ArgumentError(''); | |
| 400 var mirror = __functions[s('$name=')]; | |
| 401 if (mirror == null) mirror = __variables[fieldName]; | |
| 402 if (mirror == null) { | |
| 403 throw new NoSuchStaticMethodError.method( | |
| 404 null, setterSymbol(fieldName), [arg], null); | |
| 405 } | |
| 406 mirror._setField(this, arg); | |
| 407 return reflect(arg); | |
| 408 } | |
| 409 | |
| 410 InstanceMirror getField(Symbol fieldName) { | |
| 411 JsMirror mirror = __members[fieldName]; | |
| 412 if (mirror == null) { | |
| 413 throw new NoSuchStaticMethodError.method(null, fieldName, [], null); | |
| 414 } | |
| 415 if (mirror is! MethodMirror) return reflect(mirror._getField(this)); | |
| 416 JsMethodMirror methodMirror = mirror; | |
| 417 if (methodMirror.isGetter) return reflect(mirror._getField(this)); | |
| 418 assert(methodMirror.isRegularMethod); | |
| 419 var getter = JS("", "#['\$getter']", methodMirror._jsFunction); | |
| 420 if (getter == null) throw new UnimplementedError(); | |
| 421 return reflect(JS("", "#()", getter)); | |
| 422 } | |
| 423 | |
| 424 InstanceMirror invoke(Symbol memberName, | |
| 425 List positionalArguments, | |
| 426 [Map<Symbol, dynamic> namedArguments]) { | |
| 427 if (namedArguments != null && !namedArguments.isEmpty) { | |
| 428 throw new UnsupportedError('Named arguments are not implemented.'); | |
| 429 } | |
| 430 JsDeclarationMirror mirror = __members[memberName]; | |
| 431 | |
| 432 if (mirror is JsMethodMirror && !mirror.canInvokeReflectively()) { | |
| 433 throwInvalidReflectionError(n(memberName)); | |
| 434 } | |
| 435 if (mirror == null || mirror is JsMethodMirror && mirror.isSetter) { | |
| 436 throw new NoSuchStaticMethodError.method( | |
| 437 null, memberName, positionalArguments, namedArguments); | |
| 438 } | |
| 439 if (mirror is JsMethodMirror && !mirror.isGetter) { | |
| 440 return reflect(mirror._invoke(positionalArguments, namedArguments)); | |
| 441 } | |
| 442 return getField(memberName) | |
| 443 .invoke(#call, positionalArguments, namedArguments); | |
| 444 } | |
| 445 | |
| 446 _loadField(String name) { | |
| 447 // TODO(ahe): What about lazily initialized fields? See | |
| 448 // [JsClassMirror.getField]. | |
| 449 | |
| 450 // '$' (JS_CURRENT_ISOLATE()) stores state which is read directly, so we | |
| 451 // shouldn't use [_globalObject] here. | |
| 452 assert(JS('bool', '# in #', name, JS_CURRENT_ISOLATE())); | |
| 453 return JS('', '#[#]', JS_CURRENT_ISOLATE(), name); | |
| 454 } | |
| 455 | |
| 456 void _storeField(String name, Object arg) { | |
| 457 // '$' (JS_CURRENT_ISOLATE()) stores state which is stored directly, so we | |
| 458 // shouldn't use [_globalObject] here. | |
| 459 assert(JS('bool', '# in #', name, JS_CURRENT_ISOLATE())); | |
| 460 JS('void', '#[#] = #', JS_CURRENT_ISOLATE(), name, arg); | |
| 461 } | |
| 462 | |
| 463 List<JsMethodMirror> get _functionMirrors { | |
| 464 if (_cachedFunctionMirrors != null) return _cachedFunctionMirrors; | |
| 465 var result = new List<JsMethodMirror>(); | |
| 466 for (int i = 0; i < _functions.length; i++) { | |
| 467 String name = _functions[i]; | |
| 468 var jsFunction = JS('', '#[#]', _globalObject, name); | |
| 469 String unmangledName = mangledGlobalNames[name]; | |
| 470 if (unmangledName == null || | |
| 471 JS('bool', "!!#['\$getterStub']", jsFunction)) { | |
| 472 // If there is no unmangledName, [jsFunction] is either a synthetic | |
| 473 // implementation detail, or something that is excluded | |
| 474 // by @MirrorsUsed. | |
| 475 // If it has a getterStub property it is a synthetic stub. | |
| 476 // TODO(floitsch): Remove the getterStub hack. | |
| 477 continue; | |
| 478 } | |
| 479 bool isConstructor = unmangledName.startsWith('new '); | |
| 480 bool isStatic = !isConstructor; // Top-level functions are static, but | |
| 481 // constructors are not. | |
| 482 if (isConstructor) { | |
| 483 unmangledName = unmangledName.substring(4).replaceAll(r'$', '.'); | |
| 484 } | |
| 485 JsMethodMirror mirror = | |
| 486 new JsMethodMirror.fromUnmangledName( | |
| 487 unmangledName, jsFunction, isStatic, isConstructor); | |
| 488 result.add(mirror); | |
| 489 mirror._owner = this; | |
| 490 } | |
| 491 return _cachedFunctionMirrors = result; | |
| 492 } | |
| 493 | |
| 494 List<VariableMirror> get _fields { | |
| 495 if (_cachedFields != null) return _cachedFields; | |
| 496 var result = <VariableMirror>[]; | |
| 497 parseCompactFieldSpecification( | |
| 498 this, _compactFieldSpecification, true, result); | |
| 499 return _cachedFields = result; | |
| 500 } | |
| 501 | |
| 502 Map<Symbol, MethodMirror> get __functions { | |
| 503 if (_cachedFunctions != null) return _cachedFunctions; | |
| 504 var result = new Map(); | |
| 505 for (JsMethodMirror mirror in _functionMirrors) { | |
| 506 if (!mirror.isConstructor) result[mirror.simpleName] = mirror; | |
| 507 } | |
| 508 return _cachedFunctions = | |
| 509 new UnmodifiableMapView<Symbol, MethodMirror>(result); | |
| 510 } | |
| 511 | |
| 512 Map<Symbol, MethodMirror> get __getters { | |
| 513 if (_cachedGetters != null) return _cachedGetters; | |
| 514 var result = new Map(); | |
| 515 // TODO(ahe): Implement this. | |
| 516 return _cachedGetters = | |
| 517 new UnmodifiableMapView<Symbol, MethodMirror>(result); | |
| 518 } | |
| 519 | |
| 520 Map<Symbol, MethodMirror> get __setters { | |
| 521 if (_cachedSetters != null) return _cachedSetters; | |
| 522 var result = new Map(); | |
| 523 // TODO(ahe): Implement this. | |
| 524 return _cachedSetters = | |
| 525 new UnmodifiableMapView<Symbol, MethodMirror>(result); | |
| 526 } | |
| 527 | |
| 528 Map<Symbol, VariableMirror> get __variables { | |
| 529 if (_cachedVariables != null) return _cachedVariables; | |
| 530 var result = new Map(); | |
| 531 for (JsVariableMirror mirror in _fields) { | |
| 532 result[mirror.simpleName] = mirror; | |
| 533 } | |
| 534 return _cachedVariables = | |
| 535 new UnmodifiableMapView<Symbol, VariableMirror>(result); | |
| 536 } | |
| 537 | |
| 538 Map<Symbol, Mirror> get __members { | |
| 539 if (_cachedMembers != null) return _cachedMembers; | |
| 540 Map<Symbol, Mirror> result = new Map.from(__classes); | |
| 541 addToResult(Symbol key, Mirror value) { | |
| 542 result[key] = value; | |
| 543 } | |
| 544 __functions.forEach(addToResult); | |
| 545 __getters.forEach(addToResult); | |
| 546 __setters.forEach(addToResult); | |
| 547 __variables.forEach(addToResult); | |
| 548 return _cachedMembers = new UnmodifiableMapView<Symbol, Mirror>(result); | |
| 549 } | |
| 550 | |
| 551 Map<Symbol, DeclarationMirror> get declarations { | |
| 552 if (_cachedDeclarations != null) return _cachedDeclarations; | |
| 553 var result = new Map<Symbol, DeclarationMirror>(); | |
| 554 addToResult(Symbol key, Mirror value) { | |
| 555 result[key] = value; | |
| 556 } | |
| 557 __members.forEach(addToResult); | |
| 558 return _cachedDeclarations = | |
| 559 new UnmodifiableMapView<Symbol, DeclarationMirror>(result); | |
| 560 } | |
| 561 | |
| 562 List<InstanceMirror> get metadata { | |
| 563 if (_cachedMetadata != null) return _cachedMetadata; | |
| 564 preserveMetadata(); | |
| 565 return _cachedMetadata = | |
| 566 new UnmodifiableListView<InstanceMirror>(_metadata.map(reflect)); | |
| 567 } | |
| 568 | |
| 569 // TODO(ahe): Test this getter. | |
| 570 DeclarationMirror get owner => null; | |
| 571 | |
| 572 List<LibraryDependencyMirror> get libraryDependencies | |
| 573 => throw new UnimplementedError(); | |
| 574 } | |
| 575 | |
| 576 String n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol); | |
| 577 | |
| 578 Symbol s(String name) { | |
| 579 if (name == null) return null; | |
| 580 return new _symbol_dev.Symbol.unvalidated(name); | |
| 581 } | |
| 582 | |
| 583 Symbol setterSymbol(Symbol symbol) => s("${n(symbol)}="); | |
| 584 | |
| 585 final JsMirrorSystem currentJsMirrorSystem = new JsMirrorSystem(); | |
| 586 | |
| 587 InstanceMirror reflect(Object reflectee) { | |
| 588 if (reflectee is Closure) { | |
| 589 return new JsClosureMirror(reflectee); | |
| 590 } else { | |
| 591 return new JsInstanceMirror(reflectee); | |
| 592 } | |
| 593 } | |
| 594 | |
| 595 TypeMirror reflectType(Type key) { | |
| 596 return reflectClassByMangledName(getMangledTypeName(key)); | |
| 597 } | |
| 598 | |
| 599 TypeMirror reflectClassByMangledName(String mangledName) { | |
| 600 String unmangledName = mangledGlobalNames[mangledName]; | |
| 601 if (mangledName == 'dynamic') return JsMirrorSystem._dynamicType; | |
| 602 if (mangledName == 'void') return JsMirrorSystem._voidType; | |
| 603 if (unmangledName == null) unmangledName = mangledName; | |
| 604 return reflectClassByName(s(unmangledName), mangledName); | |
| 605 } | |
| 606 | |
| 607 var classMirrors; | |
| 608 | |
| 609 TypeMirror reflectClassByName(Symbol symbol, String mangledName) { | |
| 610 if (classMirrors == null) classMirrors = JsCache.allocate(); | |
| 611 var mirror = JsCache.fetch(classMirrors, mangledName); | |
| 612 if (mirror != null) return mirror; | |
| 613 disableTreeShaking(); | |
| 614 int typeArgIndex = mangledName.indexOf("<"); | |
| 615 if (typeArgIndex != -1) { | |
| 616 TypeMirror originalDeclaration = | |
| 617 reflectClassByMangledName(mangledName.substring(0, typeArgIndex)) | |
| 618 .originalDeclaration; | |
| 619 if (originalDeclaration is JsTypedefMirror) { | |
| 620 throw new UnimplementedError(); | |
| 621 } | |
| 622 mirror = new JsTypeBoundClassMirror(originalDeclaration, | |
| 623 // Remove the angle brackets enclosing the type arguments. | |
| 624 mangledName.substring(typeArgIndex + 1, mangledName.length - 1)); | |
| 625 JsCache.update(classMirrors, mangledName, mirror); | |
| 626 return mirror; | |
| 627 } | |
| 628 var allClasses = JS_EMBEDDED_GLOBAL('', ALL_CLASSES); | |
| 629 var constructor = JS('var', '#[#]', allClasses, mangledName); | |
| 630 if (constructor == null) { | |
| 631 // Probably an intercepted class. | |
| 632 // TODO(ahe): How to handle intercepted classes? | |
| 633 throw new UnsupportedError('Cannot find class for: ${n(symbol)}'); | |
| 634 } | |
| 635 var descriptor = JS('', '#["@"]', constructor); | |
| 636 var fields; | |
| 637 var fieldsMetadata; | |
| 638 if (descriptor == null) { | |
| 639 // This is a native class, or an intercepted class. | |
| 640 // TODO(ahe): Preserve descriptor for such classes. | |
| 641 } else if (JS('bool', '# in #', | |
| 642 TYPEDEF_PREDICATE_PROPERTY_NAME, descriptor)) { | |
| 643 // Typedefs are represented as normal classes with two special properties: | |
| 644 // TYPEDEF_PREDICATE_PROPERTY_NAME and TYPEDEF_TYPE_PROPERTY_NAME. | |
| 645 // For example: | |
| 646 // MyTypedef: { | |
| 647 // "^": "Object;", | |
| 648 // $typedefType: 58, | |
| 649 // $$isTypedef: true | |
| 650 // } | |
| 651 // The typedefType is the index into the metadata table. | |
| 652 int index = JS('int', '#[#]', descriptor, TYPEDEF_TYPE_PROPERTY_NAME); | |
| 653 mirror = new JsTypedefMirror(symbol, mangledName, getType(index)); | |
| 654 } else { | |
| 655 fields = JS('', '#[#]', descriptor, | |
| 656 JS_GET_NAME(JsGetName.CLASS_DESCRIPTOR_PROPERTY)); | |
| 657 if (fields is List) { | |
| 658 fieldsMetadata = fields.getRange(1, fields.length).toList(); | |
| 659 fields = fields[0]; | |
| 660 } | |
| 661 if (fields is! String) { | |
| 662 // TODO(ahe): This is CSP mode. Find a way to determine the | |
| 663 // fields of this class. | |
| 664 fields = ''; | |
| 665 } | |
| 666 } | |
| 667 | |
| 668 if (mirror == null) { | |
| 669 var superclassName = fields.split(';')[0]; | |
| 670 var mixins = superclassName.split('+'); | |
| 671 if (mixins.length > 1 && mangledGlobalNames[mangledName] == null) { | |
| 672 mirror = reflectMixinApplication(mixins, mangledName); | |
| 673 } else { | |
| 674 ClassMirror classMirror = new JsClassMirror( | |
| 675 symbol, mangledName, constructor, fields, fieldsMetadata); | |
| 676 List typeVariables = | |
| 677 JS('JSExtendableArray|Null', '#.prototype["<>"]', constructor); | |
| 678 if (typeVariables == null || typeVariables.length == 0) { | |
| 679 mirror = classMirror; | |
| 680 } else { | |
| 681 String typeArguments = 'dynamic'; | |
| 682 for (int i = 1; i < typeVariables.length; i++) { | |
| 683 typeArguments += ',dynamic'; | |
| 684 } | |
| 685 mirror = new JsTypeBoundClassMirror(classMirror, typeArguments); | |
| 686 } | |
| 687 } | |
| 688 } | |
| 689 | |
| 690 JsCache.update(classMirrors, mangledName, mirror); | |
| 691 return mirror; | |
| 692 } | |
| 693 | |
| 694 Map<Symbol, MethodMirror> filterMethods(List<MethodMirror> methods) { | |
| 695 var result = new Map(); | |
| 696 for (JsMethodMirror method in methods) { | |
| 697 if (!method.isConstructor && !method.isGetter && !method.isSetter) { | |
| 698 result[method.simpleName] = method; | |
| 699 } | |
| 700 } | |
| 701 return result; | |
| 702 } | |
| 703 | |
| 704 Map<Symbol, MethodMirror> filterConstructors(methods) { | |
| 705 var result = new Map(); | |
| 706 for (JsMethodMirror method in methods) { | |
| 707 if (method.isConstructor) { | |
| 708 result[method.simpleName] = method; | |
| 709 } | |
| 710 } | |
| 711 return result; | |
| 712 } | |
| 713 | |
| 714 Map<Symbol, MethodMirror> filterGetters(List<MethodMirror> methods, | |
| 715 Map<Symbol, VariableMirror> fields) { | |
| 716 var result = new Map(); | |
| 717 for (JsMethodMirror method in methods) { | |
| 718 if (method.isGetter) { | |
| 719 | |
| 720 // TODO(ahe): This is a hack to remove getters corresponding to a field. | |
| 721 if (fields[method.simpleName] != null) continue; | |
| 722 | |
| 723 result[method.simpleName] = method; | |
| 724 } | |
| 725 } | |
| 726 return result; | |
| 727 } | |
| 728 | |
| 729 Map<Symbol, MethodMirror> filterSetters(List<MethodMirror> methods, | |
| 730 Map<Symbol, VariableMirror> fields) { | |
| 731 var result = new Map(); | |
| 732 for (JsMethodMirror method in methods) { | |
| 733 if (method.isSetter) { | |
| 734 | |
| 735 // TODO(ahe): This is a hack to remove setters corresponding to a field. | |
| 736 String name = n(method.simpleName); | |
| 737 name = name.substring(0, name.length - 1); // Remove '='. | |
| 738 if (fields[s(name)] != null) continue; | |
| 739 | |
| 740 result[method.simpleName] = method; | |
| 741 } | |
| 742 } | |
| 743 return result; | |
| 744 } | |
| 745 | |
| 746 Map<Symbol, Mirror> filterMembers(List<MethodMirror> methods, | |
| 747 Map<Symbol, VariableMirror> variables) { | |
| 748 Map<Symbol, Mirror> result = new Map.from(variables); | |
| 749 for (JsMethodMirror method in methods) { | |
| 750 if (method.isSetter) { | |
| 751 String name = n(method.simpleName); | |
| 752 name = name.substring(0, name.length - 1); | |
| 753 // Filter-out setters corresponding to variables. | |
| 754 if (result[s(name)] is VariableMirror) continue; | |
| 755 } | |
| 756 // Constructors aren't 'members'. | |
| 757 if (method.isConstructor) continue; | |
| 758 // Filter out synthetic tear-off stubs | |
| 759 if (JS('bool', r'!!#.$getterStub', method._jsFunction)) continue; | |
| 760 // Use putIfAbsent to filter-out getters corresponding to variables. | |
| 761 result.putIfAbsent(method.simpleName, () => method); | |
| 762 } | |
| 763 return result; | |
| 764 } | |
| 765 | |
| 766 int counter = 0; | |
| 767 | |
| 768 ClassMirror reflectMixinApplication(mixinNames, String mangledName) { | |
| 769 disableTreeShaking(); | |
| 770 var mixins = []; | |
| 771 for (String mangledName in mixinNames) { | |
| 772 mixins.add(reflectClassByMangledName(mangledName)); | |
| 773 } | |
| 774 var it = mixins.iterator; | |
| 775 it.moveNext(); | |
| 776 var superclass = it.current; | |
| 777 while (it.moveNext()) { | |
| 778 superclass = new JsMixinApplication(superclass, it.current, mangledName); | |
| 779 } | |
| 780 return superclass; | |
| 781 } | |
| 782 | |
| 783 class JsMixinApplication extends JsTypeMirror with JsObjectMirror | |
| 784 implements ClassMirror { | |
| 785 final ClassMirror superclass; | |
| 786 final ClassMirror mixin; | |
| 787 Symbol _cachedSimpleName; | |
| 788 Map<Symbol, MethodMirror> _cachedInstanceMembers; | |
| 789 | |
| 790 JsMixinApplication(ClassMirror superclass, ClassMirror mixin, | |
| 791 String mangledName) | |
| 792 : this.superclass = superclass, | |
| 793 this.mixin = mixin, | |
| 794 super(s(mangledName)); | |
| 795 | |
| 796 String get _prettyName => 'ClassMirror'; | |
| 797 | |
| 798 Symbol get simpleName { | |
| 799 if (_cachedSimpleName != null) return _cachedSimpleName; | |
| 800 String superName = n(superclass.qualifiedName); | |
| 801 return _cachedSimpleName = (superName.contains(' with ')) | |
| 802 ? s('$superName, ${n(mixin.qualifiedName)}') | |
| 803 : s('$superName with ${n(mixin.qualifiedName)}'); | |
| 804 } | |
| 805 | |
| 806 Symbol get qualifiedName => simpleName; | |
| 807 | |
| 808 // TODO(ahe): Remove this method, only here to silence warning. | |
| 809 get _mixin => mixin; | |
| 810 | |
| 811 Map<Symbol, Mirror> get __members => _mixin.__members; | |
| 812 | |
| 813 Map<Symbol, MethodMirror> get __methods => _mixin.__methods; | |
| 814 | |
| 815 Map<Symbol, MethodMirror> get __getters => _mixin.__getters; | |
| 816 | |
| 817 Map<Symbol, MethodMirror> get __setters => _mixin.__setters; | |
| 818 | |
| 819 Map<Symbol, VariableMirror> get __variables => _mixin.__variables; | |
| 820 | |
| 821 Map<Symbol, DeclarationMirror> get declarations => mixin.declarations; | |
| 822 | |
| 823 Map<Symbol, MethodMirror> get instanceMembers { | |
| 824 if (_cachedInstanceMembers == null) { | |
| 825 var result = new Map<Symbol, MethodMirror>(); | |
| 826 if (superclass != null) { | |
| 827 result.addAll(superclass.instanceMembers); | |
| 828 } | |
| 829 result.addAll(mixin.instanceMembers); | |
| 830 _cachedInstanceMembers = result; | |
| 831 } | |
| 832 return _cachedInstanceMembers; | |
| 833 } | |
| 834 | |
| 835 Map<Symbol, MethodMirror> get staticMembers => mixin.staticMembers; | |
| 836 | |
| 837 _asRuntimeType() => null; | |
| 838 | |
| 839 InstanceMirror invoke( | |
| 840 Symbol memberName, | |
| 841 List positionalArguments, | |
| 842 [Map<Symbol,dynamic> namedArguments]) { | |
| 843 throw new NoSuchStaticMethodError.method( | |
| 844 null, memberName, positionalArguments, namedArguments); | |
| 845 } | |
| 846 | |
| 847 InstanceMirror getField(Symbol fieldName) { | |
| 848 throw new NoSuchStaticMethodError.method(null, fieldName, null, null); | |
| 849 } | |
| 850 | |
| 851 InstanceMirror setField(Symbol fieldName, Object arg) { | |
| 852 throw new NoSuchStaticMethodError.method( | |
| 853 null, setterSymbol(fieldName), [arg], null); | |
| 854 } | |
| 855 | |
| 856 List<ClassMirror> get superinterfaces => [mixin]; | |
| 857 | |
| 858 Map<Symbol, MethodMirror> get __constructors => _mixin.__constructors; | |
| 859 | |
| 860 InstanceMirror newInstance( | |
| 861 Symbol constructorName, | |
| 862 List positionalArguments, | |
| 863 [Map<Symbol,dynamic> namedArguments]) { | |
| 864 throw new UnsupportedError( | |
| 865 "Can't instantiate mixin application '${n(qualifiedName)}'"); | |
| 866 } | |
| 867 | |
| 868 bool get isOriginalDeclaration => true; | |
| 869 | |
| 870 ClassMirror get originalDeclaration => this; | |
| 871 | |
| 872 // TODO(ahe): Implement this. | |
| 873 List<TypeVariableMirror> get typeVariables { | |
| 874 throw new UnimplementedError(); | |
| 875 } | |
| 876 | |
| 877 List<TypeMirror> get typeArguments => const <TypeMirror>[]; | |
| 878 | |
| 879 bool get isAbstract => throw new UnimplementedError(); | |
| 880 | |
| 881 bool get isEnum => throw new UnimplementedError(); | |
| 882 | |
| 883 bool isSubclassOf(ClassMirror other) { | |
| 884 superclass.isSubclassOf(other) || mixin.isSubclassOf(other); | |
| 885 } | |
| 886 | |
| 887 bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError(); | |
| 888 | |
| 889 bool isAssignableTo(TypeMirror other) => throw new UnimplementedError(); | |
| 890 } | |
| 891 | |
| 892 abstract class JsObjectMirror implements ObjectMirror { | |
| 893 } | |
| 894 | |
| 895 class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { | |
| 896 final reflectee; | |
| 897 | |
| 898 JsInstanceMirror(this.reflectee); | |
| 899 | |
| 900 bool get hasReflectee => true; | |
| 901 | |
| 902 ClassMirror get type { | |
| 903 // The spec guarantees that `null` is the singleton instance of the `Null` | |
| 904 // class. | |
| 905 if (reflectee == null) return reflectClass(Null); | |
| 906 return reflectType(getRuntimeType(reflectee)); | |
| 907 } | |
| 908 | |
| 909 InstanceMirror invoke(Symbol memberName, | |
| 910 List positionalArguments, | |
| 911 [Map<Symbol,dynamic> namedArguments]) { | |
| 912 if (namedArguments == null) namedArguments = const {}; | |
| 913 // We can safely pass positionalArguments to _invoke as it will wrap it in | |
| 914 // a JSArray if needed. | |
| 915 return _invoke(memberName, JSInvocationMirror.METHOD, | |
| 916 positionalArguments, namedArguments); | |
| 917 } | |
| 918 | |
| 919 InstanceMirror _invokeMethodWithNamedArguments( | |
| 920 String reflectiveName, | |
| 921 List positionalArguments, Map<Symbol,dynamic> namedArguments) { | |
| 922 assert(namedArguments.isNotEmpty); | |
| 923 var interceptor = getInterceptor(reflectee); | |
| 924 | |
| 925 var jsFunction = JS('', '#[#]', interceptor, reflectiveName); | |
| 926 if (jsFunction == null) { | |
| 927 // TODO(ahe): Invoke noSuchMethod. | |
| 928 throw new UnimplementedNoSuchMethodError( | |
| 929 'Invoking noSuchMethod with named arguments not implemented'); | |
| 930 } | |
| 931 ReflectionInfo info = new ReflectionInfo(jsFunction); | |
| 932 if (jsFunction == null) { | |
| 933 // TODO(ahe): Invoke noSuchMethod. | |
| 934 throw new UnimplementedNoSuchMethodError( | |
| 935 'Invoking noSuchMethod with named arguments not implemented'); | |
| 936 } | |
| 937 | |
| 938 positionalArguments = new List.from(positionalArguments); | |
| 939 // Check the number of positional arguments is valid. | |
| 940 if (info.requiredParameterCount != positionalArguments.length) { | |
| 941 // TODO(ahe): Invoke noSuchMethod. | |
| 942 throw new UnimplementedNoSuchMethodError( | |
| 943 'Invoking noSuchMethod with named arguments not implemented'); | |
| 944 } | |
| 945 var defaultArguments = new Map(); | |
| 946 for (int i = 0; i < info.optionalParameterCount; i++) { | |
| 947 var parameterName = info.parameterName(i + info.requiredParameterCount); | |
| 948 var defaultValue = | |
| 949 getMetadata(info.defaultValue(i + info.requiredParameterCount)); | |
| 950 defaultArguments[parameterName] = defaultValue; | |
| 951 } | |
| 952 namedArguments.forEach((Symbol symbol, value) { | |
| 953 String parameter = n(symbol); | |
| 954 if (defaultArguments.containsKey(parameter)) { | |
| 955 defaultArguments[parameter] = value; | |
| 956 } else { | |
| 957 // Extraneous named argument. | |
| 958 // TODO(ahe): Invoke noSuchMethod. | |
| 959 throw new UnimplementedNoSuchMethodError( | |
| 960 'Invoking noSuchMethod with named arguments not implemented'); | |
| 961 } | |
| 962 }); | |
| 963 positionalArguments.addAll(defaultArguments.values); | |
| 964 // TODO(ahe): Handle intercepted methods. | |
| 965 return reflect( | |
| 966 JS('', '#.apply(#, #)', jsFunction, reflectee, positionalArguments)); | |
| 967 } | |
| 968 | |
| 969 /// Grabs hold of the class-specific invocation cache for the reflectee. | |
| 970 /// All reflectees with the same class share the same cache. The cache | |
| 971 /// maps reflective names to cached invocation objects with enough decoded | |
| 972 /// reflective information to know how to to invoke a specific member. | |
| 973 get _classInvocationCache { | |
| 974 String cacheName = Primitives.mirrorInvokeCacheName; | |
| 975 var cacheHolder = (reflectee == null) ? getInterceptor(null) : reflectee; | |
| 976 var cache = JS('', r'#.constructor[#]', cacheHolder, cacheName); | |
| 977 if (cache == null) { | |
| 978 cache = JsCache.allocate(); | |
| 979 JS('void', r'#.constructor[#] = #', cacheHolder, cacheName, cache); | |
| 980 } | |
| 981 return cache; | |
| 982 } | |
| 983 | |
| 984 String _computeReflectiveName(Symbol symbolName, int type, | |
| 985 List positionalArguments, | |
| 986 Map<Symbol, dynamic> namedArguments) { | |
| 987 String name = n(symbolName); | |
| 988 switch (type) { | |
| 989 case JSInvocationMirror.GETTER: return name; | |
| 990 case JSInvocationMirror.SETTER: return '$name='; | |
| 991 case JSInvocationMirror.METHOD: | |
| 992 if (namedArguments.isNotEmpty) return '$name*'; | |
| 993 int nbArgs = positionalArguments.length as int; | |
| 994 return "$name:$nbArgs"; | |
| 995 } | |
| 996 throw new RuntimeError("Could not compute reflective name for $name"); | |
| 997 } | |
| 998 | |
| 999 /** | |
| 1000 * Returns a `CachedInvocation` or `CachedNoSuchMethodInvocation` for the | |
| 1001 * given member. | |
| 1002 * | |
| 1003 * Caches the result. | |
| 1004 */ | |
| 1005 _getCachedInvocation(Symbol name, int type, String reflectiveName, | |
| 1006 List positionalArguments, Map<Symbol,dynamic> namedArguments) { | |
| 1007 | |
| 1008 var cache = _classInvocationCache; | |
| 1009 var cacheEntry = JsCache.fetch(cache, reflectiveName); | |
| 1010 var result; | |
| 1011 if (cacheEntry == null) { | |
| 1012 disableTreeShaking(); | |
| 1013 String mangledName = reflectiveNames[reflectiveName]; | |
| 1014 List<String> argumentNames = const []; | |
| 1015 | |
| 1016 // TODO(ahe): We don't need to create an invocation mirror here. The | |
| 1017 // logic from JSInvocationMirror.getCachedInvocation could easily be | |
| 1018 // inlined here. | |
| 1019 Invocation invocation = createUnmangledInvocationMirror( | |
| 1020 name, mangledName, type, positionalArguments, argumentNames); | |
| 1021 | |
| 1022 cacheEntry = | |
| 1023 JSInvocationMirror.getCachedInvocation(invocation, reflectee); | |
| 1024 JsCache.update(cache, reflectiveName, cacheEntry); | |
| 1025 } | |
| 1026 return cacheEntry; | |
| 1027 } | |
| 1028 | |
| 1029 bool _isReflectable(CachedInvocation cachedInvocation) { | |
| 1030 // TODO(floitsch): tear-off closure does not guarantee that the | |
| 1031 // function is reflectable. | |
| 1032 var method = cachedInvocation.jsFunction; | |
| 1033 return hasReflectableProperty(method) || reflectee is TearOffClosure; | |
| 1034 } | |
| 1035 | |
| 1036 /// Invoke the member specified through name and type on the reflectee. | |
| 1037 /// As a side-effect, this populates the class-specific invocation cache | |
| 1038 /// for the reflectee. | |
| 1039 InstanceMirror _invoke(Symbol name, | |
| 1040 int type, | |
| 1041 List positionalArguments, | |
| 1042 Map<Symbol,dynamic> namedArguments) { | |
| 1043 String reflectiveName = | |
| 1044 _computeReflectiveName(name, type, positionalArguments, namedArguments); | |
| 1045 | |
| 1046 if (namedArguments.isNotEmpty) { | |
| 1047 // TODO(floitsch): first, make sure it's not a getter. | |
| 1048 return _invokeMethodWithNamedArguments( | |
| 1049 reflectiveName, positionalArguments, namedArguments); | |
| 1050 } | |
| 1051 var cacheEntry = _getCachedInvocation( | |
| 1052 name, type, reflectiveName, positionalArguments, namedArguments); | |
| 1053 | |
| 1054 if (cacheEntry.isNoSuchMethod || !_isReflectable(cacheEntry)) { | |
| 1055 // Could be that we want to invoke a getter, or get a method. | |
| 1056 if (type == JSInvocationMirror.METHOD && _instanceFieldExists(name)) { | |
| 1057 return getField(name).invoke( | |
| 1058 #call, positionalArguments, namedArguments); | |
| 1059 } | |
| 1060 | |
| 1061 if (type == JSInvocationMirror.SETTER) { | |
| 1062 // For setters we report the setter name "field=". | |
| 1063 name = s("${n(name)}="); | |
| 1064 } | |
| 1065 | |
| 1066 if (!cacheEntry.isNoSuchMethod) { | |
| 1067 // Not reflectable. | |
| 1068 throwInvalidReflectionError(reflectiveName); | |
| 1069 } | |
| 1070 | |
| 1071 String mangledName = reflectiveNames[reflectiveName]; | |
| 1072 // TODO(ahe): Get the argument names. | |
| 1073 List<String> argumentNames = []; | |
| 1074 Invocation invocation = createUnmangledInvocationMirror( | |
| 1075 name, mangledName, type, positionalArguments, argumentNames); | |
| 1076 return reflect(cacheEntry.invokeOn(reflectee, invocation)); | |
| 1077 } else { | |
| 1078 return reflect(cacheEntry.invokeOn(reflectee, positionalArguments)); | |
| 1079 } | |
| 1080 } | |
| 1081 | |
| 1082 InstanceMirror setField(Symbol fieldName, Object arg) { | |
| 1083 _invoke(fieldName, JSInvocationMirror.SETTER, [arg], const {}); | |
| 1084 return reflect(arg); | |
| 1085 } | |
| 1086 | |
| 1087 // JS helpers for getField optimizations. | |
| 1088 static bool isUndefined(x) | |
| 1089 => JS('bool', 'typeof # == "undefined"', x); | |
| 1090 static bool isMissingCache(x) | |
| 1091 => JS('bool', 'typeof # == "number"', x); | |
| 1092 static bool isMissingProbe(Symbol symbol) | |
| 1093 => JS('bool', 'typeof #.\$p == "undefined"', symbol); | |
| 1094 static bool isEvalAllowed() | |
| 1095 => !JS_GET_FLAG("USE_CONTENT_SECURITY_POLICY"); | |
| 1096 | |
| 1097 | |
| 1098 /// The getter cache is lazily allocated after a couple | |
| 1099 /// of invocations of [InstanceMirror.getField]. The delay is | |
| 1100 /// used to avoid too aggressive caching and dynamic function | |
| 1101 /// generation for rarely used mirrors. The cache is specific to | |
| 1102 /// this [InstanceMirror] and maps reflective names to functions | |
| 1103 /// that will invoke the corresponding getter on the reflectee. | |
| 1104 /// The reflectee is passed to the function as the first argument | |
| 1105 /// to avoid the overhead of fetching it from this mirror repeatedly. | |
| 1106 /// The cache is lazily initialized to a JS object so we can | |
| 1107 /// benefit from "map transitions" in the underlying JavaScript | |
| 1108 /// engine to speed up cache probing. | |
| 1109 var _getterCache = 4; | |
| 1110 | |
| 1111 bool _instanceFieldExists(Symbol name) { | |
| 1112 int getterType = JSInvocationMirror.GETTER; | |
| 1113 String getterName = | |
| 1114 _computeReflectiveName(name, getterType, const [], const {}); | |
| 1115 var getterCacheEntry = _getCachedInvocation( | |
| 1116 name, getterType, getterName, const [], const {}); | |
| 1117 return !getterCacheEntry.isNoSuchMethod && !getterCacheEntry.isGetterStub; | |
| 1118 } | |
| 1119 | |
| 1120 InstanceMirror getField(Symbol fieldName) { | |
| 1121 FASTPATH: { | |
| 1122 var cache = _getterCache; | |
| 1123 if (isMissingCache(cache) || isMissingProbe(fieldName)) break FASTPATH; | |
| 1124 // If the [fieldName] has an associated probe function, we can use | |
| 1125 // it to read from the getter cache specific to this [InstanceMirror]. | |
| 1126 var getter = JS('', '#.\$p(#)', fieldName, cache); | |
| 1127 if (isUndefined(getter)) break FASTPATH; | |
| 1128 // Call the getter passing the reflectee as the first argument. | |
| 1129 var value = JS('', '#(#)', getter, reflectee); | |
| 1130 // The getter has an associate cache of the last [InstanceMirror] | |
| 1131 // returned to avoid repeated invocations of [reflect]. To validate | |
| 1132 // the cache, we check that the value returned by the getter is the | |
| 1133 // same value as last time. | |
| 1134 if (JS('bool', '# === #.v', value, getter)) { | |
| 1135 return JS('InstanceMirror', '#.m', getter); | |
| 1136 } else { | |
| 1137 var result = reflect(value); | |
| 1138 JS('void', '#.v = #', getter, value); | |
| 1139 JS('void', '#.m = #', getter, result); | |
| 1140 return result; | |
| 1141 } | |
| 1142 } | |
| 1143 return _getFieldSlow(fieldName); | |
| 1144 } | |
| 1145 | |
| 1146 InstanceMirror _getFieldSlow(Symbol fieldName) { | |
| 1147 // First do the slow-case getter invocation. As a side-effect of this, | |
| 1148 // the invocation cache is filled in so we can query it afterwards. | |
| 1149 var result = | |
| 1150 _invoke(fieldName, JSInvocationMirror.GETTER, const [], const {}); | |
| 1151 String name = n(fieldName); | |
| 1152 var cacheEntry = JsCache.fetch(_classInvocationCache, name); | |
| 1153 if (cacheEntry.isNoSuchMethod) { | |
| 1154 return result; | |
| 1155 } | |
| 1156 | |
| 1157 // Make sure we have a getter cache in this [InstanceMirror]. | |
| 1158 var cache = _getterCache; | |
| 1159 if (isMissingCache(cache)) { | |
| 1160 if ((_getterCache = --cache) != 0) return result; | |
| 1161 cache = _getterCache = JS('=Object', 'Object.create(null)'); | |
| 1162 } | |
| 1163 | |
| 1164 // Make sure that symbol [fieldName] has a cache probing function ($p). | |
| 1165 bool useEval = isEvalAllowed(); | |
| 1166 if (isMissingProbe(fieldName)) { | |
| 1167 var probe = _newProbeFn(name, useEval); | |
| 1168 JS('void', '#.\$p = #', fieldName, probe); | |
| 1169 } | |
| 1170 | |
| 1171 // Create a new getter function and install it in the cache. | |
| 1172 var mangledName = cacheEntry.mangledName; | |
| 1173 var getter = (cacheEntry.isIntercepted) | |
| 1174 ? _newInterceptedGetterFn(mangledName, useEval) | |
| 1175 : _newGetterFn(mangledName, useEval); | |
| 1176 JS('void', '#[#] = #', cache, name, getter); | |
| 1177 | |
| 1178 // Initialize the last value (v) and last mirror (m) on the | |
| 1179 // newly generated getter to be a sentinel value that is hard | |
| 1180 // to get hold of through user code. | |
| 1181 JS('void', '#.v = #.m = #', getter, getter, cache); | |
| 1182 | |
| 1183 // Return the result of the slow-path getter invocation. | |
| 1184 return result; | |
| 1185 } | |
| 1186 | |
| 1187 _newProbeFn(String id, bool useEval) { | |
| 1188 if (useEval) { | |
| 1189 String body = "return c.$id;"; | |
| 1190 return JS('', 'new Function("c", #)', body); | |
| 1191 } else { | |
| 1192 return JS('', '(function(n){return(function(c){return c[n]})})(#)', id); | |
| 1193 } | |
| 1194 } | |
| 1195 | |
| 1196 _newGetterFn(String name, bool useEval) { | |
| 1197 if (!useEval) return _newGetterNoEvalFn(name); | |
| 1198 // We use a comment that associates the generated function with the | |
| 1199 // class of the reflectee. This makes it more likely that the underlying | |
| 1200 // JavaScript engine will only share the generated code for accessors on the | |
| 1201 // same class (through caching of eval'ed code). This makes the | |
| 1202 // generated call to the getter - e.g. o.get$foo() - much more likely | |
| 1203 // to be monomorphic and inlineable. | |
| 1204 String className = JS('String', '#.constructor.name', reflectee); | |
| 1205 String body = "/* $className */ return o.$name();"; | |
| 1206 return JS('', 'new Function("o", #)', body); | |
| 1207 } | |
| 1208 | |
| 1209 _newGetterNoEvalFn(n) => JS('', | |
| 1210 '(function(n){return(function(o){return o[n]()})})(#)', n); | |
| 1211 | |
| 1212 _newInterceptedGetterFn(String name, bool useEval) { | |
| 1213 var object = reflectee; | |
| 1214 // It is possible that the interceptor for a given object is the object | |
| 1215 // itself, so it is important not to share the code that captures the | |
| 1216 // interceptor between multiple different instances of [InstanceMirror]. | |
| 1217 var interceptor = getInterceptor(object); | |
| 1218 if (!useEval) return _newInterceptGetterNoEvalFn(name, interceptor); | |
| 1219 String className = JS('String', '#.constructor.name', interceptor); | |
| 1220 String functionName = '$className\$$name'; | |
| 1221 String body = | |
| 1222 ' function $functionName(o){return i.$name(o)}' | |
| 1223 ' return $functionName;'; | |
| 1224 return JS('', '(new Function("i", #))(#)', body, interceptor); | |
| 1225 } | |
| 1226 | |
| 1227 _newInterceptGetterNoEvalFn(n, i) => JS('', | |
| 1228 '(function(n,i){return(function(o){return i[n](o)})})(#,#)', n, i); | |
| 1229 | |
| 1230 delegate(Invocation invocation) { | |
| 1231 return JSInvocationMirror.invokeFromMirror(invocation, reflectee); | |
| 1232 } | |
| 1233 | |
| 1234 operator ==(other) { | |
| 1235 return other is JsInstanceMirror && | |
| 1236 identical(reflectee, other.reflectee); | |
| 1237 } | |
| 1238 | |
| 1239 int get hashCode { | |
| 1240 // Avoid hash collisions with the reflectee. This constant is in Smi range | |
| 1241 // and happens to be the inner padding from RFC 2104. | |
| 1242 return identityHashCode(reflectee) ^ 0x36363636; | |
| 1243 } | |
| 1244 | |
| 1245 String toString() => 'InstanceMirror on ${Error.safeToString(reflectee)}'; | |
| 1246 | |
| 1247 // TODO(ahe): Remove this method from the API. | |
| 1248 MirrorSystem get mirrors => currentJsMirrorSystem; | |
| 1249 } | |
| 1250 | |
| 1251 /** | |
| 1252 * ClassMirror for generic classes where the type parameters are bound. | |
| 1253 * | |
| 1254 * [typeArguments] will return a list of the type arguments, in constrast | |
| 1255 * to JsCLassMirror that returns an empty list since it represents original | |
| 1256 * declarations and classes that are not generic. | |
| 1257 */ | |
| 1258 class JsTypeBoundClassMirror extends JsDeclarationMirror | |
| 1259 implements ClassMirror { | |
| 1260 final JsClassMirror _class; | |
| 1261 | |
| 1262 /** | |
| 1263 * When instantiated this field will hold a string representing the list of | |
| 1264 * type arguments for the class, i.e. what is inside the outermost angle | |
| 1265 * brackets. Then, when get typeArguments is called the first time, the string | |
| 1266 * is parsed into the actual list of TypeMirrors, and stored in | |
| 1267 * [_cachedTypeArguments]. Due to type substitution of, for instance, | |
| 1268 * superclasses the mangled name of the class and hence this string is needed | |
| 1269 * after [_cachedTypeArguments] has been computed. | |
| 1270 * | |
| 1271 * If an integer is encountered as a type argument, it represents the type | |
| 1272 * variable at the corresponding entry in [emitter.globalMetadata]. | |
| 1273 */ | |
| 1274 String _typeArguments; | |
| 1275 | |
| 1276 UnmodifiableListView<TypeMirror> _cachedTypeArguments; | |
| 1277 UnmodifiableMapView<Symbol, DeclarationMirror> _cachedDeclarations; | |
| 1278 UnmodifiableMapView<Symbol, DeclarationMirror> _cachedMembers; | |
| 1279 UnmodifiableMapView<Symbol, MethodMirror> _cachedConstructors; | |
| 1280 Map<Symbol, VariableMirror> _cachedVariables; | |
| 1281 Map<Symbol, MethodMirror> _cachedGetters; | |
| 1282 Map<Symbol, MethodMirror> _cachedSetters; | |
| 1283 Map<Symbol, MethodMirror> _cachedMethodsMap; | |
| 1284 List<JsMethodMirror> _cachedMethods; | |
| 1285 ClassMirror _superclass; | |
| 1286 List<ClassMirror> _cachedSuperinterfaces; | |
| 1287 Map<Symbol, MethodMirror> _cachedInstanceMembers; | |
| 1288 Map<Symbol, MethodMirror> _cachedStaticMembers; | |
| 1289 | |
| 1290 JsTypeBoundClassMirror(JsClassMirror originalDeclaration, this._typeArguments) | |
| 1291 : _class = originalDeclaration, | |
| 1292 super(originalDeclaration.simpleName); | |
| 1293 | |
| 1294 String get _prettyName => 'ClassMirror'; | |
| 1295 | |
| 1296 String toString() { | |
| 1297 String result = '$_prettyName on ${n(simpleName)}'; | |
| 1298 if (typeArguments != null) { | |
| 1299 result = "$result<${typeArguments.join(', ')}>"; | |
| 1300 } | |
| 1301 return result; | |
| 1302 } | |
| 1303 | |
| 1304 String get _mangledName { | |
| 1305 for (TypeMirror typeArgument in typeArguments) { | |
| 1306 if (typeArgument != JsMirrorSystem._dynamicType) { | |
| 1307 return '${_class._mangledName}<$_typeArguments>'; | |
| 1308 } | |
| 1309 } | |
| 1310 // When all type arguments are dynamic, the canonical representation is to | |
| 1311 // drop them. | |
| 1312 return _class._mangledName; | |
| 1313 } | |
| 1314 | |
| 1315 List<TypeVariableMirror> get typeVariables => _class.typeVariables; | |
| 1316 | |
| 1317 List<TypeMirror> get typeArguments { | |
| 1318 if (_cachedTypeArguments != null) return _cachedTypeArguments; | |
| 1319 List result = new List(); | |
| 1320 | |
| 1321 addTypeArgument(String typeArgument) { | |
| 1322 int parsedIndex = int.parse(typeArgument, onError: (_) => -1); | |
| 1323 if (parsedIndex == -1) { | |
| 1324 result.add(reflectClassByMangledName(typeArgument.trim())); | |
| 1325 } else { | |
| 1326 TypeVariable typeVariable = getMetadata(parsedIndex); | |
| 1327 TypeMirror owner = reflectClass(typeVariable.owner); | |
| 1328 TypeVariableMirror typeMirror = | |
| 1329 new JsTypeVariableMirror(typeVariable, owner, parsedIndex); | |
| 1330 result.add(typeMirror); | |
| 1331 } | |
| 1332 } | |
| 1333 | |
| 1334 if (_typeArguments.indexOf('<') == -1) { | |
| 1335 _typeArguments.split(',').forEach((t) => addTypeArgument(t)); | |
| 1336 } else { | |
| 1337 int level = 0; | |
| 1338 String currentTypeArgument = ''; | |
| 1339 | |
| 1340 for (int i = 0; i < _typeArguments.length; i++) { | |
| 1341 var character = _typeArguments[i]; | |
| 1342 if (character == ' ') { | |
| 1343 continue; | |
| 1344 } else if (character == '<') { | |
| 1345 currentTypeArgument += character; | |
| 1346 level++; | |
| 1347 } else if (character == '>') { | |
| 1348 currentTypeArgument += character; | |
| 1349 level--; | |
| 1350 } else if (character == ',') { | |
| 1351 if (level > 0) { | |
| 1352 currentTypeArgument += character; | |
| 1353 } else { | |
| 1354 addTypeArgument(currentTypeArgument); | |
| 1355 currentTypeArgument = ''; | |
| 1356 } | |
| 1357 } else { | |
| 1358 currentTypeArgument += character; | |
| 1359 } | |
| 1360 } | |
| 1361 addTypeArgument(currentTypeArgument); | |
| 1362 } | |
| 1363 return _cachedTypeArguments = new UnmodifiableListView(result); | |
| 1364 } | |
| 1365 | |
| 1366 List<JsMethodMirror> get _methods { | |
| 1367 if (_cachedMethods != null) return _cachedMethods; | |
| 1368 return _cachedMethods =_class._getMethodsWithOwner(this); | |
| 1369 } | |
| 1370 | |
| 1371 Map<Symbol, MethodMirror> get __methods { | |
| 1372 if (_cachedMethodsMap != null) return _cachedMethodsMap; | |
| 1373 return _cachedMethodsMap = new UnmodifiableMapView<Symbol, MethodMirror>( | |
| 1374 filterMethods(_methods)); | |
| 1375 } | |
| 1376 | |
| 1377 Map<Symbol, MethodMirror> get __constructors { | |
| 1378 if (_cachedConstructors != null) return _cachedConstructors; | |
| 1379 return _cachedConstructors = | |
| 1380 new UnmodifiableMapView<Symbol, MethodMirror>( | |
| 1381 filterConstructors(_methods)); | |
| 1382 } | |
| 1383 | |
| 1384 Map<Symbol, MethodMirror> get __getters { | |
| 1385 if (_cachedGetters != null) return _cachedGetters; | |
| 1386 return _cachedGetters = new UnmodifiableMapView<Symbol, MethodMirror>( | |
| 1387 filterGetters(_methods, __variables)); | |
| 1388 } | |
| 1389 | |
| 1390 Map<Symbol, MethodMirror> get __setters { | |
| 1391 if (_cachedSetters != null) return _cachedSetters; | |
| 1392 return _cachedSetters = new UnmodifiableMapView<Symbol, MethodMirror>( | |
| 1393 filterSetters(_methods, __variables)); | |
| 1394 } | |
| 1395 | |
| 1396 Map<Symbol, VariableMirror> get __variables { | |
| 1397 if (_cachedVariables != null) return _cachedVariables; | |
| 1398 var result = new Map(); | |
| 1399 for (JsVariableMirror mirror in _class._getFieldsWithOwner(this)) { | |
| 1400 result[mirror.simpleName] = mirror; | |
| 1401 } | |
| 1402 return _cachedVariables = | |
| 1403 new UnmodifiableMapView<Symbol, VariableMirror>(result); | |
| 1404 } | |
| 1405 | |
| 1406 Map<Symbol, DeclarationMirror> get __members { | |
| 1407 if (_cachedMembers != null) return _cachedMembers; | |
| 1408 return _cachedMembers = new UnmodifiableMapView<Symbol, DeclarationMirror>( | |
| 1409 filterMembers(_methods, __variables)); | |
| 1410 } | |
| 1411 | |
| 1412 Map<Symbol, DeclarationMirror> get declarations { | |
| 1413 if (_cachedDeclarations != null) return _cachedDeclarations; | |
| 1414 Map<Symbol, DeclarationMirror> result = | |
| 1415 new Map<Symbol, DeclarationMirror>(); | |
| 1416 result.addAll(__members); | |
| 1417 result.addAll(__constructors); | |
| 1418 typeVariables.forEach((tv) => result[tv.simpleName] = tv); | |
| 1419 return _cachedDeclarations = | |
| 1420 new UnmodifiableMapView<Symbol, DeclarationMirror>(result); | |
| 1421 } | |
| 1422 | |
| 1423 Map<Symbol, MethodMirror> get staticMembers { | |
| 1424 if (_cachedStaticMembers == null) { | |
| 1425 var result = new Map<Symbol, MethodMirror>(); | |
| 1426 declarations.values.forEach((decl) { | |
| 1427 if (decl is MethodMirror && decl.isStatic && !decl.isConstructor) { | |
| 1428 result[decl.simpleName] = decl; | |
| 1429 } | |
| 1430 if (decl is VariableMirror && decl.isStatic) { | |
| 1431 var getterName = decl.simpleName; | |
| 1432 result[getterName] = new JsSyntheticAccessor( | |
| 1433 this, getterName, true, true, false, decl); | |
| 1434 if (!decl.isFinal) { | |
| 1435 var setterName = setterSymbol(decl.simpleName); | |
| 1436 result[setterName] = new JsSyntheticAccessor( | |
| 1437 this, setterName, false, true, false, decl); | |
| 1438 } | |
| 1439 } | |
| 1440 }); | |
| 1441 _cachedStaticMembers = result; | |
| 1442 } | |
| 1443 return _cachedStaticMembers; | |
| 1444 } | |
| 1445 | |
| 1446 Map<Symbol, MethodMirror> get instanceMembers { | |
| 1447 if (_cachedInstanceMembers == null) { | |
| 1448 var result = new Map<Symbol, MethodMirror>(); | |
| 1449 if (superclass != null) { | |
| 1450 result.addAll(superclass.instanceMembers); | |
| 1451 } | |
| 1452 declarations.values.forEach((decl) { | |
| 1453 if (decl is MethodMirror && !decl.isStatic && | |
| 1454 !decl.isConstructor && !decl.isAbstract) { | |
| 1455 result[decl.simpleName] = decl; | |
| 1456 } | |
| 1457 if (decl is VariableMirror && !decl.isStatic) { | |
| 1458 var getterName = decl.simpleName; | |
| 1459 result[getterName] = new JsSyntheticAccessor( | |
| 1460 this, getterName, true, false, false, decl); | |
| 1461 if (!decl.isFinal) { | |
| 1462 var setterName = setterSymbol(decl.simpleName); | |
| 1463 result[setterName] = new JsSyntheticAccessor( | |
| 1464 this, setterName, false, false, false, decl); | |
| 1465 } | |
| 1466 } | |
| 1467 }); | |
| 1468 _cachedInstanceMembers = result; | |
| 1469 } | |
| 1470 return _cachedInstanceMembers; | |
| 1471 } | |
| 1472 | |
| 1473 InstanceMirror setField(Symbol fieldName, Object arg) { | |
| 1474 return _class.setField(fieldName, arg); | |
| 1475 } | |
| 1476 | |
| 1477 InstanceMirror getField(Symbol fieldName) => _class.getField(fieldName); | |
| 1478 | |
| 1479 InstanceMirror newInstance(Symbol constructorName, | |
| 1480 List positionalArguments, | |
| 1481 [Map<Symbol, dynamic> namedArguments]) { | |
| 1482 var instance = _class._getInvokedInstance(constructorName, | |
| 1483 positionalArguments, | |
| 1484 namedArguments); | |
| 1485 return reflect(setRuntimeTypeInfo( | |
| 1486 instance, typeArguments.map((t) => t._asRuntimeType()).toList())); | |
| 1487 } | |
| 1488 | |
| 1489 _asRuntimeType() { | |
| 1490 return [_class._jsConstructor].addAll( | |
| 1491 typeArguments.map((t) => t._asRuntimeType())); | |
| 1492 } | |
| 1493 | |
| 1494 JsLibraryMirror get owner => _class.owner; | |
| 1495 | |
| 1496 List<InstanceMirror> get metadata => _class.metadata; | |
| 1497 | |
| 1498 ClassMirror get superclass { | |
| 1499 if (_superclass != null) return _superclass; | |
| 1500 | |
| 1501 var typeInformationContainer = JS_EMBEDDED_GLOBAL('', TYPE_INFORMATION); | |
| 1502 List<int> typeInformation = | |
| 1503 JS('List|Null', '#[#]', typeInformationContainer, _class._mangledName); | |
| 1504 assert(typeInformation != null); | |
| 1505 var type = getType(typeInformation[0]); | |
| 1506 return _superclass = typeMirrorFromRuntimeTypeRepresentation(this, type); | |
| 1507 } | |
| 1508 | |
| 1509 InstanceMirror invoke(Symbol memberName, | |
| 1510 List positionalArguments, | |
| 1511 [Map<Symbol,dynamic> namedArguments]) { | |
| 1512 return _class.invoke(memberName, positionalArguments, namedArguments); | |
| 1513 } | |
| 1514 | |
| 1515 bool get isOriginalDeclaration => false; | |
| 1516 | |
| 1517 ClassMirror get originalDeclaration => _class; | |
| 1518 | |
| 1519 List<ClassMirror> get superinterfaces { | |
| 1520 if (_cachedSuperinterfaces != null) return _cachedSuperinterfaces; | |
| 1521 return _cachedSuperinterfaces = _class._getSuperinterfacesWithOwner(this); | |
| 1522 } | |
| 1523 | |
| 1524 bool get isPrivate => _class.isPrivate; | |
| 1525 | |
| 1526 bool get isTopLevel => _class.isTopLevel; | |
| 1527 | |
| 1528 bool get isAbstract => _class.isAbstract; | |
| 1529 | |
| 1530 bool get isEnum => _class.isEnum; | |
| 1531 | |
| 1532 bool isSubclassOf(ClassMirror other) => _class.isSubclassOf(other); | |
| 1533 | |
| 1534 SourceLocation get location => _class.location; | |
| 1535 | |
| 1536 MirrorSystem get mirrors => _class.mirrors; | |
| 1537 | |
| 1538 Symbol get qualifiedName => _class.qualifiedName; | |
| 1539 | |
| 1540 bool get hasReflectedType => true; | |
| 1541 | |
| 1542 Type get reflectedType => createRuntimeType(_mangledName); | |
| 1543 | |
| 1544 Symbol get simpleName => _class.simpleName; | |
| 1545 | |
| 1546 // TODO(ahe): Implement this. | |
| 1547 ClassMirror get mixin => throw new UnimplementedError(); | |
| 1548 | |
| 1549 bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError(); | |
| 1550 | |
| 1551 bool isAssignableTo(TypeMirror other) => throw new UnimplementedError(); | |
| 1552 } | |
| 1553 | |
| 1554 class JsSyntheticAccessor implements MethodMirror { | |
| 1555 final DeclarationMirror owner; | |
| 1556 final Symbol simpleName; | |
| 1557 final bool isGetter; | |
| 1558 final bool isStatic; | |
| 1559 final bool isTopLevel; | |
| 1560 final _target; /// The field or type that introduces the synthetic accessor. | |
| 1561 | |
| 1562 JsSyntheticAccessor(this.owner, | |
| 1563 this.simpleName, | |
| 1564 this.isGetter, | |
| 1565 this.isStatic, | |
| 1566 this.isTopLevel, | |
| 1567 this._target); | |
| 1568 | |
| 1569 bool get isSynthetic => true; | |
| 1570 bool get isRegularMethod => false; | |
| 1571 bool get isOperator => false; | |
| 1572 bool get isConstructor => false; | |
| 1573 bool get isConstConstructor => false; | |
| 1574 bool get isGenerativeConstructor => false; | |
| 1575 bool get isFactoryConstructor => false; | |
| 1576 bool get isRedirectingConstructor => false; | |
| 1577 bool get isAbstract => false; | |
| 1578 | |
| 1579 bool get isSetter => !isGetter; | |
| 1580 bool get isPrivate => n(simpleName).startsWith('_'); | |
| 1581 | |
| 1582 Symbol get qualifiedName => computeQualifiedName(owner, simpleName); | |
| 1583 Symbol get constructorName => const Symbol(''); | |
| 1584 | |
| 1585 TypeMirror get returnType => _target.type; | |
| 1586 List<ParameterMirror> get parameters { | |
| 1587 if (isGetter) return const []; | |
| 1588 return new UnmodifiableListView( | |
| 1589 [new JsSyntheticSetterParameter(this, this._target)]); | |
| 1590 } | |
| 1591 | |
| 1592 List<InstanceMirror> get metadata => const []; | |
| 1593 String get source => null; | |
| 1594 SourceLocation get location => throw new UnimplementedError(); | |
| 1595 } | |
| 1596 | |
| 1597 class JsSyntheticSetterParameter implements ParameterMirror { | |
| 1598 final DeclarationMirror owner; | |
| 1599 final VariableMirror _target; | |
| 1600 | |
| 1601 JsSyntheticSetterParameter(this.owner, this._target); | |
| 1602 | |
| 1603 Symbol get simpleName => _target.simpleName; | |
| 1604 Symbol get qualifiedName => computeQualifiedName(owner, simpleName); | |
| 1605 TypeMirror get type => _target.type; | |
| 1606 | |
| 1607 bool get isOptional => false; | |
| 1608 bool get isNamed => false; | |
| 1609 bool get isStatic => false; | |
| 1610 bool get isTopLevel => false; | |
| 1611 bool get isConst => false; | |
| 1612 bool get isFinal => true; | |
| 1613 bool get isPrivate => false; | |
| 1614 bool get hasDefaultValue => false; | |
| 1615 InstanceMirror get defaultValue => null; | |
| 1616 List<InstanceMirror> get metadata => const []; | |
| 1617 SourceLocation get location => throw new UnimplementedError(); | |
| 1618 } | |
| 1619 | |
| 1620 class JsClassMirror extends JsTypeMirror with JsObjectMirror | |
| 1621 implements ClassMirror { | |
| 1622 final String _mangledName; | |
| 1623 final _jsConstructor; | |
| 1624 final String _fieldsDescriptor; | |
| 1625 final List _fieldsMetadata; | |
| 1626 final _jsConstructorCache = JsCache.allocate(); | |
| 1627 List _metadata; | |
| 1628 ClassMirror _superclass; | |
| 1629 List<JsMethodMirror> _cachedMethods; | |
| 1630 List<VariableMirror> _cachedFields; | |
| 1631 UnmodifiableMapView<Symbol, MethodMirror> _cachedConstructors; | |
| 1632 UnmodifiableMapView<Symbol, MethodMirror> _cachedMethodsMap; | |
| 1633 UnmodifiableMapView<Symbol, MethodMirror> _cachedGetters; | |
| 1634 UnmodifiableMapView<Symbol, MethodMirror> _cachedSetters; | |
| 1635 UnmodifiableMapView<Symbol, VariableMirror> _cachedVariables; | |
| 1636 UnmodifiableMapView<Symbol, Mirror> _cachedMembers; | |
| 1637 UnmodifiableMapView<Symbol, DeclarationMirror> _cachedDeclarations; | |
| 1638 UnmodifiableListView<InstanceMirror> _cachedMetadata; | |
| 1639 UnmodifiableListView<ClassMirror> _cachedSuperinterfaces; | |
| 1640 UnmodifiableListView<TypeVariableMirror> _cachedTypeVariables; | |
| 1641 Map<Symbol, MethodMirror> _cachedInstanceMembers; | |
| 1642 Map<Symbol, MethodMirror> _cachedStaticMembers; | |
| 1643 | |
| 1644 // Set as side-effect of accessing JsLibraryMirror.classes. | |
| 1645 JsLibraryMirror _owner; | |
| 1646 | |
| 1647 JsClassMirror(Symbol simpleName, | |
| 1648 this._mangledName, | |
| 1649 this._jsConstructor, | |
| 1650 this._fieldsDescriptor, | |
| 1651 this._fieldsMetadata) | |
| 1652 : super(simpleName); | |
| 1653 | |
| 1654 String get _prettyName => 'ClassMirror'; | |
| 1655 | |
| 1656 Map<Symbol, MethodMirror> get __constructors { | |
| 1657 if (_cachedConstructors != null) return _cachedConstructors; | |
| 1658 return _cachedConstructors = | |
| 1659 new UnmodifiableMapView<Symbol, MethodMirror>( | |
| 1660 filterConstructors(_methods)); | |
| 1661 } | |
| 1662 | |
| 1663 _asRuntimeType() { | |
| 1664 if (typeVariables.isEmpty) return _jsConstructor; | |
| 1665 var type = [_jsConstructor]; | |
| 1666 for (int i = 0; i < typeVariables.length; i ++) { | |
| 1667 type.add(JsMirrorSystem._dynamicType._asRuntimeType); | |
| 1668 } | |
| 1669 return type; | |
| 1670 } | |
| 1671 | |
| 1672 List<JsMethodMirror> _getMethodsWithOwner(DeclarationMirror methodOwner) { | |
| 1673 var prototype = JS('', '#.prototype', _jsConstructor); | |
| 1674 // The prototype might not have been processed yet, so do that now. | |
| 1675 JS('', '#[#]()', prototype, | |
| 1676 JS_GET_NAME(JsGetName.DEFERRED_ACTION_PROPERTY)); | |
| 1677 List<String> keys = extractKeys(prototype); | |
| 1678 var result = <JsMethodMirror>[]; | |
| 1679 for (String key in keys) { | |
| 1680 if (isReflectiveDataInPrototype(key)) continue; | |
| 1681 String simpleName = mangledNames[key]; | |
| 1682 // [simpleName] can be null if [key] represents an implementation | |
| 1683 // detail, for example, a bailout method, or runtime type support. | |
| 1684 // It might also be null if the user has limited what is reified for | |
| 1685 // reflection with metadata. | |
| 1686 if (simpleName == null) continue; | |
| 1687 var function = JS('', '#[#]', prototype, key); | |
| 1688 if (!isOrdinaryReflectableMethod(function)) continue; | |
| 1689 if (isAliasedSuperMethod(function, key)) continue; | |
| 1690 var mirror = | |
| 1691 new JsMethodMirror.fromUnmangledName( | |
| 1692 simpleName, function, false, false); | |
| 1693 result.add(mirror); | |
| 1694 mirror._owner = methodOwner; | |
| 1695 } | |
| 1696 | |
| 1697 var statics = JS_EMBEDDED_GLOBAL('', STATICS); | |
| 1698 keys = extractKeys(JS('', '#[#]', statics, _mangledName)); | |
| 1699 for (String mangledName in keys) { | |
| 1700 if (isReflectiveDataInPrototype(mangledName)) continue; | |
| 1701 String unmangledName = mangledName; | |
| 1702 var jsFunction = JS('', '#[#]', owner._globalObject, mangledName); | |
| 1703 | |
| 1704 bool isConstructor = false; | |
| 1705 if (hasReflectableProperty(jsFunction)) { | |
| 1706 String reflectionName = | |
| 1707 JS('String|Null', r'#.$reflectionName', jsFunction); | |
| 1708 if (reflectionName == null) continue; | |
| 1709 isConstructor = reflectionName.startsWith('new '); | |
| 1710 if (isConstructor) { | |
| 1711 reflectionName = reflectionName.substring(4).replaceAll(r'$', '.'); | |
| 1712 } | |
| 1713 unmangledName = reflectionName; | |
| 1714 } else { | |
| 1715 continue; | |
| 1716 } | |
| 1717 bool isStatic = !isConstructor; // Constructors are not static. | |
| 1718 JsMethodMirror mirror = | |
| 1719 new JsMethodMirror.fromUnmangledName( | |
| 1720 unmangledName, jsFunction, isStatic, isConstructor); | |
| 1721 result.add(mirror); | |
| 1722 mirror._owner = methodOwner; | |
| 1723 } | |
| 1724 | |
| 1725 return result; | |
| 1726 } | |
| 1727 | |
| 1728 List<JsMethodMirror> get _methods { | |
| 1729 if (_cachedMethods != null) return _cachedMethods; | |
| 1730 return _cachedMethods = _getMethodsWithOwner(this); | |
| 1731 } | |
| 1732 | |
| 1733 List<VariableMirror> _getFieldsWithOwner(DeclarationMirror fieldOwner) { | |
| 1734 var result = <VariableMirror>[]; | |
| 1735 | |
| 1736 var instanceFieldSpecfication = _fieldsDescriptor.split(';')[1]; | |
| 1737 if (_fieldsMetadata != null) { | |
| 1738 instanceFieldSpecfication = | |
| 1739 [instanceFieldSpecfication]..addAll(_fieldsMetadata); | |
| 1740 } | |
| 1741 parseCompactFieldSpecification( | |
| 1742 fieldOwner, instanceFieldSpecfication, false, result); | |
| 1743 | |
| 1744 var statics = JS_EMBEDDED_GLOBAL('', STATICS); | |
| 1745 var staticDescriptor = JS('', '#[#]', statics, _mangledName); | |
| 1746 if (staticDescriptor != null) { | |
| 1747 parseCompactFieldSpecification( | |
| 1748 fieldOwner, | |
| 1749 JS('', '#[#]', | |
| 1750 staticDescriptor, | |
| 1751 JS_GET_NAME(JsGetName.CLASS_DESCRIPTOR_PROPERTY)), | |
| 1752 true, result); | |
| 1753 } | |
| 1754 return result; | |
| 1755 } | |
| 1756 | |
| 1757 List<VariableMirror> get _fields { | |
| 1758 if (_cachedFields != null) return _cachedFields; | |
| 1759 return _cachedFields = _getFieldsWithOwner(this); | |
| 1760 } | |
| 1761 | |
| 1762 Map<Symbol, MethodMirror> get __methods { | |
| 1763 if (_cachedMethodsMap != null) return _cachedMethodsMap; | |
| 1764 return _cachedMethodsMap = | |
| 1765 new UnmodifiableMapView<Symbol, MethodMirror>(filterMethods(_methods)); | |
| 1766 } | |
| 1767 | |
| 1768 Map<Symbol, MethodMirror> get __getters { | |
| 1769 if (_cachedGetters != null) return _cachedGetters; | |
| 1770 return _cachedGetters = new UnmodifiableMapView<Symbol, MethodMirror>( | |
| 1771 filterGetters(_methods, __variables)); | |
| 1772 } | |
| 1773 | |
| 1774 Map<Symbol, MethodMirror> get __setters { | |
| 1775 if (_cachedSetters != null) return _cachedSetters; | |
| 1776 return _cachedSetters = new UnmodifiableMapView<Symbol, MethodMirror>( | |
| 1777 filterSetters(_methods, __variables)); | |
| 1778 } | |
| 1779 | |
| 1780 Map<Symbol, VariableMirror> get __variables { | |
| 1781 if (_cachedVariables != null) return _cachedVariables; | |
| 1782 var result = new Map(); | |
| 1783 for (JsVariableMirror mirror in _fields) { | |
| 1784 result[mirror.simpleName] = mirror; | |
| 1785 } | |
| 1786 return _cachedVariables = | |
| 1787 new UnmodifiableMapView<Symbol, VariableMirror>(result); | |
| 1788 } | |
| 1789 | |
| 1790 Map<Symbol, Mirror> get __members { | |
| 1791 if (_cachedMembers != null) return _cachedMembers; | |
| 1792 return _cachedMembers = new UnmodifiableMapView<Symbol, Mirror>( | |
| 1793 filterMembers(_methods, __variables)); | |
| 1794 } | |
| 1795 | |
| 1796 Map<Symbol, DeclarationMirror> get declarations { | |
| 1797 if (_cachedDeclarations != null) return _cachedDeclarations; | |
| 1798 var result = new Map<Symbol, DeclarationMirror>(); | |
| 1799 addToResult(Symbol key, Mirror value) { | |
| 1800 result[key] = value; | |
| 1801 } | |
| 1802 __members.forEach(addToResult); | |
| 1803 __constructors.forEach(addToResult); | |
| 1804 typeVariables.forEach((tv) => result[tv.simpleName] = tv); | |
| 1805 return _cachedDeclarations = | |
| 1806 new UnmodifiableMapView<Symbol, DeclarationMirror>(result); | |
| 1807 } | |
| 1808 | |
| 1809 Map<Symbol, MethodMirror> get staticMembers { | |
| 1810 if (_cachedStaticMembers == null) { | |
| 1811 var result = new Map<Symbol, MethodMirror>(); | |
| 1812 declarations.values.forEach((decl) { | |
| 1813 if (decl is MethodMirror && decl.isStatic && !decl.isConstructor) { | |
| 1814 result[decl.simpleName] = decl; | |
| 1815 } | |
| 1816 if (decl is VariableMirror && decl.isStatic) { | |
| 1817 var getterName = decl.simpleName; | |
| 1818 result[getterName] = new JsSyntheticAccessor( | |
| 1819 this, getterName, true, true, false, decl); | |
| 1820 if (!decl.isFinal) { | |
| 1821 var setterName = setterSymbol(decl.simpleName); | |
| 1822 result[setterName] = new JsSyntheticAccessor( | |
| 1823 this, setterName, false, true, false, decl); | |
| 1824 } | |
| 1825 } | |
| 1826 }); | |
| 1827 _cachedStaticMembers = result; | |
| 1828 } | |
| 1829 return _cachedStaticMembers; | |
| 1830 } | |
| 1831 | |
| 1832 Map<Symbol, MethodMirror> get instanceMembers { | |
| 1833 if (_cachedInstanceMembers == null) { | |
| 1834 var result = new Map<Symbol, MethodMirror>(); | |
| 1835 if (superclass != null) { | |
| 1836 result.addAll(superclass.instanceMembers); | |
| 1837 } | |
| 1838 declarations.values.forEach((decl) { | |
| 1839 if (decl is MethodMirror && !decl.isStatic && | |
| 1840 !decl.isConstructor && !decl.isAbstract) { | |
| 1841 result[decl.simpleName] = decl; | |
| 1842 } | |
| 1843 if (decl is VariableMirror && !decl.isStatic) { | |
| 1844 var getterName = decl.simpleName; | |
| 1845 result[getterName] = new JsSyntheticAccessor( | |
| 1846 this, getterName, true, false, false, decl); | |
| 1847 if (!decl.isFinal) { | |
| 1848 var setterName = setterSymbol(decl.simpleName); | |
| 1849 result[setterName] = new JsSyntheticAccessor( | |
| 1850 this, setterName, false, false, false, decl); | |
| 1851 } | |
| 1852 } | |
| 1853 }); | |
| 1854 _cachedInstanceMembers = result; | |
| 1855 } | |
| 1856 return _cachedInstanceMembers; | |
| 1857 } | |
| 1858 | |
| 1859 InstanceMirror setField(Symbol fieldName, Object arg) { | |
| 1860 JsVariableMirror mirror = __variables[fieldName]; | |
| 1861 if (mirror != null && mirror.isStatic && !mirror.isFinal) { | |
| 1862 // '$' (JS_CURRENT_ISOLATE()) stores state which is stored directly, so | |
| 1863 // we shouldn't use [JsLibraryMirror._globalObject] here. | |
| 1864 String jsName = mirror._jsName; | |
| 1865 if (!JS('bool', '# in #', jsName, JS_CURRENT_ISOLATE())) { | |
| 1866 throw new RuntimeError('Cannot find "$jsName" in current isolate.'); | |
| 1867 } | |
| 1868 JS('void', '#[#] = #', JS_CURRENT_ISOLATE(), jsName, arg); | |
| 1869 return reflect(arg); | |
| 1870 } | |
| 1871 Symbol setterName = setterSymbol(fieldName); | |
| 1872 if (mirror == null) { | |
| 1873 JsMethodMirror setter = __setters[setterName]; | |
| 1874 if (setter != null) { | |
| 1875 setter._invoke([arg], const {}); | |
| 1876 return reflect(arg); | |
| 1877 } | |
| 1878 } | |
| 1879 throw new NoSuchStaticMethodError.method(null, setterName, [arg], null); | |
| 1880 } | |
| 1881 | |
| 1882 bool _staticFieldExists(Symbol fieldName) { | |
| 1883 JsVariableMirror mirror = __variables[fieldName]; | |
| 1884 if (mirror != null) return mirror.isStatic; | |
| 1885 JsMethodMirror getter = __getters[fieldName]; | |
| 1886 return getter != null && getter.isStatic; | |
| 1887 } | |
| 1888 | |
| 1889 InstanceMirror getField(Symbol fieldName) { | |
| 1890 JsVariableMirror mirror = __variables[fieldName]; | |
| 1891 if (mirror != null && mirror.isStatic) { | |
| 1892 String jsName = mirror._jsName; | |
| 1893 // '$' (JS_CURRENT_ISOLATE()) stores state which is read directly, so | |
| 1894 // we shouldn't use [JsLibraryMirror._globalObject] here. | |
| 1895 if (!JS('bool', '# in #', jsName, JS_CURRENT_ISOLATE())) { | |
| 1896 throw new RuntimeError('Cannot find "$jsName" in current isolate.'); | |
| 1897 } | |
| 1898 var lazies = JS_EMBEDDED_GLOBAL('', LAZIES); | |
| 1899 if (JS('bool', '# in #', jsName, lazies)) { | |
| 1900 String getterName = JS('String', '#[#]', lazies, jsName); | |
| 1901 return reflect(JS('', '#[#]()', JS_CURRENT_ISOLATE(), getterName)); | |
| 1902 } else { | |
| 1903 return reflect(JS('', '#[#]', JS_CURRENT_ISOLATE(), jsName)); | |
| 1904 } | |
| 1905 } | |
| 1906 JsMethodMirror getter = __getters[fieldName]; | |
| 1907 if (getter != null && getter.isStatic) { | |
| 1908 return reflect(getter._invoke(const [], const {})); | |
| 1909 } | |
| 1910 // If the fieldName designates a static function we have to return | |
| 1911 // its closure. | |
| 1912 JsMethodMirror method = __methods[fieldName]; | |
| 1913 if (method != null && method.isStatic) { | |
| 1914 // We invoke the same getter that Dart code would execute. During | |
| 1915 // initialization we have stored that getter on the function (so that | |
| 1916 // we can find it more easily here). | |
| 1917 var getter = JS("", "#['\$getter']", method._jsFunction); | |
| 1918 if (getter == null) throw new UnimplementedError(); | |
| 1919 return reflect(JS("", "#()", getter)); | |
| 1920 } | |
| 1921 throw new NoSuchStaticMethodError.method(null, fieldName, null, null); | |
| 1922 } | |
| 1923 | |
| 1924 _getInvokedInstance(Symbol constructorName, | |
| 1925 List positionalArguments, | |
| 1926 [Map<Symbol, dynamic> namedArguments]) { | |
| 1927 if (namedArguments != null && !namedArguments.isEmpty) { | |
| 1928 throw new UnsupportedError('Named arguments are not implemented.'); | |
| 1929 } | |
| 1930 JsMethodMirror mirror = | |
| 1931 JsCache.fetch(_jsConstructorCache, n(constructorName)); | |
| 1932 if (mirror == null) { | |
| 1933 mirror = __constructors.values.firstWhere( | |
| 1934 (m) => m.constructorName == constructorName, | |
| 1935 orElse: () { | |
| 1936 throw new NoSuchStaticMethodError.method( | |
| 1937 null, constructorName, positionalArguments, namedArguments); | |
| 1938 }); | |
| 1939 JsCache.update(_jsConstructorCache, n(constructorName), mirror); | |
| 1940 } | |
| 1941 return mirror._invoke(positionalArguments, namedArguments); | |
| 1942 } | |
| 1943 | |
| 1944 InstanceMirror newInstance(Symbol constructorName, | |
| 1945 List positionalArguments, | |
| 1946 [Map<Symbol, dynamic> namedArguments]) { | |
| 1947 return reflect(_getInvokedInstance(constructorName, | |
| 1948 positionalArguments, | |
| 1949 namedArguments)); | |
| 1950 } | |
| 1951 | |
| 1952 JsLibraryMirror get owner { | |
| 1953 if (_owner == null) { | |
| 1954 for (var list in JsMirrorSystem.librariesByName.values) { | |
| 1955 for (JsLibraryMirror library in list) { | |
| 1956 // This will set _owner field on all classes as a side | |
| 1957 // effect. This gives us a fast path to reflect on a | |
| 1958 // class without parsing reflection data. | |
| 1959 library.__classes; | |
| 1960 } | |
| 1961 } | |
| 1962 if (_owner == null) { | |
| 1963 throw new StateError('Class "${n(simpleName)}" has no owner'); | |
| 1964 } | |
| 1965 } | |
| 1966 return _owner; | |
| 1967 } | |
| 1968 | |
| 1969 List<InstanceMirror> get metadata { | |
| 1970 if (_cachedMetadata != null) return _cachedMetadata; | |
| 1971 if (_metadata == null) { | |
| 1972 _metadata = extractMetadata(JS('', '#.prototype', _jsConstructor)); | |
| 1973 } | |
| 1974 return _cachedMetadata = | |
| 1975 new UnmodifiableListView<InstanceMirror>(_metadata.map(reflect)); | |
| 1976 } | |
| 1977 | |
| 1978 ClassMirror get superclass { | |
| 1979 if (_superclass == null) { | |
| 1980 var typeInformationContainer = JS_EMBEDDED_GLOBAL('', TYPE_INFORMATION); | |
| 1981 List<int> typeInformation = | |
| 1982 JS('List|Null', '#[#]', typeInformationContainer, _mangledName); | |
| 1983 if (typeInformation != null) { | |
| 1984 var type = getType(typeInformation[0]); | |
| 1985 _superclass = typeMirrorFromRuntimeTypeRepresentation(this, type); | |
| 1986 } else { | |
| 1987 var superclassName = _fieldsDescriptor.split(';')[0].split(':')[0]; | |
| 1988 // TODO(zarah): Remove special handing of mixins. | |
| 1989 var mixins = superclassName.split('+'); | |
| 1990 if (mixins.length > 1) { | |
| 1991 if (mixins.length != 2) { | |
| 1992 throw new RuntimeError('Strange mixin: $_fieldsDescriptor'); | |
| 1993 } | |
| 1994 _superclass = reflectClassByMangledName(mixins[0]); | |
| 1995 } else { | |
| 1996 // Use _superclass == this to represent class with no superclass | |
| 1997 // (Object). | |
| 1998 _superclass = (superclassName == '') | |
| 1999 ? this : reflectClassByMangledName(superclassName); | |
| 2000 } | |
| 2001 } | |
| 2002 } | |
| 2003 return _superclass == this ? null : _superclass; | |
| 2004 } | |
| 2005 | |
| 2006 InstanceMirror invoke(Symbol memberName, | |
| 2007 List positionalArguments, | |
| 2008 [Map<Symbol,dynamic> namedArguments]) { | |
| 2009 // Mirror API gotcha: Calling [invoke] on a ClassMirror means invoke a | |
| 2010 // static method. | |
| 2011 | |
| 2012 if (namedArguments != null && !namedArguments.isEmpty) { | |
| 2013 throw new UnsupportedError('Named arguments are not implemented.'); | |
| 2014 } | |
| 2015 JsMethodMirror mirror = __methods[memberName]; | |
| 2016 | |
| 2017 if (mirror == null && _staticFieldExists(memberName)) { | |
| 2018 return getField(memberName) | |
| 2019 .invoke(#call, positionalArguments, namedArguments); | |
| 2020 } | |
| 2021 if (mirror == null || !mirror.isStatic) { | |
| 2022 throw new NoSuchStaticMethodError.method( | |
| 2023 null, memberName, positionalArguments, namedArguments); | |
| 2024 } | |
| 2025 if (!mirror.canInvokeReflectively()) { | |
| 2026 throwInvalidReflectionError(n(memberName)); | |
| 2027 } | |
| 2028 return reflect(mirror._invoke(positionalArguments, namedArguments)); | |
| 2029 } | |
| 2030 | |
| 2031 bool get isOriginalDeclaration => true; | |
| 2032 | |
| 2033 ClassMirror get originalDeclaration => this; | |
| 2034 | |
| 2035 List<ClassMirror> _getSuperinterfacesWithOwner(DeclarationMirror owner) { | |
| 2036 var typeInformationContainer = JS_EMBEDDED_GLOBAL('', TYPE_INFORMATION); | |
| 2037 List<int> typeInformation = | |
| 2038 JS('List|Null', '#[#]', typeInformationContainer, _mangledName); | |
| 2039 List<ClassMirror> result = const <ClassMirror>[]; | |
| 2040 if (typeInformation != null) { | |
| 2041 ClassMirror lookupType(int i) { | |
| 2042 var type = getType(i); | |
| 2043 return typeMirrorFromRuntimeTypeRepresentation(owner, type); | |
| 2044 } | |
| 2045 | |
| 2046 //We skip the first since it is the supertype. | |
| 2047 result = typeInformation.skip(1).map(lookupType).toList(); | |
| 2048 } | |
| 2049 | |
| 2050 return new UnmodifiableListView<ClassMirror>(result); | |
| 2051 } | |
| 2052 | |
| 2053 List<ClassMirror> get superinterfaces { | |
| 2054 if (_cachedSuperinterfaces != null) return _cachedSuperinterfaces; | |
| 2055 return _cachedSuperinterfaces = _getSuperinterfacesWithOwner(this); | |
| 2056 } | |
| 2057 | |
| 2058 List<TypeVariableMirror> get typeVariables { | |
| 2059 if (_cachedTypeVariables != null) return _cachedTypeVariables; | |
| 2060 List result = new List(); | |
| 2061 List typeVariables = | |
| 2062 JS('JSExtendableArray|Null', '#.prototype["<>"]', _jsConstructor); | |
| 2063 if (typeVariables == null) return result; | |
| 2064 for (int i = 0; i < typeVariables.length; i++) { | |
| 2065 TypeVariable typeVariable = getMetadata(typeVariables[i]); | |
| 2066 result.add(new JsTypeVariableMirror(typeVariable, this, | |
| 2067 typeVariables[i])); | |
| 2068 } | |
| 2069 return _cachedTypeVariables = new UnmodifiableListView(result); | |
| 2070 } | |
| 2071 | |
| 2072 List<TypeMirror> get typeArguments => const <TypeMirror>[]; | |
| 2073 | |
| 2074 bool get hasReflectedType => typeVariables.length == 0; | |
| 2075 | |
| 2076 Type get reflectedType { | |
| 2077 if (!hasReflectedType) { | |
| 2078 throw new UnsupportedError( | |
| 2079 "Declarations of generics have no reflected type"); | |
| 2080 } | |
| 2081 return createRuntimeType(_mangledName); | |
| 2082 } | |
| 2083 | |
| 2084 // TODO(ahe): Implement this. | |
| 2085 ClassMirror get mixin => throw new UnimplementedError(); | |
| 2086 | |
| 2087 bool get isAbstract => throw new UnimplementedError(); | |
| 2088 | |
| 2089 bool get isEnum => throw new UnimplementedError(); | |
| 2090 | |
| 2091 bool isSubclassOf(ClassMirror other) { | |
| 2092 if (other is! ClassMirror) { | |
| 2093 throw new ArgumentError(other); | |
| 2094 } | |
| 2095 if (other is JsFunctionTypeMirror) { | |
| 2096 return false; | |
| 2097 } if (other is JsClassMirror && | |
| 2098 JS('bool', '# == #', other._jsConstructor, _jsConstructor)) { | |
| 2099 return true; | |
| 2100 } else if (superclass == null) { | |
| 2101 return false; | |
| 2102 } else { | |
| 2103 return superclass.isSubclassOf(other); | |
| 2104 } | |
| 2105 } | |
| 2106 } | |
| 2107 | |
| 2108 class JsVariableMirror extends JsDeclarationMirror implements VariableMirror { | |
| 2109 | |
| 2110 // TODO(ahe): The values in these fields are virtually untested. | |
| 2111 final String _jsName; | |
| 2112 final bool isFinal; | |
| 2113 final bool isStatic; | |
| 2114 final _metadataFunction; | |
| 2115 final DeclarationMirror _owner; | |
| 2116 final int _type; | |
| 2117 List _metadata; | |
| 2118 | |
| 2119 JsVariableMirror(Symbol simpleName, | |
| 2120 this._jsName, | |
| 2121 this._type, | |
| 2122 this.isFinal, | |
| 2123 this.isStatic, | |
| 2124 this._metadataFunction, | |
| 2125 this._owner) | |
| 2126 : super(simpleName); | |
| 2127 | |
| 2128 factory JsVariableMirror.from(String descriptor, | |
| 2129 metadataFunction, | |
| 2130 JsDeclarationMirror owner, | |
| 2131 bool isStatic) { | |
| 2132 List<String> fieldInformation = descriptor.split('-'); | |
| 2133 if (fieldInformation.length == 1) { | |
| 2134 // The field is not available for reflection. | |
| 2135 // TODO(ahe): Should return an unreflectable field. | |
| 2136 return null; | |
| 2137 } | |
| 2138 | |
| 2139 String field = fieldInformation[0]; | |
| 2140 int length = field.length; | |
| 2141 var code = fieldCode(field.codeUnitAt(length - 1)); | |
| 2142 bool isFinal = false; | |
| 2143 if (code == 0) return null; // Inherited field. | |
| 2144 bool hasGetter = (code & 3) != 0; | |
| 2145 bool hasSetter = (code >> 2) != 0; | |
| 2146 isFinal = !hasSetter; | |
| 2147 length--; | |
| 2148 String jsName; | |
| 2149 String accessorName = jsName = field.substring(0, length); | |
| 2150 int divider = field.indexOf(':'); | |
| 2151 if (divider > 0) { | |
| 2152 accessorName = accessorName.substring(0, divider); | |
| 2153 jsName = field.substring(divider + 1); | |
| 2154 } | |
| 2155 var unmangledName; | |
| 2156 if (isStatic) { | |
| 2157 unmangledName = mangledGlobalNames[accessorName]; | |
| 2158 } else { | |
| 2159 String getterPrefix = JS_GET_NAME(JsGetName.GETTER_PREFIX); | |
| 2160 unmangledName = mangledNames['$getterPrefix$accessorName']; | |
| 2161 } | |
| 2162 if (unmangledName == null) unmangledName = accessorName; | |
| 2163 if (!hasSetter) { | |
| 2164 // TODO(ahe): This is a hack to handle checked setters in checked mode. | |
| 2165 var setterName = s('$unmangledName='); | |
| 2166 for (JsMethodMirror method in owner._methods) { | |
| 2167 if (method.simpleName == setterName) { | |
| 2168 isFinal = false; | |
| 2169 break; | |
| 2170 } | |
| 2171 } | |
| 2172 } | |
| 2173 int type = int.parse(fieldInformation[1], onError: (_) => null); | |
| 2174 return new JsVariableMirror(s(unmangledName), | |
| 2175 jsName, | |
| 2176 type, | |
| 2177 isFinal, | |
| 2178 isStatic, | |
| 2179 metadataFunction, | |
| 2180 owner); | |
| 2181 } | |
| 2182 | |
| 2183 String get _prettyName => 'VariableMirror'; | |
| 2184 | |
| 2185 TypeMirror get type { | |
| 2186 return typeMirrorFromRuntimeTypeRepresentation(owner, getType(_type)); | |
| 2187 } | |
| 2188 | |
| 2189 DeclarationMirror get owner => _owner; | |
| 2190 | |
| 2191 List<InstanceMirror> get metadata { | |
| 2192 preserveMetadata(); | |
| 2193 if (_metadata == null) { | |
| 2194 _metadata = (_metadataFunction == null) | |
| 2195 ? const [] : JS('', '#()', _metadataFunction); | |
| 2196 } | |
| 2197 return _metadata.map(reflect).toList(); | |
| 2198 } | |
| 2199 | |
| 2200 static int fieldCode(int code) { | |
| 2201 if (code >= 60 && code <= 64) return code - 59; | |
| 2202 if (code >= 123 && code <= 126) return code - 117; | |
| 2203 if (code >= 37 && code <= 43) return code - 27; | |
| 2204 return 0; | |
| 2205 } | |
| 2206 | |
| 2207 _getField(JsMirror receiver) => receiver._loadField(_jsName); | |
| 2208 | |
| 2209 void _setField(JsMirror receiver, Object arg) { | |
| 2210 if (isFinal) { | |
| 2211 // TODO(floitsch): when the field is non-static we don't want to have | |
| 2212 // a mirror as receiver. | |
| 2213 if (isStatic) { | |
| 2214 throw new NoSuchStaticMethodError.method( | |
| 2215 null, setterSymbol(simpleName), [arg], null); | |
| 2216 } | |
| 2217 throw new NoSuchMethodError(this, setterSymbol(simpleName), [arg], null); | |
| 2218 } | |
| 2219 receiver._storeField(_jsName, arg); | |
| 2220 } | |
| 2221 | |
| 2222 // TODO(ahe): Implement this method. | |
| 2223 bool get isConst => throw new UnimplementedError(); | |
| 2224 } | |
| 2225 | |
| 2226 class JsClosureMirror extends JsInstanceMirror implements ClosureMirror { | |
| 2227 JsClosureMirror(reflectee) | |
| 2228 : super(reflectee); | |
| 2229 | |
| 2230 MethodMirror get function { | |
| 2231 String cacheName = Primitives.mirrorFunctionCacheName; | |
| 2232 JsMethodMirror cachedFunction; | |
| 2233 // TODO(ahe): Restore caching. | |
| 2234 //= JS('JsMethodMirror|Null', r'#.constructor[#]', reflectee, cacheName); | |
| 2235 if (cachedFunction != null) return cachedFunction; | |
| 2236 disableTreeShaking(); | |
| 2237 // TODO(ahe): What about optional parameters (named or not). | |
| 2238 String callPrefix = "${JS_GET_NAME(JsGetName.CALL_PREFIX)}\$"; | |
| 2239 var extractCallName = JS('', r''' | |
| 2240 function(reflectee) { | |
| 2241 var properties = Object.keys(reflectee.constructor.prototype); | |
| 2242 for (var i = 0; i < properties.length; i++) { | |
| 2243 var property = properties[i]; | |
| 2244 if (# == property.substring(0, #) && | |
| 2245 property[#] >= '0' && | |
| 2246 property[#] <= '9') return property; | |
| 2247 } | |
| 2248 return null; | |
| 2249 } | |
| 2250 ''', callPrefix, callPrefix.length, callPrefix.length, callPrefix.length); | |
| 2251 String callName = JS('String|Null', '#(#)', extractCallName, reflectee); | |
| 2252 if (callName == null) { | |
| 2253 throw new RuntimeError('Cannot find callName on "$reflectee"'); | |
| 2254 } | |
| 2255 // TODO(floitsch): What about optional parameters? | |
| 2256 int parameterCount = int.parse(callName.split(r'$')[1]); | |
| 2257 if (reflectee is BoundClosure) { | |
| 2258 var target = BoundClosure.targetOf(reflectee); | |
| 2259 var self = BoundClosure.selfOf(reflectee); | |
| 2260 var name = mangledNames[BoundClosure.nameOf(reflectee)]; | |
| 2261 if (name == null) { | |
| 2262 throwInvalidReflectionError(name); | |
| 2263 } | |
| 2264 cachedFunction = new JsMethodMirror.fromUnmangledName( | |
| 2265 name, target, false, false); | |
| 2266 } else { | |
| 2267 bool isStatic = true; // TODO(ahe): Compute isStatic correctly. | |
| 2268 var jsFunction = JS('', '#[#]', reflectee, callName); | |
| 2269 var dummyOptionalParameterCount = 0; | |
| 2270 cachedFunction = new JsMethodMirror( | |
| 2271 s(callName), jsFunction, parameterCount, dummyOptionalParameterCount, | |
| 2272 false, false, isStatic, false, false); | |
| 2273 } | |
| 2274 JS('void', r'#.constructor[#] = #', reflectee, cacheName, cachedFunction); | |
| 2275 return cachedFunction; | |
| 2276 } | |
| 2277 | |
| 2278 InstanceMirror apply(List positionalArguments, | |
| 2279 [Map<Symbol, dynamic> namedArguments]) { | |
| 2280 return reflect( | |
| 2281 Function.apply(reflectee, positionalArguments, namedArguments)); | |
| 2282 } | |
| 2283 | |
| 2284 String toString() => "ClosureMirror on '${Error.safeToString(reflectee)}'"; | |
| 2285 | |
| 2286 // TODO(ahe): Implement this method. | |
| 2287 String get source => throw new UnimplementedError(); | |
| 2288 } | |
| 2289 | |
| 2290 class JsMethodMirror extends JsDeclarationMirror implements MethodMirror { | |
| 2291 final _jsFunction; | |
| 2292 final int _requiredParameterCount; | |
| 2293 final int _optionalParameterCount; | |
| 2294 final bool isGetter; | |
| 2295 final bool isSetter; | |
| 2296 final bool isStatic; | |
| 2297 final bool isConstructor; | |
| 2298 final bool isOperator; | |
| 2299 DeclarationMirror _owner; | |
| 2300 List _metadata; | |
| 2301 TypeMirror _returnType; | |
| 2302 UnmodifiableListView<ParameterMirror> _parameters; | |
| 2303 | |
| 2304 JsMethodMirror(Symbol simpleName, | |
| 2305 this._jsFunction, | |
| 2306 this._requiredParameterCount, | |
| 2307 this._optionalParameterCount, | |
| 2308 this.isGetter, | |
| 2309 this.isSetter, | |
| 2310 this.isStatic, | |
| 2311 this.isConstructor, | |
| 2312 this.isOperator) | |
| 2313 : super(simpleName); | |
| 2314 | |
| 2315 factory JsMethodMirror.fromUnmangledName(String name, | |
| 2316 jsFunction, | |
| 2317 bool isStatic, | |
| 2318 bool isConstructor) { | |
| 2319 List<String> info = name.split(':'); | |
| 2320 name = info[0]; | |
| 2321 bool isOperator = isOperatorName(name); | |
| 2322 bool isSetter = !isOperator && name.endsWith('='); | |
| 2323 int requiredParameterCount = 0; | |
| 2324 int optionalParameterCount = 0; | |
| 2325 bool isGetter = false; | |
| 2326 if (info.length == 1) { | |
| 2327 if (isSetter) { | |
| 2328 requiredParameterCount = 1; | |
| 2329 } else { | |
| 2330 isGetter = true; | |
| 2331 requiredParameterCount = 0; | |
| 2332 } | |
| 2333 } else { | |
| 2334 ReflectionInfo reflectionInfo = new ReflectionInfo(jsFunction); | |
| 2335 requiredParameterCount = reflectionInfo.requiredParameterCount; | |
| 2336 optionalParameterCount = reflectionInfo.optionalParameterCount; | |
| 2337 assert(int.parse(info[1]) == requiredParameterCount | |
| 2338 + optionalParameterCount); | |
| 2339 } | |
| 2340 return new JsMethodMirror( | |
| 2341 s(name), jsFunction, requiredParameterCount, optionalParameterCount, | |
| 2342 isGetter, isSetter, isStatic, isConstructor, isOperator); | |
| 2343 } | |
| 2344 | |
| 2345 String get _prettyName => 'MethodMirror'; | |
| 2346 | |
| 2347 int get _parameterCount => _requiredParameterCount + _optionalParameterCount; | |
| 2348 | |
| 2349 List<ParameterMirror> get parameters { | |
| 2350 if (_parameters != null) return _parameters; | |
| 2351 metadata; // Compute _parameters as a side-effect of extracting metadata. | |
| 2352 return _parameters; | |
| 2353 } | |
| 2354 | |
| 2355 bool canInvokeReflectively() { | |
| 2356 return hasReflectableProperty(_jsFunction); | |
| 2357 } | |
| 2358 | |
| 2359 DeclarationMirror get owner => _owner; | |
| 2360 | |
| 2361 TypeMirror get returnType { | |
| 2362 metadata; // Compute _returnType as a side-effect of extracting metadata. | |
| 2363 return _returnType; | |
| 2364 } | |
| 2365 | |
| 2366 List<InstanceMirror> get metadata { | |
| 2367 if (_metadata == null) { | |
| 2368 var raw = extractMetadata(_jsFunction); | |
| 2369 var formals = new List(_parameterCount); | |
| 2370 ReflectionInfo info = new ReflectionInfo(_jsFunction); | |
| 2371 if (info != null) { | |
| 2372 assert(_parameterCount | |
| 2373 == info.requiredParameterCount + info.optionalParameterCount); | |
| 2374 var functionType = info.functionType; | |
| 2375 var type; | |
| 2376 if (functionType is int) { | |
| 2377 type = new JsFunctionTypeMirror(info.computeFunctionRti(null), this); | |
| 2378 assert(_parameterCount == type.parameters.length); | |
| 2379 } else if (isTopLevel) { | |
| 2380 type = new JsFunctionTypeMirror(info.computeFunctionRti(null), owner); | |
| 2381 } else { | |
| 2382 TypeMirror ownerType = owner; | |
| 2383 JsClassMirror ownerClass = ownerType.originalDeclaration; | |
| 2384 type = new JsFunctionTypeMirror( | |
| 2385 info.computeFunctionRti(ownerClass._jsConstructor), | |
| 2386 owner); | |
| 2387 } | |
| 2388 // Constructors aren't reified with their return type. | |
| 2389 if (isConstructor) { | |
| 2390 _returnType = owner; | |
| 2391 } else { | |
| 2392 _returnType = type.returnType; | |
| 2393 } | |
| 2394 int i = 0; | |
| 2395 bool isNamed = info.areOptionalParametersNamed; | |
| 2396 for (JsParameterMirror parameter in type.parameters) { | |
| 2397 var name = info.parameterName(i); | |
| 2398 List<int> annotations = info.parameterMetadataAnnotations(i); | |
| 2399 var p; | |
| 2400 if (i < info.requiredParameterCount) { | |
| 2401 p = new JsParameterMirror(name, this, parameter._type, | |
| 2402 metadataList: annotations); | |
| 2403 } else { | |
| 2404 var defaultValue = info.defaultValue(i); | |
| 2405 p = new JsParameterMirror( | |
| 2406 name, this, parameter._type, metadataList: annotations, | |
| 2407 isOptional: true, isNamed: isNamed, defaultValue: defaultValue); | |
| 2408 } | |
| 2409 formals[i++] = p; | |
| 2410 } | |
| 2411 } | |
| 2412 _parameters = new UnmodifiableListView<ParameterMirror>(formals); | |
| 2413 _metadata = new UnmodifiableListView(raw.map(reflect)); | |
| 2414 } | |
| 2415 return _metadata; | |
| 2416 } | |
| 2417 | |
| 2418 Symbol get constructorName { | |
| 2419 // TODO(ahe): I believe it is more appropriate to throw an exception or | |
| 2420 // return null. | |
| 2421 if (!isConstructor) return const Symbol(''); | |
| 2422 String name = n(simpleName); | |
| 2423 int index = name.indexOf('.'); | |
| 2424 if (index == -1) return const Symbol(''); | |
| 2425 return s(name.substring(index + 1)); | |
| 2426 } | |
| 2427 | |
| 2428 _invoke(List positionalArguments, Map<Symbol, dynamic> namedArguments) { | |
| 2429 if (namedArguments != null && !namedArguments.isEmpty) { | |
| 2430 throw new UnsupportedError('Named arguments are not implemented.'); | |
| 2431 } | |
| 2432 if (!isStatic && !isConstructor) { | |
| 2433 throw new RuntimeError('Cannot invoke instance method without receiver.'); | |
| 2434 } | |
| 2435 int positionalLength = positionalArguments.length; | |
| 2436 if (positionalLength < _requiredParameterCount || | |
| 2437 positionalLength > _parameterCount || | |
| 2438 _jsFunction == null) { | |
| 2439 // TODO(ahe): What receiver to use? | |
| 2440 throw new NoSuchMethodError( | |
| 2441 owner, simpleName, positionalArguments, namedArguments); | |
| 2442 } | |
| 2443 if (positionalLength < _parameterCount) { | |
| 2444 // Fill up with default values. | |
| 2445 // Make a copy so we don't modify the input. | |
| 2446 positionalArguments = positionalArguments.toList(); | |
| 2447 for (int i = positionalLength; i < parameters.length; i++) { | |
| 2448 JsParameterMirror parameter = parameters[i]; | |
| 2449 positionalArguments.add(parameter.defaultValue.reflectee); | |
| 2450 } | |
| 2451 } | |
| 2452 // Using JS_CURRENT_ISOLATE() ('$') here is actually correct, although | |
| 2453 // _jsFunction may not be a property of '$', most static functions do not | |
| 2454 // care who their receiver is. But to lazy getters, it is important that | |
| 2455 // 'this' is '$'. | |
| 2456 return JS('', r'#.apply(#, #)', _jsFunction, JS_CURRENT_ISOLATE(), | |
| 2457 new List.from(positionalArguments)); | |
| 2458 } | |
| 2459 | |
| 2460 _getField(JsMirror receiver) { | |
| 2461 if (isGetter) { | |
| 2462 return _invoke([], null); | |
| 2463 } else { | |
| 2464 // TODO(ahe): Closurize method. | |
| 2465 throw new UnimplementedError('getField on $receiver'); | |
| 2466 } | |
| 2467 } | |
| 2468 | |
| 2469 _setField(JsMirror receiver, Object arg) { | |
| 2470 if (isSetter) { | |
| 2471 return _invoke([arg], null); | |
| 2472 } else { | |
| 2473 throw new NoSuchMethodError(this, setterSymbol(simpleName), [], null); | |
| 2474 } | |
| 2475 } | |
| 2476 | |
| 2477 // Abstract methods are tree-shaken away. | |
| 2478 bool get isAbstract => false; | |
| 2479 | |
| 2480 // TODO(ahe, 14633): This might not be true for all cases. | |
| 2481 bool get isSynthetic => false; | |
| 2482 | |
| 2483 // TODO(ahe): Test this. | |
| 2484 bool get isRegularMethod => !isGetter && !isSetter && !isConstructor; | |
| 2485 | |
| 2486 // TODO(ahe): Implement this method. | |
| 2487 bool get isConstConstructor => throw new UnimplementedError(); | |
| 2488 | |
| 2489 // TODO(ahe): Implement this method. | |
| 2490 bool get isGenerativeConstructor => throw new UnimplementedError(); | |
| 2491 | |
| 2492 // TODO(ahe): Implement this method. | |
| 2493 bool get isRedirectingConstructor => throw new UnimplementedError(); | |
| 2494 | |
| 2495 // TODO(ahe): Implement this method. | |
| 2496 bool get isFactoryConstructor => throw new UnimplementedError(); | |
| 2497 | |
| 2498 // TODO(ahe): Implement this method. | |
| 2499 String get source => throw new UnimplementedError(); | |
| 2500 } | |
| 2501 | |
| 2502 class JsParameterMirror extends JsDeclarationMirror implements ParameterMirror { | |
| 2503 final DeclarationMirror owner; | |
| 2504 // A JS object representing the type. | |
| 2505 final _type; | |
| 2506 | |
| 2507 final bool isOptional; | |
| 2508 | |
| 2509 final bool isNamed; | |
| 2510 | |
| 2511 final int _defaultValue; | |
| 2512 | |
| 2513 final List<int> metadataList; | |
| 2514 | |
| 2515 JsParameterMirror(String unmangledName, | |
| 2516 this.owner, | |
| 2517 this._type, | |
| 2518 {this.metadataList: const <int>[], | |
| 2519 this.isOptional: false, | |
| 2520 this.isNamed: false, | |
| 2521 defaultValue}) | |
| 2522 : _defaultValue = defaultValue, | |
| 2523 super(s(unmangledName)); | |
| 2524 | |
| 2525 String get _prettyName => 'ParameterMirror'; | |
| 2526 | |
| 2527 TypeMirror get type { | |
| 2528 return typeMirrorFromRuntimeTypeRepresentation(owner, _type); | |
| 2529 } | |
| 2530 | |
| 2531 // Only true for static fields, never for a parameter. | |
| 2532 bool get isStatic => false; | |
| 2533 | |
| 2534 // TODO(ahe): Implement this. | |
| 2535 bool get isFinal => false; | |
| 2536 | |
| 2537 // TODO(ahe): Implement this. | |
| 2538 bool get isConst => false; | |
| 2539 | |
| 2540 bool get hasDefaultValue => _defaultValue != null; | |
| 2541 | |
| 2542 get defaultValue { | |
| 2543 return hasDefaultValue ? reflect(getMetadata(_defaultValue)) : null; | |
| 2544 } | |
| 2545 | |
| 2546 List<InstanceMirror> get metadata { | |
| 2547 preserveMetadata(); | |
| 2548 return metadataList.map((int i) => reflect(getMetadata(i))).toList(); | |
| 2549 } | |
| 2550 } | |
| 2551 | |
| 2552 class JsTypedefMirror extends JsDeclarationMirror implements TypedefMirror { | |
| 2553 final String _mangledName; | |
| 2554 JsFunctionTypeMirror referent; | |
| 2555 | |
| 2556 JsTypedefMirror(Symbol simpleName, this._mangledName, _typeData) | |
| 2557 : super(simpleName) { | |
| 2558 referent = new JsFunctionTypeMirror(_typeData, this); | |
| 2559 } | |
| 2560 | |
| 2561 JsFunctionTypeMirror get value => referent; | |
| 2562 | |
| 2563 String get _prettyName => 'TypedefMirror'; | |
| 2564 | |
| 2565 bool get hasReflectedType => throw new UnimplementedError(); | |
| 2566 | |
| 2567 Type get reflectedType => createRuntimeType(_mangledName); | |
| 2568 | |
| 2569 // TODO(floitsch): Implement this method. | |
| 2570 List<TypeVariableMirror> get typeVariables => throw new UnimplementedError(); | |
| 2571 | |
| 2572 // TODO(floitsch): Implement this method. | |
| 2573 List<TypeMirror> get typeArguments => throw new UnimplementedError(); | |
| 2574 | |
| 2575 bool get isOriginalDeclaration => true; | |
| 2576 | |
| 2577 TypeMirror get originalDeclaration => this; | |
| 2578 | |
| 2579 // TODO(floitsch): Implement this method. | |
| 2580 DeclarationMirror get owner => throw new UnimplementedError(); | |
| 2581 | |
| 2582 // TODO(ahe): Implement this method. | |
| 2583 List<InstanceMirror> get metadata => throw new UnimplementedError(); | |
| 2584 | |
| 2585 bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError(); | |
| 2586 bool isAssignableTo(TypeMirror other) => throw new UnimplementedError(); | |
| 2587 } | |
| 2588 | |
| 2589 // TODO(ahe): Remove this class when API is updated. | |
| 2590 class BrokenClassMirror { | |
| 2591 bool get hasReflectedType => throw new UnimplementedError(); | |
| 2592 Type get reflectedType => throw new UnimplementedError(); | |
| 2593 ClassMirror get superclass => throw new UnimplementedError(); | |
| 2594 List<ClassMirror> get superinterfaces => throw new UnimplementedError(); | |
| 2595 Map<Symbol, DeclarationMirror> get declarations | |
| 2596 => throw new UnimplementedError(); | |
| 2597 Map<Symbol, MethodMirror> get instanceMembers | |
| 2598 => throw new UnimplementedError(); | |
| 2599 Map<Symbol, MethodMirror> get staticMembers => throw new UnimplementedError(); | |
| 2600 ClassMirror get mixin => throw new UnimplementedError(); | |
| 2601 InstanceMirror newInstance( | |
| 2602 Symbol constructorName, | |
| 2603 List positionalArguments, | |
| 2604 [Map<Symbol, dynamic> namedArguments]) => throw new UnimplementedError(); | |
| 2605 InstanceMirror invoke(Symbol memberName, | |
| 2606 List positionalArguments, | |
| 2607 [Map<Symbol, dynamic> namedArguments]) | |
| 2608 => throw new UnimplementedError(); | |
| 2609 InstanceMirror getField(Symbol fieldName) => throw new UnimplementedError(); | |
| 2610 InstanceMirror setField(Symbol fieldName, Object value) | |
| 2611 => throw new UnimplementedError(); | |
| 2612 List<TypeVariableMirror> get typeVariables => throw new UnimplementedError(); | |
| 2613 List<TypeMirror> get typeArguments => throw new UnimplementedError(); | |
| 2614 TypeMirror get originalDeclaration => throw new UnimplementedError(); | |
| 2615 Symbol get simpleName => throw new UnimplementedError(); | |
| 2616 Symbol get qualifiedName => throw new UnimplementedError(); | |
| 2617 bool get isPrivate => throw new UnimplementedError(); | |
| 2618 bool get isTopLevel => throw new UnimplementedError(); | |
| 2619 SourceLocation get location => throw new UnimplementedError(); | |
| 2620 List<InstanceMirror> get metadata => throw new UnimplementedError(); | |
| 2621 } | |
| 2622 | |
| 2623 class JsFunctionTypeMirror extends BrokenClassMirror | |
| 2624 implements FunctionTypeMirror { | |
| 2625 final _typeData; | |
| 2626 String _cachedToString; | |
| 2627 TypeMirror _cachedReturnType; | |
| 2628 UnmodifiableListView<ParameterMirror> _cachedParameters; | |
| 2629 DeclarationMirror owner; | |
| 2630 | |
| 2631 JsFunctionTypeMirror(this._typeData, this.owner); | |
| 2632 | |
| 2633 bool get _hasReturnType { | |
| 2634 return JS('bool', '# in #', | |
| 2635 JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG), _typeData); | |
| 2636 } | |
| 2637 | |
| 2638 get _returnType { | |
| 2639 return JS('', '#[#]', _typeData, | |
| 2640 JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG)); | |
| 2641 } | |
| 2642 | |
| 2643 bool get _isVoid { | |
| 2644 return JS('bool', '!!#[#]', _typeData, | |
| 2645 JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG)); | |
| 2646 } | |
| 2647 | |
| 2648 bool get _hasArguments { | |
| 2649 return JS('bool', '# in #', | |
| 2650 JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG), | |
| 2651 _typeData); | |
| 2652 } | |
| 2653 List get _arguments { | |
| 2654 return JS('JSExtendableArray', '#[#]', | |
| 2655 _typeData, | |
| 2656 JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG)); | |
| 2657 } | |
| 2658 | |
| 2659 bool get _hasOptionalArguments { | |
| 2660 return JS('bool', '# in #', | |
| 2661 JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG), | |
| 2662 _typeData); | |
| 2663 } | |
| 2664 List get _optionalArguments { | |
| 2665 return JS('JSExtendableArray', '#[#]', | |
| 2666 _typeData, | |
| 2667 JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG)); | |
| 2668 } | |
| 2669 | |
| 2670 bool get _hasNamedArguments { | |
| 2671 return JS('bool', '# in #', | |
| 2672 JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG), | |
| 2673 _typeData); | |
| 2674 } | |
| 2675 get _namedArguments { | |
| 2676 return JS('=Object', '#[#]', | |
| 2677 _typeData, | |
| 2678 JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG)); | |
| 2679 } | |
| 2680 | |
| 2681 bool get isOriginalDeclaration => true; | |
| 2682 | |
| 2683 bool get isAbstract => false; | |
| 2684 | |
| 2685 bool get isEnum => false; | |
| 2686 | |
| 2687 TypeMirror get returnType { | |
| 2688 if (_cachedReturnType != null) return _cachedReturnType; | |
| 2689 if (_isVoid) return _cachedReturnType = JsMirrorSystem._voidType; | |
| 2690 if (!_hasReturnType) return _cachedReturnType = JsMirrorSystem._dynamicType; | |
| 2691 return _cachedReturnType = | |
| 2692 typeMirrorFromRuntimeTypeRepresentation(owner, _returnType); | |
| 2693 } | |
| 2694 | |
| 2695 List<ParameterMirror> get parameters { | |
| 2696 if (_cachedParameters != null) return _cachedParameters; | |
| 2697 List result = []; | |
| 2698 int parameterCount = 0; | |
| 2699 if (_hasArguments) { | |
| 2700 for (var type in _arguments) { | |
| 2701 result.add( | |
| 2702 new JsParameterMirror('argument${parameterCount++}', this, type)); | |
| 2703 } | |
| 2704 } | |
| 2705 if (_hasOptionalArguments) { | |
| 2706 for (var type in _optionalArguments) { | |
| 2707 result.add( | |
| 2708 new JsParameterMirror('argument${parameterCount++}', this, type)); | |
| 2709 } | |
| 2710 } | |
| 2711 if (_hasNamedArguments) { | |
| 2712 for (var name in extractKeys(_namedArguments)) { | |
| 2713 var type = JS('', '#[#]', _namedArguments, name); | |
| 2714 result.add(new JsParameterMirror(name, this, type)); | |
| 2715 } | |
| 2716 } | |
| 2717 return _cachedParameters = new UnmodifiableListView<ParameterMirror>( | |
| 2718 result); | |
| 2719 } | |
| 2720 | |
| 2721 String _unmangleIfPreserved(String mangled) { | |
| 2722 String result = unmangleGlobalNameIfPreservedAnyways(mangled); | |
| 2723 if (result != null) return result; | |
| 2724 return mangled; | |
| 2725 } | |
| 2726 | |
| 2727 String toString() { | |
| 2728 if (_cachedToString != null) return _cachedToString; | |
| 2729 var s = "FunctionTypeMirror on '("; | |
| 2730 var sep = ''; | |
| 2731 if (_hasArguments) { | |
| 2732 for (var argument in _arguments) { | |
| 2733 s += sep; | |
| 2734 s += _unmangleIfPreserved(runtimeTypeToString(argument)); | |
| 2735 sep = ', '; | |
| 2736 } | |
| 2737 } | |
| 2738 if (_hasOptionalArguments) { | |
| 2739 s += '$sep['; | |
| 2740 sep = ''; | |
| 2741 for (var argument in _optionalArguments) { | |
| 2742 s += sep; | |
| 2743 s += _unmangleIfPreserved(runtimeTypeToString(argument)); | |
| 2744 sep = ', '; | |
| 2745 } | |
| 2746 s += ']'; | |
| 2747 } | |
| 2748 if (_hasNamedArguments) { | |
| 2749 s += '$sep{'; | |
| 2750 sep = ''; | |
| 2751 for (var name in extractKeys(_namedArguments)) { | |
| 2752 s += sep; | |
| 2753 s += '$name: '; | |
| 2754 s += _unmangleIfPreserved( | |
| 2755 runtimeTypeToString(JS('', '#[#]', _namedArguments, name))); | |
| 2756 sep = ', '; | |
| 2757 } | |
| 2758 s += '}'; | |
| 2759 } | |
| 2760 s += ') -> '; | |
| 2761 if (_isVoid) { | |
| 2762 s += 'void'; | |
| 2763 } else if (_hasReturnType) { | |
| 2764 s += _unmangleIfPreserved(runtimeTypeToString(_returnType)); | |
| 2765 } else { | |
| 2766 s += 'dynamic'; | |
| 2767 } | |
| 2768 return _cachedToString = "$s'"; | |
| 2769 } | |
| 2770 | |
| 2771 bool isSubclassOf(ClassMirror other) => false; | |
| 2772 | |
| 2773 bool isSubtypeOf(TypeMirror other) => throw new UnimplementedError(); | |
| 2774 | |
| 2775 bool isAssignableTo(TypeMirror other) => throw new UnimplementedError(); | |
| 2776 | |
| 2777 // TODO(ahe): Implement this method. | |
| 2778 MethodMirror get callMethod => throw new UnimplementedError(); | |
| 2779 } | |
| 2780 | |
| 2781 int findTypeVariableIndex(List<TypeVariableMirror> typeVariables, String name) { | |
| 2782 for (int i = 0; i < typeVariables.length; i++) { | |
| 2783 if (typeVariables[i].simpleName == s(name)) { | |
| 2784 return i; | |
| 2785 } | |
| 2786 } | |
| 2787 throw new ArgumentError('Type variable not present in list.'); | |
| 2788 } | |
| 2789 | |
| 2790 TypeMirror typeMirrorFromRuntimeTypeRepresentation( | |
| 2791 DeclarationMirror owner, | |
| 2792 var /*int|List|JsFunction|TypeImpl*/ type) { | |
| 2793 // TODO(ahe): This method might benefit from using convertRtiToRuntimeType | |
| 2794 // instead of working on strings. | |
| 2795 ClassMirror ownerClass; | |
| 2796 DeclarationMirror context = owner; | |
| 2797 while (context != null) { | |
| 2798 if (context is ClassMirror) { | |
| 2799 ownerClass = context; | |
| 2800 break; | |
| 2801 } | |
| 2802 // TODO(ahe): Get type parameters and arguments from typedefs. | |
| 2803 if (context is TypedefMirror) break; | |
| 2804 context = context.owner; | |
| 2805 } | |
| 2806 | |
| 2807 String representation; | |
| 2808 if (type == null) { | |
| 2809 return JsMirrorSystem._dynamicType; | |
| 2810 } else if (type is TypeImpl) { | |
| 2811 return reflectType(type); | |
| 2812 } else if (ownerClass == null) { | |
| 2813 representation = runtimeTypeToString(type); | |
| 2814 } else if (ownerClass.isOriginalDeclaration) { | |
| 2815 if (type is num) { | |
| 2816 // [type] represents a type variable so in the context of an original | |
| 2817 // declaration the corresponding type variable should be returned. | |
| 2818 TypeVariable typeVariable = getMetadata(type); | |
| 2819 List<TypeVariableMirror> typeVariables = ownerClass.typeVariables; | |
| 2820 int index = findTypeVariableIndex(typeVariables, typeVariable.name); | |
| 2821 return typeVariables[index]; | |
| 2822 } else { | |
| 2823 // Nested type variables will be retrieved lazily (the integer | |
| 2824 // representation is kept in the string) so they are not processed here. | |
| 2825 representation = runtimeTypeToString(type); | |
| 2826 } | |
| 2827 } else { | |
| 2828 TypeMirror getTypeArgument(int index) { | |
| 2829 TypeVariable typeVariable = getMetadata(index); | |
| 2830 int variableIndex = | |
| 2831 findTypeVariableIndex(ownerClass.typeVariables, typeVariable.name); | |
| 2832 return ownerClass.typeArguments[variableIndex]; | |
| 2833 } | |
| 2834 | |
| 2835 if (type is num) { | |
| 2836 // [type] represents a type variable used as type argument for example | |
| 2837 // the type argument of Bar: class Foo<T> extends Bar<T> {} | |
| 2838 TypeMirror typeArgument = getTypeArgument(type); | |
| 2839 if (typeArgument is JsTypeVariableMirror) | |
| 2840 return typeArgument; | |
| 2841 } | |
| 2842 String substituteTypeVariable(int index) { | |
| 2843 var typeArgument = getTypeArgument(index); | |
| 2844 if (typeArgument is JsTypeVariableMirror) { | |
| 2845 return '${typeArgument._metadataIndex}'; | |
| 2846 } | |
| 2847 if (typeArgument is! JsClassMirror && | |
| 2848 typeArgument is! JsTypeBoundClassMirror) { | |
| 2849 if (typeArgument == JsMirrorSystem._dynamicType) { | |
| 2850 return 'dynamic'; | |
| 2851 } else if (typeArgument == JsMirrorSystem._voidType) { | |
| 2852 return 'void'; | |
| 2853 } else { | |
| 2854 // TODO(ahe): This case shouldn't happen. | |
| 2855 return 'dynamic'; | |
| 2856 } | |
| 2857 } | |
| 2858 return typeArgument._mangledName; | |
| 2859 } | |
| 2860 representation = | |
| 2861 runtimeTypeToString(type, onTypeVariable: substituteTypeVariable); | |
| 2862 } | |
| 2863 if (representation != null) { | |
| 2864 return reflectClassByMangledName( | |
| 2865 getMangledTypeName(createRuntimeType(representation))); | |
| 2866 } | |
| 2867 String typedefPropertyName = JS_GET_NAME(JsGetName.TYPEDEF_TAG); | |
| 2868 if (type != null && JS('', '#[#]', type, typedefPropertyName) != null) { | |
| 2869 return typeMirrorFromRuntimeTypeRepresentation( | |
| 2870 owner, JS('', '#[#]', type, typedefPropertyName)); | |
| 2871 } else if (type != null && isDartFunctionType(type)) { | |
| 2872 return new JsFunctionTypeMirror(type, owner); | |
| 2873 } | |
| 2874 return reflectClass(Function); | |
| 2875 } | |
| 2876 | |
| 2877 Symbol computeQualifiedName(DeclarationMirror owner, Symbol simpleName) { | |
| 2878 if (owner == null) return simpleName; | |
| 2879 String ownerName = n(owner.qualifiedName); | |
| 2880 return s('$ownerName.${n(simpleName)}'); | |
| 2881 } | |
| 2882 | |
| 2883 List extractMetadata(victim) { | |
| 2884 preserveMetadata(); | |
| 2885 var metadataFunction; | |
| 2886 if (JS('bool', 'Object.prototype.hasOwnProperty.call(#, "@")', victim)) { | |
| 2887 metadataFunction = JS('', '#["@"]', victim); | |
| 2888 } | |
| 2889 if (metadataFunction != null) return JS('', '#()', metadataFunction); | |
| 2890 if (JS('bool', 'typeof # != "function"', victim)) return const []; | |
| 2891 if (JS('bool', '# in #', r'$metadataIndex', victim)) { | |
| 2892 return JSArray.markFixedList( | |
| 2893 JS('JSExtendableArray', | |
| 2894 r'#.$reflectionInfo.splice(#.$metadataIndex)', victim, victim)) | |
| 2895 .map((int i) => getMetadata(i)).toList(); | |
| 2896 } | |
| 2897 return const []; | |
| 2898 } | |
| 2899 | |
| 2900 void parseCompactFieldSpecification( | |
| 2901 JsDeclarationMirror owner, | |
| 2902 fieldSpecification, | |
| 2903 bool isStatic, | |
| 2904 List<Mirror> result) { | |
| 2905 List fieldsMetadata = null; | |
| 2906 List<String> fields; | |
| 2907 if (fieldSpecification is List) { | |
| 2908 fields = splitFields(fieldSpecification[0], ','); | |
| 2909 fieldsMetadata = fieldSpecification.sublist(1); | |
| 2910 } else if (fieldSpecification is String) { | |
| 2911 fields = splitFields(fieldSpecification, ','); | |
| 2912 } else { | |
| 2913 fields = []; | |
| 2914 } | |
| 2915 int fieldNumber = 0; | |
| 2916 for (String field in fields) { | |
| 2917 var metadata; | |
| 2918 if (fieldsMetadata != null) { | |
| 2919 metadata = fieldsMetadata[fieldNumber++]; | |
| 2920 } | |
| 2921 var mirror = new JsVariableMirror.from(field, metadata, owner, isStatic); | |
| 2922 if (mirror != null) { | |
| 2923 result.add(mirror); | |
| 2924 } | |
| 2925 } | |
| 2926 } | |
| 2927 | |
| 2928 /// Similar to [String.split], but returns an empty list if [string] is empty. | |
| 2929 List<String> splitFields(String string, Pattern pattern) { | |
| 2930 if (string.isEmpty) return <String>[]; | |
| 2931 return string.split(pattern); | |
| 2932 } | |
| 2933 | |
| 2934 bool isOperatorName(String name) { | |
| 2935 switch (name) { | |
| 2936 case '==': | |
| 2937 case '[]': | |
| 2938 case '*': | |
| 2939 case '/': | |
| 2940 case '%': | |
| 2941 case '~/': | |
| 2942 case '+': | |
| 2943 case '<<': | |
| 2944 case '>>': | |
| 2945 case '>=': | |
| 2946 case '>': | |
| 2947 case '<=': | |
| 2948 case '<': | |
| 2949 case '&': | |
| 2950 case '^': | |
| 2951 case '|': | |
| 2952 case '-': | |
| 2953 case 'unary-': | |
| 2954 case '[]=': | |
| 2955 case '~': | |
| 2956 return true; | |
| 2957 default: | |
| 2958 return false; | |
| 2959 } | |
| 2960 } | |
| 2961 | |
| 2962 /// Returns true if the key represent ancillary reflection data, that is, not a | |
| 2963 /// method. | |
| 2964 bool isReflectiveDataInPrototype(String key) { | |
| 2965 if (key == JS_GET_NAME(JsGetName.CLASS_DESCRIPTOR_PROPERTY) || | |
| 2966 key == METHODS_WITH_OPTIONAL_ARGUMENTS) { | |
| 2967 return true; | |
| 2968 } | |
| 2969 String firstChar = key[0]; | |
| 2970 return firstChar == '*' || firstChar == '+'; | |
| 2971 } | |
| 2972 | |
| 2973 /// Returns `true` if [jsFunction] is an ordinary reflectable method and | |
| 2974 /// not a (potentially reflectable) stub or otherwise non-reflectable method. | |
| 2975 bool isOrdinaryReflectableMethod(var jsFunction) { | |
| 2976 return JS('bool', r'#.$reflectable === 1', jsFunction); | |
| 2977 } | |
| 2978 | |
| 2979 /// Returns true if [key] is only an aliased entry for [function] in the | |
| 2980 /// prototype. | |
| 2981 bool isAliasedSuperMethod(var jsFunction, String key) { | |
| 2982 var stubName = JS('String|Null', r'#.$stubName', jsFunction); | |
| 2983 return stubName != null && key != stubName; | |
| 2984 } | |
| 2985 | |
| 2986 class NoSuchStaticMethodError extends Error implements NoSuchMethodError { | |
| 2987 static const int MISSING_CONSTRUCTOR = 0; | |
| 2988 static const int MISSING_METHOD = 1; | |
| 2989 final ClassMirror _cls; | |
| 2990 final Symbol _name; | |
| 2991 final List _positionalArguments; | |
| 2992 final Map<Symbol, dynamic> _namedArguments; | |
| 2993 final int _kind; | |
| 2994 | |
| 2995 NoSuchStaticMethodError.missingConstructor( | |
| 2996 this._cls, | |
| 2997 this._name, | |
| 2998 this._positionalArguments, | |
| 2999 this._namedArguments) | |
| 3000 : _kind = MISSING_CONSTRUCTOR; | |
| 3001 | |
| 3002 /// If the given class is `null` the static method/getter/setter is top-level. | |
| 3003 NoSuchStaticMethodError.method( | |
| 3004 this._cls, | |
| 3005 this._name, | |
| 3006 this._positionalArguments, | |
| 3007 this._namedArguments) | |
| 3008 : _kind = MISSING_METHOD; | |
| 3009 | |
| 3010 String toString() { | |
| 3011 // TODO(floitsch): show arguments. | |
| 3012 switch(_kind) { | |
| 3013 case MISSING_CONSTRUCTOR: | |
| 3014 return | |
| 3015 "NoSuchMethodError: No constructor named '${n(_name)}' in class" | |
| 3016 " '${n(_cls.qualifiedName)}'."; | |
| 3017 case MISSING_METHOD: | |
| 3018 if (_cls == null) { | |
| 3019 return "NoSuchMethodError: No top-level method named '${n(_name)}'."; | |
| 3020 } | |
| 3021 return "NoSuchMethodError: No static method named '${n(_name)}' in" | |
| 3022 " class '${n(_cls.qualifiedName)}'"; | |
| 3023 default: | |
| 3024 return 'NoSuchMethodError'; | |
| 3025 } | |
| 3026 } | |
| 3027 } | |
| 3028 | |
| 3029 Symbol getSymbol(String name, LibraryMirror library) { | |
| 3030 if (_isPublicSymbol(name)) { | |
| 3031 return new _symbol_dev.Symbol.validated(name); | |
| 3032 } | |
| 3033 if (library == null) { | |
| 3034 throw new ArgumentError( | |
| 3035 "Library required for private symbol name: $name"); | |
| 3036 } | |
| 3037 if (!_symbol_dev.Symbol.isValidSymbol(name)) { | |
| 3038 throw new ArgumentError("Not a valid symbol name: $name"); | |
| 3039 } | |
| 3040 throw new UnimplementedError( | |
| 3041 "MirrorSystem.getSymbol not implemented for private names"); | |
| 3042 } | |
| 3043 | |
| 3044 bool _isPublicSymbol(String name) { | |
| 3045 // A symbol is public if it doesn't start with '_' and it doesn't | |
| 3046 // have a part (following a '.') that starts with '_'. | |
| 3047 const int UNDERSCORE = 0x5f; | |
| 3048 if (name.isEmpty) return true; | |
| 3049 int index = -1; | |
| 3050 do { | |
| 3051 if (name.codeUnitAt(index + 1) == UNDERSCORE) return false; | |
| 3052 index = name.indexOf('.', index + 1); | |
| 3053 } while (index >= 0 && index + 1 < name.length); | |
| 3054 return true; | |
| 3055 } | |
| OLD | NEW |