Only use MapFormatter for SDK maps (HashMap and LinkedHashMap)

For classes that implement Map, using MapFormatter can result in many,
many custom format operations. Also, the presentation is not that
useful. We get e.g. a list of indices that then have a name and value
beside them, so it just duplicates the Object view, but with extra
non-useful data.

Change-Id: I74ed34521778bddae9cdad975339925d7c181bf3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100282
Commit-Queue: Alan Knight <alanknight@google.com>
Reviewed-by: Jacob Richman <jacobr@google.com>
diff --git a/pkg/dev_compiler/tool/input_sdk/private/debugger.dart b/pkg/dev_compiler/tool/input_sdk/private/debugger.dart
index 3a6f4e9..69016fd 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/debugger.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/debugger.dart
@@ -6,6 +6,7 @@
 
 import 'dart:_foreign_helper' show JS;
 import 'dart:_interceptors' show JSArray;
+import 'dart:_js_helper' show InternalMap;
 import 'dart:_runtime' as dart;
 import 'dart:core';
 import 'dart:collection';
@@ -33,6 +34,7 @@
   static const keyToString = JsonMLConfig("keyToString");
   static const asClass = JsonMLConfig("asClass");
   static const asObject = JsonMLConfig("asObject");
+  static const asMap = JsonMLConfig("asMap");
   toString() => "JsonMLConfig($name)";
 }
 
@@ -458,6 +460,7 @@
       TypeFormatter(),
       NamedConstructorFormatter(),
       MapFormatter(),
+      MapOverviewFormatter(),
       IterableFormatter(),
       IterableSpanFormatter(),
       MapEntryFormatter(),
@@ -677,8 +680,13 @@
       ];
 }
 
-/// Formatter for Dart Map objects.
-class MapFormatter implements Formatter {
+/// Formatter for Objects that implement Map but are not system Maps.
+///
+/// This shows two sub-views, one for instance fields and one for
+/// Map key/value pairs.
+class MapOverviewFormatter implements Formatter {
+  // Because this comes after MapFormatter in the list, internal
+  // maps will be picked up by that formatter.
   accept(object, config) => object is Map;
 
   bool hasChildren(object) => true;
@@ -686,6 +694,35 @@
   String preview(object) {
     Map map = object;
     try {
+      return '${getObjectTypeName(map)}';
+    } catch (e) {
+      return safePreview(object, JsonMLConfig.none);
+    }
+  }
+
+  List<NameValuePair> children(object) => [
+        NameValuePair(
+            name: "[[instance view]]",
+            value: object,
+            config: JsonMLConfig.asObject),
+        NameValuePair(
+            name: "[[entries]]", value: object, config: JsonMLConfig.asMap)
+      ];
+}
+
+/// Formatter for Dart Map objects.
+///
+/// This is only used for internal maps, or when shown as [[entries]]
+/// from MapOverViewFormatter.
+class MapFormatter implements Formatter {
+  accept(object, config) =>
+      object is InternalMap || config == JsonMLConfig.asMap;
+
+  bool hasChildren(object) => true;
+
+  String preview(object) {
+    Map map = object;
+    try {
       return '${getObjectTypeName(map)} length ${map.length}';
     } catch (e) {
       return safePreview(object, JsonMLConfig.none);
@@ -703,20 +740,9 @@
       entries.add(
           NameValuePair(name: entries.length.toString(), value: entryWrapper));
     });
-    addInstanceMembers(object, entries);
     addMetadataChildren(object, entries);
     return entries.toList();
   }
-
-  // We've formatted as a Map, but we may want to see the internals
-  // of the Map, particularly for domain objects that implement Map.
-  // Add an ObjectFormatter view underneath.
-  void addInstanceMembers(object, Set<NameValuePair> ret) {
-    ret.add(NameValuePair(
-        name: "[[instance members]]",
-        value: object,
-        config: JsonMLConfig.asObject));
-  }
 }
 
 /// Formatter for Dart Iterable objects including List and Set.
diff --git a/tests/lib_2/html/debugger_test_golden.txt b/tests/lib_2/html/debugger_test_golden.txt
index 1c9ec45..b18cfc5 100644
--- a/tests/lib_2/html/debugger_test_golden.txt
+++ b/tests/lib_2/html/debugger_test_golden.txt
@@ -4234,34 +4234,6 @@
             {
                 "style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
             },
-            "[[instance members]]: "
-        ],
-        [
-            "span",
-            {
-                "style": "margin-left: 13px"
-            },
-            [
-                "object",
-                {
-                    "object": "<OBJECT>",
-                    "config": {
-                        "name": "asObject"
-                    }
-                }
-            ]
-        ]
-    ],
-    [
-        "li",
-        {
-            "style": "padding-left: 13px;"
-        },
-        [
-            "span",
-            {
-                "style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
-            },
             "[[class]]: "
         ],
         [
@@ -4393,34 +4365,6 @@
             {
                 "style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
             },
-            "[[instance members]]: "
-        ],
-        [
-            "span",
-            {
-                "style": "margin-left: 13px"
-            },
-            [
-                "object",
-                {
-                    "object": "<OBJECT>",
-                    "config": {
-                        "name": "asObject"
-                    }
-                }
-            ]
-        ]
-    ],
-    [
-        "li",
-        {
-            "style": "padding-left: 13px;"
-        },
-        [
-            "span",
-            {
-                "style": "background-color: thistle; color: rgb(136, 19, 145); margin-right: -13px"
-            },
             "[[class]]: "
         ],
         [
@@ -7308,4 +7252,4 @@
         ]
     ]
 ]
------------------------------------
\ No newline at end of file
+-----------------------------------