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 dart2js.mirrors; | |
6 | |
7 import 'dart:collection' show UnmodifiableListView; | |
8 | |
9 import '../elements/elements.dart'; | |
10 import '../scanner/scannerlib.dart'; | |
11 import '../resolution/resolution.dart' show Scope; | |
12 import '../dart2jslib.dart'; | |
13 import '../dart_types.dart'; | |
14 import '../tree/tree.dart'; | |
15 import '../util/util.dart' show Spannable, Link, LinkBuilder; | |
16 import '../util/characters.dart' show $CR, $LF; | |
17 | |
18 import 'source_mirrors.dart'; | |
19 import 'mirrors_util.dart'; | |
20 import 'util.dart'; | |
21 | |
22 part 'dart2js_library_mirror.dart'; | |
23 part 'dart2js_type_mirrors.dart'; | |
24 part 'dart2js_member_mirrors.dart'; | |
25 part 'dart2js_instance_mirrors.dart'; | |
26 | |
27 //------------------------------------------------------------------------------ | |
28 // Utility types and functions for the dart2js mirror system | |
29 //------------------------------------------------------------------------------ | |
30 | |
31 bool _isPrivate(String name) { | |
32 return name.startsWith('_'); | |
33 } | |
34 | |
35 List<ParameterMirror> _parametersFromFunctionSignature( | |
36 Dart2JsDeclarationMirror owner, | |
37 FunctionSignature signature) { | |
38 var parameters = <ParameterMirror>[]; | |
39 Link<Element> link = signature.requiredParameters; | |
40 while (!link.isEmpty) { | |
41 parameters.add(new Dart2JsParameterMirror( | |
42 owner, link.head, isOptional: false, isNamed: false)); | |
43 link = link.tail; | |
44 } | |
45 link = signature.optionalParameters; | |
46 bool isNamed = signature.optionalParametersAreNamed; | |
47 while (!link.isEmpty) { | |
48 parameters.add(new Dart2JsParameterMirror( | |
49 owner, link.head, isOptional: true, isNamed: isNamed)); | |
50 link = link.tail; | |
51 } | |
52 return parameters; | |
53 } | |
54 | |
55 MethodMirror _convertElementMethodToMethodMirror(Dart2JsDeclarationMirror librar y, | |
Emily Fortuna
2014/01/30 19:33:10
80 char. :-P
Johnni Winther
2014/02/03 08:22:48
Done.
| |
56 Element element) { | |
57 if (element is FunctionElement) { | |
58 return new Dart2JsMethodMirror(library, element); | |
59 } else { | |
60 return null; | |
61 } | |
62 } | |
63 | |
64 //------------------------------------------------------------------------------ | |
65 // Dart2Js specific extensions of mirror interfaces | |
66 //------------------------------------------------------------------------------ | |
67 | |
68 abstract class Dart2JsMirror implements Mirror { | |
69 Dart2JsMirrorSystem get mirrors; | |
70 } | |
71 | |
72 abstract class Dart2JsDeclarationMirror extends Dart2JsMirror | |
73 implements DeclarationSourceMirror { | |
74 | |
75 bool get isTopLevel => owner != null && owner is LibraryMirror; | |
76 | |
77 bool get isPrivate => _isPrivate(_simpleNameString); | |
78 | |
79 String get _simpleNameString; | |
80 | |
81 String get _qualifiedNameString { | |
82 var parent = owner; | |
83 if (parent is Dart2JsDeclarationMirror) { | |
84 return '${parent._qualifiedNameString}.${_simpleNameString}'; | |
85 } | |
86 assert(parent == null); | |
87 return _simpleNameString; | |
88 } | |
89 | |
90 Symbol get simpleName => symbolOf(_simpleNameString, getLibrary(this)); | |
91 | |
92 Symbol get qualifiedName => symbolOf(_qualifiedNameString, getLibrary(this)); | |
93 | |
94 /** | |
95 * Returns the first token for the source of this declaration, not including | |
96 * metadata annotations. | |
97 */ | |
98 Token getBeginToken(); | |
99 | |
100 /** | |
101 * Returns the last token for the source of this declaration. | |
102 */ | |
103 Token getEndToken(); | |
104 | |
105 /** | |
106 * Returns the script for the source of this declaration. | |
107 */ | |
108 Script getScript(); | |
109 | |
110 /// Returns the type mirror for [type] in the context of this declaration. | |
111 TypeMirror _getTypeMirror(DartType type, [FunctionSignature signature]) { | |
112 return mirrors._convertTypeToTypeMirror(type, signature); | |
113 } | |
114 | |
115 /// Returns a list of the declaration mirrors for [element]. | |
116 Iterable<Dart2JsMemberMirror> _getDeclarationMirrors(Element element) { | |
117 if (element.isSynthesized) { | |
118 return const <Dart2JsMemberMirror>[]; | |
119 } else if (element is VariableElement) { | |
120 return <Dart2JsMemberMirror>[new Dart2JsFieldMirror(this, element)]; | |
121 } else if (element is FunctionElement) { | |
122 return <Dart2JsMemberMirror>[new Dart2JsMethodMirror(this, element)]; | |
123 } else if (element is AbstractFieldElement) { | |
124 var members = <Dart2JsMemberMirror>[]; | |
125 AbstractFieldElement field = element; | |
126 if (field.getter != null) { | |
127 members.add(new Dart2JsMethodMirror(this, field.getter)); | |
128 } | |
129 if (field.setter != null) { | |
130 members.add(new Dart2JsMethodMirror(this, field.setter)); | |
131 } | |
132 return members; | |
133 } | |
134 mirrors.compiler.internalError( | |
135 "Unexpected member type $element ${element.kind}"); | |
136 } | |
137 | |
138 } | |
139 | |
140 abstract class Dart2JsElementMirror extends Dart2JsDeclarationMirror { | |
141 final Dart2JsMirrorSystem mirrors; | |
142 final Element _element; | |
143 List<InstanceMirror> _metadata; | |
144 | |
145 Dart2JsElementMirror(this.mirrors, this._element) { | |
146 assert (mirrors != null); | |
147 assert (_element != null); | |
148 } | |
149 | |
150 /** | |
151 * Returns the element to be used to determine the begin token of this | |
152 * declaration and the metadata associated with this declaration. | |
153 * | |
154 * This indirection is needed to use the [VariableListElement] as the location | |
155 * for type and metadata information on a [VariableElement]. | |
156 */ | |
157 Element get _beginElement => _element; | |
158 | |
159 String get _simpleNameString => _element.name; | |
160 | |
161 bool get isNameSynthetic => false; | |
162 | |
163 /** | |
164 * Computes the first token for this declaration using the begin token of the | |
165 * element node or element position as indicator. | |
166 */ | |
167 Token getBeginToken() { | |
168 // TODO(johnniwinther): Avoid calling [parseNode]. | |
169 Node node = _beginElement.parseNode(mirrors.compiler); | |
170 if (node == null) { | |
171 return _beginElement.position(); | |
172 } | |
173 return node.getBeginToken(); | |
174 } | |
175 | |
176 /** | |
177 * Computes the last token for this declaration using the end token of the | |
178 * element node or element position as indicator. | |
179 */ | |
180 Token getEndToken() { | |
181 // TODO(johnniwinther): Avoid calling [parseNode]. | |
182 Node node = _element.parseNode(mirrors.compiler); | |
183 if (node == null) { | |
184 return _element.position(); | |
185 } | |
186 return node.getEndToken(); | |
187 } | |
188 | |
189 /** | |
190 * Returns the first token for the source of this declaration, including | |
191 * metadata annotations. | |
192 */ | |
193 Token getFirstToken() { | |
194 if (!_beginElement.metadata.isEmpty) { | |
195 for (MetadataAnnotation metadata in _beginElement.metadata) { | |
196 if (metadata.beginToken != null) { | |
197 return metadata.beginToken; | |
198 } | |
199 } | |
200 } | |
201 return getBeginToken(); | |
202 } | |
203 | |
204 Script getScript() => _element.getCompilationUnit().script; | |
205 | |
206 SourceLocation get location { | |
207 Token beginToken = getFirstToken(); | |
208 Script script = getScript(); | |
209 SourceSpan span; | |
210 if (beginToken == null) { | |
211 span = new SourceSpan(script.uri, 0, 0); | |
212 } else { | |
213 Token endToken = getEndToken(); | |
214 span = mirrors.compiler.spanFromTokens(beginToken, endToken, script.uri); | |
215 } | |
216 return new Dart2JsSourceLocation(script, span); | |
217 } | |
218 | |
219 String toString() => _element.toString(); | |
220 | |
221 void _appendCommentTokens(Token commentToken) { | |
222 while (commentToken != null && commentToken.kind == COMMENT_TOKEN) { | |
223 _metadata.add(new Dart2JsCommentInstanceMirror( | |
224 mirrors, commentToken.value)); | |
225 commentToken = commentToken.next; | |
226 } | |
227 } | |
228 | |
229 List<InstanceMirror> get metadata { | |
230 if (_metadata == null) { | |
231 _metadata = <InstanceMirror>[]; | |
232 for (MetadataAnnotation metadata in _element.metadata) { | |
233 _appendCommentTokens(mirrors.compiler.commentMap[metadata.beginToken]); | |
234 metadata.ensureResolved(mirrors.compiler); | |
235 _metadata.add( | |
236 _convertConstantToInstanceMirror(mirrors, metadata.value)); | |
237 } | |
238 _appendCommentTokens(mirrors.compiler.commentMap[getBeginToken()]); | |
239 } | |
240 // TODO(johnniwinther): Return an unmodifiable list instead. | |
241 return new List<InstanceMirror>.from(_metadata); | |
242 } | |
243 | |
244 DeclarationMirror lookupInScope(String name) { | |
245 // TODO(11653): Support lookup of constructors. | |
246 Scope scope = _element.buildScope(); | |
247 Element result; | |
248 int index = name.indexOf('.'); | |
249 if (index != -1) { | |
250 // Lookup [: prefix.id :]. | |
251 String prefix = name.substring(0, index); | |
252 String id = name.substring(index+1); | |
253 result = scope.lookup(prefix); | |
254 if (result != null && result.isPrefix()) { | |
255 PrefixElement prefix = result; | |
256 result = prefix.lookupLocalMember(id); | |
257 } else { | |
258 result = null; | |
259 } | |
260 } else { | |
261 // Lookup [: id :]. | |
262 result = scope.lookup(name); | |
263 } | |
264 if (result == null || result.isPrefix()) return null; | |
265 return _convertElementToDeclarationMirror(mirrors, result); | |
266 } | |
267 | |
268 bool operator ==(var other) { | |
269 if (identical(this, other)) return true; | |
270 if (other == null) return false; | |
271 if (other is! Dart2JsElementMirror) return false; | |
272 return _element == other._element && | |
273 owner == other.owner; | |
274 } | |
275 | |
276 int get hashCode { | |
277 return 13 * _element.hashCode + 17 * owner.hashCode; | |
278 } | |
279 } | |
280 | |
281 //------------------------------------------------------------------------------ | |
282 // Mirror system implementation. | |
283 //------------------------------------------------------------------------------ | |
284 | |
285 class Dart2JsMirrorSystem extends MirrorSystem { | |
286 final Compiler compiler; | |
287 Map<Uri, Dart2JsLibraryMirror> _libraries; | |
288 Map<LibraryElement, Dart2JsLibraryMirror> _libraryMap; | |
289 | |
290 Dart2JsMirrorSystem(this.compiler) | |
291 : _libraryMap = new Map<LibraryElement, Dart2JsLibraryMirror>(); | |
292 | |
293 IsolateMirror get isolate => null; | |
294 | |
295 void _ensureLibraries() { | |
296 if (_libraries == null) { | |
297 _libraries = new Map<Uri, Dart2JsLibraryMirror>(); | |
298 compiler.libraries.forEach((_, LibraryElement v) { | |
299 var mirror = new Dart2JsLibraryMirror(mirrors, v); | |
300 _libraries[mirror.uri] = mirror; | |
301 _libraryMap[v] = mirror; | |
302 }); | |
303 } | |
304 } | |
305 | |
306 Map<Uri, LibraryMirror> get libraries { | |
307 _ensureLibraries(); | |
308 return new FilteredImmutableMap<Uri, LibraryMirror>(_libraries, | |
309 (library) => new bool.fromEnvironment("list_all_libraries") || | |
310 !library._element.isInternalLibrary); | |
311 } | |
312 | |
313 Dart2JsLibraryMirror _getLibrary(LibraryElement element) => | |
314 _libraryMap[element]; | |
315 | |
316 Dart2JsMirrorSystem get mirrors => this; | |
317 | |
318 TypeMirror get dynamicType => | |
319 _convertTypeToTypeMirror(compiler.types.dynamicType); | |
320 | |
321 TypeMirror get voidType => | |
322 _convertTypeToTypeMirror(compiler.types.voidType); | |
323 | |
324 TypeMirror _convertTypeToTypeMirror(DartType type, | |
325 [FunctionSignature signature]) { | |
326 assert(type != null); | |
327 if (type.treatAsDynamic) { | |
328 return new Dart2JsDynamicMirror(this, type); | |
329 } else if (type is InterfaceType) { | |
330 if (type.typeArguments.isEmpty) { | |
331 return _getTypeDeclarationMirror(type.element); | |
332 } else { | |
333 return new Dart2JsInterfaceTypeMirror(this, type); | |
334 } | |
335 } else if (type is TypeVariableType) { | |
336 return new Dart2JsTypeVariableMirror(this, type); | |
337 } else if (type is FunctionType) { | |
338 return new Dart2JsFunctionTypeMirror(this, type, signature); | |
339 } else if (type is VoidType) { | |
340 return new Dart2JsVoidMirror(this, type); | |
341 } else if (type is TypedefType) { | |
342 if (type.typeArguments.isEmpty) { | |
343 return _getTypeDeclarationMirror(type.element); | |
344 } else { | |
345 return new Dart2JsTypedefMirror(this, type); | |
346 } | |
347 } | |
348 compiler.internalError("Unexpected type $type of kind ${type.kind}"); | |
349 } | |
350 | |
351 DeclarationMirror _getTypeDeclarationMirror(Element element) { | |
352 if (element.isClass()) { | |
353 return new Dart2JsClassDeclarationMirror( | |
354 this, element.computeType(compiler)); | |
355 } else if (element.isTypedef()) { | |
356 return new Dart2JsTypedefDeclarationMirror(this, | |
357 element.computeType(compiler)); | |
358 } | |
359 } | |
360 } | |
361 | |
362 abstract class ContainerMixin { | |
363 Map<Symbol, DeclarationMirror> _declarations; | |
364 | |
365 void _ensureDeclarations() { | |
366 if (_declarations == null) { | |
367 _declarations = <Symbol, DeclarationMirror>{}; | |
368 _forEachElement((Element element) { | |
369 for (DeclarationMirror mirror in _getDeclarationMirrors(element)) { | |
370 assert(invariant(_element, | |
371 !_declarations.containsKey(mirror.simpleName), | |
372 message: "Declaration name '${nameOf(mirror)}' " | |
373 "is not unique in $_element.")); | |
374 _declarations[mirror.simpleName] = mirror; | |
375 } | |
376 }); | |
377 } | |
378 } | |
379 | |
380 Element get _element; | |
381 | |
382 void _forEachElement(f(Element element)); | |
383 | |
384 Iterable<Dart2JsMemberMirror> _getDeclarationMirrors(Element element); | |
385 | |
386 Map<Symbol, DeclarationMirror> get declarations { | |
387 _ensureDeclarations(); | |
388 return new ImmutableMapWrapper<Symbol, DeclarationMirror>(_declarations); | |
389 } | |
390 } | |
391 | |
392 /** | |
393 * Converts [element] into its corresponding [DeclarationMirror], if any. | |
394 * | |
395 * If [element] is an [AbstractFieldElement] the mirror for its getter is | |
396 * returned or, if not present, the mirror for its setter. | |
397 */ | |
398 DeclarationMirror _convertElementToDeclarationMirror(Dart2JsMirrorSystem system, | |
399 Element element) { | |
400 if (element.isTypeVariable()) { | |
401 return new Dart2JsTypeVariableMirror( | |
402 system, element.computeType(system.compiler)); | |
403 } | |
404 | |
405 Dart2JsLibraryMirror library = system._libraryMap[element.getLibrary()]; | |
406 if (element.isLibrary()) return library; | |
407 if (element.isTypedef()) { | |
408 return new Dart2JsTypedefMirror.fromLibrary( | |
409 library, element.computeType(system.compiler)); | |
410 } | |
411 | |
412 Dart2JsDeclarationMirror container = library; | |
413 if (element.getEnclosingClass() != null) { | |
414 container = system._getTypeDeclarationMirror(element.getEnclosingClass()); | |
415 } | |
416 if (element.isClass()) return container; | |
417 if (element.isParameter()) { | |
418 var method = _convertElementMethodToMethodMirror( | |
floitsch
2014/01/30 18:18:20
Why the change (removing the type "MethodMirror").
Johnni Winther
2014/02/03 08:22:48
Done.
| |
419 container, element.getOutermostEnclosingMemberOrTopLevel()); | |
420 // TODO(johnniwinther): Find the right info for [isOptional] and [isNamed]. | |
421 return new Dart2JsParameterMirror( | |
422 method, element, isOptional: false, isNamed: false); | |
423 } | |
424 Iterable<DeclarationMirror> members = | |
425 container._getDeclarationMirrors(element); | |
426 if (members.isEmpty) return null; | |
427 return members.first; | |
428 } | |
429 | |
430 /** | |
431 * Experimental API for accessing compilation units defined in a | |
432 * library. | |
433 */ | |
434 // TODO(ahe): Superclasses? Is this really a mirror? | |
435 class Dart2JsCompilationUnitMirror extends Dart2JsMirror | |
436 with ContainerMixin { | |
437 final Dart2JsLibraryMirror _library; | |
438 final CompilationUnitElement _element; | |
439 | |
440 Dart2JsCompilationUnitMirror(this._element, this._library); | |
441 | |
442 Dart2JsMirrorSystem get mirrors => _library.mirrors; | |
443 | |
444 // TODO(johnniwinther): make sure that these are returned in declaration | |
445 // order. | |
446 void _forEachElement(f(Element element)) => _element.forEachLocalMember(f); | |
447 | |
448 Iterable<DeclarationMirror> _getDeclarationMirrors(Element element) => | |
449 _library._getDeclarationMirrors(element); | |
450 | |
451 Uri get uri => _element.script.uri; | |
452 } | |
453 | |
454 /** | |
455 * Transitional class that allows access to features that have not yet | |
456 * made it to the mirror API. | |
457 * | |
458 * All API in this class is experimental. | |
459 */ | |
460 class BackDoor { | |
461 /// Return the compilation units comprising [library]. | |
462 static List<Mirror> compilationUnitsOf(Dart2JsLibraryMirror library) { | |
463 return library._element.compilationUnits.toList().map( | |
464 (cu) => new Dart2JsCompilationUnitMirror(cu, library)).toList(); | |
465 } | |
466 } | |
OLD | NEW |