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

Side by Side Diff: pkg/analyzer/lib/src/summary/inspect.dart

Issue 1905173002: Add a debugging tool for inspecting the contents of a summary file. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 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
« no previous file with comments | « no previous file | pkg/analyzer/tool/summary/inspect.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'dart:convert';
6 import 'dart:mirrors';
7
8 import 'package:analyzer/src/generated/utilities_dart.dart';
9 import 'package:analyzer/src/summary/base.dart';
10 import 'package:analyzer/src/summary/idl.dart';
11
12 const int MAX_LINE_LENGTH = 80;
13
14 /**
15 * Cache used to speed up [isEnum].
16 */
17 Map<Type, bool> _isEnumCache = <Type, bool>{};
18
19 /**
20 * Determine if the given [obj] has an enumerated type.
21 */
22 bool isEnum(Object obj) {
23 return _isEnumCache.putIfAbsent(
24 obj.runtimeType, () => reflect(obj).type.isEnum);
25 }
26
27 /**
28 * Decoded reprensentation of a part of a summary that occupies multiple lines
29 * of output.
30 */
31 class BrokenEntity implements DecodedEntity {
32 final String opener;
33 final Map<String, DecodedEntity> parts;
34 final String closer;
35
36 BrokenEntity(this.opener, this.parts, this.closer);
37
38 @override
39 List<String> getLines() {
40 List<String> result = <String>[opener];
41 bool first = true;
42 for (String key in parts.keys) {
43 if (first) {
44 first = false;
45 } else {
46 result[result.length - 1] += ',';
47 }
48 List<String> subResult = parts[key].getLines();
49 subResult[0] = '$key: ${subResult[0]}';
50 result.addAll(subResult.map((String s) => ' $s'));
51 }
52 result.add(closer);
53 return result;
54 }
55 }
56
57 /**
58 * Decoded representation of a part of a summary.
59 */
60 abstract class DecodedEntity {
61 /**
62 * Create a representation of a part of the summary that consists of a group
63 * of entities (represented by [parts]) contined between [opener] and
scheglov 2016/04/21 22:11:41 contined -> contained
Paul Berry 2016/04/21 22:31:08 Done.
64 * [closers].
scheglov 2016/04/21 22:11:41 [closers] -> [closer]
Paul Berry 2016/04/21 22:31:08 Done.
65 *
66 * If [forceKeys] is `true`, the keys in [parts] will always be shown. If
67 * [forceKeys] is `false`, they keys will only be shown if the output is
68 * broken into multiple lines.
69 */
70 factory DecodedEntity.group(String opener, Map<String, DecodedEntity> parts,
71 String closer, bool forceKeys) {
72 // Attempt to format the entity in a single line; if not bail out and
73 // construct a _BrokenEntity.
74 DecodedEntity bailout() => new BrokenEntity(opener, parts, closer);
75 String short = opener;
76 bool first = true;
77 for (String key in parts.keys) {
78 if (first) {
79 first = false;
80 } else {
81 short += ', ';
82 }
83 DecodedEntity value = parts[key];
84 if (forceKeys) {
85 short += '$key: ';
86 }
87 if (value is UnbrokenEntity) {
88 short += value._s;
89 } else {
90 return bailout();
91 }
92 if (short.length > MAX_LINE_LENGTH) {
93 return bailout();
94 }
95 }
96 return new DecodedEntity.short(short + closer);
97 }
98
99 /**
100 * Create a representation of a part of the summary that is represented by a
101 * single unbroken string.
102 */
103 factory DecodedEntity.short(String s) = UnbrokenEntity;
104
105 /**
106 * Format this entity into a sequence of strings (one per output line).
107 */
108 List<String> getLines();
109 }
110
111 /**
112 * Wrapper around a [LinkedLibrary] and its constituent [UnlinkedUnit]s.
113 */
114 class LibraryWrapper {
115 final LinkedLibrary _linked;
116 final List<UnlinkedUnit> _unlinked;
117
118 LibraryWrapper(this._linked, this._unlinked);
119 }
120
121 /**
122 * Wrapper around a [LinkedReference] and its corresponding [UnlinkedReference].
123 */
124 class ReferenceWrapper {
125 final LinkedReference _linked;
126 final UnlinkedReference _unlinked;
127
128 ReferenceWrapper(this._linked, this._unlinked);
129
130 String get name {
131 if (_linked != null && _linked.name.isNotEmpty) {
132 return _linked.name;
133 } else if (_unlinked != null && _unlinked.name.isNotEmpty) {
134 return _unlinked.name;
135 } else {
136 return '???';
137 }
138 }
139 }
140
141 /**
142 * Instances of [SummaryInspector] are capable of traversing a summary and
143 * converting it to semi-human-readable output.
144 */
145 class SummaryInspector {
146 /**
147 * The dependencies of the library currently being visited.
148 */
149 List<LinkedDependency> _dependencies;
150
151 /**
152 * The references of the unit currently being visited.
153 */
154 List<ReferenceWrapper> _references;
155
156 /**
157 * Decode the object [obj], which was reached by examining [key] inside
158 * another object.
159 */
160 DecodedEntity decode(Object obj, String key) {
161 if (obj is PackageBundle) {
162 return decodePackageBundle(obj);
163 }
164 if (obj is LibraryWrapper) {
165 return decodeLibrary(obj);
166 }
167 if (obj is UnitWrapper) {
168 return decodeUnit(obj);
169 }
170 if (obj is ReferenceWrapper) {
171 return decodeReference(obj);
172 }
173 if (obj is DecodedEntity) {
174 return obj;
175 }
176 if (obj is SummaryClass) {
177 Map<String, Object> map = obj.toMap();
178 return decodeMap(map);
179 } else if (obj is List) {
180 Map<String, DecodedEntity> parts = <String, DecodedEntity>{};
181 for (int i = 0; i < obj.length; i++) {
182 parts[i.toString()] = decode(obj[i], key);
183 }
184 return new DecodedEntity.group('[', parts, ']', false);
185 } else if (obj is String) {
186 return new DecodedEntity.short(JSON.encode(obj));
187 } else if (isEnum(obj)) {
188 return new DecodedEntity.short(obj.toString().split('.')[1]);
189 } else if (obj is int &&
190 key == 'dependency' &&
191 _dependencies != null &&
192 obj < _dependencies.length) {
193 return new DecodedEntity.short('$obj (${_dependencies[obj].uri})');
194 } else if (obj is int &&
195 key == 'reference' &&
196 _references != null &&
197 obj < _references.length) {
198 return new DecodedEntity.short('$obj (${_references[obj].name})');
199 } else {
200 return new DecodedEntity.short(obj.toString());
201 }
202 }
203
204 /**
205 * Decode the given [LibraryWrapper].
206 */
207 DecodedEntity decodeLibrary(LibraryWrapper obj) {
208 try {
209 LinkedLibrary linked = obj._linked;
210 List<UnlinkedUnit> unlinked = obj._unlinked;
211 _dependencies = linked.dependencies;
212 Map<String, Object> result = linked.toMap();
213 result.remove('units');
214 result['defining compilation unit'] =
215 new UnitWrapper(linked.units[0], unlinked[0]);
216 for (int i = 1; i < linked.units.length; i++) {
217 String partUri = unlinked[0].publicNamespace.parts[i - 1];
218 result['part ${JSON.encode(partUri)}'] =
219 new UnitWrapper(linked.units[i], unlinked[i]);
220 }
221 return decodeMap(result);
222 } finally {
223 _dependencies = null;
224 }
225 }
226
227 /**
228 * Decode the given [map].
229 */
230 DecodedEntity decodeMap(Map<String, Object> map) {
231 Map<String, DecodedEntity> parts = <String, DecodedEntity>{};
232 map = reorderMap(map);
233 map.forEach((String key, Object value) {
234 if (value is String && value.isEmpty) {
235 return;
236 }
237 if (isEnum(value) && (value as dynamic).index == 0) {
238 return;
239 }
240 if (value is int && value == 0) {
241 return;
242 }
243 if (value is bool && value == false) {
244 return;
245 }
246 if (value == null) {
247 return;
248 }
249 if (value is List) {
250 if (value.isEmpty) {
251 return;
252 }
253 DecodedEntity entity = decode(value, key);
254 if (entity is BrokenEntity) {
255 for (int i = 0; i < value.length; i++) {
256 parts['$key[$i]'] = decode(value[i], key);
257 }
258 return;
259 } else {
260 parts[key] = entity;
261 }
262 }
263 parts[key] = decode(value, key);
264 });
265 return new DecodedEntity.group('{', parts, '}', true);
266 }
267
268 /**
269 * Decode the given [PackageBundle].
270 */
271 DecodedEntity decodePackageBundle(PackageBundle bundle) {
272 Map<String, UnlinkedUnit> units = <String, UnlinkedUnit>{};
273 Set<String> seenUnits = new Set<String>();
274 for (int i = 0; i < bundle.unlinkedUnits.length; i++) {
275 units[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
276 }
277 Map<String, Object> restOfMap = bundle.toMap();
278 Map<String, Object> result = <String, Object>{};
279 result['version'] = new DecodedEntity.short(
280 '${bundle.majorVersion}.${bundle.minorVersion}');
281 restOfMap.remove('majorVersion');
282 restOfMap.remove('minorVersion');
283 for (int i = 0; i < bundle.linkedLibraries.length; i++) {
284 String libraryUriString = bundle.linkedLibraryUris[i];
285 Uri libraryUri = Uri.parse(libraryUriString);
286 UnlinkedUnit unlinkedDefiningUnit = units[libraryUriString];
287 seenUnits.add(libraryUriString);
288 List<UnlinkedUnit> libraryUnits = <UnlinkedUnit>[unlinkedDefiningUnit];
289 LinkedLibrary linkedLibrary = bundle.linkedLibraries[i];
290 for (int j = 1; j < linkedLibrary.units.length; j++) {
291 String partUriString = resolveRelativeUri(libraryUri,
292 Uri.parse(unlinkedDefiningUnit.publicNamespace.parts[j - 1]))
293 .toString();
294 libraryUnits.add(units[partUriString]);
295 seenUnits.add(partUriString);
296 }
297 result['library ${JSON.encode(libraryUriString)}'] =
298 new LibraryWrapper(linkedLibrary, libraryUnits);
299 }
300 for (String uriString in units.keys) {
301 if (seenUnits.contains(uriString)) {
302 continue;
303 }
304 result['orphan unit ${JSON.encode(uriString)}'] =
305 new UnitWrapper(null, units[uriString]);
306 }
307 restOfMap.remove('linkedLibraries');
308 restOfMap.remove('linkedLibraryUris');
309 restOfMap.remove('unlinkedUnits');
310 restOfMap.remove('unlinkedUnitUris');
311 result.addAll(restOfMap);
312 return decodeMap(result);
313 }
314
315 /**
316 * Decode the given [ReferenceWrapper].
317 */
318 DecodedEntity decodeReference(ReferenceWrapper obj) {
319 Map<String, Object> result = obj._unlinked != null
320 ? obj._unlinked.toMap()
321 : <String, Object>{'linkedOnly': true};
322 if (obj._linked != null) {
323 mergeMaps(result, obj._linked.toMap());
324 }
325 return decodeMap(result);
326 }
327
328 /**
329 * Decode the given [UnitWrapper].
330 */
331 DecodedEntity decodeUnit(UnitWrapper obj) {
332 try {
333 LinkedUnit linked = obj._linked;
334 UnlinkedUnit unlinked = obj._unlinked;
335 Map<String, Object> unlinkedMap = unlinked.toMap();
336 Map<String, Object> linkedMap =
337 linked != null ? linked.toMap() : <String, Object>{};
338 Map<String, Object> result = <String, Object>{};
339 List<ReferenceWrapper> references = <ReferenceWrapper>[];
340 int numReferences = linked != null
341 ? linked.references.length
342 : unlinked.references.length;
343 for (int i = 0; i < numReferences; i++) {
344 references.add(new ReferenceWrapper(
345 linked != null ? linked.references[i] : null,
346 i < unlinked.references.length ? unlinked.references[i] : null));
347 }
348 result['references'] = references;
349 _references = references;
350 unlinkedMap.remove('references');
351 linkedMap.remove('references');
352 linkedMap.forEach((String key, Object value) {
353 result['linked $key'] = value;
354 });
355 unlinkedMap.forEach((String key, Object value) {
356 result[key] = value;
357 });
358 return decodeMap(result);
359 } finally {
360 _references = null;
361 }
362 }
363
364 /**
365 * Decode the given [PackageBundle] and dump it to a list of strings.
366 */
367 List<String> dumpPackageBundle(PackageBundle bundle) {
368 DecodedEntity decoded = decode(bundle, 'PackageBundle');
369 return decoded.getLines();
370 }
371
372 /**
373 * Merge the contents of [other] into [result], discarding empty entries.
374 */
375 void mergeMaps(Map<String, Object> result, Map<String, Object> other) {
376 other.forEach((String key, Object value) {
377 if (value is String && value.isEmpty) {
378 return;
379 }
380 if (result.containsKey(key)) {
381 Object oldValue = result[key];
382 if (oldValue is String && oldValue.isEmpty) {
383 result[key] = value;
384 } else {
385 throw new Exception(
386 'Duplicate values for $key: $oldValue and $value');
387 }
388 } else {
389 result[key] = value;
390 }
391 });
392 }
393
394 /**
395 * Reorder [map] for more intuitive display.
396 */
397 Map<String, Object> reorderMap(Map<String, Object> map) {
398 Map<String, Object> result = <String, Object>{};
399 if (map.containsKey('name')) {
400 result['name'] = map['name'];
401 }
402 result.addAll(map);
403 return result;
404 }
405 }
406
407 /**
408 * Decoded reprensentation of a part of a summary that occupies a single line of
409 * output.
410 */
411 class UnbrokenEntity implements DecodedEntity {
412 final String _s;
413
414 UnbrokenEntity(this._s);
415
416 @override
417 List<String> getLines() => <String>[_s];
418 }
419
420 /**
421 * Wrapper around a [LinkedUnit] and its corresponding [UnlinkedUnit].
422 */
423 class UnitWrapper {
424 final LinkedUnit _linked;
425 final UnlinkedUnit _unlinked;
426
427 UnitWrapper(this._linked, this._unlinked);
428 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/tool/summary/inspect.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698