Index: lib/info.dart |
diff --git a/lib/info.dart b/lib/info.dart |
index 27e1fe77a4cf40b1b6138a3116909f7b295d891a..5e79a70e973fd0fbf084ecb364fd985dd61b0635 100644 |
--- a/lib/info.dart |
+++ b/lib/info.dart |
@@ -5,9 +5,13 @@ |
/// Data produced by dart2js when run with the `--dump-info` flag. |
library dart2js_info.info; |
+import 'dart:convert'; |
+ |
import 'src/measurements.dart'; |
export 'src/measurements.dart'; |
+part 'json_info_codec.dart'; |
+ |
/// Common interface to many pieces of information generated by the dart2js |
/// compiler that are directly associated with an element (compilation unit, |
/// library, class, function, or field). |
@@ -35,12 +39,7 @@ abstract class Info { |
/// Info of the enclosing element. |
Info parent; |
- /// Serializes the information into a JSON format. |
- // TODO(sigmund): refactor and put toJson outside the class, so we can have 2 |
- // different serializer/deserializers at once. |
- Map toJson(); |
- |
- void accept(InfoVisitor visitor); |
+ dynamic accept(InfoVisitor visitor); |
} |
/// Common information used for most kind of elements. |
@@ -68,21 +67,6 @@ abstract class BasicInfo implements Info { |
: kind = _kindFromSerializedId(serializedId), |
id = _idFromSerializedId(serializedId); |
- Map toJson() { |
- var res = { |
- 'id': serializedId, |
- 'kind': _kindToString(kind), |
- 'name': name, |
- 'size': size, |
- }; |
- // TODO(sigmund): Omit this also when outputUnit.id == 0 (most code is in |
- // the main output unit by default). |
- if (outputUnit != null) res['outputUnit'] = outputUnit.serializedId; |
- if (coverageId != null) res['coverageId'] = coverageId; |
- if (parent != null) res['parent'] = parent.serializedId; |
- return res; |
- } |
- |
String toString() => '$serializedId $name [$size]'; |
} |
@@ -150,57 +134,7 @@ class AllInfo { |
AllInfo(); |
- // TODO(het): Remove this when we have an external InfoCodec, see |
- // https://github.com/dart-lang/dart2js_info/issues/4 |
- factory AllInfo.fromJson(Map json) => new _ParseHelper().parseAll(json); |
- |
- Map _listAsJsonMap(List<Info> list) { |
- var map = <String, Map>{}; |
- for (var info in list) { |
- map['${info.id}'] = info.toJson(); |
- } |
- return map; |
- } |
- |
- Map _extractHoldingInfo() { |
- var map = <String, List>{}; |
- void helper(CodeInfo info) { |
- if (info.uses.isEmpty) return; |
- map[info.serializedId] = info.uses.map((u) => u.toJson()).toList(); |
- } |
- functions.forEach(helper); |
- fields.forEach(helper); |
- return map; |
- } |
- |
- Map _extractDependencies() { |
- var map = <String, List>{}; |
- dependencies.forEach((k, v) { |
- map[k.serializedId] = v.map((i) => i.serializedId).toList(); |
- }); |
- return map; |
- } |
- |
- Map toJson() => { |
- 'elements': { |
- 'library': _listAsJsonMap(libraries), |
- 'class': _listAsJsonMap(classes), |
- 'function': _listAsJsonMap(functions), |
- 'typedef': _listAsJsonMap(typedefs), |
- 'field': _listAsJsonMap(fields), |
- 'constant': _listAsJsonMap(constants), |
- }, |
- 'holding': _extractHoldingInfo(), |
- 'dependencies': _extractDependencies(), |
- 'outputUnits': outputUnits.map((u) => u.toJson()).toList(), |
- 'dump_version': version, |
- 'deferredFiles': deferredFiles, |
- 'dump_minor_version': '$minorVersion', |
- // TODO(sigmund): change viewer to accept an int? |
- 'program': program.toJson(), |
- }; |
- |
- void accept(InfoVisitor visitor) => visitor.visitAll(this); |
+ dynamic accept(InfoVisitor visitor) => visitor.visitAll(this); |
} |
class ProgramInfo { |
@@ -226,216 +160,7 @@ class ProgramInfo { |
this.noSuchMethodEnabled, |
this.minified}); |
- Map toJson() => { |
- 'entrypoint': entrypoint.serializedId, |
- 'size': size, |
- 'dart2jsVersion': dart2jsVersion, |
- 'compilationMoment': '$compilationMoment', |
- 'compilationDuration': '${compilationDuration}', |
- 'toJsonDuration': toJsonDuration, |
- 'dumpInfoDuration': '$dumpInfoDuration', |
- 'noSuchMethodEnabled': noSuchMethodEnabled, |
- 'minified': minified, |
- }; |
- |
- void accept(InfoVisitor visitor) => visitor.visitProgram(this); |
-} |
- |
-// TODO(sigmund): add unit tests. |
-class _ParseHelper { |
- Map<String, Info> registry = {}; |
- |
- AllInfo parseAll(Map json) { |
- var result = new AllInfo(); |
- var elements = json['elements']; |
- result.libraries.addAll(elements['library'].values.map(parseLibrary)); |
- result.classes.addAll(elements['class'].values.map(parseClass)); |
- result.functions.addAll(elements['function'].values.map(parseFunction)); |
- result.fields.addAll(elements['field'].values.map(parseField)); |
- result.typedefs.addAll(elements['typedef'].values.map(parseTypedef)); |
- |
- // TODO(sigmund): remove null check on next breaking version |
- var constants = elements['constant']; |
- if (constants != null) { |
- result.constants.addAll(constants.values.map(parseConstant)); |
- } |
- |
- var idMap = {}; |
- for (var f in result.functions) { |
- idMap[f.serializedId] = f; |
- } |
- for (var f in result.fields) { |
- idMap[f.serializedId] = f; |
- } |
- |
- json['holding'].forEach((k, deps) { |
- var src = idMap[k]; |
- assert(src != null); |
- for (var dep in deps) { |
- var target = idMap[dep['id']]; |
- assert(target != null); |
- src.uses.add(new DependencyInfo(target, dep['mask'])); |
- } |
- }); |
- |
- json['dependencies']?.forEach((k, deps) { |
- result.dependencies[idMap[k]] = deps.map((d) => idMap[d]).toList(); |
- }); |
- |
- result.program = parseProgram(json['program']); |
- // todo: version, etc |
- return result; |
- } |
- |
- LibraryInfo parseLibrary(Map json) { |
- LibraryInfo result = parseId(json['id']); |
- result |
- ..name = json['name'] |
- ..uri = Uri.parse(json['canonicalUri']) |
- ..outputUnit = parseId(json['outputUnit']) |
- ..size = json['size']; |
- for (var child in json['children'].map(parseId)) { |
- if (child is FunctionInfo) { |
- result.topLevelFunctions.add(child); |
- } else if (child is FieldInfo) { |
- result.topLevelVariables.add(child); |
- } else if (child is ClassInfo) { |
- result.classes.add(child); |
- } else { |
- assert(child is TypedefInfo); |
- result.typedefs.add(child); |
- } |
- } |
- return result; |
- } |
- |
- ClassInfo parseClass(Map json) { |
- ClassInfo result = parseId(json['id']); |
- result |
- ..name = json['name'] |
- ..parent = parseId(json['parent']) |
- ..outputUnit = parseId(json['outputUnit']) |
- ..size = json['size'] |
- ..isAbstract = json['modifiers']['abstract'] == true; |
- assert(result is ClassInfo); |
- for (var child in json['children'].map(parseId)) { |
- if (child is FunctionInfo) { |
- result.functions.add(child); |
- } else { |
- assert(child is FieldInfo); |
- result.fields.add(child); |
- } |
- } |
- return result; |
- } |
- |
- FieldInfo parseField(Map json) { |
- FieldInfo result = parseId(json['id']); |
- return result |
- ..name = json['name'] |
- ..parent = parseId(json['parent']) |
- ..coverageId = json['coverageId'] |
- ..outputUnit = parseId(json['outputUnit']) |
- ..size = json['size'] |
- ..type = json['type'] |
- ..inferredType = json['inferredType'] |
- ..code = json['code'] |
- ..isConst = json['const'] ?? false |
- ..initializer = parseId(json['initializer']) |
- ..closures = json['children'].map(parseId).toList(); |
- } |
- |
- ConstantInfo parseConstant(Map json) { |
- ConstantInfo result = parseId(json['id']); |
- return result |
- ..code = json['code'] |
- ..size = json['size']; |
- } |
- |
- TypedefInfo parseTypedef(Map json) { |
- TypedefInfo result = parseId(json['id']); |
- return result |
- ..name = json['name'] |
- ..parent = parseId(json['parent']) |
- ..type = json['type'] |
- ..size = 0; |
- } |
- |
- ProgramInfo parseProgram(Map json) => new ProgramInfo() |
- ..size = json['size'] |
- ..entrypoint = parseId(json['entrypoint']); |
- |
- FunctionInfo parseFunction(Map json) { |
- FunctionInfo result = parseId(json['id']); |
- return result |
- ..name = json['name'] |
- ..parent = parseId(json['parent']) |
- ..coverageId = json['coverageId'] |
- ..outputUnit = parseId(json['outputUnit']) |
- ..size = json['size'] |
- ..type = json['type'] |
- ..returnType = json['returnType'] |
- ..inferredReturnType = json['inferredReturnType'] |
- ..parameters = json['parameters'].map(parseParameter).toList() |
- ..code = json['code'] |
- ..sideEffects = json['sideEffects'] |
- ..modifiers = parseModifiers(json['modifiers']) |
- ..closures = json['children'].map(parseId).toList() |
- ..measurements = parseMeasurements(json['measurements']); |
- } |
- |
- ParameterInfo parseParameter(Map json) => |
- new ParameterInfo(json['name'], json['type'], json['declaredType']); |
- |
- Measurements parseMeasurements(Map json) { |
- if (json == null) return null; |
- var uri = json['sourceFile']; |
- var res = new Measurements(uri == null ? null : Uri.parse(uri)); |
- for (var key in json.keys) { |
- var value = json[key]; |
- if (value == null) continue; |
- if (key == 'entries') { |
- value.forEach((metricName, entries) { |
- var metric = Metric.fromJson(metricName); |
- for (var i = 0; i < entries.length; i += 2) { |
- res.record(metric, entries[i], entries[i + 1]); |
- } |
- }); |
- } else { |
- res.counters[Metric.fromJson(key)] = value; |
- } |
- } |
- return res; |
- } |
- |
- FunctionModifiers parseModifiers(Map<String, bool> json) { |
- return new FunctionModifiers( |
- isStatic: json['static'] == true, |
- isConst: json['const'] == true, |
- isFactory: json['factory'] == true, |
- isExternal: json['external'] == true); |
- } |
- |
- Info parseId(String serializedId) => registry.putIfAbsent(serializedId, () { |
- if (serializedId == null) { |
- return null; |
- } else if (serializedId.startsWith('function/')) { |
- return new FunctionInfo._(serializedId); |
- } else if (serializedId.startsWith('library/')) { |
- return new LibraryInfo._(serializedId); |
- } else if (serializedId.startsWith('class/')) { |
- return new ClassInfo._(serializedId); |
- } else if (serializedId.startsWith('field/')) { |
- return new FieldInfo._(serializedId); |
- } else if (serializedId.startsWith('constant/')) { |
- return new ConstantInfo._(serializedId); |
- } else if (serializedId.startsWith('typedef/')) { |
- return new TypedefInfo._(serializedId); |
- } else if (serializedId.startsWith('outputUnit/')) { |
- return new OutputUnitInfo._(serializedId); |
- } |
- assert(false); |
- }); |
+ dynamic accept(InfoVisitor visitor) => visitor.visitProgram(this); |
} |
/// Info associated with a library element. |
@@ -470,17 +195,7 @@ class LibraryInfo extends BasicInfo { |
LibraryInfo._(String serializedId) : super._fromId(serializedId); |
- Map toJson() => super.toJson() |
- ..addAll({ |
- 'children': [] |
- ..addAll(topLevelFunctions.map((f) => f.serializedId)) |
- ..addAll(topLevelVariables.map((v) => v.serializedId)) |
- ..addAll(classes.map((c) => c.serializedId)) |
- ..addAll(typedefs.map((t) => t.serializedId)), |
- 'canonicalUri': '$uri', |
- }); |
- |
- void accept(InfoVisitor visitor) => visitor.visitLibrary(this); |
+ dynamic accept(InfoVisitor visitor) => visitor.visitLibrary(this); |
} |
/// Information about an output unit. Normally there is just one for the entire |
@@ -493,7 +208,7 @@ class OutputUnitInfo extends BasicInfo { |
OutputUnitInfo._(String serializedId) : super._fromId(serializedId); |
- void accept(InfoVisitor visitor) => visitor.visitOutput(this); |
+ dynamic accept(InfoVisitor visitor) => visitor.visitOutput(this); |
} |
/// Information about a class element. |
@@ -517,16 +232,7 @@ class ClassInfo extends BasicInfo { |
ClassInfo._(String serializedId) : super._fromId(serializedId); |
- Map toJson() => super.toJson() |
- ..addAll({ |
- // TODO(sigmund): change format, include only when abstract is true. |
- 'modifiers': {'abstract': isAbstract}, |
- 'children': [] |
- ..addAll(fields.map((f) => f.serializedId)) |
- ..addAll(functions.map((m) => m.serializedId)) |
- }); |
- |
- void accept(InfoVisitor visitor) => visitor.visitClass(this); |
+ dynamic accept(InfoVisitor visitor) => visitor.visitClass(this); |
} |
/// Information about a constant value. |
@@ -542,9 +248,7 @@ class ConstantInfo extends BasicInfo { |
ConstantInfo._(String serializedId) : super._fromId(serializedId); |
- Map toJson() => super.toJson()..addAll({'code': code}); |
- |
- void accept(InfoVisitor visitor) => visitor.visitConstant(this); |
+ dynamic accept(InfoVisitor visitor) => visitor.visitConstant(this); |
} |
/// Information about a field element. |
@@ -582,22 +286,7 @@ class FieldInfo extends BasicInfo with CodeInfo { |
FieldInfo._(String serializedId) : super._fromId(serializedId); |
- Map toJson() { |
- var result = super.toJson() |
- ..addAll({ |
- 'children': closures.map((i) => i.serializedId).toList(), |
- 'inferredType': inferredType, |
- 'code': code, |
- 'type': type, |
- }); |
- if (isConst) { |
- result['const'] = true; |
- if (initializer != null) result['initializer'] = initializer.serializedId; |
- } |
- return result; |
- } |
- |
- void accept(InfoVisitor visitor) => visitor.visitField(this); |
+ dynamic accept(InfoVisitor visitor) => visitor.visitField(this); |
} |
/// Information about a typedef declaration. |
@@ -611,9 +300,7 @@ class TypedefInfo extends BasicInfo { |
TypedefInfo._(String serializedId) : super._fromId(serializedId); |
- Map toJson() => super.toJson()..['type'] = '$type'; |
- |
- void accept(InfoVisitor visitor) => visitor.visitTypedef(this); |
+ dynamic accept(InfoVisitor visitor) => visitor.visitTypedef(this); |
} |
/// Information about a function or method. |
@@ -678,23 +365,7 @@ class FunctionInfo extends BasicInfo with CodeInfo { |
FunctionInfo._(String serializedId) : super._fromId(serializedId); |
- Map toJson() => super.toJson() |
- ..addAll({ |
- 'children': closures.map((i) => i.serializedId).toList(), |
- 'modifiers': modifiers.toJson(), |
- 'returnType': returnType, |
- 'inferredReturnType': inferredReturnType, |
- 'parameters': parameters.map((p) => p.toJson()).toList(), |
- 'sideEffects': sideEffects, |
- 'inlinedCount': inlinedCount, |
- 'code': code, |
- 'type': type, |
- 'measurements': measurements?.toJson(), |
- // Note: version 3.2 of dump-info serializes `uses` in a section called |
- // `holding` at the top-level. |
- }); |
- |
- void accept(InfoVisitor visitor) => visitor.visitFunction(this); |
+ dynamic accept(InfoVisitor visitor) => visitor.visitFunction(this); |
} |
/// Information about how a dependency is used. |
@@ -708,8 +379,6 @@ class DependencyInfo { |
final String mask; |
DependencyInfo(this.target, this.mask); |
- |
- Map toJson() => {'id': target.serializedId, 'mask': mask}; |
} |
/// Name and type information about a function parameter. |
@@ -719,8 +388,6 @@ class ParameterInfo { |
final String declaredType; |
ParameterInfo(this.name, this.type, this.declaredType); |
- |
- Map toJson() => {'name': name, 'type': type, 'declaredType': declaredType}; |
} |
/// Modifiers that may apply to methods. |
@@ -735,22 +402,6 @@ class FunctionModifiers { |
this.isConst: false, |
this.isFactory: false, |
this.isExternal: false}); |
- |
- // TODO(sigmund): exclude false values (requires bumping the format version): |
- // Map toJson() { |
- // var res = <String, bool>{}; |
- // if (isStatic) res['static'] = true; |
- // if (isConst) res['const'] = true; |
- // if (isFactory) res['factory'] = true; |
- // if (isExternal) res['external'] = true; |
- // return res; |
- // } |
- Map toJson() => { |
- 'static': isStatic, |
- 'const': isConst, |
- 'factory': isFactory, |
- 'external': isExternal, |
- }; |
} |
/// Possible values of the `kind` field in the serialied infos. |
@@ -813,16 +464,16 @@ InfoKind _kindFromString(String kind) { |
} |
/// A simple visitor for information produced by the dart2js compiler. |
-class InfoVisitor { |
- visitAll(AllInfo info) {} |
- visitProgram(ProgramInfo info) {} |
- visitLibrary(LibraryInfo info) {} |
- visitClass(ClassInfo info) {} |
- visitField(FieldInfo info) {} |
- visitConstant(ConstantInfo info) {} |
- visitFunction(FunctionInfo info) {} |
- visitTypedef(TypedefInfo info) {} |
- visitOutput(OutputUnitInfo info) {} |
+abstract class InfoVisitor<T> { |
+ T visitAll(AllInfo info); |
+ T visitProgram(ProgramInfo info); |
+ T visitLibrary(LibraryInfo info); |
+ T visitClass(ClassInfo info); |
+ T visitField(FieldInfo info); |
+ T visitConstant(ConstantInfo info); |
+ T visitFunction(FunctionInfo info); |
+ T visitTypedef(TypedefInfo info); |
+ T visitOutput(OutputUnitInfo info); |
} |
/// A visitor that recursively walks each portion of the program. Because the |
@@ -831,7 +482,7 @@ class InfoVisitor { |
/// visitAll contains references to functions, this visitor only recurses to |
/// visit libraries, then from each library we visit functions and classes, and |
/// so on. |
-class RecursiveInfoVisitor extends InfoVisitor { |
+class RecursiveInfoVisitor extends InfoVisitor<Null> { |
visitAll(AllInfo info) { |
// Note: we don't visit functions, fields, classes, and typedefs because |
// they are reachable from the library info. |
@@ -839,6 +490,8 @@ class RecursiveInfoVisitor extends InfoVisitor { |
info.constants.forEach(visitConstant); |
} |
+ visitProgram(ProgramInfo info) {} |
+ |
visitLibrary(LibraryInfo info) { |
info.topLevelFunctions.forEach(visitFunction); |
info.topLevelVariables.forEach(visitField); |
@@ -855,7 +508,12 @@ class RecursiveInfoVisitor extends InfoVisitor { |
info.closures.forEach(visitFunction); |
} |
+ visitConstant(ConstantInfo info) {} |
+ |
visitFunction(FunctionInfo info) { |
info.closures.forEach(visitFunction); |
} |
+ |
+ visitTypedef(TypedefInfo info) {} |
+ visitOutput(OutputUnitInfo info) {} |
} |