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(MirrorSystem mirrors, | |
81 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.where( | |
178 (mirror) => mirror is MethodMirror || mirror is VariableMirror); | |
179 } | |
180 | |
181 Iterable<TypeMirror> classesOf( | |
182 Map<Symbol, DeclarationMirror> declarations) { | |
183 return new _TypeOfIterable<ClassMirror>(declarations.values); | |
184 } | |
185 | |
186 Iterable<TypeMirror> typesOf( | |
187 Map<Symbol, DeclarationMirror> declarations) { | |
188 return new _TypeOfIterable<TypeMirror>(declarations.values); | |
189 } | |
190 | |
191 Iterable<MethodMirror> methodsOf( | |
192 Map<Symbol, DeclarationMirror> declarations) { | |
193 return anyMethodOf(declarations).where((mirror) => mirror.isRegularMethod); | |
194 } | |
195 | |
196 Iterable<MethodMirror> constructorsOf( | |
197 Map<Symbol, DeclarationMirror> declarations) { | |
198 return anyMethodOf(declarations).where((mirror) => mirror.isConstructor); | |
199 } | |
200 | |
201 Iterable<MethodMirror> settersOf( | |
202 Map<Symbol, DeclarationMirror> declarations) { | |
203 return anyMethodOf(declarations).where((mirror) => mirror.isSetter); | |
204 } | |
205 | |
206 Iterable<MethodMirror> gettersOf( | |
207 Map<Symbol, DeclarationMirror> declarations) { | |
208 return anyMethodOf(declarations).where((mirror) => mirror.isGetter); | |
209 } | |
210 | |
211 Iterable<MethodMirror> anyMethodOf( | |
212 Map<Symbol, DeclarationMirror> declarations) { | |
213 return new _TypeOfIterable<MethodMirror>(declarations.values); | |
214 } | |
215 | |
216 Iterable<VariableMirror> variablesOf( | |
217 Map<Symbol, DeclarationMirror> declarations) { | |
218 return new _TypeOfIterable<VariableMirror>(declarations.values); | |
219 } | |
220 | |
221 class _TypeOfIterable<T> extends IterableBase<T> { | |
222 final Iterable _source; | |
223 | |
224 _TypeOfIterable(this._source); | |
225 | |
226 Iterator<T> get iterator => new _TypeOfIterator<T>(_source.iterator); | |
227 } | |
228 | |
229 class _TypeOfIterator<T> implements Iterator<T> { | |
230 final Iterator _source; | |
231 | |
232 T get current => _source.current; | |
233 | |
234 _TypeOfIterator(this._source); | |
235 | |
236 bool moveNext() { | |
237 while(_source.moveNext()) { | |
238 if (_source.current is T) { | |
239 return true; | |
240 } | |
241 } | |
242 return false; | |
243 } | |
244 } | |
245 | |
246 bool isObject(TypeMirror mirror) => | |
247 mirror is ClassMirror && mirror.superclass == null; | |
248 | |
249 /// Returns `true` if [cls] is declared in a private dart library. | |
250 bool isFromPrivateDartLibrary(ClassMirror cls) { | |
251 if (isMixinApplication(cls)) cls = cls.mixin; | |
252 var uri = getLibrary(cls).uri; | |
253 return uri.scheme == 'dart' && uri.path.startsWith('_'); | |
254 } | |
255 | |
256 /// Returns `true` if [mirror] reflects a mixin application. | |
257 bool isMixinApplication(Mirror mirror) { | |
258 return mirror is ClassMirror && mirror.mixin != mirror; | |
259 } | |
260 | |
261 /** | |
262 * Returns the superclass of [cls] skipping unnamed mixin applications. | |
263 * | |
264 * For instance, for all of the following definitions this method returns [:B:]. | |
265 * | |
266 * class A extends B {} | |
267 * class A extends B with C1, C2 {} | |
268 * class A extends B implements D1, D2 {} | |
269 * class A extends B with C1, C2 implements D1, D2 {} | |
270 * class A = B with C1, C2; | |
271 * abstract class A = B with C1, C2 implements D1, D2; | |
272 */ | |
273 ClassSourceMirror getSuperclass(ClassSourceMirror cls) { | |
274 ClassSourceMirror superclass = cls.superclass; | |
275 while (isMixinApplication(superclass) && superclass.isNameSynthetic) { | |
276 superclass = superclass.superclass; | |
277 } | |
278 return superclass; | |
279 } | |
280 | |
281 /** | |
282 * Returns the mixins directly applied to [cls]. | |
283 * | |
284 * For instance, for all of the following definitions this method returns | |
285 * [:C1, C2:]. | |
286 * | |
287 * class A extends B with C1, C2 {} | |
288 * class A extends B with C1, C2 implements D1, D2 {} | |
289 * class A = B with C1, C2; | |
290 * abstract class A = B with C1, C2 implements D1, D2; | |
291 */ | |
292 Iterable<ClassSourceMirror> getAppliedMixins(ClassSourceMirror cls) { | |
293 List<ClassSourceMirror> mixins = <ClassSourceMirror>[]; | |
294 ClassSourceMirror superclass = cls.superclass; | |
295 while (isMixinApplication(superclass) && superclass.isNameSynthetic) { | |
296 mixins.add(superclass.mixin); | |
297 superclass = superclass.superclass; | |
298 } | |
299 if (mixins.length > 1) { | |
300 mixins = new List<ClassSourceMirror>.from(mixins.reversed); | |
301 } | |
302 if (isMixinApplication(cls)) { | |
303 mixins.add(cls.mixin); | |
304 } | |
305 return mixins; | |
306 } | |
307 | |
308 /** | |
309 * Returns the superinterfaces directly and explicitly implemented by [cls]. | |
310 * | |
311 * For instance, for all of the following definitions this method returns | |
312 * [:D1, D2:]. | |
313 * | |
314 * class A extends B implements D1, D2 {} | |
315 * class A extends B with C1, C2 implements D1, D2 {} | |
316 * abstract class A = B with C1, C2 implements D1, D2; | |
317 */ | |
318 Iterable<ClassMirror> getExplicitInterfaces(ClassMirror cls) { | |
319 if (isMixinApplication(cls)) { | |
320 bool first = true; | |
321 ClassMirror mixin = cls.mixin; | |
322 bool filter(ClassMirror superinterface) { | |
323 if (first && superinterface == mixin) { | |
324 first = false; | |
325 return false; | |
326 } | |
327 return true; | |
328 } | |
329 return cls.superinterfaces.where(filter); | |
330 } | |
331 return cls.superinterfaces; | |
332 } | |
333 | |
334 final RegExp _singleLineCommentStart = new RegExp(r'^///? ?(.*)'); | |
335 final RegExp _multiLineCommentStartEnd = | |
336 new RegExp(r'^/\*\*? ?([\s\S]*)\*/$', multiLine: true); | |
337 final RegExp _multiLineCommentLineStart = new RegExp(r'^[ \t]*\* ?(.*)'); | |
338 | |
339 /** | |
340 * Pulls the raw text out of a comment (i.e. removes the comment | |
341 * characters). | |
342 */ | |
343 String stripComment(String comment) { | |
344 Match match = _singleLineCommentStart.firstMatch(comment); | |
345 if (match != null) { | |
346 return match[1]; | |
347 } | |
348 match = _multiLineCommentStartEnd.firstMatch(comment); | |
349 if (match != null) { | |
350 comment = match[1]; | |
351 var sb = new StringBuffer(); | |
352 List<String> lines = comment.split('\n'); | |
353 for (int index = 0 ; index < lines.length ; index++) { | |
354 String line = lines[index]; | |
355 if (index == 0) { | |
356 sb.write(line); // Add the first line unprocessed. | |
357 continue; | |
358 } | |
359 sb.write('\n'); | |
360 match = _multiLineCommentLineStart.firstMatch(line); | |
361 if (match != null) { | |
362 sb.write(match[1]); | |
363 } else if (index < lines.length-1 || !line.trim().isEmpty) { | |
364 // Do not add the last line if it only contains white space. | |
365 // This interprets cases like | |
366 // /* | |
367 // * Foo | |
368 // */ | |
369 // as "\nFoo\n" and not as "\nFoo\n ". | |
370 sb.write(line); | |
371 } | |
372 } | |
373 return sb.toString(); | |
374 } | |
375 throw new ArgumentError('Invalid comment $comment'); | |
376 } | |
377 | |
378 /** | |
379 * Looks up [name] in the scope [declaration]. | |
380 * | |
381 * If [name] is of the form 'a.b.c', 'a' is looked up in the scope of | |
382 * [declaration] and if unresolved 'a.b' is looked in the scope of | |
383 * [declaration]. Each identifier of the remaining suffix, 'c' or 'b.c', is | |
384 * then looked up in the local scope of the previous result. | |
385 * | |
386 * For instance, assumming that [:Iterable:] is imported into the scope of | |
387 * [declaration] via the prefix 'col', 'col.Iterable.E' finds the type | |
388 * variable of [:Iterable:] and 'col.Iterable.contains.element' finds the | |
389 * [:element:] parameter of the [:contains:] method on [:Iterable:]. | |
390 */ | |
391 DeclarationMirror lookupQualifiedInScope(DeclarationSourceMirror declaration, | |
392 String name) { | |
393 // TODO(11653): Support lookup of constructors using the [:new Foo:] | |
394 // syntax. | |
395 int offset = 1; | |
396 List<String> parts = name.split('.'); | |
397 DeclarationMirror result = declaration.lookupInScope(parts[0]); | |
398 if (result == null && parts.length > 1) { | |
399 // Try lookup of `prefix.id`. | |
400 result = declaration.lookupInScope('${parts[0]}.${parts[1]}'); | |
401 offset = 2; | |
402 } | |
403 if (result == null) return null; | |
404 LibraryMirror library = getLibrary(result); | |
405 while (result != null && offset < parts.length) { | |
406 result = _lookupLocal(result, symbolOf(parts[offset++], library)); | |
407 } | |
408 return result; | |
409 } | |
410 | |
411 DeclarationMirror _lookupLocal(Mirror mirror, Symbol id) { | |
412 DeclarationMirror result; | |
413 if (mirror is LibraryMirror) { | |
414 // Try member lookup. | |
415 result = mirror.declarations[id]; | |
416 } else if (mirror is ClassMirror) { | |
417 // Try member lookup. | |
418 result = mirror.declarations[id]; | |
419 if (result != null) return result; | |
420 // Try type variables. | |
421 result = mirror.typeVariables.firstWhere( | |
422 (TypeVariableMirror v) => v.simpleName == id, orElse: () => null); | |
423 } else if (mirror is MethodMirror) { | |
424 result = mirror.parameters.firstWhere( | |
425 (ParameterMirror p) => p.simpleName == id, orElse: () => null); | |
426 } | |
427 return result; | |
428 | |
429 } | |
OLD | NEW |