| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library mirrors_util; | 5 library mirrors_util; |
| 6 | 6 |
| 7 import 'dart:collection' show Queue, IterableBase; | 7 import 'dart:collection' show Queue, IterableBase; |
| 8 | 8 |
| 9 // TODO(rnystrom): Use "package:" URL (#4968). | 9 import 'source_mirrors.dart'; |
| 10 import 'mirrors.dart'; | |
| 11 | 10 |
| 12 //------------------------------------------------------------------------------ | 11 //------------------------------------------------------------------------------ |
| 13 // Utility functions for using the Mirror API | 12 // Utility functions for using the Mirror API |
| 14 //------------------------------------------------------------------------------ | 13 //------------------------------------------------------------------------------ |
| 15 | 14 |
| 15 String nameOf(DeclarationMirror mirror) => |
| 16 MirrorSystem.getName(mirror.simpleName); |
| 17 |
| 18 String qualifiedNameOf(DeclarationMirror mirror) => |
| 19 MirrorSystem.getName(mirror.qualifiedName); |
| 20 |
| 21 // TODO(johnniwinther): Handle private names. |
| 22 Symbol symbolOf(String name, [LibraryMirror library]) => new Symbol(name); |
| 16 | 23 |
| 17 /** | 24 /** |
| 18 * Return the display name for [mirror]. | 25 * Return the display name for [mirror]. |
| 19 * | 26 * |
| 20 * The display name is the normal representation of the entity name. In most | 27 * The display name is the normal representation of the entity name. In most |
| 21 * cases the display name is the simple name, but for a setter 'foo=' the | 28 * cases the display name is the simple name, but for a setter 'foo=' the |
| 22 * display name is simply 'foo' and for the unary minus operator the display | 29 * display name is simply 'foo' and for the unary minus operator the display |
| 23 * name is 'operator -'. For 'dart:' libraries the display name is the URI and | 30 * name is 'operator -'. For 'dart:' libraries the display name is the URI and |
| 24 * not the library name, for instance 'dart:core' instead of 'dart.core'. | 31 * not the library name, for instance 'dart:core' instead of 'dart.core'. |
| 25 * | 32 * |
| 26 * The display name is not unique. | 33 * The display name is not unique. |
| 27 */ | 34 */ |
| 28 String displayName(DeclarationMirror mirror) { | 35 String displayName(DeclarationMirror mirror) { |
| 29 if (mirror is LibraryMirror) { | 36 if (mirror is LibraryMirror) { |
| 30 LibraryMirror library = mirror; | 37 LibraryMirror library = mirror; |
| 31 if (library.uri.scheme == 'dart') { | 38 if (library.uri.scheme == 'dart') { |
| 32 return library.uri.toString(); | 39 return library.uri.toString(); |
| 33 } | 40 } |
| 34 } else if (mirror is MethodMirror) { | 41 } else if (mirror is MethodMirror) { |
| 35 MethodMirror methodMirror = mirror; | 42 String simpleName = nameOf(mirror); |
| 36 String simpleName = methodMirror.simpleName; | 43 if (mirror.isSetter) { |
| 37 if (methodMirror.isSetter) { | |
| 38 // Remove trailing '='. | 44 // Remove trailing '='. |
| 39 return simpleName.substring(0, simpleName.length-1); | 45 return simpleName.substring(0, simpleName.length-1); |
| 40 } else if (methodMirror.isOperator) { | 46 } else if (mirror.isOperator) { |
| 41 return 'operator ${operatorName(methodMirror)}'; | 47 return 'operator ${operatorName(mirror)}'; |
| 42 } else if (methodMirror.isConstructor) { | 48 } else if (mirror.isConstructor) { |
| 43 String className = displayName(methodMirror.owner); | 49 String className = displayName(mirror.owner); |
| 44 if (simpleName == '') { | 50 if (simpleName == '') { |
| 45 return className; | 51 return className; |
| 46 } else { | 52 } else { |
| 47 return '$className.$simpleName'; | 53 return '$className.$simpleName'; |
| 48 } | 54 } |
| 49 } | 55 } |
| 50 } | 56 } |
| 51 return mirror.simpleName; | 57 return MirrorSystem.getName(mirror.simpleName); |
| 52 } | 58 } |
| 53 | 59 |
| 54 /** | 60 /** |
| 55 * Returns the operator name if [methodMirror] is an operator method, | 61 * Returns the operator name if [methodMirror] is an operator method, |
| 56 * for instance [:'<':] for [:operator <:] and [:'-':] for the unary minus | 62 * for instance [:'<':] for [:operator <:] and [:'-':] for the unary minus |
| 57 * operator. Return [:null:] if [methodMirror] is not an operator method. | 63 * operator. Return [:null:] if [methodMirror] is not an operator method. |
| 58 */ | 64 */ |
| 59 String operatorName(MethodMirror methodMirror) { | 65 String operatorName(MethodMirror methodMirror) { |
| 60 String simpleName = methodMirror.simpleName; | |
| 61 if (methodMirror.isOperator) { | 66 if (methodMirror.isOperator) { |
| 62 if (simpleName == Mirror.UNARY_MINUS) { | 67 if (methodMirror.simpleName == const Symbol('unary-')) { |
| 63 return '-'; | 68 return '-'; |
| 64 } else { | 69 } else { |
| 65 return simpleName; | 70 return nameOf(methodMirror); |
| 66 } | 71 } |
| 67 } | 72 } |
| 68 return null; | 73 return null; |
| 69 } | 74 } |
| 70 | 75 |
| 71 /** | 76 /** |
| 72 * Returns an iterable over the type declarations directly inheriting from | 77 * Returns an iterable over the type declarations directly inheriting from |
| 73 * the declaration of this type. | 78 * the declaration of [type] within [mirrors]. |
| 74 */ | 79 */ |
| 75 Iterable<ClassMirror> computeSubdeclarations(ClassMirror type) { | 80 Iterable<ClassMirror> computeSubdeclarations(MirrorSystem mirrors, |
| 81 ClassMirror type) { |
| 76 type = type.originalDeclaration; | 82 type = type.originalDeclaration; |
| 77 var subtypes = <ClassMirror>[]; | 83 var subtypes = <ClassMirror>[]; |
| 78 type.mirrors.libraries.forEach((_, library) { | 84 mirrors.libraries.forEach((_, library) { |
| 79 for (ClassMirror otherType in library.classes.values) { | 85 library.declarations.values |
| 86 .where((mirror) => mirror is ClassMirror) |
| 87 .forEach((ClassMirror otherType) { |
| 80 var superClass = otherType.superclass; | 88 var superClass = otherType.superclass; |
| 81 if (superClass != null) { | 89 if (superClass != null) { |
| 82 superClass = superClass.originalDeclaration; | 90 superClass = superClass.originalDeclaration; |
| 83 if (type.library == superClass.library) { | 91 if (superClass == type) { |
| 84 if (superClass == type) { | 92 subtypes.add(otherType); |
| 85 subtypes.add(otherType); | |
| 86 } | |
| 87 } | 93 } |
| 88 } | 94 } |
| 89 final superInterfaces = otherType.superinterfaces; | 95 final superInterfaces = otherType.superinterfaces; |
| 90 for (ClassMirror superInterface in superInterfaces) { | 96 for (ClassMirror superInterface in superInterfaces) { |
| 91 superInterface = superInterface.originalDeclaration; | 97 superInterface = superInterface.originalDeclaration; |
| 92 if (type.library == superInterface.library) { | 98 if (superInterface == type) { |
| 93 if (superInterface == type) { | 99 subtypes.add(otherType); |
| 94 subtypes.add(otherType); | |
| 95 } | |
| 96 } | 100 } |
| 97 } | 101 } |
| 98 } | 102 }); |
| 99 }); | 103 }); |
| 100 return subtypes; | 104 return subtypes; |
| 101 } | 105 } |
| 102 | 106 |
| 103 LibraryMirror findLibrary(MemberMirror member) { | |
| 104 DeclarationMirror owner = member.owner; | |
| 105 if (owner is LibraryMirror) { | |
| 106 return owner; | |
| 107 } else if (owner is TypeMirror) { | |
| 108 TypeMirror mirror = owner; | |
| 109 return mirror.library; | |
| 110 } | |
| 111 throw new Exception('Unexpected owner: ${owner}'); | |
| 112 } | |
| 113 | |
| 114 class HierarchyIterable extends IterableBase<ClassMirror> { | 107 class HierarchyIterable extends IterableBase<ClassMirror> { |
| 115 final bool includeType; | 108 final bool includeType; |
| 116 final ClassMirror type; | 109 final ClassMirror type; |
| 117 | 110 |
| 118 HierarchyIterable(this.type, {bool includeType}) | 111 HierarchyIterable(this.type, {bool includeType}) |
| 119 : this.includeType = includeType; | 112 : this.includeType = includeType; |
| 120 | 113 |
| 121 Iterator<ClassMirror> get iterator => | 114 Iterator<ClassMirror> get iterator => |
| 122 new HierarchyIterator(type, includeType: includeType); | 115 new HierarchyIterator(type, includeType: includeType); |
| 123 } | 116 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 139 HierarchyIterator(ClassMirror type, {bool includeType}) { | 132 HierarchyIterator(ClassMirror type, {bool includeType}) { |
| 140 if (includeType) { | 133 if (includeType) { |
| 141 queue.add(type); | 134 queue.add(type); |
| 142 } else { | 135 } else { |
| 143 push(type); | 136 push(type); |
| 144 } | 137 } |
| 145 } | 138 } |
| 146 | 139 |
| 147 ClassMirror push(ClassMirror type) { | 140 ClassMirror push(ClassMirror type) { |
| 148 if (type.superclass != null) { | 141 if (type.superclass != null) { |
| 149 if (type.superclass.isObject) { | 142 if (isObject(type.superclass)) { |
| 150 object = type.superclass; | 143 object = type.superclass; |
| 151 } else { | 144 } else { |
| 152 queue.addFirst(type.superclass); | 145 queue.addFirst(type.superclass); |
| 153 } | 146 } |
| 154 } | 147 } |
| 155 queue.addAll(type.superinterfaces); | 148 queue.addAll(type.superinterfaces); |
| 156 return type; | 149 return type; |
| 157 } | 150 } |
| 158 | 151 |
| 159 ClassMirror get current => _current; | 152 ClassMirror get current => _current; |
| 160 | 153 |
| 161 bool moveNext() { | 154 bool moveNext() { |
| 162 _current = null; | 155 _current = null; |
| 163 if (queue.isEmpty) { | 156 if (queue.isEmpty) { |
| 164 if (object == null) return false; | 157 if (object == null) return false; |
| 165 _current = object; | 158 _current = object; |
| 166 object = null; | 159 object = null; |
| 167 return true; | 160 return true; |
| 168 } else { | 161 } else { |
| 169 _current = push(queue.removeFirst()); | 162 _current = push(queue.removeFirst()); |
| 170 return true; | 163 return true; |
| 171 } | 164 } |
| 172 } | 165 } |
| 173 } | 166 } |
| 174 | 167 |
| 168 LibraryMirror getLibrary(DeclarationMirror declaration) { |
| 169 while (declaration != null && declaration is! LibraryMirror) { |
| 170 declaration = declaration.owner; |
| 171 } |
| 172 return declaration; |
| 173 } |
| 174 |
| 175 Iterable<DeclarationMirror> membersOf( |
| 176 Map<Symbol, DeclarationMirror> declarations) { |
| 177 return declarations.values.where( |
| 178 (mirror) => mirror is MethodMirror || mirror is VariableMirror); |
| 179 } |
| 180 |
| 181 Iterable<TypeMirror> classesOf( |
| 182 Map<Symbol, DeclarationMirror> declarations) { |
| 183 return declarations.values.where((mirror) => mirror is ClassMirror); |
| 184 } |
| 185 |
| 186 Iterable<TypeMirror> typesOf( |
| 187 Map<Symbol, DeclarationMirror> declarations) { |
| 188 return declarations.values.where((mirror) => mirror is TypeMirror); |
| 189 } |
| 190 |
| 191 Iterable<MethodMirror> methodsOf( |
| 192 Map<Symbol, DeclarationMirror> declarations) { |
| 193 return declarations.values.where( |
| 194 (mirror) => mirror is MethodMirror && mirror.isRegularMethod); |
| 195 } |
| 196 |
| 197 Iterable<MethodMirror> constructorsOf( |
| 198 Map<Symbol, DeclarationMirror> declarations) { |
| 199 return declarations.values.where( |
| 200 (mirror) => mirror is MethodMirror && mirror.isConstructor); |
| 201 } |
| 202 |
| 203 Iterable<MethodMirror> settersOf( |
| 204 Map<Symbol, DeclarationMirror> declarations) { |
| 205 return declarations.values.where( |
| 206 (mirror) => mirror is MethodMirror && mirror.isSetter); |
| 207 } |
| 208 |
| 209 Iterable<MethodMirror> gettersOf( |
| 210 Map<Symbol, DeclarationMirror> declarations) { |
| 211 return declarations.values.where( |
| 212 (mirror) => mirror is MethodMirror && mirror.isGetter); |
| 213 } |
| 214 |
| 215 Iterable<VariableMirror> variablesOf( |
| 216 Map<Symbol, DeclarationMirror> declarations) { |
| 217 return declarations.values.where((mirror) => mirror is VariableMirror); |
| 218 } |
| 219 |
| 220 |
| 221 |
| 222 bool isObject(TypeMirror mirror) => |
| 223 mirror is ClassMirror && mirror.superclass == null; |
| 224 |
| 175 /// Returns `true` if [cls] is declared in a private dart library. | 225 /// Returns `true` if [cls] is declared in a private dart library. |
| 176 bool isFromPrivateDartLibrary(ClassMirror cls) { | 226 bool isFromPrivateDartLibrary(ClassMirror cls) { |
| 177 if (isMixinApplication(cls)) cls = cls.mixin; | 227 if (isMixinApplication(cls)) cls = cls.mixin; |
| 178 var uri = cls.library.uri; | 228 var uri = getLibrary(cls).uri; |
| 179 return uri.scheme == 'dart' && uri.path.startsWith('_'); | 229 return uri.scheme == 'dart' && uri.path.startsWith('_'); |
| 180 } | 230 } |
| 181 | 231 |
| 182 /// Returns `true` if [mirror] reflects a mixin application. | 232 /// Returns `true` if [mirror] reflects a mixin application. |
| 183 bool isMixinApplication(Mirror mirror) { | 233 bool isMixinApplication(Mirror mirror) { |
| 184 return mirror is ClassMirror && mirror.mixin != mirror; | 234 return mirror is ClassMirror && mirror.mixin != mirror; |
| 185 } | 235 } |
| 186 | 236 |
| 187 /** | 237 /** |
| 188 * Returns the superclass of [cls] skipping unnamed mixin applications. | 238 * Returns the superclass of [cls] skipping unnamed mixin applications. |
| 189 * | 239 * |
| 190 * For instance, for all of the following definitions this method returns [:B:]. | 240 * For instance, for all of the following definitions this method returns [:B:]. |
| 191 * | 241 * |
| 192 * class A extends B {} | 242 * class A extends B {} |
| 193 * class A extends B with C1, C2 {} | 243 * class A extends B with C1, C2 {} |
| 194 * class A extends B implements D1, D2 {} | 244 * class A extends B implements D1, D2 {} |
| 195 * class A extends B with C1, C2 implements D1, D2 {} | 245 * class A extends B with C1, C2 implements D1, D2 {} |
| 196 * class A = B with C1, C2; | 246 * class A = B with C1, C2; |
| 197 * abstract class A = B with C1, C2 implements D1, D2; | 247 * abstract class A = B with C1, C2 implements D1, D2; |
| 198 */ | 248 */ |
| 199 ClassMirror getSuperclass(ClassMirror cls) { | 249 ClassSourceMirror getSuperclass(ClassSourceMirror cls) { |
| 200 ClassMirror superclass = cls.superclass; | 250 ClassSourceMirror superclass = cls.superclass; |
| 201 while (isMixinApplication(superclass) && superclass.isNameSynthetic) { | 251 while (isMixinApplication(superclass) && superclass.isNameSynthetic) { |
| 202 superclass = superclass.superclass; | 252 superclass = superclass.superclass; |
| 203 } | 253 } |
| 204 return superclass; | 254 return superclass; |
| 205 } | 255 } |
| 206 | 256 |
| 207 /** | 257 /** |
| 208 * Returns the mixins directly applied to [cls]. | 258 * Returns the mixins directly applied to [cls]. |
| 209 * | 259 * |
| 210 * For instance, for all of the following definitions this method returns | 260 * For instance, for all of the following definitions this method returns |
| 211 * [:C1, C2:]. | 261 * [:C1, C2:]. |
| 212 * | 262 * |
| 213 * class A extends B with C1, C2 {} | 263 * class A extends B with C1, C2 {} |
| 214 * class A extends B with C1, C2 implements D1, D2 {} | 264 * class A extends B with C1, C2 implements D1, D2 {} |
| 215 * class A = B with C1, C2; | 265 * class A = B with C1, C2; |
| 216 * abstract class A = B with C1, C2 implements D1, D2; | 266 * abstract class A = B with C1, C2 implements D1, D2; |
| 217 */ | 267 */ |
| 218 Iterable<ClassMirror> getAppliedMixins(ClassMirror cls) { | 268 Iterable<ClassSourceMirror> getAppliedMixins(ClassSourceMirror cls) { |
| 219 List<ClassMirror> mixins = <ClassMirror>[]; | 269 List<ClassSourceMirror> mixins = <ClassSourceMirror>[]; |
| 220 ClassMirror superclass = cls.superclass; | 270 ClassSourceMirror superclass = cls.superclass; |
| 221 while (isMixinApplication(superclass) && superclass.isNameSynthetic) { | 271 while (isMixinApplication(superclass) && superclass.isNameSynthetic) { |
| 222 mixins.add(superclass.mixin); | 272 mixins.add(superclass.mixin); |
| 223 superclass = superclass.superclass; | 273 superclass = superclass.superclass; |
| 224 } | 274 } |
| 225 if (mixins.length > 1) { | 275 if (mixins.length > 1) { |
| 226 mixins = new List<ClassMirror>.from(mixins.reversed); | 276 mixins = new List<ClassSourceMirror>.from(mixins.reversed); |
| 227 } | 277 } |
| 228 if (isMixinApplication(cls)) { | 278 if (isMixinApplication(cls)) { |
| 229 mixins.add(cls.mixin); | 279 mixins.add(cls.mixin); |
| 230 } | 280 } |
| 231 return mixins; | 281 return mixins; |
| 232 } | 282 } |
| 233 | 283 |
| 234 /** | 284 /** |
| 235 * Returns the superinterfaces directly and explicitly implemented by [cls]. | 285 * Returns the superinterfaces directly and explicitly implemented by [cls]. |
| 236 * | 286 * |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 * If [name] is of the form 'a.b.c', 'a' is looked up in the scope of | 357 * If [name] is of the form 'a.b.c', 'a' is looked up in the scope of |
| 308 * [declaration] and if unresolved 'a.b' is looked in the scope of | 358 * [declaration] and if unresolved 'a.b' is looked in the scope of |
| 309 * [declaration]. Each identifier of the remaining suffix, 'c' or 'b.c', is | 359 * [declaration]. Each identifier of the remaining suffix, 'c' or 'b.c', is |
| 310 * then looked up in the local scope of the previous result. | 360 * then looked up in the local scope of the previous result. |
| 311 * | 361 * |
| 312 * For instance, assumming that [:Iterable:] is imported into the scope of | 362 * For instance, assumming that [:Iterable:] is imported into the scope of |
| 313 * [declaration] via the prefix 'col', 'col.Iterable.E' finds the type | 363 * [declaration] via the prefix 'col', 'col.Iterable.E' finds the type |
| 314 * variable of [:Iterable:] and 'col.Iterable.contains.element' finds the | 364 * variable of [:Iterable:] and 'col.Iterable.contains.element' finds the |
| 315 * [:element:] parameter of the [:contains:] method on [:Iterable:]. | 365 * [:element:] parameter of the [:contains:] method on [:Iterable:]. |
| 316 */ | 366 */ |
| 317 DeclarationMirror lookupQualifiedInScope(DeclarationMirror declaration, | 367 DeclarationMirror lookupQualifiedInScope(DeclarationSourceMirror declaration, |
| 318 String name) { | 368 String name) { |
| 319 // TODO(11653): Support lookup of constructors using the [:new Foo:] | 369 // TODO(11653): Support lookup of constructors using the [:new Foo:] |
| 320 // syntax. | 370 // syntax. |
| 321 int offset = 1; | 371 int offset = 1; |
| 322 List<String> parts = name.split('.'); | 372 List<String> parts = name.split('.'); |
| 323 DeclarationMirror result = declaration.lookupInScope(parts[0]); | 373 DeclarationMirror result = declaration.lookupInScope(parts[0]); |
| 324 if (result == null && parts.length > 1) { | 374 if (result == null && parts.length > 1) { |
| 325 // Try lookup of `prefix.id`. | 375 // Try lookup of `prefix.id`. |
| 326 result = declaration.lookupInScope('${parts[0]}.${parts[1]}'); | 376 result = declaration.lookupInScope('${parts[0]}.${parts[1]}'); |
| 327 offset = 2; | 377 offset = 2; |
| 328 } | 378 } |
| 329 if (result == null) return null; | 379 if (result == null) return null; |
| 380 LibraryMirror library = getLibrary(result); |
| 330 while (result != null && offset < parts.length) { | 381 while (result != null && offset < parts.length) { |
| 331 result = _lookupLocal(result, parts[offset++]); | 382 result = _lookupLocal(result, symbolOf(parts[offset++], library)); |
| 332 } | 383 } |
| 333 return result; | 384 return result; |
| 334 } | 385 } |
| 335 | 386 |
| 336 DeclarationMirror _lookupLocal(Mirror mirror, String id) { | 387 DeclarationMirror _lookupLocal(Mirror mirror, Symbol id) { |
| 337 DeclarationMirror result; | 388 DeclarationMirror result; |
| 338 if (mirror is ContainerMirror) { | 389 if (mirror is LibraryMirror) { |
| 339 ContainerMirror containerMirror = mirror; | |
| 340 // Try member lookup. | 390 // Try member lookup. |
| 341 result = containerMirror.members[id]; | 391 result = mirror.declarations[id]; |
| 342 } | 392 } else if (mirror is ClassMirror) { |
| 343 if (result != null) return result; | 393 // Try member lookup. |
| 344 if (mirror is ClassMirror) { | 394 result = mirror.declarations[id]; |
| 345 ClassMirror classMirror = mirror; | 395 if (result != null) return result; |
| 346 // Try type variables. | 396 // Try type variables. |
| 347 result = classMirror.typeVariables.firstWhere( | 397 result = mirror.typeVariables.firstWhere( |
| 348 (TypeVariableMirror v) => v.simpleName == id, orElse: () => null); | 398 (TypeVariableMirror v) => v.simpleName == id, orElse: () => null); |
| 349 } else if (mirror is MethodMirror) { | 399 } else if (mirror is MethodMirror) { |
| 350 MethodMirror methodMirror = mirror; | 400 result = mirror.parameters.firstWhere( |
| 351 result = methodMirror.parameters.firstWhere( | |
| 352 (ParameterMirror p) => p.simpleName == id, orElse: () => null); | 401 (ParameterMirror p) => p.simpleName == id, orElse: () => null); |
| 353 } | 402 } |
| 354 return result; | 403 return result; |
| 355 | 404 |
| 356 } | 405 } |
| OLD | NEW |