Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(472)

Side by Side Diff: tests/compiler/dart2js/sourcemaps/diff_view.dart

Issue 1752393002: Add source mappings and inlined Dart code to diff_view. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Updated cf. comments. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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 library sourcemap.diff_view; 5 library sourcemap.diff_view;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:convert'; 8 import 'dart:convert';
9 import 'dart:io'; 9 import 'dart:io';
10 10
11 import 'package:compiler/src/common.dart';
11 import 'package:compiler/src/commandline_options.dart'; 12 import 'package:compiler/src/commandline_options.dart';
12 import 'package:compiler/src/diagnostics/invariant.dart'; 13 import 'package:compiler/src/diagnostics/invariant.dart';
13 import 'package:compiler/src/elements/elements.dart'; 14 import 'package:compiler/src/elements/elements.dart';
14 import 'package:compiler/src/io/position_information.dart'; 15 import 'package:compiler/src/io/position_information.dart';
15 import 'package:compiler/src/io/source_information.dart'; 16 import 'package:compiler/src/io/source_information.dart';
16 import 'package:compiler/src/io/source_file.dart'; 17 import 'package:compiler/src/io/source_file.dart';
17 import 'package:compiler/src/js/js.dart' as js; 18 import 'package:compiler/src/js/js.dart' as js;
18 import 'package:compiler/src/js/js_debug.dart'; 19 import 'package:compiler/src/js/js_debug.dart';
19 20
20 import 'diff.dart'; 21 import 'diff.dart';
21 import 'html_parts.dart'; 22 import 'html_parts.dart';
22 import 'js_tracer.dart'; 23 import 'js_tracer.dart';
23 import 'output_structure.dart'; 24 import 'output_structure.dart';
24 import 'sourcemap_helper.dart'; 25 import 'sourcemap_helper.dart';
25 import 'sourcemap_html_helper.dart'; 26 import 'sourcemap_html_helper.dart';
26 import 'trace_graph.dart'; 27 import 'trace_graph.dart';
27 28
28 const String WITH_SOURCE_INFO_STYLE = 'border: solid 1px #FF8080;';
29 const String WITHOUT_SOURCE_INFO_STYLE = 'background-color: #8080FF;';
30 const String ADDITIONAL_SOURCE_INFO_STYLE = 'border: solid 1px #80FF80;';
31 const String UNUSED_SOURCE_INFO_STYLE = 'border: solid 1px #8080FF;';
32
33 main(List<String> args) async { 29 main(List<String> args) async {
34 DEBUG_MODE = true; 30 DEBUG_MODE = true;
35 String out = 'out.js.diff_view.html'; 31 String out = 'out.js.diff_view.html';
36 String filename; 32 String filename;
37 List<String> currentOptions = []; 33 List<String> currentOptions = [];
38 List<List<String>> optionSegments = [currentOptions]; 34 List<List<String>> optionSegments = [currentOptions];
39 Map<int, String> loadFrom = {}; 35 Map<int, String> loadFrom = {};
40 Map<int, String> saveTo = {}; 36 Map<int, String> saveTo = {};
41 int argGroup = 0; 37 int argGroup = 0;
42 bool addAnnotations = true; 38 bool showAnnotations = true;
43 for (String arg in args) { 39 for (String arg in args) {
44 if (arg == '--') { 40 if (arg == '--') {
45 currentOptions = []; 41 currentOptions = [];
46 optionSegments.add(currentOptions); 42 optionSegments.add(currentOptions);
47 argGroup++; 43 argGroup++;
48 } else if (arg == '-h') { 44 } else if (arg == '-h') {
49 addAnnotations = false; 45 showAnnotations = false;
50 print('Hiding annotations'); 46 print('Hiding annotations');
51 } else if (arg == '-l') { 47 } else if (arg == '-l') {
52 loadFrom[argGroup] = 'out.js.diff$argGroup.json'; 48 loadFrom[argGroup] = 'out.js.diff$argGroup.json';
53 } else if (arg.startsWith('--load=')) { 49 } else if (arg.startsWith('--load=')) {
54 loadFrom[argGroup] = arg.substring('--load='.length); 50 loadFrom[argGroup] = arg.substring('--load='.length);
55 } else if (arg == '-s') { 51 } else if (arg == '-s') {
56 saveTo[argGroup] = 'out.js.diff$argGroup.json'; 52 saveTo[argGroup] = 'out.js.diff$argGroup.json';
57 } else if (arg.startsWith('--save=')) { 53 } else if (arg.startsWith('--save=')) {
58 saveTo[argGroup] = arg.substring('--save='.length); 54 saveTo[argGroup] = arg.substring('--save='.length);
59 } else if (arg.startsWith('-o')) { 55 } else if (arg.startsWith('-o')) {
(...skipping 25 matching lines...) Expand all
85 81
86 SourceFileManager sourceFileManager = new IOSourceFileManager(Uri.base); 82 SourceFileManager sourceFileManager = new IOSourceFileManager(Uri.base);
87 List<AnnotatedOutput> outputs = <AnnotatedOutput>[]; 83 List<AnnotatedOutput> outputs = <AnnotatedOutput>[];
88 for (int i = 0; i < 2; i++) { 84 for (int i = 0; i < 2; i++) {
89 AnnotatedOutput output; 85 AnnotatedOutput output;
90 if (loadFrom.containsKey(i)) { 86 if (loadFrom.containsKey(i)) {
91 output = AnnotatedOutput.loadOutput(loadFrom[i]); 87 output = AnnotatedOutput.loadOutput(loadFrom[i]);
92 } else { 88 } else {
93 print('Compiling ${options[i].join(' ')} $filename'); 89 print('Compiling ${options[i].join(' ')} $filename');
94 CodeLinesResult result = await computeCodeLines( 90 CodeLinesResult result = await computeCodeLines(
95 options[i], filename, addAnnotations: addAnnotations); 91 options[i], filename);
96 OutputStructure structure = OutputStructure.parse(result.codeLines); 92 OutputStructure structure = OutputStructure.parse(result.codeLines);
97 computeEntityCodeSources(result, structure); 93 computeEntityCodeSources(result, structure);
98 output = new AnnotatedOutput( 94 output = new AnnotatedOutput(
99 filename, 95 filename,
100 options[i], 96 options[i],
101 structure, 97 structure,
102 result.coverage.getCoverageReport()); 98 result.coverage.getCoverageReport());
103 } 99 }
104 if (saveTo.containsKey(i)) { 100 if (saveTo.containsKey(i)) {
105 AnnotatedOutput.saveOutput(output, saveTo[i]); 101 AnnotatedOutput.saveOutput(output, saveTo[i]);
106 } 102 }
107 outputs.add(output); 103 outputs.add(output);
108 } 104 }
109 105
110 List<DiffBlock> blocks = createDiffBlocks( 106 List<DiffBlock> blocks = createDiffBlocks(
111 outputs.map((o) => o.structure).toList(), 107 outputs.map((o) => o.structure).toList(),
112 sourceFileManager); 108 sourceFileManager);
113 109
114 outputDiffView( 110 outputDiffView(
115 out, outputs, blocks, addAnnotations: addAnnotations); 111 out, outputs, blocks,
112 showMarkers: showAnnotations,
113 showSourceMapped: showAnnotations);
116 } 114 }
117 115
118 /// Attaches [CodeSource]s to the entities in [structure] using the 116 /// Attaches [CodeSource]s to the entities in [structure] using the
119 /// element-to-offset in [result]. 117 /// element-to-offset in [result].
120 void computeEntityCodeSources( 118 void computeEntityCodeSources(
121 CodeLinesResult result, OutputStructure structure) { 119 CodeLinesResult result, OutputStructure structure) {
122 result.elementMap.forEach((int line, Element element) { 120 result.elementMap.forEach((int line, Element element) {
123 OutputEntity entity = structure.getEntityForLine(line); 121 OutputEntity entity = structure.getEntityForLine(line);
124 if (entity != null) { 122 if (entity != null) {
125 entity.codeSource = codeSourceFromElement(element); 123 entity.codeSource = codeSourceFromElement(element);
126 } 124 }
127 }); 125 });
128 } 126 }
129 127
128 class CodeLineAnnotationJsonStrategy implements JsonStrategy {
129 const CodeLineAnnotationJsonStrategy();
130
131 Map encodeAnnotation(Annotation annotation) {
132 CodeLineAnnotation data = annotation.data;
133 return {
134 'id': annotation.id,
135 'codeOffset': annotation.codeOffset,
136 'title': annotation.title,
137 'data': data.toJson(this),
138 };
139 }
140
141 Annotation decodeAnnotation(Map json) {
142 return new Annotation(
143 json['id'],
144 json['codeOffset'],
145 json['title'],
146 data: CodeLineAnnotation.fromJson(json['data'], this));
147 }
148
149 @override
150 decodeLineAnnotation(json) {
151 if (json != null) {
152 return CodeSource.fromJson(json);
153 }
154 return null;
155 }
156
157 @override
158 encodeLineAnnotation(CodeSource lineAnnotation) {
159 if (lineAnnotation != null) {
160 return lineAnnotation.toJson();
161 }
162 return null;
163 }
164 }
165
130 /// The structured output of a compilation. 166 /// The structured output of a compilation.
131 class AnnotatedOutput { 167 class AnnotatedOutput {
132 final String filename; 168 final String filename;
133 final List<String> options; 169 final List<String> options;
134 final OutputStructure structure; 170 final OutputStructure structure;
135 final String coverage; 171 final String coverage;
136 172
137 AnnotatedOutput(this.filename, this.options, this.structure, this.coverage); 173 AnnotatedOutput(this.filename, this.options, this.structure, this.coverage);
138 174
139 List<CodeLine> get codeLines => structure.lines; 175 List<CodeLine> get codeLines => structure.lines;
140 176
141 Map toJson() { 177 Map toJson() {
142 return { 178 return {
143 'filename': filename, 179 'filename': filename,
144 'options': options, 180 'options': options,
145 'structure': structure.toJson(), 181 'structure': structure.toJson(const CodeLineAnnotationJsonStrategy()),
146 'coverage': coverage, 182 'coverage': coverage,
147 }; 183 };
148 } 184 }
149 185
150 static AnnotatedOutput fromJson(Map json) { 186 static AnnotatedOutput fromJson(Map json) {
151 String filename = json['filename']; 187 String filename = json['filename'];
152 List<String> options = json['options']; 188 List<String> options = json['options'];
153 OutputStructure structure = OutputStructure.fromJson(json['structure']); 189 OutputStructure structure = OutputStructure.fromJson(
190 json['structure'], const CodeLineAnnotationJsonStrategy());
154 String coverage = json['coverage']; 191 String coverage = json['coverage'];
155 return new AnnotatedOutput(filename, options, structure, coverage); 192 return new AnnotatedOutput(filename, options, structure, coverage);
156 } 193 }
157 194
158 static AnnotatedOutput loadOutput(filename) { 195 static AnnotatedOutput loadOutput(filename) {
159 AnnotatedOutput output = AnnotatedOutput.fromJson( 196 AnnotatedOutput output = AnnotatedOutput.fromJson(
160 JSON.decode(new File(filename).readAsStringSync())); 197 JSON.decode(new File(filename).readAsStringSync()));
161 print('Output loaded from $filename'); 198 print('Output loaded from $filename');
162 return output; 199 return output;
163 } 200 }
164 201
165 static void saveOutput(AnnotatedOutput output, String filename) { 202 static void saveOutput(AnnotatedOutput output, String filename) {
166 if (filename != null) { 203 if (filename != null) {
167 new File(filename).writeAsStringSync( 204 new File(filename).writeAsStringSync(
168 const JsonEncoder.withIndent(' ').convert(output.toJson())); 205 const JsonEncoder.withIndent(' ').convert(output.toJson()));
169 print('Output saved in $filename'); 206 print('Output saved in $filename');
170 } 207 }
171 } 208 }
172 } 209 }
173 210
174 void outputDiffView( 211 void outputDiffView(
175 String out, 212 String out,
176 List<AnnotatedOutput> outputs, 213 List<AnnotatedOutput> outputs,
177 List<DiffBlock> blocks, 214 List<DiffBlock> blocks,
178 {bool addAnnotations: true}) { 215 {bool showMarkers: true,
216 bool showSourceMapped: true}) {
179 assert(outputs[0].filename == outputs[1].filename); 217 assert(outputs[0].filename == outputs[1].filename);
180 bool usePre = true; 218 bool usePre = true;
181 219
182 StringBuffer sb = new StringBuffer(); 220 StringBuffer sb = new StringBuffer();
183 sb.write(''' 221 sb.write('''
184 <html> 222 <html>
185 <head> 223 <head>
186 <title>Diff for ${outputs[0].filename}</title> 224 <title>Diff for ${outputs[0].filename}</title>
187 <style> 225 <style>
188 .lineNumber { 226 .${ClassNames.lineNumber} {
189 font-size: smaller; 227 font-size: smaller;
190 color: #888; 228 color: #888;
191 } 229 }
192 .comment { 230 .${ClassNames.comment} {
193 font-size: smaller; 231 font-size: smaller;
194 color: #888; 232 color: #888;
195 font-family: initial; 233 font-family: initial;
196 } 234 }
197 .header { 235 .${ClassNames.header} {
198 position: fixed; 236 position: fixed;
199 width: 100%; 237 width: 100%;
200 background-color: #FFFFFF; 238 background-color: #FFFFFF;
201 left: 0px; 239 left: 0px;
202 top: 0px; 240 top: 0px;
203 height: 42px; 241 height: 42px;
204 z-index: 1000; 242 z-index: 1000;
205 } 243 }
206 .header-table { 244 .${ClassNames.headerTable} {
207 width: 100%; 245 width: 100%;
208 background-color: #400000; 246 background-color: #400000;
209 color: #FFFFFF; 247 color: #FFFFFF;
210 border-spacing: 0px; 248 border-spacing: 0px;
211 } 249 }
212 .header-column { 250 .${ClassNames.headerColumn} {
213 width: 34%;
214 } 251 }
215 .legend { 252 .${ClassNames.legend} {
216 padding: 2px; 253 padding: 2px;
217 } 254 }
218 .table { 255 .${ClassNames.buttons} {
256 position: fixed;
257 right: 0px;
258 top: 0px;
259 width: 220px;
260 background-color: #FFFFFF;
261 border: 1px solid #C0C0C0;
262 z-index: 2000;
263 }
264 .${ClassNames.table} {
219 position: absolute; 265 position: absolute;
220 left: 0px; 266 left: 0px;
221 top: 42px; 267 top: 42px;
222 width: 100%; 268 width: 100%;
223 border-spacing: 0px; 269 border-spacing: 0px;
224 } 270 }
225 .cell { 271 .${ClassNames.cell},
226 max-width: 500px; 272 .${ClassNames.innerCell},
273 .${ClassNames.originalDart},
274 .${ClassNames.inlinedDart} {
227 overflow-y: hidden; 275 overflow-y: hidden;
228 vertical-align: top; 276 vertical-align: top;
229 border-top: 1px solid #F0F0F0;
230 border-left: 1px solid #F0F0F0;
231 '''); 277 ''');
232 if (usePre) { 278 if (usePre) {
233 sb.write(''' 279 sb.write('''
234 overflow-x: hidden; 280 overflow-x: hidden;
235 white-space: pre-wrap; 281 white-space: pre-wrap;
236 '''); 282 ''');
237 } else { 283 } else {
238 sb.write(''' 284 sb.write('''
239 overflow-x: hidden; 285 overflow-x: hidden;
240 padding-left: 100px; 286 padding-left: 100px;
241 text-indent: -100px; 287 text-indent: -100px;
242 '''); 288 ''');
243 } 289 }
244 sb.write(''' 290 sb.write('''
245 font-family: monospace; 291 font-family: monospace;
246 padding: 0px; 292 padding: 0px;
247 } 293 }
248 .corresponding1 { 294 .${ClassNames.cell} {
295 border-top: 1px solid #F0F0F0;
296 border-left: 1px solid #C0C0C0;
297 }
298 .${ClassNames.innerCell} {
299 /*border-top: 1px solid #F8F8F8;*/
300 width: 50%;
301 max-width: 250px;
302 }
303 .${ClassNames.corresponding(false)} {
249 background-color: #FFFFE0; 304 background-color: #FFFFE0;
250 } 305 }
251 .corresponding2 { 306 .${ClassNames.corresponding(true)} {
252 background-color: #EFEFD0; 307 background-color: #EFEFD0;
253 } 308 }
254 .identical1 { 309 .${ClassNames.identical(false)} {
255 background-color: #E0F0E0; 310 background-color: #E0F0E0;
256 } 311 }
257 .identical2 { 312 .${ClassNames.identical(true)} {
258 background-color: #C0E0C0; 313 background-color: #C0E0C0;
259 } 314 }
260 .line { 315 .${ClassNames.line} {
261 padding-left: 7em; 316 padding-left: 7em;
262 text-indent: -7em; 317 text-indent: -7em;
263 margin: 0px; 318 margin: 0px;
264 } 319 }
265 .column0 { 320 .${ClassNames.column(column_js0)} {
321 max-width: 500px;
322 width: 500px;
266 } 323 }
267 .column1 { 324 .${ClassNames.column(column_js1)} {
325 max-width: 500px;
326 width: 500px;
268 } 327 }
269 .column2 { 328 .${ClassNames.column(column_dart)} {
329 max-width: 300px;
330 width: 300px;
331 }
332 .${ClassNames.colored(0)} {
333 color: #FF0000;
334 }
335 .${ClassNames.colored(1)} {
336 color: #C0C000;
337 }
338 .${ClassNames.colored(2)} {
339 color: #008000;
340 }
341 .${ClassNames.colored(3)} {
342 color: #00C0C0;
343 }
344 .${ClassNames.withSourceInfo} {
345 border: solid 1px #FF8080;
346 }
347 .${ClassNames.withoutSourceInfo} {
348 background-color: #8080FF;
349 }
350 .${ClassNames.additionalSourceInfo} {
351 border: solid 1px #80FF80;
352 }
353 .${ClassNames.unusedSourceInfo} {
354 border: solid 1px #8080FF;
355 }
356 .${ClassNames.originalDart} {
357 }
358 .${ClassNames.inlinedDart} {
359 }
360 ''');
361 for (int i = 0; i < HUE_COUNT; i++) {
362 sb.write('''
363 .${ClassNames.sourceMappingIndex(i)} {
364 background-color: ${toColorCss(i)};
365 }
366 ''');
367 }
368 sb.write('''
369 .${ClassNames.sourceMapped} {
370 ${showSourceMapped ? '' : 'display: none;'}
371 }
372 .${ClassNames.sourceMapping} {
373 ${showSourceMapped ? '' : 'border: 0px;'}
374 ${showSourceMapped ? '' : 'background-color: transparent;'}
375 }
376 .${ClassNames.markers} {
377 ${showMarkers ? '' : 'display: none;'}
378 }
379 .${ClassNames.marker} {
380 ${showMarkers ? '' : 'border: 0px;'}
381 ${showMarkers ? '' : 'background-color: transparent;'}
270 } 382 }
271 </style> 383 </style>
384 <script>
385 function isChecked(name) {
386 var box = document.getElementById('box-' + name);
387 return box.checked;
388 }
389 function toggleDisplay(name) {
390 var checked = isChecked(name);
391 var styleSheet = document.styleSheets[0];
392 for (var index = 0; index < styleSheet.cssRules.length; index++) {
393 var cssRule = styleSheet.cssRules[index];
394 if (cssRule.selectorText == '.' + name) {
395 if (checked) {
396 cssRule.style.removeProperty('display');
397 } else {
398 cssRule.style.display = 'none';
399 }
400 }
401 }
402 return checked;
403 }
404 function toggle${ClassNames.sourceMapped}() {
405 var checked = toggleDisplay('${ClassNames.sourceMapped}');
406 toggleAnnotations(checked, '${ClassNames.sourceMapping}');
407 }
408 function toggle${ClassNames.markers}() {
409 var checked = toggleDisplay('${ClassNames.markers}');
410 toggleAnnotations(checked, '${ClassNames.marker}');
411 }
412 function toggleAnnotations(show, name) {
413 var styleSheet = document.styleSheets[0];
414 for (var index = 0; index < styleSheet.cssRules.length; index++) {
415 var cssRule = styleSheet.cssRules[index];
416 if (cssRule.selectorText == '.' + name) {
417 if (show) {
418 cssRule.style.removeProperty('border');
419 cssRule.style.removeProperty('background-color');
420 } else {
421 cssRule.style.border = '0px';
422 cssRule.style.backgroundColor = 'transparent';
423 }
424 }
425 }
426 }
427 </script>
272 </head> 428 </head>
273 <body>'''); 429 <body>''');
274 430
275 sb.write(''' 431 sb.write('''
276 <div class="header"> 432 <div class="${ClassNames.header}">
277 <table class="header-table"><tr> 433 <div class="${ClassNames.legend}">
278 <td class="header-column">[${outputs[0].options.join(',')}]</td> 434 <span class="${ClassNames.identical(false)}">&nbsp;&nbsp;&nbsp;</span>
279 <td class="header-column">[${outputs[1].options.join(',')}]</td> 435 <span class="${ClassNames.identical(true)}">&nbsp;&nbsp;&nbsp;</span>
280 <td class="header-column">Dart code</td>
281 </tr></table>
282 <div class="legend">
283 <span class="identical1">&nbsp;&nbsp;&nbsp;</span>
284 <span class="identical2">&nbsp;&nbsp;&nbsp;</span>
285 identical blocks 436 identical blocks
286 <span class="corresponding1">&nbsp;&nbsp;&nbsp;</span> 437 <span class="${ClassNames.corresponding(false)}">&nbsp;&nbsp;&nbsp;</span>
287 <span class="corresponding2">&nbsp;&nbsp;&nbsp;</span> 438 <span class="${ClassNames.corresponding(true)}">&nbsp;&nbsp;&nbsp;</span>
288 corresponding blocks 439 corresponding blocks
289 '''); 440 ''');
290 441
291 if (addAnnotations) { 442 sb.write('''
292 sb.write(''' 443 <span class="${ClassNames.markers}">
293 <span style="$WITH_SOURCE_INFO_STYLE">&nbsp;&nbsp;&nbsp;</span> 444 <span class="${ClassNames.withSourceInfo}">&nbsp;&nbsp;&nbsp;</span>
294 <span title="'offset with source information' means that source information 445 <span title="'offset with source information' means that source information
295 is available for an offset which is expected to have a source location 446 is available for an offset which is expected to have a source location
296 attached. This offset has source information as intended."> 447 attached. This offset has source information as intended.">
297 offset with source information</span> 448 offset with source information</span>
298 <span style="$WITHOUT_SOURCE_INFO_STYLE">&nbsp;&nbsp;&nbsp;</span> 449 <span class="${ClassNames.withoutSourceInfo}">&nbsp;&nbsp;&nbsp;</span>
299 <span title="'offset without source information' means that _no_ source 450 <span title="'offset without source information' means that _no_ source
300 information is available for an offset which was expected to have a source 451 information is available for an offset which was expected to have a source
301 location attached. Source information must be found for this offset."> 452 location attached. Source information must be found for this offset.">
302 offset without source information</span> 453 offset without source information</span>
303 <span style="$ADDITIONAL_SOURCE_INFO_STYLE">&nbsp;&nbsp;&nbsp;</span> 454 <span class="${ClassNames.additionalSourceInfo}">&nbsp;&nbsp;&nbsp;</span>
304 <span title="'offset with unneeded source information' means that a source 455 <span title="'offset with unneeded source information' means that a source
305 location was attached to an offset which was _not_ expected to have a source 456 location was attached to an offset which was _not_ expected to have a source
306 location attached. The source location should be removed from this offset."> 457 location attached. The source location should be removed from this offset.">
307 offset with unneeded source information</span> 458 offset with unneeded source information</span>
308 <span style="$UNUSED_SOURCE_INFO_STYLE">&nbsp;&nbsp;&nbsp;</span> 459 <span class="${ClassNames.unusedSourceInfo}">&nbsp;&nbsp;&nbsp;</span>
309 <span title="'offset with unused source information' means that source 460 <span title="'offset with unused source information' means that source
310 information is available for an offset which is _not_ expected to have a source 461 information is available for an offset which is _not_ expected to have a source
311 location attached. This source information _could_ be used by a parent AST node 462 location attached. This source information _could_ be used by a parent AST node
312 offset that is an 'offset without source information'."> 463 offset that is an 'offset without source information'.">
313 offset with unused source information</span> 464 offset with unused source information</span>
465 </span>
466 <span class="${ClassNames.sourceMapped}">
314 '''); 467 ''');
468 for (int i = 0; i < HUE_COUNT; i++) {
469 sb.write('''
470 <span class="${ClassNames.sourceMappingIndex(i)}">&nbsp;&nbsp;</span>''');
315 } 471 }
316
317 sb.write(''' 472 sb.write('''
318 </div></div> 473 <span title="JavaScript offsets and their corresponding Dart Code offset
319 <table class="table"> 474 as mapped through source-maps.">
475 mapped source locations</span>
476 </span>
320 '''); 477 ''');
321 478
322 void addCell(String content) {
323 sb.write('''
324 <td class="cell"><pre>
325 ''');
326 sb.write(content);
327 sb.write('''
328 </pre></td>
329 ''');
330 }
331 479
332 /// Marker to alternate output colors. 480 /// Marker to alternate output colors.
333 bool alternating = false; 481 bool alternating = false;
334 482
335 List<HtmlPrintContext> printContexts = <HtmlPrintContext>[]; 483 List<HtmlPrintContext> printContexts = <HtmlPrintContext>[];
336 for (int i = 0; i < 2; i++) { 484 for (int i = 0; i < 2; i++) {
337 int lineNoWidth; 485 int lineNoWidth;
338 if (outputs[i].codeLines.isNotEmpty) { 486 if (outputs[i].codeLines.isNotEmpty) {
339 lineNoWidth = '${outputs[i].codeLines.last.lineNo + 1}'.length; 487 lineNoWidth = '${outputs[i].codeLines.last.lineNo + 1}'.length;
340 } 488 }
341 printContexts.add(new HtmlPrintContext(lineNoWidth: lineNoWidth)); 489 printContexts.add(new HtmlPrintContext(
490 lineNoWidth: lineNoWidth,
491 getAnnotationData: getAnnotationData,
492 getLineData: getLineData));
342 } 493 }
343 494
495 Set<DiffColumn> allColumns = new Set<DiffColumn>();
496 for (DiffBlock block in blocks) {
497 allColumns.addAll(block.columns);
498 }
499
500 List<DiffColumn> columns = [column_js0, column_js1, column_dart]
501 .where((c) => allColumns.contains(c)).toList();
502
503 sb.write('''
504 </div>
505 <table class="${ClassNames.headerTable}"><tr>''');
506 for (DiffColumn column in columns) {
507 sb.write('''
508 <td class="${ClassNames.headerColumn} ${ClassNames.column(column)}">''');
509 if (column.type == 'js') {
510 sb.write('''[${outputs[column.index].options.join(',')}]''');
511 } else {
512 sb.write('''Dart code''');
513 }
514 sb.write('''</td>''');
515 }
516
517 sb.write('''
518 </tr></table>
519 </div>
520 <table class="${ClassNames.table}">
521 ''');
522
344 for (DiffBlock block in blocks) { 523 for (DiffBlock block in blocks) {
345 String className; 524 String className;
346 switch (block.kind) { 525 switch (block.kind) {
347 case DiffKind.UNMATCHED: 526 case DiffKind.UNMATCHED:
348 className = 'cell'; 527 className = '${ClassNames.cell}';
349 break; 528 break;
350 case DiffKind.MATCHING: 529 case DiffKind.MATCHING:
351 className = 'cell corresponding${alternating ? '1' : '2'}'; 530 className =
531 '${ClassNames.cell} ${ClassNames.corresponding(alternating)}';
352 alternating = !alternating; 532 alternating = !alternating;
353 break; 533 break;
354 case DiffKind.IDENTICAL: 534 case DiffKind.IDENTICAL:
355 className = 'cell identical${alternating ? '1' : '2'}'; 535 className =
536 '${ClassNames.cell} ${ClassNames.identical(alternating)}';
356 alternating = !alternating; 537 alternating = !alternating;
357 break; 538 break;
358 } 539 }
359 sb.write('<tr>'); 540 sb.write('<tr>');
360 for (int index = 0; index < 3; index++) { 541 for (DiffColumn column in columns) {
361 sb.write('''<td class="$className column$index">'''); 542 sb.write('''<td class="$className ${ClassNames.column(column)}">''');
362 List<HtmlPart> lines = block.getColumn(index); 543 HtmlPrintContext context = new HtmlPrintContext(
363 if (lines.isNotEmpty) { 544 lineNoWidth: 4,
364 for (HtmlPart line in lines) { 545 includeAnnotation: (Annotation annotation) {
365 sb.write('<p class="line">'); 546 CodeLineAnnotation data = annotation.data;
366 if (index < printContexts.length) { 547 return data.annotationType == AnnotationType.WITH_SOURCE_INFO ||
367 line.printHtmlOn(sb, printContexts[index]); 548 data.annotationType == AnnotationType.ADDITIONAL_SOURCE_INFO;
368 } else { 549 },
369 line.printHtmlOn(sb, new HtmlPrintContext()); 550 getAnnotationData: getAnnotationData,
370 } 551 getLineData: getLineData);
371 sb.write('</p>'); 552 if (column.type == 'js') {
372 } 553 context = printContexts[column.index];
373 } 554 }
555 block.printHtmlOn(column, sb, context);
374 sb.write('''</td>'''); 556 sb.write('''</td>''');
375 } 557 }
376 sb.write('</tr>'); 558 sb.write('</tr>');
377 } 559 }
378 560
379 sb.write('''</tr><tr>'''); 561 sb.write('''</tr><tr>''');
380 562
381 addCell(outputs[0].coverage); 563 for (DiffColumn column in columns) {
382 addCell(outputs[1].coverage); 564 sb.write('''
565 <td class="${ClassNames.cell} ${ClassNames.column(column)}"><pre>''');
566 if (column.type == 'js') {
567 sb.write(outputs[column.index].coverage);
568 }
569 sb.write('''</td>''');
570 }
383 571
384 sb.write(''' 572 sb.write('''
385 </table> 573 </table>
574 <div class="${ClassNames.buttons}">
575 <input type="checkbox" id="box-${ClassNames.column(column_js0)}"
576 onclick="javascript:toggleDisplay('${ClassNames.column(column_js0)}')"
577 checked>
578 Left JavaScript code<br/>
579
580 <input type="checkbox" id="box-${ClassNames.column(column_js1)}"
581 onclick="javascript:toggleDisplay('${ClassNames.column(column_js1)}')"
582 checked>
583 Right JavaScript code<br/>
584
585 <input type="checkbox" id="box-${ClassNames.column(column_dart)}"
586 onclick="javascript:toggleDisplay('${ClassNames.column(column_dart)}')"
587 checked>
588 <span title="Show column with Dart code corresponding to the block.">
589 Dart code</span><br/>
590
591 <input type="checkbox" id="box-${ClassNames.inlinedDart}"
592 onclick="javascript:toggleDisplay('${ClassNames.inlinedDart}')" checked>
593 <span title="Show Dart code inlined into the block.">
594 Inlined Dart code</span><br/>
595
596 <input type="checkbox" id="box-${ClassNames.markers}"
597 onclick="javascript:toggle${ClassNames.markers}()"
598 ${showMarkers ? 'checked' : ''}>
599 <span title="Show markers for JavaScript offsets with source information.">
600 Source information markers</span><br/>
601
602 <input type="checkbox" id="box-${ClassNames.sourceMapped}"
603 onclick="javascript:toggle${ClassNames.sourceMapped}()"
604 ${showSourceMapped ? 'checked' : ''}>
605 <span title="Show line-per-line mappings of JavaScript to Dart code.">
606 Source mapped Dart code</span><br/>
607 </div>
386 </body> 608 </body>
387 </html> 609 </html>
388 '''); 610 ''');
389 611
390 new File(out).writeAsStringSync(sb.toString()); 612 new File(out).writeAsStringSync(sb.toString());
391 print('Diff generated in $out'); 613 print('Diff generated in $out');
392 } 614 }
393 615
394 class CodeLinesResult { 616 class CodeLinesResult {
395 final List<CodeLine> codeLines; 617 final List<CodeLine> codeLines;
396 final Coverage coverage; 618 final Coverage coverage;
397 final Map<int, Element> elementMap; 619 final Map<int, Element> elementMap;
398 final SourceFileManager sourceFileManager; 620 final SourceFileManager sourceFileManager;
399 621 final CodeSources codeSources;
400 CodeLinesResult(this.codeLines, this.coverage, 622
401 this.elementMap, this.sourceFileManager); 623 CodeLinesResult(
624 this.codeLines,
625 this.coverage,
626 this.elementMap,
627 this.sourceFileManager,
628 this.codeSources);
629 }
630
631 class CodeSources {
632 Map<Element, CodeSource> codeSourceMap = <Element, CodeSource>{};
633 Map<Uri, Map<Interval, CodeSource>> uriCodeSourceMap =
634 <Uri, Map<Interval, CodeSource>>{};
635
636 CodeSources(
637 SourceMapProcessor processor,
638 SourceMaps sourceMaps) {
639
640 CodeSource computeCodeSource(Element element) {
641 return codeSourceMap.putIfAbsent(element, () {
642 CodeSource codeSource = codeSourceFromElement(element);
643 if (codeSource.begin != null) {
644 Interval interval = new Interval(codeSource.begin, codeSource.end);
645 Map<Interval, CodeSource> intervals =
646 uriCodeSourceMap[codeSource.uri];
647 if (intervals == null) {
648 intervals = <Interval, CodeSource>{};
649 uriCodeSourceMap[codeSource.uri] = intervals;
650 } else {
651 for (Interval existingInterval in intervals.keys.toList()) {
652 if (existingInterval.contains(interval.from)) {
653 CodeSource existingCodeSource = intervals[existingInterval];
654 intervals.remove(existingInterval);
655 if (existingInterval.from < interval.from) {
656 Interval preInterval = new Interval(
657 existingInterval.from, interval.from);
658 intervals[preInterval] = existingCodeSource;
659 }
660 if (interval.to < existingInterval.to) {
661 Interval postInterval = new Interval(
662 interval.to, existingInterval.to);
663 intervals[postInterval] = existingCodeSource;
664 }
665 }
666 }
667 }
668 intervals[interval] = codeSource;
669 }
670 if (element is ClassElement) {
671 element.forEachLocalMember((Element member) {
672 codeSource.members.add(computeCodeSource(member));
673 });
674 element.implementation.forEachLocalMember((Element member) {
675 codeSource.members.add(computeCodeSource(member));
676 });
677 } else if (element is MemberElement) {
678 element.nestedClosures.forEach((Element closure) {
679 codeSource.members.add(computeCodeSource(closure));
680 });
681 }
682 return codeSource;
683 });
684 }
685
686 for (LibraryElement library in
687 sourceMaps.compiler.libraryLoader.libraries) {
688 library.forEachLocalMember(computeCodeSource);
689 library.implementation.forEachLocalMember(computeCodeSource);
690 }
691
692 uriCodeSourceMap.forEach((Uri uri, Map<Interval, CodeSource> intervals) {
693 List<Interval> sortedKeys = intervals.keys.toList()..sort(
694 (i1, i2) => i1.from.compareTo(i2.from));
695 Map<Interval, CodeSource> sortedintervals = <Interval, CodeSource>{};
696 sortedKeys.forEach((Interval interval) {
697 sortedintervals[interval] = intervals[interval];
698 });
699 uriCodeSourceMap[uri] = sortedintervals;
700 });
701 }
702
703 CodeSource sourceLocationToCodeSource(SourceLocation sourceLocation) {
704 Map<Interval, CodeSource> intervals =
705 uriCodeSourceMap[sourceLocation.sourceUri];
706 if (intervals == null) {
707 print('No code source for $sourceLocation(${sourceLocation.offset})');
708 print(' -- no intervals for ${sourceLocation.sourceUri}');
709 return null;
710 }
711 for (Interval interval in intervals.keys) {
712 if (interval.contains(sourceLocation.offset)) {
713 return intervals[interval];
714 }
715 }
716 print('No code source for $sourceLocation(${sourceLocation.offset})');
717 intervals.forEach((k, v) => print(' $k: ${v.name}'));
718 return null;
719 }
402 } 720 }
403 721
404 /// Compute [CodeLine]s and [Coverage] for [filename] using the given [options]. 722 /// Compute [CodeLine]s and [Coverage] for [filename] using the given [options].
405 Future<CodeLinesResult> computeCodeLines( 723 Future<CodeLinesResult> computeCodeLines(
406 List<String> options, 724 List<String> options,
407 String filename, 725 String filename) async {
408 {bool addAnnotations: true}) async {
409 SourceMapProcessor processor = new SourceMapProcessor(filename); 726 SourceMapProcessor processor = new SourceMapProcessor(filename);
410 SourceMaps sourceMaps = 727 SourceMaps sourceMaps =
411 await processor.process(options, perElement: true, forMain: true); 728 await processor.process(options, perElement: true, forMain: true);
412 729
413 const int WITH_SOURCE_INFO = 0; 730 CodeSources codeSources = new CodeSources(processor, sourceMaps);
414 const int WITHOUT_SOURCE_INFO = 1;
415 const int ADDITIONAL_SOURCE_INFO = 2;
416 const int UNUSED_SOURCE_INFO = 3;
417 731
418 SourceMapInfo info = sourceMaps.mainSourceMapInfo; 732 SourceMapInfo info = sourceMaps.mainSourceMapInfo;
419 733
734 int nextAnnotationId = 0;
420 List<CodeLine> codeLines; 735 List<CodeLine> codeLines;
421 Coverage coverage = new Coverage(); 736 Coverage coverage = new Coverage();
422 List<Annotation> annotations = <Annotation>[]; 737 Map<int, List<CodeLineAnnotation>> codeLineAnnotationMap =
423 738 <int, List<CodeLineAnnotation>>{};
424 void addAnnotation(int id, int offset, String title) { 739
425 annotations.add(new Annotation(id, offset, title)); 740 /// Create a [CodeLineAnnotation] for [codeOffset].
741 void addCodeLineAnnotation(
742 {AnnotationType annotationType,
743 int codeOffset,
744 List<SourceLocation> locations: const <SourceLocation>[],
745 String stepInfo}) {
746 if (annotationType == AnnotationType.WITHOUT_SOURCE_INFO ||
747 annotationType == AnnotationType.UNUSED_SOURCE_INFO) {
748 locations = [];
749 }
750 List<CodeLocation> codeLocations = locations
751 .map((l) => new CodeLocation(l.sourceUri, l.sourceName, l.offset))
752 .toList();
753 List<CodeSource> codeSourceList = locations
754 .map(codeSources.sourceLocationToCodeSource)
755 .where((c) => c != null)
756 .toList();
757 CodeLineAnnotation data = new CodeLineAnnotation(
758 annotationId: nextAnnotationId++,
759 annotationType: annotationType,
760 codeLocations: codeLocations,
761 codeSources: codeSourceList,
762 stepInfo: stepInfo);
763 codeLineAnnotationMap.putIfAbsent(
764 codeOffset, () => <CodeLineAnnotation>[]).add(data);
426 } 765 }
427 766
428 String code = info.code; 767 String code = info.code;
429 TraceGraph graph = createTraceGraph(info, coverage); 768 TraceGraph graph = createTraceGraph(info, coverage);
430 if (addAnnotations) { 769
431 Set<js.Node> mappedNodes = new Set<js.Node>(); 770 Set<js.Node> mappedNodes = new Set<js.Node>();
432 771
433 void addSourceLocations( 772 /// Add an annotation for [codeOffset] pointing to [locations].
434 int kind, int offset, List<SourceLocation> locations, String prefix) { 773 void addSourceLocations(
435 774 {AnnotationType annotationType,
436 addAnnotation(kind, offset, 775 int codeOffset,
437 '${prefix}${locations 776 List<SourceLocation> locations,
438 .where((l) => l != null) 777 String stepInfo}) {
439 .map((l) => l.shortText) 778 locations = locations.where((l) => l != null).toList();
440 .join('\n')}'); 779 addCodeLineAnnotation(
441 } 780 annotationType: annotationType,
442 781 codeOffset: codeOffset,
443 bool addSourceLocationsForNode(int kind, js.Node node, String prefix) { 782 stepInfo: stepInfo,
444 Map<int, List<SourceLocation>> locations = info.nodeMap[node]; 783 locations: locations);
445 if (locations == null || locations.isEmpty) { 784 }
446 return false; 785
447 } 786 /// Add annotations for all mappings created for [node].
448 locations.forEach( 787 bool addSourceLocationsForNode(
449 (int offset, List<SourceLocation> locations) { 788 {AnnotationType annotationType,
450 addSourceLocations(kind, offset, locations, 789 js.Node node,
451 '${prefix}\n${truncate(nodeToString(node), 80)}\n'); 790 String stepInfo}) {
452 }); 791 Map<int, List<SourceLocation>> locations = info.nodeMap[node];
453 mappedNodes.add(node); 792 if (locations == null || locations.isEmpty) {
454 return true; 793 return false;
455 } 794 }
456 795 locations.forEach((int offset, List<SourceLocation> locations) {
457 796 addSourceLocations(
458 for (TraceStep step in graph.steps) { 797 annotationType: annotationType,
459 String title = '${step.id}:${step.kind}:${step.offset}'; 798 codeOffset: offset,
460 if (!addSourceLocationsForNode(WITH_SOURCE_INFO, step.node, title)) { 799 locations: locations,
461 int offset; 800 stepInfo: stepInfo);
462 if (options.contains(USE_NEW_SOURCE_INFO)) {
463 offset = step.offset.subexpressionOffset;
464 } else {
465 offset = info.jsCodePositions[step.node].startPosition;
466 }
467 if (offset != null) {
468 addAnnotation(WITHOUT_SOURCE_INFO, offset, title);
469 }
470 }
471 }
472 for (js.Node node in info.nodeMap.nodes) {
473 if (!mappedNodes.contains(node)) {
474 addSourceLocationsForNode(ADDITIONAL_SOURCE_INFO, node, '');
475 }
476 }
477 SourceLocationCollector collector = new SourceLocationCollector();
478 info.node.accept(collector);
479 collector.sourceLocations.forEach(
480 (js.Node node, List<SourceLocation> locations) {
481 if (!mappedNodes.contains(node)) {
482 int offset = info.jsCodePositions[node].startPosition;
483 addSourceLocations(UNUSED_SOURCE_INFO, offset, locations, '');
484 }
485 }); 801 });
486 } 802 mappedNodes.add(node);
487 803 return true;
804 }
805
806 // Add annotations based on trace steps.
807 for (TraceStep step in graph.steps) {
808 String stepInfo = '${step.id}:${step.kind}:${step.offset}';
809 bool added = addSourceLocationsForNode(
810 annotationType: AnnotationType.WITH_SOURCE_INFO,
811 node: step.node,
812 stepInfo: stepInfo);
813 if (!added) {
814 int offset;
815 if (options.contains(USE_NEW_SOURCE_INFO)) {
816 offset = step.offset.subexpressionOffset;
817 } else {
818 offset = info.jsCodePositions[step.node].startPosition;
819 }
820 if (offset != null) {
821 addCodeLineAnnotation(
822 annotationType: AnnotationType.WITHOUT_SOURCE_INFO,
823 codeOffset: offset,
824 stepInfo: stepInfo);
825 }
826 }
827 }
828
829 // Add additional annotations for mappings created for particular nodes.
830 for (js.Node node in info.nodeMap.nodes) {
831 if (!mappedNodes.contains(node)) {
832 addSourceLocationsForNode(
833 annotationType: AnnotationType.ADDITIONAL_SOURCE_INFO,
834 node: node);
835 }
836 }
837
838 // Add annotations for unused source information associated with nodes.
839 SourceLocationCollector collector = new SourceLocationCollector();
840 info.node.accept(collector);
841 collector.sourceLocations.forEach(
842 (js.Node node, List<SourceLocation> locations) {
843 if (!mappedNodes.contains(node)) {
844 int offset = info.jsCodePositions[node].startPosition;
845 addSourceLocations(
846 annotationType: AnnotationType.UNUSED_SOURCE_INFO,
847 codeOffset: offset,
848 locations: locations);
849 }
850 });
851
852 // Assign consecutive ids to source mappings.
853 int nextSourceMappedLocationIndex = 0;
854 List<Annotation> annotations = <Annotation>[];
855 for (int codeOffset in codeLineAnnotationMap.keys.toList()..sort()) {
856 bool hasSourceMappedLocation = false;
857 for (CodeLineAnnotation data in codeLineAnnotationMap[codeOffset]) {
858 if (data.annotationType.isSourceMapped) {
859 data.sourceMappingIndex = nextSourceMappedLocationIndex;
860 hasSourceMappedLocation = true;
861 }
862 annotations.add(new Annotation(
863 data.annotationType.index,
864 codeOffset,
865 'id=${data.annotationId}',
866 data: data));
867 }
868 if (hasSourceMappedLocation) {
869 nextSourceMappedLocationIndex++;
870 }
871 }
872
873 // Associate JavaScript offsets with [Element]s.
488 StringSourceFile sourceFile = new StringSourceFile.fromName(filename, code); 874 StringSourceFile sourceFile = new StringSourceFile.fromName(filename, code);
489 Map<int, Element> elementMap = <int, Element>{}; 875 Map<int, Element> elementMap = <int, Element>{};
490 sourceMaps.elementSourceMapInfos.forEach( 876 sourceMaps.elementSourceMapInfos.forEach(
491 (Element element, SourceMapInfo info) { 877 (Element element, SourceMapInfo info) {
492 CodePosition position = info.jsCodePositions[info.node]; 878 CodePosition position = info.jsCodePositions[info.node];
493 elementMap[sourceFile.getLine(position.startPosition)] = element; 879 elementMap[sourceFile.getLine(position.startPosition)] = element;
494 }); 880 });
495 881
496 codeLines = convertAnnotatedCodeToCodeLines( 882 codeLines = convertAnnotatedCodeToCodeLines(code, annotations);
497 code, 883 return new CodeLinesResult(
498 annotations, 884 codeLines, coverage, elementMap,
499 colorScheme: new CustomColorScheme( 885 sourceMaps.sourceFileManager,
500 single: (int id) { 886 codeSources);
501 if (id == WITH_SOURCE_INFO) {
502 return WITH_SOURCE_INFO_STYLE;
503 } else if (id == ADDITIONAL_SOURCE_INFO) {
504 return ADDITIONAL_SOURCE_INFO_STYLE;
505 } else if (id == UNUSED_SOURCE_INFO) {
506 return UNUSED_SOURCE_INFO_STYLE;
507 }
508 return WITHOUT_SOURCE_INFO_STYLE;
509 },
510 multi: (List ids) {
511 if (ids.contains(WITH_SOURCE_INFO)) {
512 return WITH_SOURCE_INFO_STYLE;
513 } else if (ids.contains(ADDITIONAL_SOURCE_INFO)) {
514 return ADDITIONAL_SOURCE_INFO_STYLE;
515 } else if (ids.contains(UNUSED_SOURCE_INFO)) {
516 return UNUSED_SOURCE_INFO_STYLE;
517 }
518 return WITHOUT_SOURCE_INFO_STYLE;
519 }
520 ));
521 return new CodeLinesResult(codeLines, coverage, elementMap,
522 sourceMaps.sourceFileManager);
523 } 887 }
524 888
525 /// Visitor that computes a map from [js.Node]s to all attached source 889 /// Visitor that computes a map from [js.Node]s to all attached source
526 /// locations. 890 /// locations.
527 class SourceLocationCollector extends js.BaseVisitor { 891 class SourceLocationCollector extends js.BaseVisitor {
528 Map<js.Node, List<SourceLocation>> sourceLocations = 892 Map<js.Node, List<SourceLocation>> sourceLocations =
529 <js.Node, List<SourceLocation>>{}; 893 <js.Node, List<SourceLocation>>{};
530 894
531 @override 895 @override
532 visitNode(js.Node node) { 896 visitNode(js.Node node) {
(...skipping 25 matching lines...) Expand all
558 AstElement astElement = element.implementation; 922 AstElement astElement = element.implementation;
559 kind = CodeKind.MEMBER; 923 kind = CodeKind.MEMBER;
560 uri = astElement.compilationUnit.script.resourceUri; 924 uri = astElement.compilationUnit.script.resourceUri;
561 name = computeElementNameForSourceMaps(astElement); 925 name = computeElementNameForSourceMaps(astElement);
562 if (astElement.hasNode) { 926 if (astElement.hasNode) {
563 begin = astElement.node.getBeginToken().charOffset; 927 begin = astElement.node.getBeginToken().charOffset;
564 end = astElement.node.getEndToken().charEnd; 928 end = astElement.node.getEndToken().charEnd;
565 } 929 }
566 } 930 }
567 return new CodeSource(kind, uri, name, begin, end); 931 return new CodeSource(kind, uri, name, begin, end);
568 } 932 }
933
934 /// Create [LineData] that colors line numbers according to the [CodeSource]s
935 /// origin if available.
936 LineData getLineData(CodeSource lineAnnotation) {
937 if (lineAnnotation != null) {
938 return new LineData(
939 lineClass: ClassNames.line,
940 lineNumberClass:
941 '${ClassNames.lineNumber} '
942 '${ClassNames.colored(lineAnnotation.hashCode % 4)}');
943 }
944 return new LineData(
945 lineClass: ClassNames.line,
946 lineNumberClass: ClassNames.lineNumber);
947 }
948
949 AnnotationData getAnnotationData(Iterable<Annotation> annotations,
950 {bool forSpan}) {
951 for (Annotation annotation in annotations) {
952 CodeLineAnnotation data = annotation.data;
953 if (data.annotationType.isSourceMapped) {
954 if (forSpan) {
955 int index = data.sourceMappingIndex;
956 return new AnnotationData(
957 tag: 'span',
958 properties: {
959 'class':
960 '${ClassNames.sourceMapping} '
961 '${ClassNames.sourceMappingIndex(index % HUE_COUNT)}',
962 'title': 'index=$index',
963 });
964 } else {
965 return new AnnotationData(
966 tag: 'span',
967 properties: {
968 'title': annotation.title,
969 'class': '${ClassNames.marker} '
970 '${data.annotationType.className}'});
971 }
972 }
973 }
974 if (forSpan) return null;
975 for (Annotation annotation in annotations) {
976 CodeLineAnnotation data = annotation.data;
977 if (data.annotationType == AnnotationType.UNUSED_SOURCE_INFO) {
978 return new AnnotationData(
979 tag: 'span',
980 properties: {
981 'title': annotation.title,
982 'class': '${ClassNames.marker} '
983 '${data.annotationType.className}'});
984 }
985 }
986 for (Annotation annotation in annotations) {
987 CodeLineAnnotation data = annotation.data;
988 if (data.annotationType == AnnotationType.WITHOUT_SOURCE_INFO) {
989 return new AnnotationData(
990 tag: 'span',
991 properties: {
992 'title': annotation.title,
993 'class': '${ClassNames.marker} '
994 '${data.annotationType.className}'});
995 }
996 }
997 return null;
998 }
OLDNEW
« no previous file with comments | « tests/compiler/dart2js/sourcemaps/diff.dart ('k') | tests/compiler/dart2js/sourcemaps/html_parts.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698