| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library mirrors_util; | |
| 6 | |
| 7 import 'dart:collection' show Queue, IterableBase; | |
| 8 | |
| 9 import 'source_mirrors.dart'; | |
| 10 | |
| 11 //------------------------------------------------------------------------------ | |
| 12 // Utility functions for using the Mirror API | |
| 13 //------------------------------------------------------------------------------ | |
| 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); | |
| 23 | |
| 24 /** | |
| 25 * Return the display name for [mirror]. | |
| 26 * | |
| 27 * The display name is the normal representation of the entity name. In most | |
| 28 * cases the display name is the simple name, but for a setter 'foo=' the | |
| 29 * display name is simply 'foo' and for the unary minus operator the display | |
| 30 * name is 'operator -'. For 'dart:' libraries the display name is the URI and | |
| 31 * not the library name, for instance 'dart:core' instead of 'dart.core'. | |
| 32 * | |
| 33 * The display name is not unique. | |
| 34 */ | |
| 35 String displayName(DeclarationMirror mirror) { | |
| 36 if (mirror is LibraryMirror) { | |
| 37 LibraryMirror library = mirror; | |
| 38 if (library.uri.scheme == 'dart') { | |
| 39 return library.uri.toString(); | |
| 40 } | |
| 41 } else if (mirror is MethodMirror) { | |
| 42 String simpleName = nameOf(mirror); | |
| 43 if (mirror.isSetter) { | |
| 44 // Remove trailing '='. | |
| 45 return simpleName.substring(0, simpleName.length - 1); | |
| 46 } else if (mirror.isOperator) { | |
| 47 return 'operator ${operatorName(mirror)}'; | |
| 48 } else if (mirror.isConstructor) { | |
| 49 String className = displayName(mirror.owner); | |
| 50 if (simpleName == '') { | |
| 51 return className; | |
| 52 } else { | |
| 53 return '$className.$simpleName'; | |
| 54 } | |
| 55 } | |
| 56 } | |
| 57 return MirrorSystem.getName(mirror.simpleName); | |
| 58 } | |
| 59 | |
| 60 /** | |
| 61 * Returns the operator name if [methodMirror] is an operator method, | |
| 62 * for instance [:'<':] for [:operator <:] and [:'-':] for the unary minus | |
| 63 * operator. Return [:null:] if [methodMirror] is not an operator method. | |
| 64 */ | |
| 65 String operatorName(MethodMirror methodMirror) { | |
| 66 if (methodMirror.isOperator) { | |
| 67 if (methodMirror.simpleName == const Symbol('unary-')) { | |
| 68 return '-'; | |
| 69 } else { | |
| 70 return nameOf(methodMirror); | |
| 71 } | |
| 72 } | |
| 73 return null; | |
| 74 } | |
| 75 | |
| 76 /** | |
| 77 * Returns an iterable over the type declarations directly inheriting from | |
| 78 * the declaration of [type] within [mirrors]. | |
| 79 */ | |
| 80 Iterable<ClassMirror> computeSubdeclarations( | |
| 81 MirrorSystem mirrors, ClassMirror type) { | |
| 82 type = type.originalDeclaration; | |
| 83 var subtypes = <ClassMirror>[]; | |
| 84 mirrors.libraries.forEach((_, library) { | |
| 85 library.declarations.values | |
| 86 .where((mirror) => mirror is ClassMirror) | |
| 87 .forEach((ClassMirror otherType) { | |
| 88 var superClass = otherType.superclass; | |
| 89 if (superClass != null) { | |
| 90 superClass = superClass.originalDeclaration; | |
| 91 if (superClass == type) { | |
| 92 subtypes.add(otherType); | |
| 93 } | |
| 94 } | |
| 95 final superInterfaces = otherType.superinterfaces; | |
| 96 for (ClassMirror superInterface in superInterfaces) { | |
| 97 superInterface = superInterface.originalDeclaration; | |
| 98 if (superInterface == type) { | |
| 99 subtypes.add(otherType); | |
| 100 } | |
| 101 } | |
| 102 }); | |
| 103 }); | |
| 104 return subtypes; | |
| 105 } | |
| 106 | |
| 107 class HierarchyIterable extends IterableBase<ClassMirror> { | |
| 108 final bool includeType; | |
| 109 final ClassMirror type; | |
| 110 | |
| 111 HierarchyIterable(this.type, {bool includeType}) | |
| 112 : this.includeType = includeType; | |
| 113 | |
| 114 Iterator<ClassMirror> get iterator => | |
| 115 new HierarchyIterator(type, includeType: includeType); | |
| 116 } | |
| 117 | |
| 118 /** | |
| 119 * [HierarchyIterator] iterates through the class hierarchy of the provided | |
| 120 * type. | |
| 121 * | |
| 122 * First the superclass relation is traversed, skipping [Object], next the | |
| 123 * superinterface relation and finally is [Object] visited. The supertypes are | |
| 124 * visited in breadth first order and a superinterface is visited more than once | |
| 125 * if implemented through multiple supertypes. | |
| 126 */ | |
| 127 class HierarchyIterator implements Iterator<ClassMirror> { | |
| 128 final Queue<ClassMirror> queue = new Queue<ClassMirror>(); | |
| 129 ClassMirror object; | |
| 130 ClassMirror _current; | |
| 131 | |
| 132 HierarchyIterator(ClassMirror type, {bool includeType}) { | |
| 133 if (includeType) { | |
| 134 queue.add(type); | |
| 135 } else { | |
| 136 push(type); | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 ClassMirror push(ClassMirror type) { | |
| 141 if (type.superclass != null) { | |
| 142 if (isObject(type.superclass)) { | |
| 143 object = type.superclass; | |
| 144 } else { | |
| 145 queue.addFirst(type.superclass); | |
| 146 } | |
| 147 } | |
| 148 queue.addAll(type.superinterfaces); | |
| 149 return type; | |
| 150 } | |
| 151 | |
| 152 ClassMirror get current => _current; | |
| 153 | |
| 154 bool moveNext() { | |
| 155 _current = null; | |
| 156 if (queue.isEmpty) { | |
| 157 if (object == null) return false; | |
| 158 _current = object; | |
| 159 object = null; | |
| 160 return true; | |
| 161 } else { | |
| 162 _current = push(queue.removeFirst()); | |
| 163 return true; | |
| 164 } | |
| 165 } | |
| 166 } | |
| 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 | |
| 178 .where((mirror) => mirror is MethodMirror || mirror is VariableMirror); | |
| 179 } | |
| 180 | |
| 181 Iterable<TypeMirror> classesOf(Map<Symbol, DeclarationMirror> declarations) { | |
| 182 return new _TypeOfIterable<ClassMirror>(declarations.values); | |
| 183 } | |
| 184 | |
| 185 Iterable<TypeMirror> typesOf(Map<Symbol, DeclarationMirror> declarations) { | |
| 186 return new _TypeOfIterable<TypeMirror>(declarations.values); | |
| 187 } | |
| 188 | |
| 189 Iterable<MethodMirror> methodsOf(Map<Symbol, DeclarationMirror> declarations) { | |
| 190 return anyMethodOf(declarations).where((mirror) => mirror.isRegularMethod); | |
| 191 } | |
| 192 | |
| 193 Iterable<MethodMirror> constructorsOf( | |
| 194 Map<Symbol, DeclarationMirror> declarations) { | |
| 195 return anyMethodOf(declarations).where((mirror) => mirror.isConstructor); | |
| 196 } | |
| 197 | |
| 198 Iterable<MethodMirror> settersOf(Map<Symbol, DeclarationMirror> declarations) { | |
| 199 return anyMethodOf(declarations).where((mirror) => mirror.isSetter); | |
| 200 } | |
| 201 | |
| 202 Iterable<MethodMirror> gettersOf(Map<Symbol, DeclarationMirror> declarations) { | |
| 203 return anyMethodOf(declarations).where((mirror) => mirror.isGetter); | |
| 204 } | |
| 205 | |
| 206 Iterable<MethodMirror> anyMethodOf( | |
| 207 Map<Symbol, DeclarationMirror> declarations) { | |
| 208 return new _TypeOfIterable<MethodMirror>(declarations.values); | |
| 209 } | |
| 210 | |
| 211 Iterable<VariableMirror> variablesOf( | |
| 212 Map<Symbol, DeclarationMirror> declarations) { | |
| 213 return new _TypeOfIterable<VariableMirror>(declarations.values); | |
| 214 } | |
| 215 | |
| 216 class _TypeOfIterable<T> extends IterableBase<T> { | |
| 217 final Iterable _source; | |
| 218 | |
| 219 _TypeOfIterable(this._source); | |
| 220 | |
| 221 Iterator<T> get iterator => new _TypeOfIterator<T>(_source.iterator); | |
| 222 } | |
| 223 | |
| 224 class _TypeOfIterator<T> implements Iterator<T> { | |
| 225 final Iterator _source; | |
| 226 | |
| 227 T get current => _source.current; | |
| 228 | |
| 229 _TypeOfIterator(this._source); | |
| 230 | |
| 231 bool moveNext() { | |
| 232 while (_source.moveNext()) { | |
| 233 if (_source.current is T) { | |
| 234 return true; | |
| 235 } | |
| 236 } | |
| 237 return false; | |
| 238 } | |
| 239 } | |
| 240 | |
| 241 bool isObject(TypeMirror mirror) => | |
| 242 mirror is ClassMirror && mirror.superclass == null; | |
| 243 | |
| 244 /// Returns `true` if [cls] is declared in a private dart library. | |
| 245 bool isFromPrivateDartLibrary(ClassMirror cls) { | |
| 246 if (isMixinApplication(cls)) cls = cls.mixin; | |
| 247 var uri = getLibrary(cls).uri; | |
| 248 return uri.scheme == 'dart' && uri.path.startsWith('_'); | |
| 249 } | |
| 250 | |
| 251 /// Returns `true` if [mirror] reflects a mixin application. | |
| 252 bool isMixinApplication(Mirror mirror) { | |
| 253 return mirror is ClassMirror && mirror.mixin != mirror; | |
| 254 } | |
| 255 | |
| 256 /** | |
| 257 * Returns the superclass of [cls] skipping unnamed mixin applications. | |
| 258 * | |
| 259 * For instance, for all of the following definitions this method returns [:B:]. | |
| 260 * | |
| 261 * class A extends B {} | |
| 262 * class A extends B with C1, C2 {} | |
| 263 * class A extends B implements D1, D2 {} | |
| 264 * class A extends B with C1, C2 implements D1, D2 {} | |
| 265 * class A = B with C1, C2; | |
| 266 * abstract class A = B with C1, C2 implements D1, D2; | |
| 267 */ | |
| 268 ClassSourceMirror getSuperclass(ClassSourceMirror cls) { | |
| 269 ClassSourceMirror superclass = cls.superclass; | |
| 270 while (isMixinApplication(superclass) && superclass.isNameSynthetic) { | |
| 271 superclass = superclass.superclass; | |
| 272 } | |
| 273 return superclass; | |
| 274 } | |
| 275 | |
| 276 /** | |
| 277 * Returns the mixins directly applied to [cls]. | |
| 278 * | |
| 279 * For instance, for all of the following definitions this method returns | |
| 280 * [:C1, C2:]. | |
| 281 * | |
| 282 * class A extends B with C1, C2 {} | |
| 283 * class A extends B with C1, C2 implements D1, D2 {} | |
| 284 * class A = B with C1, C2; | |
| 285 * abstract class A = B with C1, C2 implements D1, D2; | |
| 286 */ | |
| 287 Iterable<ClassSourceMirror> getAppliedMixins(ClassSourceMirror cls) { | |
| 288 List<ClassSourceMirror> mixins = <ClassSourceMirror>[]; | |
| 289 ClassSourceMirror superclass = cls.superclass; | |
| 290 while (isMixinApplication(superclass) && superclass.isNameSynthetic) { | |
| 291 mixins.add(superclass.mixin); | |
| 292 superclass = superclass.superclass; | |
| 293 } | |
| 294 if (mixins.length > 1) { | |
| 295 mixins = new List<ClassSourceMirror>.from(mixins.reversed); | |
| 296 } | |
| 297 if (isMixinApplication(cls)) { | |
| 298 mixins.add(cls.mixin); | |
| 299 } | |
| 300 return mixins; | |
| 301 } | |
| 302 | |
| 303 /** | |
| 304 * Returns the superinterfaces directly and explicitly implemented by [cls]. | |
| 305 * | |
| 306 * For instance, for all of the following definitions this method returns | |
| 307 * [:D1, D2:]. | |
| 308 * | |
| 309 * class A extends B implements D1, D2 {} | |
| 310 * class A extends B with C1, C2 implements D1, D2 {} | |
| 311 * abstract class A = B with C1, C2 implements D1, D2; | |
| 312 */ | |
| 313 Iterable<ClassMirror> getExplicitInterfaces(ClassMirror cls) { | |
| 314 if (isMixinApplication(cls)) { | |
| 315 bool first = true; | |
| 316 ClassMirror mixin = cls.mixin; | |
| 317 bool filter(ClassMirror superinterface) { | |
| 318 if (first && superinterface == mixin) { | |
| 319 first = false; | |
| 320 return false; | |
| 321 } | |
| 322 return true; | |
| 323 } | |
| 324 return cls.superinterfaces.where(filter); | |
| 325 } | |
| 326 return cls.superinterfaces; | |
| 327 } | |
| 328 | |
| 329 final RegExp _singleLineCommentStart = new RegExp(r'^///? ?(.*)'); | |
| 330 final RegExp _multiLineCommentStartEnd = | |
| 331 new RegExp(r'^/\*\*? ?([\s\S]*)\*/$', multiLine: true); | |
| 332 final RegExp _multiLineCommentLineStart = new RegExp(r'^[ \t]*\* ?(.*)'); | |
| 333 | |
| 334 /** | |
| 335 * Pulls the raw text out of a comment (i.e. removes the comment | |
| 336 * characters). | |
| 337 */ | |
| 338 String stripComment(String comment) { | |
| 339 Match match = _singleLineCommentStart.firstMatch(comment); | |
| 340 if (match != null) { | |
| 341 return match[1]; | |
| 342 } | |
| 343 match = _multiLineCommentStartEnd.firstMatch(comment); | |
| 344 if (match != null) { | |
| 345 comment = match[1]; | |
| 346 var sb = new StringBuffer(); | |
| 347 List<String> lines = comment.split('\n'); | |
| 348 for (int index = 0; index < lines.length; index++) { | |
| 349 String line = lines[index]; | |
| 350 if (index == 0) { | |
| 351 sb.write(line); // Add the first line unprocessed. | |
| 352 continue; | |
| 353 } | |
| 354 sb.write('\n'); | |
| 355 match = _multiLineCommentLineStart.firstMatch(line); | |
| 356 if (match != null) { | |
| 357 sb.write(match[1]); | |
| 358 } else if (index < lines.length - 1 || !line.trim().isEmpty) { | |
| 359 // Do not add the last line if it only contains white space. | |
| 360 // This interprets cases like | |
| 361 // /* | |
| 362 // * Foo | |
| 363 // */ | |
| 364 // as "\nFoo\n" and not as "\nFoo\n ". | |
| 365 sb.write(line); | |
| 366 } | |
| 367 } | |
| 368 return sb.toString(); | |
| 369 } | |
| 370 throw new ArgumentError('Invalid comment $comment'); | |
| 371 } | |
| 372 | |
| 373 /** | |
| 374 * Looks up [name] in the scope [declaration]. | |
| 375 * | |
| 376 * If [name] is of the form 'a.b.c', 'a' is looked up in the scope of | |
| 377 * [declaration] and if unresolved 'a.b' is looked in the scope of | |
| 378 * [declaration]. Each identifier of the remaining suffix, 'c' or 'b.c', is | |
| 379 * then looked up in the local scope of the previous result. | |
| 380 * | |
| 381 * For instance, assumming that [:Iterable:] is imported into the scope of | |
| 382 * [declaration] via the prefix 'col', 'col.Iterable.E' finds the type | |
| 383 * variable of [:Iterable:] and 'col.Iterable.contains.element' finds the | |
| 384 * [:element:] parameter of the [:contains:] method on [:Iterable:]. | |
| 385 */ | |
| 386 DeclarationMirror lookupQualifiedInScope( | |
| 387 DeclarationSourceMirror declaration, String name) { | |
| 388 // TODO(11653): Support lookup of constructors using the [:new Foo:] | |
| 389 // syntax. | |
| 390 int offset = 1; | |
| 391 List<String> parts = name.split('.'); | |
| 392 DeclarationMirror result = declaration.lookupInScope(parts[0]); | |
| 393 if (result == null && parts.length > 1) { | |
| 394 // Try lookup of `prefix.id`. | |
| 395 result = declaration.lookupInScope('${parts[0]}.${parts[1]}'); | |
| 396 offset = 2; | |
| 397 } | |
| 398 if (result == null) return null; | |
| 399 LibraryMirror library = getLibrary(result); | |
| 400 while (result != null && offset < parts.length) { | |
| 401 result = _lookupLocal(result, symbolOf(parts[offset++], library)); | |
| 402 } | |
| 403 return result; | |
| 404 } | |
| 405 | |
| 406 DeclarationMirror _lookupLocal(Mirror mirror, Symbol id) { | |
| 407 DeclarationMirror result; | |
| 408 if (mirror is LibraryMirror) { | |
| 409 // Try member lookup. | |
| 410 result = mirror.declarations[id]; | |
| 411 } else if (mirror is ClassMirror) { | |
| 412 // Try member lookup. | |
| 413 result = mirror.declarations[id]; | |
| 414 if (result != null) return result; | |
| 415 // Try type variables. | |
| 416 result = mirror.typeVariables.firstWhere( | |
| 417 (TypeVariableMirror v) => v.simpleName == id, | |
| 418 orElse: () => null); | |
| 419 } else if (mirror is MethodMirror) { | |
| 420 result = mirror.parameters.firstWhere( | |
| 421 (ParameterMirror p) => p.simpleName == id, | |
| 422 orElse: () => null); | |
| 423 } | |
| 424 return result; | |
| 425 } | |
| OLD | NEW |