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

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

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