Chromium Code Reviews| Index: pkg/analyzer_experimental/lib/src/services/runtime/coverage/models.dart |
| diff --git a/pkg/analyzer_experimental/lib/src/services/runtime/coverage/models.dart b/pkg/analyzer_experimental/lib/src/services/runtime/coverage/models.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..5507c9be258ac52c1ab71ff4f9e6650830cef425 |
| --- /dev/null |
| +++ b/pkg/analyzer_experimental/lib/src/services/runtime/coverage/models.dart |
| @@ -0,0 +1,167 @@ |
| +// Copyright (c) 2013, 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. |
| + |
| +/// A library with code coverage models. |
| +library runtime.coverage.model; |
| + |
| +import 'dart:collection' show SplayTreeMap; |
| + |
| +import 'package:analyzer_experimental/src/generated/source.dart' show Source, SourceRange; |
| +import 'package:analyzer_experimental/src/generated/ast.dart' show ASTNode; |
| + |
| +import 'utils.dart'; |
| + |
| + |
| +/// Contains information about the application. |
| +class AppInfo { |
| + final List<NodeInfo> nodeStack = new List<NodeInfo>(); |
|
Bob Nystrom
2013/06/17 21:30:12
final nodeStack = <NodeInfo>[];
Ditto for other f
scheglov
2013/06/17 22:30:57
For all fields or for final fields with initialize
Bob Nystrom
2013/06/17 22:44:41
Just ones with initializers. If they aren't initia
|
| + final List<UnitInfo> units = new List<UnitInfo>(); |
| + final Map<String, UnitInfo> pathToFile = new Map<String, UnitInfo>(); |
| + NodeInfo currentNode = null; |
| + int nextId = 0; |
| + |
| + void enterUnit(String path, String content) { |
| + var unit = new UnitInfo(this, path, content); |
| + units.add(unit); |
| + currentNode = unit; |
| + } |
| + |
| + void enter(String kind, String name) { |
| + nodeStack.add(currentNode); |
| + currentNode = new NodeInfo(this, currentNode, kind, name); |
| + } |
| + |
| + void leave() { |
| + currentNode = nodeStack.removeLast(); |
| + } |
| + |
| + int addNode(ASTNode node) { |
| + return currentNode.addNode(node); |
| + } |
| + |
| + void print(StringSink sink, Set<int> executedIds) { |
|
Bob Nystrom
2013/06/17 21:30:12
Calling a method "print" is probably asking for tr
scheglov
2013/06/17 22:30:57
Ah... yes.
Renamed to 'write'.
|
| + sink.writeln('{'); |
| + units.asMap().forEach((int i, UnitInfo unit) { |
| + if (i != 0) sink.writeln(','); |
| + unit.print(sink, executedIds, ' '); |
| + }); |
| + sink.writeln(); |
| + sink.writeln('}'); |
| + } |
| +} |
| + |
| +/// Information about some node - unit, class, method, function. |
| +class NodeInfo { |
| + final AppInfo appInfo; |
| + final NodeInfo parent; |
| + final String kind; |
| + final String name; |
| + final Map<int, SourceRange> idToRange = new SplayTreeMap<int, SourceRange>(); |
| + final List<NodeInfo> children = <NodeInfo> []; |
|
Bob Nystrom
2013/06/17 21:30:12
No space between > and [
scheglov
2013/06/17 22:30:57
Done.
|
| + |
| + NodeInfo(this.appInfo, this.parent, this.kind, this.name) { |
| + if (parent != null) { |
| + parent.children.add(this); |
| + } |
| + } |
| + |
| + int addNode(ASTNode node) { |
| + var id = appInfo.nextId++; |
| + var range = new SourceRange(node.offset, node.length); |
| + idToRange[id] = range; |
| + return id; |
| + } |
| + |
| + void print(StringSink sink, Set<int> executedIds, String prefix) { |
| + sink.writeln('$prefix"$name": {'); |
| + // Kind. |
| + sink.writeln('$prefix "kind": "$kind",'); |
| + // Print children. |
| + if (children.isNotEmpty) { |
|
Bob Nystrom
2013/06/17 21:30:12
Today I learned Iterable has isNotEmpty! :)
|
| + sink.writeln('$prefix "children": {'); |
| + children.asMap().forEach((int i, NodeInfo child) { |
|
scheglov
2013/06/17 22:30:57
Is it recommended to have type annotations for clo
Bob Nystrom
2013/06/17 22:44:41
The style guide says: "AVOID annotating types on f
scheglov
2013/06/18 06:11:04
Done.
|
| + if (i != 0) sink.writeln(','); |
| + children[i].print(sink, executedIds, '$prefix '); |
| + }); |
|
Bob Nystrom
2013/06/17 21:30:12
Clever! You could also try:
children.fold(null, (
scheglov
2013/06/17 22:30:57
More lines of code - I have to add "return" :-(
|
| + sink.writeln(); |
| + sink.writeln('$prefix }'); |
| + } |
| + // Print source and line ranges. |
| + if (children.isEmpty) { |
| + sink.write('${prefix} "ranges": ['); |
| + var rangePrinter = new RangePrinter(unit, sink, executedIds); |
| + idToRange.forEach(rangePrinter.handle); |
|
Bob Nystrom
2013/06/17 21:30:12
Nice.
|
| + rangePrinter.printRange(); |
| + sink.writeln(']'); |
| + } |
| + // Close this node. |
| + sink.write('$prefix}'); |
| + } |
| + |
| + UnitInfo get unit => parent.unit; |
| +} |
| + |
| +/// Helper for printing merged source/line intervals. |
| +class RangePrinter { |
| + final UnitInfo unit; |
| + final StringSink sink; |
| + final Set<int> executedIds; |
| + |
| + bool first = true; |
| + int startId = -1; |
| + int startOffset = -1; |
| + int endId = -1; |
| + int endOffset = -1; |
| + |
| + RangePrinter(this.unit, this.sink, this.executedIds); |
| + |
| + handle(int id, SourceRange range) { |
| + if (executedIds.contains(id)) { |
| + printRange(); |
| + } else { |
| + if (endId == id - 1) { |
| + endId = id; |
| + endOffset = range.end; |
| + } else { |
| + startId = id; |
| + endId = id; |
| + startOffset = range.offset; |
| + endOffset = range.end; |
| + } |
| + } |
| + } |
| + |
| + void printRange() { |
| + if (endId == -1) return; |
| + printSeparator(); |
| + var startLine = unit.getLine(startOffset); |
| + var endLine = unit.getLine(endOffset); |
| + sink.write('$startOffset,$endOffset,$startLine,$endLine'); |
| + startId = startOffset = startLine = -1; |
| + endId = endOffset = endLine = -1; |
| + } |
| + |
| + void printSeparator() { |
| + if (first) { |
| + first = false; |
| + } else { |
| + sink.write(', '); |
| + } |
| + } |
| +} |
| + |
| +/// Containts information about the single unit of the application. |
|
Bob Nystrom
2013/06/17 21:30:12
Containts -> Contains.
scheglov
2013/06/17 22:30:57
Done.
|
| +class UnitInfo extends NodeInfo { |
| + List<int> lineOffsets; |
| + |
| + UnitInfo(AppInfo appInfo, String path, String content) : super(appInfo, null, 'unit', path) { |
|
Bob Nystrom
2013/06/17 21:30:12
Move ": super..." to the next line.
scheglov
2013/06/17 22:30:57
Done.
|
| + lineOffsets = getLineOffsets(content); |
| + } |
| + |
| + UnitInfo get unit => this; |
| + |
| + int getLine(int offset) { |
| + return binarySearch(lineOffsets, (x) => x >= offset); |
| + } |
| +} |