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

Side by Side Diff: pkg/analysis_server/lib/src/index/split_store.dart

Issue 348773003: Port SplitIndexStore to Dart. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixes for review comments Created 6 years, 6 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014, 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 library index.split.store;
6
7 import 'dart:async';
8 import 'dart:collection';
9 import 'dart:io';
10 import 'dart:typed_data';
11
12 import 'package:analyzer/src/generated/element.dart';
13 import 'package:analyzer/src/generated/engine.dart';
14 import 'package:analyzer/src/generated/index.dart';
15 import 'package:analyzer/src/generated/java_engine.dart';
16 import 'package:analyzer/src/generated/source.dart';
17
18
19 /**
20 * A helper that encodes/decodes [AnalysisContext]s from/to integers.
21 *
22 * TODO(scheglov) add API to remove [AnalysisContext]s.
23 */
24 class ContextCodec {
25 /**
26 * A table mapping contexts to their unique indices.
27 */
28 Map<AnalysisContext, int> _contextToIndex = new HashMap<AnalysisContext, int>(
29 );
30
31 /**
32 * A table mapping indices to the corresponding contexts.
33 */
34 Map<int, AnalysisContext> _indexToContext = new HashMap<int, AnalysisContext>(
35 );
36
37 /**
38 * Returns the [AnalysisContext] that corresponds to the given index.
39 */
40 AnalysisContext decode(int index) => _indexToContext[index];
41
42 /**
43 * Returns an unique index for the given [AnalysisContext].
44 */
45 int encode(AnalysisContext context) {
46 int index = _contextToIndex[context];
47 if (index == null) {
48 index = _indexToContext.length;
49 _contextToIndex[context] = index;
50 _indexToContext[index] = context;
51 }
52 return index;
53 }
54 }
55
56
57 /**
58 * A helper that encodes/decodes [Element]s to/from integers.
59 */
60 class ElementCodec {
61 /**
62 * A list that works as a mapping of integers to element encodings (in form of integer arrays).
63 */
64 List<List<int>> _indexToPath = [];
65
66 /**
67 * A table mapping element locations (in form of integer arrays) into a single integer.
68 */
69 IntArrayToIntMap _pathToIndex = new IntArrayToIntMap(10000, 0.75);
70
71 final StringCodec _stringCodec;
72
73 ElementCodec(this._stringCodec);
74
75 /**
76 * Returns an [Element] that corresponds to the given location.
77 *
78 * @param context the [AnalysisContext] to find [Element] in
79 * @param index an integer corresponding to the [Element]
80 * @return the [Element] or `null`
81 */
82 Element decode(AnalysisContext context, int index) {
83 List<int> path = _indexToPath[index];
84 List<String> components = _getLocationComponents(path);
85 ElementLocation location = new ElementLocationImpl.con3(components);
86 return context.getElement(location);
87 }
88
89 /**
90 * Returns a unique integer that corresponds to the given [Element].
91 */
92 int encode(Element element) {
93 List<int> path = _getLocationPath(element);
94 int index = _pathToIndex.get(path, -1);
95 if (index == -1) {
96 index = _indexToPath.length;
97 _pathToIndex.put(path, index);
98 _indexToPath.add(path);
99 }
100 return index;
101 }
102
103 List<String> _getLocationComponents(List<int> path) {
104 int length = path.length;
105 List<String> components = new List<String>();
106 for (int i = 0; i < length; i++) {
107 int componentId = path[i];
108 String component = _stringCodec.decode(componentId);
109 if (i < length - 1 && path[i + 1] < 0) {
110 component += "@${(-path[i + 1])}";
111 i++;
112 }
113 components.add(component);
114 }
115 return components;
116 }
117
118 List<int> _getLocationPath(Element element) {
119 List<String> components = element.location.components;
120 int length = components.length;
121 if (_hasLocalOffset(components)) {
122 List<int> path = new List<int>();
123 for (String component in components) {
124 int atOffset = component.indexOf('@');
125 if (atOffset == -1) {
126 path.add(_stringCodec.encode(component));
127 } else {
128 String preAtString = component.substring(0, atOffset);
129 String atString = component.substring(atOffset + 1);
130 path.add(_stringCodec.encode(preAtString));
131 path.add(-1 * int.parse(atString));
132 }
133 }
134 return path;
135 } else {
136 List<int> path = new List<int>.filled(length, 0);
137 for (int i = 0; i < length; i++) {
138 String component = components[i];
139 path[i] = _stringCodec.encode(component);
140 }
141 return path;
142 }
143 }
144
145 bool _hasLocalOffset(List<String> components) {
146 for (String component in components) {
147 if (component.indexOf('@') != -1) {
148 return true;
149 }
150 }
151 return false;
152 }
153 }
154
155
156 /**
157 * A manager for files content.
158 */
159 abstract class FileManager {
160 /**
161 * Removes all files.
162 */
163 void clear();
164
165 /**
166 * Deletes the file with the given name.
167 */
168 void delete(String name);
169
170 /**
171 * Read the entire file contents as a list of bytes.
172 */
173 Future<List<int>> read(String name);
174
175 /**
176 * Write a list of bytes to a file.
177 */
178 Future write(String name, Uint8List bytes);
179 }
180
181
182 /**
183 * A [FileManager] based [NodeManager].
184 */
185 class FileNodeManager implements NodeManager {
186 static int _VERSION = 1;
187
188 final ContextCodec contextCodec;
189
190 final ElementCodec elementCodec;
191
192 final StringCodec stringCodec;
193
194 final FileManager _fileManager;
195
196 int _locationCount = 0;
197
198 final Logger _logger;
199
200 Map<String, int> _nodeLocationCounts = {};
201
202 final RelationshipCodec _relationshipCodec;
203
204 FileNodeManager(this._fileManager, this._logger, this.stringCodec,
205 this.contextCodec, this.elementCodec, this._relationshipCodec);
206
207 @override
208 int get locationCount => _locationCount;
209
210 @override
211 void clear() {
212 _fileManager.clear();
213 }
214
215 @override
216 Future<IndexNode> getNode(String name) {
217 return _fileManager.read(name).then((List<int> bytes) {
218 if (bytes == null) {
219 return null;
220 }
221 _DataInputStream stream = new _DataInputStream(bytes);
222 return _readNode(stream);
223 }).catchError((e, stackTrace) {
224 _logger.logError2("Exception during reading index file ${name}",
225 new CaughtException(e, stackTrace));
226 });
227 }
228
229 @override
230 IndexNode newNode(AnalysisContext context) => new IndexNode(context,
231 elementCodec, _relationshipCodec);
232
233 @override
234 Future putNode(String name, IndexNode node) {
235 // update location count
236 {
237 _locationCount -= _getLocationCount(name);
238 int nodeLocationCount = node.locationCount;
239 _nodeLocationCounts[name] = nodeLocationCount;
240 _locationCount += nodeLocationCount;
241 }
242 // write the node
243 return new Future.microtask(() {
244 _DataOutputStream stream = new _DataOutputStream();
245 _writeNode(node, stream);
246 var bytes = stream.getBytes();
247 return _fileManager.write(name, bytes);
248 }).catchError((e, stackTrace) {
249 _logger.logError2("Exception during reading index file ${name}",
250 new CaughtException(e, stackTrace));
251 });
252 }
253
254 @override
255 void removeNode(String name) {
256 // update location count
257 _locationCount -= _getLocationCount(name);
258 _nodeLocationCounts.remove(name);
259 // remove node
260 _fileManager.delete(name);
261 }
262
263 int _getLocationCount(String name) {
264 int locationCount = _nodeLocationCounts[name];
265 return locationCount != null ? locationCount : 0;
266 }
267
268 RelationKeyData _readElementRelationKey(_DataInputStream stream) {
269 int elementId = stream.readInt();
270 int relationshipId = stream.readInt();
271 return new RelationKeyData.forData(elementId, relationshipId);
272 }
273
274 LocationData _readLocationData(_DataInputStream stream) {
275 int elementId = stream.readInt();
276 int offset = stream.readInt();
277 int length = stream.readInt();
278 return new LocationData.forData(elementId, offset, length);
279 }
280
281 IndexNode _readNode(_DataInputStream stream) {
282 // check version
283 {
284 int version = stream.readInt();
285 if (version != _VERSION) {
286 throw new StateError(
287 "Version ${_VERSION} expected, but ${version} found.");
288 }
289 }
290 // context
291 int contextId = stream.readInt();
292 AnalysisContext context = contextCodec.decode(contextId);
293 if (context == null) {
294 return null;
295 }
296 // relations
297 Map<RelationKeyData, List<LocationData>> relations = {};
298 int numRelations = stream.readInt();
299 for (int i = 0; i < numRelations; i++) {
300 RelationKeyData key = _readElementRelationKey(stream);
301 int numLocations = stream.readInt();
302 List<LocationData> locations = new List<LocationData>();
303 for (int j = 0; j < numLocations; j++) {
304 locations.add(_readLocationData(stream));
305 }
306 relations[key] = locations;
307 }
308 // create IndexNode
309 IndexNode node = new IndexNode(context, elementCodec, _relationshipCodec);
310 node.relations = relations;
311 return node;
312 }
313
314 void _writeElementRelationKey(_DataOutputStream stream, RelationKeyData key) {
315 stream.writeInt(key.elementId);
316 stream.writeInt(key.relationshipId);
317 }
318
319 void _writeNode(IndexNode node, _DataOutputStream stream) {
320 // version
321 stream.writeInt(_VERSION);
322 // context
323 {
324 AnalysisContext context = node.context;
325 int contextId = contextCodec.encode(context);
326 stream.writeInt(contextId);
327 }
328 // relations
329 Map<RelationKeyData, List<LocationData>> relations = node.relations;
330 stream.writeInt(relations.length);
331 relations.forEach((key, locations) {
332 _writeElementRelationKey(stream, key);
333 stream.writeInt(locations.length);
334 for (LocationData location in locations) {
335 stream.writeInt(location.elementId);
336 stream.writeInt(location.offset);
337 stream.writeInt(location.length);
338 }
339 });
340 }
341 }
342
343
344 /**
345 * A single index file in-memory presentation.
346 */
347 class IndexNode {
348 final AnalysisContext context;
349
350 final ElementCodec _elementCodec;
351
352 Map<RelationKeyData, List<LocationData>> _relations =
353 new HashMap<RelationKeyData, List<LocationData>>();
354
355 final RelationshipCodec _relationshipCodec;
356
357 IndexNode(this.context, this._elementCodec, this._relationshipCodec);
358
359 /**
360 * Returns number of locations in this node.
361 */
362 int get locationCount {
363 int locationCount = 0;
364 for (List<LocationData> locations in _relations.values) {
365 locationCount += locations.length;
366 }
367 return locationCount;
368 }
369
370 /**
371 * Returns the recorded relations.
372 */
373 Map<RelationKeyData, List<LocationData>> get relations => _relations;
374
375 /**
376 * Sets relations data. This method is used during loading data from a storage .
377 */
378 void set relations(Map<RelationKeyData, List<LocationData>> relations) {
379 this._relations.clear();
380 this._relations.addAll(relations);
381 }
382
383 /**
384 * Return the locations of the elements that have the given relationship with the given element.
385 *
386 * @param element the the element that has the relationship with the locations to be returned
387 * @param relationship the [Relationship] between the given element and the lo cations to be
388 * returned
389 */
390 List<Location> getRelationships(Element element, Relationship relationship) {
391 // prepare key
392 RelationKeyData key = new RelationKeyData.forObject(_elementCodec,
393 _relationshipCodec, element, relationship);
394 // find LocationData(s)
395 List<LocationData> locationDatas = _relations[key];
396 if (locationDatas == null) {
397 return Location.EMPTY_ARRAY;
398 }
399 // convert to Location(s)
400 List<Location> locations = [];
401 for (LocationData locationData in locationDatas) {
402 Location location = locationData.getLocation(context, _elementCodec);
403 if (location != null) {
404 locations.add(location);
405 }
406 }
407 return locations;
408 }
409
410 /**
411 * Records that the given element and location have the given relationship.
412 *
413 * @param element the element that is related to the location
414 * @param relationship the [Relationship] between the element and the location
415 * @param location the [Location] where relationship happens
416 */
417 void recordRelationship(Element element, Relationship relationship,
418 Location location) {
419 RelationKeyData key = new RelationKeyData.forObject(_elementCodec,
420 _relationshipCodec, element, relationship);
421 // prepare LocationData(s)
422 List<LocationData> locationDatas = _relations[key];
423 if (locationDatas == null) {
424 locationDatas = [];
425 _relations[key] = locationDatas;
426 }
427 // add new LocationData
428 locationDatas.add(new LocationData.forObject(_elementCodec, location));
429 }
430 }
431
432
433 class IntArrayToIntMap {
434 // TODO(scheglov) consider using Int32List
435 final Map<List<int>, int> map = new HashMap<List<int>, int>(equals:
436 _intArrayEquals, hashCode: _intArrayHashCode);
437
438 IntArrayToIntMap(int initialCapacity, double loadFactor);
439
440 int get(List<int> key, int defaultValue) {
441 int value = map[key];
442 if (value == null) {
443 return defaultValue;
444 }
445 return value;
446 }
447
448 void put(List<int> key, int value) {
449 map[key] = value;
450 }
451
452 static bool _intArrayEquals(List<int> a, List<int> b) {
453 int length = a.length;
454 if (length != b.length) {
455 return false;
456 }
457 for (int i = 0; i < length; i++) {
458 if (a[i] != b[i]) {
459 return false;
460 }
461 }
462 return true;
463 }
464
465 static int _intArrayHashCode(List<int> key) {
466 return key.fold(0, (int result, int item) {
467 return 31 * result + item;
468 });
469 }
470 }
471
472
473 class IntToIntSetMap {
474 // TODO(scheglov) consider using Int32List
475 final Map<int, List<int>> _map = new HashMap<int, List<int>>();
476 int _size = 0;
477
478 IntToIntSetMap(int initialCapacity, double loadFactor);
479
480 int get length => _size;
481
482 void add(int key, int value) {
483 List<int> values = _map[key];
484 if (values == null) {
485 values = new List<int>();
486 _map[key] = values;
487 }
488 if (values.indexOf(value) == -1) {
489 values.add(value);
490 _size++;
491 }
492 }
493
494 void clear() {
495 _map.clear();
496 _size = 0;
497 }
498
499 List<int> get(int key) {
500 List<int> values = _map[key];
501 if (values == null) {
502 values = <int>[];
503 }
504 return values;
505 }
506 }
507
508
509 /**
510 * A container with information about a [Location].
511 */
512 class LocationData {
513 final int elementId;
514 final int length;
515 final int offset;
516
517 LocationData.forData(this.elementId, this.offset, this.length);
518
519 LocationData.forObject(ElementCodec elementCodec, Location location)
520 : elementId = elementCodec.encode(location.element),
521 offset = location.offset,
522 length = location.length;
523
524 @override
525 int get hashCode {
526 return 31 * (31 * elementId + offset) + length;
527 }
528
529 @override
530 bool operator ==(Object obj) {
531 if (obj is! LocationData) {
532 return false;
533 }
534 LocationData other = obj;
535 return other.elementId == elementId && other.offset == offset &&
536 other.length == length;
537 }
538
539 /**
540 * Returns a {@link Location} that is represented by this {@link LocationData} .
541 */
542 Location getLocation(AnalysisContext context, ElementCodec elementCodec) {
543 Element element = elementCodec.decode(context, elementId);
544 if (element == null) {
545 return null;
546 }
547 return new Location(element, offset, length);
548 }
549 }
550
551
552 /**
553 * A manager for [IndexNode]s.
554 */
555 abstract class NodeManager {
556 /**
557 * The shared {@link ContextCodec} instance.
558 */
559 ContextCodec get contextCodec;
560
561 /**
562 * The shared {@link ElementCodec} instance.
563 */
564 ElementCodec get elementCodec;
565
566 /**
567 * A number of locations in all nodes.
568 */
569 int get locationCount;
570
571 /**
572 * The shared {@link StringCodec} instance.
573 */
574 StringCodec get stringCodec;
575
576 /**
577 * Removes all nodes.
578 */
579 void clear();
580
581 /**
582 * Returns the {@link IndexNode} with the given name, {@code null} if not foun d.
583 */
584 Future<IndexNode> getNode(String name);
585
586 /**
587 * Returns a new {@link IndexNode}.
588 */
589 IndexNode newNode(AnalysisContext context);
590
591 /**
592 * Associates the given {@link IndexNode} with the given name.
593 */
594 void putNode(String name, IndexNode node);
595
596 /**
597 * Removes the {@link IndexNode} with the given name.
598 */
599 void removeNode(String name);
600 }
601
602
603 /**
604 * An [Element] to [Location] relation key.
605 */
606 class RelationKeyData {
607 final int elementId;
608 final int relationshipId;
609
610 RelationKeyData.forData(this.elementId, this.relationshipId);
611
612 RelationKeyData.forObject(ElementCodec elementCodec,
613 RelationshipCodec relationshipCodec, Element element, Relationship relatio nship)
614 : elementId = elementCodec.encode(element),
615 relationshipId = relationshipCodec.encode(relationship);
616
617 @override
618 int get hashCode {
619 return 31 * elementId + relationshipId;
620 }
621
622 @override
623 bool operator ==(Object obj) {
624 if (obj is! RelationKeyData) {
625 return false;
626 }
627 RelationKeyData other = obj;
628 return other.elementId == elementId && other.relationshipId ==
629 relationshipId;
630 }
631 }
632
633
634 /**
635 * A helper that encodes/decodes [Relationship]s to/from integers.
636 */
637 class RelationshipCodec {
638 final StringCodec _stringCodec;
639
640 RelationshipCodec(this._stringCodec);
641
642 Relationship decode(int idIndex) {
643 String id = _stringCodec.decode(idIndex);
644 return Relationship.getRelationship(id);
645 }
646
647 int encode(Relationship relationship) {
648 String id = relationship.identifier;
649 return _stringCodec.encode(id);
650 }
651 }
652
653
654 /**
655 * An [IndexStore] which keeps index information in separate nodes for each unit .
656 */
657 class SplitIndexStore implements IndexStore {
658 /**
659 * The [ContextCodec] to encode/decode [AnalysisContext]s.
660 */
661 ContextCodec _contextCodec;
662
663 /**
664 * Information about "universe" elements. We need to keep them together to avo id loading of all
665 * index nodes.
666 *
667 * Order of keys: contextId, nodeId, Relationship.
668 */
669 Map<int, Map<int, Map<Relationship, List<LocationData>>>>
670 _contextNodeRelations = new HashMap<int, Map<int, Map<Relationship,
671 List<LocationData>>>>();
672
673 /**
674 * The mapping of library [Source] to the [Source]s of part units.
675 */
676 Map<AnalysisContext, Map<Source, Set<Source>>> _contextToLibraryToUnits =
677 new HashMap<AnalysisContext, Map<Source, Set<Source>>>();
678
679 /**
680 * The mapping of unit [Source] to the [Source]s of libraries it is used in.
681 */
682 Map<AnalysisContext, Map<Source, Set<Source>>> _contextToUnitToLibraries =
683 new HashMap<AnalysisContext, Map<Source, Set<Source>>>();
684
685 int _currentContextId = 0;
686
687 IndexNode _currentNode;
688
689 String _currentNodeName;
690
691 int _currentNodeNameId = 0;
692
693 /**
694 * The [ElementCodec] to encode/decode [Element]s.
695 */
696 ElementCodec _elementCodec;
697
698 /**
699 * A table mapping element names to the node names that may have relations wit h elements with
700 * these names.
701 */
702 IntToIntSetMap _nameToNodeNames = new IntToIntSetMap(10000, 0.75);
703
704 /**
705 * The [NodeManager] to get/put [IndexNode]s.
706 */
707 final NodeManager _nodeManager;
708
709 /**
710 * The set of known [Source]s.
711 */
712 Set<Source> _sources = new HashSet<Source>();
713
714 /**
715 * The [StringCodec] to encode/decode [String]s.
716 */
717 StringCodec _stringCodec;
718
719 SplitIndexStore(this._nodeManager) {
720 this._contextCodec = _nodeManager.contextCodec;
721 this._elementCodec = _nodeManager.elementCodec;
722 this._stringCodec = _nodeManager.stringCodec;
723 }
724
725 @override
726 String get statistics =>
727 "[${_nodeManager.locationCount} locations, ${_sources.length} sources, ${_ nameToNodeNames.length} names]";
728
729 @override
730 bool aboutToIndexDart(AnalysisContext context,
731 CompilationUnitElement unitElement) {
732 context = _unwrapContext(context);
733 // may be already disposed in other thread
734 if (context.isDisposed) {
735 return false;
736 }
737 // validate unit
738 if (unitElement == null) {
739 return false;
740 }
741 LibraryElement libraryElement = unitElement.library;
742 if (libraryElement == null) {
743 return false;
744 }
745 CompilationUnitElement definingUnitElement =
746 libraryElement.definingCompilationUnit;
747 if (definingUnitElement == null) {
748 return false;
749 }
750 // prepare sources
751 Source library = definingUnitElement.source;
752 Source unit = unitElement.source;
753 // special handling for the defining library unit
754 if (unit == library) {
755 // prepare new parts
756 Set<Source> newParts = new Set();
757 for (CompilationUnitElement part in libraryElement.parts) {
758 newParts.add(part.source);
759 }
760 // prepare old parts
761 Map<Source, Set<Source>> libraryToUnits =
762 _contextToLibraryToUnits[context];
763 if (libraryToUnits == null) {
764 libraryToUnits = {};
765 _contextToLibraryToUnits[context] = libraryToUnits;
766 }
767 Set<Source> oldParts = libraryToUnits[library];
768 // check if some parts are not in the library now
769 if (oldParts != null) {
770 Set<Source> noParts = oldParts.difference(newParts);
771 for (Source noPart in noParts) {
772 _removeLocations(context, library, noPart);
773 }
774 }
775 // remember new parts
776 libraryToUnits[library] = newParts;
777 }
778 // remember library/unit relations
779 _recordUnitInLibrary(context, library, unit);
780 _recordLibraryWithUnit(context, library, unit);
781 _sources.add(library);
782 _sources.add(unit);
783 // prepare node
784 String libraryName = library.fullName;
785 String unitName = unit.fullName;
786 int libraryNameIndex = _stringCodec.encode(libraryName);
787 int unitNameIndex = _stringCodec.encode(unitName);
788 _currentNodeName = "${libraryNameIndex}_${unitNameIndex}.index";
789 _currentNodeNameId = _stringCodec.encode(_currentNodeName);
790 _currentNode = _nodeManager.newNode(context);
791 _currentContextId = _contextCodec.encode(context);
792 // remove Universe information for the current node
793 for (Map<int, dynamic> nodeRelations in _contextNodeRelations.values) {
794 nodeRelations.remove(_currentNodeNameId);
795 }
796 // done
797 return true;
798 }
799
800 @override
801 bool aboutToIndexHtml(AnalysisContext context, HtmlElement htmlElement) {
802 context = _unwrapContext(context);
803 // may be already disposed in other thread
804 if (context.isDisposed) {
805 return false;
806 }
807 // remove locations
808 Source source = htmlElement.source;
809 _removeLocations(context, null, source);
810 // remember library/unit relations
811 _recordUnitInLibrary(context, null, source);
812 // prepare node
813 String sourceName = source.fullName;
814 int sourceNameIndex = _stringCodec.encode(sourceName);
815 _currentNodeName = "${sourceNameIndex}.index";
816 _currentNodeNameId = _stringCodec.encode(_currentNodeName);
817 _currentNode = _nodeManager.newNode(context);
818 return true;
819 }
820
821 @override
822 void clear() {
823 _nodeManager.clear();
824 _nameToNodeNames.clear();
825 }
826
827 @override
828 void doneIndex() {
829 if (_currentNode != null) {
830 _nodeManager.putNode(_currentNodeName, _currentNode);
831 _currentNodeName = null;
832 _currentNodeNameId = -1;
833 _currentNode = null;
834 _currentContextId = -1;
835 }
836 }
837
838 @override
839 List<Location> getRelationships(Element element, Relationship relationship) {
840 // TODO(scheglov) make IndexStore interface async
841 return <Location>[];
842 }
843
844 Future<List<Location>> getRelationshipsAsync(Element element,
845 Relationship relationship) {
846 // special support for UniverseElement
847 if (identical(element, UniverseElement.INSTANCE)) {
848 List<Location> locations = _getRelationshipsUniverse(relationship);
849 return new Future.value(locations);
850 }
851 // prepare node names
852 String name = _getElementName(element);
853 int nameId = _stringCodec.encode(name);
854 List<int> nodeNameIds = _nameToNodeNames.get(nameId);
855 // prepare Future(s) for reading each IndexNode
856 List<Future<List<Location>>> nodeFutures = <Future<List<Location>>>[];
857 for (int nodeNameId in nodeNameIds) {
858 String nodeName = _stringCodec.decode(nodeNameId);
859 Future<IndexNode> nodeFuture = _nodeManager.getNode(nodeName);
860 Future<List<Location>> locationsFuture = nodeFuture.then((node) {
861 if (node == null) {
862 // TODO(scheglov) remove node
863 return Location.EMPTY_ARRAY;
864 }
865 return node.getRelationships(element, relationship);
866 });
867 nodeFutures.add(locationsFuture);
868 }
869 // return Future that merges separate IndexNode Location(s)
870 return Future.wait(nodeFutures).then((List<List<Location>> locationsList) {
871 List<Location> allLocations = <Location>[];
872 for (List<Location> locations in locationsList) {
873 allLocations.addAll(locations);
874 }
875 return allLocations;
876 });
877 }
878
879 @override
880 void recordRelationship(Element element, Relationship relationship,
881 Location location) {
882 if (element == null || location == null) {
883 return;
884 }
885 // special support for UniverseElement
886 if (identical(element, UniverseElement.INSTANCE)) {
887 _recordRelationshipUniverse(relationship, location);
888 return;
889 }
890 // other elements
891 _recordNodeNameForElement(element);
892 _currentNode.recordRelationship(element, relationship, location);
893 }
894
895 @override
896 void removeContext(AnalysisContext context) {
897 context = _unwrapContext(context);
898 if (context == null) {
899 return;
900 }
901 // remove sources
902 removeSources(context, null);
903 // remove context information
904 _contextToLibraryToUnits.remove(context);
905 _contextToUnitToLibraries.remove(context);
906 _contextNodeRelations.remove(_contextCodec.encode(context));
907 }
908
909 @override
910 void removeSource(AnalysisContext context, Source source) {
911 context = _unwrapContext(context);
912 if (context == null) {
913 return;
914 }
915 // remove nodes for unit/library pairs
916 Map<Source, Set<Source>> unitToLibraries =
917 _contextToUnitToLibraries[context];
918 if (unitToLibraries != null) {
919 Set<Source> libraries = unitToLibraries.remove(source);
920 if (libraries != null) {
921 for (Source library in libraries) {
922 _removeLocations(context, library, source);
923 }
924 }
925 }
926 // remove nodes for library/unit pairs
927 Map<Source, Set<Source>> libraryToUnits = _contextToLibraryToUnits[context];
928 if (libraryToUnits != null) {
929 Set<Source> units = libraryToUnits.remove(source);
930 if (units != null) {
931 for (Source unit in units) {
932 _removeLocations(context, source, unit);
933 }
934 }
935 }
936 }
937
938 @override
939 void removeSources(AnalysisContext context, SourceContainer container) {
940 context = _unwrapContext(context);
941 if (context == null) {
942 return;
943 }
944 // remove nodes for unit/library pairs
945 Map<Source, Set<Source>> unitToLibraries =
946 _contextToUnitToLibraries[context];
947 if (unitToLibraries != null) {
948 List<Source> units = new List<Source>.from(unitToLibraries.keys);
949 for (Source source in units) {
950 if (container == null || container.contains(source)) {
951 removeSource(context, source);
952 }
953 }
954 }
955 // remove nodes for library/unit pairs
956 Map<Source, Set<Source>> libraryToUnits = _contextToLibraryToUnits[context];
957 if (libraryToUnits != null) {
958 List<Source> libraries = new List<Source>.from(libraryToUnits.keys);
959 for (Source source in libraries) {
960 if (container == null || container.contains(source)) {
961 removeSource(context, source);
962 }
963 }
964 }
965 }
966
967 String _getElementName(Element element) => element.name;
968
969 List<Location> _getRelationshipsUniverse(Relationship relationship) {
970 List<Location> locations = [];
971 _contextNodeRelations.forEach((contextId, contextRelations) {
972 AnalysisContext context = _contextCodec.decode(contextId);
973 if (context != null) {
974 for (Map<Relationship, List<LocationData>> nodeRelations in
975 contextRelations.values) {
976 List<LocationData> nodeLocations = nodeRelations[relationship];
977 if (nodeLocations != null) {
978 for (LocationData locationData in nodeLocations) {
979 Location location = locationData.getLocation(context,
980 _elementCodec);
981 if (location != null) {
982 locations.add(location);
983 }
984 }
985 }
986 }
987 }
988 });
989 return locations;
990 }
991
992 void _recordLibraryWithUnit(AnalysisContext context, Source library,
993 Source unit) {
994 Map<Source, Set<Source>> libraryToUnits = _contextToLibraryToUnits[context];
995 if (libraryToUnits == null) {
996 libraryToUnits = {};
997 _contextToLibraryToUnits[context] = libraryToUnits;
998 }
999 Set<Source> units = libraryToUnits[library];
1000 if (units == null) {
1001 units = new Set();
1002 libraryToUnits[library] = units;
1003 }
1004 units.add(unit);
1005 }
1006
1007 void _recordNodeNameForElement(Element element) {
1008 String name = _getElementName(element);
1009 int nameId = _stringCodec.encode(name);
1010 _nameToNodeNames.add(nameId, _currentNodeNameId);
1011 }
1012
1013 void _recordRelationshipUniverse(Relationship relationship,
1014 Location location) {
1015 // in current context
1016 Map<int, Map<Relationship, List<LocationData>>> nodeRelations =
1017 _contextNodeRelations[_currentContextId];
1018 if (nodeRelations == null) {
1019 nodeRelations = {};
1020 _contextNodeRelations[_currentContextId] = nodeRelations;
1021 }
1022 // in current node
1023 Map<Relationship, List<LocationData>> relations =
1024 nodeRelations[_currentNodeNameId];
1025 if (relations == null) {
1026 relations = {};
1027 nodeRelations[_currentNodeNameId] = relations;
1028 }
1029 // for the given relationship
1030 List<LocationData> locations = relations[relationship];
1031 if (locations == null) {
1032 locations = [];
1033 relations[relationship] = locations;
1034 }
1035 // record LocationData
1036 locations.add(new LocationData.forObject(_elementCodec, location));
1037 }
1038
1039 void _recordUnitInLibrary(AnalysisContext context, Source library,
1040 Source unit) {
1041 Map<Source, Set<Source>> unitToLibraries =
1042 _contextToUnitToLibraries[context];
1043 if (unitToLibraries == null) {
1044 unitToLibraries = {};
1045 _contextToUnitToLibraries[context] = unitToLibraries;
1046 }
1047 Set<Source> libraries = unitToLibraries[unit];
1048 if (libraries == null) {
1049 libraries = new Set();
1050 unitToLibraries[unit] = libraries;
1051 }
1052 libraries.add(library);
1053 }
1054
1055 /**
1056 * Removes locations recorded in the given library/unit pair.
1057 */
1058 void _removeLocations(AnalysisContext context, Source library, Source unit) {
1059 // remove node
1060 String libraryName = library != null ? library.fullName : null;
1061 String unitName = unit.fullName;
1062 int libraryNameIndex = _stringCodec.encode(libraryName);
1063 int unitNameIndex = _stringCodec.encode(unitName);
1064 String nodeName = "${libraryNameIndex}_${unitNameIndex}.index";
1065 _nodeManager.removeNode(nodeName);
1066 // remove source
1067 _sources.remove(library);
1068 _sources.remove(unit);
1069 }
1070
1071 /**
1072 * When logging is on, [AnalysisEngine] actually creates
1073 * [InstrumentedAnalysisContextImpl], which wraps [AnalysisContextImpl] used t o create
1074 * actual [Element]s. So, in index we have to unwrap [InstrumentedAnalysisCont extImpl]
1075 * when perform any operation.
1076 */
1077 AnalysisContext _unwrapContext(AnalysisContext context) {
1078 if (context is InstrumentedAnalysisContextImpl) {
1079 context = (context as InstrumentedAnalysisContextImpl).basis;
1080 }
1081 return context;
1082 }
1083 }
1084
1085
1086 /**
1087 * A helper that encodes/decodes [String]s from/to integers.
1088 */
1089 class StringCodec {
1090 /**
1091 * A table mapping names to their unique indices.
1092 */
1093 final Map<String, int> nameToIndex = {};
1094
1095 /**
1096 * A table mapping indices to the corresponding strings.
1097 */
1098 List<String> _indexToName = [];
1099
1100 /**
1101 * Returns the [String] that corresponds to the given index.
1102 */
1103 String decode(int index) => _indexToName[index];
1104
1105 /**
1106 * Returns an unique index for the given [String].
1107 */
1108 int encode(String name) {
1109 int index = nameToIndex[name];
1110 if (index == null) {
1111 index = _indexToName.length;
1112 nameToIndex[name] = index;
1113 _indexToName.add(name);
1114 }
1115 return index;
1116 }
1117 }
1118
1119
1120 class _DataInputStream {
1121 ByteData _byteData;
1122 int _byteOffset = 0;
1123
1124 _DataInputStream(List<int> bytes) {
1125 ByteBuffer buffer = new Uint8List.fromList(bytes).buffer;
1126 _byteData = new ByteData.view(buffer);
1127 }
1128
1129 int readInt() {
1130 int result = _byteData.getInt32(_byteOffset);
1131 _byteOffset += 4;
1132 return result;
1133 }
1134 }
1135
1136
1137 class _DataOutputStream {
1138 BytesBuilder _buffer = new BytesBuilder();
1139
1140 Uint8List getBytes() {
1141 return new Uint8List.fromList(_buffer.takeBytes());
1142 }
1143
1144 void writeInt(int value) {
1145 _buffer.addByte((value & 0xFF000000) >> 24);
1146 _buffer.addByte((value & 0x00FF0000) >> 16);
1147 _buffer.addByte((value & 0x0000FF00) >> 8);
1148 _buffer.addByte(value & 0xFF);
1149 }
1150 }
OLDNEW
« no previous file with comments | « pkg/analysis_server/lib/src/generated/service_interfaces.dart ('k') | pkg/analysis_server/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698