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

Side by Side Diff: pkg/analyzer/lib/src/context/context.dart

Issue 1053673008: Initial re-write of analysis context for the new task model (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library analyzer.src.context.context;
6
7 import 'dart:async';
8 import 'dart:collection';
9
10 import 'package:analyzer/src/cancelable_future.dart';
11 import 'package:analyzer/src/context/cache.dart' as cache;
12 import 'package:analyzer/src/generated/ast.dart';
13 import 'package:analyzer/src/generated/constant.dart';
14 import 'package:analyzer/src/generated/element.dart';
15 import 'package:analyzer/src/generated/engine.dart';
16 import 'package:analyzer/src/generated/error.dart';
17 import 'package:analyzer/src/generated/html.dart' as ht;
18 import 'package:analyzer/src/generated/java_core.dart';
19 import 'package:analyzer/src/generated/java_engine.dart';
20 import 'package:analyzer/src/generated/resolver.dart';
21 import 'package:analyzer/src/generated/scanner.dart';
22 import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
23 import 'package:analyzer/src/generated/source.dart';
24 import 'package:analyzer/src/generated/utilities_collection.dart';
25 import 'package:analyzer/src/task/dart.dart';
26 import 'package:analyzer/src/task/driver.dart';
27 import 'package:analyzer/src/task/manager.dart';
28 import 'package:analyzer/task/dart.dart';
29 import 'package:analyzer/task/general.dart';
30 import 'package:analyzer/task/model.dart';
31
32 /**
33 * An [AnalysisContext] in which analysis can be performed.
34 */
35 class AnalysisContextImpl implements InternalAnalysisContext {
36 /**
37 * A client-provided name used to identify this context, or `null` if the
38 * client has not provided a name.
39 */
40 String name;
41
42 /**
43 * The set of analysis options controlling the behavior of this context.
44 */
45 AnalysisOptionsImpl _options = new AnalysisOptionsImpl();
46
47 /**
48 * A flag indicating whether this context is disposed.
49 */
50 bool _disposed = false;
51
52 /**
53 * A cache of content used to override the default content of a source.
54 */
55 ContentCache _contentCache = new ContentCache();
56
57 /**
58 * The source factory used to create the sources that can be analyzed in this
59 * context.
60 */
61 SourceFactory _sourceFactory;
62
63 /**
64 * The set of declared variables used when computing constant values.
65 */
66 DeclaredVariables _declaredVariables = new DeclaredVariables();
67
68 /**
69 * The partition that contains analysis results that are not shared with other
70 * contexts.
71 */
72 cache.CachePartition _privatePartition;
73
74 /**
75 * The cache in which information about the results associated with targets
76 * are stored.
77 */
78 cache.AnalysisCache _cache;
79
80 /**
81 * The task manager used to manage the tasks used to analyze code.
82 */
83 TaskManager _taskManager;
84
85 /**
86 * The analysis driver used to perform analysis.
87 */
88 AnalysisDriver _driver;
89
90 /**
91 * A list containing sources for which data should not be flushed.
92 */
93 List<Source> _priorityOrder = Source.EMPTY_ARRAY;
94
95 /**
96 * A map from all sources for which there are futures pending to a list of
97 * the corresponding PendingFuture objects. These sources will be analyzed
98 * in the same way as priority sources, except with higher priority.
99 */
100 HashMap<Source, List<PendingFuture>> _pendingFutureSources =
101 new HashMap<Source, List<PendingFuture>>();
102
103 /**
104 * A table mapping sources to the change notices that are waiting to be
105 * returned related to that source.
106 */
107 HashMap<Source, ChangeNoticeImpl> _pendingNotices =
108 new HashMap<Source, ChangeNoticeImpl>();
109
110 /**
111 * Cached information used in incremental analysis or `null` if none.
112 */
113 IncrementalAnalysisCache _incrementalAnalysisCache;
114
115 /**
116 * The [TypeProvider] for this context, `null` if not yet created.
117 */
118 TypeProvider _typeProvider;
119
120 /**
121 * The controller for sending [SourcesChangedEvent]s.
122 */
123 StreamController<SourcesChangedEvent> _onSourcesChangedController;
124
125 /**
126 * The listeners that are to be notified when various analysis results are
127 * produced in this context.
128 */
129 List<AnalysisListener> _listeners = new List<AnalysisListener>();
130
131 /**
132 * The most recently incrementally resolved source, or `null` when it was
133 * already validated, or the most recent change was not incrementally resolved .
134 */
135 Source incrementalResolutionValidation_lastUnitSource;
136
137 /**
138 * The most recently incrementally resolved library source, or `null` when it
139 * was already validated, or the most recent change was not incrementally
140 * resolved.
141 */
142 Source incrementalResolutionValidation_lastLibrarySource;
143
144 /**
145 * The result of incremental resolution result of
146 * [incrementalResolutionValidation_lastSource].
147 */
148 CompilationUnit incrementalResolutionValidation_lastUnit;
149
150 /**
151 * A factory to override how the [ResolverVisitor] is created.
152 */
153 ResolverVisitorFactory resolverVisitorFactory;
154
155 /**
156 * A factory to override how the [TypeResolverVisitor] is created.
157 */
158 TypeResolverVisitorFactory typeResolverVisitorFactory;
159
160 /**
161 * A factory to override how [LibraryResolver] is created.
162 */
163 LibraryResolverFactory libraryResolverFactory;
164
165 /**
166 * Initialize a newly created analysis context.
167 */
168 AnalysisContextImpl() {
169 _privatePartition = new cache.UniversalCachePartition(this,
170 AnalysisOptionsImpl.DEFAULT_CACHE_SIZE,
171 new ContextRetentionPolicy(this));
172 _cache = createCacheFromSourceFactory(null);
173 _taskManager = AnalysisEngine.instance.taskManager;
174 _driver = new AnalysisDriver(_taskManager, this);
175 _onSourcesChangedController =
176 new StreamController<SourcesChangedEvent>.broadcast();
177 }
178
179 @override
180 AnalysisOptions get analysisOptions => _options;
181
182 @override
183 void set analysisOptions(AnalysisOptions options) {
184 bool needsRecompute = this._options.analyzeFunctionBodiesPredicate !=
185 options.analyzeFunctionBodiesPredicate ||
186 this._options.generateImplicitErrors !=
187 options.generateImplicitErrors ||
188 this._options.generateSdkErrors != options.generateSdkErrors ||
189 this._options.dart2jsHint != options.dart2jsHint ||
190 (this._options.hint && !options.hint) ||
191 this._options.preserveComments != options.preserveComments ||
192 this._options.enableNullAwareOperators !=
193 options.enableNullAwareOperators ||
194 this._options.enableStrictCallChecks != options.enableStrictCallChecks;
195 int cacheSize = options.cacheSize;
196 if (this._options.cacheSize != cacheSize) {
197 this._options.cacheSize = cacheSize;
198 _privatePartition.maxCacheSize = cacheSize;
199 }
200 this._options.analyzeFunctionBodiesPredicate =
201 options.analyzeFunctionBodiesPredicate;
202 this._options.generateImplicitErrors = options.generateImplicitErrors;
203 this._options.generateSdkErrors = options.generateSdkErrors;
204 this._options.dart2jsHint = options.dart2jsHint;
205 this._options.enableNullAwareOperators = options.enableNullAwareOperators;
206 this._options.enableStrictCallChecks = options.enableStrictCallChecks;
207 this._options.hint = options.hint;
208 this._options.incremental = options.incremental;
209 this._options.incrementalApi = options.incrementalApi;
210 this._options.incrementalValidation = options.incrementalValidation;
211 this._options.lint = options.lint;
212 this._options.preserveComments = options.preserveComments;
213 if (needsRecompute) {
214 _invalidateAllLocalResolutionInformation(false);
215 }
216 }
217
218 @override
219 void set analysisPriorityOrder(List<Source> sources) {
220 if (sources == null || sources.isEmpty) {
221 _priorityOrder = Source.EMPTY_ARRAY;
222 } else {
223 while (sources.remove(null)) {
224 // Nothing else to do.
225 }
226 if (sources.isEmpty) {
227 _priorityOrder = Source.EMPTY_ARRAY;
228 } else {
229 _priorityOrder = sources;
230 }
231 }
232 }
233
234 @override
235 set contentCache(ContentCache value) {
236 _contentCache = value;
237 }
238
239 @override
240 DeclaredVariables get declaredVariables => _declaredVariables;
241
242 @override
243 List<AnalysisTarget> get explicitTargets {
244 List<AnalysisTarget> targets = <AnalysisTarget>[];
245 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator();
246 while (iterator.moveNext()) {
247 if (iterator.value.explicitlyAdded) {
248 targets.add(iterator.key);
249 }
250 }
251 return targets;
252 }
253
254 @override
255 List<Source> get htmlSources => _getSources(SourceKind.HTML);
256
257 @override
258 bool get isDisposed => _disposed;
259
260 @override
261 List<Source> get launchableClientLibrarySources {
262 // TODO(brianwilkerson) This needs to filter out libraries that do not
263 // reference dart:html, either directly or indirectly.
264 List<Source> sources = new List<Source>();
265 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator();
266 while (iterator.moveNext()) {
267 AnalysisTarget target = iterator.key;
268 cache.CacheEntry entry = iterator.value;
269 if (target is Source &&
270 entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY &&
271 !target.isInSystemLibrary) {
272 // DartEntry dartEntry = (DartEntry) sourceEntry;
273 // if (dartEntry.getValue(DartEntry.IS_LAUNCHABLE) && !dartEntry.getVal ue(DartEntry.IS_CLIENT)) {
274 sources.add(target);
275 // }
276 }
277 }
278 return sources;
279 }
280
281 @override
282 List<Source> get launchableServerLibrarySources {
283 // TODO(brianwilkerson) This needs to filter out libraries that reference
284 // dart:html, either directly or indirectly.
285 List<Source> sources = new List<Source>();
286 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator();
287 while (iterator.moveNext()) {
288 AnalysisTarget target = iterator.key;
289 cache.CacheEntry entry = iterator.value;
290 if (target is Source &&
291 entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY &&
292 !target.isInSystemLibrary) {
293 // DartEntry dartEntry = (DartEntry) sourceEntry;
294 // if (dartEntry.getValue(DartEntry.IS_LAUNCHABLE) && !dartEntry.getVal ue(DartEntry.IS_CLIENT)) {
295 sources.add(target);
296 // }
297 }
298 }
299 return sources;
300 }
301
302 @override
303 List<Source> get librarySources => _getSources(SourceKind.LIBRARY);
304
305 @override
306 Stream<SourcesChangedEvent> get onSourcesChanged =>
307 _onSourcesChangedController.stream;
308
309 /**
310 * Make _pendingFutureSources available to unit tests.
311 */
312 HashMap<Source, List<PendingFuture>> get pendingFutureSources_forTesting =>
313 _pendingFutureSources;
314
315 @override
316 List<Source> get prioritySources => _priorityOrder;
317
318 @override
319 List<AnalysisTarget> get priorityTargets => prioritySources;
320
321 @override
322 List<Source> get refactoringUnsafeSources {
323 // TODO(brianwilkerson) Implement this.
324 List<Source> sources = new List<Source>();
325 // MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator() ;
326 // while (iterator.moveNext()) {
327 // cache.CacheEntry entry = iterator.value;
328 // AnalysisTarget target = iterator.key;
329 // if (target is Source &&
330 // !target.isInSystemLibrary &&
331 // !entry.isRefactoringSafe) {
332 // sources.add(target);
333 // }
334 // }
335 return sources;
336 }
337
338 @override
339 SourceFactory get sourceFactory => _sourceFactory;
340
341 @override
342 void set sourceFactory(SourceFactory factory) {
343 if (identical(_sourceFactory, factory)) {
344 return;
345 } else if (factory.context != null) {
346 throw new IllegalStateException(
347 "Source factories cannot be shared between contexts");
348 }
349 if (_sourceFactory != null) {
350 _sourceFactory.context = null;
351 }
352 factory.context = this;
353 _sourceFactory = factory;
354 _cache = createCacheFromSourceFactory(factory);
355 _invalidateAllLocalResolutionInformation(true);
356 }
357
358 @override
359 List<Source> get sources {
360 List<Source> sources = new List<Source>();
361 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator();
362 while (iterator.moveNext()) {
363 AnalysisTarget target = iterator.key;
364 if (target is Source) {
365 sources.add(target);
366 }
367 }
368 return sources;
369 }
370
371 /**
372 * Return a list of the sources that would be processed by
373 * [performAnalysisTask]. This method duplicates, and must therefore be kept
374 * in sync with, [getNextAnalysisTask]. This method is intended to be used for
375 * testing purposes only.
376 */
377 List<Source> get sourcesNeedingProcessing {
378 HashSet<Source> sources = new HashSet<Source>();
379 bool hintsEnabled = _options.hint;
380 bool lintsEnabled = _options.lint;
381
382 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator();
383 while (iterator.moveNext()) {
384 AnalysisTarget target = iterator.key;
385 if (target is Source) {
386 _getSourcesNeedingProcessing(
387 target, iterator.value, false, hintsEnabled, lintsEnabled, sources);
388 }
389 }
390 return new List<Source>.from(sources);
391 }
392
393 @override
394 AnalysisContextStatistics get statistics {
395 AnalysisContextStatisticsImpl statistics =
396 new AnalysisContextStatisticsImpl();
397 // TODO(brianwilkerson) Implement this.
398 // visitCacheItems(statistics._internalPutCacheItem);
399 // statistics.partitionData = _cache.partitionData;
400 return statistics;
401 }
402
403 IncrementalAnalysisCache get test_incrementalAnalysisCache {
404 return _incrementalAnalysisCache;
405 }
406
407 set test_incrementalAnalysisCache(IncrementalAnalysisCache value) {
408 _incrementalAnalysisCache = value;
409 }
410
411 List<Source> get test_priorityOrder => _priorityOrder;
412
413 @override
414 TypeProvider get typeProvider {
415 if (_typeProvider != null) {
416 return _typeProvider;
417 }
418 Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE);
419 if (coreSource == null) {
420 throw new AnalysisException("Could not create a source for dart:core");
421 }
422 LibraryElement coreElement = computeLibraryElement(coreSource);
423 if (coreElement == null) {
424 throw new AnalysisException("Could not create an element for dart:core");
425 }
426 Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
427 if (asyncSource == null) {
428 throw new AnalysisException("Could not create a source for dart:async");
429 }
430 LibraryElement asyncElement = computeLibraryElement(asyncSource);
431 if (asyncElement == null) {
432 throw new AnalysisException("Could not create an element for dart:async");
433 }
434 _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
435 return _typeProvider;
436 }
437
438 /**
439 * Sets the [TypeProvider] for this context.
440 */
441 void set typeProvider(TypeProvider typeProvider) {
442 _typeProvider = typeProvider;
443 }
444
445 /**
446 * Return `true` if the (new) task model should be used to perform analysis.
447 */
448 bool get useTaskModel => AnalysisEngine.instance.useTaskModel;
449
450 @override
451 void addListener(AnalysisListener listener) {
452 if (!_listeners.contains(listener)) {
453 _listeners.add(listener);
454 }
455 }
456
457 @override
458 void addSourceInfo(Source source, SourceEntry info) {
459 // TODO(brianwilkerson) This method needs to be replaced by something that
460 // will copy CacheEntry's.
461 // _cache.put(source, info);
462 }
463
464 @override
465 void applyAnalysisDelta(AnalysisDelta delta) {
466 ChangeSet changeSet = new ChangeSet();
467 delta.analysisLevels.forEach((Source source, AnalysisLevel level) {
468 if (level == AnalysisLevel.NONE) {
469 changeSet.removedSource(source);
470 } else {
471 changeSet.addedSource(source);
472 }
473 });
474 applyChanges(changeSet);
475 }
476
477 @override
478 void applyChanges(ChangeSet changeSet) {
479 if (changeSet.isEmpty) {
480 return;
481 }
482 //
483 // First, compute the list of sources that have been removed.
484 //
485 List<Source> removedSources =
486 new List<Source>.from(changeSet.removedSources);
487 for (SourceContainer container in changeSet.removedContainers) {
488 _addSourcesInContainer(removedSources, container);
489 }
490 //
491 // Then determine which cached results are no longer valid.
492 //
493 for (Source source in changeSet.addedSources) {
494 _sourceAvailable(source);
495 }
496 for (Source source in changeSet.changedSources) {
497 if (_contentCache.getContents(source) != null) {
498 // This source is overridden in the content cache, so the change will
499 // have no effect. Just ignore it to avoid wasting time doing
500 // re-analysis.
501 continue;
502 }
503 _sourceChanged(source);
504 }
505 changeSet.changedContents.forEach((Source key, String value) {
506 _contentsChanged(key, value, false);
507 });
508 changeSet.changedRanges
509 .forEach((Source source, ChangeSet_ContentChange change) {
510 _contentRangeChanged(source, change.contents, change.offset,
511 change.oldLength, change.newLength);
512 });
513 for (Source source in changeSet.deletedSources) {
514 _sourceDeleted(source);
515 }
516 for (Source source in removedSources) {
517 _sourceRemoved(source);
518 }
519 _onSourcesChangedController.add(new SourcesChangedEvent(changeSet));
520 }
521
522 @override
523 String computeDocumentationComment(Element element) {
524 if (element == null) {
525 return null;
526 }
527 Source source = element.source;
528 if (source == null) {
529 return null;
530 }
531 CompilationUnit unit = parseCompilationUnit(source);
532 if (unit == null) {
533 return null;
534 }
535 NodeLocator locator = new NodeLocator.con1(element.nameOffset);
536 AstNode nameNode = locator.searchWithin(unit);
537 while (nameNode != null) {
538 if (nameNode is AnnotatedNode) {
539 Comment comment = nameNode.documentationComment;
540 if (comment == null) {
541 return null;
542 }
543 StringBuffer buffer = new StringBuffer();
544 List<Token> tokens = comment.tokens;
545 for (int i = 0; i < tokens.length; i++) {
546 if (i > 0) {
547 buffer.write("\n");
548 }
549 buffer.write(tokens[i].lexeme);
550 }
551 return buffer.toString();
552 }
553 nameNode = nameNode.parent;
554 }
555 return null;
556 }
557
558 @override
559 List<AnalysisError> computeErrors(Source source) =>
560 _computeResult(source, DART_ERRORS);
561
562 @override
563 List<Source> computeExportedLibraries(Source source) =>
564 _computeResult(source, EXPORTED_LIBRARIES);
565
566 @override
567 // TODO(brianwilkerson) Implement this.
568 HtmlElement computeHtmlElement(Source source) => null;
569
570 @override
571 List<Source> computeImportedLibraries(Source source) => _computeResult(
572 source, IMPORTED_LIBRARIES);
573
574 @override
575 SourceKind computeKindOf(Source source) =>
576 _computeResult(source, SOURCE_KIND);
577
578 @override
579 LibraryElement computeLibraryElement(Source source) =>
580 _computeResult(source, LIBRARY_ELEMENT); //_computeResult(source, HtmlEntr y.ELEMENT);
581
582 @override
583 LineInfo computeLineInfo(Source source) => _computeResult(source, LINE_INFO);
584
585 @override
586 @deprecated
587 CompilationUnit computeResolvableCompilationUnit(Source source) {
588 return null;
589 }
590
591 @override
592 CancelableFuture<CompilationUnit> computeResolvedCompilationUnitAsync(
593 Source unitSource, Source librarySource) {
594 // TODO(brianwilkerson) Implement this.
595 return new CancelableFuture<CompilationUnit>(() => null);
596 // return new _AnalysisFutureHelper<CompilationUnit>(this).computeAsync(
597 // unitSource, (SourceEntry sourceEntry) {
598 // if (sourceEntry is DartEntry) {
599 // if (sourceEntry.getStateInLibrary(
600 // DartEntry.RESOLVED_UNIT, librarySource) ==
601 // CacheState.ERROR) {
602 // throw sourceEntry.exception;
603 // }
604 // return sourceEntry.getValueInLibrary(
605 // DartEntry.RESOLVED_UNIT, librarySource);
606 // }
607 // throw new AnalysisNotScheduledError();
608 // });
609 }
610
611 /**
612 * Create an analysis cache based on the given source [factory].
613 */
614 cache.AnalysisCache createCacheFromSourceFactory(SourceFactory factory) {
615 if (factory == null) {
616 return new cache.AnalysisCache(<cache.CachePartition>[_privatePartition]);
617 }
618 DartSdk sdk = factory.dartSdk;
619 if (sdk == null) {
620 return new cache.AnalysisCache(<cache.CachePartition>[_privatePartition]);
621 }
622 return new cache.AnalysisCache(<cache.CachePartition>[
623 AnalysisEngine.instance.partitionManager_new.forSdk(sdk),
624 _privatePartition
625 ]);
626 }
627
628 @override
629 void dispose() {
630 _disposed = true;
631 for (List<PendingFuture> pendingFutures in _pendingFutureSources.values) {
632 for (PendingFuture pendingFuture in pendingFutures) {
633 pendingFuture.forciblyComplete();
634 }
635 }
636 _pendingFutureSources.clear();
637 }
638
639 @override
640 List<CompilationUnit> ensureResolvedDartUnits(Source unitSource) {
641 // TODO(brianwilkerson) Implement this.
642 return null;
643 // cache.CacheEntry entry = _cache.get(unitSource);
644 // // Check every library.
645 // List<CompilationUnit> units = <CompilationUnit>[];
646 // List<Source> containingLibraries = entry.containingLibraries;
647 // for (Source librarySource in containingLibraries) {
648 // CompilationUnit unit =
649 // entry.getValueInLibrary(DartEntry.RESOLVED_UNIT, librarySource);
650 // if (unit == null) {
651 // units = null;
652 // break;
653 // }
654 // units.add(unit);
655 // }
656 // // Invalidate the flushed RESOLVED_UNIT to force it eventually.
657 // if (units == null) {
658 // bool shouldBeScheduled = false;
659 // for (Source librarySource in containingLibraries) {
660 // if (entry.getStateInLibrary(DartEntry.RESOLVED_UNIT, librarySource) ==
661 // CacheState.FLUSHED) {
662 // entry.setStateInLibrary(
663 // DartEntry.RESOLVED_UNIT, librarySource, CacheState.INVALID);
664 // shouldBeScheduled = true;
665 // }
666 // }
667 // if (shouldBeScheduled) {
668 // _workManager.add(unitSource, SourcePriority.UNKNOWN);
669 // }
670 // // We cannot provide resolved units right now,
671 // // but the future analysis will.
672 // return null;
673 // }
674 // // done
675 // return units;
676 }
677
678 @override
679 bool exists(Source source) {
680 if (source == null) {
681 return false;
682 }
683 if (_contentCache.getContents(source) != null) {
684 return true;
685 }
686 return source.exists();
687 }
688
689 Element findElementById(int id) {
690 // TODO(brianwilkerson) Implement this.
691 return null;
692 // _ElementByIdFinder finder = new _ElementByIdFinder(id);
693 // try {
694 // MapIterator<AnalysisTarget, cache.CacheEntry> iterator =
695 // _cache.iterator();
696 // while (iterator.moveNext()) {
697 // cache.CacheEntry entry = iterator.value;
698 // if (entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY) {
699 // DartEntry dartEntry = entry;
700 // LibraryElement library = dartEntry.getValue(DartEntry.ELEMENT);
701 // if (library != null) {
702 // library.accept(finder);
703 // }
704 // }
705 // }
706 // } on _ElementByIdFinderException {
707 // return finder.result;
708 // }
709 // return null;
710 }
711
712 @override
713 cache.CacheEntry getCacheEntry(AnalysisTarget target) {
714 cache.CacheEntry entry = _cache.get(target);
715 if (entry == null) {
716 entry = new cache.CacheEntry();
717 _cache.put(target, entry);
718 }
719 return entry;
720 }
721
722 @override
723 CompilationUnitElement getCompilationUnitElement(
724 Source unitSource, Source librarySource) {
725 AnalysisTarget target = new LibrarySpecificUnit(librarySource, unitSource);
726 return _getResult(target, COMPILATION_UNIT_ELEMENT);
727 }
728
729 @override
730 TimestampedData<String> getContents(Source source) {
731 String contents = _contentCache.getContents(source);
732 if (contents != null) {
733 return new TimestampedData<String>(
734 _contentCache.getModificationStamp(source), contents);
735 }
736 return source.contents;
737 }
738
739 @override
740 InternalAnalysisContext getContextFor(Source source) {
741 InternalAnalysisContext context = _cache.getContextFor(source);
742 return context == null ? this : context;
743 }
744
745 @override
746 Element getElement(ElementLocation location) {
747 // TODO(brianwilkerson) This should not be a "get" method.
748 try {
749 List<String> components = location.components;
750 Source source = _computeSourceFromEncoding(components[0]);
751 String sourceName = source.shortName;
752 if (AnalysisEngine.isDartFileName(sourceName)) {
753 ElementImpl element = computeLibraryElement(source) as ElementImpl;
754 for (int i = 1; i < components.length; i++) {
755 if (element == null) {
756 return null;
757 }
758 element = element.getChild(components[i]);
759 }
760 return element;
761 }
762 if (AnalysisEngine.isHtmlFileName(sourceName)) {
763 return computeHtmlElement(source);
764 }
765 } catch (exception) {
766 // If the location cannot be decoded for some reason then the underlying
767 // cause should have been logged already and we can fall though to return
768 // null.
769 }
770 return null;
771 }
772
773 @override
774 AnalysisErrorInfo getErrors(Source source) => _getResult(source, DART_ERRORS);
775
776 @override
777 HtmlElement getHtmlElement(Source source) {
778 // TODO(brianwilkerson) Implement this.
779 // SourceEntry sourceEntry = getReadableSourceEntryOrNull(source);
780 // if (sourceEntry is HtmlEntry) {
781 // return sourceEntry.getValue(HtmlEntry.ELEMENT);
782 // }
783 return null;
784 }
785
786 @override
787 List<Source> getHtmlFilesReferencing(Source source) {
788 SourceKind sourceKind = getKindOf(source);
789 if (sourceKind == null) {
790 return Source.EMPTY_ARRAY;
791 }
792 List<Source> htmlSources = new List<Source>();
793 while (true) {
794 if (sourceKind == SourceKind.PART) {
795 List<Source> librarySources = getLibrariesContaining(source);
796 MapIterator<AnalysisTarget, cache.CacheEntry> iterator =
797 _cache.iterator();
798 while (iterator.moveNext()) {
799 cache.CacheEntry entry = iterator.value;
800 if (entry.getValue(SOURCE_KIND) == SourceKind.HTML) {
801 List<Source> referencedLibraries =
802 (entry as HtmlEntry).getValue(HtmlEntry.REFERENCED_LIBRARIES);
803 if (_containsAny(referencedLibraries, librarySources)) {
804 htmlSources.add(iterator.key);
805 }
806 }
807 }
808 } else {
809 MapIterator<AnalysisTarget, cache.CacheEntry> iterator =
810 _cache.iterator();
811 while (iterator.moveNext()) {
812 cache.CacheEntry entry = iterator.value;
813 if (entry.getValue(SOURCE_KIND) == SourceKind.HTML) {
814 List<Source> referencedLibraries =
815 (entry as HtmlEntry).getValue(HtmlEntry.REFERENCED_LIBRARIES);
816 if (_contains(referencedLibraries, source)) {
817 htmlSources.add(iterator.key);
818 }
819 }
820 }
821 }
822 break;
823 }
824 if (htmlSources.isEmpty) {
825 return Source.EMPTY_ARRAY;
826 }
827 return htmlSources;
828 }
829
830 @override
831 SourceKind getKindOf(Source source) => _getResult(source, SOURCE_KIND);
832
833 @override
834 List<Source> getLibrariesContaining(Source source) {
835 // TODO(brianwilkerson) Implement this.
836 // cache.CacheEntry sourceEntry = _cache.get(source);
837 // if (sourceEntry is DartEntry) {
838 // return sourceEntry.containingLibraries;
839 // }
840 return Source.EMPTY_ARRAY;
841 }
842
843 @override
844 List<Source> getLibrariesDependingOn(Source librarySource) {
845 List<Source> dependentLibraries = new List<Source>();
846 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator();
847 while (iterator.moveNext()) {
848 cache.CacheEntry entry = iterator.value;
849 if (entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY) {
850 if (_contains(entry.getValue(EXPORTED_LIBRARIES), librarySource)) {
851 dependentLibraries.add(iterator.key);
852 }
853 if (_contains(entry.getValue(IMPORTED_LIBRARIES), librarySource)) {
854 dependentLibraries.add(iterator.key);
855 }
856 }
857 }
858 if (dependentLibraries.isEmpty) {
859 return Source.EMPTY_ARRAY;
860 }
861 return dependentLibraries;
862 }
863
864 @override
865 List<Source> getLibrariesReferencedFromHtml(Source htmlSource) {
866 // TODO(brianwilkerson) Implement this.
867 // cache.CacheEntry entry = getReadableSourceEntryOrNull(htmlSource);
868 // if (entry is HtmlEntry) {
869 // HtmlEntry htmlEntry = entry;
870 // return htmlEntry.getValue(HtmlEntry.REFERENCED_LIBRARIES);
871 // }
872 return Source.EMPTY_ARRAY;
873 }
874
875 @override
876 LibraryElement getLibraryElement(Source source) =>
877 _getResult(source, LIBRARY_ELEMENT);
878
879 @override
880 LineInfo getLineInfo(Source source) => _getResult(source, LINE_INFO);
881
882 @override
883 int getModificationStamp(Source source) {
884 int stamp = _contentCache.getModificationStamp(source);
885 if (stamp != null) {
886 return stamp;
887 }
888 return source.modificationStamp;
889 }
890
891 @override
892 Namespace getPublicNamespace(LibraryElement library) {
893 // TODO(brianwilkerson) Rename this to not start with 'get'.
894 // Note that this is not part of the API of the interface.
895 // TODO(brianwilkerson) The public namespace used to be cached, but no is.
scheglov 2015/04/20 03:44:50 The only client of this method is NamespaceBuilder
Brian Wilkerson 2015/04/20 15:00:36 Clean-up (by someone) in a later CL.
896 NamespaceBuilder builder = new NamespaceBuilder();
897 return builder.createPublicNamespaceForLibrary(library);
898 }
899
900 /**
901 * Return the cache entry associated with the given [source], or `null` if
902 * there is no entry associated with the source.
903 */
904 cache.CacheEntry getReadableSourceEntryOrNull(Source source) =>
905 _cache.get(source);
906
907 @override
908 CompilationUnit getResolvedCompilationUnit(
909 Source unitSource, LibraryElement library) {
910 if (library == null) {
911 return null;
912 }
913 return getResolvedCompilationUnit2(unitSource, library.source);
914 }
915
916 @override
917 CompilationUnit getResolvedCompilationUnit2(
918 Source unitSource, Source librarySource) => _getResult(
919 new LibrarySpecificUnit(librarySource, unitSource), RESOLVED_UNIT);
920
921 @override
922 ht.HtmlUnit getResolvedHtmlUnit(Source htmlSource) {
923 // TODO(brianwilkerson) Implement this.
924 // SourceEntry sourceEntry = getReadableSourceEntryOrNull(htmlSource);
925 // if (sourceEntry is HtmlEntry) {
926 // HtmlEntry htmlEntry = sourceEntry;
927 // return htmlEntry.getValue(HtmlEntry.RESOLVED_UNIT);
928 // }
929 return null;
930 }
931
932 @override
933 List<Source> getSourcesWithFullName(String path) {
934 List<Source> sources = <Source>[];
935 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator();
936 while (iterator.moveNext()) {
937 AnalysisTarget target = iterator.key;
938 if (target is Source && target.fullName == path) {
939 sources.add(target);
940 }
941 }
942 return sources;
943 }
944
945 @override
946 bool handleContentsChanged(
947 Source source, String originalContents, String newContents, bool notify) {
948 cache.CacheEntry entry = _cache.get(source);
949 if (entry == null) {
950 return false;
951 }
952 bool changed = newContents != originalContents;
953 if (newContents != null) {
954 if (newContents != originalContents) {
955 _incrementalAnalysisCache =
956 IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
957 if (!analysisOptions.incremental ||
958 !_tryPoorMansIncrementalResolution(source, newContents)) {
959 _sourceChanged(source);
960 }
961 entry.modificationTime = _contentCache.getModificationStamp(source);
962 entry.setValue(CONTENT, newContents);
963 } else {
964 entry.modificationTime = _contentCache.getModificationStamp(source);
965 }
966 } else if (originalContents != null) {
967 _incrementalAnalysisCache =
968 IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
969 changed = newContents != originalContents;
970 // We are removing the overlay for the file, check if the file's
971 // contents is the same as it was in the overlay.
972 try {
973 TimestampedData<String> fileContents = getContents(source);
974 String fileContentsData = fileContents.data;
975 if (fileContentsData == originalContents) {
976 entry.setValue(CONTENT, fileContentsData);
977 entry.modificationTime = fileContents.modificationTime;
978 changed = false;
979 }
980 } catch (e) {}
981 // If not the same content (e.g. the file is being closed without save),
982 // then force analysis.
983 if (changed) {
984 _sourceChanged(source);
985 }
986 }
987 if (notify && changed) {
988 _onSourcesChangedController
989 .add(new SourcesChangedEvent.changedContent(source, newContents));
990 }
991 return changed;
992 }
993
994 /**
995 * Invalidates hints in the given [librarySource] and included parts.
996 */
997 void invalidateLibraryHints(Source librarySource) {
998 cache.CacheEntry entry = _cache.get(librarySource);
999 // Prepare sources to invalidate hints in.
1000 List<Source> sources = <Source>[librarySource];
1001 sources.addAll(entry.getValue(INCLUDED_PARTS));
1002 // Invalidate hints.
1003 for (Source source in sources) {
1004 LibrarySpecificUnit unitTarget =
1005 new LibrarySpecificUnit(librarySource, source);
1006 cache.CacheEntry unitEntry = _cache.get(unitTarget);
1007 if (unitEntry.getState(HINTS) == CacheState.VALID) {
1008 unitEntry.setState(HINTS, CacheState.INVALID);
1009 }
1010 }
1011 }
1012
1013 @override
1014 bool isClientLibrary(Source librarySource) {
1015 cache.CacheEntry entry = _cache.get(librarySource);
1016 return entry.getValue(IS_CLIENT) && entry.getValue(IS_LAUNCHABLE);
1017 }
1018
1019 @override
1020 bool isServerLibrary(Source librarySource) {
1021 cache.CacheEntry entry = _cache.get(librarySource);
1022 return !entry.getValue(IS_CLIENT) && entry.getValue(IS_LAUNCHABLE);
1023 }
1024
1025 @override
1026 CompilationUnit parseCompilationUnit(Source source) {
1027 if (!AnalysisEngine.isDartFileName(source.shortName)) {
1028 return null;
1029 }
1030 return _computeResult(source, PARSED_UNIT);
1031 }
1032
1033 @override
1034 ht.HtmlUnit parseHtmlUnit(Source source) {
1035 if (!AnalysisEngine.isHtmlFileName(source.shortName)) {
1036 return null;
1037 }
1038 // TODO(brianwilkerson) Implement HTML analysis.
1039 return null; //_computeResult(source, null);
1040 }
1041
1042 @override
1043 AnalysisResult performAnalysisTask() {
1044 return PerformanceStatistics.performAnaysis.makeCurrentWhile(() {
1045 bool done = !_driver.performAnalysisTask();
1046 if (done) {
1047 done = !_validateCacheConsistency();
1048 }
1049 List<ChangeNotice> notices = _getChangeNotices(done);
1050 if (notices != null) {
1051 int noticeCount = notices.length;
1052 for (int i = 0; i < noticeCount; i++) {
1053 ChangeNotice notice = notices[i];
1054 _notifyErrors(notice.source, notice.errors, notice.lineInfo);
1055 }
1056 }
1057 return new AnalysisResult(notices, -1, '', -1);
1058 });
1059 }
1060
1061 @override
1062 void recordLibraryElements(Map<Source, LibraryElement> elementMap) {
1063 elementMap.forEach((Source librarySource, LibraryElement library) {
1064 //
1065 // Cache the element in the library's info.
1066 //
1067 cache.CacheEntry entry = getCacheEntry(librarySource);
1068 entry.setValue(BUILD_DIRECTIVES_ERRORS, AnalysisError.NO_ERRORS);
1069 entry.setValue(
1070 BUILD_FUNCTION_TYPE_ALIASES_ERRORS, AnalysisError.NO_ERRORS);
1071 entry.setValue(BUILD_LIBRARY_ERRORS, AnalysisError.NO_ERRORS);
1072 // CLASS_ELEMENTS
1073 entry.setValue(COMPILATION_UNIT_ELEMENT, library.definingCompilationUnit);
1074 // CONSTRUCTORS
1075 // CONSTRUCTORS_ERRORS
1076 entry.setState(CONTENT, CacheState.FLUSHED);
1077 entry.setValue(EXPORTED_LIBRARIES, Source.EMPTY_ARRAY);
1078 // EXPORT_SOURCE_CLOSURE
1079 entry.setValue(IMPORTED_LIBRARIES, Source.EMPTY_ARRAY);
1080 // IMPORT_SOURCE_CLOSURE
1081 entry.setValue(INCLUDED_PARTS, Source.EMPTY_ARRAY);
1082 entry.setValue(IS_CLIENT, true);
1083 entry.setValue(IS_LAUNCHABLE, false);
1084 entry.setValue(LIBRARY_ELEMENT, library);
1085 entry.setValue(LIBRARY_ELEMENT1, library);
1086 entry.setValue(LIBRARY_ELEMENT2, library);
1087 entry.setValue(LIBRARY_ELEMENT3, library);
1088 entry.setValue(LIBRARY_ELEMENT4, library);
1089 entry.setValue(LIBRARY_ELEMENT5, library);
1090 entry.setValue(LINE_INFO, new LineInfo(<int>[0]));
1091 entry.setValue(PARSE_ERRORS, AnalysisError.NO_ERRORS);
1092 entry.setState(PARSED_UNIT, CacheState.FLUSHED);
1093 entry.setState(RESOLVE_TYPE_NAMES_ERRORS, CacheState.FLUSHED);
1094 entry.setValue(SCAN_ERRORS, AnalysisError.NO_ERRORS);
1095 entry.setValue(SOURCE_KIND, SourceKind.LIBRARY);
1096 entry.setState(TOKEN_STREAM, CacheState.FLUSHED);
1097 entry.setValue(UNITS, <Source>[librarySource]);
1098
1099 LibrarySpecificUnit unit =
1100 new LibrarySpecificUnit(librarySource, librarySource);
1101 entry = getCacheEntry(unit);
1102 entry.setValue(HINTS, AnalysisError.NO_ERRORS);
1103 // dartEntry.setValue(LINTS, AnalysisError.NO_ERRORS);
1104 entry.setState(RESOLVE_REFERENCES_ERRORS, CacheState.FLUSHED);
1105 entry.setState(RESOLVED_UNIT, CacheState.FLUSHED);
1106 entry.setState(RESOLVED_UNIT1, CacheState.FLUSHED);
1107 entry.setState(RESOLVED_UNIT2, CacheState.FLUSHED);
1108 entry.setState(RESOLVED_UNIT3, CacheState.FLUSHED);
1109 entry.setState(RESOLVED_UNIT4, CacheState.FLUSHED);
1110 entry.setState(RESOLVED_UNIT5, CacheState.FLUSHED);
1111 // USED_IMPORTED_ELEMENTS
1112 // USED_LOCAL_ELEMENTS
1113 entry.setValue(VERIFY_ERRORS, AnalysisError.NO_ERRORS);
1114 });
1115
1116 cache.CacheEntry entry = getCacheEntry(AnalysisContextTarget.request);
1117 entry.setValue(TYPE_PROVIDER, typeProvider);
1118 }
1119
1120 @override
1121 void removeListener(AnalysisListener listener) {
1122 _listeners.remove(listener);
1123 }
1124
1125 @override
1126 CompilationUnit resolveCompilationUnit(
1127 Source unitSource, LibraryElement library) {
1128 if (library == null) {
1129 return null;
1130 }
1131 return resolveCompilationUnit2(unitSource, library.source);
1132 }
1133
1134 @override
1135 CompilationUnit resolveCompilationUnit2(
1136 Source unitSource, Source librarySource) => _computeResult(
1137 new LibrarySpecificUnit(librarySource, unitSource), RESOLVED_UNIT);
1138
1139 @override
1140 ht.HtmlUnit resolveHtmlUnit(Source htmlSource) {
1141 computeHtmlElement(htmlSource);
1142 return parseHtmlUnit(htmlSource);
1143 }
1144
1145 @override
1146 void setChangedContents(Source source, String contents, int offset,
1147 int oldLength, int newLength) {
1148 if (_contentRangeChanged(source, contents, offset, oldLength, newLength)) {
1149 _onSourcesChangedController.add(new SourcesChangedEvent.changedRange(
1150 source, contents, offset, oldLength, newLength));
1151 }
1152 }
1153
1154 @override
1155 void setContents(Source source, String contents) {
1156 _contentsChanged(source, contents, true);
1157 }
1158
1159 @override
1160 void visitCacheItems(void callback(Source source, SourceEntry dartEntry,
1161 DataDescriptor rowDesc, CacheState state)) {
1162 // TODO(brianwilkerson) Figure out where this is used and adjust the call
1163 // sites to use CacheEntry's.
1164 // bool hintsEnabled = _options.hint;
1165 // bool lintsEnabled = _options.lint;
1166 // MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator() ;
1167 // while (iterator.moveNext()) {
1168 // Source source = iterator.key;
1169 // cache.CacheEntry sourceEntry = iterator.value;
1170 // for (DataDescriptor descriptor in sourceEntry.descriptors) {
1171 // if (descriptor == DartEntry.SOURCE_KIND) {
1172 // // The source kind is always valid, so the state isn't interesting.
1173 // continue;
1174 // } else if (descriptor == DartEntry.CONTAINING_LIBRARIES) {
1175 // // The list of containing libraries is always valid, so the state
1176 // // isn't interesting.
1177 // continue;
1178 // } else if (descriptor == DartEntry.PUBLIC_NAMESPACE) {
1179 // // The public namespace isn't computed by performAnalysisTask()
1180 // // and therefore isn't interesting.
1181 // continue;
1182 // } else if (descriptor == HtmlEntry.HINTS) {
1183 // // We are not currently recording any hints related to HTML.
1184 // continue;
1185 // }
1186 // callback(
1187 // source, sourceEntry, descriptor, sourceEntry.getState(descriptor)) ;
1188 // }
1189 // if (sourceEntry is DartEntry) {
1190 // // get library-specific values
1191 // List<Source> librarySources = getLibrariesContaining(source);
1192 // for (Source librarySource in librarySources) {
1193 // for (DataDescriptor descriptor in sourceEntry.libraryDescriptors) {
1194 // if (descriptor == DartEntry.BUILT_ELEMENT ||
1195 // descriptor == DartEntry.BUILT_UNIT) {
1196 // // These values are not currently being computed, so their state
1197 // // is not interesting.
1198 // continue;
1199 // } else if (!sourceEntry.explicitlyAdded &&
1200 // !_generateImplicitErrors &&
1201 // (descriptor == DartEntry.VERIFICATION_ERRORS ||
1202 // descriptor == DartEntry.HINTS ||
1203 // descriptor == DartEntry.LINTS)) {
1204 // continue;
1205 // } else if (source.isInSystemLibrary &&
1206 // !_generateSdkErrors &&
1207 // (descriptor == DartEntry.VERIFICATION_ERRORS ||
1208 // descriptor == DartEntry.HINTS ||
1209 // descriptor == DartEntry.LINTS)) {
1210 // continue;
1211 // } else if (!hintsEnabled && descriptor == DartEntry.HINTS) {
1212 // continue;
1213 // } else if (!lintsEnabled && descriptor == DartEntry.LINTS) {
1214 // continue;
1215 // }
1216 // callback(librarySource, sourceEntry, descriptor,
1217 // sourceEntry.getStateInLibrary(descriptor, librarySource));
1218 // }
1219 // }
1220 // }
1221 // }
1222 }
1223
1224 /**
1225 * Visit all entries of the content cache.
1226 */
1227 void visitContentCache(ContentCacheVisitor visitor) {
1228 _contentCache.accept(visitor);
1229 }
1230
1231 /**
1232 * Add all of the sources contained in the given source [container] to the
1233 * given list of [sources].
1234 */
1235 void _addSourcesInContainer(List<Source> sources, SourceContainer container) {
1236 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator();
1237 while (iterator.moveNext()) {
1238 Source source = iterator.key;
1239 if (container.contains(source)) {
1240 sources.add(source);
1241 }
1242 }
1243 }
1244
1245 /**
1246 * Return the priority that should be used when the source associated with
1247 * the given [entry] is added to the work manager.
1248 */
1249 SourcePriority _computePriority(cache.CacheEntry entry) {
1250 // Used in commented out code.
1251 SourceKind kind = entry.getValue(SOURCE_KIND);
1252 if (kind == SourceKind.LIBRARY) {
1253 return SourcePriority.LIBRARY;
1254 } else if (kind == SourceKind.PART) {
1255 return SourcePriority.NORMAL_PART;
1256 }
1257 return SourcePriority.UNKNOWN;
1258 }
1259
1260 Object /*V*/ _computeResult(
1261 AnalysisTarget target, ResultDescriptor /*<V>*/ descriptor) {
1262 cache.CacheEntry entry = _cache.get(target);
1263 if (entry == null) {
1264 return descriptor.defaultValue;
1265 }
1266 if (descriptor is CompositeResultDescriptor) {
1267 List compositeResults = [];
1268 for (ResultDescriptor descriptor in descriptor.contributors) {
1269 List value = _computeResult(target, descriptor);
1270 compositeResults.addAll(value);
1271 }
1272 return compositeResults;
1273 }
1274 CacheState state = entry.getState(descriptor);
1275 if (state == CacheState.FLUSHED || state == CacheState.INVALID) {
1276 _driver.computeResult(target, descriptor);
1277 }
1278 return entry.getValue(descriptor);
1279 }
1280
1281 /**
1282 * Given the encoded form of a source ([encoding]), use the source factory to
1283 * reconstitute the original source.
1284 */
1285 Source _computeSourceFromEncoding(String encoding) =>
1286 _sourceFactory.fromEncoding(encoding);
1287
1288 /**
1289 * Return `true` if the given list of [sources] contains the given
1290 * [targetSource].
1291 */
1292 bool _contains(List<Source> sources, Source targetSource) {
1293 for (Source source in sources) {
1294 if (source == targetSource) {
1295 return true;
1296 }
1297 }
1298 return false;
1299 }
1300
1301 /**
1302 * Return `true` if the given list of [sources] contains any of the given
1303 * [targetSources].
1304 */
1305 bool _containsAny(List<Source> sources, List<Source> targetSources) {
1306 for (Source targetSource in targetSources) {
1307 if (_contains(sources, targetSource)) {
1308 return true;
1309 }
1310 }
1311 return false;
1312 }
1313
1314 /**
1315 * Set the contents of the given [source] to the given [contents] and mark the
1316 * source as having changed. The additional [offset], [oldLength] and
1317 * [newLength] information is used by the context to determine what reanalysis
1318 * is necessary. The method [setChangedContents] triggers a source changed
1319 * event where as this method does not.
1320 */
1321 bool _contentRangeChanged(Source source, String contents, int offset,
1322 int oldLength, int newLength) {
1323 bool changed = false;
1324 String originalContents = _contentCache.setContents(source, contents);
1325 if (contents != null) {
1326 if (contents != originalContents) {
1327 // TODO(brianwilkerson) Find a better way to do incremental analysis.
1328 // if (_options.incremental) {
1329 // _incrementalAnalysisCache = IncrementalAnalysisCache.update(
1330 // _incrementalAnalysisCache, source, originalContents, contents,
1331 // offset, oldLength, newLength, _cache.get(source));
1332 // }
1333 _sourceChanged(source);
1334 changed = true;
1335 cache.CacheEntry entry = _cache.get(source);
1336 if (entry != null) {
1337 entry.modificationTime = _contentCache.getModificationStamp(source);
1338 entry.setValue(CONTENT, contents);
1339 }
1340 }
1341 } else if (originalContents != null) {
1342 _incrementalAnalysisCache =
1343 IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
1344 _sourceChanged(source);
1345 changed = true;
1346 }
1347 return changed;
1348 }
1349
1350 /**
1351 * Set the contents of the given [source] to the given [contents] and mark the
1352 * source as having changed. This has the effect of overriding the default
1353 * contents of the source. If the contents are `null` the override is removed
1354 * so that the default contents will be returned. If [notify] is true, a
1355 * source changed event is triggered.
1356 */
1357 void _contentsChanged(Source source, String contents, bool notify) {
1358 String originalContents = _contentCache.setContents(source, contents);
1359 handleContentsChanged(source, originalContents, contents, notify);
1360 }
1361
1362 /**
1363 * Create a cache entry for the given [source]. The source was explicitly
1364 * added to this context if [explicitlyAdded] is `true`. Return the cache
1365 * entry that was created.
1366 */
1367 cache.CacheEntry _createCacheEntry(Source source, bool explicitlyAdded) {
1368 cache.CacheEntry entry = new cache.CacheEntry();
1369 entry.modificationTime = getModificationStamp(source);
1370 entry.explicitlyAdded = explicitlyAdded;
1371 _cache.put(source, entry);
1372 return entry;
1373 }
1374
1375 /**
1376 * Return a list containing all of the change notices that are waiting to be
1377 * returned. If there are no notices, then return either `null` or an empty
1378 * list, depending on the value of [nullIfEmpty].
1379 */
1380 List<ChangeNotice> _getChangeNotices(bool nullIfEmpty) {
1381 if (_pendingNotices.isEmpty) {
1382 if (nullIfEmpty) {
1383 return null;
1384 }
1385 return ChangeNoticeImpl.EMPTY_ARRAY;
1386 }
1387 List<ChangeNotice> notices = new List.from(_pendingNotices.values);
1388 _pendingNotices.clear();
1389 return notices;
1390 }
1391
1392 /**
1393 * Return a change notice for the given [source], creating one if one does not
1394 * already exist.
1395 */
1396 ChangeNoticeImpl _getNotice(Source source) {
1397 // Used in commented out code.
1398 ChangeNoticeImpl notice = _pendingNotices[source];
1399 if (notice == null) {
1400 notice = new ChangeNoticeImpl(source);
1401 _pendingNotices[source] = notice;
1402 }
1403 return notice;
1404 }
1405
1406 Object _getResult(AnalysisTarget target, ResultDescriptor descriptor) {
1407 cache.CacheEntry entry = _cache.get(target);
1408 if (entry != null && entry.isValid(descriptor)) {
1409 return entry.getValue(descriptor);
1410 }
1411 return descriptor.defaultValue;
1412 }
1413
1414 /**
1415 * Return a list containing all of the sources known to this context that have
1416 * the given [kind].
1417 */
1418 List<Source> _getSources(SourceKind kind) {
1419 List<Source> sources = new List<Source>();
1420 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator();
1421 while (iterator.moveNext()) {
1422 if (iterator.value.getValue(SOURCE_KIND) == kind &&
1423 iterator.key is Source) {
1424 sources.add(iterator.key);
1425 }
1426 }
1427 return sources;
1428 }
1429
1430 /**
1431 * Look at the given [source] to see whether a task needs to be performed
1432 * related to it. If so, add the source to the set of sources that need to be
1433 * processed. This method is intended to be used for testing purposes only.
1434 */
1435 void _getSourcesNeedingProcessing(Source source, cache.CacheEntry sourceEntry,
1436 bool isPriority, bool hintsEnabled, bool lintsEnabled,
1437 HashSet<Source> sources) {
1438 CacheState state = sourceEntry.getState(CONTENT);
1439 if (state == CacheState.INVALID ||
1440 (isPriority && state == CacheState.FLUSHED)) {
1441 sources.add(source);
1442 return;
1443 } else if (state == CacheState.ERROR) {
1444 return;
1445 }
1446 state = sourceEntry.getState(SOURCE_KIND);
1447 if (state == CacheState.INVALID ||
1448 (isPriority && state == CacheState.FLUSHED)) {
1449 sources.add(source);
1450 return;
1451 } else if (state == CacheState.ERROR) {
1452 return;
1453 }
1454 SourceKind kind = sourceEntry.getValue(SOURCE_KIND);
1455 if (kind == SourceKind.LIBRARY || kind == SourceKind.PART) {
1456 state = sourceEntry.getState(SCAN_ERRORS);
1457 if (state == CacheState.INVALID ||
1458 (isPriority && state == CacheState.FLUSHED)) {
1459 sources.add(source);
1460 return;
1461 } else if (state == CacheState.ERROR) {
1462 return;
1463 }
1464 state = sourceEntry.getState(PARSE_ERRORS);
1465 if (state == CacheState.INVALID ||
1466 (isPriority && state == CacheState.FLUSHED)) {
1467 sources.add(source);
1468 return;
1469 } else if (state == CacheState.ERROR) {
1470 return;
1471 }
1472 // if (isPriority) {
1473 // if (!sourceEntry.hasResolvableCompilationUnit) {
1474 // sources.add(source);
1475 // return;
1476 // }
1477 // }
1478 for (Source librarySource in getLibrariesContaining(source)) {
1479 cache.CacheEntry libraryEntry = _cache.get(librarySource);
1480 state = libraryEntry.getState(LIBRARY_ELEMENT);
1481 if (state == CacheState.INVALID ||
1482 (isPriority && state == CacheState.FLUSHED)) {
1483 sources.add(source);
1484 return;
1485 } else if (state == CacheState.ERROR) {
1486 return;
1487 }
1488 cache.CacheEntry unitEntry =
1489 _cache.get(new LibrarySpecificUnit(librarySource, source));
1490 state = unitEntry.getState(RESOLVED_UNIT);
1491 if (state == CacheState.INVALID ||
1492 (isPriority && state == CacheState.FLUSHED)) {
1493 sources.add(source);
1494 return;
1495 } else if (state == CacheState.ERROR) {
1496 return;
1497 }
1498 if (_shouldErrorsBeAnalyzed(source, unitEntry)) {
1499 state = unitEntry.getState(VERIFY_ERRORS);
1500 if (state == CacheState.INVALID ||
1501 (isPriority && state == CacheState.FLUSHED)) {
1502 sources.add(source);
1503 return;
1504 } else if (state == CacheState.ERROR) {
1505 return;
1506 }
1507 if (hintsEnabled) {
1508 state = unitEntry.getState(HINTS);
1509 if (state == CacheState.INVALID ||
1510 (isPriority && state == CacheState.FLUSHED)) {
1511 sources.add(source);
1512 return;
1513 } else if (state == CacheState.ERROR) {
1514 return;
1515 }
1516 }
1517 // if (lintsEnabled) {
1518 // state = unitEntry.getState(LINTS);
1519 // if (state == CacheState.INVALID ||
1520 // (isPriority && state == CacheState.FLUSHED)) {
1521 // sources.add(source);
1522 // return;
1523 // } else if (state == CacheState.ERROR) {
1524 // return;
1525 // }
1526 // }
1527 }
1528 }
1529 // } else if (kind == SourceKind.HTML) {
1530 // CacheState parsedUnitState = sourceEntry.getState(HtmlEntry.PARSED_UNIT) ;
1531 // if (parsedUnitState == CacheState.INVALID ||
1532 // (isPriority && parsedUnitState == CacheState.FLUSHED)) {
1533 // sources.add(source);
1534 // return;
1535 // }
1536 // CacheState resolvedUnitState =
1537 // sourceEntry.getState(HtmlEntry.RESOLVED_UNIT);
1538 // if (resolvedUnitState == CacheState.INVALID ||
1539 // (isPriority && resolvedUnitState == CacheState.FLUSHED)) {
1540 // sources.add(source);
1541 // return;
1542 // }
1543 }
1544 }
1545
1546 /**
1547 * Invalidate all of the resolution results computed by this context. The flag
1548 * [invalidateUris] should be `true` if the cached results of converting URIs
1549 * to source files should also be invalidated.
1550 */
1551 void _invalidateAllLocalResolutionInformation(bool invalidateUris) {
1552 HashMap<Source, List<Source>> oldPartMap =
1553 new HashMap<Source, List<Source>>();
1554 // TODO(brianwilkerson) Implement this
1555 // MapIterator<AnalysisTarget, cache.CacheEntry> iterator =
1556 // _privatePartition.iterator();
1557 // while (iterator.moveNext()) {
1558 // AnalysisTarget target = iterator.key;
1559 // cache.CacheEntry entry = iterator.value;
1560 // if (entry is HtmlEntry) {
1561 // HtmlEntry htmlEntry = entry;
1562 // htmlEntry.invalidateAllResolutionInformation(invalidateUris);
1563 // iterator.value = htmlEntry;
1564 // _workManager.add(target, SourcePriority.HTML);
1565 // } else if (entry is DartEntry) {
1566 // DartEntry dartEntry = entry;
1567 // oldPartMap[target] = dartEntry.getValue(DartEntry.INCLUDED_PARTS);
1568 // dartEntry.invalidateAllResolutionInformation(invalidateUris);
1569 // iterator.value = dartEntry;
1570 // _workManager.add(target, _computePriority(dartEntry));
1571 // }
1572 // }
1573 _removeFromPartsUsingMap(oldPartMap);
1574 }
1575
1576 /**
1577 * In response to a change to at least one of the compilation units in the
1578 * library defined by the given [librarySource], invalidate any results that
1579 * are dependent on the result of resolving that library.
1580 *
1581 * <b>Note:</b> Any cache entries that were accessed before this method was
1582 * invoked must be re-accessed after this method returns.
1583 */
1584 void _invalidateLibraryResolution(Source librarySource) {
1585 // TODO(brianwilkerson) Figure out whether we still need this.
1586 // TODO(brianwilkerson) This could be optimized. There's no need to flush
1587 // all of these entries if the public namespace hasn't changed, which will
1588 // be a fairly common case. The question is whether we can afford the time
1589 // to compute the namespace to look for differences.
1590 // DartEntry libraryEntry = _getReadableDartEntry(librarySource);
1591 // if (libraryEntry != null) {
1592 // List<Source> includedParts =
1593 // libraryEntry.getValue(DartEntry.INCLUDED_PARTS);
1594 // libraryEntry.invalidateAllResolutionInformation(false);
1595 // _workManager.add(librarySource, SourcePriority.LIBRARY);
1596 // for (Source partSource in includedParts) {
1597 // SourceEntry partEntry = _cache.get(partSource);
1598 // if (partEntry is DartEntry) {
1599 // partEntry.invalidateAllResolutionInformation(false);
1600 // }
1601 // }
1602 // }
1603 }
1604
1605 /**
1606 * Log the given debugging [message].
1607 */
1608 void _logInformation(String message) {
1609 AnalysisEngine.instance.logger.logInformation(message);
1610 }
1611
1612 /**
1613 * Notify all of the analysis listeners that the errors associated with the
1614 * given [source] has been updated to the given [errors].
1615 */
1616 void _notifyErrors(
1617 Source source, List<AnalysisError> errors, LineInfo lineInfo) {
1618 int count = _listeners.length;
1619 for (int i = 0; i < count; i++) {
1620 _listeners[i].computedErrors(this, source, errors, lineInfo);
1621 }
1622 }
1623
1624 /**
1625 * Remove the given libraries that are keys in the given map from the list of
1626 * containing libraries for each of the parts in the corresponding value.
1627 */
1628 void _removeFromPartsUsingMap(HashMap<Source, List<Source>> oldPartMap) {
1629 // TODO(brianwilkerson) Figure out whether we still need this.
1630 // oldPartMap.forEach((Source librarySource, List<Source> oldParts) {
1631 // for (int i = 0; i < oldParts.length; i++) {
1632 // Source partSource = oldParts[i];
1633 // if (partSource != librarySource) {
1634 // DartEntry partEntry = _getReadableDartEntry(partSource);
1635 // if (partEntry != null) {
1636 // partEntry.removeContainingLibrary(librarySource);
1637 // if (partEntry.containingLibraries.length == 0 &&
1638 // !exists(partSource)) {
1639 // _cache.remove(partSource);
1640 // }
1641 // }
1642 // }
1643 // }
1644 // });
1645 }
1646
1647 /**
1648 * Remove the given [source] from the priority order if it is in the list.
1649 */
1650 void _removeFromPriorityOrder(Source source) {
1651 int count = _priorityOrder.length;
1652 List<Source> newOrder = new List<Source>();
1653 for (int i = 0; i < count; i++) {
1654 if (_priorityOrder[i] != source) {
1655 newOrder.add(_priorityOrder[i]);
1656 }
1657 }
1658 if (newOrder.length < count) {
1659 analysisPriorityOrder = newOrder;
1660 }
1661 }
1662
1663 /**
1664 * Return `true` if errors should be produced for the given [source]. The
1665 * [entry] associated with the source is passed in for efficiency.
1666 */
1667 bool _shouldErrorsBeAnalyzed(Source source, cache.CacheEntry entry) {
1668 if (source.isInSystemLibrary) {
1669 return _options.generateSdkErrors;
1670 } else if (!entry.explicitlyAdded) {
1671 return _options.generateImplicitErrors;
1672 } else {
1673 return true;
1674 }
1675 }
1676
1677 /**
1678 * Create an entry for the newly added [source] and invalidate any sources
1679 * that referenced the source before it existed.
1680 */
1681 void _sourceAvailable(Source source) {
1682 cache.CacheEntry entry = _cache.get(source);
1683 if (entry == null) {
1684 _createCacheEntry(source, true);
1685 } else {
1686 // TODO(brianwilkerson) Implement this.
1687 // _propagateInvalidation(source, entry);
1688 }
1689 }
1690
1691 /**
1692 * Invalidate the [source] that was changed and any sources that referenced
1693 * the source before it existed.
1694 */
1695 void _sourceChanged(Source source) {
1696 cache.CacheEntry entry = _cache.get(source);
1697 // If the source is removed, we don't care about it.
1698 if (entry == null) {
1699 return;
1700 }
1701 // Check whether the content of the source is the same as it was the last
1702 // time.
1703 String sourceContent = entry.getValue(CONTENT);
1704 if (sourceContent != null) {
1705 entry.setState(CONTENT, CacheState.FLUSHED);
1706 try {
1707 TimestampedData<String> fileContents = getContents(source);
1708 if (fileContents.data == sourceContent) {
1709 return;
1710 }
1711 } catch (e) {}
1712 }
1713 // We need to invalidate the cache.
1714 // TODO(brianwilkerson) Implement this.
1715 // _propagateInvalidation(source, entry);
1716 }
1717
1718 /**
1719 * Record that the give [source] has been deleted.
1720 */
1721 void _sourceDeleted(Source source) {
1722 // TODO(brianwilkerson) Implement this.
1723 // SourceEntry sourceEntry = _cache.get(source);
1724 // if (sourceEntry is HtmlEntry) {
1725 // HtmlEntry htmlEntry = sourceEntry;
1726 // htmlEntry.recordContentError(new CaughtException(
1727 // new AnalysisException("This source was marked as being deleted"),
1728 // null));
1729 // } else if (sourceEntry is DartEntry) {
1730 // DartEntry dartEntry = sourceEntry;
1731 // HashSet<Source> libraries = new HashSet<Source>();
1732 // for (Source librarySource in getLibrariesContaining(source)) {
1733 // libraries.add(librarySource);
1734 // for (Source dependentLibrary
1735 // in getLibrariesDependingOn(librarySource)) {
1736 // libraries.add(dependentLibrary);
1737 // }
1738 // }
1739 // for (Source librarySource in libraries) {
1740 // _invalidateLibraryResolution(librarySource);
1741 // }
1742 // dartEntry.recordContentError(new CaughtException(
1743 // new AnalysisException("This source was marked as being deleted"),
1744 // null));
1745 // }
1746 _removeFromPriorityOrder(source);
1747 }
1748
1749 /**
1750 * Record that the given [source] has been removed.
1751 */
1752 void _sourceRemoved(Source source) {
1753 List<Source> containingLibraries = getLibrariesContaining(source);
1754 if (containingLibraries != null && containingLibraries.isNotEmpty) {
1755 HashSet<Source> libraries = new HashSet<Source>();
1756 for (Source librarySource in containingLibraries) {
1757 libraries.add(librarySource);
1758 for (Source dependentLibrary
1759 in getLibrariesDependingOn(librarySource)) {
1760 libraries.add(dependentLibrary);
1761 }
1762 }
1763 for (Source librarySource in libraries) {
1764 _invalidateLibraryResolution(librarySource);
1765 }
1766 }
1767 _cache.remove(source);
1768 _removeFromPriorityOrder(source);
1769 }
1770
1771 /**
1772 * TODO(scheglov) A hackish, limited incremental resolution implementation.
1773 */
1774 bool _tryPoorMansIncrementalResolution(Source unitSource, String newCode) {
1775 // TODO(brianwilkerson) Implement this.
1776 return false;
1777 // return PerformanceStatistics.incrementalAnalysis.makeCurrentWhile(() {
1778 // incrementalResolutionValidation_lastUnitSource = null;
1779 // incrementalResolutionValidation_lastLibrarySource = null;
1780 // incrementalResolutionValidation_lastUnit = null;
1781 // // prepare the entry
1782 // cache.CacheEntry entry = _cache.get(unitSource);
1783 // if (entry == null) {
1784 // return false;
1785 // }
1786 // // prepare the (only) library source
1787 // List<Source> librarySources = getLibrariesContaining(unitSource);
1788 // if (librarySources.length != 1) {
1789 // return false;
1790 // }
1791 // Source librarySource = librarySources[0];
1792 // // prepare the library element
1793 // LibraryElement libraryElement = getLibraryElement(librarySource);
1794 // if (libraryElement == null) {
1795 // return false;
1796 // }
1797 // // prepare the existing unit
1798 // CompilationUnit oldUnit =
1799 // getResolvedCompilationUnit2(unitSource, librarySource);
1800 // if (oldUnit == null) {
1801 // return false;
1802 // }
1803 // // do resolution
1804 // Stopwatch perfCounter = new Stopwatch()..start();
1805 // PoorMansIncrementalResolver resolver = new PoorMansIncrementalResolver(
1806 // typeProvider, unitSource, entry, oldUnit,
1807 // analysisOptions.incrementalApi, analysisOptions);
1808 // bool success = resolver.resolve(newCode);
1809 // AnalysisEngine.instance.instrumentationService.logPerformance(
1810 // AnalysisPerformanceKind.INCREMENTAL, perfCounter,
1811 // 'success=$success,context_id=$_id,code_length=${newCode.length}');
1812 // if (!success) {
1813 // return false;
1814 // }
1815 // // if validation, remember the result, but throw it away
1816 // if (analysisOptions.incrementalValidation) {
1817 // incrementalResolutionValidation_lastUnitSource = oldUnit.element.sourc e;
1818 // incrementalResolutionValidation_lastLibrarySource =
1819 // oldUnit.element.library.source;
1820 // incrementalResolutionValidation_lastUnit = oldUnit;
1821 // return false;
1822 // }
1823 // // prepare notice
1824 // {
1825 // LineInfo lineInfo = getLineInfo(unitSource);
1826 // ChangeNoticeImpl notice = _getNotice(unitSource);
1827 // notice.resolvedDartUnit = oldUnit;
1828 // notice.setErrors(entry.allErrors, lineInfo);
1829 // }
1830 // // OK
1831 // return true;
1832 // });
1833 }
1834
1835 /**
1836 * Check the cache for any invalid entries (entries whose modification time
1837 * does not match the modification time of the source associated with the
1838 * entry). Invalid entries will be marked as invalid so that the source will
1839 * be re-analyzed. Return `true` if at least one entry was invalid.
1840 */
1841 bool _validateCacheConsistency() {
1842 int consistencyCheckStart = JavaSystem.nanoTime();
1843 List<AnalysisTarget> changedTargets = new List<AnalysisTarget>();
1844 List<AnalysisTarget> missingTargets = new List<AnalysisTarget>();
1845 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator();
1846 while (iterator.moveNext()) {
1847 AnalysisTarget target = iterator.key;
1848 cache.CacheEntry entry = iterator.value;
1849 if (target is Source) {
1850 int sourceTime = getModificationStamp(target);
1851 if (sourceTime != entry.modificationTime) {
1852 changedTargets.add(target);
1853 }
1854 }
1855 if (entry.exception != null) {
1856 if (!exists(target)) {
1857 missingTargets.add(target);
1858 }
1859 }
1860 }
1861 int count = changedTargets.length;
1862 for (int i = 0; i < count; i++) {
1863 _sourceChanged(changedTargets[i]);
1864 }
1865 int removalCount = 0;
1866 for (AnalysisTarget target in missingTargets) {
1867 if (target is Source &&
1868 getLibrariesContaining(target).isEmpty &&
1869 getLibrariesDependingOn(target).isEmpty) {
1870 _cache.remove(target);
1871 removalCount++;
1872 }
1873 }
1874 int consistencyCheckEnd = JavaSystem.nanoTime();
1875 if (changedTargets.length > 0 || missingTargets.length > 0) {
1876 StringBuffer buffer = new StringBuffer();
1877 buffer.write("Consistency check took ");
1878 buffer.write((consistencyCheckEnd - consistencyCheckStart) / 1000000.0);
1879 buffer.writeln(" ms and found");
1880 buffer.write(" ");
1881 buffer.write(changedTargets.length);
1882 buffer.writeln(" inconsistent entries");
1883 buffer.write(" ");
1884 buffer.write(missingTargets.length);
1885 buffer.write(" missing sources (");
1886 buffer.write(removalCount);
1887 buffer.writeln(" removed");
1888 for (Source source in missingTargets) {
1889 buffer.write(" ");
1890 buffer.writeln(source.fullName);
1891 }
1892 _logInformation(buffer.toString());
1893 }
1894 return changedTargets.length > 0;
1895 }
1896 }
1897
1898 /**
1899 * A retention policy used by an analysis context.
1900 */
1901 class ContextRetentionPolicy implements cache.CacheRetentionPolicy {
1902 /**
1903 * The context associated with this policy.
1904 */
1905 final AnalysisContextImpl context;
1906
1907 /**
1908 * Initialize a newly created policy to be associated with the given
1909 * [context].
1910 */
1911 ContextRetentionPolicy(this.context);
1912
1913 @override
1914 RetentionPriority getAstPriority(
1915 AnalysisTarget target, cache.CacheEntry entry) {
1916 int priorityCount = context._priorityOrder.length;
1917 for (int i = 0; i < priorityCount; i++) {
1918 if (target == context._priorityOrder[i]) {
1919 return RetentionPriority.HIGH;
1920 }
1921 }
1922 if (_astIsNeeded(entry)) {
1923 return RetentionPriority.MEDIUM;
1924 }
1925 return RetentionPriority.LOW;
1926 }
1927
1928 bool _astIsNeeded(cache.CacheEntry entry) =>
1929 entry.isInvalid(BUILD_FUNCTION_TYPE_ALIASES_ERRORS) ||
1930 entry.isInvalid(BUILD_LIBRARY_ERRORS) ||
1931 entry.isInvalid(CONSTRUCTORS_ERRORS) ||
1932 entry.isInvalid(HINTS) ||
1933 //entry.isInvalid(LINTS) ||
1934 entry.isInvalid(RESOLVE_REFERENCES_ERRORS) ||
1935 entry.isInvalid(RESOLVE_TYPE_NAMES_ERRORS) ||
1936 entry.isInvalid(VERIFY_ERRORS);
1937 }
1938
1939 /**
1940 * An object that manages the partitions that can be shared between analysis
1941 * contexts.
1942 */
1943 class PartitionManager {
1944 /**
1945 * The default cache size for a Dart SDK partition.
1946 */
1947 static int _DEFAULT_SDK_CACHE_SIZE = 256;
1948
1949 /**
1950 * A table mapping SDK's to the partitions used for those SDK's.
1951 */
1952 HashMap<DartSdk, cache.SdkCachePartition> _sdkPartitions =
1953 new HashMap<DartSdk, cache.SdkCachePartition>();
1954
1955 /**
1956 * Clear any cached data being maintained by this manager.
1957 */
1958 void clearCache() {
1959 _sdkPartitions.clear();
1960 }
1961
1962 /**
1963 * Return the partition being used for the given [sdk], creating the partition
1964 * if necessary.
1965 */
1966 cache.SdkCachePartition forSdk(DartSdk sdk) {
1967 // Call sdk.context now, because when it creates a new
1968 // InternalAnalysisContext instance, it calls forSdk() again, so creates an
1969 // SdkCachePartition instance.
1970 // So, if we initialize context after "partition == null", we end up
1971 // with two SdkCachePartition instances.
1972 InternalAnalysisContext sdkContext = sdk.context;
1973 // Check cache for an existing partition.
1974 cache.SdkCachePartition partition = _sdkPartitions[sdk];
1975 if (partition == null) {
1976 partition =
1977 new cache.SdkCachePartition(sdkContext, _DEFAULT_SDK_CACHE_SIZE);
1978 _sdkPartitions[sdk] = partition;
1979 }
1980 return partition;
1981 }
1982 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698