OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, 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 /// Data collected by the dump-info task. | |
6 library compiler.src.lib.info; | |
7 | |
8 // Note: this file intentionally doesn't import anything from the compiler. That | |
9 // should make it easier for tools to depend on this library. The idea is that | |
10 // by using this library, tools can consume the information in the same way it | |
11 // is produced by the compiler. | |
12 // TODO(sigmund): make this a proper public API (export this explicitly at the | |
13 // lib folder level.) | |
14 | |
15 /// Common interface to many pieces of information generated by the compiler. | |
16 abstract class Info { | |
17 /// An identifier for the kind of information. | |
18 InfoKind get kind; | |
19 | |
20 /// Name of the element associated with this info. | |
21 String name; | |
22 | |
23 /// An id to uniquely identify this info among infos of the same [kind]. | |
24 int get id; | |
25 | |
26 /// A globally unique id combining [kind] and [id] together. | |
27 String get serializedId; | |
28 | |
29 /// Id used by the compiler when instrumenting code for code coverage. | |
30 // TODO(sigmund): It would be nice if we could use the same id for | |
31 // serialization and for coverage. Could we unify them? | |
32 String coverageId; | |
33 | |
34 /// Bytes used in the generated code for the corresponding element. | |
35 int size; | |
36 | |
37 /// Info of the enclosing element. | |
38 Info parent; | |
39 | |
40 /// Serializes the information into a JSON format. | |
41 // TODO(sigmund): refactor and put toJson outside the class, so we can have 2 | |
42 // different serializer/deserializers at once. | |
43 Map toJson(); | |
44 | |
45 void accept(InfoVisitor visitor); | |
46 } | |
47 | |
48 /// Common information used for most kind of elements. | |
49 // TODO(sigmund): add more: | |
50 // - inputSize: bytes used in the Dart source program | |
51 abstract class BasicInfo implements Info { | |
52 final InfoKind kind; | |
53 final int id; | |
54 String coverageId; | |
55 int size; | |
56 Info parent; | |
57 | |
58 String get serializedId => '${_kindToString(kind)}/$id'; | |
59 | |
60 String name; | |
61 | |
62 /// If using deferred libraries, where the element associated with this info | |
63 /// is generated. | |
64 OutputUnitInfo outputUnit; | |
65 | |
66 BasicInfo(this.kind, this.id, this.name, this.outputUnit, this.size, | |
67 this.coverageId); | |
68 | |
69 BasicInfo._fromId(String serializedId) | |
70 : kind = _kindFromSerializedId(serializedId), | |
71 id = _idFromSerializedId(serializedId); | |
72 | |
73 Map toJson() { | |
74 var res = { | |
75 'id': serializedId, | |
76 'kind': _kindToString(kind), | |
77 'name': name, | |
78 'size': size, | |
79 }; | |
80 // TODO(sigmund): Omit this also when outputUnit.id == 0 (most code is in | |
81 // the main output unit by default). | |
82 if (outputUnit != null) res['outputUnit'] = outputUnit.serializedId; | |
83 if (coverageId != null) res['coverageId'] = coverageId; | |
84 if (parent != null) res['parent'] = parent.serializedId; | |
85 return res; | |
86 } | |
87 | |
88 String toString() => '$serializedId $name [$size]'; | |
89 } | |
90 | |
91 /// Info associated with elements containing executable code (like fields and | |
92 /// methods) | |
93 abstract class CodeInfo implements Info { | |
94 /// How does this function or field depend on others. | |
95 final List<DependencyInfo> uses = <DependencyInfo>[]; | |
96 } | |
97 | |
98 | |
99 /// The entire information produced while compiling a program. | |
100 class AllInfo { | |
101 /// Summary information about the program. | |
102 ProgramInfo program; | |
103 | |
104 /// Information about each library processed by the compiler. | |
105 List<LibraryInfo> libraries = <LibraryInfo>[]; | |
106 | |
107 /// Information about each function (includes methods and getters in any | |
108 /// library) | |
109 List<FunctionInfo> functions = <FunctionInfo>[]; | |
110 | |
111 /// Information about type defs in the program. | |
112 List<TypedefInfo> typedefs = <TypedefInfo>[]; | |
113 | |
114 /// Information about each class (in any library). | |
115 List<ClassInfo> classes = <ClassInfo>[]; | |
116 | |
117 /// Information about fields (in any class). | |
118 List<FieldInfo> fields = <FieldInfo>[]; | |
119 | |
120 /// Information about output units (should be just one entry if not using | |
121 /// deferred loading). | |
122 List<OutputUnitInfo> outputUnits = <OutputUnitInfo>[]; | |
123 | |
124 /// Details about all deferred imports and what files would be loaded when the | |
125 /// import is resolved. | |
126 // TODO(sigmund): use a different format for dump-info. This currently emits | |
127 // the same map that is created for the `--deferred-map` flag. | |
128 Map<String, Map<String, dynamic>> deferredFiles; | |
129 | |
130 /// A new representation of dependencies form one info to another. An entry in | |
131 /// this map indicates that an Info depends on another (e.g. a function | |
132 /// invokes another). Please note that the data in this field might not be | |
133 /// accurate yet (this is work in progress). | |
134 Map<Info, List<Info>> dependencies = {}; | |
135 | |
136 /// Major version indicating breaking changes in the format. A new version | |
137 /// means that an old deserialization algorithm will not work with the new | |
138 /// format. | |
139 final int version = 3; | |
140 | |
141 /// Minor version indicating non-breaking changes in the format. A change in | |
142 /// this version number means that the json parsing in this library from a | |
143 /// previous will continue to work after the change. This is typically | |
144 /// increased when adding new entries to the file format. | |
145 // Note: the dump-info.viewer app was written using a json parser version 3.2. | |
146 final int minorVersion = 5; | |
147 | |
148 AllInfo(); | |
149 | |
150 static AllInfo parseFromJson(Map map) => new _ParseHelper().parseAll(map); | |
151 | |
152 Map _listAsJsonMap(List<Info> list) { | |
153 var map = <String, Map>{}; | |
154 for (var info in list) { | |
155 map['${info.id}'] = info.toJson(); | |
156 } | |
157 return map; | |
158 } | |
159 | |
160 Map _extractHoldingInfo() { | |
161 var map = <String, List>{}; | |
162 void helper(CodeInfo info) { | |
163 if (info.uses.isEmpty) return; | |
164 map[info.serializedId] = info.uses.map((u) => u.toJson()).toList(); | |
165 } | |
166 functions.forEach(helper); | |
167 fields.forEach(helper); | |
168 return map; | |
169 } | |
170 | |
171 Map _extractDependencies() { | |
172 var map = <String, List>{}; | |
173 dependencies.forEach((k, v) { | |
174 map[k.serializedId] = v.map((i) => i.serializedId).toList(); | |
175 }); | |
176 return map; | |
177 } | |
178 | |
179 Map toJson() => { | |
180 'elements': { | |
181 'library': _listAsJsonMap(libraries), | |
182 'class': _listAsJsonMap(classes), | |
183 'function': _listAsJsonMap(functions), | |
184 'typedef': _listAsJsonMap(typedefs), | |
185 'field': _listAsJsonMap(fields), | |
186 }, | |
187 'holding': _extractHoldingInfo(), | |
188 'dependencies': _extractDependencies(), | |
189 'outputUnits': outputUnits.map((u) => u.toJson()).toList(), | |
190 'dump_version': version, | |
191 'deferredFiles': deferredFiles, | |
192 'dump_minor_version': '$minorVersion', | |
193 // TODO(sigmund): change viewer to accept an int? | |
194 'program': program.toJson(), | |
195 }; | |
196 | |
197 void accept(InfoVisitor visitor) => visitor.visitAll(this); | |
198 } | |
199 | |
200 class ProgramInfo { | |
201 int size; | |
202 String dart2jsVersion; | |
203 DateTime compilationMoment; | |
204 Duration compilationDuration; | |
205 // TODO(sigmund): use Duration. | |
206 int toJsonDuration; | |
207 int dumpInfoDuration; | |
208 bool noSuchMethodEnabled; | |
209 bool minified; | |
210 | |
211 ProgramInfo( | |
212 {this.size, | |
213 this.dart2jsVersion, | |
214 this.compilationMoment, | |
215 this.compilationDuration, | |
216 this.toJsonDuration, | |
217 this.dumpInfoDuration, | |
218 this.noSuchMethodEnabled, | |
219 this.minified}); | |
220 | |
221 Map toJson() => { | |
222 'size': size, | |
223 'dart2jsVersion': dart2jsVersion, | |
224 'compilationMoment': '$compilationMoment', | |
225 'compilationDuration': '${compilationDuration}', | |
226 'toJsonDuration': toJsonDuration, | |
227 'dumpInfoDuration': '$dumpInfoDuration', | |
228 'noSuchMethodEnabled': noSuchMethodEnabled, | |
229 'minified': minified, | |
230 }; | |
231 | |
232 void accept(InfoVisitor visitor) => visitor.visitProgram(this); | |
233 } | |
234 | |
235 // TODO(sigmund): add unit tests. | |
236 class _ParseHelper { | |
237 Map<String, Info> registry = {}; | |
238 | |
239 AllInfo parseAll(Map json) { | |
240 var result = new AllInfo(); | |
241 var elements = json['elements']; | |
242 result.libraries.addAll(elements['library'].values.map(parseLibrary)); | |
243 result.classes.addAll(elements['class'].values.map(parseClass)); | |
244 result.functions.addAll(elements['function'].values.map(parseFunction)); | |
245 result.fields.addAll(elements['field'].values.map(parseField)); | |
246 result.typedefs.addAll(elements['typedef'].values.map(parseTypedef)); | |
247 | |
248 var idMap = {}; | |
249 for (var f in result.functions) { | |
250 idMap[f.serializedId] = f; | |
251 } | |
252 for (var f in result.fields) { | |
253 idMap[f.serializedId] = f; | |
254 } | |
255 | |
256 json['holding'].forEach((k, deps) { | |
257 var src = idMap[k]; | |
258 assert (src != null); | |
259 for (var dep in deps) { | |
260 var target = idMap[dep['id']]; | |
261 assert (target != null); | |
262 src.uses.add(new DependencyInfo(target, dep['mask'])); | |
263 } | |
264 }); | |
265 | |
266 json['dependencies']?.forEach((k, deps) { | |
267 result.dependencies[idMap[k]] = deps.map((d) => idMap[d]).toList(); | |
268 }); | |
269 | |
270 result.program = parseProgram(json['program']); | |
271 // todo: version, etc | |
272 return result; | |
273 } | |
274 | |
275 LibraryInfo parseLibrary(Map json) { | |
276 LibraryInfo result = parseId(json['id']); | |
277 result..name = json['name'] | |
278 ..uri = Uri.parse(json['canonicalUri']) | |
279 ..outputUnit = parseId(json['outputUnit']) | |
280 ..size = json['size']; | |
281 for (var child in json['children'].map(parseId)) { | |
282 if (child is FunctionInfo) { | |
283 result.topLevelFunctions.add(child); | |
284 } else if (child is FieldInfo) { | |
285 result.topLevelVariables.add(child); | |
286 } else if (child is ClassInfo) { | |
287 result.classes.add(child); | |
288 } else { | |
289 assert(child is TypedefInfo); | |
290 result.typedefs.add(child); | |
291 } | |
292 } | |
293 return result; | |
294 } | |
295 | |
296 ClassInfo parseClass(Map json) { | |
297 ClassInfo result = parseId(json['id']); | |
298 result..name = json['name'] | |
299 ..parent = parseId(json['parent']) | |
300 ..outputUnit = parseId(json['outputUnit']) | |
301 ..size = json['size'] | |
302 ..isAbstract = json['modifiers']['abstract'] == true; | |
303 assert(result is ClassInfo); | |
304 for (var child in json['children'].map(parseId)) { | |
305 if (child is FunctionInfo) { | |
306 result.functions.add(child); | |
307 } else { | |
308 assert(child is FieldInfo); | |
309 result.fields.add(child); | |
310 } | |
311 } | |
312 return result; | |
313 } | |
314 | |
315 FieldInfo parseField(Map json) { | |
316 FieldInfo result = parseId(json['id']); | |
317 return result..name = json['name'] | |
318 ..parent = parseId(json['parent']) | |
319 ..coverageId = json['coverageId'] | |
320 ..outputUnit = parseId(json['outputUnit']) | |
321 ..size = json['size'] | |
322 ..type = json['type'] | |
323 ..inferredType = json['inferredType'] | |
324 ..code = json['code'] | |
325 ..closures = json['children'].map(parseId).toList(); | |
326 } | |
327 | |
328 TypedefInfo parseTypedef(Map json) { | |
329 TypedefInfo result = parseId(json['id']); | |
330 return result..name = json['name'] | |
331 ..parent = parseId(json['parent']) | |
332 ..type = json['type'] | |
333 ..size = 0; | |
334 } | |
335 | |
336 ProgramInfo parseProgram(Map json) => | |
337 new ProgramInfo()..size = json['size']; | |
338 | |
339 FunctionInfo parseFunction(Map json) { | |
340 FunctionInfo result = parseId(json['id']); | |
341 return result..name = json['name'] | |
342 ..parent = parseId(json['parent']) | |
343 ..coverageId = json['coverageId'] | |
344 ..outputUnit = parseId(json['outputUnit']) | |
345 ..size = json['size'] | |
346 ..type = json['type'] | |
347 ..returnType = json['returnType'] | |
348 ..inferredReturnType = json['inferredReturnType'] | |
349 ..parameters = json['parameters'].map(parseParameter).toList() | |
350 ..code = json['code'] | |
351 ..sideEffects = json['sideEffects'] | |
352 ..modifiers = parseModifiers(json['modifiers']) | |
353 ..closures = json['children'].map(parseId).toList(); | |
354 } | |
355 | |
356 ParameterInfo parseParameter(Map json) => | |
357 new ParameterInfo(json['name'], json['type'], json['declaredType']); | |
358 | |
359 FunctionModifiers parseModifiers(Map<String, bool> json) { | |
360 return new FunctionModifiers( | |
361 isStatic: json['static'] == true, | |
362 isConst: json['const'] == true, | |
363 isFactory: json['factory'] == true, | |
364 isExternal: json['external'] == true); | |
365 } | |
366 | |
367 Info parseId(String serializedId) => registry.putIfAbsent(serializedId, () { | |
368 if (serializedId == null) { | |
369 return null; | |
370 } else if (serializedId.startsWith('function/')) { | |
371 return new FunctionInfo._(serializedId); | |
372 } else if (serializedId.startsWith('library/')) { | |
373 return new LibraryInfo._(serializedId); | |
374 } else if (serializedId.startsWith('class/')) { | |
375 return new ClassInfo._(serializedId); | |
376 } else if (serializedId.startsWith('field/')) { | |
377 return new FieldInfo._(serializedId); | |
378 } else if (serializedId.startsWith('typedef/')) { | |
379 return new TypedefInfo._(serializedId); | |
380 } else if (serializedId.startsWith('outputUnit/')) { | |
381 return new OutputUnitInfo._(serializedId); | |
382 } | |
383 assert(false); | |
384 }); | |
385 } | |
386 | |
387 /// Info associated with a library element. | |
388 class LibraryInfo extends BasicInfo { | |
389 /// Canonical uri that identifies the library. | |
390 Uri uri; | |
391 | |
392 /// Top level functions defined within the library. | |
393 final List<FunctionInfo> topLevelFunctions = <FunctionInfo>[]; | |
394 | |
395 /// Top level fields defined within the library. | |
396 final List<FieldInfo> topLevelVariables = <FieldInfo>[]; | |
397 | |
398 /// Classes defined within the library. | |
399 final List<ClassInfo> classes = <ClassInfo>[]; | |
400 | |
401 /// Typedefs defined within the library. | |
402 final List<TypedefInfo> typedefs = <TypedefInfo>[]; | |
403 | |
404 static int _id = 0; | |
405 | |
406 /// Whether there is any information recorded for this library. | |
407 bool get isEmpty => | |
408 topLevelFunctions.isEmpty && topLevelVariables.isEmpty && classes.isEmpty; | |
409 | |
410 LibraryInfo(String name, this.uri, OutputUnitInfo outputUnit, int size) | |
411 : super(InfoKind.library, _id++, name, outputUnit, size, null); | |
412 | |
413 LibraryInfo._(String serializedId) : super._fromId(serializedId); | |
414 | |
415 Map toJson() => super.toJson() | |
416 ..addAll({ | |
417 'children': [] | |
418 ..addAll(topLevelFunctions.map((f) => f.serializedId)) | |
419 ..addAll(topLevelVariables.map((v) => v.serializedId)) | |
420 ..addAll(classes.map((c) => c.serializedId)) | |
421 ..addAll(typedefs.map((t) => t.serializedId)), | |
422 'canonicalUri': '$uri', | |
423 }); | |
424 | |
425 void accept(InfoVisitor visitor) => visitor.visitLibrary(this); | |
426 } | |
427 | |
428 /// Information about an output unit. Normally there is just one for the entire | |
429 /// program unless the application uses deferred imports, in which case there | |
430 /// would be an additional output unit per deferred chunk. | |
431 class OutputUnitInfo extends BasicInfo { | |
432 static int _ids = 0; | |
433 OutputUnitInfo(String name, int size) | |
434 : super(InfoKind.outputUnit, _ids++, name, null, size, null); | |
435 | |
436 OutputUnitInfo._(String serializedId) : super._fromId(serializedId); | |
437 | |
438 void accept(InfoVisitor visitor) => visitor.visitOutput(this); | |
439 } | |
440 | |
441 /// Information about a class element. | |
442 class ClassInfo extends BasicInfo { | |
443 /// Whether the class is abstract. | |
444 bool isAbstract; | |
445 | |
446 // TODO(sigmund): split static vs instance vs closures | |
447 /// Functions (static or instance) defined in the class. | |
448 final List<FunctionInfo> functions = <FunctionInfo>[]; | |
449 | |
450 /// Fields defined in the class. | |
451 // TODO(sigmund): currently appears to only be populated with instance fields, | |
452 // but this should be fixed. | |
453 final List<FieldInfo> fields = <FieldInfo>[]; | |
454 static int _ids = 0; | |
455 | |
456 ClassInfo( | |
457 {String name, this.isAbstract, OutputUnitInfo outputUnit, int size: 0}) | |
458 : super(InfoKind.clazz, _ids++, name, outputUnit, size, null); | |
459 | |
460 ClassInfo._(String serializedId) : super._fromId(serializedId); | |
461 | |
462 Map toJson() => super.toJson() | |
463 ..addAll({ | |
464 // TODO(sigmund): change format, include only when abstract is true. | |
465 'modifiers': {'abstract': isAbstract}, | |
466 'children': [] | |
467 ..addAll(fields.map((f) => f.serializedId)) | |
468 ..addAll(functions.map((m) => m.serializedId)) | |
469 }); | |
470 | |
471 void accept(InfoVisitor visitor) => visitor.visitClass(this); | |
472 } | |
473 | |
474 /// Information about a field element. | |
475 class FieldInfo extends BasicInfo with CodeInfo { | |
476 /// The type of the field. | |
477 String type; | |
478 | |
479 /// The type inferred by dart2js's whole program analysis | |
480 String inferredType; | |
481 | |
482 /// Nested closures seen in the field initializer. | |
483 List<FunctionInfo> closures; | |
484 | |
485 /// The actual generated code for the field. | |
486 String code; | |
487 | |
488 static int _ids = 0; | |
489 FieldInfo( | |
490 {String name, | |
491 String coverageId, | |
492 int size: 0, | |
493 this.type, | |
494 this.inferredType, | |
495 this.closures, | |
496 this.code, | |
497 OutputUnitInfo outputUnit}) | |
498 : super(InfoKind.field, _ids++, name, outputUnit, size, coverageId); | |
499 | |
500 FieldInfo._(String serializedId) : super._fromId(serializedId); | |
501 | |
502 Map toJson() => super.toJson() | |
503 ..addAll({ | |
504 'children': closures.map((i) => i.serializedId).toList(), | |
505 'inferredType': inferredType, | |
506 'code': code, | |
507 'type': type, | |
508 }); | |
509 | |
510 void accept(InfoVisitor visitor) => visitor.visitField(this); | |
511 } | |
512 | |
513 /// Information about a typedef declaration. | |
514 class TypedefInfo extends BasicInfo { | |
515 /// The declared type. | |
516 String type; | |
517 | |
518 static int _ids = 0; | |
519 TypedefInfo(String name, this.type, OutputUnitInfo outputUnit) | |
520 : super(InfoKind.typedef, _ids++, name, outputUnit, 0, null); | |
521 | |
522 TypedefInfo._(String serializedId) : super._fromId(serializedId); | |
523 | |
524 Map toJson() => super.toJson()..['type'] = '$type'; | |
525 | |
526 void accept(InfoVisitor visitor) => visitor.visitTypedef(this); | |
527 } | |
528 | |
529 /// Information about a function or method. | |
530 class FunctionInfo extends BasicInfo with CodeInfo { | |
531 static const int TOP_LEVEL_FUNCTION_KIND = 0; | |
532 static const int CLOSURE_FUNCTION_KIND = 1; | |
533 static const int METHOD_FUNCTION_KIND = 2; | |
534 static const int CONSTRUCTOR_FUNCTION_KIND = 3; | |
535 static int _ids = 0; | |
536 | |
537 /// Kind of function (top-level function, closure, method, or constructor). | |
538 int functionKind; | |
539 | |
540 /// Modifiers applied to this function. | |
541 FunctionModifiers modifiers; | |
542 | |
543 /// Nested closures that appear within the body of this function. | |
544 List<FunctionInfo> closures; | |
545 | |
546 /// The type of this function. | |
547 String type; | |
548 | |
549 /// The declared return type. | |
550 String returnType; | |
551 | |
552 /// The inferred return type. | |
553 String inferredReturnType; | |
554 | |
555 /// Name and type information for each parameter. | |
556 List<ParameterInfo> parameters; | |
557 | |
558 /// Side-effects. | |
559 // TODO(sigmund): serialize more precisely, not just a string representation. | |
560 String sideEffects; | |
561 | |
562 /// How many function calls were inlined into this function. | |
563 int inlinedCount; | |
564 | |
565 /// The actual generated code. | |
566 String code; | |
567 | |
568 FunctionInfo( | |
569 {String name, | |
570 String coverageId, | |
571 OutputUnitInfo outputUnit, | |
572 int size: 0, | |
573 this.functionKind, | |
574 this.modifiers, | |
575 this.closures, | |
576 this.type, | |
577 this.returnType, | |
578 this.inferredReturnType, | |
579 this.parameters, | |
580 this.sideEffects, | |
581 this.inlinedCount, | |
582 this.code}) | |
583 : super(InfoKind.function, _ids++, name, outputUnit, size, coverageId); | |
584 | |
585 FunctionInfo._(String serializedId) : super._fromId(serializedId); | |
586 | |
587 Map toJson() => super.toJson() | |
588 ..addAll({ | |
589 'children': closures.map((i) => i.serializedId).toList(), | |
590 'modifiers': modifiers.toJson(), | |
591 'returnType': returnType, | |
592 'inferredReturnType': inferredReturnType, | |
593 'parameters': parameters.map((p) => p.toJson()).toList(), | |
594 'sideEffects': sideEffects, | |
595 'inlinedCount': inlinedCount, | |
596 'code': code, | |
597 'type': type, | |
598 // Note: version 3.2 of dump-info serializes `uses` in a section called | |
599 // `holding` at the top-level. | |
600 }); | |
601 | |
602 void accept(InfoVisitor visitor) => visitor.visitFunction(this); | |
603 } | |
604 | |
605 /// Information about how a dependency is used. | |
606 class DependencyInfo { | |
607 /// The dependency, either a FunctionInfo or FieldInfo. | |
608 final Info target; | |
609 | |
610 /// Either a selector mask indicating how this is used, or 'inlined'. | |
611 // TODO(sigmund): split mask into an enum or something more precise to really | |
612 // describe the dependencies in detail. | |
613 final String mask; | |
614 | |
615 DependencyInfo(this.target, this.mask); | |
616 | |
617 Map toJson() => {'id': target.serializedId, 'mask': mask}; | |
618 } | |
619 | |
620 /// Name and type information about a function parameter. | |
621 class ParameterInfo { | |
622 final String name; | |
623 final String type; | |
624 final String declaredType; | |
625 | |
626 ParameterInfo(this.name, this.type, this.declaredType); | |
627 | |
628 Map toJson() => {'name': name, 'type': type, 'declaredType': declaredType}; | |
629 } | |
630 | |
631 /// Modifiers that may apply to methods. | |
632 class FunctionModifiers { | |
633 final bool isStatic; | |
634 final bool isConst; | |
635 final bool isFactory; | |
636 final bool isExternal; | |
637 | |
638 FunctionModifiers( | |
639 {this.isStatic: false, | |
640 this.isConst: false, | |
641 this.isFactory: false, | |
642 this.isExternal: false}); | |
643 | |
644 // TODO(sigmund): exclude false values (requires bumping the format version): | |
645 // Map toJson() { | |
646 // var res = <String, bool>{}; | |
647 // if (isStatic) res['static'] = true; | |
648 // if (isConst) res['const'] = true; | |
649 // if (isFactory) res['factory'] = true; | |
650 // if (isExternal) res['external'] = true; | |
651 // return res; | |
652 // } | |
653 Map toJson() => { | |
654 'static': isStatic, | |
655 'const': isConst, | |
656 'factory': isFactory, | |
657 'external': isExternal, | |
658 }; | |
659 } | |
660 | |
661 /// Possible values of the `kind` field in the serialied infos. | |
662 enum InfoKind { | |
663 library, | |
664 clazz, | |
665 function, | |
666 field, | |
667 outputUnit, | |
668 typedef, | |
669 } | |
670 | |
671 String _kindToString(InfoKind kind) { | |
672 switch(kind) { | |
673 case InfoKind.library: return 'library'; | |
674 case InfoKind.clazz: return 'class'; | |
675 case InfoKind.function: return 'function'; | |
676 case InfoKind.field: return 'field'; | |
677 case InfoKind.outputUnit: return 'outputUnit'; | |
678 case InfoKind.typedef: return 'typedef'; | |
679 default: return null; | |
680 } | |
681 } | |
682 | |
683 int _idFromSerializedId(String serializedId) => | |
684 int.parse(serializedId.substring(serializedId.indexOf('/') + 1)); | |
685 | |
686 InfoKind _kindFromSerializedId(String serializedId) => | |
687 _kindFromString(serializedId.substring(0, serializedId.indexOf('/'))); | |
688 | |
689 InfoKind _kindFromString(String kind) { | |
690 switch(kind) { | |
691 case 'library': return InfoKind.library; | |
692 case 'class': return InfoKind.clazz; | |
693 case 'function': return InfoKind.function; | |
694 case 'field': return InfoKind.field; | |
695 case 'outputUnit': return InfoKind.outputUnit; | |
696 case 'typedef': return InfoKind.typedef; | |
697 default: return null; | |
698 } | |
699 } | |
700 | |
701 /// A simple visitor for information produced by the dart2js compiler. | |
702 class InfoVisitor { | |
703 visitAll(AllInfo info) {} | |
704 visitProgram(ProgramInfo info) {} | |
705 visitLibrary(LibraryInfo info) {} | |
706 visitClass(ClassInfo info) {} | |
707 visitField(FieldInfo info) {} | |
708 visitFunction(FunctionInfo info) {} | |
709 visitTypedef(TypedefInfo info) {} | |
710 visitOutput(OutputUnitInfo info) {} | |
711 } | |
712 | |
713 /// A visitor that recursively walks each portion of the program. Because the | |
714 /// info representation is redundant, this visitor only walks the structure of | |
715 /// the program and skips some redundant links. For example, even though | |
716 /// visitAll contains references to functions, this visitor only recurses to | |
717 /// visit libraries, then from each library we visit functions and classes, and | |
718 /// so on. | |
719 class RecursiveInfoVisitor extends InfoVisitor { | |
720 visitAll(AllInfo info) { | |
721 // Note: we don't visit functions, fields, classes, and typedefs because | |
722 // they are reachable from the library info. | |
723 info.libraries.forEach(visitLibrary); | |
724 } | |
725 | |
726 visitLibrary(LibraryInfo info) { | |
727 info.topLevelFunctions.forEach(visitFunction); | |
728 info.topLevelVariables.forEach(visitField); | |
729 info.classes.forEach(visitClass); | |
730 info.typedefs.forEach(visitTypedef); | |
731 } | |
732 | |
733 visitClass(ClassInfo info) { | |
734 info.functions.forEach(visitFunction); | |
735 info.fields.forEach(visitField); | |
736 } | |
737 | |
738 visitField(FieldInfo info) { | |
739 info.closures.forEach(visitFunction); | |
740 } | |
741 | |
742 visitFunction(FunctionInfo info) { | |
743 info.closures.forEach(visitFunction); | |
744 } | |
745 } | |
OLD | NEW |