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

Side by Side Diff: pkg/dev_compiler/tool/input_sdk/private/debugger.dart

Issue 2703263002: Custom formatter cleanup Fix case where displaying a class constructor generated unreadable huge ou… (Closed)
Patch Set: Created 3 years, 10 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) 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 library dart._debugger; 5 library dart._debugger;
6 6
7 import 'dart:_foreign_helper' show JS; 7 import 'dart:_foreign_helper' show JS;
8 import 'dart:_runtime' as dart; 8 import 'dart:_runtime' as dart;
9 import 'dart:core'; 9 import 'dart:core';
10 import 'dart:collection'; 10 import 'dart:collection';
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 class JSNative { 46 class JSNative {
47 // Name may be a String or a Symbol. 47 // Name may be a String or a Symbol.
48 static getProperty(object, name) => JS('', '#[#]', object, name); 48 static getProperty(object, name) => JS('', '#[#]', object, name);
49 // Name may be a String or a Symbol. 49 // Name may be a String or a Symbol.
50 static setProperty(object, name, value) => 50 static setProperty(object, name, value) =>
51 JS('', '#[#]=#', object, name, value); 51 JS('', '#[#]=#', object, name, value);
52 } 52 }
53 53
54 void addMetadataChildren(object, Set<NameValuePair> ret) { 54 void addMetadataChildren(object, Set<NameValuePair> ret) {
55 ret.add(new NameValuePair( 55 ret.add(new NameValuePair(
56 name: getTypeName(_getType(object)), 56 name: "[[class]]",
57 value: object, 57 value: dart.getReifiedType(object),
58 config: JsonMLConfig.asClass)); 58 config: JsonMLConfig.asClass));
59 } 59 }
60 60
61 /// Add properties from a signature definition [sig] for [object].
62 /// Walk the prototype chain if [walkProtypeChain] is set.
63 /// Tag types on function typed properties of [object] if [tagTypes] is set.
64 ///
65 void addPropertiesFromSignature(
66 sig, Set<NameValuePair> properties, object, bool walkPrototypeChain,
67 {tagTypes: false}) {
68 // Including these property names doesn't add any value and just clutters
69 // the debugger output.
70 // TODO(jacobr): consider adding runtimeType to this list.
71 var skippedNames = new Set()..add('hashCode');
72
73 while (sig != null) {
74 for (var symbol in getOwnPropertySymbols(sig)) {
75 var dartName = symbolName(symbol);
76 String dartXPrefix = 'dartx.';
77 if (dartName.startsWith(dartXPrefix)) {
78 dartName = dartName.substring(dartXPrefix.length);
79 }
80 if (skippedNames.contains(dartName)) continue;
81 var value = safeGetProperty(object, symbol);
82 // Tag the function with its runtime type.
83 if (tagTypes && _typeof(value) == 'function') {
84 dart.tag(value, JS('', '#[#]', sig, symbol));
85 }
86 properties.add(new NameValuePair(name: dartName, value: value));
87 }
88
89 for (var name in getOwnPropertyNames(sig)) {
90 var value = safeGetProperty(object, name);
91 if (skippedNames.contains(name)) continue;
92 // Tag the function with its runtime type.
93 if (tagTypes && _typeof(value) == 'function') {
94 dart.tag(value, JS('', '#[#]', sig, name));
95 }
96 properties.add(new NameValuePair(name: name, value: value));
97 }
98
99 if (!walkPrototypeChain) break;
100
101 sig = safeGetProperty(sig, '__proto__');
102 }
103 }
104
105 /// Sort properties sorting public names before private names.
106 List<NameValuePair> sortProperties(Iterable<NameValuePair> properties) {
107 var sortedProperties = properties.toList();
108
109 sortedProperties.sort((a, b) {
110 var aPrivate = a.name.startsWith('_');
111 var bPrivate = b.name.startsWith('_');
112 if (aPrivate != bPrivate) return aPrivate ? 1 : -1;
113 return a.name.compareTo(b.name);
114 });
115 return sortedProperties;
116 }
117
61 String getObjectTypeName(object) { 118 String getObjectTypeName(object) {
62 var reifiedType = dart.getReifiedType(object); 119 var reifiedType = dart.getReifiedType(object);
63 if (reifiedType == null) { 120 if (reifiedType == null) {
64 if (_typeof(object) == 'function') { 121 if (_typeof(object) == 'function') {
65 return '[[Raw JavaScript Function]]'; 122 return '[[Raw JavaScript Function]]';
66 } 123 }
67 return '<Error getting type name>'; 124 return '<Error getting type name>';
68 } 125 }
69 return getTypeName(reifiedType); 126 return getTypeName(reifiedType);
70 } 127 }
71 128
72 String getTypeName(Type type) { 129 String getTypeName(type) {
73 var name = dart.typeName(type); 130 var name = dart.typeName(type);
74 // Hack to cleanup names for List<dynamic> 131 // Hack to cleanup names for List<dynamic>
75 // TODO(jacobr): it would be nice if there was a way we could distinguish 132 // TODO(jacobr): it would be nice if there was a way we could distinguish
76 // between a List<dynamic> created from Dart and an Array passed in from 133 // between a List<dynamic> created from Dart and an Array passed in from
77 // JavaScript. 134 // JavaScript.
78 if (name == 'JSArray<dynamic>' || name == 'JSObject<Array>') 135 if (name == 'JSArray<dynamic>' || name == 'JSObject<Array>')
79 return 'List<dynamic>'; 136 return 'List<dynamic>';
80 return name; 137 return name;
81 } 138 }
82 139
83 Object _getType(object) =>
84 object is Type ? object : dart.getReifiedType(object);
85
86 String safePreview(object, config) { 140 String safePreview(object, config) {
87 try { 141 try {
88 var preview = _devtoolsFormatter._simpleFormatter.preview(object, config); 142 var preview = _devtoolsFormatter._simpleFormatter.preview(object, config);
89 if (preview != null) return preview; 143 if (preview != null) return preview;
90 return object.toString(); 144 return object.toString();
91 } catch (e) { 145 } catch (e) {
92 return '<Exception thrown> $e'; 146 return '<Exception thrown> $e';
93 } 147 }
94 } 148 }
95 149
(...skipping 14 matching lines...) Expand all
110 /// [JsonMLFormatter] consumes [NameValuePair] objects and 164 /// [JsonMLFormatter] consumes [NameValuePair] objects and
111 class NameValuePair { 165 class NameValuePair {
112 NameValuePair( 166 NameValuePair(
113 {this.name, 167 {this.name,
114 this.value, 168 this.value,
115 this.config: JsonMLConfig.none, 169 this.config: JsonMLConfig.none,
116 this.hideName: false}); 170 this.hideName: false});
117 171
118 // Define equality and hashCode so that NameValuePair can be used 172 // Define equality and hashCode so that NameValuePair can be used
119 // in a Set to dedupe entries with duplicate names. 173 // in a Set to dedupe entries with duplicate names.
120 operator ==(other) => other is NameValuePair && other.name == name; 174 bool operator ==(other) {
175 if (other is! NameValuePair) return false;
176 if (this.hideName || other.hideName) return identical(this, other);
177 return other.name == name;
178 }
179
121 int get hashCode => name.hashCode; 180 int get hashCode => name.hashCode;
122 181
123 final String name; 182 final String name;
124 final Object value; 183 final Object value;
125 final JsonMLConfig config; 184 final JsonMLConfig config;
126 final bool hideName; 185 final bool hideName;
127 186
128 String get displayName => hideName ? '' : name; 187 String get displayName => hideName ? '' : name;
129 } 188 }
130 189
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 } 321 }
263 322
264 /// Whether an object is a native JavaScript type where we should display the 323 /// Whether an object is a native JavaScript type where we should display the
265 /// JavaScript view of the object instead of the custom Dart specific render 324 /// JavaScript view of the object instead of the custom Dart specific render
266 /// of properties. 325 /// of properties.
267 bool isNativeJavaScriptObject(object) { 326 bool isNativeJavaScriptObject(object) {
268 var type = _typeof(object); 327 var type = _typeof(object);
269 // Treat Node objects as a native JavaScript type as the regular DOM render 328 // Treat Node objects as a native JavaScript type as the regular DOM render
270 // in devtools is superior to the dart specific view. 329 // in devtools is superior to the dart specific view.
271 return (type != 'object' && type != 'function') || 330 return (type != 'object' && type != 'function') ||
272 object is dart.JSObject || 331 dart.isJsInterop(object) ||
273 object is html.Node; 332 object is html.Node;
274 } 333 }
275 334
276 /// Class implementing the Devtools Formatter API described by: 335 /// Class implementing the Devtools Formatter API described by:
277 /// https://docs.google.com/document/d/1FTascZXT9cxfetuPRT2eXPQKXui4nWFivUnS_335 T3U 336 /// https://docs.google.com/document/d/1FTascZXT9cxfetuPRT2eXPQKXui4nWFivUnS_335 T3U
278 /// Specifically, a formatter implements a header, hasBody, and body method. 337 /// Specifically, a formatter implements a header, hasBody, and body method.
279 /// This class renders the simple structured format objects [_simpleFormatter] 338 /// This class renders the simple structured format objects [_simpleFormatter]
280 /// provides as JsonML. 339 /// provides as JsonML.
281 class JsonMLFormatter { 340 class JsonMLFormatter {
282 // TODO(jacobr): define a SimpleFormatter base class that DartFormatter 341 // TODO(jacobr): define a SimpleFormatter base class that DartFormatter
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 'padding-left: 0px;' 382 'padding-left: 0px;'
324 'margin-top: 0px;' 383 'margin-top: 0px;'
325 'margin-bottom: 0px;' 384 'margin-bottom: 0px;'
326 'margin-left: 12px;'); 385 'margin-left: 12px;');
327 if (object is StackTrace) { 386 if (object is StackTrace) {
328 body.addStyle('color: rgb(196, 26, 22);'); 387 body.addStyle('color: rgb(196, 26, 22);');
329 } 388 }
330 var children = _simpleFormatter.children(object, config); 389 var children = _simpleFormatter.children(object, config);
331 for (NameValuePair child in children) { 390 for (NameValuePair child in children) {
332 var li = body.createChild('li'); 391 var li = body.createChild('li');
333 var nameSpan = new JsonMLElement('span') 392 li.setStyle("padding-left: 13px;");
334 ..createTextChild( 393
335 child.displayName.isNotEmpty ? '${child.displayName}: ' : '') 394 // The value is indented when it is on a different line from the name
336 ..setStyle('color: rgb(136, 19, 145);'); 395 // by setting right padding of the name to -13px and the padding of the
396 // value to 13px.
397 JsonMLElement nameSpan;
398 var valueStyle = '';
399 if (!child.hideName) {
400 nameSpan = new JsonMLElement('span')
401 ..createTextChild(
402 child.displayName.isNotEmpty ? '${child.displayName}: ' : '')
403 ..setStyle('color: rgb(136, 19, 145); margin-right: -13px');
404 valueStyle = 'margin-left: 13px';
405 }
406
337 if (_typeof(child.value) == 'object' || 407 if (_typeof(child.value) == 'object' ||
338 _typeof(child.value) == 'function') { 408 _typeof(child.value) == 'function') {
339 nameSpan.addStyle("padding-left: 13px;"); 409 var valueSpan = new JsonMLElement('span')..setStyle(valueStyle);
340 410 valueSpan.createObjectTag(child.value)
341 li.appendChild(nameSpan); 411 ..addAttribute('config', child.config);
342 var objectTag = li.createObjectTag(child.value); 412 if (nameSpan != null) {
343 objectTag.addAttribute('config', child.config); 413 li.appendChild(nameSpan);
344 if (!_simpleFormatter.hasChildren(child.value, child.config)) {
345 li.setStyle("padding-left: 13px;");
346 } 414 }
415 li.appendChild(valueSpan);
347 } else { 416 } else {
348 li.setStyle("padding-left: 13px;"); 417 var line = li.createChild('span');
349 li.createChild('span') 418 if (nameSpan != null) {
350 ..appendChild(nameSpan) 419 line.appendChild(nameSpan);
351 ..createTextChild(safePreview(child.value, child.config)); 420 }
421 line.appendChild(new JsonMLElement('span')
422 ..createTextChild(safePreview(child.value, child.config))
423 ..setStyle(valueStyle));
352 } 424 }
353 } 425 }
354 return body.toJsonML(); 426 return body.toJsonML();
355 } 427 }
356 } 428 }
357 429
358 abstract class Formatter { 430 abstract class Formatter {
359 bool accept(object, config); 431 bool accept(object, config);
360 String preview(object); 432 String preview(object);
361 bool hasChildren(object); 433 bool hasChildren(object);
362 List<NameValuePair> children(object); 434 List<NameValuePair> children(object);
363 } 435 }
364 436
365 class DartFormatter { 437 class DartFormatter {
366 List<Formatter> _formatters; 438 List<Formatter> _formatters;
367 439
368 DartFormatter() { 440 DartFormatter() {
369 // The order of formatters matters as formatters earlier in the list take 441 // The order of formatters matters as formatters earlier in the list take
370 // precedence. 442 // precedence.
371 _formatters = [ 443 _formatters = [
372 new ClassFormatter(), 444 new ClassFormatter(),
445 new TypeFormatter(),
373 new NamedConstructorFormatter(), 446 new NamedConstructorFormatter(),
374 new MapFormatter(), 447 new MapFormatter(),
375 new IterableFormatter(), 448 new IterableFormatter(),
376 new IterableSpanFormatter(), 449 new IterableSpanFormatter(),
377 new MapEntryFormatter(), 450 new MapEntryFormatter(),
378 new StackTraceFormatter(), 451 new StackTraceFormatter(),
379 new FunctionFormatter(), 452 new FunctionFormatter(),
380 new HeritageClauseFormatter(), 453 new HeritageClauseFormatter(),
381 new LibraryModuleFormatter(), 454 new LibraryModuleFormatter(),
382 new LibraryFormatter(), 455 new LibraryFormatter(),
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 } catch (e, trace) { 503 } catch (e, trace) {
431 // See comment for preview. 504 // See comment for preview.
432 html.window.console.error("Caught exception $e\n trace:\n$trace"); 505 html.window.console.error("Caught exception $e\n trace:\n$trace");
433 } 506 }
434 return <NameValuePair>[]; 507 return <NameValuePair>[];
435 } 508 }
436 } 509 }
437 510
438 /// Default formatter for Dart Objects. 511 /// Default formatter for Dart Objects.
439 class ObjectFormatter extends Formatter { 512 class ObjectFormatter extends Formatter {
440 static Set<String> _customNames = new Set()
441 ..add('constructor')
442 ..add('prototype')
443 ..add('__proto__');
444 bool accept(object, config) => !isNativeJavaScriptObject(object); 513 bool accept(object, config) => !isNativeJavaScriptObject(object);
445 514
446 String preview(object) => getObjectTypeName(object); 515 String preview(object) => getObjectTypeName(object);
447 516
448 bool hasChildren(object) => true; 517 bool hasChildren(object) => true;
449 518
450 List<NameValuePair> children(object) { 519 List<NameValuePair> children(object) {
451 var properties = new LinkedHashSet<NameValuePair>(); 520 var type = dart.getType(object);
452 // Set of property names used to avoid duplicates. 521 var ret = new LinkedHashSet<NameValuePair>();
453 addMetadataChildren(object, properties); 522 // We use a Set rather than a List to avoid duplicates.
454 523 var properties = new Set<NameValuePair>();
455 var current = object; 524 addPropertiesFromSignature(
456 525 dart.getFieldSig(type), properties, object, true);
457 var protoChain = <Object>[]; 526 addPropertiesFromSignature(
458 while (current != null && 527 dart.getGetterSig(type), properties, object, true);
459 !isNativeJavaScriptObject(current) && 528 ret.addAll(sortProperties(properties));
460 JS("bool", "# !== Object.prototype", current)) { 529 addMetadataChildren(object, ret);
461 protoChain.add(current); 530 return ret.toList();
462 current = safeGetProperty(current, '__proto__');
463 }
464
465 // We walk the prototype chain for symbol properties because they take
466 // priority and are accessed instead of Dart properties according to Dart
467 // calling conventions.
468 // TODO(jacobr): where possible use the data stored by dart.setSignature
469 // instead of walking the JavaScript object directly.
470 for (current in protoChain) {
471 for (var symbol in getOwnPropertySymbols(current)) {
472 var dartName = symbolName(symbol);
473 if (hasMethod(object, dartName)) {
474 continue;
475 }
476 // TODO(jacobr): find a cleaner solution than checking for dartx
477 String dartXPrefix = 'dartx.';
478 if (dartName.startsWith(dartXPrefix)) {
479 dartName = dartName.substring(dartXPrefix.length);
480 } else if (!dartName.startsWith('_')) {
481 // Dart method extension names should either be from dartx or should
482 // start with an _
483 continue;
484 }
485 var value = safeGetProperty(object, symbol);
486 properties.add(new NameValuePair(name: dartName, value: value));
487 }
488 }
489
490 for (current in protoChain) {
491 // TODO(jacobr): optionally distinguish properties and fields so that
492 // it is safe to expand untrusted objects without side effects.
493 var className = dart.getReifiedType(current).name;
494 for (var name in getOwnPropertyNames(current)) {
495 if (_customNames.contains(name) || name == className) continue;
496 if (hasMethod(object, name)) {
497 continue;
498 }
499 var value = safeGetProperty(object, name);
500 properties.add(new NameValuePair(name: name, value: value));
501 }
502 }
503
504 return properties.toList();
505 } 531 }
506 } 532 }
507 533
508 /// Formatter for module Dart Library objects. 534 /// Formatter for module Dart Library objects.
509 class LibraryModuleFormatter implements Formatter { 535 class LibraryModuleFormatter implements Formatter {
510 accept(object, config) => dart.getDartLibraryName(object) != null; 536 accept(object, config) => dart.getDartLibraryName(object) != null;
511 537
512 bool hasChildren(object) => true; 538 bool hasChildren(object) => true;
513 539
514 String preview(object) { 540 String preview(object) {
(...skipping 26 matching lines...) Expand all
541 var genericParameters = new HashMap<String, String>(); 567 var genericParameters = new HashMap<String, String>();
542 568
543 accept(object, config) => object is Library; 569 accept(object, config) => object is Library;
544 570
545 bool hasChildren(object) => true; 571 bool hasChildren(object) => true;
546 572
547 String preview(object) => object.name; 573 String preview(object) => object.name;
548 574
549 List<NameValuePair> children(object) { 575 List<NameValuePair> children(object) {
550 var children = new LinkedHashSet<NameValuePair>(); 576 var children = new LinkedHashSet<NameValuePair>();
551 var nonGenericProperties = new LinkedHashMap<String, Object>();
552 var objectProperties = safeProperties(object.object); 577 var objectProperties = safeProperties(object.object);
553 objectProperties.forEach((name, value) { 578 objectProperties.forEach((name, value) {
554 var genericTypeConstructor = dart.getGenericTypeCtor(value);
555 if (genericTypeConstructor != null) {
556 recordGenericParameters(name, genericTypeConstructor);
557 } else {
558 nonGenericProperties[name] = value;
559 }
560 });
561 nonGenericProperties.forEach((name, value) {
562 if (value is Type) { 579 if (value is Type) {
563 children.add(classChild(name, value)); 580 children.add(classChild(name, value));
564 } else { 581 } else {
565 children.add(new NameValuePair(name: name, value: value)); 582 children.add(new NameValuePair(name: name, value: value));
566 } 583 }
567 }); 584 });
568 return children.toList();
569 }
570
571 recordGenericParameters(String name, Object genericTypeConstructor) {
572 // Using JS toString() eliminates the leading metadata that is generated
573 // with the toString function provided in operations.dart.
574 // Splitting by => and taking the first element gives the list of
575 // arguments in the constructor.
576 genericParameters[name] =
577 JS('String', '#.toString()', genericTypeConstructor)
578 .split(' =>')
579 .first
580 .replaceAll(new RegExp(r'[(|)]'), '');
581 } 585 }
582 586
583 classChild(String name, Object child) { 587 classChild(String name, Object child) {
584 var typeName = getTypeName(child); 588 var typeName = getTypeName(child);
585 // Generic class names are generated with a $ at the end, so the 589 return new NameValuePair(
586 // corresponding non-generic class can be identified by adding $. 590 name: typeName, value: child, config: JsonMLConfig.asClass);
587 var parameterName = '$name\$';
588 if (genericParameters.keys.contains(parameterName)) {
589 typeName = '$typeName<${genericParameters[parameterName]}>';
590 // TODO(bmilligan): Add a symbol to classes with generic types at their
591 // creation so they can be recognized independently by the debugger.
592 JSNative.setProperty(child, 'genericTypeName', typeName);
593 }
594 return new NameValuePair(name: typeName, value: child);
595 } 591 }
596 } 592 }
597 593
598 /// Formatter for Dart Function objects. 594 /// Formatter for Dart Function objects.
599 /// Dart functions happen to be regular JavaScript Function objects but 595 /// Dart functions happen to be regular JavaScript Function objects but
600 /// we can distinguish them based on whether they have been tagged with 596 /// we can distinguish them based on whether they have been tagged with
601 /// runtime type information. 597 /// runtime type information.
602 class FunctionFormatter implements Formatter { 598 class FunctionFormatter implements Formatter {
603 accept(object, config) { 599 accept(object, config) {
604 if (_typeof(object) != 'function') return false; 600 if (_typeof(object) != 'function') return false;
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 List<NameValuePair> children(object) => object 759 List<NameValuePair> children(object) => object
764 .toString() 760 .toString()
765 .split('\n') 761 .split('\n')
766 .map((line) => new NameValuePair( 762 .map((line) => new NameValuePair(
767 value: line.replaceFirst(new RegExp(r'^\s+at\s'), ''), 763 value: line.replaceFirst(new RegExp(r'^\s+at\s'), ''),
768 hideName: true)) 764 hideName: true))
769 .toList(); 765 .toList();
770 } 766 }
771 767
772 class ClassFormatter implements Formatter { 768 class ClassFormatter implements Formatter {
773 accept(object, config) => object is Type || config == JsonMLConfig.asClass; 769 accept(object, config) => config == JsonMLConfig.asClass;
774 770
775 String preview(object) { 771 String preview(type) {
776 var typeName = safeGetProperty(object, 'genericTypeName');
777 if (typeName != null) return typeName;
778 var type = _getType(object);
779 var implements = dart.getImplements(type); 772 var implements = dart.getImplements(type);
780 typeName = getTypeName(type); 773 var typeName = getTypeName(type);
781 if (implements != null) { 774 if (implements != null) {
782 var typeNames = implements().map(getTypeName); 775 var typeNames = implements().map(getTypeName);
783 return '${typeName} implements ${typeNames.join(", ")}'; 776 return '${typeName} implements ${typeNames.join(", ")}';
784 } else { 777 } else {
785 return typeName; 778 return typeName;
786 } 779 }
787 } 780 }
788 781
789 bool hasChildren(object) => true; 782 bool hasChildren(object) => true;
790 783
791 List<NameValuePair> children(object) { 784 List<NameValuePair> children(type) {
792 // TODO(jacobr): add other entries describing the class such as 785 // TODO(jacobr): add other entries describing the class such as
793 // links to the superclass, mixins, implemented interfaces, and methods. 786 // implemented interfaces, and methods.
794 var type = _getType(object); 787 var ret = new LinkedHashSet<NameValuePair>();
795 var children = <NameValuePair>[]; 788
796 var typeName = getTypeName(_getType(object)); 789 var staticProperties = new Set<NameValuePair>();
790 var staticMethods = new Set<NameValuePair>();
791 // Static fields and properties.
792 addPropertiesFromSignature(
793 dart.getStaticFieldSig(type), staticProperties, type, false);
794 addPropertiesFromSignature(
795 dart.getStaticGetterSig(type), staticProperties, type, false);
796 // static methods.
797 addPropertiesFromSignature(
798 dart.getStaticSig(type), staticMethods, type, false);
799
800 if (staticProperties.isNotEmpty || staticMethods.isNotEmpty) {
801 ret
802 ..add(new NameValuePair(value: '[[Static members]]', hideName: true))
803 ..addAll(sortProperties(staticProperties))
804 ..addAll(sortProperties(staticMethods));
805 }
806
807 // instance methods.
808 var instanceMethods = new Set<NameValuePair>();
809 // Instance methods are defined on the prototype not the constructor object.
810 addPropertiesFromSignature(dart.getMethodSig(type), instanceMethods,
811 JS('', '#.prototype', type), false,
812 tagTypes: true);
813 if (instanceMethods.isNotEmpty) {
814 ret
815 ..add(new NameValuePair(value: '[[Instance Methods]]', hideName: true))
816 ..addAll(sortProperties(instanceMethods));
817 }
818
819 var typeName = getTypeName(type);
797 var mixins = dart.getMixins(type); 820 var mixins = dart.getMixins(type);
798 if (mixins != null && mixins.isNotEmpty) { 821 if (mixins != null && mixins.isNotEmpty) {
799 children.add(new NameValuePair( 822 ret.add(new NameValuePair(
800 name: '[[Mixins]]', value: new HeritageClause('mixins', mixins))); 823 name: '[[Mixins]]', value: new HeritageClause('mixins', mixins)));
801 } 824 }
802 825
803 var hiddenProperties = ['length', 'name', 'prototype', 'genericTypeName']; 826 var baseProto = JS('', '#.__proto__', type);
804 // Addition of NameValuePairs for static variables and named constructors. 827 if (baseProto != null && !dart.isJsInterop(baseProto)) {
805 for (var name in getOwnPropertyNames(object)) { 828 ret.add(new NameValuePair(
806 // TODO(bmilligan): Perform more principled checks to filter out spurious 829 name: "[[base class]]",
807 // members. 830 value: baseProto,
808 if (hiddenProperties.contains(name)) continue; 831 config: JsonMLConfig.asClass));
809 var value = safeGetProperty(object, name);
810 if (value != null && dart.getIsNamedConstructor(value) != null) {
811 value = new NamedConstructor(value);
812 name = '${typeName}.$name';
813 }
814 children.add(new NameValuePair(name: name, value: value));
815 } 832 }
816 833
817 // TODO(bmilligan): Replace the hard coding of $identityHash. 834 // TODO(jacobr): add back fields for named constructors.
818 var hiddenPrototypeProperties = ['constructor', 'new', r'$identityHash']; 835 return ret.toList();
819 // Addition of class methods.
820 var prototype = JS('var', '#["prototype"]', object);
821 if (prototype != null) {
822 for (var name in getOwnPropertyNames(prototype)) {
823 if (hiddenPrototypeProperties.contains(name)) continue;
824 // Simulate dart.bind by using dart.tag and tear off the function
825 // so it will be recognized by the FunctionFormatter.
826 var function = safeGetProperty(prototype, name);
827 var constructor = safeGetProperty(prototype, 'constructor');
828 var sigObj = dart.getMethodSig(constructor);
829 if (sigObj != null) {
830 var value = safeGetProperty(sigObj, name);
831 if (getTypeName(dart.getReifiedType(value)) != 'Null') {
832 dart.tag(function, value);
833 children.add(new NameValuePair(name: name, value: function));
834 }
835 }
836 }
837 }
838 return children;
839 } 836 }
840 } 837 }
841 838
839 class TypeFormatter implements Formatter {
840 accept(object, config) => object is Type;
841
842 String preview(object) => object.toString();
843
844 bool hasChildren(object) => false;
845
846 List<NameValuePair> children(object) => [];
847 }
848
842 /// This entry point is automatically invoked by the code generated by 849 /// This entry point is automatically invoked by the code generated by
843 /// Dart Dev Compiler 850 /// Dart Dev Compiler
844 registerDevtoolsFormatter() { 851 registerDevtoolsFormatter() {
845 var formatters = [_devtoolsFormatter]; 852 var formatters = [_devtoolsFormatter];
846 JS('', 'dart.global.devtoolsFormatters = #', formatters); 853 JS('', 'dart.global.devtoolsFormatters = #', formatters);
847 } 854 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698