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

Side by Side Diff: mojo/public/dart/third_party/analyzer/lib/src/context/context.dart

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

Powered by Google App Engine
This is Rietveld 408576698