Chromium Code Reviews| 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> { |
|
Siggi Cherem (dart-lang)
2015/10/15 23:36:08
should we add <T> to the recursive visitor as well
Harry Terkelsen
2015/10/15 23:59:55
The default implementation won't work for any T be
|
| 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) {} |
| } |