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

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

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

Powered by Google App Engine
This is Rietveld 408576698