| 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' | 11 import '../elements/elements.dart' |
| 12 show AstElement, ResolvedAst, ResolvedAstKind; | 12 show AstElement, ResolvedAst, ResolvedAstKind; |
| 13 import '../js/js.dart' as js; | 13 import '../js/js.dart' as js; |
| 14 import '../js/js_debug.dart'; | 14 import '../js/js_debug.dart'; |
| 15 import '../js/js_source_mapping.dart'; | 15 import '../js/js_source_mapping.dart'; |
| 16 import '../tree/tree.dart' show Node, Send; | 16 import '../tree/tree.dart' show Node, Send; |
| 17 import 'code_output.dart' show CodeBuffer; | 17 import 'code_output.dart' show BufferedCodeOutput; |
| 18 import 'source_file.dart'; | 18 import 'source_file.dart'; |
| 19 import 'source_information.dart'; | 19 import 'source_information.dart'; |
| 20 | 20 |
| 21 /// [SourceInformation] that consists of an offset position into the source | 21 /// [SourceInformation] that consists of an offset position into the source |
| 22 /// code. | 22 /// code. |
| 23 class PositionSourceInformation extends SourceInformation { | 23 class PositionSourceInformation extends SourceInformation { |
| 24 @override | 24 @override |
| 25 final SourceLocation startPosition; | 25 final SourceLocation startPosition; |
| 26 | 26 |
| 27 @override | 27 @override |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 class PositionSourceInformationStrategy | 99 class PositionSourceInformationStrategy |
| 100 implements JavaScriptSourceInformationStrategy { | 100 implements JavaScriptSourceInformationStrategy { |
| 101 const PositionSourceInformationStrategy(); | 101 const PositionSourceInformationStrategy(); |
| 102 | 102 |
| 103 @override | 103 @override |
| 104 SourceInformationBuilder createBuilderForContext(ResolvedAst resolvedAst) { | 104 SourceInformationBuilder createBuilderForContext(ResolvedAst resolvedAst) { |
| 105 return new PositionSourceInformationBuilder(resolvedAst); | 105 return new PositionSourceInformationBuilder(resolvedAst); |
| 106 } | 106 } |
| 107 | 107 |
| 108 @override | 108 @override |
| 109 SourceInformationProcessor createProcessor(SourceMapper mapper) { | 109 SourceInformationProcessor createProcessor( |
| 110 return new PositionSourceInformationProcessor(mapper); | 110 SourceMapperProvider provider, SourceInformationReader reader) { |
| 111 return new PositionSourceInformationProcessor(provider, reader); |
| 111 } | 112 } |
| 112 | 113 |
| 113 @override | 114 @override |
| 114 void onComplete() {} | 115 void onComplete() {} |
| 115 | 116 |
| 116 @override | 117 @override |
| 117 SourceInformation buildSourceMappedMarker() { | 118 SourceInformation buildSourceMappedMarker() { |
| 118 return const SourceMappedMarker(); | 119 return const SourceMappedMarker(); |
| 119 } | 120 } |
| 120 } | 121 } |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 /// foo: function() { return 0; } | 420 /// foo: function() { return 0; } |
| 420 /// ^ // the function end position | 421 /// ^ // the function end position |
| 421 /// ^ // the return end position | 422 /// ^ // the return end position |
| 422 /// | 423 /// |
| 423 END, | 424 END, |
| 424 } | 425 } |
| 425 | 426 |
| 426 /// Processor that associates [SourceLocation]s from [SourceInformation] on | 427 /// Processor that associates [SourceLocation]s from [SourceInformation] on |
| 427 /// [js.Node]s with the target offsets in a [SourceMapper]. | 428 /// [js.Node]s with the target offsets in a [SourceMapper]. |
| 428 class PositionSourceInformationProcessor extends SourceInformationProcessor { | 429 class PositionSourceInformationProcessor extends SourceInformationProcessor { |
| 430 /// The id for this source information engine. |
| 431 /// |
| 432 /// The id is added to the source map file in an extra "engine" property and |
| 433 /// serves as a version number for the engine. |
| 434 /// |
| 435 /// The version history of this engine is: |
| 436 /// |
| 437 /// v2: The initial version with an id. |
| 438 static const String id = 'v2'; |
| 439 |
| 429 final CodePositionRecorder codePositionRecorder = new CodePositionRecorder(); | 440 final CodePositionRecorder codePositionRecorder = new CodePositionRecorder(); |
| 441 final SourceInformationReader reader; |
| 430 CodePositionMap codePositionMap; | 442 CodePositionMap codePositionMap; |
| 431 List<TraceListener> traceListeners; | 443 List<TraceListener> traceListeners; |
| 432 | 444 |
| 433 PositionSourceInformationProcessor(SourceMapper sourceMapper, | 445 PositionSourceInformationProcessor(SourceMapperProvider provider, this.reader, |
| 434 [Coverage coverage]) { | 446 [Coverage coverage]) { |
| 435 codePositionMap = coverage != null | 447 codePositionMap = coverage != null |
| 436 ? new CodePositionCoverage(codePositionRecorder, coverage) | 448 ? new CodePositionCoverage(codePositionRecorder, coverage) |
| 437 : codePositionRecorder; | 449 : codePositionRecorder; |
| 438 traceListeners = [new PositionTraceListener(sourceMapper)]; | 450 traceListeners = [ |
| 451 new PositionTraceListener(provider.createSourceMapper(id), reader) |
| 452 ]; |
| 439 if (coverage != null) { | 453 if (coverage != null) { |
| 440 traceListeners.add(new CoverageListener(coverage)); | 454 traceListeners.add(new CoverageListener(coverage, reader)); |
| 441 } | 455 } |
| 442 } | 456 } |
| 443 | 457 |
| 444 void process(js.Node node, CodeBuffer codeBuffer) { | 458 void process(js.Node node, BufferedCodeOutput code) { |
| 445 new JavaScriptTracer(codePositionMap, traceListeners).apply(node); | 459 new JavaScriptTracer(codePositionMap, reader, traceListeners).apply(node); |
| 446 } | 460 } |
| 447 | 461 |
| 448 @override | 462 @override |
| 449 void onPositions( | 463 void onPositions( |
| 450 js.Node node, int startPosition, int endPosition, int closingPosition) { | 464 js.Node node, int startPosition, int endPosition, int closingPosition) { |
| 451 codePositionRecorder.registerPositions( | 465 codePositionRecorder.registerPositions( |
| 452 node, startPosition, endPosition, closingPosition); | 466 node, startPosition, endPosition, closingPosition); |
| 453 } | 467 } |
| 454 } | 468 } |
| 455 | 469 |
| 456 /// Visitor that computes [SourceInformation] for a [js.Node] using information | 470 /// Visitor that computes [SourceInformation] for a [js.Node] using information |
| 457 /// attached to the node itself or alternatively from child nodes. | 471 /// attached to the node itself or alternatively from child nodes. |
| 458 class NodeSourceInformation extends js.BaseVisitor<SourceInformation> { | 472 class NodeSourceInformation extends js.BaseVisitor<SourceInformation> { |
| 459 const NodeSourceInformation(); | 473 final SourceInformationReader reader; |
| 474 |
| 475 const NodeSourceInformation(this.reader); |
| 460 | 476 |
| 461 SourceInformation visit(js.Node node) => node?.accept(this); | 477 SourceInformation visit(js.Node node) => node?.accept(this); |
| 462 | 478 |
| 463 @override | 479 @override |
| 464 SourceInformation visitNode(js.Node node) => node.sourceInformation; | 480 SourceInformation visitNode(js.Node node) => |
| 481 reader.getSourceInformation(node); |
| 465 | 482 |
| 466 @override | 483 @override |
| 467 SourceInformation visitExpressionStatement(js.ExpressionStatement node) { | 484 SourceInformation visitExpressionStatement(js.ExpressionStatement node) { |
| 468 if (node.sourceInformation != null) { | 485 SourceInformation sourceInformation = reader.getSourceInformation(node); |
| 469 return node.sourceInformation; | 486 if (sourceInformation != null) { |
| 487 return sourceInformation; |
| 470 } | 488 } |
| 471 return visit(node.expression); | 489 return visit(node.expression); |
| 472 } | 490 } |
| 473 | 491 |
| 474 @override | 492 @override |
| 475 SourceInformation visitVariableDeclarationList( | 493 SourceInformation visitVariableDeclarationList( |
| 476 js.VariableDeclarationList node) { | 494 js.VariableDeclarationList node) { |
| 477 if (node.sourceInformation != null) { | 495 SourceInformation sourceInformation = reader.getSourceInformation(node); |
| 478 return node.sourceInformation; | 496 if (sourceInformation != null) { |
| 497 return sourceInformation; |
| 479 } | 498 } |
| 480 for (js.Node declaration in node.declarations) { | 499 for (js.Node declaration in node.declarations) { |
| 481 SourceInformation sourceInformation = visit(declaration); | 500 SourceInformation sourceInformation = visit(declaration); |
| 482 if (sourceInformation != null) { | 501 if (sourceInformation != null) { |
| 483 return sourceInformation; | 502 return sourceInformation; |
| 484 } | 503 } |
| 485 } | 504 } |
| 486 return null; | 505 return null; |
| 487 } | 506 } |
| 488 | 507 |
| 489 @override | 508 @override |
| 490 SourceInformation visitVariableInitialization( | 509 SourceInformation visitVariableInitialization( |
| 491 js.VariableInitialization node) { | 510 js.VariableInitialization node) { |
| 492 if (node.sourceInformation != null) { | 511 SourceInformation sourceInformation = reader.getSourceInformation(node); |
| 493 return node.sourceInformation; | 512 if (sourceInformation != null) { |
| 513 return sourceInformation; |
| 494 } | 514 } |
| 495 return visit(node.value); | 515 return visit(node.value); |
| 496 } | 516 } |
| 497 | 517 |
| 498 @override | 518 @override |
| 499 SourceInformation visitAssignment(js.Assignment node) { | 519 SourceInformation visitAssignment(js.Assignment node) { |
| 500 if (node.sourceInformation != null) { | 520 SourceInformation sourceInformation = reader.getSourceInformation(node); |
| 501 return node.sourceInformation; | 521 if (sourceInformation != null) { |
| 522 return sourceInformation; |
| 502 } | 523 } |
| 503 return visit(node.value); | 524 return visit(node.value); |
| 504 } | 525 } |
| 505 } | 526 } |
| 506 | 527 |
| 507 /// Mixin that add support for computing [SourceInformation] for a [js.Node]. | 528 /// Mixin that add support for computing [SourceInformation] for a [js.Node]. |
| 508 class NodeToSourceInformationMixin { | 529 abstract class NodeToSourceInformationMixin { |
| 530 SourceInformationReader get reader; |
| 531 |
| 509 SourceInformation computeSourceInformation(js.Node node) { | 532 SourceInformation computeSourceInformation(js.Node node) { |
| 510 return const NodeSourceInformation().visit(node); | 533 return new NodeSourceInformation(reader).visit(node); |
| 511 } | 534 } |
| 512 } | 535 } |
| 513 | 536 |
| 514 /// [TraceListener] that register [SourceLocation]s with a [SourceMapper]. | 537 /// [TraceListener] that register [SourceLocation]s with a [SourceMapper]. |
| 515 class PositionTraceListener extends TraceListener | 538 class PositionTraceListener extends TraceListener |
| 516 with NodeToSourceInformationMixin { | 539 with NodeToSourceInformationMixin { |
| 517 final SourceMapper sourceMapper; | 540 final SourceMapper sourceMapper; |
| 541 final SourceInformationReader reader; |
| 518 | 542 |
| 519 PositionTraceListener(this.sourceMapper); | 543 PositionTraceListener(this.sourceMapper, this.reader); |
| 520 | 544 |
| 521 @override | 545 @override |
| 522 void onStep(js.Node node, Offset offset, StepKind kind) { | 546 void onStep(js.Node node, Offset offset, StepKind kind) { |
| 523 int codeLocation = offset.value; | 547 int codeLocation = offset.value; |
| 524 if (codeLocation == null) return; | 548 if (codeLocation == null) return; |
| 525 | 549 |
| 526 if (kind == StepKind.NO_INFO) { | 550 if (kind == StepKind.NO_INFO) { |
| 527 sourceMapper.register(node, codeLocation, const NoSourceLocationMarker()); | 551 sourceMapper.register(node, codeLocation, const NoSourceLocationMarker()); |
| 528 return; | 552 return; |
| 529 } | 553 } |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 741 | 765 |
| 742 /// Called when [node] defines a step of the given [kind] at the given | 766 /// Called when [node] defines a step of the given [kind] at the given |
| 743 /// [offset] when the generated JavaScript code. | 767 /// [offset] when the generated JavaScript code. |
| 744 void onStep(js.Node node, Offset offset, StepKind kind) {} | 768 void onStep(js.Node node, Offset offset, StepKind kind) {} |
| 745 } | 769 } |
| 746 | 770 |
| 747 /// Visitor that computes the [js.Node]s the are part of the JavaScript | 771 /// Visitor that computes the [js.Node]s the are part of the JavaScript |
| 748 /// steppable execution and thus needs source mapping locations. | 772 /// steppable execution and thus needs source mapping locations. |
| 749 class JavaScriptTracer extends js.BaseVisitor { | 773 class JavaScriptTracer extends js.BaseVisitor { |
| 750 final CodePositionMap codePositions; | 774 final CodePositionMap codePositions; |
| 775 final SourceInformationReader reader; |
| 751 final List<TraceListener> listeners; | 776 final List<TraceListener> listeners; |
| 752 | 777 |
| 753 /// The steps added by subexpressions. | 778 /// The steps added by subexpressions. |
| 754 List steps = []; | 779 List steps = []; |
| 755 | 780 |
| 756 /// The offset of the current statement. | 781 /// The offset of the current statement. |
| 757 int statementOffset; | 782 int statementOffset; |
| 758 | 783 |
| 759 /// The current offset in left-to-right progression. | 784 /// The current offset in left-to-right progression. |
| 760 int leftToRightOffset; | 785 int leftToRightOffset; |
| 761 | 786 |
| 762 /// The offset of the surrounding statement, used for the first subexpression. | 787 /// The offset of the surrounding statement, used for the first subexpression. |
| 763 int offsetPosition; | 788 int offsetPosition; |
| 764 | 789 |
| 765 bool active; | 790 bool active; |
| 766 | 791 |
| 767 JavaScriptTracer(this.codePositions, this.listeners, {this.active: false}); | 792 JavaScriptTracer(this.codePositions, this.reader, this.listeners, |
| 793 {this.active: false}); |
| 768 | 794 |
| 769 void notifyStart(js.Node node) { | 795 void notifyStart(js.Node node) { |
| 770 listeners.forEach((listener) => listener.onStart(node)); | 796 listeners.forEach((listener) => listener.onStart(node)); |
| 771 } | 797 } |
| 772 | 798 |
| 773 void notifyEnd(js.Node node) { | 799 void notifyEnd(js.Node node) { |
| 774 listeners.forEach((listener) => listener.onEnd(node)); | 800 listeners.forEach((listener) => listener.onEnd(node)); |
| 775 } | 801 } |
| 776 | 802 |
| 777 void notifyPushBranch(BranchKind kind, [value]) { | 803 void notifyPushBranch(BranchKind kind, [value]) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 826 for (js.Node node in nodeList) { | 852 for (js.Node node in nodeList) { |
| 827 visit(node); | 853 visit(node); |
| 828 } | 854 } |
| 829 } | 855 } |
| 830 } | 856 } |
| 831 | 857 |
| 832 @override | 858 @override |
| 833 visitFun(js.Fun node) { | 859 visitFun(js.Fun node) { |
| 834 bool activeBefore = active; | 860 bool activeBefore = active; |
| 835 if (!active) { | 861 if (!active) { |
| 836 active = node.sourceInformation != null; | 862 active = reader.getSourceInformation(node) != null; |
| 837 } | 863 } |
| 838 leftToRightOffset = | 864 leftToRightOffset = |
| 839 statementOffset = getSyntaxOffset(node, kind: CodePositionKind.START); | 865 statementOffset = getSyntaxOffset(node, kind: CodePositionKind.START); |
| 840 Offset entryOffset = getOffsetForNode(node, statementOffset); | 866 Offset entryOffset = getOffsetForNode(node, statementOffset); |
| 841 notifyStep(node, entryOffset, StepKind.FUN_ENTRY); | 867 notifyStep(node, entryOffset, StepKind.FUN_ENTRY); |
| 842 | 868 |
| 843 visit(node.body); | 869 visit(node.body); |
| 844 | 870 |
| 845 leftToRightOffset = | 871 leftToRightOffset = |
| 846 statementOffset = getSyntaxOffset(node, kind: CodePositionKind.CLOSING); | 872 statementOffset = getSyntaxOffset(node, kind: CodePositionKind.CLOSING); |
| (...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1272 } | 1298 } |
| 1273 return sb.toString(); | 1299 return sb.toString(); |
| 1274 } | 1300 } |
| 1275 | 1301 |
| 1276 String toString() => getCoverageReport(); | 1302 String toString() => getCoverageReport(); |
| 1277 } | 1303 } |
| 1278 | 1304 |
| 1279 /// [TraceListener] that registers [onStep] callbacks with [coverage]. | 1305 /// [TraceListener] that registers [onStep] callbacks with [coverage]. |
| 1280 class CoverageListener extends TraceListener with NodeToSourceInformationMixin { | 1306 class CoverageListener extends TraceListener with NodeToSourceInformationMixin { |
| 1281 final Coverage coverage; | 1307 final Coverage coverage; |
| 1308 final SourceInformationReader reader; |
| 1282 | 1309 |
| 1283 CoverageListener(this.coverage); | 1310 CoverageListener(this.coverage, this.reader); |
| 1284 | 1311 |
| 1285 @override | 1312 @override |
| 1286 void onStep(js.Node node, Offset offset, StepKind kind) { | 1313 void onStep(js.Node node, Offset offset, StepKind kind) { |
| 1287 SourceInformation sourceInformation = computeSourceInformation(node); | 1314 SourceInformation sourceInformation = computeSourceInformation(node); |
| 1288 if (sourceInformation != null) { | 1315 if (sourceInformation != null) { |
| 1289 coverage.registerNodeWithInfo(node); | 1316 coverage.registerNodeWithInfo(node); |
| 1290 } else { | 1317 } else { |
| 1291 coverage.registerNodeWithoutInfo(node); | 1318 coverage.registerNodeWithoutInfo(node); |
| 1292 } | 1319 } |
| 1293 } | 1320 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1307 | 1334 |
| 1308 @override | 1335 @override |
| 1309 CodePosition operator [](js.Node node) { | 1336 CodePosition operator [](js.Node node) { |
| 1310 CodePosition codePosition = codePositions[node]; | 1337 CodePosition codePosition = codePositions[node]; |
| 1311 if (codePosition == null) { | 1338 if (codePosition == null) { |
| 1312 coverage.registerNodesWithoutOffset(node); | 1339 coverage.registerNodesWithoutOffset(node); |
| 1313 } | 1340 } |
| 1314 return codePosition; | 1341 return codePosition; |
| 1315 } | 1342 } |
| 1316 } | 1343 } |
| OLD | NEW |