blob: cbeb35c730164c036cc25dd84e36e2215b4467ee [file] [log] [blame]
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// Converters and codecs for converting between Protobuf and [Info] classes.
import 'dart:convert';
import 'package:fixnum/fixnum.dart';
import 'info.dart';
import 'src/proto/info.pb.dart';
export 'src/proto/info.pb.dart';
class ProtoToAllInfoConverter extends Converter<AllInfoPB, AllInfo> {
AllInfo convert(AllInfoPB info) {
// TODO(lorenvs): Implement this conversion. It is unlikely to to be used
// by production code since the goal of the proto codec is to consume this
// information from other languages. However, it is useful for roundtrip
// testing, so we should support it.
throw new UnimplementedError('ProtoToAllInfoConverter is not implemented');
}
}
class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
AllInfoPB convert(AllInfo info) => _convertToAllInfoPB(info);
static DependencyInfoPB _convertToDependencyInfoPB(DependencyInfo info) {
return new DependencyInfoPB()
..targetId = info.target?.serializedId
..mask = info.mask;
}
static ParameterInfoPB _convertToParameterInfoPB(ParameterInfo info) {
return new ParameterInfoPB()
..name = info.name
..type = info.type
..declaredType = info.declaredType;
}
static MeasurementsPB _convertToMeasurementsPB(Measurements measurements) {
final proto = new MeasurementsPB();
if (measurements.uri != null) {
proto.sourceFile = measurements.uri.toString();
}
measurements.entries.forEach((metric, values) {
final entryProto = new MeasurementEntryPB()..name = metric.name;
for (final entry in values) {
entryProto.values.add(entry.begin);
entryProto.values.add(entry.end);
}
proto.entries.add(entryProto);
});
measurements.counters.forEach((metric, value) {
proto.counters.add(new MeasurementCounterPB()
..name = metric.name
..value = value);
});
return proto;
}
static LibraryInfoPB _convertToLibraryInfoPB(LibraryInfo info) {
final proto = new LibraryInfoPB()..uri = info.uri.toString();
proto.childrenIds
.addAll(info.topLevelFunctions.map((func) => func.serializedId));
proto.childrenIds
.addAll(info.topLevelVariables.map((field) => field.serializedId));
proto.childrenIds.addAll(info.classes.map((clazz) => clazz.serializedId));
proto.childrenIds.addAll(info.typedefs.map((def) => def.serializedId));
return proto;
}
static ClassInfoPB _convertToClassInfoPB(ClassInfo info) {
final proto = new ClassInfoPB()..isAbstract = info.isAbstract;
proto.childrenIds.addAll(info.functions.map((func) => func.serializedId));
proto.childrenIds.addAll(info.fields.map((field) => field.serializedId));
return proto;
}
static FunctionModifiersPB _convertToFunctionModifiers(
FunctionModifiers modifiers) {
return new FunctionModifiersPB()
..isStatic = modifiers.isStatic
..isConst = modifiers.isConst
..isFactory = modifiers.isFactory
..isExternal = modifiers.isExternal;
}
static FunctionInfoPB _convertToFunctionInfoPB(FunctionInfo info) {
final proto = new FunctionInfoPB()
..functionModifiers = _convertToFunctionModifiers(info.modifiers)
..inlinedCount = info.inlinedCount ?? 0;
if (info.returnType != null) {
proto.returnType = info.returnType;
}
if (info.inferredReturnType != null) {
proto.inferredReturnType = info.inferredReturnType;
}
if (info.code != null) {
proto.code = info.code;
}
if (info.sideEffects != null) {
proto.sideEffects = info.sideEffects;
}
if (info.measurements != null) {
proto.measurements = _convertToMeasurementsPB(info.measurements);
}
proto.childrenIds
.addAll(info.closures.map(((closure) => closure.serializedId)));
proto.parameters.addAll(info.parameters.map(_convertToParameterInfoPB));
return proto;
}
static FieldInfoPB _convertToFieldInfoPB(FieldInfo info) {
final proto = new FieldInfoPB()
..type = info.type
..inferredType = info.inferredType
..isConst = info.isConst;
if (info.code != null) {
proto.code = info.code;
}
if (info.initializer != null) {
proto.initializerId = info.initializer.serializedId;
}
proto.childrenIds
.addAll(info.closures.map((closure) => closure.serializedId));
return proto;
}
static ConstantInfoPB _convertToConstantInfoPB(ConstantInfo info) {
return new ConstantInfoPB()..code = info.code;
}
static OutputUnitInfoPB _convertToOutputUnitInfoPB(OutputUnitInfo info) {
final proto = new OutputUnitInfoPB();
proto.imports.addAll(info.imports.where((import) => import != null));
return proto;
}
static TypedefInfoPB _convertToTypedefInfoPB(TypedefInfo info) {
return new TypedefInfoPB()..type = info.type;
}
static ClosureInfoPB _convertToClosureInfoPB(ClosureInfo info) {
return new ClosureInfoPB()..functionId = info.function.serializedId;
}
static InfoPB _convertToInfoPB(Info info) {
final proto = new InfoPB()
..id = info.id
..serializedId = info.serializedId
..size = info.size;
if (info.name != null) {
proto.name = info.name;
}
if (info.parent != null) {
proto.parentId = info.parent.serializedId;
}
if (info.coverageId != null) {
proto.coverageId = info.coverageId;
}
if (info is BasicInfo && info.outputUnit != null) {
// TODO(lorenvs): Similar to the JSON codec, omit this for the default
// output unit. At the moment, there is no easy way to identify which
// output unit is the default on [OutputUnitInfo].
proto.outputUnitId = info.outputUnit.serializedId;
}
if (info is CodeInfo) {
proto.uses.addAll(info.uses.map(_convertToDependencyInfoPB));
}
if (info is LibraryInfo) {
proto.libraryInfo = _convertToLibraryInfoPB(info);
} else if (info is ClassInfo) {
proto.classInfo = _convertToClassInfoPB(info);
} else if (info is FunctionInfo) {
proto.functionInfo = _convertToFunctionInfoPB(info);
} else if (info is FieldInfo) {
proto.fieldInfo = _convertToFieldInfoPB(info);
} else if (info is ConstantInfo) {
proto.constantInfo = _convertToConstantInfoPB(info);
} else if (info is OutputUnitInfo) {
proto.outputUnitInfo = _convertToOutputUnitInfoPB(info);
} else if (info is TypedefInfo) {
proto.typedefInfo = _convertToTypedefInfoPB(info);
} else if (info is ClosureInfo) {
proto.closureInfo = _convertToClosureInfoPB(info);
}
return proto;
}
static ProgramInfoPB _convertToProgramInfoPB(ProgramInfo info) {
return new ProgramInfoPB()
..entrypointId = info.entrypoint.serializedId
..size = info.size
..dart2jsVersion = info.dart2jsVersion
..compilationMoment =
new Int64(info.compilationMoment.microsecondsSinceEpoch)
..compilationDuration = new Int64(info.compilationDuration.inMicroseconds)
..toProtoDuration = new Int64(info.toJsonDuration.inMicroseconds)
..dumpInfoDuration = new Int64(info.dumpInfoDuration.inMicroseconds)
..noSuchMethodEnabled = info.noSuchMethodEnabled ?? false
..isRuntimeTypeUsed = info.isRuntimeTypeUsed ?? false
..isIsolateUsed = info.isIsolateInUse ?? false
..isFunctionApplyUsed = info.isFunctionApplyUsed ?? false
..isMirrorsUsed = info.isMirrorsUsed ?? false
..minified = info.minified ?? false;
}
static Iterable<AllInfoPB_AllInfosEntry>
_convertToAllInfosEntries<T extends Info>(Iterable<T> infos) sync* {
for (final info in infos) {
final infoProto = _convertToInfoPB(info);
final entry = new AllInfoPB_AllInfosEntry()
..key = infoProto.serializedId
..value = infoProto;
yield entry;
}
}
static LibraryDeferredImportsPB _convertToLibraryDeferredImportsPB(
String libraryUri, Map<String, dynamic> fields) {
final proto = new LibraryDeferredImportsPB()
..libraryUri = libraryUri
..libraryName = fields['name'] ?? '<unnamed>';
Map<String, List<String>> imports = fields['imports'];
imports.forEach((prefix, files) {
final import = new DeferredImportPB()..prefix = prefix;
import.files.addAll(files);
proto.imports.add(import);
});
return proto;
}
static AllInfoPB _convertToAllInfoPB(AllInfo info) {
final proto = new AllInfoPB()
..program = _convertToProgramInfoPB(info.program);
proto.allInfos.addAll(_convertToAllInfosEntries(info.libraries));
proto.allInfos.addAll(_convertToAllInfosEntries(info.classes));
proto.allInfos.addAll(_convertToAllInfosEntries(info.functions));
proto.allInfos.addAll(_convertToAllInfosEntries(info.fields));
proto.allInfos.addAll(_convertToAllInfosEntries(info.constants));
proto.allInfos.addAll(_convertToAllInfosEntries(info.outputUnits));
proto.allInfos.addAll(_convertToAllInfosEntries(info.typedefs));
proto.allInfos.addAll(_convertToAllInfosEntries(info.closures));
info.deferredFiles?.forEach((libraryUri, fields) {
proto.deferredImports
.add(_convertToLibraryDeferredImportsPB(libraryUri, fields));
});
return proto;
}
}
/// A codec for converting [AllInfo] to a protobuf format.
///
/// This codec is still experimental, and will likely crash on certain output
/// from dart2js.
class AllInfoProtoCodec extends Codec<AllInfo, AllInfoPB> {
final Converter<AllInfo, AllInfoPB> encoder = new AllInfoToProtoConverter();
final Converter<AllInfoPB, AllInfo> decoder = new ProtoToAllInfoConverter();
}