blob: b8f5dd7de2634b7a829edeabf1dcf8eaaa05af31 [file] [log] [blame]
// Copyright (c) 2016, 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.
/**
* This file contains code for collecting statistics about the use of fields in
* a summary file.
*/
library analyzer.tool.summary.stats;
import 'dart:io';
import 'dart:mirrors';
import 'package:analyzer/src/summary/base.dart';
import 'package:analyzer/src/summary/idl.dart';
main(List<String> args) {
if (args.length != 1) {
_printUsage();
exitCode = 1;
return;
}
String inputFilePath = args[0];
// Read the input.
PackageBundle bundle =
new PackageBundle.fromBuffer(new File(inputFilePath).readAsBytesSync());
// Compute and output stats.
Stats stats = new Stats();
stats.record(bundle);
stats.dump();
}
/**
* The name of the stats tool.
*/
const String BINARY_NAME = "stats";
/**
* Print information about how to use the stats tool.
*/
void _printUsage() {
print('Usage: $BINARY_NAME input_file_path');
}
/**
* An instance of [Stats] keeps track of statistics about the use of fields in
* summary objects.
*/
class Stats {
/**
* Map from type to field name to a count of how often the field is used.
*/
Map<Type, Map<String, int>> counts = <Type, Map<String, int>>{};
/**
* Print out statistics gathered so far.
*/
void dump() {
counts.forEach((Type type, Map<String, int> typeCounts) {
print(type);
List<String> keys = typeCounts.keys.toList();
keys.sort((String a, String b) => typeCounts[b].compareTo(typeCounts[a]));
for (String key in keys) {
print(' $key: ${typeCounts[key]}');
}
print('');
});
}
/**
* Record statistics for [obj] and all objects it refers to.
*/
void record(SummaryClass obj) {
Map<String, int> typeCounts =
counts.putIfAbsent(obj.runtimeType, () => <String, int>{});
obj.toMap().forEach((String key, Object value) {
if (value == null ||
value == 0 ||
value == false ||
value == '' ||
value is List && value.isEmpty ||
reflect(value).type.isEnum && (value as dynamic).index == 0) {
return;
}
if (!typeCounts.containsKey(key)) {
typeCounts[key] = 0;
}
typeCounts[key]++;
if (value is SummaryClass) {
record(value);
} else if (value is List) {
value.forEach((Object element) {
if (element is SummaryClass) {
record(element);
}
});
}
});
}
}