| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /// Source information system mapping that attempts a semantic mapping between | 5 /// Source information system mapping that attempts a semantic mapping between |
| 6 /// offsets of JavaScript code points to offsets of Dart code points. | 6 /// offsets of JavaScript code points to offsets of Dart code points. |
| 7 | 7 |
| 8 library dart2js.source_information.position; | 8 library dart2js.source_information.position; |
| 9 | 9 |
| 10 import '../common.dart'; | 10 import '../common.dart'; |
| 11 import '../elements/elements.dart' show | 11 import '../elements/elements.dart' show AstElement, FieldElement, LocalElement; |
| 12 AstElement, | |
| 13 FieldElement, | |
| 14 LocalElement; | |
| 15 import '../js/js.dart' as js; | 12 import '../js/js.dart' as js; |
| 16 import '../js/js_source_mapping.dart'; | 13 import '../js/js_source_mapping.dart'; |
| 17 import '../js/js_debug.dart'; | 14 import '../js/js_debug.dart'; |
| 18 import '../tree/tree.dart' show | 15 import '../tree/tree.dart' show FunctionExpression, Node, Send; |
| 19 FunctionExpression, | |
| 20 Node, | |
| 21 Send; | |
| 22 | 16 |
| 23 import 'code_output.dart' show | 17 import 'code_output.dart' show CodeBuffer; |
| 24 CodeBuffer; | |
| 25 import 'source_file.dart'; | 18 import 'source_file.dart'; |
| 26 import 'source_information.dart'; | 19 import 'source_information.dart'; |
| 27 | 20 |
| 28 /// [SourceInformation] that consists of an offset position into the source | 21 /// [SourceInformation] that consists of an offset position into the source |
| 29 /// code. | 22 /// code. |
| 30 class PositionSourceInformation extends SourceInformation { | 23 class PositionSourceInformation extends SourceInformation { |
| 31 @override | 24 @override |
| 32 final SourceLocation startPosition; | 25 final SourceLocation startPosition; |
| 33 | 26 |
| 34 @override | 27 @override |
| 35 final SourceLocation closingPosition; | 28 final SourceLocation closingPosition; |
| 36 | 29 |
| 37 PositionSourceInformation(this.startPosition, | 30 PositionSourceInformation(this.startPosition, [this.closingPosition]); |
| 38 [this.closingPosition]); | |
| 39 | 31 |
| 40 @override | 32 @override |
| 41 List<SourceLocation> get sourceLocations { | 33 List<SourceLocation> get sourceLocations { |
| 42 List<SourceLocation> list = <SourceLocation>[]; | 34 List<SourceLocation> list = <SourceLocation>[]; |
| 43 if (startPosition != null) { | 35 if (startPosition != null) { |
| 44 list.add(startPosition); | 36 list.add(startPosition); |
| 45 } | 37 } |
| 46 if (closingPosition != null) { | 38 if (closingPosition != null) { |
| 47 list.add(closingPosition); | 39 list.add(closingPosition); |
| 48 } | 40 } |
| 49 return list; | 41 return list; |
| 50 } | 42 } |
| 51 | 43 |
| 52 @override | 44 @override |
| 53 SourceSpan get sourceSpan { | 45 SourceSpan get sourceSpan { |
| 54 SourceLocation location = | 46 SourceLocation location = |
| 55 startPosition != null ? startPosition : closingPosition; | 47 startPosition != null ? startPosition : closingPosition; |
| 56 Uri uri = location.sourceUri; | 48 Uri uri = location.sourceUri; |
| 57 int offset = location.offset; | 49 int offset = location.offset; |
| 58 return new SourceSpan(uri, offset, offset); | 50 return new SourceSpan(uri, offset, offset); |
| 59 } | 51 } |
| 60 | 52 |
| 61 int get hashCode { | 53 int get hashCode { |
| 62 return 0x7FFFFFFF & | 54 return 0x7FFFFFFF & |
| 63 (startPosition.hashCode * 17 + closingPosition.hashCode * 19); | 55 (startPosition.hashCode * 17 + closingPosition.hashCode * 19); |
| 64 } | 56 } |
| 65 | 57 |
| 66 bool operator ==(other) { | 58 bool operator ==(other) { |
| 67 if (identical(this, other)) return true; | 59 if (identical(this, other)) return true; |
| 68 if (other is! PositionSourceInformation) return false; | 60 if (other is! PositionSourceInformation) return false; |
| 69 return startPosition == other.startPosition && | 61 return startPosition == other.startPosition && |
| 70 closingPosition == other.closingPosition; | 62 closingPosition == other.closingPosition; |
| 71 } | 63 } |
| 72 | 64 |
| 73 /// Create a textual representation of the source information using [uriText] | 65 /// Create a textual representation of the source information using [uriText] |
| 74 /// as the Uri representation. | 66 /// as the Uri representation. |
| 75 String _computeText(String uriText) { | 67 String _computeText(String uriText) { |
| 76 StringBuffer sb = new StringBuffer(); | 68 StringBuffer sb = new StringBuffer(); |
| 77 sb.write('$uriText:'); | 69 sb.write('$uriText:'); |
| 78 // Use 1-based line/column info to match usual dart tool output. | 70 // Use 1-based line/column info to match usual dart tool output. |
| 79 if (startPosition != null) { | 71 if (startPosition != null) { |
| 80 sb.write('[${startPosition.line + 1},' | 72 sb.write('[${startPosition.line + 1},' |
| 81 '${startPosition.column + 1}]'); | 73 '${startPosition.column + 1}]'); |
| 82 } | 74 } |
| 83 if (closingPosition != null) { | 75 if (closingPosition != null) { |
| 84 sb.write('-[${closingPosition.line + 1},' | 76 sb.write('-[${closingPosition.line + 1},' |
| 85 '${closingPosition.column + 1}]'); | 77 '${closingPosition.column + 1}]'); |
| 86 } | 78 } |
| 87 return sb.toString(); | 79 return sb.toString(); |
| 88 } | 80 } |
| 89 | 81 |
| 90 String get shortText { | 82 String get shortText { |
| 91 if (startPosition != null) { | 83 if (startPosition != null) { |
| 92 return _computeText(startPosition.sourceUri.pathSegments.last); | 84 return _computeText(startPosition.sourceUri.pathSegments.last); |
| 93 } else { | 85 } else { |
| 94 return _computeText(closingPosition.sourceUri.pathSegments.last); | 86 return _computeText(closingPosition.sourceUri.pathSegments.last); |
| 95 } | 87 } |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 final String name; | 143 final String name; |
| 152 final AstElement element; | 144 final AstElement element; |
| 153 | 145 |
| 154 PositionSourceInformationBuilder(AstElement element) | 146 PositionSourceInformationBuilder(AstElement element) |
| 155 : this.element = element, | 147 : this.element = element, |
| 156 sourceFile = element.implementation.compilationUnit.script.file, | 148 sourceFile = element.implementation.compilationUnit.script.file, |
| 157 name = computeElementNameForSourceMaps(element); | 149 name = computeElementNameForSourceMaps(element); |
| 158 | 150 |
| 159 SourceInformation buildDeclaration(AstElement element) { | 151 SourceInformation buildDeclaration(AstElement element) { |
| 160 if (element.isSynthesized) { | 152 if (element.isSynthesized) { |
| 161 return new PositionSourceInformation( | 153 return new PositionSourceInformation(new OffsetSourceLocation( |
| 162 new OffsetSourceLocation( | 154 sourceFile, element.position.charOffset, name)); |
| 163 sourceFile, element.position.charOffset, name)); | |
| 164 } else { | 155 } else { |
| 165 return new PositionSourceInformation( | 156 return new PositionSourceInformation( |
| 166 new OffsetSourceLocation(sourceFile, | 157 new OffsetSourceLocation(sourceFile, |
| 167 element.resolvedAst.node.getBeginToken().charOffset, name), | 158 element.resolvedAst.node.getBeginToken().charOffset, name), |
| 168 new OffsetSourceLocation(sourceFile, | 159 new OffsetSourceLocation(sourceFile, |
| 169 element.resolvedAst.node.getEndToken().charOffset, name)); | 160 element.resolvedAst.node.getEndToken().charOffset, name)); |
| 170 } | 161 } |
| 171 } | 162 } |
| 172 | 163 |
| 173 /// Builds a source information object pointing the start position of [node]. | 164 /// Builds a source information object pointing the start position of [node]. |
| 174 SourceInformation buildBegin(Node node) { | 165 SourceInformation buildBegin(Node node) { |
| 175 return new PositionSourceInformation(new OffsetSourceLocation( | 166 return new PositionSourceInformation(new OffsetSourceLocation( |
| 176 sourceFile, node.getBeginToken().charOffset, name)); | 167 sourceFile, node.getBeginToken().charOffset, name)); |
| 177 } | 168 } |
| 178 | 169 |
| 179 @override | 170 @override |
| 180 SourceInformation buildGeneric(Node node) => buildBegin(node); | 171 SourceInformation buildGeneric(Node node) => buildBegin(node); |
| 181 | 172 |
| 182 @override | 173 @override |
| 183 SourceInformation buildCreate(Node node) => buildBegin(node); | 174 SourceInformation buildCreate(Node node) => buildBegin(node); |
| 184 | 175 |
| 185 @override | 176 @override |
| 186 SourceInformation buildReturn(Node node) => buildBegin(node); | 177 SourceInformation buildReturn(Node node) => buildBegin(node); |
| 187 | 178 |
| 188 @override | 179 @override |
| 189 SourceInformation buildImplicitReturn(AstElement element) { | 180 SourceInformation buildImplicitReturn(AstElement element) { |
| 190 if (element.isSynthesized) { | 181 if (element.isSynthesized) { |
| 191 return new PositionSourceInformation( | 182 return new PositionSourceInformation(new OffsetSourceLocation( |
| 192 new OffsetSourceLocation( | 183 sourceFile, element.position.charOffset, name)); |
| 193 sourceFile, element.position.charOffset, name)); | |
| 194 } else { | 184 } else { |
| 195 return new PositionSourceInformation( | 185 return new PositionSourceInformation(new OffsetSourceLocation( |
| 196 new OffsetSourceLocation(sourceFile, | 186 sourceFile, element.resolvedAst.node.getEndToken().charOffset, name)); |
| 197 element.resolvedAst.node.getEndToken().charOffset, name)); | |
| 198 } | 187 } |
| 199 } | 188 } |
| 200 | |
| 201 | 189 |
| 202 @override | 190 @override |
| 203 SourceInformation buildLoop(Node node) => buildBegin(node); | 191 SourceInformation buildLoop(Node node) => buildBegin(node); |
| 204 | 192 |
| 205 @override | 193 @override |
| 206 SourceInformation buildGet(Node node) { | 194 SourceInformation buildGet(Node node) { |
| 207 Node left = node; | 195 Node left = node; |
| 208 Node right = node; | 196 Node right = node; |
| 209 Send send = node.asSend(); | 197 Send send = node.asSend(); |
| 210 if (send != null) { | 198 if (send != null) { |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 return startPosition; | 314 return startPosition; |
| 327 case CodePositionKind.END: | 315 case CodePositionKind.END: |
| 328 return endPosition; | 316 return endPosition; |
| 329 case CodePositionKind.CLOSING: | 317 case CodePositionKind.CLOSING: |
| 330 return closingPosition; | 318 return closingPosition; |
| 331 } | 319 } |
| 332 } | 320 } |
| 333 | 321 |
| 334 String toString() { | 322 String toString() { |
| 335 return 'CodePosition(start=$startPosition,' | 323 return 'CodePosition(start=$startPosition,' |
| 336 'end=$endPosition,closing=$closingPosition)'; | 324 'end=$endPosition,closing=$closingPosition)'; |
| 337 } | 325 } |
| 338 } | 326 } |
| 339 | 327 |
| 340 /// A map from a [js.Node] to its [CodePosition]. | 328 /// A map from a [js.Node] to its [CodePosition]. |
| 341 abstract class CodePositionMap { | 329 abstract class CodePositionMap { |
| 342 CodePosition operator [](js.Node node); | 330 CodePosition operator [](js.Node node); |
| 343 } | 331 } |
| 344 | 332 |
| 345 /// Registry for mapping [js.Node]s to their [CodePosition]. | 333 /// Registry for mapping [js.Node]s to their [CodePosition]. |
| 346 class CodePositionRecorder implements CodePositionMap { | 334 class CodePositionRecorder implements CodePositionMap { |
| 347 Map<js.Node, CodePosition> _codePositionMap = | 335 Map<js.Node, CodePosition> _codePositionMap = |
| 348 new Map<js.Node, CodePosition>.identity(); | 336 new Map<js.Node, CodePosition>.identity(); |
| 349 | 337 |
| 350 void registerPositions(js.Node node, | 338 void registerPositions( |
| 351 int startPosition, | 339 js.Node node, int startPosition, int endPosition, int closingPosition) { |
| 352 int endPosition, | 340 registerCodePosition( |
| 353 int closingPosition) { | 341 node, new CodePosition(startPosition, endPosition, closingPosition)); |
| 354 registerCodePosition(node, | |
| 355 new CodePosition(startPosition, endPosition, closingPosition)); | |
| 356 } | 342 } |
| 357 | 343 |
| 358 void registerCodePosition(js.Node node, CodePosition codePosition) { | 344 void registerCodePosition(js.Node node, CodePosition codePosition) { |
| 359 _codePositionMap[node] = codePosition; | 345 _codePositionMap[node] = codePosition; |
| 360 } | 346 } |
| 361 | 347 |
| 362 CodePosition operator [](js.Node node) => _codePositionMap[node]; | 348 CodePosition operator [](js.Node node) => _codePositionMap[node]; |
| 363 } | 349 } |
| 364 | 350 |
| 365 /// Enum values for the part of a Dart node used for the source location offset. | 351 /// Enum values for the part of a Dart node used for the source location offset. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 389 /// For function expressions the inner position is the closing brace or the | 375 /// For function expressions the inner position is the closing brace or the |
| 390 /// arrow: | 376 /// arrow: |
| 391 /// | 377 /// |
| 392 /// foo() => () {} | 378 /// foo() => () {} |
| 393 /// ^ // the inner position of the 'foo' function | 379 /// ^ // the inner position of the 'foo' function |
| 394 /// ^ // the inner position of the closure | 380 /// ^ // the inner position of the closure |
| 395 /// | 381 /// |
| 396 INNER, | 382 INNER, |
| 397 } | 383 } |
| 398 | 384 |
| 399 SourceLocation getSourceLocation( | 385 SourceLocation getSourceLocation(SourceInformation sourceInformation, |
| 400 SourceInformation sourceInformation, | |
| 401 [SourcePositionKind sourcePositionKind = SourcePositionKind.START]) { | 386 [SourcePositionKind sourcePositionKind = SourcePositionKind.START]) { |
| 402 if (sourceInformation == null) return null; | 387 if (sourceInformation == null) return null; |
| 403 switch (sourcePositionKind) { | 388 switch (sourcePositionKind) { |
| 404 case SourcePositionKind.START: | 389 case SourcePositionKind.START: |
| 405 return sourceInformation.startPosition; | 390 return sourceInformation.startPosition; |
| 406 case SourcePositionKind.INNER: | 391 case SourcePositionKind.INNER: |
| 407 return sourceInformation.closingPosition; | 392 return sourceInformation.closingPosition; |
| 408 } | 393 } |
| 409 } | 394 } |
| 410 | 395 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 442 END, | 427 END, |
| 443 } | 428 } |
| 444 | 429 |
| 445 /// Processor that associates [SourceLocation]s from [SourceInformation] on | 430 /// Processor that associates [SourceLocation]s from [SourceInformation] on |
| 446 /// [js.Node]s with the target offsets in a [SourceMapper]. | 431 /// [js.Node]s with the target offsets in a [SourceMapper]. |
| 447 class PositionSourceInformationProcessor implements SourceInformationProcessor { | 432 class PositionSourceInformationProcessor implements SourceInformationProcessor { |
| 448 final CodePositionRecorder codePositionRecorder = new CodePositionRecorder(); | 433 final CodePositionRecorder codePositionRecorder = new CodePositionRecorder(); |
| 449 CodePositionMap codePositionMap; | 434 CodePositionMap codePositionMap; |
| 450 List<TraceListener> traceListeners; | 435 List<TraceListener> traceListeners; |
| 451 | 436 |
| 452 PositionSourceInformationProcessor( | 437 PositionSourceInformationProcessor(SourceMapper sourceMapper, |
| 453 SourceMapper sourceMapper, | |
| 454 [Coverage coverage]) { | 438 [Coverage coverage]) { |
| 455 codePositionMap = coverage != null | 439 codePositionMap = coverage != null |
| 456 ? new CodePositionCoverage(codePositionRecorder, coverage) | 440 ? new CodePositionCoverage(codePositionRecorder, coverage) |
| 457 : codePositionRecorder; | 441 : codePositionRecorder; |
| 458 traceListeners = [new PositionTraceListener(sourceMapper)]; | 442 traceListeners = [new PositionTraceListener(sourceMapper)]; |
| 459 if (coverage != null) { | 443 if (coverage != null) { |
| 460 traceListeners.add(new CoverageListener(coverage)); | 444 traceListeners.add(new CoverageListener(coverage)); |
| 461 } | 445 } |
| 462 } | 446 } |
| 463 | 447 |
| 464 void process(js.Node node, CodeBuffer codeBuffer) { | 448 void process(js.Node node, CodeBuffer codeBuffer) { |
| 465 new JavaScriptTracer(codePositionMap, traceListeners).apply(node); | 449 new JavaScriptTracer(codePositionMap, traceListeners).apply(node); |
| 466 } | 450 } |
| 467 | 451 |
| 468 @override | 452 @override |
| 469 void onPositions(js.Node node, | 453 void onPositions( |
| 470 int startPosition, | 454 js.Node node, int startPosition, int endPosition, int closingPosition) { |
| 471 int endPosition, | |
| 472 int closingPosition) { | |
| 473 codePositionRecorder.registerPositions( | 455 codePositionRecorder.registerPositions( |
| 474 node, startPosition, endPosition, closingPosition); | 456 node, startPosition, endPosition, closingPosition); |
| 475 } | 457 } |
| 476 } | 458 } |
| 477 | 459 |
| 478 /// Visitor that computes [SourceInformation] for a [js.Node] using information | 460 /// Visitor that computes [SourceInformation] for a [js.Node] using information |
| 479 /// attached to the node itself or alternatively from child nodes. | 461 /// attached to the node itself or alternatively from child nodes. |
| 480 class NodeSourceInformation extends js.BaseVisitor<SourceInformation> { | 462 class NodeSourceInformation extends js.BaseVisitor<SourceInformation> { |
| 481 const NodeSourceInformation(); | 463 const NodeSourceInformation(); |
| 482 | 464 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 return visit(node.value); | 499 return visit(node.value); |
| 518 } | 500 } |
| 519 | 501 |
| 520 @override | 502 @override |
| 521 SourceInformation visitAssignment(js.Assignment node) { | 503 SourceInformation visitAssignment(js.Assignment node) { |
| 522 if (node.sourceInformation != null) { | 504 if (node.sourceInformation != null) { |
| 523 return node.sourceInformation; | 505 return node.sourceInformation; |
| 524 } | 506 } |
| 525 return visit(node.value); | 507 return visit(node.value); |
| 526 } | 508 } |
| 527 | |
| 528 } | 509 } |
| 529 | 510 |
| 530 /// Mixin that add support for computing [SourceInformation] for a [js.Node]. | 511 /// Mixin that add support for computing [SourceInformation] for a [js.Node]. |
| 531 class NodeToSourceInformationMixin { | 512 class NodeToSourceInformationMixin { |
| 532 SourceInformation computeSourceInformation(js.Node node) { | 513 SourceInformation computeSourceInformation(js.Node node) { |
| 533 return const NodeSourceInformation().visit(node); | 514 return const NodeSourceInformation().visit(node); |
| 534 } | 515 } |
| 535 } | 516 } |
| 536 | 517 |
| 537 /// [TraceListener] that register [SourceLocation]s with a [SourceMapper]. | 518 /// [TraceListener] that register [SourceLocation]s with a [SourceMapper]. |
| 538 class PositionTraceListener extends TraceListener with | 519 class PositionTraceListener extends TraceListener |
| 539 NodeToSourceInformationMixin { | 520 with NodeToSourceInformationMixin { |
| 540 final SourceMapper sourceMapper; | 521 final SourceMapper sourceMapper; |
| 541 | 522 |
| 542 PositionTraceListener(this.sourceMapper); | 523 PositionTraceListener(this.sourceMapper); |
| 543 | 524 |
| 544 @override | 525 @override |
| 545 void onStep(js.Node node, Offset offset, StepKind kind) { | 526 void onStep(js.Node node, Offset offset, StepKind kind) { |
| 546 SourceInformation sourceInformation = computeSourceInformation(node); | 527 SourceInformation sourceInformation = computeSourceInformation(node); |
| 547 if (sourceInformation == null) return; | 528 if (sourceInformation == null) return; |
| 548 int codeLocation = offset.subexpressionOffset; | 529 int codeLocation = offset.subexpressionOffset; |
| 549 if (codeLocation == null) return; | 530 if (codeLocation == null) return; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 610 pureAccess = true; | 591 pureAccess = true; |
| 611 break; | 592 break; |
| 612 } else { | 593 } else { |
| 613 target = targetAccess.receiver; | 594 target = targetAccess.receiver; |
| 614 } | 595 } |
| 615 } | 596 } |
| 616 if (pureAccess) { | 597 if (pureAccess) { |
| 617 // a.m() this.m() a.b.c.d.m() | 598 // a.m() this.m() a.b.c.d.m() |
| 618 // ^ ^ ^ | 599 // ^ ^ ^ |
| 619 return new CallPosition( | 600 return new CallPosition( |
| 620 node, | 601 node, CodePositionKind.START, SourcePositionKind.START); |
| 621 CodePositionKind.START, | |
| 622 SourcePositionKind.START); | |
| 623 } else { | 602 } else { |
| 624 // *.m() *.a.b.c.d.m() | 603 // *.m() *.a.b.c.d.m() |
| 625 // ^ ^ | 604 // ^ ^ |
| 626 return new CallPosition( | 605 return new CallPosition( |
| 627 access.selector, | 606 access.selector, CodePositionKind.START, SourcePositionKind.INNER); |
| 628 CodePositionKind.START, | |
| 629 SourcePositionKind.INNER); | |
| 630 } | 607 } |
| 631 } else if (node.target is js.VariableUse) { | 608 } else if (node.target is js.VariableUse) { |
| 632 // m() | 609 // m() |
| 633 // ^ | 610 // ^ |
| 634 return new CallPosition( | 611 return new CallPosition( |
| 635 node, | 612 node, CodePositionKind.START, SourcePositionKind.START); |
| 636 CodePositionKind.START, | |
| 637 SourcePositionKind.START); | |
| 638 } else if (node.target is js.Fun || node.target is js.New) { | 613 } else if (node.target is js.Fun || node.target is js.New) { |
| 639 // function(){}() new Function("...")() | 614 // function(){}() new Function("...")() |
| 640 // ^ ^ | 615 // ^ ^ |
| 641 return new CallPosition( | 616 return new CallPosition( |
| 642 node.target, | 617 node.target, CodePositionKind.END, SourcePositionKind.INNER); |
| 643 CodePositionKind.END, | |
| 644 SourcePositionKind.INNER); | |
| 645 } else if (node.target is js.Binary || node.target is js.Call) { | 618 } else if (node.target is js.Binary || node.target is js.Call) { |
| 646 // (0,a)() m()() | 619 // (0,a)() m()() |
| 647 // ^ ^ | 620 // ^ ^ |
| 648 return new CallPosition( | 621 return new CallPosition( |
| 649 node.target, | 622 node.target, CodePositionKind.END, SourcePositionKind.INNER); |
| 650 CodePositionKind.END, | |
| 651 SourcePositionKind.INNER); | |
| 652 } else { | 623 } else { |
| 653 assert(invariant(NO_LOCATION_SPANNABLE, false, | 624 assert(invariant(NO_LOCATION_SPANNABLE, false, |
| 654 message: "Unexpected property access ${nodeToString(node)}:\n" | 625 message: "Unexpected property access ${nodeToString(node)}:\n" |
| 655 "${DebugPrinter.prettyPrint(node)}")); | 626 "${DebugPrinter.prettyPrint(node)}")); |
| 656 // Don't know.... | 627 // Don't know.... |
| 657 return new CallPosition( | 628 return new CallPosition( |
| 658 node, | 629 node, CodePositionKind.START, SourcePositionKind.START); |
| 659 CodePositionKind.START, | |
| 660 SourcePositionKind.START); | |
| 661 } | 630 } |
| 662 } | 631 } |
| 663 } | 632 } |
| 664 | 633 |
| 665 class Offset { | 634 class Offset { |
| 666 /// The offset of the enclosing statement relative to the beginning of the | 635 /// The offset of the enclosing statement relative to the beginning of the |
| 667 /// file. | 636 /// file. |
| 668 /// | 637 /// |
| 669 /// For instance: | 638 /// For instance: |
| 670 /// | 639 /// |
| (...skipping 30 matching lines...) Expand all Loading... |
| 701 /// foo().bar(baz()); | 670 /// foo().bar(baz()); |
| 702 /// ^ // the left-to-right offset of the `foo()` call | 671 /// ^ // the left-to-right offset of the `foo()` call |
| 703 /// ^ // the left-to-right offset of the `*.bar()` call | 672 /// ^ // the left-to-right offset of the `*.bar()` call |
| 704 /// ^ // the left-to-right offset of the `baz()` call | 673 /// ^ // the left-to-right offset of the `baz()` call |
| 705 /// | 674 /// |
| 706 /// Here, `baz()` is executed before `foo()` so we need to use 'f' as its best | 675 /// Here, `baz()` is executed before `foo()` so we need to use 'f' as its best |
| 707 /// position under the restriction. | 676 /// position under the restriction. |
| 708 /// | 677 /// |
| 709 final int leftToRightOffset; | 678 final int leftToRightOffset; |
| 710 | 679 |
| 711 Offset(this.statementOffset, this.leftToRightOffset, this.subexpressionOffset)
; | 680 Offset( |
| 681 this.statementOffset, this.leftToRightOffset, this.subexpressionOffset); |
| 712 | 682 |
| 713 String toString() { | 683 String toString() { |
| 714 return 'Offset[statementOffset=$statementOffset,' | 684 return 'Offset[statementOffset=$statementOffset,' |
| 715 'leftToRightOffset=$leftToRightOffset,' | 685 'leftToRightOffset=$leftToRightOffset,' |
| 716 'subexpressionOffset=$subexpressionOffset]'; | 686 'subexpressionOffset=$subexpressionOffset]'; |
| 717 } | 687 } |
| 718 } | 688 } |
| 719 | 689 |
| 720 enum BranchKind { | 690 enum BranchKind { CONDITION, LOOP, CATCH, FINALLY, CASE, } |
| 721 CONDITION, | |
| 722 LOOP, | |
| 723 CATCH, | |
| 724 FINALLY, | |
| 725 CASE, | |
| 726 } | |
| 727 | 691 |
| 728 enum StepKind { | 692 enum StepKind { |
| 729 FUN_ENTRY, | 693 FUN_ENTRY, |
| 730 FUN_EXIT, | 694 FUN_EXIT, |
| 731 CALL, | 695 CALL, |
| 732 NEW, | 696 NEW, |
| 733 RETURN, | 697 RETURN, |
| 734 BREAK, | 698 BREAK, |
| 735 CONTINUE, | 699 CONTINUE, |
| 736 THROW, | 700 THROW, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 760 /// Called when the current branch ends. | 724 /// Called when the current branch ends. |
| 761 void popBranch() {} | 725 void popBranch() {} |
| 762 | 726 |
| 763 /// Called when [node] defines a step of the given [kind] at the given | 727 /// Called when [node] defines a step of the given [kind] at the given |
| 764 /// [offset] when the generated JavaScript code. | 728 /// [offset] when the generated JavaScript code. |
| 765 void onStep(js.Node node, Offset offset, StepKind kind) {} | 729 void onStep(js.Node node, Offset offset, StepKind kind) {} |
| 766 } | 730 } |
| 767 | 731 |
| 768 /// Visitor that computes the [js.Node]s the are part of the JavaScript | 732 /// Visitor that computes the [js.Node]s the are part of the JavaScript |
| 769 /// steppable execution and thus needs source mapping locations. | 733 /// steppable execution and thus needs source mapping locations. |
| 770 class JavaScriptTracer extends js.BaseVisitor { | 734 class JavaScriptTracer extends js.BaseVisitor { |
| 771 final CodePositionMap codePositions; | 735 final CodePositionMap codePositions; |
| 772 final List<TraceListener> listeners; | 736 final List<TraceListener> listeners; |
| 773 | 737 |
| 774 /// The steps added by subexpressions. | 738 /// The steps added by subexpressions. |
| 775 List steps = []; | 739 List steps = []; |
| 776 | 740 |
| 777 /// The offset of the current statement. | 741 /// The offset of the current statement. |
| 778 int statementOffset; | 742 int statementOffset; |
| 779 | 743 |
| 780 /// The current offset in left-to-right progression. | 744 /// The current offset in left-to-right progression. |
| 781 int leftToRightOffset; | 745 int leftToRightOffset; |
| 782 | 746 |
| 783 /// The offset of the surrounding statement, used for the first subexpression. | 747 /// The offset of the surrounding statement, used for the first subexpression. |
| 784 int offsetPosition; | 748 int offsetPosition; |
| 785 | 749 |
| 786 bool active; | 750 bool active; |
| 787 | 751 |
| 788 JavaScriptTracer(this.codePositions, | 752 JavaScriptTracer(this.codePositions, this.listeners, {this.active: false}); |
| 789 this.listeners, | |
| 790 {this.active: false}); | |
| 791 | 753 |
| 792 void notifyStart(js.Node node) { | 754 void notifyStart(js.Node node) { |
| 793 listeners.forEach((listener) => listener.onStart(node)); | 755 listeners.forEach((listener) => listener.onStart(node)); |
| 794 } | 756 } |
| 795 | 757 |
| 796 void notifyEnd(js.Node node) { | 758 void notifyEnd(js.Node node) { |
| 797 listeners.forEach((listener) => listener.onEnd(node)); | 759 listeners.forEach((listener) => listener.onEnd(node)); |
| 798 } | 760 } |
| 799 | 761 |
| 800 void notifyPushBranch(BranchKind kind, [value]) { | 762 void notifyPushBranch(BranchKind kind, [value]) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 845 } | 807 } |
| 846 } | 808 } |
| 847 } | 809 } |
| 848 | 810 |
| 849 @override | 811 @override |
| 850 visitFun(js.Fun node) { | 812 visitFun(js.Fun node) { |
| 851 bool activeBefore = active; | 813 bool activeBefore = active; |
| 852 if (!active) { | 814 if (!active) { |
| 853 active = node.sourceInformation != null; | 815 active = node.sourceInformation != null; |
| 854 } | 816 } |
| 855 leftToRightOffset = statementOffset = | 817 leftToRightOffset = |
| 856 getSyntaxOffset(node, kind: CodePositionKind.START); | 818 statementOffset = getSyntaxOffset(node, kind: CodePositionKind.START); |
| 857 Offset entryOffset = getOffsetForNode(node, statementOffset); | 819 Offset entryOffset = getOffsetForNode(node, statementOffset); |
| 858 notifyStep(node, entryOffset, StepKind.FUN_ENTRY); | 820 notifyStep(node, entryOffset, StepKind.FUN_ENTRY); |
| 859 | 821 |
| 860 visit(node.body); | 822 visit(node.body); |
| 861 | 823 |
| 862 leftToRightOffset = statementOffset = | 824 leftToRightOffset = |
| 863 getSyntaxOffset(node, kind: CodePositionKind.CLOSING); | 825 statementOffset = getSyntaxOffset(node, kind: CodePositionKind.CLOSING); |
| 864 Offset exitOffset = getOffsetForNode(node, statementOffset); | 826 Offset exitOffset = getOffsetForNode(node, statementOffset); |
| 865 notifyStep(node, exitOffset, StepKind.FUN_EXIT); | 827 notifyStep(node, exitOffset, StepKind.FUN_EXIT); |
| 866 active = activeBefore; | 828 active = activeBefore; |
| 867 } | 829 } |
| 868 | 830 |
| 869 @override | 831 @override |
| 870 visitBlock(js.Block node) { | 832 visitBlock(js.Block node) { |
| 871 for (js.Statement statement in node.statements) { | 833 for (js.Statement statement in node.statements) { |
| 872 visit(statement); | 834 visit(statement); |
| 873 } | 835 } |
| 874 } | 836 } |
| 875 | 837 |
| 876 int getSyntaxOffset(js.Node node, | 838 int getSyntaxOffset(js.Node node, |
| 877 {CodePositionKind kind: CodePositionKind.START}) { | 839 {CodePositionKind kind: CodePositionKind.START}) { |
| 878 CodePosition codePosition = codePositions[node]; | 840 CodePosition codePosition = codePositions[node]; |
| 879 if (codePosition != null) { | 841 if (codePosition != null) { |
| 880 return codePosition.getPosition(kind); | 842 return codePosition.getPosition(kind); |
| 881 } | 843 } |
| 882 return null; | 844 return null; |
| 883 } | 845 } |
| 884 | 846 |
| 885 visitSubexpression(js.Node parent, | 847 visitSubexpression( |
| 886 js.Expression child, | 848 js.Node parent, js.Expression child, int codeOffset, StepKind kind) { |
| 887 int codeOffset, | |
| 888 StepKind kind) { | |
| 889 var oldSteps = steps; | 849 var oldSteps = steps; |
| 890 steps = []; | 850 steps = []; |
| 891 offsetPosition = codeOffset; | 851 offsetPosition = codeOffset; |
| 892 visit(child); | 852 visit(child); |
| 893 if (steps.isEmpty) { | 853 if (steps.isEmpty) { |
| 894 notifyStep(parent, | 854 notifyStep(parent, getOffsetForNode(parent, offsetPosition), kind); |
| 895 getOffsetForNode(parent, offsetPosition), | |
| 896 kind); | |
| 897 // The [offsetPosition] should only be used by the first subexpression. | 855 // The [offsetPosition] should only be used by the first subexpression. |
| 898 offsetPosition = null; | 856 offsetPosition = null; |
| 899 } | 857 } |
| 900 steps = oldSteps; | 858 steps = oldSteps; |
| 901 } | 859 } |
| 902 | 860 |
| 903 @override | 861 @override |
| 904 visitExpressionStatement(js.ExpressionStatement node) { | 862 visitExpressionStatement(js.ExpressionStatement node) { |
| 905 statementOffset = getSyntaxOffset(node); | 863 statementOffset = getSyntaxOffset(node); |
| 906 visitSubexpression( | 864 visitSubexpression( |
| 907 node, node.expression, statementOffset, | 865 node, node.expression, statementOffset, StepKind.EXPRESSION_STATEMENT); |
| 908 StepKind.EXPRESSION_STATEMENT); | |
| 909 statementOffset = null; | 866 statementOffset = null; |
| 910 leftToRightOffset = null; | 867 leftToRightOffset = null; |
| 911 } | 868 } |
| 912 | 869 |
| 913 @override | 870 @override |
| 914 visitEmptyStatement(js.EmptyStatement node) {} | 871 visitEmptyStatement(js.EmptyStatement node) {} |
| 915 | 872 |
| 916 @override | 873 @override |
| 917 visitCall(js.Call node) { | 874 visitCall(js.Call node) { |
| 918 visit(node.target); | 875 visit(node.target); |
| 919 int oldPosition = offsetPosition; | 876 int oldPosition = offsetPosition; |
| 920 offsetPosition = null; | 877 offsetPosition = null; |
| 921 visitList(node.arguments); | 878 visitList(node.arguments); |
| 922 offsetPosition = oldPosition; | 879 offsetPosition = oldPosition; |
| 923 CallPosition callPosition = | 880 CallPosition callPosition = CallPosition.getSemanticPositionForCall(node); |
| 924 CallPosition.getSemanticPositionForCall(node); | |
| 925 js.Node positionNode = callPosition.node; | 881 js.Node positionNode = callPosition.node; |
| 926 int callOffset = getSyntaxOffset( | 882 int callOffset = |
| 927 positionNode, kind: callPosition.codePositionKind); | 883 getSyntaxOffset(positionNode, kind: callPosition.codePositionKind); |
| 928 if (offsetPosition == null) { | 884 if (offsetPosition == null) { |
| 929 // Use the call offset if this is not the first subexpression. | 885 // Use the call offset if this is not the first subexpression. |
| 930 offsetPosition = callOffset; | 886 offsetPosition = callOffset; |
| 931 } | 887 } |
| 932 Offset offset = getOffsetForNode(positionNode, offsetPosition); | 888 Offset offset = getOffsetForNode(positionNode, offsetPosition); |
| 933 notifyStep(node, offset, StepKind.CALL); | 889 notifyStep(node, offset, StepKind.CALL); |
| 934 steps.add(node); | 890 steps.add(node); |
| 935 offsetPosition = null; | 891 offsetPosition = null; |
| 936 } | 892 } |
| 937 | 893 |
| 938 @override | 894 @override |
| 939 visitNew(js.New node) { | 895 visitNew(js.New node) { |
| 940 visit(node.target); | 896 visit(node.target); |
| 941 visitList(node.arguments); | 897 visitList(node.arguments); |
| 942 if (offsetPosition == null) { | 898 if (offsetPosition == null) { |
| 943 // Use the syntax offset if this is not the first subexpression. | 899 // Use the syntax offset if this is not the first subexpression. |
| 944 offsetPosition = getSyntaxOffset(node); | 900 offsetPosition = getSyntaxOffset(node); |
| 945 } | 901 } |
| 946 notifyStep( | 902 notifyStep(node, getOffsetForNode(node, offsetPosition), StepKind.NEW); |
| 947 node, getOffsetForNode(node, offsetPosition), StepKind.NEW); | |
| 948 steps.add(node); | 903 steps.add(node); |
| 949 offsetPosition = null; | 904 offsetPosition = null; |
| 950 } | 905 } |
| 951 | 906 |
| 952 @override | 907 @override |
| 953 visitAccess(js.PropertyAccess node) { | 908 visitAccess(js.PropertyAccess node) { |
| 954 visit(node.receiver); | 909 visit(node.receiver); |
| 955 visit(node.selector); | 910 visit(node.selector); |
| 956 } | 911 } |
| 957 | 912 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 989 | 944 |
| 990 @override | 945 @override |
| 991 visitAssignment(js.Assignment node) { | 946 visitAssignment(js.Assignment node) { |
| 992 visit(node.leftHandSide); | 947 visit(node.leftHandSide); |
| 993 visit(node.value); | 948 visit(node.value); |
| 994 } | 949 } |
| 995 | 950 |
| 996 @override | 951 @override |
| 997 visitIf(js.If node) { | 952 visitIf(js.If node) { |
| 998 statementOffset = getSyntaxOffset(node); | 953 statementOffset = getSyntaxOffset(node); |
| 999 visitSubexpression(node, node.condition, statementOffset, | 954 visitSubexpression( |
| 1000 StepKind.IF_CONDITION); | 955 node, node.condition, statementOffset, StepKind.IF_CONDITION); |
| 1001 statementOffset = null; | 956 statementOffset = null; |
| 1002 visit(node.then, BranchKind.CONDITION, true); | 957 visit(node.then, BranchKind.CONDITION, true); |
| 1003 visit(node.otherwise, BranchKind.CONDITION, false); | 958 visit(node.otherwise, BranchKind.CONDITION, false); |
| 1004 } | 959 } |
| 1005 | 960 |
| 1006 @override | 961 @override |
| 1007 visitFor(js.For node) { | 962 visitFor(js.For node) { |
| 1008 int offset = statementOffset = getSyntaxOffset(node); | 963 int offset = statementOffset = getSyntaxOffset(node); |
| 1009 statementOffset = offset; | 964 statementOffset = offset; |
| 1010 leftToRightOffset = null; | 965 leftToRightOffset = null; |
| 1011 if (node.init != null) { | 966 if (node.init != null) { |
| 1012 visitSubexpression(node, node.init, getSyntaxOffset(node), | 967 visitSubexpression( |
| 1013 StepKind.FOR_INITIALIZER); | 968 node, node.init, getSyntaxOffset(node), StepKind.FOR_INITIALIZER); |
| 1014 } | 969 } |
| 1015 | 970 |
| 1016 if (node.condition != null) { | 971 if (node.condition != null) { |
| 1017 visitSubexpression(node, node.condition, getSyntaxOffset(node.condition), | 972 visitSubexpression(node, node.condition, getSyntaxOffset(node.condition), |
| 1018 StepKind.FOR_CONDITION); | 973 StepKind.FOR_CONDITION); |
| 1019 } | 974 } |
| 1020 | 975 |
| 1021 notifyPushBranch(BranchKind.LOOP); | 976 notifyPushBranch(BranchKind.LOOP); |
| 1022 visit(node.body); | 977 visit(node.body); |
| 1023 | 978 |
| 1024 statementOffset = offset; | 979 statementOffset = offset; |
| 1025 if (node.update != null) { | 980 if (node.update != null) { |
| 1026 visitSubexpression(node, node.update, getSyntaxOffset(node.update), | 981 visitSubexpression( |
| 1027 StepKind.FOR_UPDATE); | 982 node, node.update, getSyntaxOffset(node.update), StepKind.FOR_UPDATE); |
| 1028 } | 983 } |
| 1029 | 984 |
| 1030 notifyPopBranch(); | 985 notifyPopBranch(); |
| 1031 } | 986 } |
| 1032 | 987 |
| 1033 @override | 988 @override |
| 1034 visitWhile(js.While node) { | 989 visitWhile(js.While node) { |
| 1035 statementOffset = getSyntaxOffset(node); | 990 statementOffset = getSyntaxOffset(node); |
| 1036 if (node.condition != null) { | 991 if (node.condition != null) { |
| 1037 visitSubexpression(node, node.condition, getSyntaxOffset(node), | 992 visitSubexpression(node, node.condition, getSyntaxOffset(node), |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1143 visit(node.name); | 1098 visit(node.name); |
| 1144 visit(node.value); | 1099 visit(node.value); |
| 1145 } | 1100 } |
| 1146 | 1101 |
| 1147 @override | 1102 @override |
| 1148 visitRegExpLiteral(js.RegExpLiteral node) {} | 1103 visitRegExpLiteral(js.RegExpLiteral node) {} |
| 1149 | 1104 |
| 1150 @override | 1105 @override |
| 1151 visitSwitch(js.Switch node) { | 1106 visitSwitch(js.Switch node) { |
| 1152 statementOffset = getSyntaxOffset(node); | 1107 statementOffset = getSyntaxOffset(node); |
| 1153 visitSubexpression(node, node.key, getSyntaxOffset(node), | 1108 visitSubexpression( |
| 1154 StepKind.SWITCH_EXPRESSION); | 1109 node, node.key, getSyntaxOffset(node), StepKind.SWITCH_EXPRESSION); |
| 1155 statementOffset = null; | 1110 statementOffset = null; |
| 1156 leftToRightOffset = null; | 1111 leftToRightOffset = null; |
| 1157 for (int i = 0; i < node.cases.length; i++) { | 1112 for (int i = 0; i < node.cases.length; i++) { |
| 1158 visit(node.cases[i], BranchKind.CASE, i); | 1113 visit(node.cases[i], BranchKind.CASE, i); |
| 1159 } | 1114 } |
| 1160 } | 1115 } |
| 1161 | 1116 |
| 1162 @override | 1117 @override |
| 1163 visitCase(js.Case node) { | 1118 visitCase(js.Case node) { |
| 1164 visit(node.expression); | 1119 visit(node.expression); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1195 if (leftToRightOffset != null && leftToRightOffset < codeOffset) { | 1150 if (leftToRightOffset != null && leftToRightOffset < codeOffset) { |
| 1196 leftToRightOffset = codeOffset; | 1151 leftToRightOffset = codeOffset; |
| 1197 } | 1152 } |
| 1198 if (leftToRightOffset == null) { | 1153 if (leftToRightOffset == null) { |
| 1199 leftToRightOffset = statementOffset; | 1154 leftToRightOffset = statementOffset; |
| 1200 } | 1155 } |
| 1201 return new Offset(statementOffset, leftToRightOffset, codeOffset); | 1156 return new Offset(statementOffset, leftToRightOffset, codeOffset); |
| 1202 } | 1157 } |
| 1203 } | 1158 } |
| 1204 | 1159 |
| 1205 | |
| 1206 class Coverage { | 1160 class Coverage { |
| 1207 Set<js.Node> _nodesWithInfo = new Set<js.Node>(); | 1161 Set<js.Node> _nodesWithInfo = new Set<js.Node>(); |
| 1208 int _nodesWithInfoCount = 0; | 1162 int _nodesWithInfoCount = 0; |
| 1209 Set<js.Node> _nodesWithoutInfo = new Set<js.Node>(); | 1163 Set<js.Node> _nodesWithoutInfo = new Set<js.Node>(); |
| 1210 int _nodesWithoutInfoCount = 0; | 1164 int _nodesWithoutInfoCount = 0; |
| 1211 Map<Type, int> _nodesWithoutInfoCountByType = <Type, int>{}; | 1165 Map<Type, int> _nodesWithoutInfoCountByType = <Type, int>{}; |
| 1212 Set<js.Node> _nodesWithoutOffset = new Set<js.Node>(); | 1166 Set<js.Node> _nodesWithoutOffset = new Set<js.Node>(); |
| 1213 int _nodesWithoutOffsetCount = 0; | 1167 int _nodesWithoutOffsetCount = 0; |
| 1214 | 1168 |
| 1215 void registerNodeWithInfo(js.Node node) { | 1169 void registerNodeWithInfo(js.Node node) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1230 _nodesWithoutOffsetCount += _nodesWithoutOffset.length; | 1184 _nodesWithoutOffsetCount += _nodesWithoutOffset.length; |
| 1231 _nodesWithoutOffset.clear(); | 1185 _nodesWithoutOffset.clear(); |
| 1232 | 1186 |
| 1233 _nodesWithoutInfoCount += _nodesWithoutInfo.length; | 1187 _nodesWithoutInfoCount += _nodesWithoutInfo.length; |
| 1234 for (js.Node node in _nodesWithoutInfo) { | 1188 for (js.Node node in _nodesWithoutInfo) { |
| 1235 if (node is js.ExpressionStatement) { | 1189 if (node is js.ExpressionStatement) { |
| 1236 _nodesWithoutInfoCountByType.putIfAbsent( | 1190 _nodesWithoutInfoCountByType.putIfAbsent( |
| 1237 node.expression.runtimeType, () => 0); | 1191 node.expression.runtimeType, () => 0); |
| 1238 _nodesWithoutInfoCountByType[node.expression.runtimeType]++; | 1192 _nodesWithoutInfoCountByType[node.expression.runtimeType]++; |
| 1239 } else { | 1193 } else { |
| 1240 _nodesWithoutInfoCountByType.putIfAbsent( | 1194 _nodesWithoutInfoCountByType.putIfAbsent(node.runtimeType, () => 0); |
| 1241 node.runtimeType, () => 0); | |
| 1242 _nodesWithoutInfoCountByType[node.runtimeType]++; | 1195 _nodesWithoutInfoCountByType[node.runtimeType]++; |
| 1243 } | 1196 } |
| 1244 } | 1197 } |
| 1245 _nodesWithoutInfo.clear(); | 1198 _nodesWithoutInfo.clear(); |
| 1246 } | 1199 } |
| 1247 | 1200 |
| 1248 String getCoverageReport() { | 1201 String getCoverageReport() { |
| 1249 collapse(); | 1202 collapse(); |
| 1250 StringBuffer sb = new StringBuffer(); | 1203 StringBuffer sb = new StringBuffer(); |
| 1251 int total = _nodesWithInfoCount + _nodesWithoutInfoCount; | 1204 int total = _nodesWithInfoCount + _nodesWithoutInfoCount; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1267 sb.write('s'); | 1220 sb.write('s'); |
| 1268 } | 1221 } |
| 1269 sb.write(' without offset.'); | 1222 sb.write(' without offset.'); |
| 1270 } | 1223 } |
| 1271 if (_nodesWithoutInfoCount > 0) { | 1224 if (_nodesWithoutInfoCount > 0) { |
| 1272 sb.write('\nNodes without info ('); | 1225 sb.write('\nNodes without info ('); |
| 1273 sb.write(_nodesWithoutInfoCount); | 1226 sb.write(_nodesWithoutInfoCount); |
| 1274 sb.write(') by runtime type:'); | 1227 sb.write(') by runtime type:'); |
| 1275 List<Type> types = _nodesWithoutInfoCountByType.keys.toList(); | 1228 List<Type> types = _nodesWithoutInfoCountByType.keys.toList(); |
| 1276 types.sort((a, b) { | 1229 types.sort((a, b) { |
| 1277 return -_nodesWithoutInfoCountByType[a].compareTo( | 1230 return -_nodesWithoutInfoCountByType[a] |
| 1278 _nodesWithoutInfoCountByType[b]); | 1231 .compareTo(_nodesWithoutInfoCountByType[b]); |
| 1279 }); | 1232 }); |
| 1280 | 1233 |
| 1281 types.forEach((Type type) { | 1234 types.forEach((Type type) { |
| 1282 int count = _nodesWithoutInfoCountByType[type]; | 1235 int count = _nodesWithoutInfoCountByType[type]; |
| 1283 sb.write('\n '); | 1236 sb.write('\n '); |
| 1284 sb.write(count); | 1237 sb.write(count); |
| 1285 sb.write(' '); | 1238 sb.write(' '); |
| 1286 sb.write(type); | 1239 sb.write(type); |
| 1287 sb.write(' node'); | 1240 sb.write(' node'); |
| 1288 if (count > 1) { | 1241 if (count > 1) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1324 final CodePositionMap codePositions; | 1277 final CodePositionMap codePositions; |
| 1325 final Coverage coverage; | 1278 final Coverage coverage; |
| 1326 | 1279 |
| 1327 CodePositionCoverage(this.codePositions, this.coverage); | 1280 CodePositionCoverage(this.codePositions, this.coverage); |
| 1328 | 1281 |
| 1329 @override | 1282 @override |
| 1330 CodePosition operator [](js.Node node) { | 1283 CodePosition operator [](js.Node node) { |
| 1331 CodePosition codePosition = codePositions[node]; | 1284 CodePosition codePosition = codePositions[node]; |
| 1332 if (codePosition == null) { | 1285 if (codePosition == null) { |
| 1333 coverage.registerNodesWithoutOffset(node); | 1286 coverage.registerNodesWithoutOffset(node); |
| 1334 } | 1287 } |
| 1335 return codePosition; | 1288 return codePosition; |
| 1336 } | 1289 } |
| 1337 } | 1290 } |
| OLD | NEW |