Chromium Code Reviews| 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 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 13 matching lines...) Expand all Loading... | |
| 24 class JsonMLConfig { | 24 class JsonMLConfig { |
| 25 const JsonMLConfig(this.name); | 25 const JsonMLConfig(this.name); |
| 26 | 26 |
| 27 final String name; | 27 final String name; |
| 28 static const none = const JsonMLConfig("none"); | 28 static const none = const JsonMLConfig("none"); |
| 29 static const skipDart = const JsonMLConfig("skipDart"); | 29 static const skipDart = const JsonMLConfig("skipDart"); |
| 30 static const keyToString = const JsonMLConfig("keyToString"); | 30 static const keyToString = const JsonMLConfig("keyToString"); |
| 31 } | 31 } |
| 32 | 32 |
| 33 int _maxSpanLength = 100; | 33 int _maxSpanLength = 100; |
| 34 | 34 Symbol isClass = JS('Symbol', 'Symbol("isClass")'); |
|
bmilligan
2016/08/02 01:12:44
Using 'new Symbol('isClass') in Dart followed by J
| |
| 35 var _devtoolsFormatter = new JsonMLFormatter(new DartFormatter()); | 35 var _devtoolsFormatter = new JsonMLFormatter(new DartFormatter()); |
| 36 | 36 |
| 37 String _typeof(object) => JS('String', 'typeof #', object); | 37 String _typeof(object) => JS('String', 'typeof #', object); |
| 38 | 38 |
| 39 List<String> getOwnPropertyNames(object) => JS('List<String>', | 39 List<String> getOwnPropertyNames(object) => JS('List<String>', |
| 40 'dart.list(Object.getOwnPropertyNames(#), #)', object, String); | 40 'dart.list(Object.getOwnPropertyNames(#), #)', object, String); |
| 41 | 41 |
| 42 List getOwnPropertySymbols(object) => | 42 List getOwnPropertySymbols(object) => |
| 43 JS('List', 'Object.getOwnPropertySymbols(#)', object); | 43 JS('List', 'Object.getOwnPropertySymbols(#)', object); |
| 44 | 44 |
| 45 // TODO(jacobr): move this to dart:js and fully implement. | 45 // TODO(jacobr): move this to dart:js and fully implement. |
| 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) { | |
| 55 JSNative.setProperty(object, isClass, true); | |
| 56 ret.add( | |
| 57 new NameValuePair(name: getTypeName(_getType(object)), value: object)); | |
| 58 } | |
| 59 | |
| 54 String getObjectTypeName(object) { | 60 String getObjectTypeName(object) { |
| 55 var reifiedType = dart.getReifiedType(object); | 61 var reifiedType = dart.getReifiedType(object); |
| 56 if (reifiedType == null) { | 62 if (reifiedType == null) { |
| 57 if (_typeof(object) == 'function') { | 63 if (_typeof(object) == 'function') { |
| 58 return '[[Raw JavaScript Function]]'; | 64 return '[[Raw JavaScript Function]]'; |
| 59 } | 65 } |
| 60 return '<Error getting type name>'; | 66 return '<Error getting type name>'; |
| 61 } | 67 } |
| 62 return getTypeName(reifiedType); | 68 return getTypeName(reifiedType); |
| 63 } | 69 } |
| 64 | 70 |
| 65 String getTypeName(Type type) { | 71 String getTypeName(Type type) { |
| 66 var name = dart.typeName(type); | 72 var name = dart.typeName(type); |
| 67 // Hack to cleanup names for List<dynamic> | 73 // Hack to cleanup names for List<dynamic> |
| 68 // TODO(jacobr): it would be nice if there was a way we could distinguish | 74 // TODO(jacobr): it would be nice if there was a way we could distinguish |
| 69 // between a List<dynamic> created from Dart and an Array passed in from | 75 // between a List<dynamic> created from Dart and an Array passed in from |
| 70 // JavaScript. | 76 // JavaScript. |
| 71 if (name == 'JSArray<dynamic>' || name == 'JSObject<Array>') | 77 if (name == 'JSArray<dynamic>' || name == 'JSObject<Array>') |
| 72 return 'List<dynamic>'; | 78 return 'List<dynamic>'; |
| 73 return name; | 79 return name; |
| 74 } | 80 } |
| 75 | 81 |
| 82 Object _getType(object) => | |
| 83 object is Type ? object : dart.getReifiedType(object); | |
| 84 | |
| 76 String safePreview(object) { | 85 String safePreview(object) { |
| 77 try { | 86 try { |
| 78 var preview = _devtoolsFormatter._simpleFormatter.preview(object); | 87 var preview = _devtoolsFormatter._simpleFormatter.preview(object); |
| 79 if (preview != null) return preview; | 88 if (preview != null) return preview; |
| 80 return object.toString(); | 89 return object.toString(); |
| 81 } catch (e) { | 90 } catch (e) { |
| 82 return '<Exception thrown> $e'; | 91 return '<Exception thrown> $e'; |
| 83 } | 92 } |
| 84 } | 93 } |
| 85 | 94 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 176 final String name; | 185 final String name; |
| 177 final Object object; | 186 final Object object; |
| 178 } | 187 } |
| 179 | 188 |
| 180 class NamedConstructor { | 189 class NamedConstructor { |
| 181 NamedConstructor(this.object); | 190 NamedConstructor(this.object); |
| 182 | 191 |
| 183 final Object object; | 192 final Object object; |
| 184 } | 193 } |
| 185 | 194 |
| 186 class ClassMetadata { | |
| 187 ClassMetadata(this.object, {this.name}); | |
| 188 | |
| 189 final Object object; | |
| 190 final String name; | |
| 191 | |
| 192 String get typeName => | |
| 193 name ?? | |
| 194 getTypeName(object is Type ? object : dart.getReifiedType(object)); | |
| 195 } | |
| 196 | |
| 197 class HeritageClause { | 195 class HeritageClause { |
| 198 HeritageClause(this.name, this.types); | 196 HeritageClause(this.name, this.types); |
| 199 | 197 |
| 200 final String name; | 198 final String name; |
| 201 final List types; | 199 final List types; |
| 202 } | 200 } |
| 203 | 201 |
| 204 Object safeGetProperty(Object protoChain, String name) { | 202 Object safeGetProperty(Object protoChain, Object name) { |
| 205 try { | 203 try { |
| 206 return JSNative.getProperty(protoChain, name); | 204 return JSNative.getProperty(protoChain, name); |
| 207 } catch (e) { | 205 } catch (e) { |
| 208 return '<Exception thrown> $e'; | 206 return '<Exception thrown> $e'; |
| 209 } | 207 } |
| 210 } | 208 } |
| 211 | 209 |
| 212 safeProperties(object) => new Map.fromIterable( | 210 safeProperties(object) => new Map.fromIterable( |
| 213 getOwnPropertyNames(object) | 211 getOwnPropertyNames(object) |
| 214 .where((each) => safeGetProperty(object, each) != null), | 212 .where((each) => safeGetProperty(object, each) != null), |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 364 List<NameValuePair> children(object); | 362 List<NameValuePair> children(object); |
| 365 } | 363 } |
| 366 | 364 |
| 367 class DartFormatter { | 365 class DartFormatter { |
| 368 List<Formatter> _formatters; | 366 List<Formatter> _formatters; |
| 369 | 367 |
| 370 DartFormatter() { | 368 DartFormatter() { |
| 371 // The order of formatters matters as formatters earlier in the list take | 369 // The order of formatters matters as formatters earlier in the list take |
| 372 // precedence. | 370 // precedence. |
| 373 _formatters = [ | 371 _formatters = [ |
| 372 new ClassFormatter(), | |
| 374 new NamedConstructorFormatter(), | 373 new NamedConstructorFormatter(), |
| 375 new FunctionFormatter(), | |
| 376 new MapFormatter(), | 374 new MapFormatter(), |
| 377 new IterableFormatter(), | 375 new IterableFormatter(), |
| 376 new IterableSpanFormatter(), | |
| 378 new MapEntryFormatter(), | 377 new MapEntryFormatter(), |
| 379 new IterableSpanFormatter(), | |
| 380 new StackTraceFormatter(), | 378 new StackTraceFormatter(), |
| 381 new ClassMetadataFormatter(), | 379 new FunctionFormatter(), |
| 382 new HeritageClauseFormatter(), | 380 new HeritageClauseFormatter(), |
| 383 new LibraryModuleFormatter(), | 381 new LibraryModuleFormatter(), |
| 384 new LibraryFormatter(), | 382 new LibraryFormatter(), |
| 385 new ObjectFormatter(), | 383 new ObjectFormatter(), |
| 386 ]; | 384 ]; |
| 387 } | 385 } |
| 388 | 386 |
| 389 String preview(object) { | 387 String preview(object) { |
| 390 try { | 388 try { |
| 391 if (object == null || | 389 if (object == null || |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 497 if (hasMethod(object, name)) { | 495 if (hasMethod(object, name)) { |
| 498 continue; | 496 continue; |
| 499 } | 497 } |
| 500 var value = safeGetProperty(object, name); | 498 var value = safeGetProperty(object, name); |
| 501 properties.add(new NameValuePair(name: name, value: value)); | 499 properties.add(new NameValuePair(name: name, value: value)); |
| 502 } | 500 } |
| 503 } | 501 } |
| 504 | 502 |
| 505 return properties.toList(); | 503 return properties.toList(); |
| 506 } | 504 } |
| 507 | |
| 508 addMetadataChildren(object, Set<NameValuePair> ret) { | |
| 509 var child = new ClassMetadata(object); | |
| 510 ret.add(new NameValuePair(name: child.typeName, value: child)); | |
| 511 } | |
| 512 } | 505 } |
| 513 | 506 |
| 514 /// Formatter for module Dart Library objects. | 507 /// Formatter for module Dart Library objects. |
| 515 class LibraryModuleFormatter extends ObjectFormatter { | 508 class LibraryModuleFormatter implements Formatter { |
| 516 String libraryName; | 509 String libraryName; |
| 517 | 510 |
| 518 accept(object) { | 511 accept(object) { |
| 519 libraryName = dart.getDartLibraryName(object); | 512 libraryName = dart.getDartLibraryName(object); |
| 520 return libraryName != null; | 513 return libraryName != null; |
| 521 } | 514 } |
| 522 | 515 |
| 523 bool hasChildren(object) => true; | 516 bool hasChildren(object) => true; |
| 524 | 517 |
| 525 String preview(object) { | 518 String preview(object) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 541 // Replace __ with / to make file paths more readable. Then | 534 // Replace __ with / to make file paths more readable. Then |
| 542 // 'src__result__error' becomes 'src/result/error'. | 535 // 'src__result__error' becomes 'src/result/error'. |
| 543 name = '${name.replaceAll("__", "/")}.dart'; | 536 name = '${name.replaceAll("__", "/")}.dart'; |
| 544 children.add(new NameValuePair( | 537 children.add(new NameValuePair( |
| 545 name: name, value: new Library(name, value), hideName: true)); | 538 name: name, value: new Library(name, value), hideName: true)); |
| 546 } | 539 } |
| 547 return children.toList(); | 540 return children.toList(); |
| 548 } | 541 } |
| 549 } | 542 } |
| 550 | 543 |
| 551 /// Formatter for Dart Library objects. | 544 class LibraryFormatter implements Formatter { |
| 552 class LibraryFormatter extends ObjectFormatter { | |
| 553 var genericParameters = new HashMap<String, String>(); | 545 var genericParameters = new HashMap<String, String>(); |
| 554 | 546 |
| 555 accept(object) => object is Library; | 547 accept(object) => object is Library; |
| 556 | 548 |
| 557 bool hasChildren(object) => true; | 549 bool hasChildren(object) => true; |
| 558 | 550 |
| 559 String preview(object) => object.name; | 551 String preview(object) => object.name; |
| 560 | 552 |
| 561 List<NameValuePair> children(object) { | 553 List<NameValuePair> children(object) { |
| 562 var children = new LinkedHashSet<NameValuePair>(); | 554 var children = new LinkedHashSet<NameValuePair>(); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 592 .replaceAll(new RegExp(r'[(|)]'), ''); | 584 .replaceAll(new RegExp(r'[(|)]'), ''); |
| 593 } | 585 } |
| 594 | 586 |
| 595 classChild(String name, Object child) { | 587 classChild(String name, Object child) { |
| 596 var typeName = getTypeName(child); | 588 var typeName = getTypeName(child); |
| 597 // Generic class names are generated with a $ at the end, so the | 589 // Generic class names are generated with a $ at the end, so the |
| 598 // corresponding non-generic class can be identified by adding $. | 590 // corresponding non-generic class can be identified by adding $. |
| 599 var parameterName = '$name\$'; | 591 var parameterName = '$name\$'; |
| 600 if (genericParameters.keys.contains(parameterName)) { | 592 if (genericParameters.keys.contains(parameterName)) { |
| 601 typeName = '$typeName<${genericParameters[parameterName]}>'; | 593 typeName = '$typeName<${genericParameters[parameterName]}>'; |
| 594 JSNative.setProperty(child, 'genericTypeName', typeName); | |
| 602 } | 595 } |
| 603 return new NameValuePair( | 596 return new NameValuePair(name: typeName, value: child); |
| 604 name: typeName, value: new ClassMetadata(child, name: typeName)); | |
| 605 } | 597 } |
| 606 } | 598 } |
| 607 | 599 |
| 608 /// Formatter for Dart Function objects. | 600 /// Formatter for Dart Function objects. |
| 609 /// Dart functions happen to be regular JavaScript Function objects but | 601 /// Dart functions happen to be regular JavaScript Function objects but |
| 610 /// we can distinguish them based on whether they have been tagged with | 602 /// we can distinguish them based on whether they have been tagged with |
| 611 /// runtime type information. | 603 /// runtime type information. |
| 612 class FunctionFormatter extends Formatter { | 604 class FunctionFormatter implements Formatter { |
| 613 accept(object) { | 605 accept(object) { |
| 614 if (_typeof(object) != 'function') return false; | 606 if (_typeof(object) != 'function') return false; |
| 615 return dart.getReifiedType(object) != null; | 607 return dart.getReifiedType(object) != null; |
| 616 } | 608 } |
| 617 | 609 |
| 618 bool hasChildren(object) => true; | 610 bool hasChildren(object) => true; |
| 619 | 611 |
| 620 String preview(object) { | 612 String preview(object) { |
| 621 return dart.typeName(dart.getReifiedType(object)); | 613 return dart.typeName(dart.getReifiedType(object)); |
| 622 } | 614 } |
| 623 | 615 |
| 624 List<NameValuePair> children(object) => <NameValuePair>[ | 616 List<NameValuePair> children(object) => <NameValuePair>[ |
| 625 new NameValuePair(name: 'signature', value: preview(object)), | 617 new NameValuePair(name: 'signature', value: preview(object)), |
| 626 new NameValuePair( | 618 new NameValuePair( |
| 627 name: 'JavaScript Function', | 619 name: 'JavaScript Function', |
| 628 value: object, | 620 value: object, |
| 629 config: JsonMLConfig.skipDart) | 621 config: JsonMLConfig.skipDart) |
| 630 ]; | 622 ]; |
| 631 } | 623 } |
| 632 | 624 |
| 633 /// Formatter for Dart Map objects. | 625 /// Formatter for Dart Map objects. |
| 634 class MapFormatter extends ObjectFormatter { | 626 class MapFormatter implements Formatter { |
| 635 accept(object) => object is Map; | 627 accept(object) => object is Map; |
| 636 | 628 |
| 637 bool hasChildren(object) => true; | 629 bool hasChildren(object) => true; |
| 638 | 630 |
| 639 String preview(object) { | 631 String preview(object) { |
| 640 Map map = object; | 632 Map map = object; |
| 641 return '${getObjectTypeName(map)} length ${map.length}'; | 633 return '${getObjectTypeName(map)} length ${map.length}'; |
| 642 } | 634 } |
| 643 | 635 |
| 644 List<NameValuePair> children(object) { | 636 List<NameValuePair> children(object) { |
| 645 // TODO(jacobr): be lazier about enumerating contents of Maps that are not | 637 // TODO(jacobr): be lazier about enumerating contents of Maps that are not |
| 646 // the build in LinkedHashMap class. | 638 // the build in LinkedHashMap class. |
| 647 // TODO(jacobr): handle large Maps better. | 639 // TODO(jacobr): handle large Maps better. |
| 648 Map map = object; | 640 Map map = object; |
| 649 var entries = new LinkedHashSet<NameValuePair>(); | 641 var entries = new LinkedHashSet<NameValuePair>(); |
| 650 map.forEach((key, value) { | 642 map.forEach((key, value) { |
| 651 var entryWrapper = new MapEntry(key: key, value: value); | 643 var entryWrapper = new MapEntry(key: key, value: value); |
| 652 entries.add(new NameValuePair( | 644 entries.add(new NameValuePair( |
| 653 name: entries.length.toString(), value: entryWrapper)); | 645 name: entries.length.toString(), value: entryWrapper)); |
| 654 }); | 646 }); |
| 655 addMetadataChildren(object, entries); | 647 addMetadataChildren(object, entries); |
| 656 return entries.toList(); | 648 return entries.toList(); |
| 657 } | 649 } |
| 658 } | 650 } |
| 659 | 651 |
| 660 /// Formatter for Dart Iterable objects including List and Set. | 652 /// Formatter for Dart Iterable objects including List and Set. |
| 661 class IterableFormatter extends ObjectFormatter { | 653 class IterableFormatter implements Formatter { |
| 662 bool accept(object) => object is Iterable; | 654 bool accept(object) => object is Iterable; |
| 663 | 655 |
| 664 String preview(object) { | 656 String preview(object) { |
| 665 Iterable iterable = object; | 657 Iterable iterable = object; |
| 666 try { | 658 try { |
| 667 var length = iterable.length; | 659 var length = iterable.length; |
| 668 return '${getObjectTypeName(iterable)} length $length'; | 660 return '${getObjectTypeName(iterable)} length $length'; |
| 669 } catch (_) { | 661 } catch (_) { |
| 670 return '${getObjectTypeName(iterable)}'; | 662 return '${getObjectTypeName(iterable)}'; |
| 671 } | 663 } |
| 672 } | 664 } |
| 673 | 665 |
| 674 bool hasChildren(object) => true; | 666 bool hasChildren(object) => true; |
| 675 | 667 |
| 676 List<NameValuePair> children(object) { | 668 List<NameValuePair> children(object) { |
| 677 // TODO(jacobr): be lazier about enumerating contents of Iterables that | 669 // TODO(jacobr): be lazier about enumerating contents of Iterables that |
| 678 // are not the built in Set or List types. | 670 // are not the built in Set or List types. |
| 679 // TODO(jacobr): handle large Iterables better. | 671 // TODO(jacobr): handle large Iterables better. |
| 680 // TODO(jacobr): consider only using numeric indices | 672 // TODO(jacobr): consider only using numeric indices |
| 681 var children = new LinkedHashSet<NameValuePair>(); | 673 var children = new LinkedHashSet<NameValuePair>(); |
| 682 children.addAll(new IterableSpan(0, object.length, object).children()); | 674 children.addAll(new IterableSpan(0, object.length, object).children()); |
| 683 // TODO(jacobr): provide a link to show regular class properties here. | 675 // TODO(jacobr): provide a link to show regular class properties here. |
| 684 // required for subclasses of iterable, etc. | 676 // required for subclasses of iterable, etc. |
| 685 addMetadataChildren(object, children); | 677 addMetadataChildren(object, children); |
| 686 return children.toList(); | 678 return children.toList(); |
| 687 } | 679 } |
| 688 } | 680 } |
| 689 | 681 |
| 690 // This class does double duting displaying metadata for | |
| 691 class ClassMetadataFormatter implements Formatter { | |
| 692 accept(object) => object is ClassMetadata; | |
| 693 | |
| 694 Object _getType(object) { | |
| 695 if (object is Type) return object; | |
| 696 return dart.getReifiedType(object); | |
| 697 } | |
| 698 | |
| 699 String preview(object) { | |
| 700 ClassMetadata entry = object; | |
| 701 var type = | |
| 702 entry.object is Type ? entry.object : dart.getReifiedType(entry.object); | |
| 703 var implements = dart.getImplements(type); | |
| 704 if (implements != null) { | |
| 705 var typeNames = implements().map(getTypeName); | |
| 706 return '${entry.typeName} implements ${typeNames.join(", ")}'; | |
| 707 } else { | |
| 708 return entry.typeName; | |
| 709 } | |
| 710 } | |
| 711 | |
| 712 bool hasChildren(object) => true; | |
| 713 | |
| 714 List<NameValuePair> children(object) { | |
| 715 ClassMetadata entry = object; | |
| 716 var classObject = entry.object; | |
| 717 // TODO(jacobr): add other entries describing the class such as | |
| 718 // links to the superclass, mixins, implemented interfaces, and methods. | |
| 719 var type = _getType(classObject); | |
| 720 var children = <NameValuePair>[]; | |
| 721 | |
| 722 var mixins = dart.getMixins(type); | |
| 723 if (mixins != null && mixins.isNotEmpty) { | |
| 724 children.add(new NameValuePair( | |
| 725 name: '[[Mixins]]', value: new HeritageClause('mixins', mixins))); | |
| 726 } | |
| 727 | |
| 728 var hiddenProperties = ['length', 'name', 'prototype']; | |
| 729 // Addition of NameValuePairs for static variables and named constructors. | |
| 730 for (var name in getOwnPropertyNames(classObject)) { | |
| 731 // TODO(bmilligan): Perform more principled checks to filter out spurious | |
| 732 // members. | |
| 733 if (hiddenProperties.contains(name)) continue; | |
| 734 var value = safeGetProperty(classObject, name); | |
| 735 if (value != null && dart.getIsNamedConstructor(value) != null) { | |
| 736 value = new NamedConstructor(value); | |
| 737 name = '${entry.typeName}.$name'; | |
| 738 } | |
| 739 children.add(new NameValuePair(name: name, value: value)); | |
| 740 } | |
| 741 | |
| 742 // TODO(bmilligan): Replace the hard coding of $identityHash. | |
| 743 var hiddenPrototypeProperties = ['constructor', 'new', r'$identityHash']; | |
| 744 // Addition of class methods. | |
| 745 var prototype = JS('var', '#["prototype"]', classObject); | |
| 746 if (prototype != null) { | |
| 747 for (var name in getOwnPropertyNames(prototype)) { | |
| 748 if (hiddenPrototypeProperties.contains(name)) continue; | |
| 749 // Simulate dart.bind by using dart.tag and tear off the function | |
| 750 // so it will be recognized by the FunctionFormatter. | |
| 751 var function = safeGetProperty(prototype, name); | |
| 752 var constructor = safeGetProperty(prototype, 'constructor'); | |
| 753 var sigObj = dart.getMethodSig(constructor); | |
| 754 if (sigObj != null) { | |
| 755 var value = safeGetProperty(sigObj, name); | |
| 756 if (getTypeName(dart.getReifiedType(value)) != 'Null') { | |
| 757 dart.tag(function, value); | |
| 758 children.add(new NameValuePair(name: name, value: function)); | |
| 759 } | |
| 760 } | |
| 761 } | |
| 762 } | |
| 763 // TODO(jacobr): provide a link to the base class or perhaps the entire | |
| 764 // base class hierarchy as a flat list. | |
| 765 // TODO(jacobr): add constructors, methods, extended class, and static | |
| 766 return children; | |
| 767 } | |
| 768 } | |
| 769 | |
| 770 class NamedConstructorFormatter implements Formatter { | 682 class NamedConstructorFormatter implements Formatter { |
| 771 accept(object) => object is NamedConstructor; | 683 accept(object) => object is NamedConstructor; |
| 772 | 684 |
| 773 // TODO(bmilligan): Display the signature of the named constructor as the | 685 // TODO(bmilligan): Display the signature of the named constructor as the |
| 774 // preview. | 686 // preview. |
| 775 String preview(object) => 'Named Constructor'; | 687 String preview(object) => 'Named Constructor'; |
| 776 | 688 |
| 777 bool hasChildren(object) => true; | 689 bool hasChildren(object) => true; |
| 778 | 690 |
| 779 List<NameValuePair> children(object) => <NameValuePair>[ | 691 List<NameValuePair> children(object) => <NameValuePair>[ |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 812 var typeNames = clause.types.map(getTypeName); | 724 var typeNames = clause.types.map(getTypeName); |
| 813 return '${clause.name} ${typeNames.join(", ")}'; | 725 return '${clause.name} ${typeNames.join(", ")}'; |
| 814 } | 726 } |
| 815 | 727 |
| 816 bool hasChildren(object) => true; | 728 bool hasChildren(object) => true; |
| 817 | 729 |
| 818 List<NameValuePair> children(object) { | 730 List<NameValuePair> children(object) { |
| 819 HeritageClause clause = object; | 731 HeritageClause clause = object; |
| 820 var children = <NameValuePair>[]; | 732 var children = <NameValuePair>[]; |
| 821 for (var type in clause.types) { | 733 for (var type in clause.types) { |
| 822 children.add(new NameValuePair(value: new ClassMetadata(type))); | 734 JSNative.setProperty(type, isClass, true); |
| 735 children.add(new NameValuePair(value: type)); | |
| 823 } | 736 } |
| 824 return children; | 737 return children; |
| 825 } | 738 } |
| 826 } | 739 } |
| 827 | 740 |
| 828 /// Formatter for synthetic IterableSpan objects used to display contents of | 741 /// Formatter for synthetic IterableSpan objects used to display contents of |
| 829 /// an Iterable cleanly. | 742 /// an Iterable cleanly. |
| 830 class IterableSpanFormatter implements Formatter { | 743 class IterableSpanFormatter implements Formatter { |
| 831 accept(object) => object is IterableSpan; | 744 accept(object) => object is IterableSpan; |
| 832 | 745 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 851 // StackTrace will be added as its own child. | 764 // StackTrace will be added as its own child. |
| 852 List<NameValuePair> children(object) => object | 765 List<NameValuePair> children(object) => object |
| 853 .toString() | 766 .toString() |
| 854 .split('\n') | 767 .split('\n') |
| 855 .map((line) => new NameValuePair( | 768 .map((line) => new NameValuePair( |
| 856 value: line.replaceFirst(new RegExp(r'^\s+at\s'), ''), | 769 value: line.replaceFirst(new RegExp(r'^\s+at\s'), ''), |
| 857 hideName: true)) | 770 hideName: true)) |
| 858 .toList(); | 771 .toList(); |
| 859 } | 772 } |
| 860 | 773 |
| 774 class ClassFormatter implements Formatter { | |
| 775 accept(object) => object is Type || safeGetProperty(object, isClass) == true; | |
| 776 | |
| 777 String preview(object) { | |
| 778 // TODO(bmilligan): Tag classes with generic types with a Symbol at their | |
| 779 // creation so they can be recognized by the ClassFormatter. | |
| 780 var typeName = safeGetProperty(object, 'genericTypeName'); | |
| 781 if (typeName != null) return typeName; | |
| 782 var type = _getType(object); | |
| 783 var implements = dart.getImplements(type); | |
| 784 typeName = getTypeName(type); | |
| 785 if (implements != null) { | |
| 786 var typeNames = implements().map(getTypeName); | |
| 787 return '${typeName} implements ${typeNames.join(", ")}'; | |
| 788 } else { | |
| 789 return typeName; | |
| 790 } | |
| 791 } | |
| 792 | |
| 793 bool hasChildren(object) => true; | |
| 794 | |
| 795 List<NameValuePair> children(object) { | |
| 796 // TODO(jacobr): add other entries describing the class such as | |
| 797 // links to the superclass, mixins, implemented interfaces, and methods. | |
| 798 var type = _getType(object); | |
| 799 var children = <NameValuePair>[]; | |
| 800 var typeName = getTypeName(_getType(object)); | |
| 801 var mixins = dart.getMixins(type); | |
| 802 if (mixins != null && mixins.isNotEmpty) { | |
| 803 children.add(new NameValuePair( | |
| 804 name: '[[Mixins]]', value: new HeritageClause('mixins', mixins))); | |
| 805 } | |
| 806 | |
| 807 var hiddenProperties = ['length', 'name', 'prototype', 'genericTypeName']; | |
| 808 // Addition of NameValuePairs for static variables and named constructors. | |
| 809 for (var name in getOwnPropertyNames(object)) { | |
| 810 // TODO(bmilligan): Perform more principled checks to filter out spurious | |
| 811 // members. | |
| 812 if (hiddenProperties.contains(name)) continue; | |
| 813 var value = safeGetProperty(object, name); | |
| 814 if (value != null && dart.getIsNamedConstructor(value) != null) { | |
| 815 value = new NamedConstructor(value); | |
| 816 name = '${typeName}.$name'; | |
| 817 } | |
| 818 children.add(new NameValuePair(name: name, value: value)); | |
| 819 } | |
| 820 | |
| 821 // TODO(bmilligan): Replace the hard coding of $identityHash. | |
| 822 var hiddenPrototypeProperties = ['constructor', 'new', r'$identityHash']; | |
| 823 // Addition of class methods. | |
| 824 var prototype = JS('var', '#["prototype"]', object); | |
| 825 if (prototype != null) { | |
| 826 for (var name in getOwnPropertyNames(prototype)) { | |
| 827 if (hiddenPrototypeProperties.contains(name)) continue; | |
| 828 // Simulate dart.bind by using dart.tag and tear off the function | |
| 829 // so it will be recognized by the FunctionFormatter. | |
| 830 var function = safeGetProperty(prototype, name); | |
| 831 var constructor = safeGetProperty(prototype, 'constructor'); | |
| 832 var sigObj = dart.getMethodSig(constructor); | |
| 833 if (sigObj != null) { | |
| 834 var value = safeGetProperty(sigObj, name); | |
| 835 if (getTypeName(dart.getReifiedType(value)) != 'Null') { | |
| 836 dart.tag(function, value); | |
| 837 children.add(new NameValuePair(name: name, value: function)); | |
| 838 } | |
| 839 } | |
| 840 } | |
| 841 } | |
| 842 return children; | |
| 843 } | |
| 844 } | |
| 845 | |
| 861 /// This entry point is automatically invoked by the code generated by | 846 /// This entry point is automatically invoked by the code generated by |
| 862 /// Dart Dev Compiler | 847 /// Dart Dev Compiler |
| 863 registerDevtoolsFormatter() { | 848 registerDevtoolsFormatter() { |
| 864 var formatters = [_devtoolsFormatter]; | 849 var formatters = [_devtoolsFormatter]; |
| 865 JS('', 'dart.global.devtoolsFormatters = #', formatters); | 850 JS('', 'dart.global.devtoolsFormatters = #', formatters); |
| 866 } | 851 } |
| OLD | NEW |