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

Side by Side Diff: mojo/public/dart/third_party/analyzer/lib/src/generated/engine.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) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library engine;
6
7 import 'dart:async';
8 import 'dart:collection';
9 import 'dart:math' as math;
10
11 import 'package:analyzer/src/cancelable_future.dart';
12 import 'package:analyzer/src/context/cache.dart' as cache;
13 import 'package:analyzer/src/context/context.dart' as newContext;
14 import 'package:analyzer/src/generated/incremental_resolution_validator.dart';
15 import 'package:analyzer/src/plugin/command_line_plugin.dart';
16 import 'package:analyzer/src/plugin/engine_plugin.dart';
17 import 'package:analyzer/src/plugin/options_plugin.dart';
18 import 'package:analyzer/src/services/lint.dart';
19 import 'package:analyzer/src/task/manager.dart';
20 import 'package:analyzer/task/dart.dart';
21 import 'package:analyzer/task/model.dart';
22 import 'package:html/dom.dart' show Document;
23 import 'package:plugin/manager.dart';
24 import 'package:plugin/plugin.dart';
25
26 import '../../instrumentation/instrumentation.dart';
27 import 'ast.dart';
28 import 'constant.dart';
29 import 'element.dart';
30 import 'error.dart';
31 import 'error_verifier.dart';
32 import 'html.dart' as ht;
33 import 'incremental_resolver.dart'
34 show IncrementalResolver, PoorMansIncrementalResolver;
35 import 'incremental_scanner.dart';
36 import 'java_core.dart';
37 import 'java_engine.dart';
38 import 'parser.dart' show Parser, IncrementalParser;
39 import 'resolver.dart';
40 import 'scanner.dart';
41 import 'sdk.dart' show DartSdk;
42 import 'source.dart';
43 import 'utilities_collection.dart';
44 import 'utilities_general.dart';
45
46 /**
47 * Used by [AnalysisOptions] to allow function bodies to be analyzed in some
48 * sources but not others.
49 */
50 typedef bool AnalyzeFunctionBodiesPredicate(Source source);
51
52 /**
53 * Type of callback functions used by PendingFuture. Functions of this type
54 * should perform a computation based on the data in [sourceEntry] and return
55 * it. If the computation can't be performed yet because more analysis is
56 * needed, null should be returned.
57 *
58 * The function may also throw an exception, in which case the corresponding
59 * future will be completed with failure.
60 *
61 * Since this function is called while the state of analysis is being updated,
62 * it should be free of side effects so that it doesn't cause reentrant
63 * changes to the analysis state.
64 */
65 typedef T PendingFutureComputer<T>(SourceEntry sourceEntry);
66
67 /**
68 * An LRU cache of information related to analysis.
69 */
70 class AnalysisCache {
71 /**
72 * A flag used to control whether trace information should be produced when
73 * the content of the cache is modified.
74 */
75 static bool _TRACE_CHANGES = false;
76
77 /**
78 * A list containing the partitions of which this cache is comprised.
79 */
80 final List<CachePartition> _partitions;
81
82 /**
83 * Initialize a newly created cache to have the given [_partitions]. The
84 * partitions will be searched in the order in which they appear in the list,
85 * so the most specific partition (usually an [SdkCachePartition]) should be
86 * first and the most general (usually a [UniversalCachePartition]) last.
87 */
88 AnalysisCache(this._partitions);
89
90 /**
91 * Return the number of entries in this cache that have an AST associated with
92 * them.
93 */
94 int get astSize => _partitions[_partitions.length - 1].astSize;
95
96 /**
97 * Return information about each of the partitions in this cache.
98 */
99 List<AnalysisContextStatistics_PartitionData> get partitionData {
100 int count = _partitions.length;
101 List<AnalysisContextStatistics_PartitionData> data =
102 new List<AnalysisContextStatistics_PartitionData>(count);
103 for (int i = 0; i < count; i++) {
104 CachePartition partition = _partitions[i];
105 data[i] = new AnalysisContextStatisticsImpl_PartitionDataImpl(
106 partition.astSize, partition.map.length);
107 }
108 return data;
109 }
110
111 /**
112 * Record that the AST associated with the given [source] was just read from
113 * the cache.
114 */
115 void accessedAst(Source source) {
116 int count = _partitions.length;
117 for (int i = 0; i < count; i++) {
118 if (_partitions[i].contains(source)) {
119 _partitions[i].accessedAst(source);
120 return;
121 }
122 }
123 }
124
125 /**
126 * Return the entry associated with the given [source].
127 */
128 SourceEntry get(Source source) {
129 int count = _partitions.length;
130 for (int i = 0; i < count; i++) {
131 if (_partitions[i].contains(source)) {
132 return _partitions[i].get(source);
133 }
134 }
135 //
136 // We should never get to this point because the last partition should
137 // always be a universal partition, except in the case of the SDK context,
138 // in which case the source should always be part of the SDK.
139 //
140 return null;
141 }
142
143 /**
144 * Return context that owns the given [source].
145 */
146 InternalAnalysisContext getContextFor(Source source) {
147 int count = _partitions.length;
148 for (int i = 0; i < count; i++) {
149 if (_partitions[i].contains(source)) {
150 return _partitions[i].context;
151 }
152 }
153 //
154 // We should never get to this point because the last partition should
155 // always be a universal partition, except in the case of the SDK context,
156 // in which case the source should always be part of the SDK.
157 //
158 AnalysisEngine.instance.logger.logInformation(
159 "Could not find context for ${source.fullName}",
160 new CaughtException(new AnalysisException(), null));
161 return null;
162 }
163
164 /**
165 * Return an iterator returning all of the map entries mapping sources to
166 * cache entries.
167 */
168 MapIterator<Source, SourceEntry> iterator() {
169 int count = _partitions.length;
170 List<Map<Source, SourceEntry>> maps =
171 new List<Map<Source, SourceEntry>>(count);
172 for (int i = 0; i < count; i++) {
173 maps[i] = _partitions[i].map;
174 }
175 return new MultipleMapIterator<Source, SourceEntry>(maps);
176 }
177
178 /**
179 * Associate the given [entry] with the given [source].
180 */
181 void put(Source source, SourceEntry entry) {
182 entry.fixExceptionState();
183 int count = _partitions.length;
184 for (int i = 0; i < count; i++) {
185 if (_partitions[i].contains(source)) {
186 if (_TRACE_CHANGES) {
187 try {
188 SourceEntry oldEntry = _partitions[i].get(source);
189 if (oldEntry == null) {
190 AnalysisEngine.instance.logger.logInformation(
191 "Added a cache entry for '${source.fullName}'.");
192 } else {
193 AnalysisEngine.instance.logger.logInformation(
194 "Modified the cache entry for ${source.fullName}'. Diff = ${en try.getDiff(oldEntry)}");
195 }
196 } catch (exception) {
197 // Ignored
198 JavaSystem.currentTimeMillis();
199 }
200 }
201 _partitions[i].put(source, entry);
202 return;
203 }
204 }
205 }
206
207 /**
208 * Remove all information related to the given [source] from this cache.
209 * Return the entry associated with the source, or `null` if there was cache
210 * entry for the source.
211 */
212 SourceEntry remove(Source source) {
213 int count = _partitions.length;
214 for (int i = 0; i < count; i++) {
215 if (_partitions[i].contains(source)) {
216 if (_TRACE_CHANGES) {
217 try {
218 AnalysisEngine.instance.logger.logInformation(
219 "Removed the cache entry for ${source.fullName}'.");
220 } catch (exception) {
221 // Ignored
222 JavaSystem.currentTimeMillis();
223 }
224 }
225 return _partitions[i].remove(source);
226 }
227 }
228 return null;
229 }
230
231 /**
232 * Record that the AST associated with the given [source] was just removed
233 * from the cache.
234 */
235 void removedAst(Source source) {
236 int count = _partitions.length;
237 for (int i = 0; i < count; i++) {
238 if (_partitions[i].contains(source)) {
239 _partitions[i].removedAst(source);
240 return;
241 }
242 }
243 }
244
245 /**
246 * Return the number of sources that are mapped to cache entries.
247 */
248 int size() {
249 int size = 0;
250 int count = _partitions.length;
251 for (int i = 0; i < count; i++) {
252 size += _partitions[i].size();
253 }
254 return size;
255 }
256
257 /**
258 * Record that the AST associated with the given [source] was just stored to
259 * the cache.
260 */
261 void storedAst(Source source) {
262 int count = _partitions.length;
263 for (int i = 0; i < count; i++) {
264 if (_partitions[i].contains(source)) {
265 _partitions[i].storedAst(source);
266 return;
267 }
268 }
269 }
270 }
271
272 /**
273 * A context in which a single analysis can be performed and incrementally
274 * maintained. The context includes such information as the version of the SDK
275 * being analyzed against as well as the package-root used to resolve 'package:'
276 * URI's. (Both of which are known indirectly through the [SourceFactory].)
277 *
278 * An analysis context also represents the state of the analysis, which includes
279 * knowing which sources have been included in the analysis (either directly or
280 * indirectly) and the results of the analysis. Sources must be added and
281 * removed from the context using the method [applyChanges], which is also used
282 * to notify the context when sources have been modified and, consequently,
283 * previously known results might have been invalidated.
284 *
285 * There are two ways to access the results of the analysis. The most common is
286 * to use one of the 'get' methods to access the results. The 'get' methods have
287 * the advantage that they will always return quickly, but have the disadvantage
288 * that if the results are not currently available they will return either
289 * nothing or in some cases an incomplete result. The second way to access
290 * results is by using one of the 'compute' methods. The 'compute' methods will
291 * always attempt to compute the requested results but might block the caller
292 * for a significant period of time.
293 *
294 * When results have been invalidated, have never been computed (as is the case
295 * for newly added sources), or have been removed from the cache, they are
296 * <b>not</b> automatically recreated. They will only be recreated if one of the
297 * 'compute' methods is invoked.
298 *
299 * However, this is not always acceptable. Some clients need to keep the
300 * analysis results up-to-date. For such clients there is a mechanism that
301 * allows them to incrementally perform needed analysis and get notified of the
302 * consequent changes to the analysis results. This mechanism is realized by the
303 * method [performAnalysisTask].
304 *
305 * Analysis engine allows for having more than one context. This can be used,
306 * for example, to perform one analysis based on the state of files on disk and
307 * a separate analysis based on the state of those files in open editors. It can
308 * also be used to perform an analysis based on a proposed future state, such as
309 * the state after a refactoring.
310 */
311 abstract class AnalysisContext {
312 /**
313 * An empty list of contexts.
314 */
315 static const List<AnalysisContext> EMPTY_LIST = const <AnalysisContext>[];
316
317 /**
318 * Return the set of analysis options controlling the behavior of this
319 * context. Clients should not modify the returned set of options. The options
320 * should only be set by invoking the method [setAnalysisOptions].
321 */
322 AnalysisOptions get analysisOptions;
323
324 /**
325 * Set the set of analysis options controlling the behavior of this context to
326 * the given [options]. Clients can safely assume that all necessary analysis
327 * results have been invalidated.
328 */
329 void set analysisOptions(AnalysisOptions options);
330
331 /**
332 * Set the order in which sources will be analyzed by [performAnalysisTask] to
333 * match the order of the sources in the given list of [sources]. If a source
334 * that needs to be analyzed is not contained in the list, then it will be
335 * treated as if it were at the end of the list. If the list is empty (or
336 * `null`) then no sources will be given priority over other sources.
337 *
338 * Changes made to the list after this method returns will <b>not</b> be
339 * reflected in the priority order.
340 */
341 void set analysisPriorityOrder(List<Source> sources);
342
343 /**
344 * Return the set of declared variables used when computing constant values.
345 */
346 DeclaredVariables get declaredVariables;
347
348 /**
349 * Return a list containing all of the sources known to this context that
350 * represent HTML files. The contents of the list can be incomplete.
351 */
352 List<Source> get htmlSources;
353
354 /**
355 * The stream that is notified when a source either starts or stops being
356 * analyzed implicitly.
357 */
358 Stream<ImplicitAnalysisEvent> get implicitAnalysisEvents;
359
360 /**
361 * Returns `true` if this context was disposed using [dispose].
362 */
363 bool get isDisposed;
364
365 /**
366 * Return a list containing all of the sources known to this context that
367 * represent the defining compilation unit of a library that can be run within
368 * a browser. The sources that are returned represent libraries that have a
369 * 'main' method and are either referenced by an HTML file or import, directly
370 * or indirectly, a client-only library. The contents of the list can be
371 * incomplete.
372 */
373 List<Source> get launchableClientLibrarySources;
374
375 /**
376 * Return a list containing all of the sources known to this context that
377 * represent the defining compilation unit of a library that can be run
378 * outside of a browser. The contents of the list can be incomplete.
379 */
380 List<Source> get launchableServerLibrarySources;
381
382 /**
383 * Return a list containing all of the sources known to this context that
384 * represent the defining compilation unit of a library. The contents of the
385 * list can be incomplete.
386 */
387 List<Source> get librarySources;
388
389 /**
390 * Return a client-provided name used to identify this context, or `null` if
391 * the client has not provided a name.
392 */
393 String get name;
394
395 /**
396 * Set the client-provided name used to identify this context to the given
397 * [name].
398 */
399 set name(String name);
400
401 /**
402 * The stream that is notified when sources have been added or removed,
403 * or the source's content has changed.
404 */
405 Stream<SourcesChangedEvent> get onSourcesChanged;
406
407 /**
408 * Return the source factory used to create the sources that can be analyzed
409 * in this context.
410 */
411 SourceFactory get sourceFactory;
412
413 /**
414 * Set the source factory used to create the sources that can be analyzed in
415 * this context to the given source [factory]. Clients can safely assume that
416 * all analysis results have been invalidated.
417 */
418 void set sourceFactory(SourceFactory factory);
419
420 /**
421 * Return a list containing all of the sources known to this context.
422 */
423 List<Source> get sources;
424
425 /**
426 * Return a type provider for this context or throw [AnalysisException] if
427 * either `dart:core` or `dart:async` cannot be resolved.
428 */
429 TypeProvider get typeProvider;
430
431 /**
432 * Add the given [listener] to the list of objects that are to be notified
433 * when various analysis results are produced in this context.
434 */
435 void addListener(AnalysisListener listener);
436
437 /**
438 * Apply the given [delta] to change the level of analysis that will be
439 * performed for the sources known to this context.
440 */
441 void applyAnalysisDelta(AnalysisDelta delta);
442
443 /**
444 * Apply the changes specified by the given [changeSet] to this context. Any
445 * analysis results that have been invalidated by these changes will be
446 * removed.
447 */
448 void applyChanges(ChangeSet changeSet);
449
450 /**
451 * Return the documentation comment for the given [element] as it appears in
452 * the original source (complete with the beginning and ending delimiters) for
453 * block documentation comments, or lines starting with `"///"` and separated
454 * with `"\n"` characters for end-of-line documentation comments, or `null` if
455 * the element does not have a documentation comment associated with it. This
456 * can be a long-running operation if the information needed to access the
457 * comment is not cached.
458 *
459 * Throws an [AnalysisException] if the documentation comment could not be
460 * determined because the analysis could not be performed.
461 *
462 * <b>Note:</b> This method cannot be used in an async environment.
463 */
464 String computeDocumentationComment(Element element);
465
466 /**
467 * Return a list containing all of the errors associated with the given
468 * [source]. If the errors are not already known then the source will be
469 * analyzed in order to determine the errors associated with it.
470 *
471 * Throws an [AnalysisException] if the errors could not be determined because
472 * the analysis could not be performed.
473 *
474 * <b>Note:</b> This method cannot be used in an async environment.
475 *
476 * See [getErrors].
477 */
478 List<AnalysisError> computeErrors(Source source);
479
480 /**
481 * Return the element model corresponding to the HTML file defined by the
482 * given [source]. If the element model does not yet exist it will be created.
483 * The process of creating an element model for an HTML file can be
484 * long-running, depending on the size of the file and the number of libraries
485 * that are defined in it (via script tags) that also need to have a model
486 * built for them.
487 *
488 * Throws AnalysisException if the element model could not be determined
489 * because the analysis could not be performed.
490 *
491 * <b>Note:</b> This method cannot be used in an async environment.
492 *
493 * See [getHtmlElement].
494 */
495 @deprecated
496 HtmlElement computeHtmlElement(Source source);
497
498 /**
499 * Return the kind of the given [source], computing it's kind if it is not
500 * already known. Return [SourceKind.UNKNOWN] if the source is not contained
501 * in this context.
502 *
503 * <b>Note:</b> This method cannot be used in an async environment.
504 *
505 * See [getKindOf].
506 */
507 SourceKind computeKindOf(Source source);
508
509 /**
510 * Return the element model corresponding to the library defined by the given
511 * [source]. If the element model does not yet exist it will be created. The
512 * process of creating an element model for a library can long-running,
513 * depending on the size of the library and the number of libraries that are
514 * imported into it that also need to have a model built for them.
515 *
516 * Throws an [AnalysisException] if the element model could not be determined
517 * because the analysis could not be performed.
518 *
519 * <b>Note:</b> This method cannot be used in an async environment.
520 *
521 * See [getLibraryElement].
522 */
523 LibraryElement computeLibraryElement(Source source);
524
525 /**
526 * Return the line information for the given [source], or `null` if the source
527 * is not of a recognized kind (neither a Dart nor HTML file). If the line
528 * information was not previously known it will be created. The line
529 * information is used to map offsets from the beginning of the source to line
530 * and column pairs.
531 *
532 * Throws an [AnalysisException] if the line information could not be
533 * determined because the analysis could not be performed.
534 *
535 * <b>Note:</b> This method cannot be used in an async environment.
536 *
537 * See [getLineInfo].
538 */
539 LineInfo computeLineInfo(Source source);
540
541 /**
542 * Return a future which will be completed with the fully resolved AST for a
543 * single compilation unit within the given library, once that AST is up to
544 * date.
545 *
546 * If the resolved AST can't be computed for some reason, the future will be
547 * completed with an error. One possible error is AnalysisNotScheduledError,
548 * which means that the resolved AST can't be computed because the given
549 * source file is not scheduled to be analyzed within the context of the
550 * given library.
551 */
552 CancelableFuture<CompilationUnit> computeResolvedCompilationUnitAsync(
553 Source source, Source librarySource);
554
555 /**
556 * Perform work until the given [result] has been computed for the given
557 * [target]. Return the computed value.
558 */
559 Object /*V*/ computeResult(AnalysisTarget target, ResultDescriptor /*<V>*/ res ult);
560
561 /**
562 * Notifies the context that the client is going to stop using this context.
563 */
564 void dispose();
565
566 /**
567 * Return `true` if the given [source] exists.
568 *
569 * This method should be used rather than the method [Source.exists] because
570 * contexts can have local overrides of the content of a source that the
571 * source is not aware of and a source with local content is considered to
572 * exist even if there is no file on disk.
573 */
574 bool exists(Source source);
575
576 /**
577 * Return the element model corresponding to the compilation unit defined by
578 * the given [unitSource] in the library defined by the given [librarySource],
579 * or `null` if the element model does not currently exist or if the library
580 * cannot be analyzed for some reason.
581 */
582 CompilationUnitElement getCompilationUnitElement(
583 Source unitSource, Source librarySource);
584
585 /**
586 * Return the contents and timestamp of the given [source].
587 *
588 * This method should be used rather than the method [Source.getContents]
589 * because contexts can have local overrides of the content of a source that
590 * the source is not aware of.
591 */
592 TimestampedData<String> getContents(Source source);
593
594 /**
595 * Return the element referenced by the given [location], or `null` if the
596 * element is not immediately available or if there is no element with the
597 * given location. The latter condition can occur, for example, if the
598 * location describes an element from a different context or if the element
599 * has been removed from this context as a result of some change since it was
600 * originally obtained.
601 */
602 Element getElement(ElementLocation location);
603
604 /**
605 * Return an analysis error info containing the list of all of the errors and
606 * the line info associated with the given [source]. The list of errors will
607 * be empty if the source is not known to this context or if there are no
608 * errors in the source. The errors contained in the list can be incomplete.
609 *
610 * See [computeErrors].
611 */
612 AnalysisErrorInfo getErrors(Source source);
613
614 /**
615 * Return the element model corresponding to the HTML file defined by the
616 * given [source], or `null` if the source does not represent an HTML file,
617 * the element representing the file has not yet been created, or the analysis
618 * of the HTML file failed for some reason.
619 *
620 * See [computeHtmlElement].
621 */
622 @deprecated
623 HtmlElement getHtmlElement(Source source);
624
625 /**
626 * Return the sources for the HTML files that reference the compilation unit
627 * with the given [source]. If the source does not represent a Dart source or
628 * is not known to this context, the returned list will be empty. The contents
629 * of the list can be incomplete.
630 */
631 List<Source> getHtmlFilesReferencing(Source source);
632
633 /**
634 * Return the kind of the given [source], or `null` if the kind is not known
635 * to this context.
636 *
637 * See [computeKindOf].
638 */
639 SourceKind getKindOf(Source source);
640
641 /**
642 * Return the sources for the defining compilation units of any libraries of
643 * which the given [source] is a part. The list will normally contain a single
644 * library because most Dart sources are only included in a single library,
645 * but it is possible to have a part that is contained in multiple identically
646 * named libraries. If the source represents the defining compilation unit of
647 * a library, then the returned list will contain the given source as its only
648 * element. If the source does not represent a Dart source or is not known to
649 * this context, the returned list will be empty. The contents of the list can
650 * be incomplete.
651 */
652 List<Source> getLibrariesContaining(Source source);
653
654 /**
655 * Return the sources for the defining compilation units of any libraries that
656 * depend on the library defined by the given [librarySource]. One library
657 * depends on another if it either imports or exports that library.
658 */
659 List<Source> getLibrariesDependingOn(Source librarySource);
660
661 /**
662 * Return the sources for the defining compilation units of any libraries that
663 * are referenced from the HTML file defined by the given [htmlSource].
664 */
665 List<Source> getLibrariesReferencedFromHtml(Source htmlSource);
666
667 /**
668 * Return the element model corresponding to the library defined by the given
669 * [source], or `null` if the element model does not currently exist or if the
670 * library cannot be analyzed for some reason.
671 */
672 LibraryElement getLibraryElement(Source source);
673
674 /**
675 * Return the line information for the given [source], or `null` if the line
676 * information is not known. The line information is used to map offsets from
677 * the beginning of the source to line and column pairs.
678 *
679 * See [computeLineInfo].
680 */
681 LineInfo getLineInfo(Source source);
682
683 /**
684 * Return the modification stamp for the [source], or a negative value if the
685 * source does not exist. A modification stamp is a non-negative integer with
686 * the property that if the contents of the source have not been modified
687 * since the last time the modification stamp was accessed then the same value
688 * will be returned, but if the contents of the source have been modified one
689 * or more times (even if the net change is zero) the stamps will be different .
690 *
691 * This method should be used rather than the method
692 * [Source.getModificationStamp] because contexts can have local overrides of
693 * the content of a source that the source is not aware of.
694 */
695 int getModificationStamp(Source source);
696
697 /**
698 * Return a fully resolved AST for the compilation unit defined by the given
699 * [unitSource] within the given [library], or `null` if the resolved AST is
700 * not already computed.
701 *
702 * See [resolveCompilationUnit].
703 */
704 CompilationUnit getResolvedCompilationUnit(
705 Source unitSource, LibraryElement library);
706
707 /**
708 * Return a fully resolved AST for the compilation unit defined by the given
709 * [unitSource] within the library defined by the given [librarySource], or
710 * `null` if the resolved AST is not already computed.
711 *
712 * See [resolveCompilationUnit2].
713 */
714 CompilationUnit getResolvedCompilationUnit2(
715 Source unitSource, Source librarySource);
716
717 /**
718 * Return the fully resolved HTML unit defined by the given [htmlSource], or
719 * `null` if the resolved unit is not already computed.
720 *
721 * See [resolveHtmlUnit].
722 */
723 @deprecated
724 ht.HtmlUnit getResolvedHtmlUnit(Source htmlSource);
725
726 /**
727 * Return the value of the given [result] for the given [target].
728 *
729 * If the corresponding [target] does not exist, or the [result] is not
730 * computed yet, then the default value is returned.
731 */
732 Object /*V*/ getResult(AnalysisTarget target, ResultDescriptor /*<V>*/ result) ;
733
734 /**
735 * Return a list of the sources being analyzed in this context whose full path
736 * is equal to the given [path].
737 */
738 List<Source> getSourcesWithFullName(String path);
739
740 /**
741 * Invalidates hints in the given [librarySource] and included parts.
742 */
743 void invalidateLibraryHints(Source librarySource);
744
745 /**
746 * Return `true` if the given [librarySource] is known to be the defining
747 * compilation unit of a library that can be run on a client (references
748 * 'dart:html', either directly or indirectly).
749 *
750 * <b>Note:</b> In addition to the expected case of returning `false` if the
751 * source is known to be a library that cannot be run on a client, this method
752 * will also return `false` if the source is not known to be a library or if
753 * we do not know whether it can be run on a client.
754 */
755 bool isClientLibrary(Source librarySource);
756
757 /**
758 * Return `true` if the given [librarySource] is known to be the defining
759 * compilation unit of a library that can be run on the server (does not
760 * reference 'dart:html', either directly or indirectly).
761 *
762 * <b>Note:</b> In addition to the expected case of returning `false` if the
763 * source is known to be a library that cannot be run on the server, this
764 * method will also return `false` if the source is not known to be a library
765 * or if we do not know whether it can be run on the server.
766 */
767 bool isServerLibrary(Source librarySource);
768
769 /**
770 * Return the stream that is notified when a new value for the given
771 * [descriptor] is computed.
772 */
773 Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor);
774
775 /**
776 * Parse the content of the given [source] to produce an AST structure. The
777 * resulting AST structure may or may not be resolved, and may have a slightly
778 * different structure depending upon whether it is resolved.
779 *
780 * Throws an [AnalysisException] if the analysis could not be performed
781 *
782 * <b>Note:</b> This method cannot be used in an async environment.
783 */
784 CompilationUnit parseCompilationUnit(Source source);
785
786 /**
787 * Parse a single HTML [source] to produce a document model.
788 *
789 * Throws an [AnalysisException] if the analysis could not be performed
790 *
791 * <b>Note:</b> This method cannot be used in an async environment.
792 */
793 Document parseHtmlDocument(Source source);
794
795 /**
796 * Parse a single HTML [source] to produce an AST structure. The resulting
797 * HTML AST structure may or may not be resolved, and may have a slightly
798 * different structure depending upon whether it is resolved.
799 *
800 * Throws an [AnalysisException] if the analysis could not be performed
801 *
802 * <b>Note:</b> This method cannot be used in an async environment.
803 */
804 @deprecated // use parseHtmlDocument(source)
805 ht.HtmlUnit parseHtmlUnit(Source source);
806
807 /**
808 * Perform the next unit of work required to keep the analysis results
809 * up-to-date and return information about the consequent changes to the
810 * analysis results. This method can be long running.
811 *
812 * The implementation that uses the task model notifies subscribers of
813 * [onResultComputed] about computed results.
814 *
815 * The following results are computed for Dart sources.
816 *
817 * 1. For explicit and implicit sources:
818 * [PARSED_UNIT]
819 * [RESOLVED_UNIT]
820 *
821 * 2. For explicit sources:
822 * [DART_ERRORS].
823 *
824 * 3. For explicit and implicit library sources:
825 * [LIBRARY_ELEMENT].
826 */
827 AnalysisResult performAnalysisTask();
828
829 /**
830 * Remove the given [listener] from the list of objects that are to be
831 * notified when various analysis results are produced in this context.
832 */
833 void removeListener(AnalysisListener listener);
834
835 /**
836 * Return a fully resolved AST for the compilation unit defined by the given
837 * [unitSource] within the given [library].
838 *
839 * Throws an [AnalysisException] if the analysis could not be performed.
840 *
841 * <b>Note:</b> This method cannot be used in an async environment.
842 *
843 * See [getResolvedCompilationUnit].
844 */
845 CompilationUnit resolveCompilationUnit(
846 Source unitSource, LibraryElement library);
847
848 /**
849 * Return a fully resolved AST for the compilation unit defined by the given
850 * [unitSource] within the library defined by the given [librarySource].
851 *
852 * Throws an [AnalysisException] if the analysis could not be performed.
853 *
854 * <b>Note:</b> This method cannot be used in an async environment.
855 *
856 * See [getResolvedCompilationUnit2].
857 */
858 CompilationUnit resolveCompilationUnit2(
859 Source unitSource, Source librarySource);
860
861 /**
862 * Parse and resolve a single [htmlSource] within the given context to produce
863 * a fully resolved AST.
864 *
865 * Throws an [AnalysisException] if the analysis could not be performed.
866 *
867 * <b>Note:</b> This method cannot be used in an async environment.
868 */
869 @deprecated
870 ht.HtmlUnit resolveHtmlUnit(Source htmlSource);
871
872 /**
873 * Set the contents of the given [source] to the given [contents] and mark the
874 * source as having changed. The additional [offset] and [length] information
875 * is used by the context to determine what reanalysis is necessary.
876 */
877 void setChangedContents(
878 Source source, String contents, int offset, int oldLength, int newLength);
879
880 /**
881 * Set the contents of the given [source] to the given [contents] and mark the
882 * source as having changed. This has the effect of overriding the default
883 * contents of the source. If the contents are `null` the override is removed
884 * so that the default contents will be returned.
885 */
886 void setContents(Source source, String contents);
887
888 /**
889 * Check the cache for any invalid entries (entries whose modification time
890 * does not match the modification time of the source associated with the
891 * entry). Invalid entries will be marked as invalid so that the source will
892 * be re-analyzed. Return `true` if at least one entry was invalid.
893 */
894 bool validateCacheConsistency();
895 }
896
897 /**
898 * An [AnalysisContext].
899 */
900 class AnalysisContextImpl implements InternalAnalysisContext {
901 /**
902 * The difference between the maximum cache size and the maximum priority
903 * order size. The priority list must be capped so that it is less than the
904 * cache size. Failure to do so can result in an infinite loop in
905 * performAnalysisTask() because re-caching one AST structure can cause
906 * another priority source's AST structure to be flushed.
907 */
908 static int _PRIORITY_ORDER_SIZE_DELTA = 4;
909
910 /**
911 * A flag indicating whether trace output should be produced as analysis tasks
912 * are performed. Used for debugging.
913 */
914 static bool _TRACE_PERFORM_TASK = false;
915
916 /**
917 * The next context identifier.
918 */
919 static int _NEXT_ID = 0;
920
921 /**
922 * The unique identifier of this context.
923 */
924 final int _id = _NEXT_ID++;
925
926 /**
927 * A client-provided name used to identify this context, or `null` if the
928 * client has not provided a name.
929 */
930 String name;
931
932 /**
933 * The set of analysis options controlling the behavior of this context.
934 */
935 AnalysisOptionsImpl _options = new AnalysisOptionsImpl();
936
937 /**
938 * A flag indicating whether errors related to implicitly analyzed sources
939 * should be generated and reported.
940 */
941 bool _generateImplicitErrors = true;
942
943 /**
944 * A flag indicating whether errors related to sources in the SDK should be
945 * generated and reported.
946 */
947 bool _generateSdkErrors = true;
948
949 /**
950 * A flag indicating whether this context is disposed.
951 */
952 bool _disposed = false;
953
954 /**
955 * A cache of content used to override the default content of a source.
956 */
957 ContentCache _contentCache = new ContentCache();
958
959 /**
960 * The source factory used to create the sources that can be analyzed in this
961 * context.
962 */
963 SourceFactory _sourceFactory;
964
965 /**
966 * The set of declared variables used when computing constant values.
967 */
968 DeclaredVariables _declaredVariables = new DeclaredVariables();
969
970 /**
971 * A source representing the core library.
972 */
973 Source _coreLibrarySource;
974
975 /**
976 * A source representing the async library.
977 */
978 Source _asyncLibrarySource;
979
980 /**
981 * The partition that contains analysis results that are not shared with other
982 * contexts.
983 */
984 CachePartition _privatePartition;
985
986 /**
987 * A table mapping the sources known to the context to the information known
988 * about the source.
989 */
990 AnalysisCache _cache;
991
992 /**
993 * A list containing sources for which data should not be flushed.
994 */
995 List<Source> _priorityOrder = Source.EMPTY_LIST;
996
997 /**
998 * A map from all sources for which there are futures pending to a list of
999 * the corresponding PendingFuture objects. These sources will be analyzed
1000 * in the same way as priority sources, except with higher priority.
1001 *
1002 * TODO(paulberry): since the size of this map is not constrained (as it is
1003 * for _priorityOrder), we run the risk of creating an analysis loop if
1004 * re-caching one AST structure causes the AST structure for another source
1005 * with pending futures to be flushed. However, this is unlikely to happen
1006 * in practice since sources are removed from this hash set as soon as their
1007 * futures have completed.
1008 */
1009 HashMap<Source, List<PendingFuture>> _pendingFutureSources =
1010 new HashMap<Source, List<PendingFuture>>();
1011
1012 /**
1013 * A list containing sources whose AST structure is needed in order to resolve
1014 * the next library to be resolved.
1015 */
1016 HashSet<Source> _neededForResolution = null;
1017
1018 /**
1019 * A table mapping sources to the change notices that are waiting to be
1020 * returned related to that source.
1021 */
1022 HashMap<Source, ChangeNoticeImpl> _pendingNotices =
1023 new HashMap<Source, ChangeNoticeImpl>();
1024
1025 /**
1026 * The object used to record the results of performing an analysis task.
1027 */
1028 AnalysisContextImpl_AnalysisTaskResultRecorder _resultRecorder;
1029
1030 /**
1031 * Cached information used in incremental analysis or `null` if none.
1032 */
1033 IncrementalAnalysisCache _incrementalAnalysisCache;
1034
1035 /**
1036 * The [TypeProvider] for this context, `null` if not yet created.
1037 */
1038 TypeProvider _typeProvider;
1039
1040 /**
1041 * The object used to manage the list of sources that need to be analyzed.
1042 */
1043 WorkManager _workManager = new WorkManager();
1044
1045 /**
1046 * The [Stopwatch] of the current "perform tasks cycle".
1047 */
1048 Stopwatch _performAnalysisTaskStopwatch;
1049
1050 /**
1051 * The controller for sending [SourcesChangedEvent]s.
1052 */
1053 StreamController<SourcesChangedEvent> _onSourcesChangedController;
1054
1055 /**
1056 * A subscription for a stream of events indicating when files are (and are
1057 * not) being implicitly analyzed.
1058 */
1059 StreamController<ImplicitAnalysisEvent> _implicitAnalysisEventsController;
1060
1061 /**
1062 * The listeners that are to be notified when various analysis results are
1063 * produced in this context.
1064 */
1065 List<AnalysisListener> _listeners = new List<AnalysisListener>();
1066
1067 /**
1068 * The most recently incrementally resolved source, or `null` when it was
1069 * already validated, or the most recent change was not incrementally resolved .
1070 */
1071 Source incrementalResolutionValidation_lastUnitSource;
1072
1073 /**
1074 * The most recently incrementally resolved library source, or `null` when it
1075 * was already validated, or the most recent change was not incrementally
1076 * resolved.
1077 */
1078 Source incrementalResolutionValidation_lastLibrarySource;
1079
1080 /**
1081 * The result of incremental resolution result of
1082 * [incrementalResolutionValidation_lastSource].
1083 */
1084 CompilationUnit incrementalResolutionValidation_lastUnit;
1085
1086 /**
1087 * A factory to override how the [ResolverVisitor] is created.
1088 */
1089 ResolverVisitorFactory resolverVisitorFactory;
1090
1091 /**
1092 * A factory to override how the [TypeResolverVisitor] is created.
1093 */
1094 TypeResolverVisitorFactory typeResolverVisitorFactory;
1095
1096 /**
1097 * A factory to override how [LibraryResolver] is created.
1098 */
1099 LibraryResolverFactory libraryResolverFactory;
1100
1101 /**
1102 * Initialize a newly created analysis context.
1103 */
1104 AnalysisContextImpl() {
1105 _resultRecorder = new AnalysisContextImpl_AnalysisTaskResultRecorder(this);
1106 _privatePartition = new UniversalCachePartition(
1107 this,
1108 AnalysisOptionsImpl.DEFAULT_CACHE_SIZE,
1109 new AnalysisContextImpl_ContextRetentionPolicy(this));
1110 _cache = createCacheFromSourceFactory(null);
1111 _onSourcesChangedController =
1112 new StreamController<SourcesChangedEvent>.broadcast();
1113 _implicitAnalysisEventsController =
1114 new StreamController<ImplicitAnalysisEvent>.broadcast();
1115 }
1116
1117 @override
1118 AnalysisCache get analysisCache => _cache;
1119
1120 @override
1121 AnalysisOptions get analysisOptions => _options;
1122
1123 @override
1124 void set analysisOptions(AnalysisOptions options) {
1125 bool needsRecompute = this._options.analyzeFunctionBodiesPredicate !=
1126 options.analyzeFunctionBodiesPredicate ||
1127 this._options.generateImplicitErrors !=
1128 options.generateImplicitErrors ||
1129 this._options.generateSdkErrors != options.generateSdkErrors ||
1130 this._options.dart2jsHint != options.dart2jsHint ||
1131 (this._options.hint && !options.hint) ||
1132 this._options.preserveComments != options.preserveComments ||
1133 this._options.strongMode != options.strongMode ||
1134 this._options.enableStrictCallChecks !=
1135 options.enableStrictCallChecks ||
1136 this._options.enableSuperMixins != options.enableSuperMixins;
1137 int cacheSize = options.cacheSize;
1138 if (this._options.cacheSize != cacheSize) {
1139 this._options.cacheSize = cacheSize;
1140 //cache.setMaxCacheSize(cacheSize);
1141 _privatePartition.maxCacheSize = cacheSize;
1142 //
1143 // Cap the size of the priority list to being less than the cache size.
1144 // Failure to do so can result in an infinite loop in
1145 // performAnalysisTask() because re-caching one AST structure
1146 // can cause another priority source's AST structure to be flushed.
1147 //
1148 // TODO(brianwilkerson) Remove this constraint when the new task model is
1149 // implemented.
1150 //
1151 int maxPriorityOrderSize = cacheSize - _PRIORITY_ORDER_SIZE_DELTA;
1152 if (_priorityOrder.length > maxPriorityOrderSize) {
1153 _priorityOrder = _priorityOrder.sublist(0, maxPriorityOrderSize);
1154 }
1155 }
1156 this._options.analyzeFunctionBodiesPredicate =
1157 options.analyzeFunctionBodiesPredicate;
1158 this._options.generateImplicitErrors = options.generateImplicitErrors;
1159 this._options.generateSdkErrors = options.generateSdkErrors;
1160 this._options.dart2jsHint = options.dart2jsHint;
1161 this._options.enableStrictCallChecks = options.enableStrictCallChecks;
1162 this._options.enableSuperMixins = options.enableSuperMixins;
1163 this._options.hint = options.hint;
1164 this._options.incremental = options.incremental;
1165 this._options.incrementalApi = options.incrementalApi;
1166 this._options.incrementalValidation = options.incrementalValidation;
1167 this._options.lint = options.lint;
1168 this._options.preserveComments = options.preserveComments;
1169 this._options.strongMode = options.strongMode;
1170 _generateImplicitErrors = options.generateImplicitErrors;
1171 _generateSdkErrors = options.generateSdkErrors;
1172 if (needsRecompute) {
1173 _invalidateAllLocalResolutionInformation(false);
1174 }
1175 }
1176
1177 @override
1178 void set analysisPriorityOrder(List<Source> sources) {
1179 if (sources == null || sources.isEmpty) {
1180 _priorityOrder = Source.EMPTY_LIST;
1181 } else {
1182 while (sources.remove(null)) {
1183 // Nothing else to do.
1184 }
1185 if (sources.isEmpty) {
1186 _priorityOrder = Source.EMPTY_LIST;
1187 }
1188 //
1189 // Cap the size of the priority list to being less than the cache size.
1190 // Failure to do so can result in an infinite loop in
1191 // performAnalysisTask() because re-caching one AST structure
1192 // can cause another priority source's AST structure to be flushed.
1193 //
1194 int count = math.min(
1195 sources.length, _options.cacheSize - _PRIORITY_ORDER_SIZE_DELTA);
1196 _priorityOrder = new List<Source>(count);
1197 for (int i = 0; i < count; i++) {
1198 _priorityOrder[i] = sources[i];
1199 }
1200 // Ensure entries for every priority source.
1201 for (var source in _priorityOrder) {
1202 SourceEntry entry = _getReadableSourceEntry(source);
1203 if (entry == null) {
1204 _createSourceEntry(source, false);
1205 }
1206 }
1207 }
1208 }
1209
1210 @override
1211 set contentCache(ContentCache value) {
1212 _contentCache = value;
1213 }
1214
1215 @override
1216 DeclaredVariables get declaredVariables => _declaredVariables;
1217
1218 @override
1219 List<AnalysisTarget> get explicitTargets {
1220 List<AnalysisTarget> targets = <AnalysisTarget>[];
1221 MapIterator<Source, SourceEntry> iterator = _cache.iterator();
1222 while (iterator.moveNext()) {
1223 if (iterator.value.explicitlyAdded) {
1224 targets.add(iterator.key);
1225 }
1226 }
1227 return targets;
1228 }
1229
1230 @override
1231 List<Source> get htmlSources => _getSources(SourceKind.HTML);
1232
1233 @override
1234 Stream<ImplicitAnalysisEvent> get implicitAnalysisEvents =>
1235 _implicitAnalysisEventsController.stream;
1236
1237 @override
1238 bool get isDisposed => _disposed;
1239
1240 @override
1241 List<Source> get launchableClientLibrarySources {
1242 // TODO(brianwilkerson) This needs to filter out libraries that do not
1243 // reference dart:html, either directly or indirectly.
1244 List<Source> sources = new List<Source>();
1245 MapIterator<Source, SourceEntry> iterator = _cache.iterator();
1246 while (iterator.moveNext()) {
1247 Source source = iterator.key;
1248 SourceEntry sourceEntry = iterator.value;
1249 if (sourceEntry.kind == SourceKind.LIBRARY && !source.isInSystemLibrary) {
1250 // DartEntry dartEntry = (DartEntry) sourceEntry;
1251 // if (dartEntry.getValue(DartEntry.IS_LAUNCHABLE) && dartEntry.getValu e(DartEntry.IS_CLIENT)) {
1252 sources.add(source);
1253 // }
1254 }
1255 }
1256 return sources;
1257 }
1258
1259 @override
1260 List<Source> get launchableServerLibrarySources {
1261 // TODO(brianwilkerson) This needs to filter out libraries that reference
1262 // dart:html, either directly or indirectly.
1263 List<Source> sources = new List<Source>();
1264 MapIterator<Source, SourceEntry> iterator = _cache.iterator();
1265 while (iterator.moveNext()) {
1266 Source source = iterator.key;
1267 SourceEntry sourceEntry = iterator.value;
1268 if (sourceEntry.kind == SourceKind.LIBRARY && !source.isInSystemLibrary) {
1269 // DartEntry dartEntry = (DartEntry) sourceEntry;
1270 // if (dartEntry.getValue(DartEntry.IS_LAUNCHABLE) && !dartEntry.getVal ue(DartEntry.IS_CLIENT)) {
1271 sources.add(source);
1272 // }
1273 }
1274 }
1275 return sources;
1276 }
1277
1278 @override
1279 List<Source> get librarySources => _getSources(SourceKind.LIBRARY);
1280
1281 /**
1282 * Look through the cache for a task that needs to be performed. Return the
1283 * task that was found, or `null` if there is no more work to be done.
1284 */
1285 AnalysisTask get nextAnalysisTask {
1286 bool hintsEnabled = _options.hint;
1287 bool lintsEnabled = _options.lint;
1288 bool hasBlockedTask = false;
1289 //
1290 // Look for incremental analysis
1291 //
1292 if (_incrementalAnalysisCache != null &&
1293 _incrementalAnalysisCache.hasWork) {
1294 AnalysisTask task =
1295 new IncrementalAnalysisTask(this, _incrementalAnalysisCache);
1296 _incrementalAnalysisCache = null;
1297 return task;
1298 }
1299 //
1300 // Look for a source that needs to be analyzed because it has futures
1301 // pending.
1302 //
1303 if (_pendingFutureSources.isNotEmpty) {
1304 List<Source> sourcesToRemove = <Source>[];
1305 AnalysisTask task;
1306 for (Source source in _pendingFutureSources.keys) {
1307 SourceEntry sourceEntry = _cache.get(source);
1308 List<PendingFuture> pendingFutures = _pendingFutureSources[source];
1309 for (int i = 0; i < pendingFutures.length;) {
1310 if (pendingFutures[i].evaluate(sourceEntry)) {
1311 pendingFutures.removeAt(i);
1312 } else {
1313 i++;
1314 }
1315 }
1316 if (pendingFutures.isEmpty) {
1317 sourcesToRemove.add(source);
1318 continue;
1319 }
1320 AnalysisContextImpl_TaskData taskData = _getNextAnalysisTaskForSource(
1321 source, sourceEntry, true, hintsEnabled, lintsEnabled);
1322 task = taskData.task;
1323 if (task != null) {
1324 break;
1325 } else if (taskData.isBlocked) {
1326 hasBlockedTask = true;
1327 } else {
1328 // There is no more work to do for this task, so forcibly complete
1329 // all its pending futures.
1330 for (PendingFuture pendingFuture in pendingFutures) {
1331 pendingFuture.forciblyComplete();
1332 }
1333 sourcesToRemove.add(source);
1334 }
1335 }
1336 for (Source source in sourcesToRemove) {
1337 _pendingFutureSources.remove(source);
1338 }
1339 if (task != null) {
1340 return task;
1341 }
1342 }
1343 //
1344 // Look for a priority source that needs to be analyzed.
1345 //
1346 int priorityCount = _priorityOrder.length;
1347 for (int i = 0; i < priorityCount; i++) {
1348 Source source = _priorityOrder[i];
1349 AnalysisContextImpl_TaskData taskData = _getNextAnalysisTaskForSource(
1350 source, _cache.get(source), true, hintsEnabled, lintsEnabled);
1351 AnalysisTask task = taskData.task;
1352 if (task != null) {
1353 return task;
1354 } else if (taskData.isBlocked) {
1355 hasBlockedTask = true;
1356 }
1357 }
1358 if (_neededForResolution != null) {
1359 List<Source> sourcesToRemove = new List<Source>();
1360 for (Source source in _neededForResolution) {
1361 SourceEntry sourceEntry = _cache.get(source);
1362 if (sourceEntry is DartEntry) {
1363 DartEntry dartEntry = sourceEntry;
1364 if (!dartEntry.hasResolvableCompilationUnit) {
1365 if (dartEntry.getState(DartEntry.PARSED_UNIT) == CacheState.ERROR) {
1366 sourcesToRemove.add(source);
1367 } else {
1368 AnalysisContextImpl_TaskData taskData =
1369 _createParseDartTask(source, dartEntry);
1370 AnalysisTask task = taskData.task;
1371 if (task != null) {
1372 return task;
1373 } else if (taskData.isBlocked) {
1374 hasBlockedTask = true;
1375 }
1376 }
1377 }
1378 }
1379 }
1380 int count = sourcesToRemove.length;
1381 for (int i = 0; i < count; i++) {
1382 _neededForResolution.remove(sourcesToRemove[i]);
1383 }
1384 }
1385 //
1386 // Look for a non-priority source that needs to be analyzed.
1387 //
1388 List<Source> sourcesToRemove = new List<Source>();
1389 WorkManager_WorkIterator sources = _workManager.iterator();
1390 try {
1391 while (sources.hasNext) {
1392 Source source = sources.next();
1393 AnalysisContextImpl_TaskData taskData = _getNextAnalysisTaskForSource(
1394 source, _cache.get(source), false, hintsEnabled, lintsEnabled);
1395 AnalysisTask task = taskData.task;
1396 if (task != null) {
1397 return task;
1398 } else if (taskData.isBlocked) {
1399 hasBlockedTask = true;
1400 } else {
1401 sourcesToRemove.add(source);
1402 }
1403 }
1404 } finally {
1405 int count = sourcesToRemove.length;
1406 for (int i = 0; i < count; i++) {
1407 _workManager.remove(sourcesToRemove[i]);
1408 }
1409 }
1410 if (hasBlockedTask) {
1411 // All of the analysis work is blocked waiting for an asynchronous task
1412 // to complete.
1413 return WaitForAsyncTask.instance;
1414 }
1415 return null;
1416 }
1417
1418 @override
1419 Stream<SourcesChangedEvent> get onSourcesChanged =>
1420 _onSourcesChangedController.stream;
1421
1422 /**
1423 * Make _pendingFutureSources available to unit tests.
1424 */
1425 HashMap<Source, List<PendingFuture>> get pendingFutureSources_forTesting =>
1426 _pendingFutureSources;
1427
1428 @override
1429 List<Source> get prioritySources => _priorityOrder;
1430
1431 @override
1432 List<AnalysisTarget> get priorityTargets => prioritySources;
1433
1434 @override
1435 CachePartition get privateAnalysisCachePartition => _privatePartition;
1436
1437 @override
1438 SourceFactory get sourceFactory => _sourceFactory;
1439
1440 @override
1441 void set sourceFactory(SourceFactory factory) {
1442 if (identical(_sourceFactory, factory)) {
1443 return;
1444 } else if (factory.context != null) {
1445 throw new IllegalStateException(
1446 "Source factories cannot be shared between contexts");
1447 }
1448 if (_sourceFactory != null) {
1449 _sourceFactory.context = null;
1450 }
1451 factory.context = this;
1452 _sourceFactory = factory;
1453 _coreLibrarySource = _sourceFactory.forUri(DartSdk.DART_CORE);
1454 _asyncLibrarySource = _sourceFactory.forUri(DartSdk.DART_ASYNC);
1455 _cache = createCacheFromSourceFactory(factory);
1456 _invalidateAllLocalResolutionInformation(true);
1457 }
1458
1459 @override
1460 List<Source> get sources {
1461 List<Source> sources = new List<Source>();
1462 MapIterator<Source, SourceEntry> iterator = _cache.iterator();
1463 while (iterator.moveNext()) {
1464 sources.add(iterator.key);
1465 }
1466 return sources;
1467 }
1468
1469 /**
1470 * Return a list of the sources that would be processed by
1471 * [performAnalysisTask]. This method duplicates, and must therefore be kept
1472 * in sync with, [getNextAnalysisTask]. This method is intended to be used for
1473 * testing purposes only.
1474 */
1475 List<Source> get sourcesNeedingProcessing {
1476 HashSet<Source> sources = new HashSet<Source>();
1477 bool hintsEnabled = _options.hint;
1478 bool lintsEnabled = _options.lint;
1479
1480 //
1481 // Look for priority sources that need to be analyzed.
1482 //
1483 for (Source source in _priorityOrder) {
1484 _getSourcesNeedingProcessing(source, _cache.get(source), true,
1485 hintsEnabled, lintsEnabled, sources);
1486 }
1487 //
1488 // Look for non-priority sources that need to be analyzed.
1489 //
1490 WorkManager_WorkIterator iterator = _workManager.iterator();
1491 while (iterator.hasNext) {
1492 Source source = iterator.next();
1493 _getSourcesNeedingProcessing(source, _cache.get(source), false,
1494 hintsEnabled, lintsEnabled, sources);
1495 }
1496 return new List<Source>.from(sources);
1497 }
1498
1499 @override
1500 AnalysisContextStatistics get statistics {
1501 AnalysisContextStatisticsImpl statistics =
1502 new AnalysisContextStatisticsImpl();
1503 visitCacheItems(statistics._internalPutCacheItem);
1504 statistics.partitionData = _cache.partitionData;
1505 return statistics;
1506 }
1507
1508 IncrementalAnalysisCache get test_incrementalAnalysisCache {
1509 return _incrementalAnalysisCache;
1510 }
1511
1512 set test_incrementalAnalysisCache(IncrementalAnalysisCache value) {
1513 _incrementalAnalysisCache = value;
1514 }
1515
1516 List<Source> get test_priorityOrder => _priorityOrder;
1517
1518 @override
1519 TypeProvider get typeProvider {
1520 if (_typeProvider != null) {
1521 return _typeProvider;
1522 }
1523 Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE);
1524 if (coreSource == null) {
1525 throw new AnalysisException("Could not create a source for dart:core");
1526 }
1527 LibraryElement coreElement = computeLibraryElement(coreSource);
1528 if (coreElement == null) {
1529 throw new AnalysisException("Could not create an element for dart:core");
1530 }
1531 Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
1532 if (asyncSource == null) {
1533 throw new AnalysisException("Could not create a source for dart:async");
1534 }
1535 LibraryElement asyncElement = computeLibraryElement(asyncSource);
1536 if (asyncElement == null) {
1537 throw new AnalysisException("Could not create an element for dart:async");
1538 }
1539 _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
1540 return _typeProvider;
1541 }
1542
1543 /**
1544 * Sets the [TypeProvider] for this context.
1545 */
1546 void set typeProvider(TypeProvider typeProvider) {
1547 _typeProvider = typeProvider;
1548 }
1549
1550 @override
1551 void addListener(AnalysisListener listener) {
1552 if (!_listeners.contains(listener)) {
1553 _listeners.add(listener);
1554 }
1555 }
1556
1557 @override
1558 void applyAnalysisDelta(AnalysisDelta delta) {
1559 ChangeSet changeSet = new ChangeSet();
1560 delta.analysisLevels.forEach((Source source, AnalysisLevel level) {
1561 if (level == AnalysisLevel.NONE) {
1562 changeSet.removedSource(source);
1563 } else {
1564 changeSet.addedSource(source);
1565 }
1566 });
1567 applyChanges(changeSet);
1568 }
1569
1570 @override
1571 void applyChanges(ChangeSet changeSet) {
1572 if (changeSet.isEmpty) {
1573 return;
1574 }
1575 //
1576 // First, compute the list of sources that have been removed.
1577 //
1578 List<Source> removedSources =
1579 new List<Source>.from(changeSet.removedSources);
1580 for (SourceContainer container in changeSet.removedContainers) {
1581 _addSourcesInContainer(removedSources, container);
1582 }
1583 //
1584 // Then determine which cached results are no longer valid.
1585 //
1586 for (Source source in changeSet.addedSources) {
1587 _sourceAvailable(source);
1588 }
1589 for (Source source in changeSet.changedSources) {
1590 if (_contentCache.getContents(source) != null) {
1591 // This source is overridden in the content cache, so the change will
1592 // have no effect. Just ignore it to avoid wasting time doing
1593 // re-analysis.
1594 continue;
1595 }
1596 _sourceChanged(source);
1597 }
1598 changeSet.changedContents.forEach((Source key, String value) {
1599 _contentsChanged(key, value, false);
1600 });
1601 changeSet.changedRanges
1602 .forEach((Source source, ChangeSet_ContentChange change) {
1603 _contentRangeChanged(source, change.contents, change.offset,
1604 change.oldLength, change.newLength);
1605 });
1606 for (Source source in changeSet.deletedSources) {
1607 _sourceDeleted(source);
1608 }
1609 for (Source source in removedSources) {
1610 _sourceRemoved(source);
1611 }
1612 _onSourcesChangedController.add(new SourcesChangedEvent(changeSet));
1613 }
1614
1615 @override
1616 String computeDocumentationComment(Element element) {
1617 if (element == null) {
1618 return null;
1619 }
1620 Source source = element.source;
1621 if (source == null) {
1622 return null;
1623 }
1624 CompilationUnit unit = parseCompilationUnit(source);
1625 if (unit == null) {
1626 return null;
1627 }
1628 NodeLocator locator = new NodeLocator(element.nameOffset);
1629 AstNode nameNode = locator.searchWithin(unit);
1630 while (nameNode != null) {
1631 if (nameNode is AnnotatedNode) {
1632 Comment comment = nameNode.documentationComment;
1633 if (comment == null) {
1634 return null;
1635 }
1636 StringBuffer buffer = new StringBuffer();
1637 List<Token> tokens = comment.tokens;
1638 for (int i = 0; i < tokens.length; i++) {
1639 if (i > 0) {
1640 buffer.write("\n");
1641 }
1642 buffer.write(tokens[i].lexeme);
1643 }
1644 return buffer.toString();
1645 }
1646 nameNode = nameNode.parent;
1647 }
1648 return null;
1649 }
1650
1651 @override
1652 List<AnalysisError> computeErrors(Source source) {
1653 bool enableHints = _options.hint;
1654 bool enableLints = _options.lint;
1655
1656 SourceEntry sourceEntry = _getReadableSourceEntry(source);
1657 if (sourceEntry is DartEntry) {
1658 List<AnalysisError> errors = new List<AnalysisError>();
1659 try {
1660 DartEntry dartEntry = sourceEntry;
1661 ListUtilities.addAll(
1662 errors, _getDartScanData(source, dartEntry, DartEntry.SCAN_ERRORS));
1663 dartEntry = _getReadableDartEntry(source);
1664 ListUtilities.addAll(errors,
1665 _getDartParseData(source, dartEntry, DartEntry.PARSE_ERRORS));
1666 dartEntry = _getReadableDartEntry(source);
1667 if (dartEntry.getValue(DartEntry.SOURCE_KIND) == SourceKind.LIBRARY) {
1668 ListUtilities.addAll(
1669 errors,
1670 _getDartResolutionData(
1671 source, source, dartEntry, DartEntry.RESOLUTION_ERRORS));
1672 dartEntry = _getReadableDartEntry(source);
1673 ListUtilities.addAll(
1674 errors,
1675 _getDartVerificationData(
1676 source, source, dartEntry, DartEntry.VERIFICATION_ERRORS));
1677 if (enableHints) {
1678 dartEntry = _getReadableDartEntry(source);
1679 ListUtilities.addAll(errors,
1680 _getDartHintData(source, source, dartEntry, DartEntry.HINTS));
1681 }
1682 if (enableLints) {
1683 dartEntry = _getReadableDartEntry(source);
1684 ListUtilities.addAll(errors,
1685 _getDartLintData(source, source, dartEntry, DartEntry.LINTS));
1686 }
1687 } else {
1688 List<Source> libraries = getLibrariesContaining(source);
1689 for (Source librarySource in libraries) {
1690 ListUtilities.addAll(
1691 errors,
1692 _getDartResolutionData(source, librarySource, dartEntry,
1693 DartEntry.RESOLUTION_ERRORS));
1694 dartEntry = _getReadableDartEntry(source);
1695 ListUtilities.addAll(
1696 errors,
1697 _getDartVerificationData(source, librarySource, dartEntry,
1698 DartEntry.VERIFICATION_ERRORS));
1699 if (enableHints) {
1700 dartEntry = _getReadableDartEntry(source);
1701 ListUtilities.addAll(
1702 errors,
1703 _getDartHintData(
1704 source, librarySource, dartEntry, DartEntry.HINTS));
1705 }
1706 if (enableLints) {
1707 dartEntry = _getReadableDartEntry(source);
1708 ListUtilities.addAll(
1709 errors,
1710 _getDartLintData(
1711 source, librarySource, dartEntry, DartEntry.LINTS));
1712 }
1713 }
1714 }
1715 } on ObsoleteSourceAnalysisException catch (exception, stackTrace) {
1716 AnalysisEngine.instance.logger.logInformation(
1717 "Could not compute errors",
1718 new CaughtException(exception, stackTrace));
1719 }
1720 if (errors.isEmpty) {
1721 return AnalysisError.NO_ERRORS;
1722 }
1723 return errors;
1724 } else if (sourceEntry is HtmlEntry) {
1725 HtmlEntry htmlEntry = sourceEntry;
1726 try {
1727 return _getHtmlResolutionData2(
1728 source, htmlEntry, HtmlEntry.RESOLUTION_ERRORS);
1729 } on ObsoleteSourceAnalysisException catch (exception, stackTrace) {
1730 AnalysisEngine.instance.logger.logInformation(
1731 "Could not compute errors",
1732 new CaughtException(exception, stackTrace));
1733 }
1734 }
1735 return AnalysisError.NO_ERRORS;
1736 }
1737
1738 @override
1739 List<Source> computeExportedLibraries(Source source) => _getDartParseData2(
1740 source, DartEntry.EXPORTED_LIBRARIES, Source.EMPTY_LIST);
1741
1742 @override
1743 @deprecated
1744 HtmlElement computeHtmlElement(Source source) =>
1745 _getHtmlResolutionData(source, HtmlEntry.ELEMENT, null);
1746
1747 @override
1748 List<Source> computeImportedLibraries(Source source) => _getDartParseData2(
1749 source, DartEntry.IMPORTED_LIBRARIES, Source.EMPTY_LIST);
1750
1751 @override
1752 SourceKind computeKindOf(Source source) {
1753 SourceEntry sourceEntry = _getReadableSourceEntry(source);
1754 if (sourceEntry == null) {
1755 return SourceKind.UNKNOWN;
1756 } else if (sourceEntry is DartEntry) {
1757 try {
1758 return _getDartParseData(source, sourceEntry, DartEntry.SOURCE_KIND);
1759 } on AnalysisException {
1760 return SourceKind.UNKNOWN;
1761 }
1762 }
1763 return sourceEntry.kind;
1764 }
1765
1766 @override
1767 LibraryElement computeLibraryElement(Source source) =>
1768 _getDartResolutionData2(source, source, DartEntry.ELEMENT, null);
1769
1770 @override
1771 LineInfo computeLineInfo(Source source) {
1772 SourceEntry sourceEntry = _getReadableSourceEntry(source);
1773 try {
1774 if (sourceEntry is HtmlEntry) {
1775 return _getHtmlParseData(source, SourceEntry.LINE_INFO, null);
1776 } else if (sourceEntry is DartEntry) {
1777 return _getDartScanData2(source, SourceEntry.LINE_INFO, null);
1778 }
1779 } on ObsoleteSourceAnalysisException catch (exception, stackTrace) {
1780 AnalysisEngine.instance.logger.logInformation(
1781 "Could not compute ${SourceEntry.LINE_INFO}",
1782 new CaughtException(exception, stackTrace));
1783 }
1784 return null;
1785 }
1786
1787 @override
1788 CompilationUnit computeResolvableCompilationUnit(Source source) {
1789 DartEntry dartEntry = _getReadableDartEntry(source);
1790 if (dartEntry == null) {
1791 throw new AnalysisException(
1792 "computeResolvableCompilationUnit for non-Dart: ${source.fullName}");
1793 }
1794 dartEntry = _cacheDartParseData(source, dartEntry, DartEntry.PARSED_UNIT);
1795 CompilationUnit unit = dartEntry.resolvableCompilationUnit;
1796 if (unit == null) {
1797 throw new AnalysisException(
1798 "Internal error: computeResolvableCompilationUnit could not parse ${so urce.fullName}",
1799 new CaughtException(dartEntry.exception, null));
1800 }
1801 return unit;
1802 }
1803
1804 @override
1805 CancelableFuture<CompilationUnit> computeResolvedCompilationUnitAsync(
1806 Source unitSource, Source librarySource) {
1807 return new _AnalysisFutureHelper<CompilationUnit>(this)
1808 .computeAsync(unitSource, (SourceEntry sourceEntry) {
1809 if (sourceEntry is DartEntry) {
1810 if (sourceEntry.getStateInLibrary(
1811 DartEntry.RESOLVED_UNIT, librarySource) ==
1812 CacheState.ERROR) {
1813 throw sourceEntry.exception;
1814 }
1815 return sourceEntry.getValueInLibrary(
1816 DartEntry.RESOLVED_UNIT, librarySource);
1817 }
1818 throw new AnalysisNotScheduledError();
1819 });
1820 }
1821
1822 @override
1823 Object computeResult(AnalysisTarget target, ResultDescriptor result) {
1824 return result.defaultValue;
1825 }
1826
1827 /**
1828 * Create an analysis cache based on the given source [factory].
1829 */
1830 AnalysisCache createCacheFromSourceFactory(SourceFactory factory) {
1831 if (factory == null) {
1832 return new AnalysisCache(<CachePartition>[_privatePartition]);
1833 }
1834 DartSdk sdk = factory.dartSdk;
1835 if (sdk == null) {
1836 return new AnalysisCache(<CachePartition>[_privatePartition]);
1837 }
1838 return new AnalysisCache(<CachePartition>[
1839 AnalysisEngine.instance.partitionManager.forSdk(sdk),
1840 _privatePartition
1841 ]);
1842 }
1843
1844 @override
1845 void dispose() {
1846 _disposed = true;
1847 for (List<PendingFuture> pendingFutures in _pendingFutureSources.values) {
1848 for (PendingFuture pendingFuture in pendingFutures) {
1849 pendingFuture.forciblyComplete();
1850 }
1851 }
1852 _pendingFutureSources.clear();
1853 }
1854
1855 @override
1856 List<CompilationUnit> ensureResolvedDartUnits(Source unitSource) {
1857 SourceEntry sourceEntry = _cache.get(unitSource);
1858 if (sourceEntry is! DartEntry) {
1859 return null;
1860 }
1861 DartEntry dartEntry = sourceEntry;
1862 // Check every library.
1863 List<CompilationUnit> units = <CompilationUnit>[];
1864 List<Source> containingLibraries = dartEntry.containingLibraries;
1865 for (Source librarySource in containingLibraries) {
1866 CompilationUnit unit =
1867 dartEntry.getValueInLibrary(DartEntry.RESOLVED_UNIT, librarySource);
1868 if (unit == null) {
1869 units = null;
1870 break;
1871 }
1872 units.add(unit);
1873 }
1874 // Invalidate the flushed RESOLVED_UNIT to force it eventually.
1875 if (units == null) {
1876 bool shouldBeScheduled = false;
1877 for (Source librarySource in containingLibraries) {
1878 if (dartEntry.getStateInLibrary(
1879 DartEntry.RESOLVED_UNIT, librarySource) ==
1880 CacheState.FLUSHED) {
1881 dartEntry.setStateInLibrary(
1882 DartEntry.RESOLVED_UNIT, librarySource, CacheState.INVALID);
1883 shouldBeScheduled = true;
1884 }
1885 }
1886 if (shouldBeScheduled) {
1887 _workManager.add(unitSource, SourcePriority.UNKNOWN);
1888 }
1889 // We cannot provide resolved units right now,
1890 // but the future analysis will.
1891 return null;
1892 }
1893 // done
1894 return units;
1895 }
1896
1897 @override
1898 bool exists(Source source) {
1899 if (source == null) {
1900 return false;
1901 }
1902 if (_contentCache.getContents(source) != null) {
1903 return true;
1904 }
1905 return source.exists();
1906 }
1907
1908 @override
1909 cache.CacheEntry getCacheEntry(AnalysisTarget target) {
1910 return null;
1911 }
1912
1913 @override
1914 CompilationUnitElement getCompilationUnitElement(
1915 Source unitSource, Source librarySource) {
1916 LibraryElement libraryElement = getLibraryElement(librarySource);
1917 if (libraryElement != null) {
1918 // try defining unit
1919 CompilationUnitElement definingUnit =
1920 libraryElement.definingCompilationUnit;
1921 if (definingUnit.source == unitSource) {
1922 return definingUnit;
1923 }
1924 // try parts
1925 for (CompilationUnitElement partUnit in libraryElement.parts) {
1926 if (partUnit.source == unitSource) {
1927 return partUnit;
1928 }
1929 }
1930 }
1931 return null;
1932 }
1933
1934 @override
1935 TimestampedData<String> getContents(Source source) {
1936 String contents = _contentCache.getContents(source);
1937 if (contents != null) {
1938 return new TimestampedData<String>(
1939 _contentCache.getModificationStamp(source), contents);
1940 }
1941 return source.contents;
1942 }
1943
1944 @override
1945 InternalAnalysisContext getContextFor(Source source) {
1946 InternalAnalysisContext context = _cache.getContextFor(source);
1947 return context == null ? this : context;
1948 }
1949
1950 @override
1951 Element getElement(ElementLocation location) {
1952 // TODO(brianwilkerson) This should not be a "get" method.
1953 try {
1954 List<String> components = location.components;
1955 Source source = _computeSourceFromEncoding(components[0]);
1956 String sourceName = source.shortName;
1957 if (AnalysisEngine.isDartFileName(sourceName)) {
1958 ElementImpl element = computeLibraryElement(source) as ElementImpl;
1959 for (int i = 1; i < components.length; i++) {
1960 if (element == null) {
1961 return null;
1962 }
1963 element = element.getChild(components[i]);
1964 }
1965 return element;
1966 }
1967 if (AnalysisEngine.isHtmlFileName(sourceName)) {
1968 return computeHtmlElement(source);
1969 }
1970 } catch (exception) {
1971 // If the location cannot be decoded for some reason then the underlying
1972 // cause should have been logged already and we can fall though to return
1973 // null.
1974 }
1975 return null;
1976 }
1977
1978 @override
1979 AnalysisErrorInfo getErrors(Source source) {
1980 SourceEntry sourceEntry = getReadableSourceEntryOrNull(source);
1981 if (sourceEntry is DartEntry) {
1982 DartEntry dartEntry = sourceEntry;
1983 return new AnalysisErrorInfoImpl(
1984 dartEntry.allErrors, dartEntry.getValue(SourceEntry.LINE_INFO));
1985 } else if (sourceEntry is HtmlEntry) {
1986 HtmlEntry htmlEntry = sourceEntry;
1987 return new AnalysisErrorInfoImpl(
1988 htmlEntry.allErrors, htmlEntry.getValue(SourceEntry.LINE_INFO));
1989 }
1990 return new AnalysisErrorInfoImpl(AnalysisError.NO_ERRORS, null);
1991 }
1992
1993 @override
1994 @deprecated
1995 HtmlElement getHtmlElement(Source source) {
1996 SourceEntry sourceEntry = getReadableSourceEntryOrNull(source);
1997 if (sourceEntry is HtmlEntry) {
1998 return sourceEntry.getValue(HtmlEntry.ELEMENT);
1999 }
2000 return null;
2001 }
2002
2003 @override
2004 List<Source> getHtmlFilesReferencing(Source source) {
2005 SourceKind sourceKind = getKindOf(source);
2006 if (sourceKind == null) {
2007 return Source.EMPTY_LIST;
2008 }
2009 List<Source> htmlSources = new List<Source>();
2010 while (true) {
2011 if (sourceKind == SourceKind.PART) {
2012 List<Source> librarySources = getLibrariesContaining(source);
2013 MapIterator<Source, SourceEntry> partIterator = _cache.iterator();
2014 while (partIterator.moveNext()) {
2015 SourceEntry sourceEntry = partIterator.value;
2016 if (sourceEntry.kind == SourceKind.HTML) {
2017 List<Source> referencedLibraries = (sourceEntry as HtmlEntry)
2018 .getValue(HtmlEntry.REFERENCED_LIBRARIES);
2019 if (_containsAny(referencedLibraries, librarySources)) {
2020 htmlSources.add(partIterator.key);
2021 }
2022 }
2023 }
2024 } else {
2025 MapIterator<Source, SourceEntry> iterator = _cache.iterator();
2026 while (iterator.moveNext()) {
2027 SourceEntry sourceEntry = iterator.value;
2028 if (sourceEntry.kind == SourceKind.HTML) {
2029 List<Source> referencedLibraries = (sourceEntry as HtmlEntry)
2030 .getValue(HtmlEntry.REFERENCED_LIBRARIES);
2031 if (_contains(referencedLibraries, source)) {
2032 htmlSources.add(iterator.key);
2033 }
2034 }
2035 }
2036 }
2037 break;
2038 }
2039 if (htmlSources.isEmpty) {
2040 return Source.EMPTY_LIST;
2041 }
2042 return htmlSources;
2043 }
2044
2045 @override
2046 SourceKind getKindOf(Source source) {
2047 SourceEntry sourceEntry = getReadableSourceEntryOrNull(source);
2048 if (sourceEntry == null) {
2049 return SourceKind.UNKNOWN;
2050 }
2051 return sourceEntry.kind;
2052 }
2053
2054 @override
2055 List<Source> getLibrariesContaining(Source source) {
2056 SourceEntry sourceEntry = getReadableSourceEntryOrNull(source);
2057 if (sourceEntry is DartEntry) {
2058 return sourceEntry.containingLibraries;
2059 }
2060 return Source.EMPTY_LIST;
2061 }
2062
2063 @override
2064 List<Source> getLibrariesDependingOn(Source librarySource) {
2065 List<Source> dependentLibraries = new List<Source>();
2066 MapIterator<Source, SourceEntry> iterator = _cache.iterator();
2067 while (iterator.moveNext()) {
2068 SourceEntry sourceEntry = iterator.value;
2069 if (sourceEntry.kind == SourceKind.LIBRARY) {
2070 if (_contains(
2071 (sourceEntry as DartEntry).getValue(DartEntry.EXPORTED_LIBRARIES),
2072 librarySource)) {
2073 dependentLibraries.add(iterator.key);
2074 }
2075 if (_contains(
2076 (sourceEntry as DartEntry).getValue(DartEntry.IMPORTED_LIBRARIES),
2077 librarySource)) {
2078 dependentLibraries.add(iterator.key);
2079 }
2080 }
2081 }
2082 if (dependentLibraries.isEmpty) {
2083 return Source.EMPTY_LIST;
2084 }
2085 return dependentLibraries;
2086 }
2087
2088 @override
2089 List<Source> getLibrariesReferencedFromHtml(Source htmlSource) {
2090 SourceEntry sourceEntry = getReadableSourceEntryOrNull(htmlSource);
2091 if (sourceEntry is HtmlEntry) {
2092 HtmlEntry htmlEntry = sourceEntry;
2093 return htmlEntry.getValue(HtmlEntry.REFERENCED_LIBRARIES);
2094 }
2095 return Source.EMPTY_LIST;
2096 }
2097
2098 @override
2099 LibraryElement getLibraryElement(Source source) {
2100 SourceEntry sourceEntry = getReadableSourceEntryOrNull(source);
2101 if (sourceEntry is DartEntry) {
2102 return sourceEntry.getValue(DartEntry.ELEMENT);
2103 }
2104 return null;
2105 }
2106
2107 @override
2108 LineInfo getLineInfo(Source source) {
2109 SourceEntry sourceEntry = getReadableSourceEntryOrNull(source);
2110 if (sourceEntry != null) {
2111 return sourceEntry.getValue(SourceEntry.LINE_INFO);
2112 }
2113 return null;
2114 }
2115
2116 @override
2117 int getModificationStamp(Source source) {
2118 int stamp = _contentCache.getModificationStamp(source);
2119 if (stamp != null) {
2120 return stamp;
2121 }
2122 return source.modificationStamp;
2123 }
2124
2125 @override
2126 ChangeNoticeImpl getNotice(Source source) {
2127 ChangeNoticeImpl notice = _pendingNotices[source];
2128 if (notice == null) {
2129 notice = new ChangeNoticeImpl(source);
2130 _pendingNotices[source] = notice;
2131 }
2132 return notice;
2133 }
2134
2135 @override
2136 Namespace getPublicNamespace(LibraryElement library) {
2137 // TODO(brianwilkerson) Rename this to not start with 'get'.
2138 // Note that this is not part of the API of the interface.
2139 Source source = library.definingCompilationUnit.source;
2140 DartEntry dartEntry = _getReadableDartEntry(source);
2141 if (dartEntry == null) {
2142 return null;
2143 }
2144 Namespace namespace = null;
2145 if (identical(dartEntry.getValue(DartEntry.ELEMENT), library)) {
2146 namespace = dartEntry.getValue(DartEntry.PUBLIC_NAMESPACE);
2147 }
2148 if (namespace == null) {
2149 NamespaceBuilder builder = new NamespaceBuilder();
2150 namespace = builder.createPublicNamespaceForLibrary(library);
2151 if (dartEntry == null) {
2152 AnalysisEngine.instance.logger.logError(
2153 "Could not compute the public namespace for ${library.source.fullNam e}",
2154 new CaughtException(
2155 new AnalysisException(
2156 "A Dart file became a non-Dart file: ${source.fullName}"),
2157 null));
2158 return null;
2159 }
2160 if (identical(dartEntry.getValue(DartEntry.ELEMENT), library)) {
2161 dartEntry.setValue(DartEntry.PUBLIC_NAMESPACE, namespace);
2162 }
2163 }
2164 return namespace;
2165 }
2166
2167 /**
2168 * Return the cache entry associated with the given [source], or `null` if
2169 * there is no entry associated with the source.
2170 */
2171 SourceEntry getReadableSourceEntryOrNull(Source source) => _cache.get(source);
2172
2173 @override
2174 CompilationUnit getResolvedCompilationUnit(
2175 Source unitSource, LibraryElement library) {
2176 if (library == null) {
2177 return null;
2178 }
2179 return getResolvedCompilationUnit2(unitSource, library.source);
2180 }
2181
2182 @override
2183 CompilationUnit getResolvedCompilationUnit2(
2184 Source unitSource, Source librarySource) {
2185 SourceEntry sourceEntry = getReadableSourceEntryOrNull(unitSource);
2186 if (sourceEntry is DartEntry) {
2187 return sourceEntry.getValueInLibrary(
2188 DartEntry.RESOLVED_UNIT, librarySource);
2189 }
2190 return null;
2191 }
2192
2193 @override
2194 @deprecated
2195 ht.HtmlUnit getResolvedHtmlUnit(Source htmlSource) {
2196 SourceEntry sourceEntry = getReadableSourceEntryOrNull(htmlSource);
2197 if (sourceEntry is HtmlEntry) {
2198 HtmlEntry htmlEntry = sourceEntry;
2199 return htmlEntry.getValue(HtmlEntry.RESOLVED_UNIT);
2200 }
2201 return null;
2202 }
2203
2204 @override
2205 Object getResult(AnalysisTarget target, ResultDescriptor result) {
2206 return result.defaultValue;
2207 }
2208
2209 @override
2210 List<Source> getSourcesWithFullName(String path) {
2211 List<Source> sources = <Source>[];
2212 MapIterator<Source, SourceEntry> iterator = _cache.iterator();
2213 while (iterator.moveNext()) {
2214 if (iterator.key.fullName == path) {
2215 sources.add(iterator.key);
2216 }
2217 }
2218 return sources;
2219 }
2220
2221 @override
2222 bool handleContentsChanged(
2223 Source source, String originalContents, String newContents, bool notify) {
2224 SourceEntry sourceEntry = _cache.get(source);
2225 if (sourceEntry == null) {
2226 return false;
2227 }
2228 bool changed = newContents != originalContents;
2229 if (newContents != null) {
2230 if (changed) {
2231 _incrementalAnalysisCache =
2232 IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
2233 if (!analysisOptions.incremental ||
2234 !_tryPoorMansIncrementalResolution(source, newContents)) {
2235 _sourceChanged(source);
2236 }
2237 sourceEntry.modificationTime =
2238 _contentCache.getModificationStamp(source);
2239 sourceEntry.setValue(SourceEntry.CONTENT, newContents);
2240 } else {
2241 sourceEntry.modificationTime =
2242 _contentCache.getModificationStamp(source);
2243 }
2244 } else if (originalContents != null) {
2245 _incrementalAnalysisCache =
2246 IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
2247 // We are removing the overlay for the file, check if the file's
2248 // contents is the same as it was in the overlay.
2249 try {
2250 TimestampedData<String> fileContents = getContents(source);
2251 newContents = fileContents.data;
2252 sourceEntry.modificationTime = fileContents.modificationTime;
2253 if (newContents == originalContents) {
2254 sourceEntry.setValue(SourceEntry.CONTENT, newContents);
2255 changed = false;
2256 }
2257 } catch (e) {}
2258 // If not the same content (e.g. the file is being closed without save),
2259 // then force analysis.
2260 if (changed) {
2261 if (!analysisOptions.incremental ||
2262 !_tryPoorMansIncrementalResolution(source, newContents)) {
2263 _sourceChanged(source);
2264 }
2265 }
2266 }
2267 if (notify && changed) {
2268 _onSourcesChangedController
2269 .add(new SourcesChangedEvent.changedContent(source, newContents));
2270 }
2271 return changed;
2272 }
2273
2274 @override
2275 void invalidateLibraryHints(Source librarySource) {
2276 SourceEntry sourceEntry = _cache.get(librarySource);
2277 if (sourceEntry is! DartEntry) {
2278 return;
2279 }
2280 DartEntry dartEntry = sourceEntry;
2281 // Prepare sources to invalidate hints in.
2282 List<Source> sources = <Source>[librarySource];
2283 sources.addAll(dartEntry.getValue(DartEntry.INCLUDED_PARTS));
2284 // Invalidate hints and lints.
2285 for (Source source in sources) {
2286 DartEntry dartEntry = _cache.get(source);
2287 if (dartEntry.getStateInLibrary(DartEntry.HINTS, librarySource) ==
2288 CacheState.VALID) {
2289 dartEntry.setStateInLibrary(
2290 DartEntry.HINTS, librarySource, CacheState.INVALID);
2291 }
2292 if (dartEntry.getStateInLibrary(DartEntry.LINTS, librarySource) ==
2293 CacheState.VALID) {
2294 dartEntry.setStateInLibrary(
2295 DartEntry.LINTS, librarySource, CacheState.INVALID);
2296 }
2297 }
2298 }
2299
2300 @override
2301 bool isClientLibrary(Source librarySource) {
2302 SourceEntry sourceEntry = _getReadableSourceEntry(librarySource);
2303 if (sourceEntry is DartEntry) {
2304 DartEntry dartEntry = sourceEntry;
2305 return dartEntry.getValue(DartEntry.IS_CLIENT) &&
2306 dartEntry.getValue(DartEntry.IS_LAUNCHABLE);
2307 }
2308 return false;
2309 }
2310
2311 @override
2312 bool isServerLibrary(Source librarySource) {
2313 SourceEntry sourceEntry = _getReadableSourceEntry(librarySource);
2314 if (sourceEntry is DartEntry) {
2315 DartEntry dartEntry = sourceEntry;
2316 return !dartEntry.getValue(DartEntry.IS_CLIENT) &&
2317 dartEntry.getValue(DartEntry.IS_LAUNCHABLE);
2318 }
2319 return false;
2320 }
2321
2322 @override
2323 Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor) {
2324 throw new NotImplementedException('In not task-based AnalysisContext.');
2325 }
2326
2327 @override
2328 CompilationUnit parseCompilationUnit(Source source) =>
2329 _getDartParseData2(source, DartEntry.PARSED_UNIT, null);
2330
2331 @override
2332 Document parseHtmlDocument(Source source) {
2333 return null;
2334 }
2335
2336 @override
2337 @deprecated
2338 ht.HtmlUnit parseHtmlUnit(Source source) =>
2339 _getHtmlParseData(source, HtmlEntry.PARSED_UNIT, null);
2340
2341 @override
2342 AnalysisResult performAnalysisTask() {
2343 if (_TRACE_PERFORM_TASK) {
2344 print("----------------------------------------");
2345 }
2346 return PerformanceStatistics.performAnaysis.makeCurrentWhile(() {
2347 int getStart = JavaSystem.currentTimeMillis();
2348 AnalysisTask task = PerformanceStatistics.nextTask
2349 .makeCurrentWhile(() => nextAnalysisTask);
2350 int getEnd = JavaSystem.currentTimeMillis();
2351 if (task == null) {
2352 _validateLastIncrementalResolutionResult();
2353 if (_performAnalysisTaskStopwatch != null) {
2354 AnalysisEngine.instance.instrumentationService.logPerformance(
2355 AnalysisPerformanceKind.FULL,
2356 _performAnalysisTaskStopwatch,
2357 'context_id=$_id');
2358 _performAnalysisTaskStopwatch = null;
2359 }
2360 return new AnalysisResult(
2361 _getChangeNotices(true), getEnd - getStart, null, -1);
2362 }
2363 if (_performAnalysisTaskStopwatch == null) {
2364 _performAnalysisTaskStopwatch = new Stopwatch()..start();
2365 }
2366 String taskDescription = task.toString();
2367 _notifyAboutToPerformTask(taskDescription);
2368 if (_TRACE_PERFORM_TASK) {
2369 print(taskDescription);
2370 }
2371 int performStart = JavaSystem.currentTimeMillis();
2372 try {
2373 task.perform(_resultRecorder);
2374 } on ObsoleteSourceAnalysisException catch (exception, stackTrace) {
2375 AnalysisEngine.instance.logger.logInformation(
2376 "Could not perform analysis task: $taskDescription",
2377 new CaughtException(exception, stackTrace));
2378 } on AnalysisException catch (exception, stackTrace) {
2379 if (exception.cause is! JavaIOException) {
2380 AnalysisEngine.instance.logger.logError(
2381 "Internal error while performing the task: $task",
2382 new CaughtException(exception, stackTrace));
2383 }
2384 }
2385 int performEnd = JavaSystem.currentTimeMillis();
2386 List<ChangeNotice> notices = _getChangeNotices(false);
2387 int noticeCount = notices.length;
2388 for (int i = 0; i < noticeCount; i++) {
2389 ChangeNotice notice = notices[i];
2390 Source source = notice.source;
2391 // TODO(brianwilkerson) Figure out whether the compilation unit is
2392 // always resolved, or whether we need to decide whether to invoke the
2393 // "parsed" or "resolved" method. This might be better done when
2394 // recording task results in order to reduce the chance of errors.
2395 // if (notice.getCompilationUnit() != null) {
2396 // notifyResolvedDart(source, notice.getCompilationUnit());
2397 // } else if (notice.getHtmlUnit() != null) {
2398 // notifyResolvedHtml(source, notice.getHtmlUnit());
2399 // }
2400 _notifyErrors(source, notice.errors, notice.lineInfo);
2401 }
2402 return new AnalysisResult(notices, getEnd - getStart,
2403 task.runtimeType.toString(), performEnd - performStart);
2404 });
2405 }
2406
2407 @override
2408 void recordLibraryElements(Map<Source, LibraryElement> elementMap) {
2409 Source htmlSource = _sourceFactory.forUri(DartSdk.DART_HTML);
2410 elementMap.forEach((Source librarySource, LibraryElement library) {
2411 //
2412 // Cache the element in the library's info.
2413 //
2414 DartEntry dartEntry = _getReadableDartEntry(librarySource);
2415 if (dartEntry != null) {
2416 _recordElementData(dartEntry, library, library.source, htmlSource);
2417 dartEntry.setState(SourceEntry.CONTENT, CacheState.FLUSHED);
2418 dartEntry.setValue(SourceEntry.LINE_INFO, new LineInfo(<int>[0]));
2419 // DartEntry.ELEMENT - set in recordElementData
2420 dartEntry.setValue(DartEntry.EXPORTED_LIBRARIES, Source.EMPTY_LIST);
2421 dartEntry.setValue(DartEntry.IMPORTED_LIBRARIES, Source.EMPTY_LIST);
2422 dartEntry.setValue(DartEntry.INCLUDED_PARTS, Source.EMPTY_LIST);
2423 // DartEntry.IS_CLIENT - set in recordElementData
2424 // DartEntry.IS_LAUNCHABLE - set in recordElementData
2425 dartEntry.setValue(DartEntry.PARSE_ERRORS, AnalysisError.NO_ERRORS);
2426 dartEntry.setState(DartEntry.PARSED_UNIT, CacheState.FLUSHED);
2427 dartEntry.setState(DartEntry.PUBLIC_NAMESPACE, CacheState.FLUSHED);
2428 dartEntry.setValue(DartEntry.SCAN_ERRORS, AnalysisError.NO_ERRORS);
2429 dartEntry.setValue(DartEntry.SOURCE_KIND, SourceKind.LIBRARY);
2430 dartEntry.setState(DartEntry.TOKEN_STREAM, CacheState.FLUSHED);
2431 dartEntry.setValueInLibrary(DartEntry.RESOLUTION_ERRORS, librarySource,
2432 AnalysisError.NO_ERRORS);
2433 dartEntry.setStateInLibrary(
2434 DartEntry.RESOLVED_UNIT, librarySource, CacheState.FLUSHED);
2435 dartEntry.setValueInLibrary(DartEntry.VERIFICATION_ERRORS,
2436 librarySource, AnalysisError.NO_ERRORS);
2437 dartEntry.setValueInLibrary(
2438 DartEntry.HINTS, librarySource, AnalysisError.NO_ERRORS);
2439 dartEntry.setValueInLibrary(
2440 DartEntry.LINTS, librarySource, AnalysisError.NO_ERRORS);
2441 }
2442 });
2443 }
2444
2445 /**
2446 * Record the results produced by performing a [task] and return the cache
2447 * entry associated with the results.
2448 */
2449 DartEntry recordResolveDartLibraryCycleTaskResults(
2450 ResolveDartLibraryCycleTask task) {
2451 LibraryResolver2 resolver = task.libraryResolver;
2452 CaughtException thrownException = task.exception;
2453 Source unitSource = task.unitSource;
2454 DartEntry unitEntry = _getReadableDartEntry(unitSource);
2455 if (resolver != null) {
2456 //
2457 // The resolver should only be null if an exception was thrown before (or
2458 // while) it was being created.
2459 //
2460 List<ResolvableLibrary> resolvedLibraries = resolver.resolvedLibraries;
2461 if (resolvedLibraries == null) {
2462 //
2463 // The resolved libraries should only be null if an exception was thrown
2464 // during resolution.
2465 //
2466 if (thrownException == null) {
2467 var message = "In recordResolveDartLibraryCycleTaskResults, "
2468 "resolvedLibraries was null and there was no thrown exception";
2469 unitEntry.recordResolutionError(
2470 new CaughtException(new AnalysisException(message), null));
2471 } else {
2472 unitEntry.recordResolutionError(thrownException);
2473 }
2474 _removeFromCache(unitSource);
2475 if (thrownException != null) {
2476 throw new AnalysisException('<rethrow>', thrownException);
2477 }
2478 return unitEntry;
2479 }
2480 Source htmlSource = sourceFactory.forUri(DartSdk.DART_HTML);
2481 RecordingErrorListener errorListener = resolver.errorListener;
2482 for (ResolvableLibrary library in resolvedLibraries) {
2483 Source librarySource = library.librarySource;
2484 for (Source source in library.compilationUnitSources) {
2485 CompilationUnit unit = library.getAST(source);
2486 List<AnalysisError> errors = errorListener.getErrorsForSource(source);
2487 LineInfo lineInfo = getLineInfo(source);
2488 DartEntry dartEntry = _cache.get(source);
2489 if (thrownException == null) {
2490 dartEntry.setState(DartEntry.PARSED_UNIT, CacheState.FLUSHED);
2491 dartEntry.setValueInLibrary(
2492 DartEntry.RESOLVED_UNIT, librarySource, unit);
2493 dartEntry.setValueInLibrary(
2494 DartEntry.RESOLUTION_ERRORS, librarySource, errors);
2495 if (source == librarySource) {
2496 _recordElementData(
2497 dartEntry, library.libraryElement, librarySource, htmlSource);
2498 }
2499 _cache.storedAst(source);
2500 } else {
2501 dartEntry.recordResolutionErrorInLibrary(
2502 librarySource, thrownException);
2503 }
2504 if (source != librarySource) {
2505 _workManager.add(source, SourcePriority.PRIORITY_PART);
2506 }
2507 ChangeNoticeImpl notice = getNotice(source);
2508 notice.resolvedDartUnit = unit;
2509 notice.setErrors(dartEntry.allErrors, lineInfo);
2510 }
2511 }
2512 }
2513 if (thrownException != null) {
2514 throw new AnalysisException('<rethrow>', thrownException);
2515 }
2516 return unitEntry;
2517 }
2518
2519 /**
2520 * Record the results produced by performing a [task] and return the cache
2521 * entry associated with the results.
2522 */
2523 DartEntry recordResolveDartLibraryTaskResults(ResolveDartLibraryTask task) {
2524 LibraryResolver resolver = task.libraryResolver;
2525 CaughtException thrownException = task.exception;
2526 Source unitSource = task.unitSource;
2527 DartEntry unitEntry = _getReadableDartEntry(unitSource);
2528 if (resolver != null) {
2529 //
2530 // The resolver should only be null if an exception was thrown before (or
2531 // while) it was being created.
2532 //
2533 Set<Library> resolvedLibraries = resolver.resolvedLibraries;
2534 if (resolvedLibraries == null) {
2535 //
2536 // The resolved libraries should only be null if an exception was thrown
2537 // during resolution.
2538 //
2539 if (thrownException == null) {
2540 String message = "In recordResolveDartLibraryTaskResults, "
2541 "resolvedLibraries was null and there was no thrown exception";
2542 unitEntry.recordResolutionError(
2543 new CaughtException(new AnalysisException(message), null));
2544 } else {
2545 unitEntry.recordResolutionError(thrownException);
2546 }
2547 _removeFromCache(unitSource);
2548 if (thrownException != null) {
2549 throw new AnalysisException('<rethrow>', thrownException);
2550 }
2551 return unitEntry;
2552 }
2553 Source htmlSource = sourceFactory.forUri(DartSdk.DART_HTML);
2554 RecordingErrorListener errorListener = resolver.errorListener;
2555 for (Library library in resolvedLibraries) {
2556 Source librarySource = library.librarySource;
2557 for (Source source in library.compilationUnitSources) {
2558 CompilationUnit unit = library.getAST(source);
2559 List<AnalysisError> errors = errorListener.getErrorsForSource(source);
2560 LineInfo lineInfo = getLineInfo(source);
2561 DartEntry dartEntry = _cache.get(source);
2562 if (thrownException == null) {
2563 dartEntry.setValue(SourceEntry.LINE_INFO, lineInfo);
2564 dartEntry.setState(DartEntry.PARSED_UNIT, CacheState.FLUSHED);
2565 dartEntry.setValueInLibrary(
2566 DartEntry.RESOLVED_UNIT, librarySource, unit);
2567 dartEntry.setValueInLibrary(
2568 DartEntry.RESOLUTION_ERRORS, librarySource, errors);
2569 if (source == librarySource) {
2570 _recordElementData(
2571 dartEntry, library.libraryElement, librarySource, htmlSource);
2572 }
2573 _cache.storedAst(source);
2574 } else {
2575 dartEntry.recordResolutionErrorInLibrary(
2576 librarySource, thrownException);
2577 _removeFromCache(source);
2578 }
2579 if (source != librarySource) {
2580 _workManager.add(source, SourcePriority.PRIORITY_PART);
2581 }
2582 ChangeNoticeImpl notice = getNotice(source);
2583 notice.resolvedDartUnit = unit;
2584 notice.setErrors(dartEntry.allErrors, lineInfo);
2585 }
2586 }
2587 }
2588 if (thrownException != null) {
2589 throw new AnalysisException('<rethrow>', thrownException);
2590 }
2591 return unitEntry;
2592 }
2593
2594 @override
2595 void removeListener(AnalysisListener listener) {
2596 _listeners.remove(listener);
2597 }
2598
2599 @override
2600 CompilationUnit resolveCompilationUnit(
2601 Source unitSource, LibraryElement library) {
2602 if (library == null) {
2603 return null;
2604 }
2605 return resolveCompilationUnit2(unitSource, library.source);
2606 }
2607
2608 @override
2609 CompilationUnit resolveCompilationUnit2(
2610 Source unitSource, Source librarySource) =>
2611 _getDartResolutionData2(
2612 unitSource, librarySource, DartEntry.RESOLVED_UNIT, null);
2613
2614 @override
2615 @deprecated
2616 ht.HtmlUnit resolveHtmlUnit(Source htmlSource) {
2617 computeHtmlElement(htmlSource);
2618 return parseHtmlUnit(htmlSource);
2619 }
2620
2621 @override
2622 void setChangedContents(Source source, String contents, int offset,
2623 int oldLength, int newLength) {
2624 if (_contentRangeChanged(source, contents, offset, oldLength, newLength)) {
2625 _onSourcesChangedController.add(new SourcesChangedEvent.changedRange(
2626 source, contents, offset, oldLength, newLength));
2627 }
2628 }
2629
2630 @override
2631 void setContents(Source source, String contents) {
2632 _contentsChanged(source, contents, true);
2633 }
2634
2635 @override
2636 bool shouldErrorsBeAnalyzed(Source source, Object entry) {
2637 DartEntry dartEntry = entry;
2638 if (source.isInSystemLibrary) {
2639 return _generateSdkErrors;
2640 } else if (!dartEntry.explicitlyAdded) {
2641 return _generateImplicitErrors;
2642 } else {
2643 return true;
2644 }
2645 }
2646
2647 @override
2648 void test_flushAstStructures(Source source) {
2649 DartEntry dartEntry = getReadableSourceEntryOrNull(source);
2650 dartEntry.flushAstStructures();
2651 }
2652
2653 @override
2654 bool validateCacheConsistency() {
2655 int consistencyCheckStart = JavaSystem.nanoTime();
2656 List<Source> changedSources = new List<Source>();
2657 List<Source> missingSources = new List<Source>();
2658 MapIterator<Source, SourceEntry> iterator = _cache.iterator();
2659 while (iterator.moveNext()) {
2660 Source source = iterator.key;
2661 SourceEntry sourceEntry = iterator.value;
2662 int sourceTime = getModificationStamp(source);
2663 if (sourceTime != sourceEntry.modificationTime) {
2664 changedSources.add(source);
2665 }
2666 if (sourceEntry.exception != null) {
2667 if (!exists(source)) {
2668 missingSources.add(source);
2669 }
2670 }
2671 }
2672 int count = changedSources.length;
2673 for (int i = 0; i < count; i++) {
2674 _sourceChanged(changedSources[i]);
2675 }
2676 int removalCount = 0;
2677 for (Source source in missingSources) {
2678 if (getLibrariesContaining(source).isEmpty &&
2679 getLibrariesDependingOn(source).isEmpty) {
2680 _removeFromCache(source);
2681 removalCount++;
2682 }
2683 }
2684 int consistencyCheckEnd = JavaSystem.nanoTime();
2685 if (changedSources.length > 0 || missingSources.length > 0) {
2686 StringBuffer buffer = new StringBuffer();
2687 buffer.write("Consistency check took ");
2688 buffer.write((consistencyCheckEnd - consistencyCheckStart) / 1000000.0);
2689 buffer.writeln(" ms and found");
2690 buffer.write(" ");
2691 buffer.write(changedSources.length);
2692 buffer.writeln(" inconsistent entries");
2693 buffer.write(" ");
2694 buffer.write(missingSources.length);
2695 buffer.write(" missing sources (");
2696 buffer.write(removalCount);
2697 buffer.writeln(" removed");
2698 for (Source source in missingSources) {
2699 buffer.write(" ");
2700 buffer.writeln(source.fullName);
2701 }
2702 _logInformation(buffer.toString());
2703 }
2704 return changedSources.length > 0;
2705 }
2706
2707 @deprecated
2708 @override
2709 void visitCacheItems(void callback(Source source, SourceEntry dartEntry,
2710 DataDescriptor rowDesc, CacheState state)) {
2711 bool hintsEnabled = _options.hint;
2712 bool lintsEnabled = _options.lint;
2713 MapIterator<Source, SourceEntry> iterator = _cache.iterator();
2714 while (iterator.moveNext()) {
2715 Source source = iterator.key;
2716 SourceEntry sourceEntry = iterator.value;
2717 for (DataDescriptor descriptor in sourceEntry.descriptors) {
2718 if (descriptor == DartEntry.SOURCE_KIND) {
2719 // The source kind is always valid, so the state isn't interesting.
2720 continue;
2721 } else if (descriptor == DartEntry.CONTAINING_LIBRARIES) {
2722 // The list of containing libraries is always valid, so the state
2723 // isn't interesting.
2724 continue;
2725 } else if (descriptor == DartEntry.PUBLIC_NAMESPACE) {
2726 // The public namespace isn't computed by performAnalysisTask()
2727 // and therefore isn't interesting.
2728 continue;
2729 } else if (descriptor == HtmlEntry.HINTS) {
2730 // We are not currently recording any hints related to HTML.
2731 continue;
2732 }
2733 callback(
2734 source, sourceEntry, descriptor, sourceEntry.getState(descriptor));
2735 }
2736 if (sourceEntry is DartEntry) {
2737 // get library-specific values
2738 List<Source> librarySources = getLibrariesContaining(source);
2739 for (Source librarySource in librarySources) {
2740 for (DataDescriptor descriptor in sourceEntry.libraryDescriptors) {
2741 if (descriptor == DartEntry.BUILT_ELEMENT ||
2742 descriptor == DartEntry.BUILT_UNIT) {
2743 // These values are not currently being computed, so their state
2744 // is not interesting.
2745 continue;
2746 } else if (!sourceEntry.explicitlyAdded &&
2747 !_generateImplicitErrors &&
2748 (descriptor == DartEntry.VERIFICATION_ERRORS ||
2749 descriptor == DartEntry.HINTS ||
2750 descriptor == DartEntry.LINTS)) {
2751 continue;
2752 } else if (source.isInSystemLibrary &&
2753 !_generateSdkErrors &&
2754 (descriptor == DartEntry.VERIFICATION_ERRORS ||
2755 descriptor == DartEntry.HINTS ||
2756 descriptor == DartEntry.LINTS)) {
2757 continue;
2758 } else if (!hintsEnabled && descriptor == DartEntry.HINTS) {
2759 continue;
2760 } else if (!lintsEnabled && descriptor == DartEntry.LINTS) {
2761 continue;
2762 }
2763 callback(librarySource, sourceEntry, descriptor,
2764 sourceEntry.getStateInLibrary(descriptor, librarySource));
2765 }
2766 }
2767 }
2768 }
2769 }
2770
2771 @override
2772 void visitContentCache(ContentCacheVisitor visitor) {
2773 _contentCache.accept(visitor);
2774 }
2775
2776 /**
2777 * Record that we have accessed the AST structure associated with the given
2778 * [source]. At the moment, there is no differentiation between the parsed and
2779 * resolved forms of the AST.
2780 */
2781 void _accessedAst(Source source) {
2782 _cache.accessedAst(source);
2783 }
2784
2785 /**
2786 * Add all of the sources contained in the given source [container] to the
2787 * given list of [sources].
2788 */
2789 void _addSourcesInContainer(List<Source> sources, SourceContainer container) {
2790 MapIterator<Source, SourceEntry> iterator = _cache.iterator();
2791 while (iterator.moveNext()) {
2792 Source source = iterator.key;
2793 if (container.contains(source)) {
2794 sources.add(source);
2795 }
2796 }
2797 }
2798
2799 /**
2800 * Given the [unitSource] of a Dart file and the [librarySource] of the
2801 * library that contains it, return a cache entry in which the state of the
2802 * data represented by the given [descriptor] is either [CacheState.VALID] or
2803 * [CacheState.ERROR]. This method assumes that the data can be produced by
2804 * generating hints for the library if the data is not already cached. The
2805 * [dartEntry] is the cache entry associated with the Dart file.
2806 *
2807 * Throws an [AnalysisException] if data could not be returned because the
2808 * source could not be parsed.
2809 */
2810 DartEntry _cacheDartHintData(Source unitSource, Source librarySource,
2811 DartEntry dartEntry, DataDescriptor descriptor) {
2812 //
2813 // Check to see whether we already have the information being requested.
2814 //
2815 CacheState state = dartEntry.getStateInLibrary(descriptor, librarySource);
2816 while (state != CacheState.ERROR && state != CacheState.VALID) {
2817 //
2818 // If not, compute the information.
2819 // Unless the modification date of the source continues to change,
2820 // this loop will eventually terminate.
2821 //
2822 DartEntry libraryEntry = _getReadableDartEntry(librarySource);
2823 libraryEntry = _cacheDartResolutionData(
2824 librarySource, librarySource, libraryEntry, DartEntry.ELEMENT);
2825 LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT);
2826 CompilationUnitElement definingUnit =
2827 libraryElement.definingCompilationUnit;
2828 List<CompilationUnitElement> parts = libraryElement.parts;
2829 List<TimestampedData<CompilationUnit>> units =
2830 new List<TimestampedData<CompilationUnit>>(parts.length + 1);
2831 units[0] = _getResolvedUnit(definingUnit, librarySource);
2832 if (units[0] == null) {
2833 Source source = definingUnit.source;
2834 units[0] = new TimestampedData<CompilationUnit>(
2835 getModificationStamp(source),
2836 resolveCompilationUnit(source, libraryElement));
2837 }
2838 for (int i = 0; i < parts.length; i++) {
2839 units[i + 1] = _getResolvedUnit(parts[i], librarySource);
2840 if (units[i + 1] == null) {
2841 Source source = parts[i].source;
2842 units[i + 1] = new TimestampedData<CompilationUnit>(
2843 getModificationStamp(source),
2844 resolveCompilationUnit(source, libraryElement));
2845 }
2846 }
2847 dartEntry = new GenerateDartHintsTask(
2848 this, units, getLibraryElement(librarySource))
2849 .perform(_resultRecorder) as DartEntry;
2850 state = dartEntry.getStateInLibrary(descriptor, librarySource);
2851 }
2852 return dartEntry;
2853 }
2854
2855 /**
2856 * Given a source for a Dart file and the library that contains it, return a
2857 * cache entry in which the state of the data represented by the given
2858 * descriptor is either [CacheState.VALID] or [CacheState.ERROR]. This method
2859 * assumes that the data can be produced by generating lints for the library
2860 * if the data is not already cached.
2861 *
2862 * <b>Note:</b> This method cannot be used in an async environment.
2863 */
2864 DartEntry _cacheDartLintData(Source unitSource, Source librarySource,
2865 DartEntry dartEntry, DataDescriptor descriptor) {
2866 //
2867 // Check to see whether we already have the information being requested.
2868 //
2869 CacheState state = dartEntry.getStateInLibrary(descriptor, librarySource);
2870 while (state != CacheState.ERROR && state != CacheState.VALID) {
2871 //
2872 // If not, compute the information.
2873 // Unless the modification date of the source continues to change,
2874 // this loop will eventually terminate.
2875 //
2876 DartEntry libraryEntry = _getReadableDartEntry(librarySource);
2877 libraryEntry = _cacheDartResolutionData(
2878 librarySource, librarySource, libraryEntry, DartEntry.ELEMENT);
2879 LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT);
2880 CompilationUnitElement definingUnit =
2881 libraryElement.definingCompilationUnit;
2882 List<CompilationUnitElement> parts = libraryElement.parts;
2883 List<TimestampedData<CompilationUnit>> units =
2884 new List<TimestampedData<CompilationUnit>>(parts.length + 1);
2885 units[0] = _getResolvedUnit(definingUnit, librarySource);
2886 if (units[0] == null) {
2887 Source source = definingUnit.source;
2888 units[0] = new TimestampedData<CompilationUnit>(
2889 getModificationStamp(source),
2890 resolveCompilationUnit(source, libraryElement));
2891 }
2892 for (int i = 0; i < parts.length; i++) {
2893 units[i + 1] = _getResolvedUnit(parts[i], librarySource);
2894 if (units[i + 1] == null) {
2895 Source source = parts[i].source;
2896 units[i + 1] = new TimestampedData<CompilationUnit>(
2897 getModificationStamp(source),
2898 resolveCompilationUnit(source, libraryElement));
2899 }
2900 }
2901 //TODO(pquitslund): revisit if we need all units or whether one will do
2902 dartEntry = new GenerateDartLintsTask(
2903 this, units, getLibraryElement(librarySource))
2904 .perform(_resultRecorder) as DartEntry;
2905 state = dartEntry.getStateInLibrary(descriptor, librarySource);
2906 }
2907 return dartEntry;
2908 }
2909
2910 /**
2911 * Given a source for a Dart file, return a cache entry in which the state of
2912 * the data represented by the given descriptor is either [CacheState.VALID]
2913 * or [CacheState.ERROR]. This method assumes that the data can be produced by
2914 * parsing the source if it is not already cached.
2915 *
2916 * <b>Note:</b> This method cannot be used in an async environment.
2917 */
2918 DartEntry _cacheDartParseData(
2919 Source source, DartEntry dartEntry, DataDescriptor descriptor) {
2920 if (identical(descriptor, DartEntry.PARSED_UNIT)) {
2921 if (dartEntry.hasResolvableCompilationUnit) {
2922 return dartEntry;
2923 }
2924 }
2925 //
2926 // Check to see whether we already have the information being requested.
2927 //
2928 CacheState state = dartEntry.getState(descriptor);
2929 while (state != CacheState.ERROR && state != CacheState.VALID) {
2930 //
2931 // If not, compute the information. Unless the modification date of the
2932 // source continues to change, this loop will eventually terminate.
2933 //
2934 dartEntry = _cacheDartScanData(source, dartEntry, DartEntry.TOKEN_STREAM);
2935 dartEntry = new ParseDartTask(
2936 this,
2937 source,
2938 dartEntry.getValue(DartEntry.TOKEN_STREAM),
2939 dartEntry.getValue(SourceEntry.LINE_INFO))
2940 .perform(_resultRecorder) as DartEntry;
2941 state = dartEntry.getState(descriptor);
2942 }
2943 return dartEntry;
2944 }
2945
2946 /**
2947 * Given a source for a Dart file and the library that contains it, return a
2948 * cache entry in which the state of the data represented by the given
2949 * descriptor is either [CacheState.VALID] or [CacheState.ERROR]. This method
2950 * assumes that the data can be produced by resolving the source in the
2951 * context of the library if it is not already cached.
2952 *
2953 * <b>Note:</b> This method cannot be used in an async environment.
2954 */
2955 DartEntry _cacheDartResolutionData(Source unitSource, Source librarySource,
2956 DartEntry dartEntry, DataDescriptor descriptor) {
2957 //
2958 // Check to see whether we already have the information being requested.
2959 //
2960 CacheState state = (identical(descriptor, DartEntry.ELEMENT))
2961 ? dartEntry.getState(descriptor)
2962 : dartEntry.getStateInLibrary(descriptor, librarySource);
2963 while (state != CacheState.ERROR && state != CacheState.VALID) {
2964 //
2965 // If not, compute the information. Unless the modification date of the
2966 // source continues to change, this loop will eventually terminate.
2967 //
2968 // TODO(brianwilkerson) As an optimization, if we already have the
2969 // element model for the library we can use ResolveDartUnitTask to produce
2970 // the resolved AST structure much faster.
2971 dartEntry = new ResolveDartLibraryTask(this, unitSource, librarySource)
2972 .perform(_resultRecorder) as DartEntry;
2973 state = (identical(descriptor, DartEntry.ELEMENT))
2974 ? dartEntry.getState(descriptor)
2975 : dartEntry.getStateInLibrary(descriptor, librarySource);
2976 }
2977 return dartEntry;
2978 }
2979
2980 /**
2981 * Given a source for a Dart file, return a cache entry in which the state of
2982 * the data represented by the given descriptor is either [CacheState.VALID]
2983 * or [CacheState.ERROR]. This method assumes that the data can be produced by
2984 * scanning the source if it is not already cached.
2985 *
2986 * <b>Note:</b> This method cannot be used in an async environment.
2987 */
2988 DartEntry _cacheDartScanData(
2989 Source source, DartEntry dartEntry, DataDescriptor descriptor) {
2990 //
2991 // Check to see whether we already have the information being requested.
2992 //
2993 CacheState state = dartEntry.getState(descriptor);
2994 while (state != CacheState.ERROR && state != CacheState.VALID) {
2995 //
2996 // If not, compute the information. Unless the modification date of the
2997 // source continues to change, this loop will eventually terminate.
2998 //
2999 try {
3000 if (dartEntry.getState(SourceEntry.CONTENT) != CacheState.VALID) {
3001 dartEntry = new GetContentTask(this, source).perform(_resultRecorder)
3002 as DartEntry;
3003 }
3004 dartEntry = new ScanDartTask(
3005 this, source, dartEntry.getValue(SourceEntry.CONTENT))
3006 .perform(_resultRecorder) as DartEntry;
3007 } on AnalysisException catch (exception) {
3008 throw exception;
3009 } catch (exception, stackTrace) {
3010 throw new AnalysisException(
3011 "Exception", new CaughtException(exception, stackTrace));
3012 }
3013 state = dartEntry.getState(descriptor);
3014 }
3015 return dartEntry;
3016 }
3017
3018 /**
3019 * Given a source for a Dart file and the library that contains it, return a
3020 * cache entry in which the state of the data represented by the given
3021 * descriptor is either [CacheState.VALID] or [CacheState.ERROR]. This method
3022 * assumes that the data can be produced by verifying the source in the given
3023 * library if the data is not already cached.
3024 *
3025 * <b>Note:</b> This method cannot be used in an async environment.
3026 */
3027 DartEntry _cacheDartVerificationData(Source unitSource, Source librarySource,
3028 DartEntry dartEntry, DataDescriptor descriptor) {
3029 //
3030 // Check to see whether we already have the information being requested.
3031 //
3032 CacheState state = dartEntry.getStateInLibrary(descriptor, librarySource);
3033 while (state != CacheState.ERROR && state != CacheState.VALID) {
3034 //
3035 // If not, compute the information. Unless the modification date of the
3036 // source continues to change, this loop will eventually terminate.
3037 //
3038 LibraryElement library = computeLibraryElement(librarySource);
3039 CompilationUnit unit = resolveCompilationUnit(unitSource, library);
3040 if (unit == null) {
3041 throw new AnalysisException(
3042 "Could not resolve compilation unit ${unitSource.fullName} in ${libr arySource.fullName}");
3043 }
3044 dartEntry = new GenerateDartErrorsTask(this, unitSource, unit, library)
3045 .perform(_resultRecorder) as DartEntry;
3046 state = dartEntry.getStateInLibrary(descriptor, librarySource);
3047 }
3048 return dartEntry;
3049 }
3050
3051 /**
3052 * Given a source for an HTML file, return a cache entry in which all of the
3053 * data represented by the state of the given descriptors is either
3054 * [CacheState.VALID] or [CacheState.ERROR]. This method assumes that the data
3055 * can be produced by parsing the source if it is not already cached.
3056 *
3057 * <b>Note:</b> This method cannot be used in an async environment.
3058 */
3059 HtmlEntry _cacheHtmlParseData(
3060 Source source, HtmlEntry htmlEntry, DataDescriptor descriptor) {
3061 if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
3062 ht.HtmlUnit unit = htmlEntry.anyParsedUnit;
3063 if (unit != null) {
3064 return htmlEntry;
3065 }
3066 }
3067 //
3068 // Check to see whether we already have the information being requested.
3069 //
3070 CacheState state = htmlEntry.getState(descriptor);
3071 while (state != CacheState.ERROR && state != CacheState.VALID) {
3072 //
3073 // If not, compute the information. Unless the modification date of the
3074 // source continues to change, this loop will eventually terminate.
3075 //
3076 try {
3077 if (htmlEntry.getState(SourceEntry.CONTENT) != CacheState.VALID) {
3078 htmlEntry = new GetContentTask(this, source).perform(_resultRecorder)
3079 as HtmlEntry;
3080 }
3081 htmlEntry = new ParseHtmlTask(
3082 this, source, htmlEntry.getValue(SourceEntry.CONTENT))
3083 .perform(_resultRecorder) as HtmlEntry;
3084 } on AnalysisException catch (exception) {
3085 throw exception;
3086 } catch (exception, stackTrace) {
3087 throw new AnalysisException(
3088 "Exception", new CaughtException(exception, stackTrace));
3089 }
3090 state = htmlEntry.getState(descriptor);
3091 }
3092 return htmlEntry;
3093 }
3094
3095 /**
3096 * Given a source for an HTML file, return a cache entry in which the state of
3097 * the data represented by the given descriptor is either [CacheState.VALID]
3098 * or [CacheState.ERROR]. This method assumes that the data can be produced by
3099 * resolving the source if it is not already cached.
3100 *
3101 * <b>Note:</b> This method cannot be used in an async environment.
3102 */
3103 HtmlEntry _cacheHtmlResolutionData(
3104 Source source, HtmlEntry htmlEntry, DataDescriptor descriptor) {
3105 //
3106 // Check to see whether we already have the information being requested.
3107 //
3108 CacheState state = htmlEntry.getState(descriptor);
3109 while (state != CacheState.ERROR && state != CacheState.VALID) {
3110 //
3111 // If not, compute the information. Unless the modification date of the
3112 // source continues to change, this loop will eventually terminate.
3113 //
3114 htmlEntry = _cacheHtmlParseData(source, htmlEntry, HtmlEntry.PARSED_UNIT);
3115 htmlEntry = new ResolveHtmlTask(this, source, htmlEntry.modificationTime,
3116 htmlEntry.getValue(HtmlEntry.PARSED_UNIT))
3117 .perform(_resultRecorder) as HtmlEntry;
3118 state = htmlEntry.getState(descriptor);
3119 }
3120 return htmlEntry;
3121 }
3122
3123 /**
3124 * Remove the given [pendingFuture] from [_pendingFutureSources], since the
3125 * client has indicated its computation is not needed anymore.
3126 */
3127 void _cancelFuture(PendingFuture pendingFuture) {
3128 List<PendingFuture> pendingFutures =
3129 _pendingFutureSources[pendingFuture.source];
3130 if (pendingFutures != null) {
3131 pendingFutures.remove(pendingFuture);
3132 if (pendingFutures.isEmpty) {
3133 _pendingFutureSources.remove(pendingFuture.source);
3134 }
3135 }
3136 }
3137
3138 /**
3139 * Compute the transitive closure of all libraries that depend on the given
3140 * [library] by adding such libraries to the given collection of
3141 * [librariesToInvalidate].
3142 */
3143 void _computeAllLibrariesDependingOn(
3144 Source library, HashSet<Source> librariesToInvalidate) {
3145 if (librariesToInvalidate.add(library)) {
3146 for (Source dependentLibrary in getLibrariesDependingOn(library)) {
3147 _computeAllLibrariesDependingOn(
3148 dependentLibrary, librariesToInvalidate);
3149 }
3150 }
3151 }
3152
3153 /**
3154 * Return the priority that should be used when the source associated with
3155 * the given [dartEntry] is added to the work manager.
3156 */
3157 SourcePriority _computePriority(DartEntry dartEntry) {
3158 SourceKind kind = dartEntry.kind;
3159 if (kind == SourceKind.LIBRARY) {
3160 return SourcePriority.LIBRARY;
3161 } else if (kind == SourceKind.PART) {
3162 return SourcePriority.NORMAL_PART;
3163 }
3164 return SourcePriority.UNKNOWN;
3165 }
3166
3167 /**
3168 * Given the encoded form of a source ([encoding]), use the source factory to
3169 * reconstitute the original source.
3170 */
3171 Source _computeSourceFromEncoding(String encoding) =>
3172 _sourceFactory.fromEncoding(encoding);
3173
3174 /**
3175 * Return `true` if the given list of [sources] contains the given
3176 * [targetSource].
3177 */
3178 bool _contains(List<Source> sources, Source targetSource) {
3179 for (Source source in sources) {
3180 if (source == targetSource) {
3181 return true;
3182 }
3183 }
3184 return false;
3185 }
3186
3187 /**
3188 * Return `true` if the given list of [sources] contains any of the given
3189 * [targetSources].
3190 */
3191 bool _containsAny(List<Source> sources, List<Source> targetSources) {
3192 for (Source targetSource in targetSources) {
3193 if (_contains(sources, targetSource)) {
3194 return true;
3195 }
3196 }
3197 return false;
3198 }
3199
3200 /**
3201 * Set the contents of the given [source] to the given [contents] and mark the
3202 * source as having changed. The additional [offset], [oldLength] and
3203 * [newLength] information is used by the context to determine what reanalysis
3204 * is necessary. The method [setChangedContents] triggers a source changed
3205 * event where as this method does not.
3206 */
3207 bool _contentRangeChanged(Source source, String contents, int offset,
3208 int oldLength, int newLength) {
3209 bool changed = false;
3210 String originalContents = _contentCache.setContents(source, contents);
3211 if (contents != null) {
3212 if (contents != originalContents) {
3213 if (_options.incremental) {
3214 _incrementalAnalysisCache = IncrementalAnalysisCache.update(
3215 _incrementalAnalysisCache,
3216 source,
3217 originalContents,
3218 contents,
3219 offset,
3220 oldLength,
3221 newLength,
3222 _getReadableSourceEntry(source));
3223 }
3224 _sourceChanged(source);
3225 changed = true;
3226 SourceEntry sourceEntry = _cache.get(source);
3227 if (sourceEntry != null) {
3228 sourceEntry.modificationTime =
3229 _contentCache.getModificationStamp(source);
3230 sourceEntry.setValue(SourceEntry.CONTENT, contents);
3231 }
3232 }
3233 } else if (originalContents != null) {
3234 _incrementalAnalysisCache =
3235 IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
3236 _sourceChanged(source);
3237 changed = true;
3238 }
3239 return changed;
3240 }
3241
3242 /**
3243 * Set the contents of the given [source] to the given [contents] and mark the
3244 * source as having changed. This has the effect of overriding the default
3245 * contents of the source. If the contents are `null` the override is removed
3246 * so that the default contents will be returned. If [notify] is true, a
3247 * source changed event is triggered.
3248 */
3249 void _contentsChanged(Source source, String contents, bool notify) {
3250 String originalContents = _contentCache.setContents(source, contents);
3251 handleContentsChanged(source, originalContents, contents, notify);
3252 }
3253
3254 /**
3255 * Create a [GenerateDartErrorsTask] for the given [unitSource], marking the
3256 * verification errors as being in-process. The compilation unit and the
3257 * library can be the same if the compilation unit is the defining compilation
3258 * unit of the library.
3259 */
3260 AnalysisContextImpl_TaskData _createGenerateDartErrorsTask(Source unitSource,
3261 DartEntry unitEntry, Source librarySource, DartEntry libraryEntry) {
3262 if (unitEntry.getStateInLibrary(DartEntry.RESOLVED_UNIT, librarySource) !=
3263 CacheState.VALID ||
3264 libraryEntry.getState(DartEntry.ELEMENT) != CacheState.VALID) {
3265 return _createResolveDartLibraryTask(librarySource, libraryEntry);
3266 }
3267 CompilationUnit unit =
3268 unitEntry.getValueInLibrary(DartEntry.RESOLVED_UNIT, librarySource);
3269 if (unit == null) {
3270 CaughtException exception = new CaughtException(
3271 new AnalysisException(
3272 "Entry has VALID state for RESOLVED_UNIT but null value for ${unit Source.fullName} in ${librarySource.fullName}"),
3273 null);
3274 AnalysisEngine.instance.logger
3275 .logInformation(exception.toString(), exception);
3276 unitEntry.recordResolutionError(exception);
3277 return new AnalysisContextImpl_TaskData(null, false);
3278 }
3279 LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT);
3280 return new AnalysisContextImpl_TaskData(
3281 new GenerateDartErrorsTask(this, unitSource, unit, libraryElement),
3282 false);
3283 }
3284
3285 /**
3286 * Create a [GenerateDartHintsTask] for the given [source], marking the hints
3287 * as being in-process.
3288 */
3289 AnalysisContextImpl_TaskData _createGenerateDartHintsTask(Source source,
3290 DartEntry dartEntry, Source librarySource, DartEntry libraryEntry) {
3291 if (libraryEntry.getState(DartEntry.ELEMENT) != CacheState.VALID) {
3292 return _createResolveDartLibraryTask(librarySource, libraryEntry);
3293 }
3294 LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT);
3295 CompilationUnitElement definingUnit =
3296 libraryElement.definingCompilationUnit;
3297 List<CompilationUnitElement> parts = libraryElement.parts;
3298 List<TimestampedData<CompilationUnit>> units =
3299 new List<TimestampedData<CompilationUnit>>(parts.length + 1);
3300 units[0] = _getResolvedUnit(definingUnit, librarySource);
3301 if (units[0] == null) {
3302 // TODO(brianwilkerson) We should return a ResolveDartUnitTask
3303 // (unless there are multiple ASTs that need to be resolved).
3304 return _createResolveDartLibraryTask(librarySource, libraryEntry);
3305 }
3306 for (int i = 0; i < parts.length; i++) {
3307 units[i + 1] = _getResolvedUnit(parts[i], librarySource);
3308 if (units[i + 1] == null) {
3309 // TODO(brianwilkerson) We should return a ResolveDartUnitTask
3310 // (unless there are multiple ASTs that need to be resolved).
3311 return _createResolveDartLibraryTask(librarySource, libraryEntry);
3312 }
3313 }
3314 return new AnalysisContextImpl_TaskData(
3315 new GenerateDartHintsTask(this, units, libraryElement), false);
3316 }
3317
3318 /**
3319 * Create a [GenerateDartLintsTask] for the given [source], marking the lints
3320 * as being in-process.
3321 */
3322 AnalysisContextImpl_TaskData _createGenerateDartLintsTask(Source source,
3323 DartEntry dartEntry, Source librarySource, DartEntry libraryEntry) {
3324 if (libraryEntry.getState(DartEntry.ELEMENT) != CacheState.VALID) {
3325 return _createResolveDartLibraryTask(librarySource, libraryEntry);
3326 }
3327 LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT);
3328 CompilationUnitElement definingUnit =
3329 libraryElement.definingCompilationUnit;
3330 List<CompilationUnitElement> parts = libraryElement.parts;
3331 List<TimestampedData<CompilationUnit>> units =
3332 new List<TimestampedData<CompilationUnit>>(parts.length + 1);
3333 units[0] = _getResolvedUnit(definingUnit, librarySource);
3334 if (units[0] == null) {
3335 // TODO(brianwilkerson) We should return a ResolveDartUnitTask
3336 // (unless there are multiple ASTs that need to be resolved).
3337 return _createResolveDartLibraryTask(librarySource, libraryEntry);
3338 }
3339 for (int i = 0; i < parts.length; i++) {
3340 units[i + 1] = _getResolvedUnit(parts[i], librarySource);
3341 if (units[i + 1] == null) {
3342 // TODO(brianwilkerson) We should return a ResolveDartUnitTask
3343 // (unless there are multiple ASTs that need to be resolved).
3344 return _createResolveDartLibraryTask(librarySource, libraryEntry);
3345 }
3346 }
3347 //TODO(pquitslund): revisit if we need all units or whether one will do
3348 return new AnalysisContextImpl_TaskData(
3349 new GenerateDartLintsTask(this, units, libraryElement), false);
3350 }
3351
3352 /**
3353 * Create a [GetContentTask] for the given [source], marking the content as
3354 * being in-process.
3355 */
3356 AnalysisContextImpl_TaskData _createGetContentTask(
3357 Source source, SourceEntry sourceEntry) {
3358 return new AnalysisContextImpl_TaskData(
3359 new GetContentTask(this, source), false);
3360 }
3361
3362 /**
3363 * Create a [ParseDartTask] for the given [source].
3364 */
3365 AnalysisContextImpl_TaskData _createParseDartTask(
3366 Source source, DartEntry dartEntry) {
3367 if (dartEntry.getState(DartEntry.TOKEN_STREAM) != CacheState.VALID ||
3368 dartEntry.getState(SourceEntry.LINE_INFO) != CacheState.VALID) {
3369 return _createScanDartTask(source, dartEntry);
3370 }
3371 Token tokenStream = dartEntry.getValue(DartEntry.TOKEN_STREAM);
3372 dartEntry.setState(DartEntry.TOKEN_STREAM, CacheState.FLUSHED);
3373 return new AnalysisContextImpl_TaskData(
3374 new ParseDartTask(this, source, tokenStream,
3375 dartEntry.getValue(SourceEntry.LINE_INFO)),
3376 false);
3377 }
3378
3379 /**
3380 * Create a [ParseHtmlTask] for the given [source].
3381 */
3382 AnalysisContextImpl_TaskData _createParseHtmlTask(
3383 Source source, HtmlEntry htmlEntry) {
3384 if (htmlEntry.getState(SourceEntry.CONTENT) != CacheState.VALID) {
3385 return _createGetContentTask(source, htmlEntry);
3386 }
3387 String content = htmlEntry.getValue(SourceEntry.CONTENT);
3388 htmlEntry.setState(SourceEntry.CONTENT, CacheState.FLUSHED);
3389 return new AnalysisContextImpl_TaskData(
3390 new ParseHtmlTask(this, source, content), false);
3391 }
3392
3393 /**
3394 * Create a [ResolveDartLibraryTask] for the given [source], marking ? as
3395 * being in-process.
3396 */
3397 AnalysisContextImpl_TaskData _createResolveDartLibraryTask(
3398 Source source, DartEntry dartEntry) {
3399 try {
3400 AnalysisContextImpl_CycleBuilder builder =
3401 new AnalysisContextImpl_CycleBuilder(this);
3402 PerformanceStatistics.cycles.makeCurrentWhile(() {
3403 builder.computeCycleContaining(source);
3404 });
3405 AnalysisContextImpl_TaskData taskData = builder.taskData;
3406 if (taskData != null) {
3407 return taskData;
3408 }
3409 return new AnalysisContextImpl_TaskData(
3410 new ResolveDartLibraryCycleTask(
3411 this, source, source, builder.librariesInCycle),
3412 false);
3413 } on AnalysisException catch (exception, stackTrace) {
3414 dartEntry
3415 .recordResolutionError(new CaughtException(exception, stackTrace));
3416 AnalysisEngine.instance.logger.logError(
3417 "Internal error trying to create a ResolveDartLibraryTask",
3418 new CaughtException(exception, stackTrace));
3419 }
3420 return new AnalysisContextImpl_TaskData(null, false);
3421 }
3422
3423 /**
3424 * Create a [ResolveHtmlTask] for the given [source], marking the resolved
3425 * unit as being in-process.
3426 */
3427 AnalysisContextImpl_TaskData _createResolveHtmlTask(
3428 Source source, HtmlEntry htmlEntry) {
3429 if (htmlEntry.getState(HtmlEntry.PARSED_UNIT) != CacheState.VALID) {
3430 return _createParseHtmlTask(source, htmlEntry);
3431 }
3432 return new AnalysisContextImpl_TaskData(
3433 new ResolveHtmlTask(this, source, htmlEntry.modificationTime,
3434 htmlEntry.getValue(HtmlEntry.PARSED_UNIT)),
3435 false);
3436 }
3437
3438 /**
3439 * Create a [ScanDartTask] for the given [source], marking the scan errors as
3440 * being in-process.
3441 */
3442 AnalysisContextImpl_TaskData _createScanDartTask(
3443 Source source, DartEntry dartEntry) {
3444 if (dartEntry.getState(SourceEntry.CONTENT) != CacheState.VALID) {
3445 return _createGetContentTask(source, dartEntry);
3446 }
3447 String content = dartEntry.getValue(SourceEntry.CONTENT);
3448 dartEntry.setState(SourceEntry.CONTENT, CacheState.FLUSHED);
3449 return new AnalysisContextImpl_TaskData(
3450 new ScanDartTask(this, source, content), false);
3451 }
3452
3453 /**
3454 * Create a source entry for the given [source]. Return the source entry that
3455 * was created, or `null` if the source should not be tracked by this context.
3456 */
3457 SourceEntry _createSourceEntry(Source source, bool explicitlyAdded) {
3458 String name = source.shortName;
3459 if (AnalysisEngine.isHtmlFileName(name)) {
3460 HtmlEntry htmlEntry = new HtmlEntry();
3461 htmlEntry.modificationTime = getModificationStamp(source);
3462 htmlEntry.explicitlyAdded = explicitlyAdded;
3463 _cache.put(source, htmlEntry);
3464 if (!explicitlyAdded) {
3465 _implicitAnalysisEventsController
3466 .add(new ImplicitAnalysisEvent(source, true));
3467 }
3468 return htmlEntry;
3469 } else {
3470 DartEntry dartEntry = new DartEntry();
3471 dartEntry.modificationTime = getModificationStamp(source);
3472 dartEntry.explicitlyAdded = explicitlyAdded;
3473 _cache.put(source, dartEntry);
3474 if (!explicitlyAdded) {
3475 _implicitAnalysisEventsController
3476 .add(new ImplicitAnalysisEvent(source, true));
3477 }
3478 return dartEntry;
3479 }
3480 }
3481
3482 /**
3483 * Return a list containing all of the change notices that are waiting to be
3484 * returned. If there are no notices, then return either `null` or an empty
3485 * list, depending on the value of [nullIfEmpty].
3486 */
3487 List<ChangeNotice> _getChangeNotices(bool nullIfEmpty) {
3488 if (_pendingNotices.isEmpty) {
3489 if (nullIfEmpty) {
3490 return null;
3491 }
3492 return ChangeNoticeImpl.EMPTY_LIST;
3493 }
3494 List<ChangeNotice> notices = new List.from(_pendingNotices.values);
3495 _pendingNotices.clear();
3496 return notices;
3497 }
3498
3499 /**
3500 * Given a source for a Dart file and the library that contains it, return the
3501 * data represented by the given descriptor that is associated with that
3502 * source. This method assumes that the data can be produced by generating
3503 * hints for the library if it is not already cached.
3504 *
3505 * Throws an [AnalysisException] if data could not be returned because the
3506 * source could not be resolved.
3507 *
3508 * <b>Note:</b> This method cannot be used in an async environment.
3509 */
3510 Object _getDartHintData(Source unitSource, Source librarySource,
3511 DartEntry dartEntry, DataDescriptor descriptor) {
3512 dartEntry =
3513 _cacheDartHintData(unitSource, librarySource, dartEntry, descriptor);
3514 if (identical(descriptor, DartEntry.ELEMENT)) {
3515 return dartEntry.getValue(descriptor);
3516 }
3517 return dartEntry.getValueInLibrary(descriptor, librarySource);
3518 }
3519
3520 /**
3521 * Given a source for a Dart file and the library that contains it, return the
3522 * data represented by the given descriptor that is associated with that
3523 * source. This method assumes that the data can be produced by generating
3524 * lints for the library if it is not already cached.
3525 *
3526 * Throws an [AnalysisException] if data could not be returned because the
3527 * source could not be resolved.
3528 *
3529 * <b>Note:</b> This method cannot be used in an async environment.
3530 */
3531 Object _getDartLintData(Source unitSource, Source librarySource,
3532 DartEntry dartEntry, DataDescriptor descriptor) {
3533 dartEntry =
3534 _cacheDartLintData(unitSource, librarySource, dartEntry, descriptor);
3535 if (identical(descriptor, DartEntry.ELEMENT)) {
3536 return dartEntry.getValue(descriptor);
3537 }
3538 return dartEntry.getValueInLibrary(descriptor, librarySource);
3539 }
3540
3541 /**
3542 * Given a source for a Dart file, return the data represented by the given
3543 * descriptor that is associated with that source. This method assumes that
3544 * the data can be produced by parsing the source if it is not already cached.
3545 *
3546 * Throws an [AnalysisException] if data could not be returned because the
3547 * source could not be parsed.
3548 *
3549 * <b>Note:</b> This method cannot be used in an async environment.
3550 */
3551 Object _getDartParseData(
3552 Source source, DartEntry dartEntry, DataDescriptor descriptor) {
3553 dartEntry = _cacheDartParseData(source, dartEntry, descriptor);
3554 if (identical(descriptor, DartEntry.PARSED_UNIT)) {
3555 _accessedAst(source);
3556 return dartEntry.anyParsedCompilationUnit;
3557 }
3558 return dartEntry.getValue(descriptor);
3559 }
3560
3561 /**
3562 * Given a source for a Dart file, return the data represented by the given
3563 * descriptor that is associated with that source, or the given default value
3564 * if the source is not a Dart file. This method assumes that the data can be
3565 * produced by parsing the source if it is not already cached.
3566 *
3567 * Throws an [AnalysisException] if data could not be returned because the
3568 * source could not be parsed.
3569 *
3570 * <b>Note:</b> This method cannot be used in an async environment.
3571 */
3572 Object _getDartParseData2(
3573 Source source, DataDescriptor descriptor, Object defaultValue) {
3574 DartEntry dartEntry = _getReadableDartEntry(source);
3575 if (dartEntry == null) {
3576 return defaultValue;
3577 }
3578 try {
3579 return _getDartParseData(source, dartEntry, descriptor);
3580 } on ObsoleteSourceAnalysisException catch (exception, stackTrace) {
3581 AnalysisEngine.instance.logger.logInformation(
3582 "Could not compute $descriptor",
3583 new CaughtException(exception, stackTrace));
3584 return defaultValue;
3585 }
3586 }
3587
3588 /**
3589 * Given a source for a Dart file and the library that contains it, return the
3590 * data represented by the given descriptor that is associated with that
3591 * source. This method assumes that the data can be produced by resolving the
3592 * source in the context of the library if it is not already cached.
3593 *
3594 * Throws an [AnalysisException] if data could not be returned because the
3595 * source could not be resolved.
3596 *
3597 * <b>Note:</b> This method cannot be used in an async environment.
3598 */
3599 Object _getDartResolutionData(Source unitSource, Source librarySource,
3600 DartEntry dartEntry, DataDescriptor descriptor) {
3601 dartEntry = _cacheDartResolutionData(
3602 unitSource, librarySource, dartEntry, descriptor);
3603 if (identical(descriptor, DartEntry.ELEMENT)) {
3604 return dartEntry.getValue(descriptor);
3605 } else if (identical(descriptor, DartEntry.RESOLVED_UNIT)) {
3606 _accessedAst(unitSource);
3607 }
3608 return dartEntry.getValueInLibrary(descriptor, librarySource);
3609 }
3610
3611 /**
3612 * Given a source for a Dart file and the library that contains it, return the
3613 * data represented by the given descriptor that is associated with that
3614 * source, or the given default value if the source is not a Dart file. This
3615 * method assumes that the data can be produced by resolving the source in the
3616 * context of the library if it is not already cached.
3617 *
3618 * Throws an [AnalysisException] if data could not be returned because the
3619 * source could not be resolved.
3620 *
3621 * <b>Note:</b> This method cannot be used in an async environment.
3622 */
3623 Object _getDartResolutionData2(Source unitSource, Source librarySource,
3624 DataDescriptor descriptor, Object defaultValue) {
3625 DartEntry dartEntry = _getReadableDartEntry(unitSource);
3626 if (dartEntry == null) {
3627 return defaultValue;
3628 }
3629 try {
3630 return _getDartResolutionData(
3631 unitSource, librarySource, dartEntry, descriptor);
3632 } on ObsoleteSourceAnalysisException catch (exception, stackTrace) {
3633 AnalysisEngine.instance.logger.logInformation(
3634 "Could not compute $descriptor",
3635 new CaughtException(exception, stackTrace));
3636 return defaultValue;
3637 }
3638 }
3639
3640 /**
3641 * Given a source for a Dart file, return the data represented by the given
3642 * descriptor that is associated with that source. This method assumes that
3643 * the data can be produced by scanning the source if it is not already
3644 * cached.
3645 *
3646 * Throws an [AnalysisException] if data could not be returned because the
3647 * source could not be scanned.
3648 *
3649 * <b>Note:</b> This method cannot be used in an async environment.
3650 */
3651 Object _getDartScanData(
3652 Source source, DartEntry dartEntry, DataDescriptor descriptor) {
3653 dartEntry = _cacheDartScanData(source, dartEntry, descriptor);
3654 return dartEntry.getValue(descriptor);
3655 }
3656
3657 /**
3658 * Given a source for a Dart file, return the data represented by the given
3659 * descriptor that is associated with that source, or the given default value
3660 * if the source is not a Dart file. This method assumes that the data can be
3661 * produced by scanning the source if it is not already cached.
3662 *
3663 * Throws an [AnalysisException] if data could not be returned because the
3664 * source could not be scanned.
3665 *
3666 * <b>Note:</b> This method cannot be used in an async environment.
3667 */
3668 Object _getDartScanData2(
3669 Source source, DataDescriptor descriptor, Object defaultValue) {
3670 DartEntry dartEntry = _getReadableDartEntry(source);
3671 if (dartEntry == null) {
3672 return defaultValue;
3673 }
3674 try {
3675 return _getDartScanData(source, dartEntry, descriptor);
3676 } on ObsoleteSourceAnalysisException catch (exception, stackTrace) {
3677 AnalysisEngine.instance.logger.logInformation(
3678 "Could not compute $descriptor",
3679 new CaughtException(exception, stackTrace));
3680 return defaultValue;
3681 }
3682 }
3683
3684 /**
3685 * Given a source for a Dart file and the library that contains it, return the
3686 * data represented by the given descriptor that is associated with that
3687 * source. This method assumes that the data can be produced by verifying the
3688 * source within the given library if it is not already cached.
3689 *
3690 * Throws an [AnalysisException] if data could not be returned because the
3691 * source could not be resolved.
3692 *
3693 * <b>Note:</b> This method cannot be used in an async environment.
3694 */
3695 Object _getDartVerificationData(Source unitSource, Source librarySource,
3696 DartEntry dartEntry, DataDescriptor descriptor) {
3697 dartEntry = _cacheDartVerificationData(
3698 unitSource, librarySource, dartEntry, descriptor);
3699 return dartEntry.getValueInLibrary(descriptor, librarySource);
3700 }
3701
3702 /**
3703 * Given a source for an HTML file, return the data represented by the given
3704 * descriptor that is associated with that source, or the given default value
3705 * if the source is not an HTML file. This method assumes that the data can be
3706 * produced by parsing the source if it is not already cached.
3707 *
3708 * Throws an [AnalysisException] if data could not be returned because the
3709 * source could not be parsed.
3710 *
3711 * <b>Note:</b> This method cannot be used in an async environment.
3712 */
3713 Object _getHtmlParseData(
3714 Source source, DataDescriptor descriptor, Object defaultValue) {
3715 HtmlEntry htmlEntry = _getReadableHtmlEntry(source);
3716 if (htmlEntry == null) {
3717 return defaultValue;
3718 }
3719 htmlEntry = _cacheHtmlParseData(source, htmlEntry, descriptor);
3720 if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
3721 _accessedAst(source);
3722 return htmlEntry.anyParsedUnit;
3723 }
3724 return htmlEntry.getValue(descriptor);
3725 }
3726
3727 /**
3728 * Given a source for an HTML file, return the data represented by the given
3729 * descriptor that is associated with that source, or the given default value
3730 * if the source is not an HTML file. This method assumes that the data can be
3731 * produced by resolving the source if it is not already cached.
3732 *
3733 * Throws an [AnalysisException] if data could not be returned because the
3734 * source could not be resolved.
3735 *
3736 * <b>Note:</b> This method cannot be used in an async environment.
3737 */
3738 Object _getHtmlResolutionData(
3739 Source source, DataDescriptor descriptor, Object defaultValue) {
3740 HtmlEntry htmlEntry = _getReadableHtmlEntry(source);
3741 if (htmlEntry == null) {
3742 return defaultValue;
3743 }
3744 try {
3745 return _getHtmlResolutionData2(source, htmlEntry, descriptor);
3746 } on ObsoleteSourceAnalysisException catch (exception, stackTrace) {
3747 AnalysisEngine.instance.logger.logInformation(
3748 "Could not compute $descriptor",
3749 new CaughtException(exception, stackTrace));
3750 return defaultValue;
3751 }
3752 }
3753
3754 /**
3755 * Given a source for an HTML file, return the data represented by the given
3756 * descriptor that is associated with that source. This method assumes that
3757 * the data can be produced by resolving the source if it is not already
3758 * cached.
3759 *
3760 * Throws an [AnalysisException] if data could not be returned because the
3761 * source could not be resolved.
3762 *
3763 * <b>Note:</b> This method cannot be used in an async environment.
3764 */
3765 Object _getHtmlResolutionData2(
3766 Source source, HtmlEntry htmlEntry, DataDescriptor descriptor) {
3767 htmlEntry = _cacheHtmlResolutionData(source, htmlEntry, descriptor);
3768 if (identical(descriptor, HtmlEntry.RESOLVED_UNIT)) {
3769 _accessedAst(source);
3770 }
3771 return htmlEntry.getValue(descriptor);
3772 }
3773
3774 /**
3775 * Look at the given [source] to see whether a task needs to be performed
3776 * related to it. Return the task that should be performed, or `null` if there
3777 * is no more work to be done for the source.
3778 */
3779 AnalysisContextImpl_TaskData _getNextAnalysisTaskForSource(
3780 Source source,
3781 SourceEntry sourceEntry,
3782 bool isPriority,
3783 bool hintsEnabled,
3784 bool lintsEnabled) {
3785 // Refuse to generate tasks for html based files that are above 1500 KB
3786 if (_isTooBigHtmlSourceEntry(source, sourceEntry)) {
3787 // TODO (jwren) we still need to report an error of some kind back to the
3788 // client.
3789 return new AnalysisContextImpl_TaskData(null, false);
3790 }
3791 if (sourceEntry == null) {
3792 return new AnalysisContextImpl_TaskData(null, false);
3793 }
3794 CacheState contentState = sourceEntry.getState(SourceEntry.CONTENT);
3795 if (contentState == CacheState.INVALID) {
3796 return _createGetContentTask(source, sourceEntry);
3797 } else if (contentState == CacheState.IN_PROCESS) {
3798 // We are already in the process of getting the content.
3799 // There's nothing else we can do with this source until that's complete.
3800 return new AnalysisContextImpl_TaskData(null, true);
3801 } else if (contentState == CacheState.ERROR) {
3802 // We have done all of the analysis we can for this source because we
3803 // cannot get its content.
3804 return new AnalysisContextImpl_TaskData(null, false);
3805 }
3806 if (sourceEntry is DartEntry) {
3807 DartEntry dartEntry = sourceEntry;
3808 CacheState scanErrorsState = dartEntry.getState(DartEntry.SCAN_ERRORS);
3809 if (scanErrorsState == CacheState.INVALID ||
3810 (isPriority && scanErrorsState == CacheState.FLUSHED)) {
3811 return _createScanDartTask(source, dartEntry);
3812 }
3813 CacheState parseErrorsState = dartEntry.getState(DartEntry.PARSE_ERRORS);
3814 if (parseErrorsState == CacheState.INVALID ||
3815 (isPriority && parseErrorsState == CacheState.FLUSHED)) {
3816 return _createParseDartTask(source, dartEntry);
3817 }
3818 if (isPriority && parseErrorsState != CacheState.ERROR) {
3819 if (!dartEntry.hasResolvableCompilationUnit) {
3820 return _createParseDartTask(source, dartEntry);
3821 }
3822 }
3823 SourceKind kind = dartEntry.getValue(DartEntry.SOURCE_KIND);
3824 if (kind == SourceKind.UNKNOWN) {
3825 return _createParseDartTask(source, dartEntry);
3826 } else if (kind == SourceKind.LIBRARY) {
3827 CacheState elementState = dartEntry.getState(DartEntry.ELEMENT);
3828 if (elementState == CacheState.INVALID) {
3829 return _createResolveDartLibraryTask(source, dartEntry);
3830 }
3831 }
3832 List<Source> librariesContaining = dartEntry.containingLibraries;
3833 for (Source librarySource in librariesContaining) {
3834 SourceEntry librarySourceEntry = _cache.get(librarySource);
3835 if (librarySourceEntry is DartEntry) {
3836 DartEntry libraryEntry = librarySourceEntry;
3837 CacheState elementState = libraryEntry.getState(DartEntry.ELEMENT);
3838 if (elementState == CacheState.INVALID ||
3839 (isPriority && elementState == CacheState.FLUSHED)) {
3840 // return createResolveDartLibraryTask(librarySource, (DartEntry) lib raryEntry);
3841 return new AnalysisContextImpl_TaskData(
3842 new ResolveDartLibraryTask(this, source, librarySource), false);
3843 }
3844 CacheState resolvedUnitState = dartEntry.getStateInLibrary(
3845 DartEntry.RESOLVED_UNIT, librarySource);
3846 if (resolvedUnitState == CacheState.INVALID ||
3847 (isPriority && resolvedUnitState == CacheState.FLUSHED)) {
3848 //
3849 // The commented out lines below are an optimization that doesn't
3850 // quite work yet. The problem is that if the source was not
3851 // resolved because it wasn't part of any library, then there won't
3852 // be any elements in the element model that we can use to resolve
3853 // it.
3854 //
3855 // LibraryElement libraryElement = libraryEntry.getValue(DartEntry.EL EMENT);
3856 // if (libraryElement != null) {
3857 // return new ResolveDartUnitTask(this, source, libraryElement);
3858 // }
3859 // Possibly replace with:
3860 // return createResolveDartLibraryTask(librarySource, (DartEntry) li braryEntry);
3861 return new AnalysisContextImpl_TaskData(
3862 new ResolveDartLibraryTask(this, source, librarySource), false);
3863 }
3864 if (shouldErrorsBeAnalyzed(source, dartEntry)) {
3865 CacheState verificationErrorsState = dartEntry.getStateInLibrary(
3866 DartEntry.VERIFICATION_ERRORS, librarySource);
3867 if (verificationErrorsState == CacheState.INVALID ||
3868 (isPriority && verificationErrorsState == CacheState.FLUSHED)) {
3869 return _createGenerateDartErrorsTask(
3870 source, dartEntry, librarySource, libraryEntry);
3871 }
3872 if (hintsEnabled) {
3873 CacheState hintsState =
3874 dartEntry.getStateInLibrary(DartEntry.HINTS, librarySource);
3875 if (hintsState == CacheState.INVALID ||
3876 (isPriority && hintsState == CacheState.FLUSHED)) {
3877 return _createGenerateDartHintsTask(
3878 source, dartEntry, librarySource, libraryEntry);
3879 }
3880 }
3881 if (lintsEnabled) {
3882 CacheState lintsState =
3883 dartEntry.getStateInLibrary(DartEntry.LINTS, librarySource);
3884 if (lintsState == CacheState.INVALID ||
3885 (isPriority && lintsState == CacheState.FLUSHED)) {
3886 return _createGenerateDartLintsTask(
3887 source, dartEntry, librarySource, libraryEntry);
3888 }
3889 }
3890 }
3891 }
3892 }
3893 } else if (sourceEntry is HtmlEntry) {
3894 HtmlEntry htmlEntry = sourceEntry;
3895 CacheState parseErrorsState = htmlEntry.getState(HtmlEntry.PARSE_ERRORS);
3896 if (parseErrorsState == CacheState.INVALID ||
3897 (isPriority && parseErrorsState == CacheState.FLUSHED)) {
3898 return _createParseHtmlTask(source, htmlEntry);
3899 }
3900 if (isPriority && parseErrorsState != CacheState.ERROR) {
3901 ht.HtmlUnit parsedUnit = htmlEntry.anyParsedUnit;
3902 if (parsedUnit == null) {
3903 return _createParseHtmlTask(source, htmlEntry);
3904 }
3905 }
3906 CacheState resolvedUnitState =
3907 htmlEntry.getState(HtmlEntry.RESOLVED_UNIT);
3908 if (resolvedUnitState == CacheState.INVALID ||
3909 (isPriority && resolvedUnitState == CacheState.FLUSHED)) {
3910 return _createResolveHtmlTask(source, htmlEntry);
3911 }
3912 }
3913 return new AnalysisContextImpl_TaskData(null, false);
3914 }
3915
3916 /**
3917 * Return the cache entry associated with the given [source], or `null` if the
3918 * source is not a Dart file.
3919 *
3920 * @param source the source for which a cache entry is being sought
3921 * @return the source cache entry associated with the given source
3922 */
3923 DartEntry _getReadableDartEntry(Source source) {
3924 SourceEntry sourceEntry = _cache.get(source);
3925 if (sourceEntry == null) {
3926 sourceEntry = _createSourceEntry(source, false);
3927 }
3928 if (sourceEntry is DartEntry) {
3929 return sourceEntry;
3930 }
3931 return null;
3932 }
3933
3934 /**
3935 * Return the cache entry associated with the given [source], or `null` if the
3936 * source is not an HTML file.
3937 */
3938 HtmlEntry _getReadableHtmlEntry(Source source) {
3939 SourceEntry sourceEntry = _cache.get(source);
3940 if (sourceEntry == null) {
3941 sourceEntry = _createSourceEntry(source, false);
3942 }
3943 if (sourceEntry is HtmlEntry) {
3944 return sourceEntry;
3945 }
3946 return null;
3947 }
3948
3949 /**
3950 * Return the cache entry associated with the given [source], creating it if
3951 * necessary.
3952 */
3953 SourceEntry _getReadableSourceEntry(Source source) {
3954 SourceEntry sourceEntry = _cache.get(source);
3955 if (sourceEntry == null) {
3956 sourceEntry = _createSourceEntry(source, false);
3957 }
3958 return sourceEntry;
3959 }
3960
3961 /**
3962 * Return a resolved compilation unit corresponding to the given [element] in
3963 * the library defined by the given [librarySource], or `null` if the
3964 * information is not cached.
3965 */
3966 TimestampedData<CompilationUnit> _getResolvedUnit(
3967 CompilationUnitElement element, Source librarySource) {
3968 SourceEntry sourceEntry = _cache.get(element.source);
3969 if (sourceEntry is DartEntry) {
3970 DartEntry dartEntry = sourceEntry;
3971 if (dartEntry.getStateInLibrary(DartEntry.RESOLVED_UNIT, librarySource) ==
3972 CacheState.VALID) {
3973 return new TimestampedData<CompilationUnit>(
3974 dartEntry.modificationTime,
3975 dartEntry.getValueInLibrary(
3976 DartEntry.RESOLVED_UNIT, librarySource));
3977 }
3978 }
3979 return null;
3980 }
3981
3982 /**
3983 * Return a list containing all of the sources known to this context that have
3984 * the given [kind].
3985 */
3986 List<Source> _getSources(SourceKind kind) {
3987 List<Source> sources = new List<Source>();
3988 MapIterator<Source, SourceEntry> iterator = _cache.iterator();
3989 while (iterator.moveNext()) {
3990 if (iterator.value.kind == kind) {
3991 sources.add(iterator.key);
3992 }
3993 }
3994 return sources;
3995 }
3996
3997 /**
3998 * Look at the given [source] to see whether a task needs to be performed
3999 * related to it. If so, add the source to the set of sources that need to be
4000 * processed. This method duplicates, and must therefore be kept in sync with,
4001 * [_getNextAnalysisTaskForSource]. This method is intended to be used for
4002 * testing purposes only.
4003 */
4004 void _getSourcesNeedingProcessing(
4005 Source source,
4006 SourceEntry sourceEntry,
4007 bool isPriority,
4008 bool hintsEnabled,
4009 bool lintsEnabled,
4010 HashSet<Source> sources) {
4011 if (sourceEntry is DartEntry) {
4012 DartEntry dartEntry = sourceEntry;
4013 CacheState scanErrorsState = dartEntry.getState(DartEntry.SCAN_ERRORS);
4014 if (scanErrorsState == CacheState.INVALID ||
4015 (isPriority && scanErrorsState == CacheState.FLUSHED)) {
4016 sources.add(source);
4017 return;
4018 }
4019 CacheState parseErrorsState = dartEntry.getState(DartEntry.PARSE_ERRORS);
4020 if (parseErrorsState == CacheState.INVALID ||
4021 (isPriority && parseErrorsState == CacheState.FLUSHED)) {
4022 sources.add(source);
4023 return;
4024 }
4025 if (isPriority) {
4026 if (!dartEntry.hasResolvableCompilationUnit) {
4027 sources.add(source);
4028 return;
4029 }
4030 }
4031 for (Source librarySource in getLibrariesContaining(source)) {
4032 SourceEntry libraryEntry = _cache.get(librarySource);
4033 if (libraryEntry is DartEntry) {
4034 CacheState elementState = libraryEntry.getState(DartEntry.ELEMENT);
4035 if (elementState == CacheState.INVALID ||
4036 (isPriority && elementState == CacheState.FLUSHED)) {
4037 sources.add(source);
4038 return;
4039 }
4040 CacheState resolvedUnitState = dartEntry.getStateInLibrary(
4041 DartEntry.RESOLVED_UNIT, librarySource);
4042 if (resolvedUnitState == CacheState.INVALID ||
4043 (isPriority && resolvedUnitState == CacheState.FLUSHED)) {
4044 LibraryElement libraryElement =
4045 libraryEntry.getValue(DartEntry.ELEMENT);
4046 if (libraryElement != null) {
4047 sources.add(source);
4048 return;
4049 }
4050 }
4051 if (shouldErrorsBeAnalyzed(source, dartEntry)) {
4052 CacheState verificationErrorsState = dartEntry.getStateInLibrary(
4053 DartEntry.VERIFICATION_ERRORS, librarySource);
4054 if (verificationErrorsState == CacheState.INVALID ||
4055 (isPriority && verificationErrorsState == CacheState.FLUSHED)) {
4056 LibraryElement libraryElement =
4057 libraryEntry.getValue(DartEntry.ELEMENT);
4058 if (libraryElement != null) {
4059 sources.add(source);
4060 return;
4061 }
4062 }
4063 if (hintsEnabled) {
4064 CacheState hintsState =
4065 dartEntry.getStateInLibrary(DartEntry.HINTS, librarySource);
4066 if (hintsState == CacheState.INVALID ||
4067 (isPriority && hintsState == CacheState.FLUSHED)) {
4068 LibraryElement libraryElement =
4069 libraryEntry.getValue(DartEntry.ELEMENT);
4070 if (libraryElement != null) {
4071 sources.add(source);
4072 return;
4073 }
4074 }
4075 }
4076 if (lintsEnabled) {
4077 CacheState lintsState =
4078 dartEntry.getStateInLibrary(DartEntry.LINTS, librarySource);
4079 if (lintsState == CacheState.INVALID ||
4080 (isPriority && lintsState == CacheState.FLUSHED)) {
4081 LibraryElement libraryElement =
4082 libraryEntry.getValue(DartEntry.ELEMENT);
4083 if (libraryElement != null) {
4084 sources.add(source);
4085 return;
4086 }
4087 }
4088 }
4089 }
4090 }
4091 }
4092 } else if (sourceEntry is HtmlEntry) {
4093 HtmlEntry htmlEntry = sourceEntry;
4094 CacheState parsedUnitState = htmlEntry.getState(HtmlEntry.PARSED_UNIT);
4095 if (parsedUnitState == CacheState.INVALID ||
4096 (isPriority && parsedUnitState == CacheState.FLUSHED)) {
4097 sources.add(source);
4098 return;
4099 }
4100 CacheState resolvedUnitState =
4101 htmlEntry.getState(HtmlEntry.RESOLVED_UNIT);
4102 if (resolvedUnitState == CacheState.INVALID ||
4103 (isPriority && resolvedUnitState == CacheState.FLUSHED)) {
4104 sources.add(source);
4105 return;
4106 }
4107 }
4108 }
4109
4110 /**
4111 * Invalidate all of the resolution results computed by this context. The flag
4112 * [invalidateUris] should be `true` if the cached results of converting URIs
4113 * to source files should also be invalidated.
4114 */
4115 void _invalidateAllLocalResolutionInformation(bool invalidateUris) {
4116 HashMap<Source, List<Source>> oldPartMap =
4117 new HashMap<Source, List<Source>>();
4118 MapIterator<Source, SourceEntry> iterator = _privatePartition.iterator();
4119 while (iterator.moveNext()) {
4120 Source source = iterator.key;
4121 SourceEntry sourceEntry = iterator.value;
4122 if (sourceEntry is HtmlEntry) {
4123 HtmlEntry htmlEntry = sourceEntry;
4124 htmlEntry.invalidateAllResolutionInformation(invalidateUris);
4125 iterator.value = htmlEntry;
4126 _workManager.add(source, SourcePriority.HTML);
4127 } else if (sourceEntry is DartEntry) {
4128 DartEntry dartEntry = sourceEntry;
4129 oldPartMap[source] = dartEntry.getValue(DartEntry.INCLUDED_PARTS);
4130 dartEntry.invalidateAllResolutionInformation(invalidateUris);
4131 iterator.value = dartEntry;
4132 _workManager.add(source, _computePriority(dartEntry));
4133 }
4134 }
4135 _removeFromPartsUsingMap(oldPartMap);
4136 }
4137
4138 /**
4139 * In response to a change to at least one of the compilation units in the
4140 * library defined by the given [librarySource], invalidate any results that
4141 * are dependent on the result of resolving that library.
4142 *
4143 * <b>Note:</b> Any cache entries that were accessed before this method was
4144 * invoked must be re-accessed after this method returns.
4145 */
4146 void _invalidateLibraryResolution(Source librarySource) {
4147 // TODO(brianwilkerson) This could be optimized. There's no need to flush
4148 // all of these entries if the public namespace hasn't changed, which will
4149 // be a fairly common case. The question is whether we can afford the time
4150 // to compute the namespace to look for differences.
4151 DartEntry libraryEntry = _getReadableDartEntry(librarySource);
4152 if (libraryEntry != null) {
4153 List<Source> includedParts =
4154 libraryEntry.getValue(DartEntry.INCLUDED_PARTS);
4155 libraryEntry.invalidateAllResolutionInformation(false);
4156 _workManager.add(librarySource, SourcePriority.LIBRARY);
4157 for (Source partSource in includedParts) {
4158 SourceEntry partEntry = _cache.get(partSource);
4159 if (partEntry is DartEntry) {
4160 partEntry.invalidateAllResolutionInformation(false);
4161 }
4162 }
4163 }
4164 }
4165
4166 /**
4167 * Return `true` if the given [library] is, or depends on, 'dart:html'. The
4168 * [visitedLibraries] is a collection of the libraries that have been visited,
4169 * used to prevent infinite recursion.
4170 */
4171 bool _isClient(LibraryElement library, Source htmlSource,
4172 HashSet<LibraryElement> visitedLibraries) {
4173 if (visitedLibraries.contains(library)) {
4174 return false;
4175 }
4176 if (library.source == htmlSource) {
4177 return true;
4178 }
4179 visitedLibraries.add(library);
4180 for (LibraryElement imported in library.importedLibraries) {
4181 if (_isClient(imported, htmlSource, visitedLibraries)) {
4182 return true;
4183 }
4184 }
4185 for (LibraryElement exported in library.exportedLibraries) {
4186 if (_isClient(exported, htmlSource, visitedLibraries)) {
4187 return true;
4188 }
4189 }
4190 return false;
4191 }
4192
4193 bool _isTooBigHtmlSourceEntry(Source source, SourceEntry sourceEntry) =>
4194 false;
4195
4196 // /**
4197 // * Notify all of the analysis listeners that the given source is no longer i ncluded in the set of
4198 // * sources that are being analyzed.
4199 // *
4200 // * @param source the source that is no longer being analyzed
4201 // */
4202 // void _notifyExcludedSource(Source source) {
4203 // int count = _listeners.length;
4204 // for (int i = 0; i < count; i++) {
4205 // _listeners[i].excludedSource(this, source);
4206 // }
4207 // }
4208
4209 // /**
4210 // * Notify all of the analysis listeners that the given source is now include d in the set of
4211 // * sources that are being analyzed.
4212 // *
4213 // * @param source the source that is now being analyzed
4214 // */
4215 // void _notifyIncludedSource(Source source) {
4216 // int count = _listeners.length;
4217 // for (int i = 0; i < count; i++) {
4218 // _listeners[i].includedSource(this, source);
4219 // }
4220 // }
4221
4222 // /**
4223 // * Notify all of the analysis listeners that the given Dart source was parse d.
4224 // *
4225 // * @param source the source that was parsed
4226 // * @param unit the result of parsing the source
4227 // */
4228 // void _notifyParsedDart(Source source, CompilationUnit unit) {
4229 // int count = _listeners.length;
4230 // for (int i = 0; i < count; i++) {
4231 // _listeners[i].parsedDart(this, source, unit);
4232 // }
4233 // }
4234
4235 // /**
4236 // * Notify all of the analysis listeners that the given HTML source was parse d.
4237 // *
4238 // * @param source the source that was parsed
4239 // * @param unit the result of parsing the source
4240 // */
4241 // void _notifyParsedHtml(Source source, ht.HtmlUnit unit) {
4242 // int count = _listeners.length;
4243 // for (int i = 0; i < count; i++) {
4244 // _listeners[i].parsedHtml(this, source, unit);
4245 // }
4246 // }
4247
4248 // /**
4249 // * Notify all of the analysis listeners that the given Dart source was resol ved.
4250 // *
4251 // * @param source the source that was resolved
4252 // * @param unit the result of resolving the source
4253 // */
4254 // void _notifyResolvedDart(Source source, CompilationUnit unit) {
4255 // int count = _listeners.length;
4256 // for (int i = 0; i < count; i++) {
4257 // _listeners[i].resolvedDart(this, source, unit);
4258 // }
4259 // }
4260
4261 // /**
4262 // * Notify all of the analysis listeners that the given HTML source was resol ved.
4263 // *
4264 // * @param source the source that was resolved
4265 // * @param unit the result of resolving the source
4266 // */
4267 // void _notifyResolvedHtml(Source source, ht.HtmlUnit unit) {
4268 // int count = _listeners.length;
4269 // for (int i = 0; i < count; i++) {
4270 // _listeners[i].resolvedHtml(this, source, unit);
4271 // }
4272 // }
4273
4274 /**
4275 * Log the given debugging [message].
4276 */
4277 void _logInformation(String message) {
4278 AnalysisEngine.instance.logger.logInformation(message);
4279 }
4280
4281 /**
4282 * Notify all of the analysis listeners that a task is about to be performed.
4283 */
4284 void _notifyAboutToPerformTask(String taskDescription) {
4285 int count = _listeners.length;
4286 for (int i = 0; i < count; i++) {
4287 _listeners[i].aboutToPerformTask(this, taskDescription);
4288 }
4289 }
4290
4291 /**
4292 * Notify all of the analysis listeners that the errors associated with the
4293 * given [source] has been updated to the given [errors].
4294 */
4295 void _notifyErrors(
4296 Source source, List<AnalysisError> errors, LineInfo lineInfo) {
4297 int count = _listeners.length;
4298 for (int i = 0; i < count; i++) {
4299 _listeners[i].computedErrors(this, source, errors, lineInfo);
4300 }
4301 }
4302
4303 /**
4304 * Given that the given [source] (with the corresponding [sourceEntry]) has
4305 * been invalidated, invalidate all of the libraries that depend on it.
4306 */
4307 void _propagateInvalidation(Source source, SourceEntry sourceEntry) {
4308 if (sourceEntry is HtmlEntry) {
4309 HtmlEntry htmlEntry = sourceEntry;
4310 htmlEntry.modificationTime = getModificationStamp(source);
4311 htmlEntry.invalidateAllInformation();
4312 _cache.removedAst(source);
4313 _workManager.add(source, SourcePriority.HTML);
4314 } else if (sourceEntry is DartEntry) {
4315 List<Source> containingLibraries = getLibrariesContaining(source);
4316 List<Source> dependentLibraries = getLibrariesDependingOn(source);
4317 HashSet<Source> librariesToInvalidate = new HashSet<Source>();
4318 for (Source containingLibrary in containingLibraries) {
4319 _computeAllLibrariesDependingOn(
4320 containingLibrary, librariesToInvalidate);
4321 }
4322 for (Source dependentLibrary in dependentLibraries) {
4323 _computeAllLibrariesDependingOn(
4324 dependentLibrary, librariesToInvalidate);
4325 }
4326 for (Source library in librariesToInvalidate) {
4327 _invalidateLibraryResolution(library);
4328 }
4329 DartEntry dartEntry = _cache.get(source);
4330 _removeFromParts(source, dartEntry);
4331 dartEntry.modificationTime = getModificationStamp(source);
4332 dartEntry.invalidateAllInformation();
4333 _cache.removedAst(source);
4334 _workManager.add(source, SourcePriority.UNKNOWN);
4335 }
4336 // reset unit in the notification, it is out of date now
4337 ChangeNoticeImpl notice = _pendingNotices[source];
4338 if (notice != null) {
4339 notice.resolvedDartUnit = null;
4340 notice.resolvedHtmlUnit = null;
4341 }
4342 }
4343
4344 /**
4345 * Given a [dartEntry] and a [library] element, record the library element and
4346 * other information gleaned from the element in the cache entry.
4347 */
4348 void _recordElementData(DartEntry dartEntry, LibraryElement library,
4349 Source librarySource, Source htmlSource) {
4350 dartEntry.setValue(DartEntry.ELEMENT, library);
4351 dartEntry.setValue(DartEntry.IS_LAUNCHABLE, library.entryPoint != null);
4352 dartEntry.setValue(DartEntry.IS_CLIENT,
4353 _isClient(library, htmlSource, new HashSet<LibraryElement>()));
4354 }
4355
4356 /**
4357 * Record the results produced by performing a [task] and return the cache
4358 * entry associated with the results.
4359 */
4360 DartEntry _recordGenerateDartErrorsTask(GenerateDartErrorsTask task) {
4361 Source source = task.source;
4362 DartEntry dartEntry = _cache.get(source);
4363 Source librarySource = task.libraryElement.source;
4364 CaughtException thrownException = task.exception;
4365 if (thrownException != null) {
4366 dartEntry.recordVerificationErrorInLibrary(
4367 librarySource, thrownException);
4368 throw new AnalysisException('<rethrow>', thrownException);
4369 }
4370 dartEntry.setValueInLibrary(
4371 DartEntry.VERIFICATION_ERRORS, librarySource, task.errors);
4372 ChangeNoticeImpl notice = getNotice(source);
4373 LineInfo lineInfo = dartEntry.getValue(SourceEntry.LINE_INFO);
4374 notice.setErrors(dartEntry.allErrors, lineInfo);
4375 return dartEntry;
4376 }
4377
4378 /**
4379 * Record the results produced by performing a [task] and return the cache
4380 * entry associated with the results.
4381 */
4382 DartEntry _recordGenerateDartHintsTask(GenerateDartHintsTask task) {
4383 Source librarySource = task.libraryElement.source;
4384 CaughtException thrownException = task.exception;
4385 DartEntry libraryEntry = null;
4386 HashMap<Source, List<AnalysisError>> hintMap = task.hintMap;
4387 if (hintMap == null) {
4388 // We don't have any information about which sources to mark as invalid
4389 // other than the library source.
4390 DartEntry libraryEntry = _cache.get(librarySource);
4391 if (thrownException == null) {
4392 String message = "GenerateDartHintsTask returned a null hint map "
4393 "without throwing an exception: ${librarySource.fullName}";
4394 thrownException =
4395 new CaughtException(new AnalysisException(message), null);
4396 }
4397 libraryEntry.recordHintErrorInLibrary(librarySource, thrownException);
4398 throw new AnalysisException('<rethrow>', thrownException);
4399 }
4400 hintMap.forEach((Source unitSource, List<AnalysisError> hints) {
4401 DartEntry dartEntry = _cache.get(unitSource);
4402 if (unitSource == librarySource) {
4403 libraryEntry = dartEntry;
4404 }
4405 if (thrownException == null) {
4406 dartEntry.setValueInLibrary(DartEntry.HINTS, librarySource, hints);
4407 ChangeNoticeImpl notice = getNotice(unitSource);
4408 LineInfo lineInfo = dartEntry.getValue(SourceEntry.LINE_INFO);
4409 notice.setErrors(dartEntry.allErrors, lineInfo);
4410 } else {
4411 dartEntry.recordHintErrorInLibrary(librarySource, thrownException);
4412 }
4413 });
4414 if (thrownException != null) {
4415 throw new AnalysisException('<rethrow>', thrownException);
4416 }
4417 return libraryEntry;
4418 }
4419
4420 /**
4421 * Record the results produced by performing a [task] and return the cache
4422 * entry associated with the results.
4423 */
4424 DartEntry _recordGenerateDartLintsTask(GenerateDartLintsTask task) {
4425 Source librarySource = task.libraryElement.source;
4426 CaughtException thrownException = task.exception;
4427 DartEntry libraryEntry = null;
4428 HashMap<Source, List<AnalysisError>> lintMap = task.lintMap;
4429 if (lintMap == null) {
4430 // We don't have any information about which sources to mark as invalid
4431 // other than the library source.
4432 DartEntry libraryEntry = _cache.get(librarySource);
4433 if (thrownException == null) {
4434 String message = "GenerateDartLintsTask returned a null lint map "
4435 "without throwing an exception: ${librarySource.fullName}";
4436 thrownException =
4437 new CaughtException(new AnalysisException(message), null);
4438 }
4439 libraryEntry.recordLintErrorInLibrary(librarySource, thrownException);
4440 throw new AnalysisException('<rethrow>', thrownException);
4441 }
4442 lintMap.forEach((Source unitSource, List<AnalysisError> lints) {
4443 DartEntry dartEntry = _cache.get(unitSource);
4444 if (unitSource == librarySource) {
4445 libraryEntry = dartEntry;
4446 }
4447 if (thrownException == null) {
4448 dartEntry.setValueInLibrary(DartEntry.LINTS, librarySource, lints);
4449 ChangeNoticeImpl notice = getNotice(unitSource);
4450 LineInfo lineInfo = dartEntry.getValue(SourceEntry.LINE_INFO);
4451 notice.setErrors(dartEntry.allErrors, lineInfo);
4452 } else {
4453 dartEntry.recordLintErrorInLibrary(librarySource, thrownException);
4454 }
4455 });
4456 if (thrownException != null) {
4457 throw new AnalysisException('<rethrow>', thrownException);
4458 }
4459 return libraryEntry;
4460 }
4461
4462 /**
4463 * Record the results produced by performing a [task] and return the cache
4464 * entry associated with the results.
4465 */
4466 SourceEntry _recordGetContentsTask(GetContentTask task) {
4467 if (!task.isComplete) {
4468 return null;
4469 }
4470 Source source = task.source;
4471 SourceEntry sourceEntry = _cache.get(source);
4472 CaughtException thrownException = task.exception;
4473 if (thrownException != null) {
4474 sourceEntry.recordContentError(thrownException);
4475 {
4476 sourceEntry.setValue(SourceEntry.CONTENT_ERRORS, task.errors);
4477 ChangeNoticeImpl notice = getNotice(source);
4478 notice.setErrors(sourceEntry.allErrors, null);
4479 }
4480 _workManager.remove(source);
4481 throw new AnalysisException('<rethrow>', thrownException);
4482 }
4483 sourceEntry.modificationTime = task.modificationTime;
4484 sourceEntry.setValue(SourceEntry.CONTENT, task.content);
4485 return sourceEntry;
4486 }
4487
4488 /**
4489 * Record the results produced by performing a [task] and return the cache
4490 * entry associated with the results.
4491 */
4492 DartEntry _recordIncrementalAnalysisTaskResults(
4493 IncrementalAnalysisTask task) {
4494 CompilationUnit unit = task.compilationUnit;
4495 if (unit != null) {
4496 ChangeNoticeImpl notice = getNotice(task.source);
4497 notice.resolvedDartUnit = unit;
4498 _incrementalAnalysisCache =
4499 IncrementalAnalysisCache.cacheResult(task.cache, unit);
4500 }
4501 return null;
4502 }
4503
4504 /**
4505 * Record the results produced by performing a [task] and return the cache
4506 * entry associated with the results.
4507 */
4508 DartEntry _recordParseDartTaskResults(ParseDartTask task) {
4509 Source source = task.source;
4510 DartEntry dartEntry = _cache.get(source);
4511 _removeFromParts(source, dartEntry);
4512 CaughtException thrownException = task.exception;
4513 if (thrownException != null) {
4514 _removeFromParts(source, dartEntry);
4515 dartEntry.recordParseError(thrownException);
4516 _cache.removedAst(source);
4517 throw new AnalysisException('<rethrow>', thrownException);
4518 }
4519 if (task.hasNonPartOfDirective) {
4520 dartEntry.setValue(DartEntry.SOURCE_KIND, SourceKind.LIBRARY);
4521 dartEntry.containingLibrary = source;
4522 _workManager.add(source, SourcePriority.LIBRARY);
4523 } else if (task.hasPartOfDirective) {
4524 dartEntry.setValue(DartEntry.SOURCE_KIND, SourceKind.PART);
4525 dartEntry.removeContainingLibrary(source);
4526 _workManager.add(source, SourcePriority.NORMAL_PART);
4527 } else {
4528 // The file contains no directives.
4529 List<Source> containingLibraries = dartEntry.containingLibraries;
4530 if (containingLibraries.length > 1 ||
4531 (containingLibraries.length == 1 &&
4532 containingLibraries[0] != source)) {
4533 dartEntry.setValue(DartEntry.SOURCE_KIND, SourceKind.PART);
4534 dartEntry.removeContainingLibrary(source);
4535 _workManager.add(source, SourcePriority.NORMAL_PART);
4536 } else {
4537 dartEntry.setValue(DartEntry.SOURCE_KIND, SourceKind.LIBRARY);
4538 dartEntry.containingLibrary = source;
4539 _workManager.add(source, SourcePriority.LIBRARY);
4540 }
4541 }
4542 List<Source> newParts = task.includedSources;
4543 for (int i = 0; i < newParts.length; i++) {
4544 Source partSource = newParts[i];
4545 DartEntry partEntry = _getReadableDartEntry(partSource);
4546 if (partEntry != null && !identical(partEntry, dartEntry)) {
4547 // TODO(brianwilkerson) Change the kind of the "part" if it was marked
4548 // as a library and it has no directives.
4549 partEntry.addContainingLibrary(source);
4550 }
4551 }
4552 dartEntry.setValue(DartEntry.PARSED_UNIT, task.compilationUnit);
4553 dartEntry.setValue(DartEntry.PARSE_ERRORS, task.errors);
4554 dartEntry.setValue(DartEntry.EXPORTED_LIBRARIES, task.exportedSources);
4555 dartEntry.setValue(DartEntry.IMPORTED_LIBRARIES, task.importedSources);
4556 dartEntry.setValue(DartEntry.INCLUDED_PARTS, newParts);
4557 _cache.storedAst(source);
4558 ChangeNoticeImpl notice = getNotice(source);
4559 if (notice.resolvedDartUnit == null) {
4560 notice.parsedDartUnit = task.compilationUnit;
4561 }
4562 notice.setErrors(dartEntry.allErrors, task.lineInfo);
4563 // Verify that the incrementally parsed and resolved unit in the incremental
4564 // cache is structurally equivalent to the fully parsed unit
4565 _incrementalAnalysisCache = IncrementalAnalysisCache.verifyStructure(
4566 _incrementalAnalysisCache, source, task.compilationUnit);
4567 return dartEntry;
4568 }
4569
4570 /**
4571 * Record the results produced by performing a [task] and return the cache
4572 * entry associated with the results.
4573 */
4574 HtmlEntry _recordParseHtmlTaskResults(ParseHtmlTask task) {
4575 Source source = task.source;
4576 HtmlEntry htmlEntry = _cache.get(source);
4577 CaughtException thrownException = task.exception;
4578 if (thrownException != null) {
4579 htmlEntry.recordParseError(thrownException);
4580 _cache.removedAst(source);
4581 throw new AnalysisException('<rethrow>', thrownException);
4582 }
4583 LineInfo lineInfo = task.lineInfo;
4584 htmlEntry.setValue(SourceEntry.LINE_INFO, lineInfo);
4585 htmlEntry.setValue(HtmlEntry.PARSED_UNIT, task.htmlUnit);
4586 htmlEntry.setValue(HtmlEntry.PARSE_ERRORS, task.errors);
4587 htmlEntry.setValue(
4588 HtmlEntry.REFERENCED_LIBRARIES, task.referencedLibraries);
4589 _cache.storedAst(source);
4590 ChangeNoticeImpl notice = getNotice(source);
4591 notice.setErrors(htmlEntry.allErrors, lineInfo);
4592 return htmlEntry;
4593 }
4594
4595 /**
4596 * Record the results produced by performing a [task] and return the cache
4597 * entry associated with the results.
4598 */
4599 DartEntry _recordResolveDartUnitTaskResults(ResolveDartUnitTask task) {
4600 Source unitSource = task.source;
4601 DartEntry dartEntry = _cache.get(unitSource);
4602 Source librarySource = task.librarySource;
4603 CaughtException thrownException = task.exception;
4604 if (thrownException != null) {
4605 dartEntry.recordResolutionErrorInLibrary(librarySource, thrownException);
4606 _cache.removedAst(unitSource);
4607 throw new AnalysisException('<rethrow>', thrownException);
4608 }
4609 dartEntry.setValueInLibrary(
4610 DartEntry.RESOLVED_UNIT, librarySource, task.resolvedUnit);
4611 _cache.storedAst(unitSource);
4612 return dartEntry;
4613 }
4614
4615 /**
4616 * Record the results produced by performing a [task] and return the cache
4617 * entry associated with the results.
4618 */
4619 HtmlEntry _recordResolveHtmlTaskResults(ResolveHtmlTask task) {
4620 Source source = task.source;
4621 HtmlEntry htmlEntry = _cache.get(source);
4622 CaughtException thrownException = task.exception;
4623 if (thrownException != null) {
4624 htmlEntry.recordResolutionError(thrownException);
4625 _cache.removedAst(source);
4626 throw new AnalysisException('<rethrow>', thrownException);
4627 }
4628 htmlEntry.setState(HtmlEntry.PARSED_UNIT, CacheState.FLUSHED);
4629 htmlEntry.setValue(HtmlEntry.RESOLVED_UNIT, task.resolvedUnit);
4630 htmlEntry.setValue(HtmlEntry.ELEMENT, task.element);
4631 htmlEntry.setValue(HtmlEntry.RESOLUTION_ERRORS, task.resolutionErrors);
4632 _cache.storedAst(source);
4633 ChangeNoticeImpl notice = getNotice(source);
4634 notice.resolvedHtmlUnit = task.resolvedUnit;
4635 LineInfo lineInfo = htmlEntry.getValue(SourceEntry.LINE_INFO);
4636 notice.setErrors(htmlEntry.allErrors, lineInfo);
4637 return htmlEntry;
4638 }
4639
4640 /**
4641 * Record the results produced by performing a [task] and return the cache
4642 * entry associated with the results.
4643 */
4644 DartEntry _recordScanDartTaskResults(ScanDartTask task) {
4645 Source source = task.source;
4646 DartEntry dartEntry = _cache.get(source);
4647 CaughtException thrownException = task.exception;
4648 if (thrownException != null) {
4649 _removeFromParts(source, dartEntry);
4650 dartEntry.recordScanError(thrownException);
4651 _cache.removedAst(source);
4652 throw new AnalysisException('<rethrow>', thrownException);
4653 }
4654 LineInfo lineInfo = task.lineInfo;
4655 dartEntry.setValue(SourceEntry.LINE_INFO, lineInfo);
4656 dartEntry.setValue(DartEntry.TOKEN_STREAM, task.tokenStream);
4657 dartEntry.setValue(DartEntry.SCAN_ERRORS, task.errors);
4658 _cache.storedAst(source);
4659 ChangeNoticeImpl notice = getNotice(source);
4660 notice.setErrors(dartEntry.allErrors, lineInfo);
4661 return dartEntry;
4662 }
4663
4664 void _removeFromCache(Source source) {
4665 SourceEntry entry = _cache.remove(source);
4666 if (entry != null && !entry.explicitlyAdded) {
4667 _implicitAnalysisEventsController
4668 .add(new ImplicitAnalysisEvent(source, false));
4669 }
4670 }
4671
4672 /**
4673 * Remove the given [librarySource] from the list of containing libraries for
4674 * all of the parts referenced by the given [dartEntry].
4675 */
4676 void _removeFromParts(Source librarySource, DartEntry dartEntry) {
4677 List<Source> oldParts = dartEntry.getValue(DartEntry.INCLUDED_PARTS);
4678 for (int i = 0; i < oldParts.length; i++) {
4679 Source partSource = oldParts[i];
4680 DartEntry partEntry = _getReadableDartEntry(partSource);
4681 if (partEntry != null && !identical(partEntry, dartEntry)) {
4682 partEntry.removeContainingLibrary(librarySource);
4683 if (partEntry.containingLibraries.length == 0 && !exists(partSource)) {
4684 _removeFromCache(partSource);
4685 }
4686 }
4687 }
4688 }
4689
4690 /**
4691 * Remove the given libraries that are keys in the given map from the list of
4692 * containing libraries for each of the parts in the corresponding value.
4693 */
4694 void _removeFromPartsUsingMap(HashMap<Source, List<Source>> oldPartMap) {
4695 oldPartMap.forEach((Source librarySource, List<Source> oldParts) {
4696 for (int i = 0; i < oldParts.length; i++) {
4697 Source partSource = oldParts[i];
4698 if (partSource != librarySource) {
4699 DartEntry partEntry = _getReadableDartEntry(partSource);
4700 if (partEntry != null) {
4701 partEntry.removeContainingLibrary(librarySource);
4702 if (partEntry.containingLibraries.length == 0 &&
4703 !exists(partSource)) {
4704 _removeFromCache(partSource);
4705 }
4706 }
4707 }
4708 }
4709 });
4710 }
4711
4712 /**
4713 * Remove the given [source] from the priority order if it is in the list.
4714 */
4715 void _removeFromPriorityOrder(Source source) {
4716 int count = _priorityOrder.length;
4717 List<Source> newOrder = new List<Source>();
4718 for (int i = 0; i < count; i++) {
4719 if (_priorityOrder[i] != source) {
4720 newOrder.add(_priorityOrder[i]);
4721 }
4722 }
4723 if (newOrder.length < count) {
4724 analysisPriorityOrder = newOrder;
4725 }
4726 }
4727
4728 /**
4729 * Create an entry for the newly added [source] and invalidate any sources
4730 * that referenced the source before it existed.
4731 */
4732 void _sourceAvailable(Source source) {
4733 // TODO(brianwilkerson) This method needs to check whether the source was
4734 // previously being implicitly analyzed. If so, the cache entry needs to be
4735 // update to reflect the new status and an event needs to be generated to
4736 // inform clients that it is no longer being implicitly analyzed.
4737 SourceEntry sourceEntry = _cache.get(source);
4738 if (sourceEntry == null) {
4739 sourceEntry = _createSourceEntry(source, true);
4740 } else {
4741 _propagateInvalidation(source, sourceEntry);
4742 sourceEntry = _cache.get(source);
4743 }
4744 if (sourceEntry is HtmlEntry) {
4745 _workManager.add(source, SourcePriority.HTML);
4746 } else if (sourceEntry is DartEntry) {
4747 _workManager.add(source, _computePriority(sourceEntry));
4748 }
4749 }
4750
4751 /**
4752 * Invalidate the [source] that was changed and any sources that referenced
4753 * the source before it existed.
4754 */
4755 void _sourceChanged(Source source) {
4756 SourceEntry sourceEntry = _cache.get(source);
4757 // If the source is removed, we don't care about it.
4758 if (sourceEntry == null) {
4759 return;
4760 }
4761 // Check if the content of the source is the same as it was the last time.
4762 String sourceContent = sourceEntry.getValue(SourceEntry.CONTENT);
4763 if (sourceContent != null) {
4764 sourceEntry.setState(SourceEntry.CONTENT, CacheState.FLUSHED);
4765 try {
4766 TimestampedData<String> fileContents = getContents(source);
4767 if (fileContents.data == sourceContent) {
4768 return;
4769 }
4770 } catch (e) {}
4771 }
4772 // We have to invalidate the cache.
4773 _propagateInvalidation(source, sourceEntry);
4774 }
4775
4776 /**
4777 * Record that the give [source] has been deleted.
4778 */
4779 void _sourceDeleted(Source source) {
4780 SourceEntry sourceEntry = _cache.get(source);
4781 if (sourceEntry is HtmlEntry) {
4782 HtmlEntry htmlEntry = sourceEntry;
4783 htmlEntry.recordContentError(new CaughtException(
4784 new AnalysisException("This source was marked as being deleted"),
4785 null));
4786 } else if (sourceEntry is DartEntry) {
4787 DartEntry dartEntry = sourceEntry;
4788 HashSet<Source> libraries = new HashSet<Source>();
4789 for (Source librarySource in getLibrariesContaining(source)) {
4790 libraries.add(librarySource);
4791 for (Source dependentLibrary
4792 in getLibrariesDependingOn(librarySource)) {
4793 libraries.add(dependentLibrary);
4794 }
4795 }
4796 for (Source librarySource in libraries) {
4797 _invalidateLibraryResolution(librarySource);
4798 }
4799 dartEntry.recordContentError(new CaughtException(
4800 new AnalysisException("This source was marked as being deleted"),
4801 null));
4802 }
4803 _workManager.remove(source);
4804 _removeFromPriorityOrder(source);
4805 }
4806
4807 /**
4808 * Record that the given [source] has been removed.
4809 */
4810 void _sourceRemoved(Source source) {
4811 SourceEntry sourceEntry = _cache.get(source);
4812 if (sourceEntry is HtmlEntry) {} else if (sourceEntry is DartEntry) {
4813 HashSet<Source> libraries = new HashSet<Source>();
4814 for (Source librarySource in getLibrariesContaining(source)) {
4815 libraries.add(librarySource);
4816 for (Source dependentLibrary
4817 in getLibrariesDependingOn(librarySource)) {
4818 libraries.add(dependentLibrary);
4819 }
4820 }
4821 for (Source librarySource in libraries) {
4822 _invalidateLibraryResolution(librarySource);
4823 }
4824 }
4825 _removeFromCache(source);
4826 _workManager.remove(source);
4827 _removeFromPriorityOrder(source);
4828 }
4829
4830 /**
4831 * TODO(scheglov) A hackish, limited incremental resolution implementation.
4832 */
4833 bool _tryPoorMansIncrementalResolution(Source unitSource, String newCode) {
4834 return PerformanceStatistics.incrementalAnalysis.makeCurrentWhile(() {
4835 incrementalResolutionValidation_lastUnitSource = null;
4836 incrementalResolutionValidation_lastLibrarySource = null;
4837 incrementalResolutionValidation_lastUnit = null;
4838 // prepare the entry
4839 DartEntry dartEntry = _cache.get(unitSource);
4840 if (dartEntry == null) {
4841 return false;
4842 }
4843 // prepare the (only) library source
4844 List<Source> librarySources = getLibrariesContaining(unitSource);
4845 if (librarySources.length != 1) {
4846 return false;
4847 }
4848 Source librarySource = librarySources[0];
4849 // prepare the library element
4850 LibraryElement libraryElement = getLibraryElement(librarySource);
4851 if (libraryElement == null) {
4852 return false;
4853 }
4854 // prepare the existing unit
4855 CompilationUnit oldUnit =
4856 getResolvedCompilationUnit2(unitSource, librarySource);
4857 if (oldUnit == null) {
4858 return false;
4859 }
4860 // do resolution
4861 Stopwatch perfCounter = new Stopwatch()..start();
4862 PoorMansIncrementalResolver resolver = new PoorMansIncrementalResolver(
4863 typeProvider,
4864 unitSource,
4865 getReadableSourceEntryOrNull(unitSource),
4866 null,
4867 null,
4868 oldUnit,
4869 analysisOptions.incrementalApi,
4870 analysisOptions);
4871 bool success = resolver.resolve(newCode);
4872 AnalysisEngine.instance.instrumentationService.logPerformance(
4873 AnalysisPerformanceKind.INCREMENTAL,
4874 perfCounter,
4875 'success=$success,context_id=$_id,code_length=${newCode.length}');
4876 if (!success) {
4877 return false;
4878 }
4879 // if validation, remember the result, but throw it away
4880 if (analysisOptions.incrementalValidation) {
4881 incrementalResolutionValidation_lastUnitSource = oldUnit.element.source;
4882 incrementalResolutionValidation_lastLibrarySource =
4883 oldUnit.element.library.source;
4884 incrementalResolutionValidation_lastUnit = oldUnit;
4885 return false;
4886 }
4887 // prepare notice
4888 {
4889 LineInfo lineInfo = getLineInfo(unitSource);
4890 ChangeNoticeImpl notice = getNotice(unitSource);
4891 notice.resolvedDartUnit = oldUnit;
4892 notice.setErrors(dartEntry.allErrors, lineInfo);
4893 }
4894 // OK
4895 return true;
4896 });
4897 }
4898
4899 void _validateLastIncrementalResolutionResult() {
4900 if (incrementalResolutionValidation_lastUnitSource == null ||
4901 incrementalResolutionValidation_lastLibrarySource == null ||
4902 incrementalResolutionValidation_lastUnit == null) {
4903 return;
4904 }
4905 CompilationUnit fullUnit = getResolvedCompilationUnit2(
4906 incrementalResolutionValidation_lastUnitSource,
4907 incrementalResolutionValidation_lastLibrarySource);
4908 if (fullUnit != null) {
4909 try {
4910 assertSameResolution(
4911 incrementalResolutionValidation_lastUnit, fullUnit);
4912 } on IncrementalResolutionMismatch catch (mismatch, stack) {
4913 String failure = mismatch.message;
4914 String message =
4915 'Incremental resolution mismatch:\n$failure\nat\n$stack';
4916 AnalysisEngine.instance.logger.logError(message);
4917 }
4918 }
4919 incrementalResolutionValidation_lastUnitSource = null;
4920 incrementalResolutionValidation_lastLibrarySource = null;
4921 incrementalResolutionValidation_lastUnit = null;
4922 }
4923 }
4924
4925 /**
4926 * An object used by an analysis context to record the results of a task.
4927 */
4928 class AnalysisContextImpl_AnalysisTaskResultRecorder
4929 implements AnalysisTaskVisitor<SourceEntry> {
4930 final AnalysisContextImpl AnalysisContextImpl_this;
4931
4932 AnalysisContextImpl_AnalysisTaskResultRecorder(this.AnalysisContextImpl_this);
4933
4934 @override
4935 DartEntry visitGenerateDartErrorsTask(GenerateDartErrorsTask task) =>
4936 AnalysisContextImpl_this._recordGenerateDartErrorsTask(task);
4937
4938 @override
4939 DartEntry visitGenerateDartHintsTask(GenerateDartHintsTask task) =>
4940 AnalysisContextImpl_this._recordGenerateDartHintsTask(task);
4941
4942 @override
4943 DartEntry visitGenerateDartLintsTask(GenerateDartLintsTask task) =>
4944 AnalysisContextImpl_this._recordGenerateDartLintsTask(task);
4945
4946 @override
4947 SourceEntry visitGetContentTask(GetContentTask task) =>
4948 AnalysisContextImpl_this._recordGetContentsTask(task);
4949
4950 @override
4951 DartEntry visitIncrementalAnalysisTask(IncrementalAnalysisTask task) =>
4952 AnalysisContextImpl_this._recordIncrementalAnalysisTaskResults(task);
4953
4954 @override
4955 DartEntry visitParseDartTask(ParseDartTask task) =>
4956 AnalysisContextImpl_this._recordParseDartTaskResults(task);
4957
4958 @override
4959 HtmlEntry visitParseHtmlTask(ParseHtmlTask task) =>
4960 AnalysisContextImpl_this._recordParseHtmlTaskResults(task);
4961
4962 @override
4963 DartEntry visitResolveDartLibraryCycleTask(
4964 ResolveDartLibraryCycleTask task) =>
4965 AnalysisContextImpl_this.recordResolveDartLibraryCycleTaskResults(task);
4966
4967 @override
4968 DartEntry visitResolveDartLibraryTask(ResolveDartLibraryTask task) =>
4969 AnalysisContextImpl_this.recordResolveDartLibraryTaskResults(task);
4970
4971 @override
4972 DartEntry visitResolveDartUnitTask(ResolveDartUnitTask task) =>
4973 AnalysisContextImpl_this._recordResolveDartUnitTaskResults(task);
4974
4975 @override
4976 HtmlEntry visitResolveHtmlTask(ResolveHtmlTask task) =>
4977 AnalysisContextImpl_this._recordResolveHtmlTaskResults(task);
4978
4979 @override
4980 DartEntry visitScanDartTask(ScanDartTask task) =>
4981 AnalysisContextImpl_this._recordScanDartTaskResults(task);
4982 }
4983
4984 class AnalysisContextImpl_ContextRetentionPolicy
4985 implements CacheRetentionPolicy {
4986 final AnalysisContextImpl AnalysisContextImpl_this;
4987
4988 AnalysisContextImpl_ContextRetentionPolicy(this.AnalysisContextImpl_this);
4989
4990 @override
4991 RetentionPriority getAstPriority(Source source, SourceEntry sourceEntry) {
4992 int priorityCount = AnalysisContextImpl_this._priorityOrder.length;
4993 for (int i = 0; i < priorityCount; i++) {
4994 if (source == AnalysisContextImpl_this._priorityOrder[i]) {
4995 return RetentionPriority.HIGH;
4996 }
4997 }
4998 if (AnalysisContextImpl_this._neededForResolution != null &&
4999 AnalysisContextImpl_this._neededForResolution.contains(source)) {
5000 return RetentionPriority.HIGH;
5001 }
5002 if (sourceEntry is DartEntry) {
5003 DartEntry dartEntry = sourceEntry;
5004 if (_astIsNeeded(dartEntry)) {
5005 return RetentionPriority.MEDIUM;
5006 }
5007 }
5008 return RetentionPriority.LOW;
5009 }
5010
5011 bool _astIsNeeded(DartEntry dartEntry) =>
5012 dartEntry.hasInvalidData(DartEntry.HINTS) ||
5013 dartEntry.hasInvalidData(DartEntry.LINTS) ||
5014 dartEntry.hasInvalidData(DartEntry.VERIFICATION_ERRORS) ||
5015 dartEntry.hasInvalidData(DartEntry.RESOLUTION_ERRORS);
5016 }
5017
5018 /**
5019 * An object used to construct a list of the libraries that must be resolved
5020 * together in order to resolve any one of the libraries.
5021 */
5022 class AnalysisContextImpl_CycleBuilder {
5023 final AnalysisContextImpl AnalysisContextImpl_this;
5024
5025 /**
5026 * A table mapping the sources of the defining compilation units of libraries
5027 * to the representation of the library that has the information needed to
5028 * resolve the library.
5029 */
5030 HashMap<Source, ResolvableLibrary> _libraryMap =
5031 new HashMap<Source, ResolvableLibrary>();
5032
5033 /**
5034 * The dependency graph used to compute the libraries in the cycle.
5035 */
5036 DirectedGraph<ResolvableLibrary> _dependencyGraph;
5037
5038 /**
5039 * A list containing the libraries that are ready to be resolved.
5040 */
5041 List<ResolvableLibrary> _librariesInCycle;
5042
5043 /**
5044 * The analysis task that needs to be performed before the cycle of libraries
5045 * can be resolved, or `null` if the libraries are ready to be resolved.
5046 */
5047 AnalysisContextImpl_TaskData _taskData;
5048
5049 /**
5050 * Initialize a newly created cycle builder.
5051 */
5052 AnalysisContextImpl_CycleBuilder(this.AnalysisContextImpl_this) : super();
5053
5054 /**
5055 * Return a list containing the libraries that are ready to be resolved
5056 * (assuming that [getTaskData] returns `null`).
5057 */
5058 List<ResolvableLibrary> get librariesInCycle => _librariesInCycle;
5059
5060 /**
5061 * Return a representation of an analysis task that needs to be performed
5062 * before the cycle of libraries can be resolved, or `null` if the libraries
5063 * are ready to be resolved.
5064 */
5065 AnalysisContextImpl_TaskData get taskData => _taskData;
5066
5067 /**
5068 * Compute a list of the libraries that need to be resolved together in orde
5069 * to resolve the given [librarySource].
5070 */
5071 void computeCycleContaining(Source librarySource) {
5072 //
5073 // Create the object representing the library being resolved.
5074 //
5075 ResolvableLibrary targetLibrary = _createLibrary(librarySource);
5076 //
5077 // Compute the set of libraries that need to be resolved together.
5078 //
5079 _dependencyGraph = new DirectedGraph<ResolvableLibrary>();
5080 _computeLibraryDependencies(targetLibrary);
5081 if (_taskData != null) {
5082 return;
5083 }
5084 _librariesInCycle = _dependencyGraph.findCycleContaining(targetLibrary);
5085 //
5086 // Ensure that all of the data needed to resolve them has been computed.
5087 //
5088 _ensureImportsAndExports();
5089 if (_taskData != null) {
5090 // At least one imported library needs to be resolved before the target
5091 // library.
5092 AnalysisTask task = _taskData.task;
5093 if (task is ResolveDartLibraryTask) {
5094 AnalysisContextImpl_this._workManager
5095 .addFirst(task.librarySource, SourcePriority.LIBRARY);
5096 }
5097 return;
5098 }
5099 _computePartsInCycle(librarySource);
5100 if (_taskData != null) {
5101 // At least one part needs to be parsed.
5102 return;
5103 }
5104 // All of the AST's necessary to perform a resolution of the library cycle
5105 // have been gathered, so it is no longer necessary to retain them in the
5106 // cache.
5107 AnalysisContextImpl_this._neededForResolution = null;
5108 }
5109
5110 bool _addDependency(ResolvableLibrary dependant, Source dependency,
5111 List<ResolvableLibrary> dependencyList) {
5112 if (dependant.librarySource == dependency) {
5113 // Don't add a dependency of a library on itself; there's no point.
5114 return true;
5115 }
5116 ResolvableLibrary importedLibrary = _libraryMap[dependency];
5117 if (importedLibrary == null) {
5118 importedLibrary = _createLibraryOrNull(dependency);
5119 if (importedLibrary != null) {
5120 _computeLibraryDependencies(importedLibrary);
5121 if (_taskData != null) {
5122 return false;
5123 }
5124 }
5125 }
5126 if (importedLibrary != null) {
5127 if (dependencyList != null) {
5128 dependencyList.add(importedLibrary);
5129 }
5130 _dependencyGraph.addEdge(dependant, importedLibrary);
5131 }
5132 return true;
5133 }
5134
5135 /**
5136 * Recursively traverse the libraries reachable from the given [library],
5137 * creating instances of the class [Library] to represent them, and record the
5138 * references in the library objects.
5139 *
5140 * Throws an [AnalysisException] if some portion of the library graph could
5141 * not be traversed.
5142 */
5143 void _computeLibraryDependencies(ResolvableLibrary library) {
5144 Source librarySource = library.librarySource;
5145 DartEntry dartEntry =
5146 AnalysisContextImpl_this._getReadableDartEntry(librarySource);
5147 List<Source> importedSources =
5148 _getSources(librarySource, dartEntry, DartEntry.IMPORTED_LIBRARIES);
5149 if (_taskData != null) {
5150 return;
5151 }
5152 List<Source> exportedSources =
5153 _getSources(librarySource, dartEntry, DartEntry.EXPORTED_LIBRARIES);
5154 if (_taskData != null) {
5155 return;
5156 }
5157 _computeLibraryDependenciesFromDirectives(
5158 library, importedSources, exportedSources);
5159 }
5160
5161 /**
5162 * Recursively traverse the libraries reachable from the given [library],
5163 * creating instances of the class [Library] to represent them, and record the
5164 * references in the library objects. The [importedSources] is a list
5165 * containing the sources that are imported into the given library. The
5166 * [exportedSources] is a list containing the sources that are exported from
5167 * the given library.
5168 */
5169 void _computeLibraryDependenciesFromDirectives(ResolvableLibrary library,
5170 List<Source> importedSources, List<Source> exportedSources) {
5171 int importCount = importedSources.length;
5172 List<ResolvableLibrary> importedLibraries = new List<ResolvableLibrary>();
5173 bool explicitlyImportsCore = false;
5174 bool importsAsync = false;
5175 for (int i = 0; i < importCount; i++) {
5176 Source importedSource = importedSources[i];
5177 if (importedSource == AnalysisContextImpl_this._coreLibrarySource) {
5178 explicitlyImportsCore = true;
5179 } else if (importedSource ==
5180 AnalysisContextImpl_this._asyncLibrarySource) {
5181 importsAsync = true;
5182 }
5183 if (!_addDependency(library, importedSource, importedLibraries)) {
5184 return;
5185 }
5186 }
5187 library.explicitlyImportsCore = explicitlyImportsCore;
5188 if (!explicitlyImportsCore) {
5189 if (!_addDependency(library, AnalysisContextImpl_this._coreLibrarySource,
5190 importedLibraries)) {
5191 return;
5192 }
5193 }
5194 if (!importsAsync) {
5195 // Add a dependency on async to ensure that the Future element will be
5196 // built before we generate errors and warnings for async methods. Also
5197 // include it in importedLibraries, so that it will be picked up by
5198 // LibraryResolver2._buildLibraryMap().
5199 // TODO(paulberry): this is a bit of a hack, since the async library
5200 // isn't actually being imported. Also, it's not clear whether it should
5201 // be necessary: in theory, dart:core already (indirectly) imports
5202 // dart:async, so if core has been built, async should have been built
5203 // too. However, removing this code causes unit test failures.
5204 if (!_addDependency(library, AnalysisContextImpl_this._asyncLibrarySource,
5205 importedLibraries)) {
5206 return;
5207 }
5208 }
5209 library.importedLibraries = importedLibraries;
5210 int exportCount = exportedSources.length;
5211 if (exportCount > 0) {
5212 List<ResolvableLibrary> exportedLibraries = new List<ResolvableLibrary>();
5213 for (int i = 0; i < exportCount; i++) {
5214 Source exportedSource = exportedSources[i];
5215 if (!_addDependency(library, exportedSource, exportedLibraries)) {
5216 return;
5217 }
5218 }
5219 library.exportedLibraries = exportedLibraries;
5220 }
5221 }
5222
5223 /**
5224 * Gather the resolvable AST structures for each of the compilation units in
5225 * each of the libraries in the cycle. This is done in two phases: first we
5226 * ensure that we have cached an AST structure for each compilation unit, then
5227 * we gather them. We split the work this way because getting the AST
5228 * structures can change the state of the cache in such a way that we would
5229 * have more work to do if any compilation unit didn't have a resolvable AST
5230 * structure.
5231 */
5232 void _computePartsInCycle(Source librarySource) {
5233 int count = _librariesInCycle.length;
5234 List<CycleBuilder_LibraryPair> libraryData =
5235 new List<CycleBuilder_LibraryPair>();
5236 for (int i = 0; i < count; i++) {
5237 ResolvableLibrary library = _librariesInCycle[i];
5238 libraryData.add(new CycleBuilder_LibraryPair(
5239 library, _ensurePartsInLibrary(library)));
5240 }
5241 AnalysisContextImpl_this._neededForResolution = _gatherSources(libraryData);
5242 if (AnalysisContextImpl._TRACE_PERFORM_TASK) {
5243 print(
5244 " preserve resolution data for ${AnalysisContextImpl_this._neededForR esolution.length} sources while resolving ${librarySource.fullName}");
5245 }
5246 if (_taskData != null) {
5247 return;
5248 }
5249 for (int i = 0; i < count; i++) {
5250 _computePartsInLibrary(libraryData[i]);
5251 }
5252 }
5253
5254 /**
5255 * Gather the resolvable compilation units for each of the compilation units
5256 * in the library represented by the [libraryPair].
5257 */
5258 void _computePartsInLibrary(CycleBuilder_LibraryPair libraryPair) {
5259 ResolvableLibrary library = libraryPair.library;
5260 List<CycleBuilder_SourceEntryPair> entryPairs = libraryPair.entryPairs;
5261 int count = entryPairs.length;
5262 List<ResolvableCompilationUnit> units =
5263 new List<ResolvableCompilationUnit>(count);
5264 for (int i = 0; i < count; i++) {
5265 CycleBuilder_SourceEntryPair entryPair = entryPairs[i];
5266 Source source = entryPair.source;
5267 DartEntry dartEntry = entryPair.entry;
5268 units[i] = new ResolvableCompilationUnit(
5269 source, dartEntry.resolvableCompilationUnit);
5270 }
5271 library.resolvableCompilationUnits = units;
5272 }
5273
5274 /**
5275 * Create an object to represent the information about the library defined by
5276 * the compilation unit with the given [librarySource].
5277 */
5278 ResolvableLibrary _createLibrary(Source librarySource) {
5279 ResolvableLibrary library = new ResolvableLibrary(librarySource);
5280 SourceEntry sourceEntry =
5281 AnalysisContextImpl_this._cache.get(librarySource);
5282 if (sourceEntry is DartEntry) {
5283 LibraryElementImpl libraryElement =
5284 sourceEntry.getValue(DartEntry.ELEMENT) as LibraryElementImpl;
5285 if (libraryElement != null) {
5286 library.libraryElement = libraryElement;
5287 }
5288 }
5289 _libraryMap[librarySource] = library;
5290 return library;
5291 }
5292
5293 /**
5294 * Create an object to represent the information about the library defined by
5295 * the compilation unit with the given [librarySource].
5296 */
5297 ResolvableLibrary _createLibraryOrNull(Source librarySource) {
5298 ResolvableLibrary library = new ResolvableLibrary(librarySource);
5299 SourceEntry sourceEntry =
5300 AnalysisContextImpl_this._cache.get(librarySource);
5301 if (sourceEntry is DartEntry) {
5302 LibraryElementImpl libraryElement =
5303 sourceEntry.getValue(DartEntry.ELEMENT) as LibraryElementImpl;
5304 if (libraryElement != null) {
5305 library.libraryElement = libraryElement;
5306 }
5307 }
5308 _libraryMap[librarySource] = library;
5309 return library;
5310 }
5311
5312 /**
5313 * Ensure that the given [library] has an element model built for it. If
5314 * another task needs to be executed first in order to build the element
5315 * model, that task is placed in [taskData].
5316 */
5317 void _ensureElementModel(ResolvableLibrary library) {
5318 Source librarySource = library.librarySource;
5319 DartEntry libraryEntry =
5320 AnalysisContextImpl_this._getReadableDartEntry(librarySource);
5321 if (libraryEntry != null &&
5322 libraryEntry.getState(DartEntry.PARSED_UNIT) != CacheState.ERROR) {
5323 AnalysisContextImpl_this._workManager
5324 .addFirst(librarySource, SourcePriority.LIBRARY);
5325 if (_taskData == null) {
5326 _taskData = AnalysisContextImpl_this._createResolveDartLibraryTask(
5327 librarySource, libraryEntry);
5328 }
5329 }
5330 }
5331
5332 /**
5333 * Ensure that all of the libraries that are exported by the given [library]
5334 * (but are not themselves in the cycle) have element models built for them.
5335 * If another task needs to be executed first in order to build the element
5336 * model, that task is placed in [taskData].
5337 */
5338 void _ensureExports(
5339 ResolvableLibrary library, HashSet<Source> visitedLibraries) {
5340 List<ResolvableLibrary> dependencies = library.exports;
5341 int dependencyCount = dependencies.length;
5342 for (int i = 0; i < dependencyCount; i++) {
5343 ResolvableLibrary dependency = dependencies[i];
5344 if (!_librariesInCycle.contains(dependency) &&
5345 visitedLibraries.add(dependency.librarySource)) {
5346 if (dependency.libraryElement == null) {
5347 _ensureElementModel(dependency);
5348 } else {
5349 _ensureExports(dependency, visitedLibraries);
5350 }
5351 if (_taskData != null) {
5352 return;
5353 }
5354 }
5355 }
5356 }
5357
5358 /**
5359 * Ensure that all of the libraries that are exported by the given [library]
5360 * (but are not themselves in the cycle) have element models built for them.
5361 * If another task needs to be executed first in order to build the element
5362 * model, that task is placed in [taskData].
5363 */
5364 void _ensureImports(ResolvableLibrary library) {
5365 List<ResolvableLibrary> dependencies = library.imports;
5366 int dependencyCount = dependencies.length;
5367 for (int i = 0; i < dependencyCount; i++) {
5368 ResolvableLibrary dependency = dependencies[i];
5369 if (!_librariesInCycle.contains(dependency) &&
5370 dependency.libraryElement == null) {
5371 _ensureElementModel(dependency);
5372 if (_taskData != null) {
5373 return;
5374 }
5375 }
5376 }
5377 }
5378
5379 /**
5380 * Ensure that all of the libraries that are either imported or exported by
5381 * libraries in the cycle (but are not themselves in the cycle) have element
5382 * models built for them.
5383 */
5384 void _ensureImportsAndExports() {
5385 HashSet<Source> visitedLibraries = new HashSet<Source>();
5386 int libraryCount = _librariesInCycle.length;
5387 for (int i = 0; i < libraryCount; i++) {
5388 ResolvableLibrary library = _librariesInCycle[i];
5389 _ensureImports(library);
5390 if (_taskData != null) {
5391 return;
5392 }
5393 _ensureExports(library, visitedLibraries);
5394 if (_taskData != null) {
5395 return;
5396 }
5397 }
5398 }
5399
5400 /**
5401 * Ensure that there is a resolvable compilation unit available for all of the
5402 * compilation units in the given [library].
5403 */
5404 List<CycleBuilder_SourceEntryPair> _ensurePartsInLibrary(
5405 ResolvableLibrary library) {
5406 List<CycleBuilder_SourceEntryPair> pairs =
5407 new List<CycleBuilder_SourceEntryPair>();
5408 Source librarySource = library.librarySource;
5409 DartEntry libraryEntry =
5410 AnalysisContextImpl_this._getReadableDartEntry(librarySource);
5411 if (libraryEntry == null) {
5412 throw new AnalysisException(
5413 "Cannot find entry for ${librarySource.fullName}");
5414 } else if (libraryEntry.getState(DartEntry.PARSED_UNIT) ==
5415 CacheState.ERROR) {
5416 String message =
5417 "Cannot compute parsed unit for ${librarySource.fullName}";
5418 CaughtException exception = libraryEntry.exception;
5419 if (exception == null) {
5420 throw new AnalysisException(message);
5421 }
5422 throw new AnalysisException(
5423 message, new CaughtException(exception, null));
5424 }
5425 _ensureResolvableCompilationUnit(librarySource, libraryEntry);
5426 pairs.add(new CycleBuilder_SourceEntryPair(librarySource, libraryEntry));
5427 List<Source> partSources =
5428 _getSources(librarySource, libraryEntry, DartEntry.INCLUDED_PARTS);
5429 int count = partSources.length;
5430 for (int i = 0; i < count; i++) {
5431 Source partSource = partSources[i];
5432 DartEntry partEntry =
5433 AnalysisContextImpl_this._getReadableDartEntry(partSource);
5434 if (partEntry != null &&
5435 partEntry.getState(DartEntry.PARSED_UNIT) != CacheState.ERROR) {
5436 _ensureResolvableCompilationUnit(partSource, partEntry);
5437 pairs.add(new CycleBuilder_SourceEntryPair(partSource, partEntry));
5438 }
5439 }
5440 return pairs;
5441 }
5442
5443 /**
5444 * Ensure that there is a resolvable compilation unit available for the given
5445 * [source].
5446 */
5447 void _ensureResolvableCompilationUnit(Source source, DartEntry dartEntry) {
5448 // The entry will be null if the source represents a non-Dart file.
5449 if (dartEntry != null && !dartEntry.hasResolvableCompilationUnit) {
5450 if (_taskData == null) {
5451 _taskData =
5452 AnalysisContextImpl_this._createParseDartTask(source, dartEntry);
5453 }
5454 }
5455 }
5456
5457 HashSet<Source> _gatherSources(List<CycleBuilder_LibraryPair> libraryData) {
5458 int libraryCount = libraryData.length;
5459 HashSet<Source> sources = new HashSet<Source>();
5460 for (int i = 0; i < libraryCount; i++) {
5461 List<CycleBuilder_SourceEntryPair> entryPairs = libraryData[i].entryPairs;
5462 int entryCount = entryPairs.length;
5463 for (int j = 0; j < entryCount; j++) {
5464 sources.add(entryPairs[j].source);
5465 }
5466 }
5467 return sources;
5468 }
5469
5470 /**
5471 * Return the sources described by the given [descriptor].
5472 */
5473 List<Source> _getSources(Source source, DartEntry dartEntry,
5474 DataDescriptor<List<Source>> descriptor) {
5475 if (dartEntry == null) {
5476 return Source.EMPTY_LIST;
5477 }
5478 CacheState exportState = dartEntry.getState(descriptor);
5479 if (exportState == CacheState.ERROR) {
5480 return Source.EMPTY_LIST;
5481 } else if (exportState != CacheState.VALID) {
5482 if (_taskData == null) {
5483 _taskData =
5484 AnalysisContextImpl_this._createParseDartTask(source, dartEntry);
5485 }
5486 return Source.EMPTY_LIST;
5487 }
5488 return dartEntry.getValue(descriptor);
5489 }
5490 }
5491
5492 /**
5493 * Information about the next task to be performed. Each data has an implicit
5494 * associated source: the source that might need to be analyzed. There are
5495 * essentially three states that can be represented:
5496 *
5497 * * If [getTask] returns a non-`null` value, then that is the task that should
5498 * be executed to further analyze the associated source.
5499 * * Otherwise, if [isBlocked] returns `true`, then there is no work that can be
5500 * done, but analysis for the associated source is not complete.
5501 * * Otherwise, [getDependentSource] should return a source that needs to be
5502 * analyzed before the analysis of the associated source can be completed.
5503 */
5504 class AnalysisContextImpl_TaskData {
5505 /**
5506 * The task that is to be performed.
5507 */
5508 final AnalysisTask task;
5509
5510 /**
5511 * A flag indicating whether the associated source is blocked waiting for its
5512 * contents to be loaded.
5513 */
5514 final bool _blocked;
5515
5516 /**
5517 * Initialize a newly created data holder.
5518 */
5519 AnalysisContextImpl_TaskData(this.task, this._blocked);
5520
5521 /**
5522 * Return `true` if the associated source is blocked waiting for its contents
5523 * to be loaded.
5524 */
5525 bool get isBlocked => _blocked;
5526
5527 @override
5528 String toString() {
5529 if (task == null) {
5530 return "blocked: $_blocked";
5531 }
5532 return task.toString();
5533 }
5534 }
5535
5536 /**
5537 * Statistics and information about a single [AnalysisContext].
5538 */
5539 abstract class AnalysisContextStatistics {
5540 /**
5541 * Return the statistics for each kind of cached data.
5542 */
5543 List<AnalysisContextStatistics_CacheRow> get cacheRows;
5544
5545 /**
5546 * Return the exceptions that caused some entries to have a state of
5547 * [CacheState.ERROR].
5548 */
5549 List<CaughtException> get exceptions;
5550
5551 /**
5552 * Return information about each of the partitions in the cache.
5553 */
5554 List<AnalysisContextStatistics_PartitionData> get partitionData;
5555
5556 /**
5557 * Return a list containing all of the sources in the cache.
5558 */
5559 List<Source> get sources;
5560 }
5561
5562 /**
5563 * Information about single piece of data in the cache.
5564 */
5565 abstract class AnalysisContextStatistics_CacheRow {
5566 /**
5567 * List of possible states which can be queried.
5568 */
5569 static const List<CacheState> STATES = const <CacheState>[
5570 CacheState.ERROR,
5571 CacheState.FLUSHED,
5572 CacheState.IN_PROCESS,
5573 CacheState.INVALID,
5574 CacheState.VALID
5575 ];
5576
5577 /**
5578 * Return the number of entries whose state is [CacheState.ERROR].
5579 */
5580 int get errorCount;
5581
5582 /**
5583 * Return the number of entries whose state is [CacheState.FLUSHED].
5584 */
5585 int get flushedCount;
5586
5587 /**
5588 * Return the number of entries whose state is [CacheState.IN_PROCESS].
5589 */
5590 int get inProcessCount;
5591
5592 /**
5593 * Return the number of entries whose state is [CacheState.INVALID].
5594 */
5595 int get invalidCount;
5596
5597 /**
5598 * Return the name of the data represented by this object.
5599 */
5600 String get name;
5601
5602 /**
5603 * Return the number of entries whose state is [CacheState.VALID].
5604 */
5605 int get validCount;
5606
5607 /**
5608 * Return the number of entries whose state is [state].
5609 */
5610 int getCount(CacheState state);
5611 }
5612
5613 /**
5614 * Information about a single partition in the cache.
5615 */
5616 abstract class AnalysisContextStatistics_PartitionData {
5617 /**
5618 * Return the number of entries in the partition that have an AST structure in
5619 * one state or another.
5620 */
5621 int get astCount;
5622
5623 /**
5624 * Return the total number of entries in the partition.
5625 */
5626 int get totalCount;
5627 }
5628
5629 /**
5630 * Implementation of the [AnalysisContextStatistics].
5631 */
5632 class AnalysisContextStatisticsImpl implements AnalysisContextStatistics {
5633 Map<String, AnalysisContextStatistics_CacheRow> _dataMap =
5634 new HashMap<String, AnalysisContextStatistics_CacheRow>();
5635
5636 List<Source> _sources = new List<Source>();
5637
5638 HashSet<CaughtException> _exceptions = new HashSet<CaughtException>();
5639
5640 List<AnalysisContextStatistics_PartitionData> _partitionData;
5641
5642 @override
5643 List<AnalysisContextStatistics_CacheRow> get cacheRows =>
5644 _dataMap.values.toList();
5645
5646 @override
5647 List<CaughtException> get exceptions => new List.from(_exceptions);
5648
5649 @override
5650 List<AnalysisContextStatistics_PartitionData> get partitionData =>
5651 _partitionData;
5652
5653 /**
5654 * Set the partition data returned by this object to the given data.
5655 */
5656 void set partitionData(List<AnalysisContextStatistics_PartitionData> data) {
5657 _partitionData = data;
5658 }
5659
5660 @override
5661 List<Source> get sources => _sources;
5662
5663 void addSource(Source source) {
5664 _sources.add(source);
5665 }
5666
5667 void _internalPutCacheItem(Source source, SourceEntry dartEntry,
5668 DataDescriptor rowDesc, CacheState state) {
5669 String rowName = rowDesc.toString();
5670 AnalysisContextStatisticsImpl_CacheRowImpl row =
5671 _dataMap[rowName] as AnalysisContextStatisticsImpl_CacheRowImpl;
5672 if (row == null) {
5673 row = new AnalysisContextStatisticsImpl_CacheRowImpl(rowName);
5674 _dataMap[rowName] = row;
5675 }
5676 row._incState(state);
5677 if (state == CacheState.ERROR) {
5678 CaughtException exception = dartEntry.exception;
5679 if (exception != null) {
5680 _exceptions.add(exception);
5681 }
5682 }
5683 }
5684 }
5685
5686 class AnalysisContextStatisticsImpl_CacheRowImpl
5687 implements AnalysisContextStatistics_CacheRow {
5688 final String name;
5689
5690 Map<CacheState, int> _counts = <CacheState, int>{};
5691
5692 AnalysisContextStatisticsImpl_CacheRowImpl(this.name);
5693
5694 @override
5695 int get errorCount => getCount(CacheState.ERROR);
5696
5697 @override
5698 int get flushedCount => getCount(CacheState.FLUSHED);
5699
5700 @override
5701 int get hashCode => name.hashCode;
5702
5703 @override
5704 int get inProcessCount => getCount(CacheState.IN_PROCESS);
5705
5706 @override
5707 int get invalidCount => getCount(CacheState.INVALID);
5708
5709 @override
5710 int get validCount => getCount(CacheState.VALID);
5711
5712 @override
5713 bool operator ==(Object obj) =>
5714 obj is AnalysisContextStatisticsImpl_CacheRowImpl && obj.name == name;
5715
5716 @override
5717 int getCount(CacheState state) {
5718 int count = _counts[state];
5719 if (count != null) {
5720 return count;
5721 } else {
5722 return 0;
5723 }
5724 }
5725
5726 void _incState(CacheState state) {
5727 if (_counts[state] == null) {
5728 _counts[state] = 1;
5729 } else {
5730 _counts[state]++;
5731 }
5732 }
5733 }
5734
5735 class AnalysisContextStatisticsImpl_PartitionDataImpl
5736 implements AnalysisContextStatistics_PartitionData {
5737 final int astCount;
5738
5739 final int totalCount;
5740
5741 AnalysisContextStatisticsImpl_PartitionDataImpl(
5742 this.astCount, this.totalCount);
5743 }
5744
5745 /**
5746 * A representation of changes to the types of analysis that should be
5747 * performed.
5748 */
5749 class AnalysisDelta {
5750 /**
5751 * A mapping from source to what type of analysis should be performed on that
5752 * source.
5753 */
5754 HashMap<Source, AnalysisLevel> _analysisMap =
5755 new HashMap<Source, AnalysisLevel>();
5756
5757 /**
5758 * Return a collection of the sources that have been added. This is equivalent
5759 * to calling [getAnalysisLevels] and collecting all sources that do not have
5760 * an analysis level of [AnalysisLevel.NONE].
5761 */
5762 List<Source> get addedSources {
5763 List<Source> result = new List<Source>();
5764 _analysisMap.forEach((Source source, AnalysisLevel level) {
5765 if (level != AnalysisLevel.NONE) {
5766 result.add(source);
5767 }
5768 });
5769 return result;
5770 }
5771
5772 /**
5773 * Return a mapping of sources to the level of analysis that should be
5774 * performed.
5775 */
5776 Map<Source, AnalysisLevel> get analysisLevels => _analysisMap;
5777
5778 /**
5779 * Record that the given [source] should be analyzed at the given [level].
5780 */
5781 void setAnalysisLevel(Source source, AnalysisLevel level) {
5782 _analysisMap[source] = level;
5783 }
5784
5785 @override
5786 String toString() {
5787 StringBuffer buffer = new StringBuffer();
5788 bool needsSeparator = _appendSources(buffer, false, AnalysisLevel.ALL);
5789 needsSeparator =
5790 _appendSources(buffer, needsSeparator, AnalysisLevel.RESOLVED);
5791 _appendSources(buffer, needsSeparator, AnalysisLevel.NONE);
5792 return buffer.toString();
5793 }
5794
5795 /**
5796 * Appendto the given [buffer] all sources with the given analysis [level],
5797 * prefixed with a label and a separator if [needsSeparator] is `true`.
5798 */
5799 bool _appendSources(
5800 StringBuffer buffer, bool needsSeparator, AnalysisLevel level) {
5801 bool first = true;
5802 _analysisMap.forEach((Source source, AnalysisLevel sourceLevel) {
5803 if (sourceLevel == level) {
5804 if (first) {
5805 first = false;
5806 if (needsSeparator) {
5807 buffer.write("; ");
5808 }
5809 buffer.write(level);
5810 buffer.write(" ");
5811 } else {
5812 buffer.write(", ");
5813 }
5814 buffer.write(source.fullName);
5815 }
5816 });
5817 return needsSeparator || !first;
5818 }
5819 }
5820
5821 /**
5822 * The entry point for the functionality provided by the analysis engine. There
5823 * is a single instance of this class.
5824 */
5825 class AnalysisEngine {
5826 /**
5827 * The suffix used for Dart source files.
5828 */
5829 static const String SUFFIX_DART = "dart";
5830
5831 /**
5832 * The short suffix used for HTML files.
5833 */
5834 static const String SUFFIX_HTM = "htm";
5835
5836 /**
5837 * The long suffix used for HTML files.
5838 */
5839 static const String SUFFIX_HTML = "html";
5840
5841 /**
5842 * The unique instance of this class.
5843 */
5844 static final AnalysisEngine instance = new AnalysisEngine._();
5845
5846 /**
5847 * The logger that should receive information about errors within the analysis
5848 * engine.
5849 */
5850 Logger _logger = Logger.NULL;
5851
5852 /**
5853 * The plugin that defines the extension points and extensions that are define d by
5854 * command-line applications using the analysis engine.
5855 */
5856 final CommandLinePlugin commandLinePlugin = new CommandLinePlugin();
5857
5858 /**
5859 * The plugin that defines the extension points and extensions that are
5860 * inherently defined by the analysis engine.
5861 */
5862 final EnginePlugin enginePlugin = new EnginePlugin();
5863
5864 /***
5865 * The plugin that defines the extension points and extensions that are define d
5866 * by applications that want to consume options defined in the analysis
5867 * options file.
5868 */
5869 final OptionsPlugin optionsPlugin = new OptionsPlugin();
5870
5871 /**
5872 * The instrumentation service that is to be used by this analysis engine.
5873 */
5874 InstrumentationService _instrumentationService =
5875 InstrumentationService.NULL_SERVICE;
5876
5877 /**
5878 * The list of supported plugins for processing by clients.
5879 */
5880 List<Plugin> _supportedPlugins;
5881
5882 /**
5883 * The partition manager being used to manage the shared partitions.
5884 */
5885 final PartitionManager partitionManager = new PartitionManager();
5886
5887 /**
5888 * The partition manager being used to manage the shared partitions.
5889 */
5890 final newContext.PartitionManager partitionManager_new =
5891 new newContext.PartitionManager();
5892
5893 /**
5894 * A flag indicating whether the (new) task model should be used to perform
5895 * analysis.
5896 */
5897 bool useTaskModel = false;
5898
5899 /**
5900 * A flag indicating whether the task model should attempt to limit
5901 * invalidation after a change.
5902 */
5903 bool limitInvalidationInTaskModel = false;
5904
5905 /**
5906 * The task manager used to manage the tasks used to analyze code.
5907 */
5908 TaskManager _taskManager;
5909
5910 AnalysisEngine._();
5911
5912 /**
5913 * Return the instrumentation service that is to be used by this analysis
5914 * engine.
5915 */
5916 InstrumentationService get instrumentationService => _instrumentationService;
5917
5918 /**
5919 * Set the instrumentation service that is to be used by this analysis engine
5920 * to the given [service].
5921 */
5922 void set instrumentationService(InstrumentationService service) {
5923 if (service == null) {
5924 _instrumentationService = InstrumentationService.NULL_SERVICE;
5925 } else {
5926 _instrumentationService = service;
5927 }
5928 }
5929
5930 /**
5931 * Return the logger that should receive information about errors within the
5932 * analysis engine.
5933 */
5934 Logger get logger => _logger;
5935
5936 /**
5937 * Set the logger that should receive information about errors within the
5938 * analysis engine to the given [logger].
5939 */
5940 void set logger(Logger logger) {
5941 this._logger = logger == null ? Logger.NULL : logger;
5942 }
5943
5944 /**
5945 * Return the list of supported plugins for processing by clients.
5946 */
5947 List<Plugin> get supportedPlugins {
5948 if (_supportedPlugins == null) {
5949 _supportedPlugins = <Plugin>[
5950 enginePlugin,
5951 commandLinePlugin,
5952 optionsPlugin
5953 ];
5954 }
5955 return _supportedPlugins;
5956 }
5957
5958 /**
5959 * Return the task manager used to manage the tasks used to analyze code.
5960 */
5961 TaskManager get taskManager {
5962 if (_taskManager == null) {
5963 if (enginePlugin.taskExtensionPoint == null) {
5964 // The plugin wasn't used, so tasks are not registered.
5965 new ExtensionManager().processPlugins([enginePlugin]);
5966 }
5967 _taskManager = new TaskManager();
5968 _taskManager.addTaskDescriptors(enginePlugin.taskDescriptors);
5969 // TODO(brianwilkerson) Create a way to associate different results with
5970 // different file suffixes, then make this pluggable.
5971 _taskManager.addGeneralResult(DART_ERRORS);
5972 }
5973 return _taskManager;
5974 }
5975
5976 /**
5977 * Clear any caches holding on to analysis results so that a full re-analysis
5978 * will be performed the next time an analysis context is created.
5979 */
5980 void clearCaches() {
5981 partitionManager.clearCache();
5982 }
5983
5984 /**
5985 * Create and return a new context in which analysis can be performed.
5986 */
5987 AnalysisContext createAnalysisContext() {
5988 if (useTaskModel) {
5989 return new newContext.AnalysisContextImpl();
5990 }
5991 return new AnalysisContextImpl();
5992 }
5993
5994 /**
5995 * Return `true` if the given [fileName] is assumed to contain Dart source
5996 * code.
5997 */
5998 static bool isDartFileName(String fileName) {
5999 if (fileName == null) {
6000 return false;
6001 }
6002 return javaStringEqualsIgnoreCase(
6003 FileNameUtilities.getExtension(fileName), SUFFIX_DART);
6004 }
6005
6006 /**
6007 * Return `true` if the given [fileName] is assumed to contain HTML.
6008 */
6009 static bool isHtmlFileName(String fileName) {
6010 if (fileName == null) {
6011 return false;
6012 }
6013 String extension = FileNameUtilities.getExtension(fileName);
6014 return javaStringEqualsIgnoreCase(extension, SUFFIX_HTML) ||
6015 javaStringEqualsIgnoreCase(extension, SUFFIX_HTM);
6016 }
6017 }
6018
6019 /**
6020 * The analysis errors and line information for the errors.
6021 */
6022 abstract class AnalysisErrorInfo {
6023 /**
6024 * Return the errors that as a result of the analysis, or `null` if there were
6025 * no errors.
6026 */
6027 List<AnalysisError> get errors;
6028
6029 /**
6030 * Return the line information associated with the errors, or `null` if there
6031 * were no errors.
6032 */
6033 LineInfo get lineInfo;
6034 }
6035
6036 /**
6037 * The analysis errors and line info associated with a source.
6038 */
6039 class AnalysisErrorInfoImpl implements AnalysisErrorInfo {
6040 /**
6041 * The analysis errors associated with a source, or `null` if there are no
6042 * errors.
6043 */
6044 final List<AnalysisError> errors;
6045
6046 /**
6047 * The line information associated with the errors, or `null` if there are no
6048 * errors.
6049 */
6050 final LineInfo lineInfo;
6051
6052 /**
6053 * Initialize an newly created error info with the given [errors] and
6054 * [lineInfo].
6055 */
6056 AnalysisErrorInfoImpl(this.errors, this.lineInfo);
6057 }
6058
6059 /**
6060 * The levels at which a source can be analyzed.
6061 */
6062 class AnalysisLevel extends Enum<AnalysisLevel> {
6063 /**
6064 * Indicates a source should be fully analyzed.
6065 */
6066 static const AnalysisLevel ALL = const AnalysisLevel('ALL', 0);
6067
6068 /**
6069 * Indicates a source should be resolved and that errors, warnings and hints a re needed.
6070 */
6071 static const AnalysisLevel ERRORS = const AnalysisLevel('ERRORS', 1);
6072
6073 /**
6074 * Indicates a source should be resolved, but that errors, warnings and hints are not needed.
6075 */
6076 static const AnalysisLevel RESOLVED = const AnalysisLevel('RESOLVED', 2);
6077
6078 /**
6079 * Indicates a source is not of interest to the client.
6080 */
6081 static const AnalysisLevel NONE = const AnalysisLevel('NONE', 3);
6082
6083 static const List<AnalysisLevel> values = const [ALL, ERRORS, RESOLVED, NONE];
6084
6085 const AnalysisLevel(String name, int ordinal) : super(name, ordinal);
6086 }
6087
6088 /**
6089 * An object that is listening for results being produced by an analysis
6090 * context.
6091 */
6092 abstract class AnalysisListener {
6093 /**
6094 * Reports that a task, described by the given [taskDescription] is about to
6095 * be performed by the given [context].
6096 */
6097 void aboutToPerformTask(AnalysisContext context, String taskDescription);
6098
6099 /**
6100 * Reports that the [errors] associated with the given [source] in the given
6101 * [context] has been updated to the given errors. The [lineInfo] is the line
6102 * information associated with the source.
6103 */
6104 void computedErrors(AnalysisContext context, Source source,
6105 List<AnalysisError> errors, LineInfo lineInfo);
6106
6107 /**
6108 * Reports that the given [source] is no longer included in the set of sources
6109 * that are being analyzed by the given analysis [context].
6110 */
6111 void excludedSource(AnalysisContext context, Source source);
6112
6113 /**
6114 * Reports that the given [source] is now included in the set of sources that
6115 * are being analyzed by the given analysis [context].
6116 */
6117 void includedSource(AnalysisContext context, Source source);
6118
6119 /**
6120 * Reports that the given Dart [source] was parsed in the given [context],
6121 * producing the given [unit].
6122 */
6123 void parsedDart(AnalysisContext context, Source source, CompilationUnit unit);
6124
6125 /**
6126 * Reports that the given HTML [source] was parsed in the given [context].
6127 */
6128 @deprecated
6129 void parsedHtml(AnalysisContext context, Source source, ht.HtmlUnit unit);
6130
6131 /**
6132 * Reports that the given Dart [source] was resolved in the given [context].
6133 */
6134 void resolvedDart(
6135 AnalysisContext context, Source source, CompilationUnit unit);
6136
6137 /**
6138 * Reports that the given HTML [source] was resolved in the given [context].
6139 */
6140 @deprecated
6141 void resolvedHtml(AnalysisContext context, Source source, ht.HtmlUnit unit);
6142 }
6143
6144 /**
6145 * Futures returned by [AnalysisContext] for pending analysis results will
6146 * complete with this error if it is determined that analysis results will
6147 * never become available (e.g. because the requested source is not subject to
6148 * analysis, or because the requested source is a part file which is not a part
6149 * of any known library).
6150 */
6151 class AnalysisNotScheduledError implements Exception {}
6152
6153 /**
6154 * A set of analysis options used to control the behavior of an analysis
6155 * context.
6156 */
6157 abstract class AnalysisOptions {
6158 /**
6159 * If analysis is to parse and analyze all function bodies, return `true`.
6160 * If analysis is to skip all function bodies, return `false`. If analysis
6161 * is to parse and analyze function bodies in some sources and not in others,
6162 * throw an exception.
6163 *
6164 * This getter is deprecated; consider using [analyzeFunctionBodiesPredicate]
6165 * instead.
6166 */
6167 @deprecated // Use this.analyzeFunctionBodiesPredicate
6168 bool get analyzeFunctionBodies;
6169
6170 /**
6171 * Function that returns `true` if analysis is to parse and analyze function
6172 * bodies for a given source.
6173 */
6174 AnalyzeFunctionBodiesPredicate get analyzeFunctionBodiesPredicate;
6175
6176 /**
6177 * Return the maximum number of sources for which AST structures should be
6178 * kept in the cache.
6179 */
6180 int get cacheSize;
6181
6182 /**
6183 * Return `true` if analysis is to generate dart2js related hint results.
6184 */
6185 bool get dart2jsHint;
6186
6187 /**
6188 * Return `true` if analysis is to include the new async support.
6189 */
6190 @deprecated // Always true
6191 bool get enableAsync;
6192
6193 /**
6194 * Return `true` if analysis is to include the new deferred loading support.
6195 */
6196 @deprecated // Always true
6197 bool get enableDeferredLoading;
6198
6199 /**
6200 * Return `true` if analysis is to include the new enum support.
6201 */
6202 @deprecated // Always true
6203 bool get enableEnum;
6204
6205 /**
6206 * Return `true` to enable generic methods (DEP 22).
6207 */
6208 bool get enableGenericMethods => null;
6209
6210 /**
6211 * Return `true` to enable null-aware operators (DEP 9).
6212 */
6213 @deprecated // Always true
6214 bool get enableNullAwareOperators;
6215
6216 /**
6217 * Return `true` to strictly follow the specification when generating
6218 * warnings on "call" methods (fixes dartbug.com/21938).
6219 */
6220 bool get enableStrictCallChecks;
6221
6222 /**
6223 * Return `true` if mixins are allowed to inherit from types other than
6224 * Object, and are allowed to reference `super`.
6225 */
6226 bool get enableSuperMixins;
6227
6228 /**
6229 * Return `true` if errors, warnings and hints should be generated for sources
6230 * that are implicitly being analyzed. The default value is `true`.
6231 */
6232 bool get generateImplicitErrors;
6233
6234 /**
6235 * Return `true` if errors, warnings and hints should be generated for sources
6236 * in the SDK. The default value is `false`.
6237 */
6238 bool get generateSdkErrors;
6239
6240 /**
6241 * Return `true` if analysis is to generate hint results (e.g. type inference
6242 * based information and pub best practices).
6243 */
6244 bool get hint;
6245
6246 /**
6247 * Return `true` if incremental analysis should be used.
6248 */
6249 bool get incremental;
6250
6251 /**
6252 * A flag indicating whether incremental analysis should be used for API
6253 * changes.
6254 */
6255 bool get incrementalApi;
6256
6257 /**
6258 * A flag indicating whether validation should be performed after incremental
6259 * analysis.
6260 */
6261 bool get incrementalValidation;
6262
6263 /**
6264 * Return `true` if analysis is to generate lint warnings.
6265 */
6266 bool get lint;
6267
6268 /**
6269 * Return `true` if analysis is to parse comments.
6270 */
6271 bool get preserveComments;
6272
6273 /**
6274 * Return `true` if strong mode analysis should be used.
6275 */
6276 bool get strongMode;
6277 }
6278
6279 /**
6280 * A set of analysis options used to control the behavior of an analysis
6281 * context.
6282 */
6283 class AnalysisOptionsImpl implements AnalysisOptions {
6284 /**
6285 * The maximum number of sources for which data should be kept in the cache.
6286 */
6287 static const int DEFAULT_CACHE_SIZE = 64;
6288
6289 /**
6290 * The default value for enabling deferred loading.
6291 */
6292 @deprecated
6293 static bool DEFAULT_ENABLE_DEFERRED_LOADING = true;
6294
6295 /**
6296 * The default value for enabling enum support.
6297 */
6298 @deprecated
6299 static bool DEFAULT_ENABLE_ENUM = true;
6300
6301 /**
6302 * A predicate indicating whether analysis is to parse and analyze function
6303 * bodies.
6304 */
6305 AnalyzeFunctionBodiesPredicate _analyzeFunctionBodiesPredicate =
6306 _analyzeAllFunctionBodies;
6307
6308 /**
6309 * The maximum number of sources for which AST structures should be kept in
6310 * the cache.
6311 */
6312 int cacheSize = DEFAULT_CACHE_SIZE;
6313
6314 /**
6315 * A flag indicating whether analysis is to generate dart2js related hint
6316 * results.
6317 */
6318 bool dart2jsHint = false;
6319
6320 /**
6321 * A flag indicating whether generic methods are to be supported (DEP 22).
6322 */
6323 bool enableGenericMethods = false;
6324
6325 /**
6326 * A flag indicating whether analysis is to strictly follow the specification
6327 * when generating warnings on "call" methods (fixes dartbug.com/21938).
6328 */
6329 bool enableStrictCallChecks = false;
6330
6331 /**
6332 * A flag indicating whether mixins are allowed to inherit from types other
6333 * than Object, and are allowed to reference `super`.
6334 */
6335 bool enableSuperMixins = false;
6336
6337 /**
6338 * A flag indicating whether errors, warnings and hints should be generated
6339 * for sources that are implicitly being analyzed.
6340 */
6341 bool generateImplicitErrors = true;
6342
6343 /**
6344 * A flag indicating whether errors, warnings and hints should be generated
6345 * for sources in the SDK.
6346 */
6347 bool generateSdkErrors = false;
6348
6349 /**
6350 * A flag indicating whether analysis is to generate hint results (e.g. type
6351 * inference based information and pub best practices).
6352 */
6353 bool hint = true;
6354
6355 /**
6356 * A flag indicating whether incremental analysis should be used.
6357 */
6358 bool incremental = false;
6359
6360 /**
6361 * A flag indicating whether incremental analysis should be used for API
6362 * changes.
6363 */
6364 bool incrementalApi = false;
6365
6366 /**
6367 * A flag indicating whether validation should be performed after incremental
6368 * analysis.
6369 */
6370 bool incrementalValidation = false;
6371
6372 /**
6373 * A flag indicating whether analysis is to generate lint warnings.
6374 */
6375 bool lint = false;
6376
6377 /**
6378 * A flag indicating whether analysis is to parse comments.
6379 */
6380 bool preserveComments = true;
6381
6382 /**
6383 * A flag indicating whether strong-mode analysis should be used.
6384 */
6385 bool strongMode = false;
6386
6387 /**
6388 * Initialize a newly created set of analysis options to have their default
6389 * values.
6390 */
6391 AnalysisOptionsImpl();
6392
6393 /**
6394 * Initialize a newly created set of analysis options to have the same values
6395 * as those in the given set of analysis [options].
6396 */
6397 @deprecated // Use new AnalysisOptionsImpl.from(options)
6398 AnalysisOptionsImpl.con1(AnalysisOptions options) {
6399 analyzeFunctionBodiesPredicate = options.analyzeFunctionBodiesPredicate;
6400 cacheSize = options.cacheSize;
6401 dart2jsHint = options.dart2jsHint;
6402 enableStrictCallChecks = options.enableStrictCallChecks;
6403 enableSuperMixins = options.enableSuperMixins;
6404 generateImplicitErrors = options.generateImplicitErrors;
6405 generateSdkErrors = options.generateSdkErrors;
6406 hint = options.hint;
6407 incremental = options.incremental;
6408 incrementalApi = options.incrementalApi;
6409 incrementalValidation = options.incrementalValidation;
6410 lint = options.lint;
6411 preserveComments = options.preserveComments;
6412 strongMode = options.strongMode;
6413 }
6414
6415 /**
6416 * Initialize a newly created set of analysis options to have the same values
6417 * as those in the given set of analysis [options].
6418 */
6419 AnalysisOptionsImpl.from(AnalysisOptions options) {
6420 analyzeFunctionBodiesPredicate = options.analyzeFunctionBodiesPredicate;
6421 cacheSize = options.cacheSize;
6422 dart2jsHint = options.dart2jsHint;
6423 enableStrictCallChecks = options.enableStrictCallChecks;
6424 enableSuperMixins = options.enableSuperMixins;
6425 generateImplicitErrors = options.generateImplicitErrors;
6426 generateSdkErrors = options.generateSdkErrors;
6427 hint = options.hint;
6428 incremental = options.incremental;
6429 incrementalApi = options.incrementalApi;
6430 incrementalValidation = options.incrementalValidation;
6431 lint = options.lint;
6432 preserveComments = options.preserveComments;
6433 strongMode = options.strongMode;
6434 }
6435
6436 bool get analyzeFunctionBodies {
6437 if (identical(analyzeFunctionBodiesPredicate, _analyzeAllFunctionBodies)) {
6438 return true;
6439 } else if (identical(
6440 analyzeFunctionBodiesPredicate, _analyzeNoFunctionBodies)) {
6441 return false;
6442 } else {
6443 throw new StateError('analyzeFunctionBodiesPredicate in use');
6444 }
6445 }
6446
6447 set analyzeFunctionBodies(bool value) {
6448 if (value) {
6449 analyzeFunctionBodiesPredicate = _analyzeAllFunctionBodies;
6450 } else {
6451 analyzeFunctionBodiesPredicate = _analyzeNoFunctionBodies;
6452 }
6453 }
6454
6455 @override
6456 AnalyzeFunctionBodiesPredicate get analyzeFunctionBodiesPredicate =>
6457 _analyzeFunctionBodiesPredicate;
6458
6459 set analyzeFunctionBodiesPredicate(AnalyzeFunctionBodiesPredicate value) {
6460 if (value == null) {
6461 throw new ArgumentError.notNull('analyzeFunctionBodiesPredicate');
6462 }
6463 _analyzeFunctionBodiesPredicate = value;
6464 }
6465
6466 @deprecated
6467 @override
6468 bool get enableAsync => true;
6469
6470 @deprecated
6471 void set enableAsync(bool enable) {
6472 // Async support cannot be disabled
6473 }
6474
6475 @deprecated
6476 @override
6477 bool get enableDeferredLoading => true;
6478
6479 @deprecated
6480 void set enableDeferredLoading(bool enable) {
6481 // Deferred loading support cannot be disabled
6482 }
6483
6484 @deprecated
6485 @override
6486 bool get enableEnum => true;
6487
6488 @deprecated
6489 void set enableEnum(bool enable) {
6490 // Enum support cannot be disabled
6491 }
6492
6493 @deprecated
6494 @override
6495 bool get enableNullAwareOperators => true;
6496
6497 @deprecated
6498 void set enableNullAwareOperators(bool enable) {
6499 // Null-aware operator support cannot be disabled
6500 }
6501
6502 /**
6503 * Predicate used for [analyzeFunctionBodiesPredicate] when
6504 * [analyzeFunctionBodies] is set to `true`.
6505 */
6506 static bool _analyzeAllFunctionBodies(Source _) => true;
6507
6508 /**
6509 * Predicate used for [analyzeFunctionBodiesPredicate] when
6510 * [analyzeFunctionBodies] is set to `false`.
6511 */
6512 static bool _analyzeNoFunctionBodies(Source _) => false;
6513 }
6514
6515 /**
6516 *
6517 */
6518 class AnalysisResult {
6519 /**
6520 * The change notices associated with this result, or `null` if there were no
6521 * changes and there is no more work to be done.
6522 */
6523 final List<ChangeNotice> _notices;
6524
6525 /**
6526 * The number of milliseconds required to determine which task was to be
6527 * performed.
6528 */
6529 final int getTime;
6530
6531 /**
6532 * The name of the class of the task that was performed.
6533 */
6534 final String taskClassName;
6535
6536 /**
6537 * The number of milliseconds required to perform the task.
6538 */
6539 final int performTime;
6540
6541 /**
6542 * Initialize a newly created analysis result to have the given values. The
6543 * [notices] is the change notices associated with this result. The [getTime]
6544 * is the number of milliseconds required to determine which task was to be
6545 * performed. The [taskClassName] is the name of the class of the task that
6546 * was performed. The [performTime] is the number of milliseconds required to
6547 * perform the task.
6548 */
6549 AnalysisResult(
6550 this._notices, this.getTime, this.taskClassName, this.performTime);
6551
6552 /**
6553 * Return the change notices associated with this result, or `null` if there
6554 * were no changes and there is no more work to be done.
6555 */
6556 List<ChangeNotice> get changeNotices => _notices;
6557
6558 /**
6559 * Return `true` if there is more to be performed after the task that was
6560 * performed.
6561 */
6562 bool get hasMoreWork => _notices != null;
6563 }
6564
6565 /**
6566 * An analysis task.
6567 */
6568 abstract class AnalysisTask {
6569 /**
6570 * The context in which the task is to be performed.
6571 */
6572 final InternalAnalysisContext context;
6573
6574 /**
6575 * The exception that was thrown while performing this task, or `null` if the
6576 * task completed successfully.
6577 */
6578 CaughtException _thrownException;
6579
6580 /**
6581 * Initialize a newly created task to perform analysis within the given
6582 * [context].
6583 */
6584 AnalysisTask(this.context);
6585
6586 /**
6587 * Return the exception that was thrown while performing this task, or `null`
6588 * if the task completed successfully.
6589 */
6590 CaughtException get exception => _thrownException;
6591
6592 /**
6593 * Return a textual description of this task.
6594 */
6595 String get taskDescription;
6596
6597 /**
6598 * Use the given [visitor] to visit this task. Throws an [AnalysisException]
6599 * if the visitor throws the exception.
6600 */
6601 accept(AnalysisTaskVisitor visitor);
6602
6603 /**
6604 * Perform this analysis task, protected by an exception handler. Throws an
6605 * [AnalysisException] if an exception occurs while performing the task.
6606 */
6607 void internalPerform();
6608
6609 /**
6610 * Perform this analysis task and use the given [visitor] to visit this task
6611 * after it has completed. Throws an [AnalysisException] if the visitor throws
6612 * the exception.
6613 */
6614 Object perform(AnalysisTaskVisitor visitor) {
6615 try {
6616 _safelyPerform();
6617 } on AnalysisException catch (exception, stackTrace) {
6618 _thrownException = new CaughtException(exception, stackTrace);
6619 AnalysisEngine.instance.logger.logInformation(
6620 "Task failed: $taskDescription",
6621 new CaughtException(exception, stackTrace));
6622 }
6623 return PerformanceStatistics.analysisTaskVisitor
6624 .makeCurrentWhile(() => accept(visitor));
6625 }
6626
6627 @override
6628 String toString() => taskDescription;
6629
6630 /**
6631 * Perform this analysis task, ensuring that all exceptions are wrapped in an
6632 * [AnalysisException]. Throws an [AnalysisException] if any exception occurs
6633 * while performing the task
6634 */
6635 void _safelyPerform() {
6636 try {
6637 String contextName = context.name;
6638 if (contextName == null) {
6639 contextName = 'unnamed';
6640 }
6641 AnalysisEngine.instance.instrumentationService
6642 .logAnalysisTask(contextName, taskDescription);
6643 internalPerform();
6644 } on AnalysisException {
6645 rethrow;
6646 } catch (exception, stackTrace) {
6647 throw new AnalysisException(
6648 exception.toString(), new CaughtException(exception, stackTrace));
6649 }
6650 }
6651 }
6652
6653 /**
6654 * An object used to visit tasks. While tasks are not structured in any
6655 * interesting way, this class provides the ability to dispatch to an
6656 * appropriate method.
6657 */
6658 abstract class AnalysisTaskVisitor<E> {
6659 /**
6660 * Visit the given [task], returning the result of the visit. This method will
6661 * throw an AnalysisException if the visitor throws an exception.
6662 */
6663 E visitGenerateDartErrorsTask(GenerateDartErrorsTask task);
6664
6665 /**
6666 * Visit the given [task], returning the result of the visit. This method will
6667 * throw an AnalysisException if the visitor throws an exception.
6668 */
6669 E visitGenerateDartHintsTask(GenerateDartHintsTask task);
6670
6671 /**
6672 * Visit the given [task], returning the result of the visit. This method will
6673 * throw an AnalysisException if the visitor throws an exception.
6674 */
6675 E visitGenerateDartLintsTask(GenerateDartLintsTask task);
6676
6677 /**
6678 * Visit the given [task], returning the result of the visit. This method will
6679 * throw an AnalysisException if the visitor throws an exception.
6680 */
6681 E visitGetContentTask(GetContentTask task);
6682
6683 /**
6684 * Visit the given [task], returning the result of the visit. This method will
6685 * throw an AnalysisException if the visitor throws an exception.
6686 */
6687 E visitIncrementalAnalysisTask(
6688 IncrementalAnalysisTask incrementalAnalysisTask);
6689
6690 /**
6691 * Visit the given [task], returning the result of the visit. This method will
6692 * throw an AnalysisException if the visitor throws an exception.
6693 */
6694 E visitParseDartTask(ParseDartTask task);
6695
6696 /**
6697 * Visit the given [task], returning the result of the visit. This method will
6698 * throw an AnalysisException if the visitor throws an exception.
6699 */
6700 E visitParseHtmlTask(ParseHtmlTask task);
6701
6702 /**
6703 * Visit the given [task], returning the result of the visit. This method will
6704 * throw an AnalysisException if the visitor throws an exception.
6705 */
6706 E visitResolveDartLibraryCycleTask(ResolveDartLibraryCycleTask task);
6707
6708 /**
6709 * Visit the given [task], returning the result of the visit. This method will
6710 * throw an AnalysisException if the visitor throws an exception.
6711 */
6712 E visitResolveDartLibraryTask(ResolveDartLibraryTask task);
6713
6714 /**
6715 * Visit the given [task], returning the result of the visit. This method will
6716 * throw an AnalysisException if the visitor throws an exception.
6717 */
6718 E visitResolveDartUnitTask(ResolveDartUnitTask task);
6719
6720 /**
6721 * Visit the given [task], returning the result of the visit. This method will
6722 * throw an AnalysisException if the visitor throws an exception.
6723 */
6724 E visitResolveHtmlTask(ResolveHtmlTask task);
6725
6726 /**
6727 * Visit the given [task], returning the result of the visit. This method will
6728 * throw an AnalysisException if the visitor throws an exception.
6729 */
6730 E visitScanDartTask(ScanDartTask task);
6731 }
6732
6733 /**
6734 * A `CachedResult` is a single analysis result that is stored in a
6735 * [SourceEntry].
6736 */
6737 class CachedResult<E> {
6738 /**
6739 * The state of the cached value.
6740 */
6741 CacheState state;
6742
6743 /**
6744 * The value being cached, or `null` if there is no value (for example, when
6745 * the [state] is [CacheState.INVALID].
6746 */
6747 E value;
6748
6749 /**
6750 * Initialize a newly created result holder to represent the value of data
6751 * described by the given [descriptor].
6752 */
6753 CachedResult(DataDescriptor descriptor) {
6754 state = CacheState.INVALID;
6755 value = descriptor.defaultValue;
6756 }
6757 }
6758
6759 /**
6760 * A single partition in an LRU cache of information related to analysis.
6761 */
6762 abstract class CachePartition {
6763 /**
6764 * The context that owns this partition. Multiple contexts can reference a
6765 * partition, but only one context can own it.
6766 */
6767 final InternalAnalysisContext context;
6768
6769 /**
6770 * The maximum number of sources for which AST structures should be kept in
6771 * the cache.
6772 */
6773 int _maxCacheSize = 0;
6774
6775 /**
6776 * The policy used to determine which pieces of data to remove from the cache.
6777 */
6778 final CacheRetentionPolicy _retentionPolicy;
6779
6780 /**
6781 * A table mapping the sources belonging to this partition to the information
6782 * known about those sources.
6783 */
6784 HashMap<Source, SourceEntry> _sourceMap = new HashMap<Source, SourceEntry>();
6785
6786 /**
6787 * A list containing the most recently accessed sources with the most recently
6788 * used at the end of the list. When more sources are added than the maximum
6789 * allowed then the least recently used source will be removed and will have
6790 * it's cached AST structure flushed.
6791 */
6792 List<Source> _recentlyUsed;
6793
6794 /**
6795 * Initialize a newly created cache to maintain at most [maxCacheSize] AST
6796 * structures in the cache. The cache is owned by the give [context], and the
6797 * [retentionPolicy] will be used to determine which pieces of data to remove
6798 * from the cache.
6799 */
6800 CachePartition(this.context, this._maxCacheSize, this._retentionPolicy) {
6801 _recentlyUsed = new List<Source>();
6802 }
6803
6804 /**
6805 * Return the number of entries in this partition that have an AST associated
6806 * with them.
6807 */
6808 int get astSize {
6809 int astSize = 0;
6810 int count = _recentlyUsed.length;
6811 for (int i = 0; i < count; i++) {
6812 Source source = _recentlyUsed[i];
6813 SourceEntry sourceEntry = _sourceMap[source];
6814 if (sourceEntry is DartEntry) {
6815 if (sourceEntry.anyParsedCompilationUnit != null) {
6816 astSize++;
6817 }
6818 } else if (sourceEntry is HtmlEntry) {
6819 if (sourceEntry.anyParsedUnit != null) {
6820 astSize++;
6821 }
6822 }
6823 }
6824 return astSize;
6825 }
6826
6827 /**
6828 * Return a table mapping the sources known to the context to the information
6829 * known about the source.
6830 *
6831 * <b>Note:</b> This method is only visible for use by [AnalysisCache] and
6832 * should not be used for any other purpose.
6833 */
6834 Map<Source, SourceEntry> get map => _sourceMap;
6835
6836 /**
6837 * Set the maximum size of the cache to the given [size].
6838 */
6839 void set maxCacheSize(int size) {
6840 _maxCacheSize = size;
6841 while (_recentlyUsed.length > _maxCacheSize) {
6842 if (!_flushAstFromCache()) {
6843 break;
6844 }
6845 }
6846 }
6847
6848 /**
6849 * Record that the AST associated with the given source was just read from the
6850 * cache.
6851 */
6852 void accessedAst(Source source) {
6853 if (_recentlyUsed.remove(source)) {
6854 _recentlyUsed.add(source);
6855 return;
6856 }
6857 while (_recentlyUsed.length >= _maxCacheSize) {
6858 if (!_flushAstFromCache()) {
6859 break;
6860 }
6861 }
6862 _recentlyUsed.add(source);
6863 }
6864
6865 /**
6866 * Return `true` if the given [source] is contained in this partition.
6867 */
6868 bool contains(Source source);
6869
6870 /**
6871 * Return the entry associated with the given [source].
6872 */
6873 SourceEntry get(Source source) => _sourceMap[source];
6874
6875 /**
6876 * Return an iterator returning all of the map entries mapping sources to
6877 * cache entries.
6878 */
6879 MapIterator<Source, SourceEntry> iterator() =>
6880 new SingleMapIterator<Source, SourceEntry>(_sourceMap);
6881
6882 /**
6883 * Associate the given [entry] with the given [source].
6884 */
6885 void put(Source source, SourceEntry entry) {
6886 entry.fixExceptionState();
6887 _sourceMap[source] = entry;
6888 }
6889
6890 /**
6891 * Remove all information related to the given [source] from this partition.
6892 * Return the entry associated with the source, or `null` if there was cache
6893 * entry for the source.
6894 */
6895 SourceEntry remove(Source source) {
6896 _recentlyUsed.remove(source);
6897 return _sourceMap.remove(source);
6898 }
6899
6900 /**
6901 * Record that the AST associated with the given [source] was just removed
6902 * from the cache.
6903 */
6904 void removedAst(Source source) {
6905 _recentlyUsed.remove(source);
6906 }
6907
6908 /**
6909 * Return the number of sources that are mapped to cache entries.
6910 */
6911 int size() => _sourceMap.length;
6912
6913 /**
6914 * Record that the AST associated with the given [source] was just stored to
6915 * the cache.
6916 */
6917 void storedAst(Source source) {
6918 if (_recentlyUsed.contains(source)) {
6919 return;
6920 }
6921 while (_recentlyUsed.length >= _maxCacheSize) {
6922 if (!_flushAstFromCache()) {
6923 break;
6924 }
6925 }
6926 _recentlyUsed.add(source);
6927 }
6928
6929 /**
6930 * Attempt to flush one AST structure from the cache. Return `true` if a
6931 * structure was flushed.
6932 */
6933 bool _flushAstFromCache() {
6934 Source removedSource = _removeAstToFlush();
6935 if (removedSource == null) {
6936 return false;
6937 }
6938 SourceEntry sourceEntry = _sourceMap[removedSource];
6939 if (sourceEntry is HtmlEntry) {
6940 HtmlEntry htmlEntry = sourceEntry;
6941 htmlEntry.flushAstStructures();
6942 } else if (sourceEntry is DartEntry) {
6943 DartEntry dartEntry = sourceEntry;
6944 dartEntry.flushAstStructures();
6945 }
6946 return true;
6947 }
6948
6949 /**
6950 * Remove and return one source from the list of recently used sources whose
6951 * AST structure can be flushed from the cache. The source that will be
6952 * returned will be the source that has been unreferenced for the longest
6953 * period of time but that is not a priority for analysis.
6954 */
6955 Source _removeAstToFlush() {
6956 int sourceToRemove = -1;
6957 for (int i = 0; i < _recentlyUsed.length; i++) {
6958 Source source = _recentlyUsed[i];
6959 RetentionPriority priority =
6960 _retentionPolicy.getAstPriority(source, _sourceMap[source]);
6961 if (priority == RetentionPriority.LOW) {
6962 return _recentlyUsed.removeAt(i);
6963 } else if (priority == RetentionPriority.MEDIUM && sourceToRemove < 0) {
6964 sourceToRemove = i;
6965 }
6966 }
6967 if (sourceToRemove < 0) {
6968 // This happens if the retention policy returns a priority of HIGH for all
6969 // of the sources that have been recently used. This is the case, for
6970 // example, when the list of priority sources is bigger than the current
6971 // cache size.
6972 return null;
6973 }
6974 return _recentlyUsed.removeAt(sourceToRemove);
6975 }
6976 }
6977
6978 /**
6979 * An object used to determine how important it is for data to be retained in
6980 * the analysis cache.
6981 */
6982 abstract class CacheRetentionPolicy {
6983 /**
6984 * Return the priority of retaining the AST structure for the given [source].
6985 */
6986 RetentionPriority getAstPriority(Source source, SourceEntry sourceEntry);
6987 }
6988
6989 /**
6990 * The possible states of cached data.
6991 */
6992 class CacheState extends Enum<CacheState> {
6993 /**
6994 * The data is not in the cache and the last time an attempt was made to
6995 * compute the data an exception occurred, making it pointless to attempt to
6996 * compute the data again.
6997 *
6998 * Valid Transitions:
6999 * * [INVALID] if a source was modified that might cause the data to be
7000 * computable
7001 */
7002 static const CacheState ERROR = const CacheState('ERROR', 0);
7003
7004 /**
7005 * The data is not in the cache because it was flushed from the cache in order
7006 * to control memory usage. If the data is recomputed, results do not need to
7007 * be reported.
7008 *
7009 * Valid Transitions:
7010 * * [IN_PROCESS] if the data is being recomputed
7011 * * [INVALID] if a source was modified that causes the data to need to be
7012 * recomputed
7013 */
7014 static const CacheState FLUSHED = const CacheState('FLUSHED', 1);
7015
7016 /**
7017 * The data might or might not be in the cache but is in the process of being
7018 * recomputed.
7019 *
7020 * Valid Transitions:
7021 * * [ERROR] if an exception occurred while trying to compute the data
7022 * * [VALID] if the data was successfully computed and stored in the cache
7023 */
7024 static const CacheState IN_PROCESS = const CacheState('IN_PROCESS', 2);
7025
7026 /**
7027 * The data is not in the cache and needs to be recomputed so that results can
7028 * be reported.
7029 *
7030 * Valid Transitions:
7031 * * [IN_PROCESS] if an attempt is being made to recompute the data
7032 */
7033 static const CacheState INVALID = const CacheState('INVALID', 3);
7034
7035 /**
7036 * The data is in the cache and up-to-date.
7037 *
7038 * Valid Transitions:
7039 * * [FLUSHED] if the data is removed in order to manage memory usage
7040 * * [INVALID] if a source was modified in such a way as to invalidate the
7041 * previous data
7042 */
7043 static const CacheState VALID = const CacheState('VALID', 4);
7044
7045 static const List<CacheState> values = const [
7046 ERROR,
7047 FLUSHED,
7048 IN_PROCESS,
7049 INVALID,
7050 VALID
7051 ];
7052
7053 const CacheState(String name, int ordinal) : super(name, ordinal);
7054 }
7055
7056 /**
7057 * An object that represents a change to the analysis results associated with a
7058 * given source.
7059 */
7060 abstract class ChangeNotice implements AnalysisErrorInfo {
7061 /**
7062 * The parsed, but maybe not resolved Dart AST that changed as a result of
7063 * the analysis, or `null` if the AST was not changed.
7064 */
7065 CompilationUnit get parsedDartUnit;
7066
7067 /**
7068 * The fully resolved Dart AST that changed as a result of the analysis, or
7069 * `null` if the AST was not changed.
7070 */
7071 CompilationUnit get resolvedDartUnit;
7072
7073 /**
7074 * The fully resolved HTML AST that changed as a result of the analysis, or
7075 * `null` if the AST was not changed.
7076 */
7077 @deprecated
7078 ht.HtmlUnit get resolvedHtmlUnit;
7079
7080 /**
7081 * Return the source for which the result is being reported.
7082 */
7083 Source get source;
7084 }
7085
7086 /**
7087 * An implementation of a [ChangeNotice].
7088 */
7089 class ChangeNoticeImpl implements ChangeNotice {
7090 /**
7091 * An empty list of change notices.
7092 */
7093 static const List<ChangeNoticeImpl> EMPTY_LIST = const <ChangeNoticeImpl>[];
7094
7095 /**
7096 * The source for which the result is being reported.
7097 */
7098 final Source source;
7099
7100 /**
7101 * The parsed, but maybe not resolved Dart AST that changed as a result of
7102 * the analysis, or `null` if the AST was not changed.
7103 */
7104 CompilationUnit parsedDartUnit;
7105
7106 /**
7107 * The fully resolved Dart AST that changed as a result of the analysis, or
7108 * `null` if the AST was not changed.
7109 */
7110 CompilationUnit resolvedDartUnit;
7111
7112 /**
7113 * The fully resolved HTML AST that changed as a result of the analysis, or
7114 * `null` if the AST was not changed.
7115 */
7116 @deprecated
7117 ht.HtmlUnit resolvedHtmlUnit;
7118
7119 /**
7120 * The errors that changed as a result of the analysis, or `null` if errors
7121 * were not changed.
7122 */
7123 List<AnalysisError> _errors;
7124
7125 /**
7126 * The line information associated with the source, or `null` if errors were
7127 * not changed.
7128 */
7129 LineInfo _lineInfo;
7130
7131 /**
7132 * Initialize a newly created notice associated with the given source.
7133 *
7134 * @param source the source for which the change is being reported
7135 */
7136 ChangeNoticeImpl(this.source);
7137
7138 @override
7139 List<AnalysisError> get errors => _errors;
7140
7141 @override
7142 LineInfo get lineInfo => _lineInfo;
7143
7144 /**
7145 * Set the errors that changed as a result of the analysis to the given
7146 * [errors] and set the line information to the given [lineInfo].
7147 */
7148 void setErrors(List<AnalysisError> errors, LineInfo lineInfo) {
7149 this._errors = errors;
7150 this._lineInfo = lineInfo;
7151 if (lineInfo == null) {
7152 AnalysisEngine.instance.logger.logInformation("No line info: $source",
7153 new CaughtException(new AnalysisException(), null));
7154 }
7155 }
7156
7157 @override
7158 String toString() => "Changes for ${source.fullName}";
7159 }
7160
7161 /**
7162 * An indication of which sources have been added, changed, removed, or deleted.
7163 * In the case of a changed source, there are multiple ways of indicating the
7164 * nature of the change.
7165 *
7166 * No source should be added to the change set more than once, either with the
7167 * same or a different kind of change. It does not make sense, for example, for
7168 * a source to be both added and removed, and it is redundant for a source to be
7169 * marked as changed in its entirety and changed in some specific range.
7170 */
7171 class ChangeSet {
7172 /**
7173 * A list containing the sources that have been added.
7174 */
7175 final List<Source> addedSources = new List<Source>();
7176
7177 /**
7178 * A list containing the sources that have been changed.
7179 */
7180 final List<Source> changedSources = new List<Source>();
7181
7182 /**
7183 * A table mapping the sources whose content has been changed to the current
7184 * content of those sources.
7185 */
7186 HashMap<Source, String> _changedContent = new HashMap<Source, String>();
7187
7188 /**
7189 * A table mapping the sources whose content has been changed within a single
7190 * range to the current content of those sources and information about the
7191 * affected range.
7192 */
7193 final HashMap<Source, ChangeSet_ContentChange> changedRanges =
7194 new HashMap<Source, ChangeSet_ContentChange>();
7195
7196 /**
7197 * A list containing the sources that have been removed.
7198 */
7199 final List<Source> removedSources = new List<Source>();
7200
7201 /**
7202 * A list containing the source containers specifying additional sources that
7203 * have been removed.
7204 */
7205 final List<SourceContainer> removedContainers = new List<SourceContainer>();
7206
7207 /**
7208 * A list containing the sources that have been deleted.
7209 */
7210 final List<Source> deletedSources = new List<Source>();
7211
7212 /**
7213 * Return a table mapping the sources whose content has been changed to the
7214 * current content of those sources.
7215 */
7216 Map<Source, String> get changedContents => _changedContent;
7217
7218 /**
7219 * Return `true` if this change set does not contain any changes.
7220 */
7221 bool get isEmpty => addedSources.isEmpty &&
7222 changedSources.isEmpty &&
7223 _changedContent.isEmpty &&
7224 changedRanges.isEmpty &&
7225 removedSources.isEmpty &&
7226 removedContainers.isEmpty &&
7227 deletedSources.isEmpty;
7228
7229 /**
7230 * Record that the specified [source] has been added and that its content is
7231 * the default contents of the source.
7232 */
7233 void addedSource(Source source) {
7234 addedSources.add(source);
7235 }
7236
7237 /**
7238 * Record that the specified [source] has been changed and that its content is
7239 * the given [contents].
7240 */
7241 void changedContent(Source source, String contents) {
7242 _changedContent[source] = contents;
7243 }
7244
7245 /**
7246 * Record that the specified [source] has been changed and that its content is
7247 * the given [contents]. The [offset] is the offset into the current contents.
7248 * The [oldLength] is the number of characters in the original contents that
7249 * were replaced. The [newLength] is the number of characters in the
7250 * replacement text.
7251 */
7252 void changedRange(Source source, String contents, int offset, int oldLength,
7253 int newLength) {
7254 changedRanges[source] =
7255 new ChangeSet_ContentChange(contents, offset, oldLength, newLength);
7256 }
7257
7258 /**
7259 * Record that the specified [source] has been changed. If the content of the
7260 * source was previously overridden, this has no effect (the content remains
7261 * overridden). To cancel (or change) the override, use [changedContent]
7262 * instead.
7263 */
7264 void changedSource(Source source) {
7265 changedSources.add(source);
7266 }
7267
7268 /**
7269 * Record that the specified [source] has been deleted.
7270 */
7271 void deletedSource(Source source) {
7272 deletedSources.add(source);
7273 }
7274
7275 /**
7276 * Record that the specified source [container] has been removed.
7277 */
7278 void removedContainer(SourceContainer container) {
7279 if (container != null) {
7280 removedContainers.add(container);
7281 }
7282 }
7283
7284 /**
7285 * Record that the specified [source] has been removed.
7286 */
7287 void removedSource(Source source) {
7288 if (source != null) {
7289 removedSources.add(source);
7290 }
7291 }
7292
7293 @override
7294 String toString() {
7295 StringBuffer buffer = new StringBuffer();
7296 bool needsSeparator =
7297 _appendSources(buffer, addedSources, false, "addedSources");
7298 needsSeparator = _appendSources(
7299 buffer, changedSources, needsSeparator, "changedSources");
7300 needsSeparator = _appendSources2(
7301 buffer, _changedContent, needsSeparator, "changedContent");
7302 needsSeparator =
7303 _appendSources2(buffer, changedRanges, needsSeparator, "changedRanges");
7304 needsSeparator = _appendSources(
7305 buffer, deletedSources, needsSeparator, "deletedSources");
7306 needsSeparator = _appendSources(
7307 buffer, removedSources, needsSeparator, "removedSources");
7308 int count = removedContainers.length;
7309 if (count > 0) {
7310 if (removedSources.isEmpty) {
7311 if (needsSeparator) {
7312 buffer.write("; ");
7313 }
7314 buffer.write("removed: from ");
7315 buffer.write(count);
7316 buffer.write(" containers");
7317 } else {
7318 buffer.write(", and more from ");
7319 buffer.write(count);
7320 buffer.write(" containers");
7321 }
7322 }
7323 return buffer.toString();
7324 }
7325
7326 /**
7327 * Append the given [sources] to the given [buffer], prefixed with the given
7328 * [label] and a separator if [needsSeparator] is `true`. Return `true` if
7329 * future lists of sources will need a separator.
7330 */
7331 bool _appendSources(StringBuffer buffer, List<Source> sources,
7332 bool needsSeparator, String label) {
7333 if (sources.isEmpty) {
7334 return needsSeparator;
7335 }
7336 if (needsSeparator) {
7337 buffer.write("; ");
7338 }
7339 buffer.write(label);
7340 String prefix = " ";
7341 for (Source source in sources) {
7342 buffer.write(prefix);
7343 buffer.write(source.fullName);
7344 prefix = ", ";
7345 }
7346 return true;
7347 }
7348
7349 /**
7350 * Append the given [sources] to the given [builder], prefixed with the given
7351 * [label] and a separator if [needsSeparator] is `true`. Return `true` if
7352 * future lists of sources will need a separator.
7353 */
7354 bool _appendSources2(StringBuffer buffer, HashMap<Source, dynamic> sources,
7355 bool needsSeparator, String label) {
7356 if (sources.isEmpty) {
7357 return needsSeparator;
7358 }
7359 if (needsSeparator) {
7360 buffer.write("; ");
7361 }
7362 buffer.write(label);
7363 String prefix = " ";
7364 for (Source source in sources.keys.toSet()) {
7365 buffer.write(prefix);
7366 buffer.write(source.fullName);
7367 prefix = ", ";
7368 }
7369 return true;
7370 }
7371 }
7372
7373 /**
7374 * A change to the content of a source.
7375 */
7376 class ChangeSet_ContentChange {
7377 /**
7378 * The new contents of the source.
7379 */
7380 final String contents;
7381
7382 /**
7383 * The offset into the current contents.
7384 */
7385 final int offset;
7386
7387 /**
7388 * The number of characters in the original contents that were replaced
7389 */
7390 final int oldLength;
7391
7392 /**
7393 * The number of characters in the replacement text.
7394 */
7395 final int newLength;
7396
7397 /**
7398 * Initialize a newly created change object to represent a change to the
7399 * content of a source. The [contents] is the new contents of the source. The
7400 * [offse] ist the offset into the current contents. The [oldLength] is the
7401 * number of characters in the original contents that were replaced. The
7402 * [newLength] is the number of characters in the replacement text.
7403 */
7404 ChangeSet_ContentChange(
7405 this.contents, this.offset, this.oldLength, this.newLength);
7406 }
7407
7408 /**
7409 * [ComputedResult] describes a value computed for a [ResultDescriptor].
7410 */
7411 class ComputedResult<V> {
7412 /**
7413 * The context in which the value was computed.
7414 */
7415 final AnalysisContext context;
7416
7417 /**
7418 * The descriptor of the result which was computed.
7419 */
7420 final ResultDescriptor<V> descriptor;
7421
7422 /**
7423 * The target for which the result was computed.
7424 */
7425 final AnalysisTarget target;
7426
7427 /**
7428 * The computed value.
7429 */
7430 final V value;
7431
7432 ComputedResult(this.context, this.descriptor, this.target, this.value);
7433
7434 @override
7435 String toString() => '$descriptor of $target in $context';
7436 }
7437
7438 /**
7439 * A pair containing a library and a list of the (source, entry) pairs for
7440 * compilation units in the library.
7441 */
7442 class CycleBuilder_LibraryPair {
7443 /**
7444 * The library containing the compilation units.
7445 */
7446 ResolvableLibrary library;
7447
7448 /**
7449 * The (source, entry) pairs representing the compilation units in the
7450 * library.
7451 */
7452 List<CycleBuilder_SourceEntryPair> entryPairs;
7453
7454 /**
7455 * Initialize a newly created pair from the given [library] and [entryPairs].
7456 */
7457 CycleBuilder_LibraryPair(this.library, this.entryPairs);
7458 }
7459
7460 /**
7461 * A pair containing a source and the cache entry associated with that source.
7462 * They are used to reduce the number of times an entry must be looked up in the
7463 * cache.
7464 */
7465 class CycleBuilder_SourceEntryPair {
7466 /**
7467 * The source associated with the entry.
7468 */
7469 Source source;
7470
7471 /**
7472 * The entry associated with the source.
7473 */
7474 DartEntry entry;
7475
7476 /**
7477 * Initialize a newly created pair from the given [source] and [entry].
7478 */
7479 CycleBuilder_SourceEntryPair(this.source, this.entry);
7480 }
7481
7482 /**
7483 * The information cached by an analysis context about an individual Dart file.
7484 */
7485 class DartEntry extends SourceEntry {
7486 /**
7487 * The data descriptor representing the element model representing a single
7488 * compilation unit. This model is incomplete and should not be used except as
7489 * input to another task.
7490 */
7491 static final DataDescriptor<List<AnalysisError>> BUILT_ELEMENT =
7492 new DataDescriptor<List<AnalysisError>>("DartEntry.BUILT_ELEMENT");
7493
7494 /**
7495 * The data descriptor representing the AST structure after the element model
7496 * has been built (and declarations are resolved) but before other resolution
7497 * has been performed.
7498 */
7499 static final DataDescriptor<CompilationUnit> BUILT_UNIT =
7500 new DataDescriptor<CompilationUnit>("DartEntry.BUILT_UNIT");
7501
7502 /**
7503 * The data descriptor representing the list of libraries that contain this
7504 * compilation unit.
7505 */
7506 static final DataDescriptor<List<Source>> CONTAINING_LIBRARIES =
7507 new DataDescriptor<List<Source>>(
7508 "DartEntry.CONTAINING_LIBRARIES", Source.EMPTY_LIST);
7509
7510 /**
7511 * The data descriptor representing the library element for the library. This
7512 * data is only available for Dart files that are the defining compilation
7513 * unit of a library.
7514 */
7515 static final DataDescriptor<LibraryElement> ELEMENT =
7516 new DataDescriptor<LibraryElement>("DartEntry.ELEMENT");
7517
7518 /**
7519 * The data descriptor representing the list of exported libraries. This data
7520 * is only available for Dart files that are the defining compilation unit of
7521 * a library.
7522 */
7523 static final DataDescriptor<List<Source>> EXPORTED_LIBRARIES =
7524 new DataDescriptor<List<Source>>(
7525 "DartEntry.EXPORTED_LIBRARIES", Source.EMPTY_LIST);
7526
7527 /**
7528 * The data descriptor representing the hints resulting from auditing the
7529 * source.
7530 */
7531 static final DataDescriptor<List<AnalysisError>> HINTS =
7532 new DataDescriptor<List<AnalysisError>>(
7533 "DartEntry.HINTS", AnalysisError.NO_ERRORS);
7534
7535 /**
7536 * The data descriptor representing the list of imported libraries. This data
7537 * is only available for Dart files that are the defining compilation unit of
7538 * a library.
7539 */
7540 static final DataDescriptor<List<Source>> IMPORTED_LIBRARIES =
7541 new DataDescriptor<List<Source>>(
7542 "DartEntry.IMPORTED_LIBRARIES", Source.EMPTY_LIST);
7543
7544 /**
7545 * The data descriptor representing the list of included parts. This data is
7546 * only available for Dart files that are the defining compilation unit of a
7547 * library.
7548 */
7549 static final DataDescriptor<List<Source>> INCLUDED_PARTS =
7550 new DataDescriptor<List<Source>>(
7551 "DartEntry.INCLUDED_PARTS", Source.EMPTY_LIST);
7552
7553 /**
7554 * The data descriptor representing the client flag. This data is only
7555 * available for Dart files that are the defining compilation unit of a
7556 * library.
7557 */
7558 static final DataDescriptor<bool> IS_CLIENT =
7559 new DataDescriptor<bool>("DartEntry.IS_CLIENT", false);
7560
7561 /**
7562 * The data descriptor representing the launchable flag. This data is only
7563 * available for Dart files that are the defining compilation unit of a
7564 * library.
7565 */
7566 static final DataDescriptor<bool> IS_LAUNCHABLE =
7567 new DataDescriptor<bool>("DartEntry.IS_LAUNCHABLE", false);
7568
7569 /**
7570 * The data descriptor representing lint warnings resulting from auditing the
7571 * source.
7572 */
7573 static final DataDescriptor<List<AnalysisError>> LINTS =
7574 new DataDescriptor<List<AnalysisError>>(
7575 "DartEntry.LINTS", AnalysisError.NO_ERRORS);
7576
7577 /**
7578 * The data descriptor representing the errors resulting from parsing the
7579 * source.
7580 */
7581 static final DataDescriptor<List<AnalysisError>> PARSE_ERRORS =
7582 new DataDescriptor<List<AnalysisError>>(
7583 "DartEntry.PARSE_ERRORS", AnalysisError.NO_ERRORS);
7584
7585 /**
7586 * The data descriptor representing the parsed AST structure.
7587 */
7588 static final DataDescriptor<CompilationUnit> PARSED_UNIT =
7589 new DataDescriptor<CompilationUnit>("DartEntry.PARSED_UNIT");
7590
7591 /**
7592 * The data descriptor representing the public namespace of the library. This
7593 * data is only available for Dart files that are the defining compilation
7594 * unit of a library.
7595 */
7596 static final DataDescriptor<Namespace> PUBLIC_NAMESPACE =
7597 new DataDescriptor<Namespace>("DartEntry.PUBLIC_NAMESPACE");
7598
7599 /**
7600 * The data descriptor representing the errors resulting from resolving the
7601 * source.
7602 */
7603 static final DataDescriptor<List<AnalysisError>> RESOLUTION_ERRORS =
7604 new DataDescriptor<List<AnalysisError>>(
7605 "DartEntry.RESOLUTION_ERRORS", AnalysisError.NO_ERRORS);
7606
7607 /**
7608 * The data descriptor representing the resolved AST structure.
7609 */
7610 static final DataDescriptor<CompilationUnit> RESOLVED_UNIT =
7611 new DataDescriptor<CompilationUnit>("DartEntry.RESOLVED_UNIT");
7612
7613 /**
7614 * The data descriptor representing the errors resulting from scanning the
7615 * source.
7616 */
7617 static final DataDescriptor<List<AnalysisError>> SCAN_ERRORS =
7618 new DataDescriptor<List<AnalysisError>>(
7619 "DartEntry.SCAN_ERRORS", AnalysisError.NO_ERRORS);
7620
7621 /**
7622 * The data descriptor representing the source kind.
7623 */
7624 static final DataDescriptor<SourceKind> SOURCE_KIND =
7625 new DataDescriptor<SourceKind>(
7626 "DartEntry.SOURCE_KIND", SourceKind.UNKNOWN);
7627
7628 /**
7629 * The data descriptor representing the token stream.
7630 */
7631 static final DataDescriptor<Token> TOKEN_STREAM =
7632 new DataDescriptor<Token>("DartEntry.TOKEN_STREAM");
7633
7634 /**
7635 * The data descriptor representing the errors resulting from verifying the
7636 * source.
7637 */
7638 static final DataDescriptor<List<AnalysisError>> VERIFICATION_ERRORS =
7639 new DataDescriptor<List<AnalysisError>>(
7640 "DartEntry.VERIFICATION_ERRORS", AnalysisError.NO_ERRORS);
7641
7642 /**
7643 * The list of libraries that contain this compilation unit. The list will be
7644 * empty if there are no known libraries that contain this compilation unit.
7645 */
7646 List<Source> _containingLibraries = new List<Source>();
7647
7648 /**
7649 * The information known as a result of resolving this compilation unit as
7650 * part of the library that contains this unit. This field will never be
7651 * `null`.
7652 */
7653 ResolutionState _resolutionState = new ResolutionState();
7654
7655 /**
7656 * Return all of the errors associated with the compilation unit that are
7657 * currently cached.
7658 */
7659 List<AnalysisError> get allErrors {
7660 List<AnalysisError> errors = new List<AnalysisError>();
7661 errors.addAll(super.allErrors);
7662 errors.addAll(getValue(SCAN_ERRORS));
7663 errors.addAll(getValue(PARSE_ERRORS));
7664 ResolutionState state = _resolutionState;
7665 while (state != null) {
7666 errors.addAll(state.getValue(RESOLUTION_ERRORS));
7667 errors.addAll(state.getValue(VERIFICATION_ERRORS));
7668 errors.addAll(state.getValue(HINTS));
7669 errors.addAll(state.getValue(LINTS));
7670 state = state._nextState;
7671 }
7672 if (errors.length == 0) {
7673 return AnalysisError.NO_ERRORS;
7674 }
7675 return errors;
7676 }
7677
7678 /**
7679 * Return a valid parsed compilation unit, either an unresolved AST structure
7680 * or the result of resolving the AST structure in the context of some
7681 * library, or `null` if there is no parsed compilation unit available.
7682 */
7683 CompilationUnit get anyParsedCompilationUnit {
7684 if (getState(PARSED_UNIT) == CacheState.VALID) {
7685 return getValue(PARSED_UNIT);
7686 }
7687 ResolutionState state = _resolutionState;
7688 while (state != null) {
7689 if (state.getState(BUILT_UNIT) == CacheState.VALID) {
7690 return state.getValue(BUILT_UNIT);
7691 }
7692 state = state._nextState;
7693 }
7694
7695 return anyResolvedCompilationUnit;
7696 }
7697
7698 /**
7699 * Return the result of resolving the compilation unit as part of any library,
7700 * or `null` if there is no cached resolved compilation unit.
7701 */
7702 CompilationUnit get anyResolvedCompilationUnit {
7703 ResolutionState state = _resolutionState;
7704 while (state != null) {
7705 if (state.getState(RESOLVED_UNIT) == CacheState.VALID) {
7706 return state.getValue(RESOLVED_UNIT);
7707 }
7708 state = state._nextState;
7709 }
7710 return null;
7711 }
7712
7713 /**
7714 * The libraries that are known to contain this part.
7715 */
7716 List<Source> get containingLibraries => _containingLibraries;
7717
7718 /**
7719 * Set the list of libraries that contain this compilation unit to contain
7720 * only the given [librarySource]. This method should only be invoked on
7721 * entries that represent a library.
7722 */
7723 void set containingLibrary(Source librarySource) {
7724 _containingLibraries.clear();
7725 _containingLibraries.add(librarySource);
7726 }
7727
7728 @override
7729 List<DataDescriptor> get descriptors {
7730 List<DataDescriptor> result = super.descriptors;
7731 result.addAll(<DataDescriptor>[
7732 DartEntry.SOURCE_KIND,
7733 DartEntry.CONTAINING_LIBRARIES,
7734 DartEntry.PARSE_ERRORS,
7735 DartEntry.PARSED_UNIT,
7736 DartEntry.SCAN_ERRORS,
7737 DartEntry.SOURCE_KIND,
7738 DartEntry.TOKEN_STREAM
7739 ]);
7740 SourceKind kind = getValue(DartEntry.SOURCE_KIND);
7741 if (kind == SourceKind.LIBRARY) {
7742 result.addAll(<DataDescriptor>[
7743 DartEntry.ELEMENT,
7744 DartEntry.EXPORTED_LIBRARIES,
7745 DartEntry.IMPORTED_LIBRARIES,
7746 DartEntry.INCLUDED_PARTS,
7747 DartEntry.IS_CLIENT,
7748 DartEntry.IS_LAUNCHABLE,
7749 DartEntry.PUBLIC_NAMESPACE
7750 ]);
7751 }
7752 return result;
7753 }
7754
7755 /**
7756 * Return `true` if this entry has an AST structure that can be resolved, even
7757 * if it needs to be copied. Returning `true` implies that the method
7758 * [resolvableCompilationUnit] will return a non-`null` result.
7759 */
7760 bool get hasResolvableCompilationUnit {
7761 if (getState(PARSED_UNIT) == CacheState.VALID) {
7762 return true;
7763 }
7764 ResolutionState state = _resolutionState;
7765 while (state != null) {
7766 if (state.getState(BUILT_UNIT) == CacheState.VALID ||
7767 state.getState(RESOLVED_UNIT) == CacheState.VALID) {
7768 return true;
7769 }
7770 state = state._nextState;
7771 }
7772
7773 return false;
7774 }
7775
7776 @override
7777 SourceKind get kind => getValue(SOURCE_KIND);
7778
7779 /**
7780 * The library sources containing the receiver's source.
7781 */
7782 List<Source> get librariesContaining {
7783 ResolutionState state = _resolutionState;
7784 List<Source> result = new List<Source>();
7785 while (state != null) {
7786 if (state._librarySource != null) {
7787 result.add(state._librarySource);
7788 }
7789 state = state._nextState;
7790 }
7791 return result;
7792 }
7793
7794 /**
7795 * Get a list of all the library-dependent descriptors for which values may
7796 * be stored in this SourceEntry.
7797 */
7798 List<DataDescriptor> get libraryDescriptors {
7799 return <DataDescriptor>[
7800 DartEntry.BUILT_ELEMENT,
7801 DartEntry.BUILT_UNIT,
7802 DartEntry.RESOLUTION_ERRORS,
7803 DartEntry.RESOLVED_UNIT,
7804 DartEntry.VERIFICATION_ERRORS,
7805 DartEntry.HINTS,
7806 DartEntry.LINTS
7807 ];
7808 }
7809
7810 /**
7811 * A compilation unit that has not been accessed by any other client and can
7812 * therefore safely be modified by the reconciler, or `null` if the source has
7813 * not been parsed.
7814 */
7815 CompilationUnit get resolvableCompilationUnit {
7816 if (getState(PARSED_UNIT) == CacheState.VALID) {
7817 CompilationUnit unit = getValue(PARSED_UNIT);
7818 setState(PARSED_UNIT, CacheState.FLUSHED);
7819 return unit;
7820 }
7821 ResolutionState state = _resolutionState;
7822 while (state != null) {
7823 if (state.getState(BUILT_UNIT) == CacheState.VALID) {
7824 // TODO(brianwilkerson) We're cloning the structure to remove any
7825 // previous resolution data, but I'm not sure that's necessary.
7826 return state.getValue(BUILT_UNIT).accept(new AstCloner());
7827 }
7828 if (state.getState(RESOLVED_UNIT) == CacheState.VALID) {
7829 return state.getValue(RESOLVED_UNIT).accept(new AstCloner());
7830 }
7831 state = state._nextState;
7832 }
7833 return null;
7834 }
7835
7836 /**
7837 * Add the given [librarySource] to the list of libraries that contain this
7838 * part. This method should only be invoked on entries that represent a part.
7839 */
7840 void addContainingLibrary(Source librarySource) {
7841 _containingLibraries.add(librarySource);
7842 }
7843
7844 /**
7845 * Flush any AST structures being maintained by this entry.
7846 */
7847 void flushAstStructures() {
7848 _flush(TOKEN_STREAM);
7849 _flush(PARSED_UNIT);
7850 _resolutionState.flushAstStructures();
7851 }
7852
7853 /**
7854 * Return the state of the data represented by the given [descriptor] in the
7855 * context of the given [librarySource].
7856 */
7857 CacheState getStateInLibrary(
7858 DataDescriptor descriptor, Source librarySource) {
7859 if (!_isValidLibraryDescriptor(descriptor)) {
7860 throw new ArgumentError("Invalid descriptor: $descriptor");
7861 }
7862 ResolutionState state = _resolutionState;
7863 while (state != null) {
7864 if (librarySource == state._librarySource) {
7865 return state.getState(descriptor);
7866 }
7867 state = state._nextState;
7868 }
7869 return CacheState.INVALID;
7870 }
7871
7872 /**
7873 * Return the value of the data represented by the given [descriptor] in the
7874 * context of the given [librarySource], or `null` if the data represented by
7875 * the descriptor is not in the cache.
7876 */
7877 Object getValueInLibrary(DataDescriptor descriptor, Source librarySource) {
7878 if (!_isValidLibraryDescriptor(descriptor)) {
7879 throw new ArgumentError("Invalid descriptor: $descriptor");
7880 }
7881 ResolutionState state = _resolutionState;
7882 while (state != null) {
7883 if (librarySource == state._librarySource) {
7884 return state.getValue(descriptor);
7885 }
7886 state = state._nextState;
7887 }
7888 return descriptor.defaultValue;
7889 }
7890
7891 /**
7892 * Return `true` if the data represented by the given [descriptor] is marked
7893 * as being invalid. If the descriptor represents library-specific data then
7894 * this method will return `true` if the data associated with any library it
7895 * marked as invalid.
7896 */
7897 bool hasInvalidData(DataDescriptor descriptor) {
7898 if (_isValidDescriptor(descriptor)) {
7899 return getState(descriptor) == CacheState.INVALID;
7900 } else if (_isValidLibraryDescriptor(descriptor)) {
7901 ResolutionState state = _resolutionState;
7902 while (state != null) {
7903 if (state.getState(descriptor) == CacheState.INVALID) {
7904 return true;
7905 }
7906 state = state._nextState;
7907 }
7908 }
7909 return false;
7910 }
7911
7912 @override
7913 void invalidateAllInformation() {
7914 super.invalidateAllInformation();
7915 setState(SCAN_ERRORS, CacheState.INVALID);
7916 setState(TOKEN_STREAM, CacheState.INVALID);
7917 setState(SOURCE_KIND, CacheState.INVALID);
7918 setState(PARSE_ERRORS, CacheState.INVALID);
7919 setState(PARSED_UNIT, CacheState.INVALID);
7920 _discardCachedResolutionInformation(true);
7921 }
7922
7923 /**
7924 * Invalidate all of the resolution information associated with the
7925 * compilation unit. The flag [invalidateUris] should be `true` if the cached
7926 * results of converting URIs to source files should also be invalidated.
7927 */
7928 void invalidateAllResolutionInformation(bool invalidateUris) {
7929 if (getState(PARSED_UNIT) == CacheState.FLUSHED) {
7930 ResolutionState state = _resolutionState;
7931 while (state != null) {
7932 if (state.getState(BUILT_UNIT) == CacheState.VALID) {
7933 CompilationUnit unit = state.getValue(BUILT_UNIT);
7934 setValue(PARSED_UNIT, unit.accept(new AstCloner()));
7935 break;
7936 } else if (state.getState(RESOLVED_UNIT) == CacheState.VALID) {
7937 CompilationUnit unit = state.getValue(RESOLVED_UNIT);
7938 setValue(PARSED_UNIT, unit.accept(new AstCloner()));
7939 break;
7940 }
7941 state = state._nextState;
7942 }
7943 }
7944 _discardCachedResolutionInformation(invalidateUris);
7945 }
7946
7947 /**
7948 * Invalidate all of the parse and resolution information associated with
7949 * this source.
7950 */
7951 void invalidateParseInformation() {
7952 setState(SOURCE_KIND, CacheState.INVALID);
7953 setState(PARSE_ERRORS, CacheState.INVALID);
7954 setState(PARSED_UNIT, CacheState.INVALID);
7955 _containingLibraries.clear();
7956 _discardCachedResolutionInformation(true);
7957 }
7958
7959 /**
7960 * Record that an [exception] occurred while attempting to build the element
7961 * model for the source represented by this entry in the context of the given
7962 * [library]. This will set the state of all resolution-based information as
7963 * being in error, but will not change the state of any parse results.
7964 */
7965 void recordBuildElementErrorInLibrary(
7966 Source librarySource, CaughtException exception) {
7967 setStateInLibrary(BUILT_ELEMENT, librarySource, CacheState.ERROR);
7968 setStateInLibrary(BUILT_UNIT, librarySource, CacheState.ERROR);
7969 recordResolutionErrorInLibrary(librarySource, exception);
7970 }
7971
7972 @override
7973 void recordContentError(CaughtException exception) {
7974 super.recordContentError(exception);
7975 recordScanError(exception);
7976 }
7977
7978 /**
7979 * Record that an error occurred while attempting to generate hints for the
7980 * source represented by this entry. This will set the state of all
7981 * verification information as being in error. The [librarySource] is the
7982 * source of the library in which hints were being generated. The [exception]
7983 * is the exception that shows where the error occurred.
7984 */
7985 void recordHintErrorInLibrary(
7986 Source librarySource, CaughtException exception) {
7987 this.exception = exception;
7988 ResolutionState state = _getOrCreateResolutionState(librarySource);
7989 state.recordHintError();
7990 }
7991
7992 /**
7993 * Record that an error occurred while attempting to generate lints for the
7994 * source represented by this entry. This will set the state of all
7995 * verification information as being in error. The [librarySource] is the
7996 * source of the library in which lints were being generated. The [exception]
7997 * is the exception that shows where the error occurred.
7998 */
7999 void recordLintErrorInLibrary(
8000 Source librarySource, CaughtException exception) {
8001 this.exception = exception;
8002 ResolutionState state = _getOrCreateResolutionState(librarySource);
8003 state.recordLintError();
8004 }
8005
8006 /**
8007 * Record that an [exception] occurred while attempting to scan or parse the
8008 * entry represented by this entry. This will set the state of all information ,
8009 * including any resolution-based information, as being in error.
8010 */
8011 void recordParseError(CaughtException exception) {
8012 setState(SOURCE_KIND, CacheState.ERROR);
8013 setState(PARSE_ERRORS, CacheState.ERROR);
8014 setState(PARSED_UNIT, CacheState.ERROR);
8015 setState(EXPORTED_LIBRARIES, CacheState.ERROR);
8016 setState(IMPORTED_LIBRARIES, CacheState.ERROR);
8017 setState(INCLUDED_PARTS, CacheState.ERROR);
8018 recordResolutionError(exception);
8019 }
8020
8021 /**
8022 * Record that an [exception] occurred while attempting to resolve the source
8023 * represented by this entry. This will set the state of all resolution-based
8024 * information as being in error, but will not change the state of any parse
8025 * results.
8026 */
8027 void recordResolutionError(CaughtException exception) {
8028 this.exception = exception;
8029 setState(ELEMENT, CacheState.ERROR);
8030 setState(IS_CLIENT, CacheState.ERROR);
8031 setState(IS_LAUNCHABLE, CacheState.ERROR);
8032 setState(PUBLIC_NAMESPACE, CacheState.ERROR);
8033 _resolutionState.recordResolutionErrorsInAllLibraries();
8034 }
8035
8036 /**
8037 * Record that an error occurred while attempting to resolve the source
8038 * represented by this entry. This will set the state of all resolution-based
8039 * information as being in error, but will not change the state of any parse
8040 * results. The [librarySource] is the source of the library in which
8041 * resolution was being performed. The [exception] is the exception that shows
8042 * where the error occurred.
8043 */
8044 void recordResolutionErrorInLibrary(
8045 Source librarySource, CaughtException exception) {
8046 this.exception = exception;
8047 setState(ELEMENT, CacheState.ERROR);
8048 setState(IS_CLIENT, CacheState.ERROR);
8049 setState(IS_LAUNCHABLE, CacheState.ERROR);
8050 setState(PUBLIC_NAMESPACE, CacheState.ERROR);
8051 ResolutionState state = _getOrCreateResolutionState(librarySource);
8052 state.recordResolutionError();
8053 }
8054
8055 /**
8056 * Record that an [exception] occurred while attempting to scan or parse the
8057 * entry represented by this entry. This will set the state of all
8058 * information, including any resolution-based information, as being in error.
8059 */
8060 @override
8061 void recordScanError(CaughtException exception) {
8062 super.recordScanError(exception);
8063 setState(SCAN_ERRORS, CacheState.ERROR);
8064 setState(TOKEN_STREAM, CacheState.ERROR);
8065 recordParseError(exception);
8066 }
8067
8068 /**
8069 * Record that an [exception] occurred while attempting to generate errors and
8070 * warnings for the source represented by this entry. This will set the state
8071 * of all verification information as being in error. The [librarySource] is
8072 * the source of the library in which verification was being performed. The
8073 * [exception] is the exception that shows where the error occurred.
8074 */
8075 void recordVerificationErrorInLibrary(
8076 Source librarySource, CaughtException exception) {
8077 this.exception = exception;
8078 ResolutionState state = _getOrCreateResolutionState(librarySource);
8079 state.recordVerificationError();
8080 }
8081
8082 /**
8083 * Remove the given [library] from the list of libraries that contain this
8084 * part. This method should only be invoked on entries that represent a part.
8085 */
8086 void removeContainingLibrary(Source library) {
8087 _containingLibraries.remove(library);
8088 }
8089
8090 /**
8091 * Remove any resolution information associated with this compilation unit
8092 * being part of the given [library], presumably because it is no longer part
8093 * of the library.
8094 */
8095 void removeResolution(Source library) {
8096 if (library != null) {
8097 if (library == _resolutionState._librarySource) {
8098 if (_resolutionState._nextState == null) {
8099 _resolutionState.invalidateAllResolutionInformation();
8100 } else {
8101 _resolutionState = _resolutionState._nextState;
8102 }
8103 } else {
8104 ResolutionState priorState = _resolutionState;
8105 ResolutionState state = _resolutionState._nextState;
8106 while (state != null) {
8107 if (library == state._librarySource) {
8108 priorState._nextState = state._nextState;
8109 break;
8110 }
8111 priorState = state;
8112 state = state._nextState;
8113 }
8114 }
8115 }
8116 }
8117
8118 /**
8119 * Set the state of the data represented by the given [descriptor] in the
8120 * context of the given [library] to the given [state].
8121 */
8122 void setStateInLibrary(
8123 DataDescriptor descriptor, Source library, CacheState state) {
8124 if (!_isValidLibraryDescriptor(descriptor)) {
8125 throw new ArgumentError("Invalid descriptor: $descriptor");
8126 }
8127 ResolutionState resolutionState = _getOrCreateResolutionState(library);
8128 resolutionState.setState(descriptor, state);
8129 }
8130
8131 /**
8132 * Set the value of the data represented by the given [descriptor] in the
8133 * context of the given [library] to the given [value], and set the state of
8134 * that data to [CacheState.VALID].
8135 */
8136 void setValueInLibrary(
8137 DataDescriptor descriptor, Source library, Object value) {
8138 if (!_isValidLibraryDescriptor(descriptor)) {
8139 throw new ArgumentError("Invalid descriptor: $descriptor");
8140 }
8141 ResolutionState state = _getOrCreateResolutionState(library);
8142 state.setValue(descriptor, value);
8143 }
8144
8145 /**
8146 * Invalidate all of the resolution information associated with the
8147 * compilation unit. The flag [invalidateUris] should be `true` if the cached
8148 * results of converting URIs to source files should also be invalidated.
8149 */
8150 void _discardCachedResolutionInformation(bool invalidateUris) {
8151 setState(ELEMENT, CacheState.INVALID);
8152 setState(IS_CLIENT, CacheState.INVALID);
8153 setState(IS_LAUNCHABLE, CacheState.INVALID);
8154 setState(PUBLIC_NAMESPACE, CacheState.INVALID);
8155 _resolutionState.invalidateAllResolutionInformation();
8156 if (invalidateUris) {
8157 setState(EXPORTED_LIBRARIES, CacheState.INVALID);
8158 setState(IMPORTED_LIBRARIES, CacheState.INVALID);
8159 setState(INCLUDED_PARTS, CacheState.INVALID);
8160 }
8161 }
8162
8163 /**
8164 * Return a resolution state for the specified [library], creating one as
8165 * necessary.
8166 */
8167 ResolutionState _getOrCreateResolutionState(Source library) {
8168 ResolutionState state = _resolutionState;
8169 if (state._librarySource == null) {
8170 state._librarySource = library;
8171 return state;
8172 }
8173 while (state._librarySource != library) {
8174 if (state._nextState == null) {
8175 ResolutionState newState = new ResolutionState();
8176 newState._librarySource = library;
8177 state._nextState = newState;
8178 return newState;
8179 }
8180 state = state._nextState;
8181 }
8182 return state;
8183 }
8184
8185 @override
8186 bool _isValidDescriptor(DataDescriptor descriptor) {
8187 return descriptor == CONTAINING_LIBRARIES ||
8188 descriptor == ELEMENT ||
8189 descriptor == EXPORTED_LIBRARIES ||
8190 descriptor == IMPORTED_LIBRARIES ||
8191 descriptor == INCLUDED_PARTS ||
8192 descriptor == IS_CLIENT ||
8193 descriptor == IS_LAUNCHABLE ||
8194 descriptor == PARSED_UNIT ||
8195 descriptor == PARSE_ERRORS ||
8196 descriptor == PUBLIC_NAMESPACE ||
8197 descriptor == SCAN_ERRORS ||
8198 descriptor == SOURCE_KIND ||
8199 descriptor == TOKEN_STREAM ||
8200 super._isValidDescriptor(descriptor);
8201 }
8202
8203 /**
8204 * Return `true` if the [descriptor] is valid for this entry when the data is
8205 * relative to a library.
8206 */
8207 bool _isValidLibraryDescriptor(DataDescriptor descriptor) {
8208 return descriptor == BUILT_ELEMENT ||
8209 descriptor == BUILT_UNIT ||
8210 descriptor == HINTS ||
8211 descriptor == LINTS ||
8212 descriptor == RESOLUTION_ERRORS ||
8213 descriptor == RESOLVED_UNIT ||
8214 descriptor == VERIFICATION_ERRORS;
8215 }
8216
8217 @override
8218 bool _writeDiffOn(StringBuffer buffer, SourceEntry oldEntry) {
8219 bool needsSeparator = super._writeDiffOn(buffer, oldEntry);
8220 if (oldEntry is! DartEntry) {
8221 if (needsSeparator) {
8222 buffer.write("; ");
8223 }
8224 buffer.write("entry type changed; was ");
8225 buffer.write(oldEntry.runtimeType.toString());
8226 return true;
8227 }
8228 needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "tokenStream",
8229 DartEntry.TOKEN_STREAM, oldEntry);
8230 needsSeparator = _writeStateDiffOn(
8231 buffer, needsSeparator, "scanErrors", DartEntry.SCAN_ERRORS, oldEntry);
8232 needsSeparator = _writeStateDiffOn(
8233 buffer, needsSeparator, "sourceKind", DartEntry.SOURCE_KIND, oldEntry);
8234 needsSeparator = _writeStateDiffOn(
8235 buffer, needsSeparator, "parsedUnit", DartEntry.PARSED_UNIT, oldEntry);
8236 needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "parseErrors",
8237 DartEntry.PARSE_ERRORS, oldEntry);
8238 needsSeparator = _writeStateDiffOn(buffer, needsSeparator,
8239 "importedLibraries", DartEntry.IMPORTED_LIBRARIES, oldEntry);
8240 needsSeparator = _writeStateDiffOn(buffer, needsSeparator,
8241 "exportedLibraries", DartEntry.EXPORTED_LIBRARIES, oldEntry);
8242 needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "includedParts",
8243 DartEntry.INCLUDED_PARTS, oldEntry);
8244 needsSeparator = _writeStateDiffOn(
8245 buffer, needsSeparator, "element", DartEntry.ELEMENT, oldEntry);
8246 needsSeparator = _writeStateDiffOn(buffer, needsSeparator,
8247 "publicNamespace", DartEntry.PUBLIC_NAMESPACE, oldEntry);
8248 needsSeparator = _writeStateDiffOn(
8249 buffer, needsSeparator, "clientServer", DartEntry.IS_CLIENT, oldEntry);
8250 needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "launchable",
8251 DartEntry.IS_LAUNCHABLE, oldEntry);
8252 // TODO(brianwilkerson) Add better support for containingLibraries.
8253 // It would be nice to be able to report on size-preserving changes.
8254 int oldLibraryCount = (oldEntry as DartEntry)._containingLibraries.length;
8255 int libraryCount = _containingLibraries.length;
8256 if (oldLibraryCount != libraryCount) {
8257 if (needsSeparator) {
8258 buffer.write("; ");
8259 }
8260 buffer.write("containingLibraryCount = ");
8261 buffer.write(oldLibraryCount);
8262 buffer.write(" -> ");
8263 buffer.write(libraryCount);
8264 needsSeparator = true;
8265 }
8266 //
8267 // Report change to the per-library state.
8268 //
8269 HashMap<Source, ResolutionState> oldStateMap =
8270 new HashMap<Source, ResolutionState>();
8271 ResolutionState state = (oldEntry as DartEntry)._resolutionState;
8272 while (state != null) {
8273 Source librarySource = state._librarySource;
8274 if (librarySource != null) {
8275 oldStateMap[librarySource] = state;
8276 }
8277 state = state._nextState;
8278 }
8279 state = _resolutionState;
8280 while (state != null) {
8281 Source librarySource = state._librarySource;
8282 if (librarySource != null) {
8283 ResolutionState oldState = oldStateMap.remove(librarySource);
8284 if (oldState == null) {
8285 if (needsSeparator) {
8286 buffer.write("; ");
8287 }
8288 buffer.write("added resolution for ");
8289 buffer.write(librarySource.fullName);
8290 needsSeparator = true;
8291 } else {
8292 needsSeparator = oldState._writeDiffOn(
8293 buffer, needsSeparator, oldEntry as DartEntry);
8294 }
8295 }
8296 state = state._nextState;
8297 }
8298 for (Source librarySource in oldStateMap.keys.toSet()) {
8299 if (needsSeparator) {
8300 buffer.write("; ");
8301 }
8302 buffer.write("removed resolution for ");
8303 buffer.write(librarySource.fullName);
8304 needsSeparator = true;
8305 }
8306 return needsSeparator;
8307 }
8308
8309 @override
8310 void _writeOn(StringBuffer buffer) {
8311 buffer.write("Dart: ");
8312 super._writeOn(buffer);
8313 _writeStateOn(buffer, "tokenStream", TOKEN_STREAM);
8314 _writeStateOn(buffer, "scanErrors", SCAN_ERRORS);
8315 _writeStateOn(buffer, "sourceKind", SOURCE_KIND);
8316 _writeStateOn(buffer, "parsedUnit", PARSED_UNIT);
8317 _writeStateOn(buffer, "parseErrors", PARSE_ERRORS);
8318 _writeStateOn(buffer, "exportedLibraries", EXPORTED_LIBRARIES);
8319 _writeStateOn(buffer, "importedLibraries", IMPORTED_LIBRARIES);
8320 _writeStateOn(buffer, "includedParts", INCLUDED_PARTS);
8321 _writeStateOn(buffer, "element", ELEMENT);
8322 _writeStateOn(buffer, "publicNamespace", PUBLIC_NAMESPACE);
8323 _writeStateOn(buffer, "clientServer", IS_CLIENT);
8324 _writeStateOn(buffer, "launchable", IS_LAUNCHABLE);
8325 _resolutionState._writeOn(buffer);
8326 }
8327 }
8328
8329 /**
8330 * An immutable constant representing data that can be stored in the cache.
8331 */
8332 class DataDescriptor<E> {
8333 /**
8334 * The next artificial hash code.
8335 */
8336 static int _NEXT_HASH_CODE = 0;
8337
8338 /**
8339 * The artifitial hash code for this object.
8340 */
8341 final int _hashCode = _NEXT_HASH_CODE++;
8342
8343 /**
8344 * The name of the descriptor, used for debugging purposes.
8345 */
8346 final String _name;
8347
8348 /**
8349 * The default value used when the data does not exist.
8350 */
8351 final E defaultValue;
8352
8353 /**
8354 * Initialize a newly created descriptor to have the given [name] and
8355 * [defaultValue].
8356 */
8357 DataDescriptor(this._name, [this.defaultValue = null]);
8358
8359 @override
8360 int get hashCode => _hashCode;
8361
8362 @override
8363 String toString() => _name;
8364 }
8365
8366 /**
8367 * A retention policy that will keep AST's in the cache if there is analysis
8368 * information that needs to be computed for a source, where the computation is
8369 * dependent on having the AST.
8370 */
8371 class DefaultRetentionPolicy implements CacheRetentionPolicy {
8372 /**
8373 * An instance of this class that can be shared.
8374 */
8375 static DefaultRetentionPolicy POLICY = new DefaultRetentionPolicy();
8376
8377 /**
8378 * Return `true` if there is analysis information in the given [dartEntry]
8379 * that needs to be computed, where the computation is dependent on having the
8380 * AST.
8381 */
8382 bool astIsNeeded(DartEntry dartEntry) =>
8383 dartEntry.hasInvalidData(DartEntry.HINTS) ||
8384 dartEntry.hasInvalidData(DartEntry.LINTS) ||
8385 dartEntry.hasInvalidData(DartEntry.VERIFICATION_ERRORS) ||
8386 dartEntry.hasInvalidData(DartEntry.RESOLUTION_ERRORS);
8387
8388 @override
8389 RetentionPriority getAstPriority(Source source, SourceEntry sourceEntry) {
8390 if (sourceEntry is DartEntry) {
8391 DartEntry dartEntry = sourceEntry;
8392 if (astIsNeeded(dartEntry)) {
8393 return RetentionPriority.MEDIUM;
8394 }
8395 }
8396 return RetentionPriority.LOW;
8397 }
8398 }
8399
8400 /**
8401 * Instances of the class `GenerateDartErrorsTask` generate errors and warnings for a single
8402 * Dart source.
8403 */
8404 class GenerateDartErrorsTask extends AnalysisTask {
8405 /**
8406 * The source for which errors and warnings are to be produced.
8407 */
8408 final Source source;
8409
8410 /**
8411 * The compilation unit used to resolve the dependencies.
8412 */
8413 final CompilationUnit _unit;
8414
8415 /**
8416 * The element model for the library containing the source.
8417 */
8418 final LibraryElement libraryElement;
8419
8420 /**
8421 * The errors that were generated for the source.
8422 */
8423 List<AnalysisError> _errors;
8424
8425 /**
8426 * Initialize a newly created task to perform analysis within the given contex t.
8427 *
8428 * @param context the context in which the task is to be performed
8429 * @param source the source for which errors and warnings are to be produced
8430 * @param unit the compilation unit used to resolve the dependencies
8431 * @param libraryElement the element model for the library containing the sour ce
8432 */
8433 GenerateDartErrorsTask(InternalAnalysisContext context, this.source,
8434 this._unit, this.libraryElement)
8435 : super(context);
8436
8437 /**
8438 * Return the errors that were generated for the source.
8439 *
8440 * @return the errors that were generated for the source
8441 */
8442 List<AnalysisError> get errors => _errors;
8443
8444 @override
8445 String get taskDescription =>
8446 "generate errors and warnings for ${source.fullName}";
8447
8448 @override
8449 accept(AnalysisTaskVisitor visitor) =>
8450 visitor.visitGenerateDartErrorsTask(this);
8451
8452 @override
8453 void internalPerform() {
8454 PerformanceStatistics.errors.makeCurrentWhile(() {
8455 RecordingErrorListener errorListener = new RecordingErrorListener();
8456 ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
8457 TypeProvider typeProvider = context.typeProvider;
8458 //
8459 // Validate the directives
8460 //
8461 validateDirectives(context, source, _unit, errorListener);
8462 //
8463 // Use the ConstantVerifier to verify the use of constants.
8464 // This needs to happen before using the ErrorVerifier because some error
8465 // codes need the computed constant values.
8466 //
8467 // TODO(paulberry): as a temporary workaround for issue 21572,
8468 // ConstantVerifier is being run right after ConstantValueComputer, so we
8469 // don't need to run it here. Once issue 21572 is fixed, re-enable the
8470 // call to ConstantVerifier.
8471 // ConstantVerifier constantVerifier = new ConstantVerifier(errorReporter, libraryElement, typeProvider);
8472 // _unit.accept(constantVerifier);
8473 //
8474 // Use the ErrorVerifier to compute the rest of the errors.
8475 //
8476 ErrorVerifier errorVerifier = new ErrorVerifier(
8477 errorReporter,
8478 libraryElement,
8479 typeProvider,
8480 new InheritanceManager(libraryElement),
8481 context.analysisOptions.enableSuperMixins);
8482 _unit.accept(errorVerifier);
8483 _errors = errorListener.getErrorsForSource(source);
8484 });
8485 }
8486
8487 /**
8488 * Check each directive in the given compilation unit to see if the referenced source exists and
8489 * report an error if it does not.
8490 *
8491 * @param context the context in which the library exists
8492 * @param librarySource the source representing the library containing the dir ectives
8493 * @param unit the compilation unit containing the directives to be validated
8494 * @param errorListener the error listener to which errors should be reported
8495 */
8496 static void validateDirectives(AnalysisContext context, Source librarySource,
8497 CompilationUnit unit, AnalysisErrorListener errorListener) {
8498 for (Directive directive in unit.directives) {
8499 if (directive is UriBasedDirective) {
8500 validateReferencedSource(
8501 context, librarySource, directive, errorListener);
8502 }
8503 }
8504 }
8505
8506 /**
8507 * Check the given directive to see if the referenced source exists and report an error if it does
8508 * not.
8509 *
8510 * @param context the context in which the library exists
8511 * @param librarySource the source representing the library containing the dir ective
8512 * @param directive the directive to be verified
8513 * @param errorListener the error listener to which errors should be reported
8514 */
8515 static void validateReferencedSource(
8516 AnalysisContext context,
8517 Source librarySource,
8518 UriBasedDirective directive,
8519 AnalysisErrorListener errorListener) {
8520 Source source = directive.source;
8521 if (source != null) {
8522 if (context.exists(source)) {
8523 return;
8524 }
8525 } else {
8526 // Don't report errors already reported by ParseDartTask.resolveDirective
8527 if (directive.validate() != null) {
8528 return;
8529 }
8530 }
8531 StringLiteral uriLiteral = directive.uri;
8532 errorListener.onError(new AnalysisError(
8533 librarySource,
8534 uriLiteral.offset,
8535 uriLiteral.length,
8536 CompileTimeErrorCode.URI_DOES_NOT_EXIST,
8537 [directive.uriContent]));
8538 }
8539 }
8540
8541 /**
8542 * Instances of the class `GenerateDartHintsTask` generate hints for a single Da rt library.
8543 */
8544 class GenerateDartHintsTask extends AnalysisTask {
8545 /**
8546 * The compilation units that comprise the library, with the defining compilat ion unit appearing
8547 * first in the list.
8548 */
8549 final List<TimestampedData<CompilationUnit>> _units;
8550
8551 /**
8552 * The element model for the library being analyzed.
8553 */
8554 final LibraryElement libraryElement;
8555
8556 /**
8557 * A table mapping the sources that were analyzed to the hints that were
8558 * generated for the sources.
8559 */
8560 HashMap<Source, List<AnalysisError>> _hintMap;
8561
8562 /**
8563 * Initialize a newly created task to perform analysis within the given contex t.
8564 *
8565 * @param context the context in which the task is to be performed
8566 * @param units the compilation units that comprise the library, with the defi ning compilation
8567 * unit appearing first in the list
8568 * @param libraryElement the element model for the library being analyzed
8569 */
8570 GenerateDartHintsTask(
8571 InternalAnalysisContext context, this._units, this.libraryElement)
8572 : super(context);
8573
8574 /**
8575 * Return a table mapping the sources that were analyzed to the hints that wer e generated for the
8576 * sources, or `null` if the task has not been performed or if the analysis di d not complete
8577 * normally.
8578 *
8579 * @return a table mapping the sources that were analyzed to the hints that we re generated for the
8580 * sources
8581 */
8582 HashMap<Source, List<AnalysisError>> get hintMap => _hintMap;
8583
8584 @override
8585 String get taskDescription {
8586 Source librarySource = libraryElement.source;
8587 if (librarySource == null) {
8588 return "generate Dart hints for library without source";
8589 }
8590 return "generate Dart hints for ${librarySource.fullName}";
8591 }
8592
8593 @override
8594 accept(AnalysisTaskVisitor visitor) =>
8595 visitor.visitGenerateDartHintsTask(this);
8596
8597 @override
8598 void internalPerform() {
8599 //
8600 // Gather the compilation units.
8601 //
8602 int unitCount = _units.length;
8603 List<CompilationUnit> compilationUnits =
8604 new List<CompilationUnit>(unitCount);
8605 for (int i = 0; i < unitCount; i++) {
8606 compilationUnits[i] = _units[i].data;
8607 }
8608 //
8609 // Analyze all of the units.
8610 //
8611 RecordingErrorListener errorListener = new RecordingErrorListener();
8612 HintGenerator hintGenerator =
8613 new HintGenerator(compilationUnits, context, errorListener);
8614 hintGenerator.generateForLibrary();
8615 //
8616 // Store the results.
8617 //
8618 _hintMap = new HashMap<Source, List<AnalysisError>>();
8619 for (int i = 0; i < unitCount; i++) {
8620 Source source = _units[i].data.element.source;
8621 _hintMap[source] = errorListener.getErrorsForSource(source);
8622 }
8623 }
8624 }
8625
8626 /// Generates lint feedback for a single Dart library.
8627 class GenerateDartLintsTask extends AnalysisTask {
8628 ///The compilation units that comprise the library, with the defining
8629 ///compilation unit appearing first in the list.
8630 final List<TimestampedData<CompilationUnit>> _units;
8631
8632 /// The element model for the library being analyzed.
8633 final LibraryElement libraryElement;
8634
8635 /// A mapping of analyzed sources to their associated lint warnings.
8636 /// May be [null] if the task has not been performed or if analysis did not
8637 /// complete normally.
8638 HashMap<Source, List<AnalysisError>> lintMap;
8639
8640 /// Initialize a newly created task to perform lint checking over these
8641 /// [_units] belonging to this [libraryElement] within the given [context].
8642 GenerateDartLintsTask(context, this._units, this.libraryElement)
8643 : super(context);
8644
8645 @override
8646 String get taskDescription {
8647 Source librarySource = libraryElement.source;
8648 return (librarySource == null)
8649 ? "generate Dart lints for library without source"
8650 : "generate Dart lints for ${librarySource.fullName}";
8651 }
8652
8653 @override
8654 accept(AnalysisTaskVisitor visitor) =>
8655 visitor.visitGenerateDartLintsTask(this);
8656
8657 @override
8658 void internalPerform() {
8659 Iterable<CompilationUnit> compilationUnits =
8660 _units.map((TimestampedData<CompilationUnit> unit) => unit.data);
8661 RecordingErrorListener errorListener = new RecordingErrorListener();
8662 LintGenerator lintGenerator =
8663 new LintGenerator(compilationUnits, errorListener);
8664 lintGenerator.generate();
8665
8666 lintMap = new HashMap<Source, List<AnalysisError>>();
8667 compilationUnits.forEach((CompilationUnit unit) {
8668 Source source = unit.element.source;
8669 lintMap[source] = errorListener.getErrorsForSource(source);
8670 });
8671 }
8672 }
8673
8674 /**
8675 * Instances of the class `GetContentTask` get the contents of a source.
8676 */
8677 class GetContentTask extends AnalysisTask {
8678 /**
8679 * The source to be read.
8680 */
8681 final Source source;
8682
8683 /**
8684 * A flag indicating whether this task is complete.
8685 */
8686 bool _complete = false;
8687
8688 /**
8689 * The contents of the source.
8690 */
8691 String _content;
8692
8693 /**
8694 * The errors that were produced by getting the source content.
8695 */
8696 final List<AnalysisError> errors = <AnalysisError>[];
8697
8698 /**
8699 * The time at which the contents of the source were last modified.
8700 */
8701 int _modificationTime = -1;
8702
8703 /**
8704 * Initialize a newly created task to perform analysis within the given contex t.
8705 *
8706 * @param context the context in which the task is to be performed
8707 * @param source the source to be parsed
8708 * @param contentData the time-stamped contents of the source
8709 */
8710 GetContentTask(InternalAnalysisContext context, this.source)
8711 : super(context) {
8712 if (source == null) {
8713 throw new IllegalArgumentException("Cannot get contents of null source");
8714 }
8715 }
8716
8717 /**
8718 * Return the contents of the source, or `null` if the task has not completed or if there
8719 * was an exception while getting the contents.
8720 *
8721 * @return the contents of the source
8722 */
8723 String get content => _content;
8724
8725 /**
8726 * Return `true` if this task is complete. Unlike most tasks, this task is all owed to be
8727 * visited more than once in order to support asynchronous IO. If the task is not complete when it
8728 * is visited synchronously as part of the [AnalysisTask.perform]
8729 * method, it will be visited again, using the same visitor, when the IO opera tion has been
8730 * performed.
8731 *
8732 * @return `true` if this task is complete
8733 */
8734 bool get isComplete => _complete;
8735
8736 /**
8737 * Return the time at which the contents of the source that was parsed were la st modified, or a
8738 * negative value if the task has not yet been performed or if an exception oc curred.
8739 *
8740 * @return the time at which the contents of the source that was parsed were l ast modified
8741 */
8742 int get modificationTime => _modificationTime;
8743
8744 @override
8745 String get taskDescription => "get contents of ${source.fullName}";
8746
8747 @override
8748 accept(AnalysisTaskVisitor visitor) => visitor.visitGetContentTask(this);
8749
8750 @override
8751 void internalPerform() {
8752 _complete = true;
8753 try {
8754 TimestampedData<String> data = context.getContents(source);
8755 _content = data.data;
8756 _modificationTime = data.modificationTime;
8757 AnalysisEngine.instance.instrumentationService
8758 .logFileRead(source.fullName, _modificationTime, _content);
8759 } catch (exception, stackTrace) {
8760 errors.add(new AnalysisError(
8761 source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [exception]));
8762 throw new AnalysisException("Could not get contents of $source",
8763 new CaughtException(exception, stackTrace));
8764 }
8765 }
8766 }
8767
8768 /**
8769 * The information cached by an analysis context about an individual HTML file.
8770 */
8771 class HtmlEntry extends SourceEntry {
8772 /**
8773 * The data descriptor representing the HTML element.
8774 */
8775 static final DataDescriptor<HtmlElement> ELEMENT =
8776 new DataDescriptor<HtmlElement>("HtmlEntry.ELEMENT");
8777
8778 /**
8779 * The data descriptor representing the hints resulting from auditing the
8780 * source.
8781 */
8782 static final DataDescriptor<List<AnalysisError>> HINTS =
8783 new DataDescriptor<List<AnalysisError>>(
8784 "HtmlEntry.HINTS", AnalysisError.NO_ERRORS);
8785
8786 /**
8787 * The data descriptor representing the errors resulting from parsing the
8788 * source.
8789 */
8790 static final DataDescriptor<List<AnalysisError>> PARSE_ERRORS =
8791 new DataDescriptor<List<AnalysisError>>(
8792 "HtmlEntry.PARSE_ERRORS", AnalysisError.NO_ERRORS);
8793
8794 /**
8795 * The data descriptor representing the parsed AST structure.
8796 */
8797 static final DataDescriptor<ht.HtmlUnit> PARSED_UNIT =
8798 new DataDescriptor<ht.HtmlUnit>("HtmlEntry.PARSED_UNIT");
8799
8800 /**
8801 * The data descriptor representing the resolved AST structure.
8802 */
8803 static final DataDescriptor<ht.HtmlUnit> RESOLVED_UNIT =
8804 new DataDescriptor<ht.HtmlUnit>("HtmlEntry.RESOLVED_UNIT");
8805
8806 /**
8807 * The data descriptor representing the list of referenced libraries.
8808 */
8809 static final DataDescriptor<List<Source>> REFERENCED_LIBRARIES =
8810 new DataDescriptor<List<Source>>(
8811 "HtmlEntry.REFERENCED_LIBRARIES", Source.EMPTY_LIST);
8812
8813 /**
8814 * The data descriptor representing the errors resulting from resolving the
8815 * source.
8816 */
8817 static final DataDescriptor<List<AnalysisError>> RESOLUTION_ERRORS =
8818 new DataDescriptor<List<AnalysisError>>(
8819 "HtmlEntry.RESOLUTION_ERRORS", AnalysisError.NO_ERRORS);
8820
8821 /**
8822 * Return all of the errors associated with the HTML file that are currently
8823 * cached.
8824 */
8825 List<AnalysisError> get allErrors {
8826 List<AnalysisError> errors = new List<AnalysisError>();
8827 errors.addAll(super.allErrors);
8828 errors.addAll(getValue(PARSE_ERRORS));
8829 errors.addAll(getValue(RESOLUTION_ERRORS));
8830 errors.addAll(getValue(HINTS));
8831 if (errors.length == 0) {
8832 return AnalysisError.NO_ERRORS;
8833 }
8834 return errors;
8835 }
8836
8837 /**
8838 * Return a valid parsed unit, either an unresolved AST structure or the
8839 * result of resolving the AST structure, or `null` if there is no parsed unit
8840 * available.
8841 */
8842 ht.HtmlUnit get anyParsedUnit {
8843 if (getState(PARSED_UNIT) == CacheState.VALID) {
8844 return getValue(PARSED_UNIT);
8845 }
8846 if (getState(RESOLVED_UNIT) == CacheState.VALID) {
8847 return getValue(RESOLVED_UNIT);
8848 }
8849 return null;
8850 }
8851
8852 @override
8853 List<DataDescriptor> get descriptors {
8854 List<DataDescriptor> result = super.descriptors;
8855 result.addAll([
8856 HtmlEntry.ELEMENT,
8857 HtmlEntry.PARSE_ERRORS,
8858 HtmlEntry.PARSED_UNIT,
8859 HtmlEntry.RESOLUTION_ERRORS,
8860 HtmlEntry.RESOLVED_UNIT,
8861 HtmlEntry.HINTS
8862 ]);
8863 return result;
8864 }
8865
8866 @override
8867 SourceKind get kind => SourceKind.HTML;
8868
8869 /**
8870 * Flush any AST structures being maintained by this entry.
8871 */
8872 void flushAstStructures() {
8873 _flush(PARSED_UNIT);
8874 _flush(RESOLVED_UNIT);
8875 }
8876
8877 @override
8878 void invalidateAllInformation() {
8879 super.invalidateAllInformation();
8880 setState(PARSE_ERRORS, CacheState.INVALID);
8881 setState(PARSED_UNIT, CacheState.INVALID);
8882 setState(RESOLVED_UNIT, CacheState.INVALID);
8883 invalidateAllResolutionInformation(true);
8884 }
8885
8886 /**
8887 * Invalidate all of the resolution information associated with the HTML file.
8888 * If [invalidateUris] is `true`, the cached results of converting URIs to
8889 * source files should also be invalidated.
8890 */
8891 void invalidateAllResolutionInformation(bool invalidateUris) {
8892 setState(RESOLVED_UNIT, CacheState.INVALID);
8893 setState(ELEMENT, CacheState.INVALID);
8894 setState(RESOLUTION_ERRORS, CacheState.INVALID);
8895 setState(HINTS, CacheState.INVALID);
8896 if (invalidateUris) {
8897 setState(REFERENCED_LIBRARIES, CacheState.INVALID);
8898 }
8899 }
8900
8901 /**
8902 * Invalidate all of the parse and resolution information associated with
8903 * this source.
8904 */
8905 void invalidateParseInformation() {
8906 setState(PARSE_ERRORS, CacheState.INVALID);
8907 setState(PARSED_UNIT, CacheState.INVALID);
8908 invalidateAllResolutionInformation(true);
8909 }
8910
8911 @override
8912 void recordContentError(CaughtException exception) {
8913 super.recordContentError(exception);
8914 recordParseError(exception);
8915 }
8916
8917 /**
8918 * Record that an [exception] was encountered while attempting to parse the
8919 * source associated with this entry.
8920 */
8921 void recordParseError(CaughtException exception) {
8922 // If the scanning and parsing of HTML are separated,
8923 // the following line can be removed.
8924 recordScanError(exception);
8925 setState(PARSE_ERRORS, CacheState.ERROR);
8926 setState(PARSED_UNIT, CacheState.ERROR);
8927 setState(REFERENCED_LIBRARIES, CacheState.ERROR);
8928 recordResolutionError(exception);
8929 }
8930
8931 /**
8932 * Record that an [exception] was encountered while attempting to resolve the
8933 * source associated with this entry.
8934 */
8935 void recordResolutionError(CaughtException exception) {
8936 this.exception = exception;
8937 setState(RESOLVED_UNIT, CacheState.ERROR);
8938 setState(ELEMENT, CacheState.ERROR);
8939 setState(RESOLUTION_ERRORS, CacheState.ERROR);
8940 setState(HINTS, CacheState.ERROR);
8941 }
8942
8943 @override
8944 bool _isValidDescriptor(DataDescriptor descriptor) {
8945 return descriptor == ELEMENT ||
8946 descriptor == HINTS ||
8947 descriptor == PARSED_UNIT ||
8948 descriptor == PARSE_ERRORS ||
8949 descriptor == REFERENCED_LIBRARIES ||
8950 descriptor == RESOLUTION_ERRORS ||
8951 descriptor == RESOLVED_UNIT ||
8952 super._isValidDescriptor(descriptor);
8953 }
8954
8955 @override
8956 bool _writeDiffOn(StringBuffer buffer, SourceEntry oldEntry) {
8957 bool needsSeparator = super._writeDiffOn(buffer, oldEntry);
8958 if (oldEntry is! HtmlEntry) {
8959 if (needsSeparator) {
8960 buffer.write("; ");
8961 }
8962 buffer.write("entry type changed; was ");
8963 buffer.write(oldEntry.runtimeType);
8964 return true;
8965 }
8966 needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "parseErrors",
8967 HtmlEntry.PARSE_ERRORS, oldEntry);
8968 needsSeparator = _writeStateDiffOn(
8969 buffer, needsSeparator, "parsedUnit", HtmlEntry.PARSED_UNIT, oldEntry);
8970 needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "resolvedUnit",
8971 HtmlEntry.RESOLVED_UNIT, oldEntry);
8972 needsSeparator = _writeStateDiffOn(buffer, needsSeparator,
8973 "resolutionErrors", HtmlEntry.RESOLUTION_ERRORS, oldEntry);
8974 needsSeparator = _writeStateDiffOn(buffer, needsSeparator,
8975 "referencedLibraries", HtmlEntry.REFERENCED_LIBRARIES, oldEntry);
8976 needsSeparator = _writeStateDiffOn(
8977 buffer, needsSeparator, "element", HtmlEntry.ELEMENT, oldEntry);
8978 return needsSeparator;
8979 }
8980
8981 @override
8982 void _writeOn(StringBuffer buffer) {
8983 buffer.write("Html: ");
8984 super._writeOn(buffer);
8985 _writeStateOn(buffer, "parseErrors", PARSE_ERRORS);
8986 _writeStateOn(buffer, "parsedUnit", PARSED_UNIT);
8987 _writeStateOn(buffer, "resolvedUnit", RESOLVED_UNIT);
8988 _writeStateOn(buffer, "resolutionErrors", RESOLUTION_ERRORS);
8989 _writeStateOn(buffer, "referencedLibraries", REFERENCED_LIBRARIES);
8990 _writeStateOn(buffer, "element", ELEMENT);
8991 }
8992 }
8993
8994 /**
8995 * An event indicating when a source either starts or stops being implicitly
8996 * analyzed.
8997 */
8998 class ImplicitAnalysisEvent {
8999 /**
9000 * The source whose status has changed.
9001 */
9002 final Source source;
9003
9004 /**
9005 * A flag indicating whether the source is now being analyzed.
9006 */
9007 final bool isAnalyzed;
9008
9009 /**
9010 * Initialize a newly created event to indicate that the given [source] has
9011 * changed it status to match the [isAnalyzed] flag.
9012 */
9013 ImplicitAnalysisEvent(this.source, this.isAnalyzed);
9014
9015 @override
9016 String toString() =>
9017 '${isAnalyzed ? '' : 'not '}analyzing ${source.fullName}';
9018 }
9019
9020 /**
9021 * Instances of the class `IncrementalAnalysisCache` hold information used to pe rform
9022 * incremental analysis.
9023 *
9024 * See [AnalysisContextImpl.setChangedContents].
9025 */
9026 class IncrementalAnalysisCache {
9027 final Source librarySource;
9028
9029 final Source source;
9030
9031 final String oldContents;
9032
9033 final CompilationUnit resolvedUnit;
9034
9035 String _newContents;
9036
9037 int _offset = 0;
9038
9039 int _oldLength = 0;
9040
9041 int _newLength = 0;
9042
9043 IncrementalAnalysisCache(
9044 this.librarySource,
9045 this.source,
9046 this.resolvedUnit,
9047 this.oldContents,
9048 this._newContents,
9049 this._offset,
9050 this._oldLength,
9051 this._newLength);
9052
9053 /**
9054 * Determine if the cache contains source changes that need to be analyzed
9055 *
9056 * @return `true` if the cache contains changes to be analyzed, else `false`
9057 */
9058 bool get hasWork => _oldLength > 0 || _newLength > 0;
9059
9060 /**
9061 * Return the current contents for the receiver's source.
9062 *
9063 * @return the contents (not `null`)
9064 */
9065 String get newContents => _newContents;
9066
9067 /**
9068 * Return the number of characters in the replacement text.
9069 *
9070 * @return the replacement length (zero or greater)
9071 */
9072 int get newLength => _newLength;
9073
9074 /**
9075 * Return the character position of the first changed character.
9076 *
9077 * @return the offset (zero or greater)
9078 */
9079 int get offset => _offset;
9080
9081 /**
9082 * Return the number of characters that were replaced.
9083 *
9084 * @return the replaced length (zero or greater)
9085 */
9086 int get oldLength => _oldLength;
9087
9088 /**
9089 * Determine if the incremental analysis result can be cached for the next inc remental analysis.
9090 *
9091 * @param cache the prior incremental analysis cache
9092 * @param unit the incrementally updated compilation unit
9093 * @return the cache used for incremental analysis or `null` if incremental an alysis results
9094 * cannot be cached for the next incremental analysis
9095 */
9096 static IncrementalAnalysisCache cacheResult(
9097 IncrementalAnalysisCache cache, CompilationUnit unit) {
9098 if (cache != null && unit != null) {
9099 return new IncrementalAnalysisCache(cache.librarySource, cache.source,
9100 unit, cache._newContents, cache._newContents, 0, 0, 0);
9101 }
9102 return null;
9103 }
9104
9105 /**
9106 * Determine if the cache should be cleared.
9107 *
9108 * @param cache the prior cache or `null` if none
9109 * @param source the source being updated (not `null`)
9110 * @return the cache used for incremental analysis or `null` if incremental an alysis cannot
9111 * be performed
9112 */
9113 static IncrementalAnalysisCache clear(
9114 IncrementalAnalysisCache cache, Source source) {
9115 if (cache == null || cache.source == source) {
9116 return null;
9117 }
9118 return cache;
9119 }
9120
9121 /**
9122 * Determine if incremental analysis can be performed from the given informati on.
9123 *
9124 * @param cache the prior cache or `null` if none
9125 * @param source the source being updated (not `null`)
9126 * @param oldContents the original source contents prior to this update (may b e `null`)
9127 * @param newContents the new contents after this incremental change (not `nul l`)
9128 * @param offset the offset at which the change occurred
9129 * @param oldLength the length of the text being replaced
9130 * @param newLength the length of the replacement text
9131 * @param sourceEntry the cached entry for the given source or `null` if none
9132 * @return the cache used for incremental analysis or `null` if incremental an alysis cannot
9133 * be performed
9134 */
9135 static IncrementalAnalysisCache update(
9136 IncrementalAnalysisCache cache,
9137 Source source,
9138 String oldContents,
9139 String newContents,
9140 int offset,
9141 int oldLength,
9142 int newLength,
9143 SourceEntry sourceEntry) {
9144 // Determine the cache resolved unit
9145 Source librarySource = null;
9146 CompilationUnit unit = null;
9147 if (sourceEntry is DartEntry) {
9148 DartEntry dartEntry = sourceEntry;
9149 List<Source> librarySources = dartEntry.librariesContaining;
9150 if (librarySources.length == 1) {
9151 librarySource = librarySources[0];
9152 if (librarySource != null) {
9153 unit = dartEntry.getValueInLibrary(
9154 DartEntry.RESOLVED_UNIT, librarySource);
9155 }
9156 }
9157 }
9158 // Create a new cache if there is not an existing cache or the source is
9159 // different or a new resolved compilation unit is available.
9160 if (cache == null || cache.source != source || unit != null) {
9161 if (unit == null) {
9162 return null;
9163 }
9164 if (oldContents == null) {
9165 if (oldLength != 0) {
9166 return null;
9167 }
9168 oldContents =
9169 "${newContents.substring(0, offset)}${newContents.substring(offset + newLength)}";
9170 }
9171 return new IncrementalAnalysisCache(librarySource, source, unit,
9172 oldContents, newContents, offset, oldLength, newLength);
9173 }
9174 // Update the existing cache if the change is contiguous
9175 if (cache._oldLength == 0 && cache._newLength == 0) {
9176 cache._offset = offset;
9177 cache._oldLength = oldLength;
9178 cache._newLength = newLength;
9179 } else {
9180 if (cache._offset > offset || offset > cache._offset + cache._newLength) {
9181 return null;
9182 }
9183 cache._newLength += newLength - oldLength;
9184 }
9185 cache._newContents = newContents;
9186 return cache;
9187 }
9188
9189 /**
9190 * Verify that the incrementally parsed and resolved unit in the incremental c ache is structurally
9191 * equivalent to the fully parsed unit.
9192 *
9193 * @param cache the prior cache or `null` if none
9194 * @param source the source of the compilation unit that was parsed (not `null `)
9195 * @param unit the compilation unit that was just parsed
9196 * @return the cache used for incremental analysis or `null` if incremental an alysis results
9197 * cannot be cached for the next incremental analysis
9198 */
9199 static IncrementalAnalysisCache verifyStructure(
9200 IncrementalAnalysisCache cache, Source source, CompilationUnit unit) {
9201 if (cache != null && unit != null && cache.source == source) {
9202 if (!AstComparator.equalNodes(cache.resolvedUnit, unit)) {
9203 return null;
9204 }
9205 }
9206 return cache;
9207 }
9208 }
9209
9210 /**
9211 * Instances of the class `IncrementalAnalysisTask` incrementally update existin g analysis.
9212 */
9213 class IncrementalAnalysisTask extends AnalysisTask {
9214 /**
9215 * The information used to perform incremental analysis.
9216 */
9217 final IncrementalAnalysisCache cache;
9218
9219 /**
9220 * The compilation unit that was produced by incrementally updating the existi ng unit.
9221 */
9222 CompilationUnit _updatedUnit;
9223
9224 /**
9225 * Initialize a newly created task to perform analysis within the given contex t.
9226 *
9227 * @param context the context in which the task is to be performed
9228 * @param cache the incremental analysis cache used to perform the analysis
9229 */
9230 IncrementalAnalysisTask(InternalAnalysisContext context, this.cache)
9231 : super(context);
9232
9233 /**
9234 * Return the compilation unit that was produced by incrementally updating the existing
9235 * compilation unit, or `null` if the task has not yet been performed, could n ot be
9236 * performed, or if an exception occurred.
9237 *
9238 * @return the compilation unit
9239 */
9240 CompilationUnit get compilationUnit => _updatedUnit;
9241
9242 /**
9243 * Return the source that is to be incrementally analyzed.
9244 *
9245 * @return the source
9246 */
9247 Source get source => cache != null ? cache.source : null;
9248
9249 @override
9250 String get taskDescription =>
9251 "incremental analysis ${cache != null ? cache.source : "null"}";
9252
9253 /**
9254 * Return the type provider used for incremental resolution.
9255 *
9256 * @return the type provider (or `null` if an exception occurs)
9257 */
9258 TypeProvider get typeProvider {
9259 try {
9260 return context.typeProvider;
9261 } on AnalysisException {
9262 return null;
9263 }
9264 }
9265
9266 @override
9267 accept(AnalysisTaskVisitor visitor) =>
9268 visitor.visitIncrementalAnalysisTask(this);
9269
9270 @override
9271 void internalPerform() {
9272 if (cache == null) {
9273 return;
9274 }
9275 // Only handle small changes
9276 if (cache.oldLength > 0 || cache.newLength > 30) {
9277 return;
9278 }
9279 // Produce an updated token stream
9280 CharacterReader reader = new CharSequenceReader(cache.newContents);
9281 BooleanErrorListener errorListener = new BooleanErrorListener();
9282 IncrementalScanner scanner = new IncrementalScanner(
9283 cache.source, reader, errorListener, context.analysisOptions);
9284 scanner.rescan(cache.resolvedUnit.beginToken, cache.offset, cache.oldLength,
9285 cache.newLength);
9286 if (errorListener.errorReported) {
9287 return;
9288 }
9289 // Produce an updated AST
9290 IncrementalParser parser = new IncrementalParser(
9291 cache.source, scanner.tokenMap, AnalysisErrorListener.NULL_LISTENER);
9292 _updatedUnit = parser.reparse(cache.resolvedUnit, scanner.leftToken,
9293 scanner.rightToken, cache.offset, cache.offset + cache.oldLength);
9294 // Update the resolution
9295 TypeProvider typeProvider = this.typeProvider;
9296 if (_updatedUnit != null && typeProvider != null) {
9297 CompilationUnitElement element = _updatedUnit.element;
9298 if (element != null) {
9299 LibraryElement library = element.library;
9300 if (library != null) {
9301 IncrementalResolver resolver = new IncrementalResolver(null, null,
9302 null, element, cache.offset, cache.oldLength, cache.newLength);
9303 resolver.resolve(parser.updatedNode);
9304 }
9305 }
9306 }
9307 }
9308 }
9309
9310 /**
9311 * Additional behavior for an analysis context that is required by internal
9312 * users of the context.
9313 */
9314 abstract class InternalAnalysisContext implements AnalysisContext {
9315 /**
9316 * A table mapping the sources known to the context to the information known
9317 * about the source.
9318 *
9319 * TODO(scheglov) add the type, once we have only one cache.
9320 */
9321 dynamic get analysisCache;
9322
9323 /**
9324 * Allow the client to supply its own content cache. This will take the
9325 * place of the content cache created by default, allowing clients to share
9326 * the content cache between contexts.
9327 */
9328 set contentCache(ContentCache value);
9329
9330 /**
9331 * Return a list of the explicit targets being analyzed by this context.
9332 */
9333 List<AnalysisTarget> get explicitTargets;
9334
9335 /**
9336 * A factory to override how [LibraryResolver] is created.
9337 */
9338 LibraryResolverFactory get libraryResolverFactory;
9339
9340 /**
9341 * Return a list containing all of the sources that have been marked as
9342 * priority sources. Clients must not modify the returned list.
9343 */
9344 List<Source> get prioritySources;
9345
9346 /**
9347 * Return a list of the priority targets being analyzed by this context.
9348 */
9349 List<AnalysisTarget> get priorityTargets;
9350
9351 /**
9352 * The partition that contains analysis results that are not shared with other
9353 * contexts.
9354 *
9355 * TODO(scheglov) add the type, once we have only one cache.
9356 */
9357 dynamic get privateAnalysisCachePartition;
9358
9359 /**
9360 * A factory to override how [ResolverVisitor] is created.
9361 */
9362 ResolverVisitorFactory get resolverVisitorFactory;
9363
9364 /**
9365 * Returns a statistics about this context.
9366 */
9367 AnalysisContextStatistics get statistics;
9368
9369 /**
9370 * Sets the [TypeProvider] for this context.
9371 */
9372 void set typeProvider(TypeProvider typeProvider);
9373
9374 /**
9375 * A factory to override how [TypeResolverVisitor] is created.
9376 */
9377 TypeResolverVisitorFactory get typeResolverVisitorFactory;
9378
9379 /**
9380 * Return a list containing the sources of the libraries that are exported by
9381 * the library with the given [source]. The list will be empty if the given
9382 * source is invalid, if the given source does not represent a library, or if
9383 * the library does not export any other libraries.
9384 *
9385 * Throws an [AnalysisException] if the exported libraries could not be
9386 * computed.
9387 */
9388 List<Source> computeExportedLibraries(Source source);
9389
9390 /**
9391 * Return a list containing the sources of the libraries that are imported by
9392 * the library with the given [source]. The list will be empty if the given
9393 * source is invalid, if the given source does not represent a library, or if
9394 * the library does not import any other libraries.
9395 *
9396 * Throws an [AnalysisException] if the imported libraries could not be
9397 * computed.
9398 */
9399 List<Source> computeImportedLibraries(Source source);
9400
9401 /**
9402 * Return an AST structure corresponding to the given [source], but ensure
9403 * that the structure has not already been resolved and will not be resolved
9404 * by any other threads or in any other library.
9405 *
9406 * Throws an [AnalysisException] if the analysis could not be performed.
9407 *
9408 * <b>Note:</b> This method cannot be used in an async environment
9409 */
9410 CompilationUnit computeResolvableCompilationUnit(Source source);
9411
9412 /**
9413 * Return all the resolved [CompilationUnit]s for the given [source] if not
9414 * flushed, otherwise return `null` and ensures that the [CompilationUnit]s
9415 * will be eventually returned to the client from [performAnalysisTask].
9416 */
9417 List<CompilationUnit> ensureResolvedDartUnits(Source source);
9418
9419 /**
9420 * Return the cache entry associated with the given [target].
9421 */
9422 cache.CacheEntry getCacheEntry(AnalysisTarget target);
9423
9424 /**
9425 * Return context that owns the given [source].
9426 */
9427 InternalAnalysisContext getContextFor(Source source);
9428
9429 /**
9430 * Return a change notice for the given [source], creating one if one does not
9431 * already exist.
9432 */
9433 ChangeNoticeImpl getNotice(Source source);
9434
9435 /**
9436 * Return a namespace containing mappings for all of the public names defined
9437 * by the given [library].
9438 */
9439 Namespace getPublicNamespace(LibraryElement library);
9440
9441 /**
9442 * Respond to a change which has been made to the given [source] file.
9443 * [originalContents] is the former contents of the file, and [newContents]
9444 * is the updated contents. If [notify] is true, a source changed event is
9445 * triggered.
9446 *
9447 * Normally it should not be necessary for clients to call this function,
9448 * since it will be automatically invoked in response to a call to
9449 * [applyChanges] or [setContents]. However, if this analysis context is
9450 * sharing its content cache with other contexts, then the client must
9451 * manually update the content cache and call this function for each context.
9452 *
9453 * Return `true` if the change was significant to this context (i.e. [source]
9454 * is either implicitly or explicitly analyzed by this context, and a change
9455 * actually occurred).
9456 */
9457 bool handleContentsChanged(
9458 Source source, String originalContents, String newContents, bool notify);
9459
9460 /**
9461 * Given an [elementMap] mapping the source for the libraries represented by
9462 * the corresponding elements to the elements representing the libraries,
9463 * record those mappings.
9464 */
9465 void recordLibraryElements(Map<Source, LibraryElement> elementMap);
9466
9467 /**
9468 * Return `true` if errors should be produced for the given [source].
9469 * The [entry] associated with the source is passed in for efficiency.
9470 *
9471 * TODO(scheglov) remove [entry] after migration to the new task model.
9472 * It is not used there anyway.
9473 */
9474 bool shouldErrorsBeAnalyzed(Source source, Object entry);
9475
9476 /**
9477 * For testing only: flush all representations of the AST (both resolved and
9478 * unresolved) for the given [source] out of the cache.
9479 */
9480 void test_flushAstStructures(Source source);
9481
9482 /**
9483 * Call the given callback function for eache cache item in the context.
9484 */
9485 @deprecated
9486 void visitCacheItems(void callback(Source source, SourceEntry dartEntry,
9487 DataDescriptor rowDesc, CacheState state));
9488
9489 /**
9490 * Visit all entries of the content cache.
9491 */
9492 void visitContentCache(ContentCacheVisitor visitor);
9493 }
9494
9495 /**
9496 * An object that can be used to receive information about errors within the
9497 * analysis engine. Implementations usually write this information to a file,
9498 * but can also record the information for later use (such as during testing) or
9499 * even ignore the information.
9500 */
9501 abstract class Logger {
9502 /**
9503 * A logger that ignores all logging.
9504 */
9505 static final Logger NULL = new NullLogger();
9506
9507 /**
9508 * Log the given message as an error. The [message] is expected to be an
9509 * explanation of why the error occurred or what it means. The [exception] is
9510 * expected to be the reason for the error. At least one argument must be
9511 * provided.
9512 */
9513 void logError(String message, [CaughtException exception]);
9514
9515 /**
9516 * Log the given [exception] as one representing an error. The [message] is an
9517 * explanation of why the error occurred or what it means.
9518 */
9519 @deprecated // Use logError(message, exception)
9520 void logError2(String message, Object exception);
9521
9522 /**
9523 * Log the given informational message. The [message] is expected to be an
9524 * explanation of why the error occurred or what it means. The [exception] is
9525 * expected to be the reason for the error.
9526 */
9527 void logInformation(String message, [CaughtException exception]);
9528
9529 /**
9530 * Log the given [exception] as one representing an informational message. The
9531 * [message] is an explanation of why the error occurred or what it means.
9532 */
9533 @deprecated // Use logInformation(message, exception)
9534 void logInformation2(String message, Object exception);
9535 }
9536
9537 /**
9538 * An implementation of [Logger] that does nothing.
9539 */
9540 class NullLogger implements Logger {
9541 @override
9542 void logError(String message, [CaughtException exception]) {}
9543
9544 @override
9545 void logError2(String message, Object exception) {}
9546
9547 @override
9548 void logInformation(String message, [CaughtException exception]) {}
9549
9550 @override
9551 void logInformation2(String message, Object exception) {}
9552 }
9553
9554 /**
9555 * An exception created when an analysis attempt fails because a source was
9556 * deleted between the time the analysis started and the time the results of the
9557 * analysis were ready to be recorded.
9558 */
9559 class ObsoleteSourceAnalysisException extends AnalysisException {
9560 /**
9561 * The source that was removed while it was being analyzed.
9562 */
9563 Source _source;
9564
9565 /**
9566 * Initialize a newly created exception to represent the removal of the given
9567 * [source].
9568 */
9569 ObsoleteSourceAnalysisException(Source source)
9570 : super(
9571 "The source '${source.fullName}' was removed while it was being anal yzed") {
9572 this._source = source;
9573 }
9574
9575 /**
9576 * Return the source that was removed while it was being analyzed.
9577 */
9578 Source get source => _source;
9579 }
9580
9581 /**
9582 * Instances of the class `ParseDartTask` parse a specific source as a Dart file .
9583 */
9584 class ParseDartTask extends AnalysisTask {
9585 /**
9586 * The source to be parsed.
9587 */
9588 final Source source;
9589
9590 /**
9591 * The head of the token stream used for parsing.
9592 */
9593 final Token _tokenStream;
9594
9595 /**
9596 * The line information associated with the source.
9597 */
9598 final LineInfo lineInfo;
9599
9600 /**
9601 * The compilation unit that was produced by parsing the source.
9602 */
9603 CompilationUnit _unit;
9604
9605 /**
9606 * A flag indicating whether the source contains a 'part of' directive.
9607 */
9608 bool _containsPartOfDirective = false;
9609
9610 /**
9611 * A flag indicating whether the source contains any directive other than a 'p art of' directive.
9612 */
9613 bool _containsNonPartOfDirective = false;
9614
9615 /**
9616 * A set containing the sources referenced by 'export' directives.
9617 */
9618 HashSet<Source> _exportedSources = new HashSet<Source>();
9619
9620 /**
9621 * A set containing the sources referenced by 'import' directives.
9622 */
9623 HashSet<Source> _importedSources = new HashSet<Source>();
9624
9625 /**
9626 * A set containing the sources referenced by 'part' directives.
9627 */
9628 HashSet<Source> _includedSources = new HashSet<Source>();
9629
9630 /**
9631 * The errors that were produced by scanning and parsing the source.
9632 */
9633 List<AnalysisError> _errors = AnalysisError.NO_ERRORS;
9634
9635 /**
9636 * Initialize a newly created task to perform analysis within the given contex t.
9637 *
9638 * @param context the context in which the task is to be performed
9639 * @param source the source to be parsed
9640 * @param tokenStream the head of the token stream used for parsing
9641 * @param lineInfo the line information associated with the source
9642 */
9643 ParseDartTask(InternalAnalysisContext context, this.source, this._tokenStream,
9644 this.lineInfo)
9645 : super(context);
9646
9647 /**
9648 * Return the compilation unit that was produced by parsing the source, or `nu ll` if the
9649 * task has not yet been performed or if an exception occurred.
9650 *
9651 * @return the compilation unit that was produced by parsing the source
9652 */
9653 CompilationUnit get compilationUnit => _unit;
9654
9655 /**
9656 * Return the errors that were produced by scanning and parsing the source, or an empty list if
9657 * the task has not yet been performed or if an exception occurred.
9658 *
9659 * @return the errors that were produced by scanning and parsing the source
9660 */
9661 List<AnalysisError> get errors => _errors;
9662
9663 /**
9664 * Return a list containing the sources referenced by 'export' directives, or an empty list if
9665 * the task has not yet been performed or if an exception occurred.
9666 *
9667 * @return an list containing the sources referenced by 'export' directives
9668 */
9669 List<Source> get exportedSources => _toArray(_exportedSources);
9670
9671 /**
9672 * Return `true` if the source contains any directive other than a 'part of' d irective, or
9673 * `false` if the task has not yet been performed or if an exception occurred.
9674 *
9675 * @return `true` if the source contains any directive other than a 'part of' directive
9676 */
9677 bool get hasNonPartOfDirective => _containsNonPartOfDirective;
9678
9679 /**
9680 * Return `true` if the source contains a 'part of' directive, or `false` if t he task
9681 * has not yet been performed or if an exception occurred.
9682 *
9683 * @return `true` if the source contains a 'part of' directive
9684 */
9685 bool get hasPartOfDirective => _containsPartOfDirective;
9686
9687 /**
9688 * Return a list containing the sources referenced by 'import' directives, or an empty list if
9689 * the task has not yet been performed or if an exception occurred.
9690 *
9691 * @return a list containing the sources referenced by 'import' directives
9692 */
9693 List<Source> get importedSources => _toArray(_importedSources);
9694
9695 /**
9696 * Return a list containing the sources referenced by 'part' directives, or an empty list if
9697 * the task has not yet been performed or if an exception occurred.
9698 *
9699 * @return a list containing the sources referenced by 'part' directives
9700 */
9701 List<Source> get includedSources => _toArray(_includedSources);
9702
9703 @override
9704 String get taskDescription {
9705 if (source == null) {
9706 return "parse as dart null source";
9707 }
9708 return "parse as dart ${source.fullName}";
9709 }
9710
9711 @override
9712 accept(AnalysisTaskVisitor visitor) => visitor.visitParseDartTask(this);
9713
9714 @override
9715 void internalPerform() {
9716 //
9717 // Then parse the token stream.
9718 //
9719 PerformanceStatistics.parse.makeCurrentWhile(() {
9720 RecordingErrorListener errorListener = new RecordingErrorListener();
9721 Parser parser = new Parser(source, errorListener);
9722 AnalysisOptions options = context.analysisOptions;
9723 parser.parseFunctionBodies =
9724 options.analyzeFunctionBodiesPredicate(source);
9725 parser.parseGenericMethods = options.enableGenericMethods;
9726 _unit = parser.parseCompilationUnit(_tokenStream);
9727 _unit.lineInfo = lineInfo;
9728 AnalysisContext analysisContext = context;
9729 for (Directive directive in _unit.directives) {
9730 if (directive is PartOfDirective) {
9731 _containsPartOfDirective = true;
9732 } else {
9733 _containsNonPartOfDirective = true;
9734 if (directive is UriBasedDirective) {
9735 Source referencedSource = resolveDirective(
9736 analysisContext, source, directive, errorListener);
9737 if (referencedSource != null) {
9738 if (directive is ExportDirective) {
9739 _exportedSources.add(referencedSource);
9740 } else if (directive is ImportDirective) {
9741 _importedSources.add(referencedSource);
9742 } else if (directive is PartDirective) {
9743 if (referencedSource != source) {
9744 _includedSources.add(referencedSource);
9745 }
9746 } else {
9747 throw new AnalysisException(
9748 "$runtimeType failed to handle a ${directive.runtimeType}");
9749 }
9750 }
9751 }
9752 }
9753 }
9754 _errors = errorListener.getErrorsForSource(source);
9755 });
9756 }
9757
9758 /**
9759 * Efficiently convert the given set of [sources] to a list.
9760 */
9761 List<Source> _toArray(HashSet<Source> sources) {
9762 int size = sources.length;
9763 if (size == 0) {
9764 return Source.EMPTY_LIST;
9765 }
9766 return new List.from(sources);
9767 }
9768
9769 /**
9770 * Return the result of resolving the URI of the given URI-based directive aga inst the URI of the
9771 * given library, or `null` if the URI is not valid.
9772 *
9773 * @param context the context in which the resolution is to be performed
9774 * @param librarySource the source representing the library containing the dir ective
9775 * @param directive the directive which URI should be resolved
9776 * @param errorListener the error listener to which errors should be reported
9777 * @return the result of resolving the URI against the URI of the library
9778 */
9779 static Source resolveDirective(AnalysisContext context, Source librarySource,
9780 UriBasedDirective directive, AnalysisErrorListener errorListener) {
9781 StringLiteral uriLiteral = directive.uri;
9782 String uriContent = uriLiteral.stringValue;
9783 if (uriContent != null) {
9784 uriContent = uriContent.trim();
9785 directive.uriContent = uriContent;
9786 }
9787 UriValidationCode code = directive.validate();
9788 if (code == null) {
9789 String encodedUriContent = Uri.encodeFull(uriContent);
9790 try {
9791 Source source =
9792 context.sourceFactory.resolveUri(librarySource, encodedUriContent);
9793 directive.source = source;
9794 return source;
9795 } on JavaIOException {
9796 code = UriValidationCode.INVALID_URI;
9797 }
9798 }
9799 if (code == UriValidationCode.URI_WITH_DART_EXT_SCHEME) {
9800 return null;
9801 }
9802 if (code == UriValidationCode.URI_WITH_INTERPOLATION) {
9803 errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset,
9804 uriLiteral.length, CompileTimeErrorCode.URI_WITH_INTERPOLATION));
9805 return null;
9806 }
9807 if (code == UriValidationCode.INVALID_URI) {
9808 errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset,
9809 uriLiteral.length, CompileTimeErrorCode.INVALID_URI, [uriContent]));
9810 return null;
9811 }
9812 throw new RuntimeException(
9813 message: "Failed to handle validation code: $code");
9814 }
9815 }
9816
9817 /**
9818 * Instances of the class `ParseHtmlTask` parse a specific source as an HTML fil e.
9819 */
9820 class ParseHtmlTask extends AnalysisTask {
9821 /**
9822 * The name of the 'src' attribute in a HTML tag.
9823 */
9824 static String _ATTRIBUTE_SRC = "src";
9825
9826 /**
9827 * The name of the 'script' tag in an HTML file.
9828 */
9829 static String _TAG_SCRIPT = "script";
9830
9831 /**
9832 * The source to be parsed.
9833 */
9834 final Source source;
9835
9836 /**
9837 * The contents of the source.
9838 */
9839 final String _content;
9840
9841 /**
9842 * The line information that was produced.
9843 */
9844 LineInfo _lineInfo;
9845
9846 /**
9847 * The HTML unit that was produced by parsing the source.
9848 */
9849 ht.HtmlUnit _unit;
9850
9851 /**
9852 * The errors that were produced by scanning and parsing the source.
9853 */
9854 List<AnalysisError> _errors = AnalysisError.NO_ERRORS;
9855
9856 /**
9857 * A list containing the sources of the libraries that are referenced within t he HTML.
9858 */
9859 List<Source> _referencedLibraries = Source.EMPTY_LIST;
9860
9861 /**
9862 * Initialize a newly created task to perform analysis within the given contex t.
9863 *
9864 * @param context the context in which the task is to be performed
9865 * @param source the source to be parsed
9866 * @param content the contents of the source
9867 */
9868 ParseHtmlTask(InternalAnalysisContext context, this.source, this._content)
9869 : super(context);
9870
9871 /**
9872 * Return the errors that were produced by scanning and parsing the source, or `null` if the
9873 * task has not yet been performed or if an exception occurred.
9874 *
9875 * @return the errors that were produced by scanning and parsing the source
9876 */
9877 List<AnalysisError> get errors => _errors;
9878
9879 /**
9880 * Return the HTML unit that was produced by parsing the source.
9881 *
9882 * @return the HTML unit that was produced by parsing the source
9883 */
9884 ht.HtmlUnit get htmlUnit => _unit;
9885
9886 /**
9887 * Return the sources of libraries that are referenced in the specified HTML f ile.
9888 *
9889 * @return the sources of libraries that are referenced in the HTML file
9890 */
9891 List<Source> get librarySources {
9892 List<Source> libraries = new List<Source>();
9893 _unit.accept(new ParseHtmlTask_getLibrarySources(this, libraries));
9894 if (libraries.isEmpty) {
9895 return Source.EMPTY_LIST;
9896 }
9897 return libraries;
9898 }
9899
9900 /**
9901 * Return the line information that was produced, or `null` if the task has no t yet been
9902 * performed or if an exception occurred.
9903 *
9904 * @return the line information that was produced
9905 */
9906 LineInfo get lineInfo => _lineInfo;
9907
9908 /**
9909 * Return a list containing the sources of the libraries that are referenced w ithin the HTML.
9910 *
9911 * @return the sources of the libraries that are referenced within the HTML
9912 */
9913 List<Source> get referencedLibraries => _referencedLibraries;
9914
9915 @override
9916 String get taskDescription {
9917 if (source == null) {
9918 return "parse as html null source";
9919 }
9920 return "parse as html ${source.fullName}";
9921 }
9922
9923 @override
9924 accept(AnalysisTaskVisitor visitor) => visitor.visitParseHtmlTask(this);
9925
9926 @override
9927 void internalPerform() {
9928 try {
9929 ht.AbstractScanner scanner = new ht.StringScanner(source, _content);
9930 scanner.passThroughElements = <String>[_TAG_SCRIPT];
9931 ht.Token token = scanner.tokenize();
9932 _lineInfo = new LineInfo(scanner.lineStarts);
9933 RecordingErrorListener errorListener = new RecordingErrorListener();
9934 _unit = new ht.HtmlParser(source, errorListener, context.analysisOptions)
9935 .parse(token, _lineInfo);
9936 _unit.accept(new RecursiveXmlVisitor_ParseHtmlTask_internalPerform(
9937 this, errorListener));
9938 _errors = errorListener.getErrorsForSource(source);
9939 _referencedLibraries = librarySources;
9940 } catch (exception, stackTrace) {
9941 throw new AnalysisException(
9942 "Exception", new CaughtException(exception, stackTrace));
9943 }
9944 }
9945
9946 /**
9947 * Resolves directives in the given [CompilationUnit].
9948 */
9949 void _resolveScriptDirectives(
9950 CompilationUnit script, AnalysisErrorListener errorListener) {
9951 if (script == null) {
9952 return;
9953 }
9954 AnalysisContext analysisContext = context;
9955 for (Directive directive in script.directives) {
9956 if (directive is UriBasedDirective) {
9957 ParseDartTask.resolveDirective(
9958 analysisContext, source, directive, errorListener);
9959 }
9960 }
9961 }
9962 }
9963
9964 class ParseHtmlTask_getLibrarySources extends ht.RecursiveXmlVisitor<Object> {
9965 final ParseHtmlTask _task;
9966
9967 List<Source> libraries;
9968
9969 ParseHtmlTask_getLibrarySources(this._task, this.libraries) : super();
9970
9971 @override
9972 Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) {
9973 ht.XmlAttributeNode scriptAttribute = null;
9974 for (ht.XmlAttributeNode attribute in node.attributes) {
9975 if (javaStringEqualsIgnoreCase(
9976 attribute.name, ParseHtmlTask._ATTRIBUTE_SRC)) {
9977 scriptAttribute = attribute;
9978 }
9979 }
9980 if (scriptAttribute != null) {
9981 try {
9982 Uri uri = Uri.parse(scriptAttribute.text);
9983 String fileName = uri.path;
9984 Source librarySource =
9985 _task.context.sourceFactory.resolveUri(_task.source, fileName);
9986 if (_task.context.exists(librarySource)) {
9987 libraries.add(librarySource);
9988 }
9989 } on FormatException {
9990 // ignored - invalid URI reported during resolution phase
9991 }
9992 }
9993 return super.visitHtmlScriptTagNode(node);
9994 }
9995 }
9996
9997 /**
9998 * An object that manages the partitions that can be shared between analysis
9999 * contexts.
10000 */
10001 class PartitionManager {
10002 /**
10003 * The default cache size for a Dart SDK partition.
10004 */
10005 static int _DEFAULT_SDK_CACHE_SIZE = 256;
10006
10007 /**
10008 * A table mapping SDK's to the partitions used for those SDK's.
10009 */
10010 HashMap<DartSdk, SdkCachePartition> _sdkPartitions =
10011 new HashMap<DartSdk, SdkCachePartition>();
10012
10013 /**
10014 * Clear any cached data being maintained by this manager.
10015 */
10016 void clearCache() {
10017 _sdkPartitions.clear();
10018 }
10019
10020 /**
10021 * Return the partition being used for the given [sdk], creating the partition
10022 * if necessary.
10023 */
10024 SdkCachePartition forSdk(DartSdk sdk) {
10025 // Call sdk.context now, because when it creates a new
10026 // InternalAnalysisContext instance, it calls forSdk() again, so creates an
10027 // SdkCachePartition instance.
10028 // So, if we initialize context after "partition == null", we end up
10029 // with two SdkCachePartition instances.
10030 InternalAnalysisContext sdkContext = sdk.context;
10031 // Check cache for an existing partition.
10032 SdkCachePartition partition = _sdkPartitions[sdk];
10033 if (partition == null) {
10034 partition = new SdkCachePartition(sdkContext, _DEFAULT_SDK_CACHE_SIZE);
10035 _sdkPartitions[sdk] = partition;
10036 }
10037 return partition;
10038 }
10039 }
10040
10041 /**
10042 * Representation of a pending computation which is based on the results of
10043 * analysis that may or may not have been completed.
10044 */
10045 class PendingFuture<T> {
10046 /**
10047 * The context in which this computation runs.
10048 */
10049 final AnalysisContextImpl _context;
10050
10051 /**
10052 * The source used by this computation to compute its value.
10053 */
10054 final Source source;
10055
10056 /**
10057 * The function which implements the computation.
10058 */
10059 final PendingFutureComputer<T> _computeValue;
10060
10061 /**
10062 * The completer that should be completed once the computation has succeeded.
10063 */
10064 CancelableCompleter<T> _completer;
10065
10066 PendingFuture(this._context, this.source, this._computeValue) {
10067 _completer = new CancelableCompleter<T>(_onCancel);
10068 }
10069
10070 /**
10071 * Retrieve the future which will be completed when this object is
10072 * successfully evaluated.
10073 */
10074 CancelableFuture<T> get future => _completer.future;
10075
10076 /**
10077 * Execute [_computeValue], passing it the given [sourceEntry], and complete
10078 * the pending future if it's appropriate to do so. If the pending future is
10079 * completed by this call, true is returned; otherwise false is returned.
10080 *
10081 * Once this function has returned true, it should not be called again.
10082 *
10083 * Other than completing the future, this method is free of side effects.
10084 * Note that any code the client has attached to the future will be executed
10085 * in a microtask, so there is no danger of side effects occurring due to
10086 * client callbacks.
10087 */
10088 bool evaluate(SourceEntry sourceEntry) {
10089 assert(!_completer.isCompleted);
10090 try {
10091 T result = _computeValue(sourceEntry);
10092 if (result == null) {
10093 return false;
10094 } else {
10095 _completer.complete(result);
10096 return true;
10097 }
10098 } catch (exception, stackTrace) {
10099 _completer.completeError(exception, stackTrace);
10100 return true;
10101 }
10102 }
10103
10104 /**
10105 * No further analysis updates are expected which affect this future, so
10106 * complete it with an AnalysisNotScheduledError in order to avoid
10107 * deadlocking the client.
10108 */
10109 void forciblyComplete() {
10110 try {
10111 throw new AnalysisNotScheduledError();
10112 } catch (exception, stackTrace) {
10113 _completer.completeError(exception, stackTrace);
10114 }
10115 }
10116
10117 void _onCancel() {
10118 _context._cancelFuture(this);
10119 }
10120 }
10121
10122 /**
10123 * Container with global [AnalysisContext] performance statistics.
10124 */
10125 class PerformanceStatistics {
10126 /**
10127 * The [PerformanceTag] for time spent in reading files.
10128 */
10129 static PerformanceTag io = new PerformanceTag('io');
10130
10131 /**
10132 * The [PerformanceTag] for time spent in scanning.
10133 */
10134 static PerformanceTag scan = new PerformanceTag('scan');
10135
10136 /**
10137 * The [PerformanceTag] for time spent in parsing.
10138 */
10139 static PerformanceTag parse = new PerformanceTag('parse');
10140
10141 /**
10142 * The [PerformanceTag] for time spent in resolving.
10143 */
10144 static PerformanceTag resolve = new PerformanceTag('resolve');
10145
10146 /**
10147 * The [PerformanceTag] for time spent in error verifier.
10148 */
10149 static PerformanceTag errors = new PerformanceTag('errors');
10150
10151 /**
10152 * The [PerformanceTag] for time spent in hints generator.
10153 */
10154 static PerformanceTag hints = new PerformanceTag('hints');
10155
10156 /**
10157 * The [PerformanceTag] for time spent in linting.
10158 */
10159 static PerformanceTag lint = new PerformanceTag('lint');
10160
10161 /**
10162 * The [PerformanceTag] for time spent computing cycles.
10163 */
10164 static PerformanceTag cycles = new PerformanceTag('cycles');
10165
10166 /**
10167 * The [PerformanceTag] for time spent in other phases of analysis.
10168 */
10169 static PerformanceTag performAnaysis = new PerformanceTag('performAnaysis');
10170
10171 /**
10172 * The [PerformanceTag] for time spent in the analysis task visitor after
10173 * tasks are complete.
10174 */
10175 static PerformanceTag analysisTaskVisitor =
10176 new PerformanceTag('analysisTaskVisitor');
10177
10178 /**
10179 * The [PerformanceTag] for time spent in the getter
10180 * AnalysisContextImpl.nextAnalysisTask.
10181 */
10182 static var nextTask = new PerformanceTag('nextAnalysisTask');
10183
10184 /**
10185 * The [PerformanceTag] for time spent during otherwise not accounted parts
10186 * incremental of analysis.
10187 */
10188 static PerformanceTag incrementalAnalysis =
10189 new PerformanceTag('incrementalAnalysis');
10190 }
10191
10192 /**
10193 * An error listener that will record the errors that are reported to it in a
10194 * way that is appropriate for caching those errors within an analysis context.
10195 */
10196 class RecordingErrorListener implements AnalysisErrorListener {
10197 /**
10198 * A map of sets containing the errors that were collected, keyed by each
10199 * source.
10200 */
10201 Map<Source, HashSet<AnalysisError>> _errors =
10202 new HashMap<Source, HashSet<AnalysisError>>();
10203
10204 /**
10205 * Return the errors collected by the listener.
10206 */
10207 List<AnalysisError> get errors {
10208 int numEntries = _errors.length;
10209 if (numEntries == 0) {
10210 return AnalysisError.NO_ERRORS;
10211 }
10212 List<AnalysisError> resultList = new List<AnalysisError>();
10213 for (HashSet<AnalysisError> errors in _errors.values) {
10214 resultList.addAll(errors);
10215 }
10216 return resultList;
10217 }
10218
10219 /**
10220 * Add all of the errors recorded by the given [listener] to this listener.
10221 */
10222 void addAll(RecordingErrorListener listener) {
10223 for (AnalysisError error in listener.errors) {
10224 onError(error);
10225 }
10226 }
10227
10228 /**
10229 * Return the errors collected by the listener for the given [source].
10230 */
10231 List<AnalysisError> getErrorsForSource(Source source) {
10232 HashSet<AnalysisError> errorsForSource = _errors[source];
10233 if (errorsForSource == null) {
10234 return AnalysisError.NO_ERRORS;
10235 } else {
10236 return new List.from(errorsForSource);
10237 }
10238 }
10239
10240 @override
10241 void onError(AnalysisError error) {
10242 Source source = error.source;
10243 HashSet<AnalysisError> errorsForSource = _errors[source];
10244 if (_errors[source] == null) {
10245 errorsForSource = new HashSet<AnalysisError>();
10246 _errors[source] = errorsForSource;
10247 }
10248 errorsForSource.add(error);
10249 }
10250 }
10251
10252 class RecursiveXmlVisitor_ParseHtmlTask_internalPerform
10253 extends ht.RecursiveXmlVisitor<Object> {
10254 final ParseHtmlTask ParseHtmlTask_this;
10255
10256 RecordingErrorListener errorListener;
10257
10258 RecursiveXmlVisitor_ParseHtmlTask_internalPerform(
10259 this.ParseHtmlTask_this, this.errorListener)
10260 : super();
10261
10262 @override
10263 Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) {
10264 ParseHtmlTask_this._resolveScriptDirectives(node.script, errorListener);
10265 return null;
10266 }
10267 }
10268
10269 class RecursiveXmlVisitor_ResolveHtmlTask_internalPerform
10270 extends ht.RecursiveXmlVisitor<Object> {
10271 final ResolveHtmlTask ResolveHtmlTask_this;
10272
10273 RecordingErrorListener errorListener;
10274
10275 RecursiveXmlVisitor_ResolveHtmlTask_internalPerform(
10276 this.ResolveHtmlTask_this, this.errorListener)
10277 : super();
10278
10279 @override
10280 Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) {
10281 CompilationUnit script = node.script;
10282 if (script != null) {
10283 GenerateDartErrorsTask.validateDirectives(ResolveHtmlTask_this.context,
10284 ResolveHtmlTask_this.source, script, errorListener);
10285 }
10286 return null;
10287 }
10288 }
10289
10290 /**
10291 * An visitor that removes any resolution information from an AST structure when
10292 * used to visit that structure.
10293 */
10294 class ResolutionEraser extends GeneralizingAstVisitor<Object> {
10295 @override
10296 Object visitAssignmentExpression(AssignmentExpression node) {
10297 node.staticElement = null;
10298 node.propagatedElement = null;
10299 return super.visitAssignmentExpression(node);
10300 }
10301
10302 @override
10303 Object visitBinaryExpression(BinaryExpression node) {
10304 node.staticElement = null;
10305 node.propagatedElement = null;
10306 return super.visitBinaryExpression(node);
10307 }
10308
10309 @override
10310 Object visitBreakStatement(BreakStatement node) {
10311 node.target = null;
10312 return super.visitBreakStatement(node);
10313 }
10314
10315 @override
10316 Object visitCompilationUnit(CompilationUnit node) {
10317 node.element = null;
10318 return super.visitCompilationUnit(node);
10319 }
10320
10321 @override
10322 Object visitConstructorDeclaration(ConstructorDeclaration node) {
10323 node.element = null;
10324 return super.visitConstructorDeclaration(node);
10325 }
10326
10327 @override
10328 Object visitConstructorName(ConstructorName node) {
10329 node.staticElement = null;
10330 return super.visitConstructorName(node);
10331 }
10332
10333 @override
10334 Object visitContinueStatement(ContinueStatement node) {
10335 node.target = null;
10336 return super.visitContinueStatement(node);
10337 }
10338
10339 @override
10340 Object visitDirective(Directive node) {
10341 node.element = null;
10342 return super.visitDirective(node);
10343 }
10344
10345 @override
10346 Object visitExpression(Expression node) {
10347 node.staticType = null;
10348 node.propagatedType = null;
10349 return super.visitExpression(node);
10350 }
10351
10352 @override
10353 Object visitFunctionExpression(FunctionExpression node) {
10354 node.element = null;
10355 return super.visitFunctionExpression(node);
10356 }
10357
10358 @override
10359 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
10360 node.staticElement = null;
10361 node.propagatedElement = null;
10362 return super.visitFunctionExpressionInvocation(node);
10363 }
10364
10365 @override
10366 Object visitIndexExpression(IndexExpression node) {
10367 node.staticElement = null;
10368 node.propagatedElement = null;
10369 return super.visitIndexExpression(node);
10370 }
10371
10372 @override
10373 Object visitInstanceCreationExpression(InstanceCreationExpression node) {
10374 node.staticElement = null;
10375 return super.visitInstanceCreationExpression(node);
10376 }
10377
10378 @override
10379 Object visitPostfixExpression(PostfixExpression node) {
10380 node.staticElement = null;
10381 node.propagatedElement = null;
10382 return super.visitPostfixExpression(node);
10383 }
10384
10385 @override
10386 Object visitPrefixExpression(PrefixExpression node) {
10387 node.staticElement = null;
10388 node.propagatedElement = null;
10389 return super.visitPrefixExpression(node);
10390 }
10391
10392 @override
10393 Object visitRedirectingConstructorInvocation(
10394 RedirectingConstructorInvocation node) {
10395 node.staticElement = null;
10396 return super.visitRedirectingConstructorInvocation(node);
10397 }
10398
10399 @override
10400 Object visitSimpleIdentifier(SimpleIdentifier node) {
10401 node.staticElement = null;
10402 node.propagatedElement = null;
10403 return super.visitSimpleIdentifier(node);
10404 }
10405
10406 @override
10407 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
10408 node.staticElement = null;
10409 return super.visitSuperConstructorInvocation(node);
10410 }
10411
10412 /**
10413 * Remove any resolution information from the given AST structure.
10414 */
10415 static void erase(AstNode node) {
10416 node.accept(new ResolutionEraser());
10417 }
10418 }
10419
10420 /**
10421 * The information produced by resolving a compilation unit as part of a
10422 * specific library.
10423 */
10424 class ResolutionState {
10425 /**
10426 * The next resolution state or `null` if none.
10427 */
10428 ResolutionState _nextState;
10429
10430 /**
10431 * The source for the defining compilation unit of the library that contains
10432 * this unit. If this unit is the defining compilation unit for it's library,
10433 * then this will be the source for this unit.
10434 */
10435 Source _librarySource;
10436
10437 /**
10438 * A table mapping descriptors to the cached results for those descriptors.
10439 * If there is no entry for a given descriptor then the state is implicitly
10440 * [CacheState.INVALID] and the value is implicitly the default value.
10441 */
10442 Map<DataDescriptor, CachedResult> resultMap =
10443 new HashMap<DataDescriptor, CachedResult>();
10444
10445 /**
10446 * Flush any AST structures being maintained by this state.
10447 */
10448 void flushAstStructures() {
10449 _flush(DartEntry.BUILT_UNIT);
10450 _flush(DartEntry.RESOLVED_UNIT);
10451 if (_nextState != null) {
10452 _nextState.flushAstStructures();
10453 }
10454 }
10455
10456 /**
10457 * Return the state of the data represented by the given [descriptor].
10458 */
10459 CacheState getState(DataDescriptor descriptor) {
10460 CachedResult result = resultMap[descriptor];
10461 if (result == null) {
10462 return CacheState.INVALID;
10463 }
10464 return result.state;
10465 }
10466
10467 /**
10468 * Return the value of the data represented by the given [descriptor], or
10469 * `null` if the data represented by the descriptor is not valid.
10470 */
10471 /*<V>*/ dynamic /*V*/ getValue(DataDescriptor /*<V>*/ descriptor) {
10472 CachedResult result = resultMap[descriptor];
10473 if (result == null) {
10474 return descriptor.defaultValue;
10475 }
10476 return result.value;
10477 }
10478
10479 /**
10480 * Return `true` if the state of any data value is [CacheState.ERROR].
10481 */
10482 bool hasErrorState() {
10483 for (CachedResult result in resultMap.values) {
10484 if (result.state == CacheState.ERROR) {
10485 return true;
10486 }
10487 }
10488 return false;
10489 }
10490
10491 /**
10492 * Invalidate all of the resolution information associated with the compilatio n unit.
10493 */
10494 void invalidateAllResolutionInformation() {
10495 _nextState = null;
10496 _librarySource = null;
10497 setState(DartEntry.BUILT_UNIT, CacheState.INVALID);
10498 setState(DartEntry.BUILT_ELEMENT, CacheState.INVALID);
10499 setState(DartEntry.HINTS, CacheState.INVALID);
10500 setState(DartEntry.LINTS, CacheState.INVALID);
10501 setState(DartEntry.RESOLVED_UNIT, CacheState.INVALID);
10502 setState(DartEntry.RESOLUTION_ERRORS, CacheState.INVALID);
10503 setState(DartEntry.VERIFICATION_ERRORS, CacheState.INVALID);
10504 }
10505
10506 /**
10507 * Record that an exception occurred while attempting to build the element
10508 * model for the source associated with this state.
10509 */
10510 void recordBuildElementError() {
10511 setState(DartEntry.BUILT_UNIT, CacheState.ERROR);
10512 setState(DartEntry.BUILT_ELEMENT, CacheState.ERROR);
10513 recordResolutionError();
10514 }
10515
10516 /**
10517 * Record that an exception occurred while attempting to generate hints for
10518 * the source associated with this entry. This will set the state of all
10519 * verification information as being in error.
10520 */
10521 void recordHintError() {
10522 setState(DartEntry.HINTS, CacheState.ERROR);
10523 }
10524
10525 /**
10526 * Record that an exception occurred while attempting to generate lints for
10527 * the source associated with this entry. This will set the state of all
10528 * verification information as being in error.
10529 */
10530 void recordLintError() {
10531 setState(DartEntry.LINTS, CacheState.ERROR);
10532 }
10533
10534 /**
10535 * Record that an exception occurred while attempting to resolve the source
10536 * associated with this state.
10537 */
10538 void recordResolutionError() {
10539 setState(DartEntry.RESOLVED_UNIT, CacheState.ERROR);
10540 setState(DartEntry.RESOLUTION_ERRORS, CacheState.ERROR);
10541 recordVerificationError();
10542 }
10543
10544 /**
10545 * Record that an exception occurred while attempting to scan or parse the
10546 * source associated with this entry. This will set the state of all
10547 * resolution-based information as being in error.
10548 */
10549 void recordResolutionErrorsInAllLibraries() {
10550 recordBuildElementError();
10551 if (_nextState != null) {
10552 _nextState.recordResolutionErrorsInAllLibraries();
10553 }
10554 }
10555
10556 /**
10557 * Record that an exception occurred while attempting to generate errors and
10558 * warnings for the source associated with this entry. This will set the state
10559 * of all verification information as being in error.
10560 */
10561 void recordVerificationError() {
10562 setState(DartEntry.VERIFICATION_ERRORS, CacheState.ERROR);
10563 recordHintError();
10564 }
10565
10566 /**
10567 * Set the state of the data represented by the given [descriptor] to the
10568 * given [state].
10569 */
10570 void setState(DataDescriptor descriptor, CacheState state) {
10571 if (state == CacheState.VALID) {
10572 throw new ArgumentError("use setValue() to set the state to VALID");
10573 }
10574 if (state == CacheState.INVALID) {
10575 resultMap.remove(descriptor);
10576 } else {
10577 CachedResult result =
10578 resultMap.putIfAbsent(descriptor, () => new CachedResult(descriptor));
10579 result.state = state;
10580 if (state != CacheState.IN_PROCESS) {
10581 //
10582 // If the state is in-process, we can leave the current value in the
10583 // cache for any 'get' methods to access.
10584 //
10585 result.value = descriptor.defaultValue;
10586 }
10587 }
10588 }
10589
10590 /**
10591 * Set the value of the data represented by the given [descriptor] to the
10592 * given [value].
10593 */
10594 void setValue(DataDescriptor /*<V>*/ descriptor, dynamic /*V*/ value) {
10595 CachedResult result =
10596 resultMap.putIfAbsent(descriptor, () => new CachedResult(descriptor));
10597 SourceEntry.countTransition(descriptor, result);
10598 result.state = CacheState.VALID;
10599 result.value = value == null ? descriptor.defaultValue : value;
10600 }
10601
10602 /**
10603 * Flush the value of the data described by the [descriptor].
10604 */
10605 void _flush(DataDescriptor descriptor) {
10606 CachedResult result = resultMap[descriptor];
10607 if (result != null && result.state == CacheState.VALID) {
10608 result.state = CacheState.FLUSHED;
10609 result.value = descriptor.defaultValue;
10610 }
10611 }
10612
10613 /**
10614 * Write a textual representation of the difference between the old entry and
10615 * this entry to the given string [buffer]. A separator will be written before
10616 * the first difference if [needsSeparator] is `true`. The [oldEntry] is the
10617 * entry that was replaced by this entry. Return `true` is a separator is
10618 * needed before writing any subsequent differences.
10619 */
10620 bool _writeDiffOn(
10621 StringBuffer buffer, bool needsSeparator, DartEntry oldEntry) {
10622 needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "resolvedUnit",
10623 DartEntry.RESOLVED_UNIT, oldEntry);
10624 needsSeparator = _writeStateDiffOn(buffer, needsSeparator,
10625 "resolutionErrors", DartEntry.RESOLUTION_ERRORS, oldEntry);
10626 needsSeparator = _writeStateDiffOn(buffer, needsSeparator,
10627 "verificationErrors", DartEntry.VERIFICATION_ERRORS, oldEntry);
10628 needsSeparator = _writeStateDiffOn(
10629 buffer, needsSeparator, "hints", DartEntry.HINTS, oldEntry);
10630 needsSeparator = _writeStateDiffOn(
10631 buffer, needsSeparator, "lints", DartEntry.LINTS, oldEntry);
10632 return needsSeparator;
10633 }
10634
10635 /**
10636 * Write a textual representation of this state to the given [buffer]. The
10637 * result will only be used for debugging purposes.
10638 */
10639 void _writeOn(StringBuffer buffer) {
10640 if (_librarySource != null) {
10641 _writeStateOn(buffer, "builtElement", DartEntry.BUILT_ELEMENT);
10642 _writeStateOn(buffer, "builtUnit", DartEntry.BUILT_UNIT);
10643 _writeStateOn(buffer, "resolvedUnit", DartEntry.RESOLVED_UNIT);
10644 _writeStateOn(buffer, "resolutionErrors", DartEntry.RESOLUTION_ERRORS);
10645 _writeStateOn(
10646 buffer, "verificationErrors", DartEntry.VERIFICATION_ERRORS);
10647 _writeStateOn(buffer, "hints", DartEntry.HINTS);
10648 _writeStateOn(buffer, "lints", DartEntry.LINTS);
10649 if (_nextState != null) {
10650 _nextState._writeOn(buffer);
10651 }
10652 }
10653 }
10654
10655 /**
10656 * Write a textual representation of the difference between the state of the
10657 * value described by the given [descriptor] between the [oldEntry] and this
10658 * entry to the given [buffer]. Return `true` if some difference was written.
10659 */
10660 bool _writeStateDiffOn(StringBuffer buffer, bool needsSeparator, String label,
10661 DataDescriptor descriptor, SourceEntry oldEntry) {
10662 CacheState oldState = oldEntry.getState(descriptor);
10663 CacheState newState = getState(descriptor);
10664 if (oldState != newState) {
10665 if (needsSeparator) {
10666 buffer.write("; ");
10667 }
10668 buffer.write(label);
10669 buffer.write(" = ");
10670 buffer.write(oldState);
10671 buffer.write(" -> ");
10672 buffer.write(newState);
10673 return true;
10674 }
10675 return needsSeparator;
10676 }
10677
10678 /**
10679 * Write a textual representation of the state of the value described by the
10680 * given [descriptor] to the given bugger, prefixed by the given [label] to
10681 * the given [buffer].
10682 */
10683 void _writeStateOn(
10684 StringBuffer buffer, String label, DataDescriptor descriptor) {
10685 CachedResult result = resultMap[descriptor];
10686 buffer.write("; ");
10687 buffer.write(label);
10688 buffer.write(" = ");
10689 buffer.write(result == null ? CacheState.INVALID : result.state);
10690 }
10691 }
10692
10693 /**
10694 * A compilation unit that is not referenced by any other objects. It is used by
10695 * the [LibraryResolver] to resolve a library.
10696 */
10697 class ResolvableCompilationUnit {
10698 /**
10699 * The source of the compilation unit.
10700 */
10701 final Source source;
10702
10703 /**
10704 * The compilation unit.
10705 */
10706 final CompilationUnit compilationUnit;
10707
10708 /**
10709 * Initialize a newly created holder to hold the given [source] and
10710 * [compilationUnit].
10711 */
10712 ResolvableCompilationUnit(this.source, this.compilationUnit);
10713 }
10714
10715 /**
10716 * Instances of the class `ResolveDartLibraryTask` resolve a specific Dart libra ry.
10717 */
10718 class ResolveDartLibraryCycleTask extends AnalysisTask {
10719 /**
10720 * The source representing the file whose compilation unit is to be returned. TODO(brianwilkerson)
10721 * This should probably be removed, but is being left in for now to ease the t ransition.
10722 */
10723 final Source unitSource;
10724
10725 /**
10726 * The source representing the library to be resolved.
10727 */
10728 final Source librarySource;
10729
10730 /**
10731 * The libraries that are part of the cycle containing the library to be resol ved.
10732 */
10733 final List<ResolvableLibrary> _librariesInCycle;
10734
10735 /**
10736 * The library resolver holding information about the libraries that were reso lved.
10737 */
10738 LibraryResolver2 _resolver;
10739
10740 /**
10741 * Initialize a newly created task to perform analysis within the given contex t.
10742 *
10743 * @param context the context in which the task is to be performed
10744 * @param unitSource the source representing the file whose compilation unit i s to be returned
10745 * @param librarySource the source representing the library to be resolved
10746 * @param librariesInCycle the libraries that are part of the cycle containing the library to be
10747 * resolved
10748 */
10749 ResolveDartLibraryCycleTask(InternalAnalysisContext context, this.unitSource,
10750 this.librarySource, this._librariesInCycle)
10751 : super(context);
10752
10753 /**
10754 * Return the library resolver holding information about the libraries that we re resolved.
10755 *
10756 * @return the library resolver holding information about the libraries that w ere resolved
10757 */
10758 LibraryResolver2 get libraryResolver => _resolver;
10759
10760 @override
10761 String get taskDescription {
10762 if (librarySource == null) {
10763 return "resolve library null source";
10764 }
10765 return "resolve library ${librarySource.fullName}";
10766 }
10767
10768 @override
10769 accept(AnalysisTaskVisitor visitor) =>
10770 visitor.visitResolveDartLibraryCycleTask(this);
10771
10772 @override
10773 void internalPerform() {
10774 _resolver = new LibraryResolver2(context);
10775 _resolver.resolveLibrary(librarySource, _librariesInCycle);
10776 }
10777 }
10778
10779 /**
10780 * Instances of the class `ResolveDartLibraryTask` resolve a specific Dart libra ry.
10781 */
10782 class ResolveDartLibraryTask extends AnalysisTask {
10783 /**
10784 * The source representing the file whose compilation unit is to be returned.
10785 */
10786 final Source unitSource;
10787
10788 /**
10789 * The source representing the library to be resolved.
10790 */
10791 final Source librarySource;
10792
10793 /**
10794 * The library resolver holding information about the libraries that were reso lved.
10795 */
10796 LibraryResolver _resolver;
10797
10798 /**
10799 * Initialize a newly created task to perform analysis within the given contex t.
10800 *
10801 * @param context the context in which the task is to be performed
10802 * @param unitSource the source representing the file whose compilation unit i s to be returned
10803 * @param librarySource the source representing the library to be resolved
10804 */
10805 ResolveDartLibraryTask(
10806 InternalAnalysisContext context, this.unitSource, this.librarySource)
10807 : super(context);
10808
10809 /**
10810 * Return the library resolver holding information about the libraries that we re resolved.
10811 *
10812 * @return the library resolver holding information about the libraries that w ere resolved
10813 */
10814 LibraryResolver get libraryResolver => _resolver;
10815
10816 @override
10817 String get taskDescription {
10818 if (librarySource == null) {
10819 return "resolve library null source";
10820 }
10821 return "resolve library ${librarySource.fullName}";
10822 }
10823
10824 @override
10825 accept(AnalysisTaskVisitor visitor) =>
10826 visitor.visitResolveDartLibraryTask(this);
10827
10828 @override
10829 void internalPerform() {
10830 LibraryResolverFactory resolverFactory = context.libraryResolverFactory;
10831 _resolver = resolverFactory == null
10832 ? new LibraryResolver(context)
10833 : resolverFactory(context);
10834 _resolver.resolveLibrary(librarySource, true);
10835 }
10836 }
10837
10838 /**
10839 * Instances of the class `ResolveDartUnitTask` resolve a single Dart file based on a existing
10840 * element model.
10841 */
10842 class ResolveDartUnitTask extends AnalysisTask {
10843 /**
10844 * The source that is to be resolved.
10845 */
10846 final Source source;
10847
10848 /**
10849 * The element model for the library containing the source.
10850 */
10851 final LibraryElement _libraryElement;
10852
10853 /**
10854 * The compilation unit that was resolved by this task.
10855 */
10856 CompilationUnit _resolvedUnit;
10857
10858 /**
10859 * Initialize a newly created task to perform analysis within the given contex t.
10860 *
10861 * @param context the context in which the task is to be performed
10862 * @param source the source to be parsed
10863 * @param libraryElement the element model for the library containing the sour ce
10864 */
10865 ResolveDartUnitTask(
10866 InternalAnalysisContext context, this.source, this._libraryElement)
10867 : super(context);
10868
10869 /**
10870 * Return the source for the library containing the source that is to be resol ved.
10871 *
10872 * @return the source for the library containing the source that is to be reso lved
10873 */
10874 Source get librarySource => _libraryElement.source;
10875
10876 /**
10877 * Return the compilation unit that was resolved by this task.
10878 *
10879 * @return the compilation unit that was resolved by this task
10880 */
10881 CompilationUnit get resolvedUnit => _resolvedUnit;
10882
10883 @override
10884 String get taskDescription {
10885 Source librarySource = _libraryElement.source;
10886 if (librarySource == null) {
10887 return "resolve unit null source";
10888 }
10889 return "resolve unit ${librarySource.fullName}";
10890 }
10891
10892 @override
10893 accept(AnalysisTaskVisitor visitor) => visitor.visitResolveDartUnitTask(this);
10894
10895 @override
10896 void internalPerform() {
10897 TypeProvider typeProvider = _libraryElement.context.typeProvider;
10898 CompilationUnit unit = context.computeResolvableCompilationUnit(source);
10899 if (unit == null) {
10900 throw new AnalysisException(
10901 "Internal error: computeResolvableCompilationUnit returned a value wit hout a parsed Dart unit");
10902 }
10903 //
10904 // Resolve names in declarations.
10905 //
10906 new DeclarationResolver().resolve(unit, _find(_libraryElement, source));
10907 //
10908 // Resolve the type names.
10909 //
10910 RecordingErrorListener errorListener = new RecordingErrorListener();
10911 TypeResolverVisitor typeResolverVisitor = new TypeResolverVisitor(
10912 _libraryElement, source, typeProvider, errorListener);
10913 unit.accept(typeResolverVisitor);
10914 //
10915 // Resolve the rest of the structure
10916 //
10917 InheritanceManager inheritanceManager =
10918 new InheritanceManager(_libraryElement);
10919 ResolverVisitor resolverVisitor = new ResolverVisitor(
10920 _libraryElement, source, typeProvider, errorListener,
10921 inheritanceManager: inheritanceManager);
10922 unit.accept(resolverVisitor);
10923 //
10924 // Perform additional error checking.
10925 //
10926 PerformanceStatistics.errors.makeCurrentWhile(() {
10927 ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
10928 ErrorVerifier errorVerifier = new ErrorVerifier(
10929 errorReporter,
10930 _libraryElement,
10931 typeProvider,
10932 inheritanceManager,
10933 context.analysisOptions.enableSuperMixins);
10934 unit.accept(errorVerifier);
10935 // TODO(paulberry): as a temporary workaround for issue 21572,
10936 // ConstantVerifier is being run right after ConstantValueComputer, so we
10937 // don't need to run it here. Once issue 21572 is fixed, re-enable the
10938 // call to ConstantVerifier.
10939 // ConstantVerifier constantVerifier = new ConstantVerifier(errorReporter, _libraryElement, typeProvider);
10940 // unit.accept(constantVerifier);
10941 });
10942 //
10943 // Capture the results.
10944 //
10945 _resolvedUnit = unit;
10946 }
10947
10948 /**
10949 * Search the compilation units that are part of the given library and return the element
10950 * representing the compilation unit with the given source. Return `null` if t here is no
10951 * such compilation unit.
10952 *
10953 * @param libraryElement the element representing the library being searched t hrough
10954 * @param unitSource the source for the compilation unit whose element is to b e returned
10955 * @return the element representing the compilation unit
10956 */
10957 CompilationUnitElement _find(
10958 LibraryElement libraryElement, Source unitSource) {
10959 CompilationUnitElement element = libraryElement.definingCompilationUnit;
10960 if (element.source == unitSource) {
10961 return element;
10962 }
10963 for (CompilationUnitElement partElement in libraryElement.parts) {
10964 if (partElement.source == unitSource) {
10965 return partElement;
10966 }
10967 }
10968 return null;
10969 }
10970 }
10971
10972 /**
10973 * Instances of the class `ResolveHtmlTask` resolve a specific source as an HTML file.
10974 */
10975 class ResolveHtmlTask extends AnalysisTask {
10976 /**
10977 * The source to be resolved.
10978 */
10979 final Source source;
10980
10981 /**
10982 * The time at which the contents of the source were last modified.
10983 */
10984 final int modificationTime;
10985
10986 /**
10987 * The HTML unit to be resolved.
10988 */
10989 final ht.HtmlUnit _unit;
10990
10991 /**
10992 * The [HtmlUnit] that was resolved by this task.
10993 */
10994 ht.HtmlUnit _resolvedUnit;
10995
10996 /**
10997 * The element produced by resolving the source.
10998 */
10999 HtmlElement _element = null;
11000
11001 /**
11002 * The resolution errors that were discovered while resolving the source.
11003 */
11004 List<AnalysisError> _resolutionErrors = AnalysisError.NO_ERRORS;
11005
11006 /**
11007 * Initialize a newly created task to perform analysis within the given contex t.
11008 *
11009 * @param context the context in which the task is to be performed
11010 * @param source the source to be resolved
11011 * @param modificationTime the time at which the contents of the source were l ast modified
11012 * @param unit the HTML unit to be resolved
11013 */
11014 ResolveHtmlTask(InternalAnalysisContext context, this.source,
11015 this.modificationTime, this._unit)
11016 : super(context);
11017
11018 HtmlElement get element => _element;
11019
11020 List<AnalysisError> get resolutionErrors => _resolutionErrors;
11021
11022 /**
11023 * Return the [HtmlUnit] that was resolved by this task.
11024 *
11025 * @return the [HtmlUnit] that was resolved by this task
11026 */
11027 ht.HtmlUnit get resolvedUnit => _resolvedUnit;
11028
11029 @override
11030 String get taskDescription {
11031 if (source == null) {
11032 return "resolve as html null source";
11033 }
11034 return "resolve as html ${source.fullName}";
11035 }
11036
11037 @override
11038 accept(AnalysisTaskVisitor visitor) => visitor.visitResolveHtmlTask(this);
11039
11040 @override
11041 void internalPerform() {
11042 //
11043 // Build the standard HTML element.
11044 //
11045 HtmlUnitBuilder builder = new HtmlUnitBuilder(context);
11046 _element = builder.buildHtmlElement(source, _unit);
11047 RecordingErrorListener errorListener = builder.errorListener;
11048 //
11049 // Validate the directives
11050 //
11051 _unit.accept(new RecursiveXmlVisitor_ResolveHtmlTask_internalPerform(
11052 this, errorListener));
11053 //
11054 // Record all resolution errors.
11055 //
11056 _resolutionErrors = errorListener.getErrorsForSource(source);
11057 //
11058 // Remember the resolved unit.
11059 //
11060 _resolvedUnit = _unit;
11061 }
11062 }
11063
11064 /**
11065 * The priority of data in the cache in terms of the desirability of retaining
11066 * some specified data about a specified source.
11067 */
11068 class RetentionPriority extends Enum<RetentionPriority> {
11069 /**
11070 * A priority indicating that a given piece of data can be removed from the
11071 * cache without reservation.
11072 */
11073 static const RetentionPriority LOW = const RetentionPriority('LOW', 0);
11074
11075 /**
11076 * A priority indicating that a given piece of data should not be removed from
11077 * the cache unless there are no sources for which the corresponding data has
11078 * a lower priority. Currently used for data that is needed in order to finish
11079 * some outstanding analysis task.
11080 */
11081 static const RetentionPriority MEDIUM = const RetentionPriority('MEDIUM', 1);
11082
11083 /**
11084 * A priority indicating that a given piece of data should not be removed from
11085 * the cache. Currently used for data related to a priority source.
11086 */
11087 static const RetentionPriority HIGH = const RetentionPriority('HIGH', 2);
11088
11089 static const List<RetentionPriority> values = const [LOW, MEDIUM, HIGH];
11090
11091 const RetentionPriority(String name, int ordinal) : super(name, ordinal);
11092 }
11093
11094 /**
11095 * Instances of the class `ScanDartTask` scan a specific source as a Dart file.
11096 */
11097 class ScanDartTask extends AnalysisTask {
11098 /**
11099 * The source to be scanned.
11100 */
11101 final Source source;
11102
11103 /**
11104 * The contents of the source.
11105 */
11106 final String _content;
11107
11108 /**
11109 * The token stream that was produced by scanning the source.
11110 */
11111 Token _tokenStream;
11112
11113 /**
11114 * The line information that was produced.
11115 */
11116 LineInfo _lineInfo;
11117
11118 /**
11119 * The errors that were produced by scanning the source.
11120 */
11121 List<AnalysisError> _errors = AnalysisError.NO_ERRORS;
11122
11123 /**
11124 * Initialize a newly created task to perform analysis within the given contex t.
11125 *
11126 * @param context the context in which the task is to be performed
11127 * @param source the source to be parsed
11128 * @param content the contents of the source
11129 */
11130 ScanDartTask(InternalAnalysisContext context, this.source, this._content)
11131 : super(context);
11132
11133 /**
11134 * Return the errors that were produced by scanning the source, or `null` if t he task has
11135 * not yet been performed or if an exception occurred.
11136 *
11137 * @return the errors that were produced by scanning the source
11138 */
11139 List<AnalysisError> get errors => _errors;
11140
11141 /**
11142 * Return the line information that was produced, or `null` if the task has no t yet been
11143 * performed or if an exception occurred.
11144 *
11145 * @return the line information that was produced
11146 */
11147 LineInfo get lineInfo => _lineInfo;
11148
11149 @override
11150 String get taskDescription {
11151 if (source == null) {
11152 return "scan as dart null source";
11153 }
11154 return "scan as dart ${source.fullName}";
11155 }
11156
11157 /**
11158 * Return the token stream that was produced by scanning the source, or `null` if the task
11159 * has not yet been performed or if an exception occurred.
11160 *
11161 * @return the token stream that was produced by scanning the source
11162 */
11163 Token get tokenStream => _tokenStream;
11164
11165 @override
11166 accept(AnalysisTaskVisitor visitor) => visitor.visitScanDartTask(this);
11167
11168 @override
11169 void internalPerform() {
11170 PerformanceStatistics.scan.makeCurrentWhile(() {
11171 RecordingErrorListener errorListener = new RecordingErrorListener();
11172 try {
11173 Scanner scanner = new Scanner(
11174 source, new CharSequenceReader(_content), errorListener);
11175 scanner.preserveComments = context.analysisOptions.preserveComments;
11176 _tokenStream = scanner.tokenize();
11177 _lineInfo = new LineInfo(scanner.lineStarts);
11178 _errors = errorListener.getErrorsForSource(source);
11179 } catch (exception, stackTrace) {
11180 throw new AnalysisException(
11181 "Exception", new CaughtException(exception, stackTrace));
11182 }
11183 });
11184 }
11185 }
11186
11187 /**
11188 * An [AnalysisContext] that only contains sources for a Dart SDK.
11189 */
11190 class SdkAnalysisContext extends AnalysisContextImpl {
11191 @override
11192 AnalysisCache createCacheFromSourceFactory(SourceFactory factory) {
11193 if (factory == null) {
11194 return super.createCacheFromSourceFactory(factory);
11195 }
11196 DartSdk sdk = factory.dartSdk;
11197 if (sdk == null) {
11198 throw new IllegalArgumentException(
11199 "The source factory for an SDK analysis context must have a DartUriRes olver");
11200 }
11201 return new AnalysisCache(
11202 <CachePartition>[AnalysisEngine.instance.partitionManager.forSdk(sdk)]);
11203 }
11204 }
11205
11206 /**
11207 * A cache partition that contains all of the sources in the SDK.
11208 */
11209 class SdkCachePartition extends CachePartition {
11210 /**
11211 * Initialize a newly created partition. The [context] is the context that
11212 * owns this partition. The [maxCacheSize] is the maximum number of sources
11213 * for which AST structures should be kept in the cache.
11214 */
11215 SdkCachePartition(InternalAnalysisContext context, int maxCacheSize)
11216 : super(context, maxCacheSize, DefaultRetentionPolicy.POLICY);
11217
11218 @override
11219 bool contains(Source source) => source.isInSystemLibrary;
11220 }
11221
11222 /**
11223 * The information cached by an analysis context about an individual source, no
11224 * matter what kind of source it is.
11225 */
11226 abstract class SourceEntry {
11227 /**
11228 * The data descriptor representing the contents of the source.
11229 */
11230 static final DataDescriptor<String> CONTENT =
11231 new DataDescriptor<String>("SourceEntry.CONTENT");
11232
11233 /**
11234 * The data descriptor representing the errors resulting from reading the
11235 * source content.
11236 */
11237 static final DataDescriptor<List<AnalysisError>> CONTENT_ERRORS =
11238 new DataDescriptor<List<AnalysisError>>(
11239 "SourceEntry.CONTENT_ERRORS", AnalysisError.NO_ERRORS);
11240
11241 /**
11242 * The data descriptor representing the line information.
11243 */
11244 static final DataDescriptor<LineInfo> LINE_INFO =
11245 new DataDescriptor<LineInfo>("SourceEntry.LINE_INFO");
11246
11247 /**
11248 * The index of the flag indicating whether the source was explicitly added to
11249 * the context or whether the source was implicitly added because it was
11250 * referenced by another source.
11251 */
11252 static int _EXPLICITLY_ADDED_FLAG = 0;
11253
11254 /**
11255 * A table mapping data descriptors to a count of the number of times a value
11256 * was set when in a given state.
11257 */
11258 static final Map<DataDescriptor, Map<CacheState, int>> transitionMap =
11259 new HashMap<DataDescriptor, Map<CacheState, int>>();
11260
11261 /**
11262 * The most recent time at which the state of the source matched the state
11263 * represented by this entry.
11264 */
11265 int modificationTime = 0;
11266
11267 /**
11268 * The exception that caused one or more values to have a state of
11269 * [CacheState.ERROR].
11270 */
11271 CaughtException exception;
11272
11273 /**
11274 * A bit-encoding of boolean flags associated with this element.
11275 */
11276 int _flags = 0;
11277
11278 /**
11279 * A table mapping data descriptors to the cached results for those
11280 * descriptors.
11281 */
11282 Map<DataDescriptor, CachedResult> resultMap =
11283 new HashMap<DataDescriptor, CachedResult>();
11284
11285 /**
11286 * Return all of the errors associated with this entry.
11287 */
11288 List<AnalysisError> get allErrors {
11289 return getValue(CONTENT_ERRORS);
11290 }
11291
11292 /**
11293 * Get a list of all the library-independent descriptors for which values may
11294 * be stored in this SourceEntry.
11295 */
11296 List<DataDescriptor> get descriptors {
11297 return <DataDescriptor>[CONTENT, CONTENT_ERRORS, LINE_INFO];
11298 }
11299
11300 /**
11301 * Return `true` if the source was explicitly added to the context or `false`
11302 * if the source was implicitly added because it was referenced by another
11303 * source.
11304 */
11305 bool get explicitlyAdded => _getFlag(_EXPLICITLY_ADDED_FLAG);
11306
11307 /**
11308 * Set whether the source was explicitly added to the context to match the
11309 * [explicitlyAdded] flag.
11310 */
11311 void set explicitlyAdded(bool explicitlyAdded) {
11312 _setFlag(_EXPLICITLY_ADDED_FLAG, explicitlyAdded);
11313 }
11314
11315 /**
11316 * Return the kind of the source, or `null` if the kind is not currently
11317 * cached.
11318 */
11319 SourceKind get kind;
11320
11321 /**
11322 * Fix the state of the [exception] to match the current state of the entry.
11323 */
11324 void fixExceptionState() {
11325 if (hasErrorState()) {
11326 if (exception == null) {
11327 //
11328 // This code should never be reached, but is a fail-safe in case an
11329 // exception is not recorded when it should be.
11330 //
11331 String message = "State set to ERROR without setting an exception";
11332 exception = new CaughtException(new AnalysisException(message), null);
11333 }
11334 } else {
11335 exception = null;
11336 }
11337 }
11338
11339 /**
11340 * Return a textual representation of the difference between the [oldEntry]
11341 * and this entry. The difference is represented as a sequence of fields whose
11342 * value would change if the old entry were converted into the new entry.
11343 */
11344 String getDiff(SourceEntry oldEntry) {
11345 StringBuffer buffer = new StringBuffer();
11346 _writeDiffOn(buffer, oldEntry);
11347 return buffer.toString();
11348 }
11349
11350 /**
11351 * Return the state of the data represented by the given [descriptor].
11352 */
11353 CacheState getState(DataDescriptor descriptor) {
11354 if (!_isValidDescriptor(descriptor)) {
11355 throw new ArgumentError("Invalid descriptor: $descriptor");
11356 }
11357 CachedResult result = resultMap[descriptor];
11358 if (result == null) {
11359 return CacheState.INVALID;
11360 }
11361 return result.state;
11362 }
11363
11364 /**
11365 * Return the value of the data represented by the given [descriptor], or
11366 * `null` if the data represented by the descriptor is not valid.
11367 */
11368 /*<V>*/ dynamic /*V*/ getValue(DataDescriptor /*<V>*/ descriptor) {
11369 if (!_isValidDescriptor(descriptor)) {
11370 throw new ArgumentError("Invalid descriptor: $descriptor");
11371 }
11372 CachedResult result = resultMap[descriptor];
11373 if (result == null) {
11374 return descriptor.defaultValue;
11375 }
11376 return result.value;
11377 }
11378
11379 /**
11380 * Return `true` if the state of any data value is [CacheState.ERROR].
11381 */
11382 bool hasErrorState() {
11383 for (CachedResult result in resultMap.values) {
11384 if (result.state == CacheState.ERROR) {
11385 return true;
11386 }
11387 }
11388 return false;
11389 }
11390
11391 /**
11392 * Invalidate all of the information associated with this source.
11393 */
11394 void invalidateAllInformation() {
11395 setState(CONTENT, CacheState.INVALID);
11396 setState(CONTENT_ERRORS, CacheState.INVALID);
11397 setState(LINE_INFO, CacheState.INVALID);
11398 }
11399
11400 /**
11401 * Record that an [exception] occurred while attempting to get the contents of
11402 * the source represented by this entry. This will set the state of all
11403 * information, including any resolution-based information, as being in error.
11404 */
11405 void recordContentError(CaughtException exception) {
11406 setState(CONTENT, CacheState.ERROR);
11407 recordScanError(exception);
11408 }
11409
11410 /**
11411 * Record that an [exception] occurred while attempting to scan or parse the
11412 * entry represented by this entry. This will set the state of all
11413 * information, including any resolution-based information, as being in error.
11414 */
11415 void recordScanError(CaughtException exception) {
11416 this.exception = exception;
11417 setState(LINE_INFO, CacheState.ERROR);
11418 }
11419
11420 /**
11421 * Set the state of the data represented by the given [descriptor] to the
11422 * given [state].
11423 */
11424 void setState(DataDescriptor descriptor, CacheState state) {
11425 if (!_isValidDescriptor(descriptor)) {
11426 throw new ArgumentError("Invalid descriptor: $descriptor");
11427 }
11428 if (state == CacheState.VALID) {
11429 throw new ArgumentError("use setValue() to set the state to VALID");
11430 }
11431 _validateStateChange(descriptor, state);
11432 if (state == CacheState.INVALID) {
11433 resultMap.remove(descriptor);
11434 } else {
11435 CachedResult result =
11436 resultMap.putIfAbsent(descriptor, () => new CachedResult(descriptor));
11437 result.state = state;
11438 if (state != CacheState.IN_PROCESS) {
11439 //
11440 // If the state is in-process, we can leave the current value in the
11441 // cache for any 'get' methods to access.
11442 //
11443 result.value = descriptor.defaultValue;
11444 }
11445 }
11446 }
11447
11448 /**
11449 * Set the value of the data represented by the given [descriptor] to the
11450 * given [value].
11451 */
11452 void setValue(DataDescriptor /*<V>*/ descriptor, dynamic /*V*/ value) {
11453 if (!_isValidDescriptor(descriptor)) {
11454 throw new ArgumentError("Invalid descriptor: $descriptor");
11455 }
11456 _validateStateChange(descriptor, CacheState.VALID);
11457 CachedResult result =
11458 resultMap.putIfAbsent(descriptor, () => new CachedResult(descriptor));
11459 countTransition(descriptor, result);
11460 result.state = CacheState.VALID;
11461 result.value = value == null ? descriptor.defaultValue : value;
11462 }
11463
11464 @override
11465 String toString() {
11466 StringBuffer buffer = new StringBuffer();
11467 _writeOn(buffer);
11468 return buffer.toString();
11469 }
11470
11471 /**
11472 * Flush the value of the data described by the [descriptor].
11473 */
11474 void _flush(DataDescriptor descriptor) {
11475 CachedResult result = resultMap[descriptor];
11476 if (result != null && result.state == CacheState.VALID) {
11477 _validateStateChange(descriptor, CacheState.FLUSHED);
11478 result.state = CacheState.FLUSHED;
11479 result.value = descriptor.defaultValue;
11480 }
11481 }
11482
11483 /**
11484 * Return the value of the flag with the given [index].
11485 */
11486 bool _getFlag(int index) => BooleanArray.get(_flags, index);
11487
11488 /**
11489 * Return `true` if the [descriptor] is valid for this entry.
11490 */
11491 bool _isValidDescriptor(DataDescriptor descriptor) {
11492 return descriptor == CONTENT ||
11493 descriptor == CONTENT_ERRORS ||
11494 descriptor == LINE_INFO;
11495 }
11496
11497 /**
11498 * Set the value of the flag with the given [index] to the given [value].
11499 */
11500 void _setFlag(int index, bool value) {
11501 _flags = BooleanArray.set(_flags, index, value);
11502 }
11503
11504 /**
11505 * If the state of the value described by the given [descriptor] is changing
11506 * from ERROR to anything else, capture the information. This is an attempt to
11507 * discover the underlying cause of a long-standing bug.
11508 */
11509 void _validateStateChange(DataDescriptor descriptor, CacheState newState) {
11510 // TODO(brianwilkerson) Decide whether we still want to capture this data.
11511 // if (descriptor != CONTENT) {
11512 // return;
11513 // }
11514 // CachedResult result = resultMap[CONTENT];
11515 // if (result != null && result.state == CacheState.ERROR) {
11516 // String message =
11517 // "contentState changing from ${result.state} to $newState";
11518 // InstrumentationBuilder builder =
11519 // Instrumentation.builder2("SourceEntry-validateStateChange");
11520 // builder.data3("message", message);
11521 // //builder.data("source", source.getFullName());
11522 // builder.record(new CaughtException(new AnalysisException(message), null) );
11523 // builder.log();
11524 // }
11525 }
11526
11527 /**
11528 * Write a textual representation of the difference between the [oldEntry] and
11529 * this entry to the given string [buffer]. Return `true` if some difference
11530 * was written.
11531 */
11532 bool _writeDiffOn(StringBuffer buffer, SourceEntry oldEntry) {
11533 bool needsSeparator = false;
11534 CaughtException oldException = oldEntry.exception;
11535 if (!identical(oldException, exception)) {
11536 buffer.write("exception = ");
11537 buffer.write(oldException.runtimeType);
11538 buffer.write(" -> ");
11539 buffer.write(exception.runtimeType);
11540 needsSeparator = true;
11541 }
11542 int oldModificationTime = oldEntry.modificationTime;
11543 if (oldModificationTime != modificationTime) {
11544 if (needsSeparator) {
11545 buffer.write("; ");
11546 }
11547 buffer.write("time = ");
11548 buffer.write(oldModificationTime);
11549 buffer.write(" -> ");
11550 buffer.write(modificationTime);
11551 needsSeparator = true;
11552 }
11553 needsSeparator =
11554 _writeStateDiffOn(buffer, needsSeparator, "content", CONTENT, oldEntry);
11555 needsSeparator = _writeStateDiffOn(
11556 buffer, needsSeparator, "contentErrors", CONTENT_ERRORS, oldEntry);
11557 needsSeparator = _writeStateDiffOn(
11558 buffer, needsSeparator, "lineInfo", LINE_INFO, oldEntry);
11559 return needsSeparator;
11560 }
11561
11562 /**
11563 * Write a textual representation of this entry to the given [buffer]. The
11564 * result should only be used for debugging purposes.
11565 */
11566 void _writeOn(StringBuffer buffer) {
11567 buffer.write("time = ");
11568 buffer.write(modificationTime);
11569 _writeStateOn(buffer, "content", CONTENT);
11570 _writeStateOn(buffer, "contentErrors", CONTENT_ERRORS);
11571 _writeStateOn(buffer, "lineInfo", LINE_INFO);
11572 }
11573
11574 /**
11575 * Write a textual representation of the difference between the state of the
11576 * value described by the given [descriptor] between the [oldEntry] and this
11577 * entry to the given [buffer]. Return `true` if some difference was written.
11578 */
11579 bool _writeStateDiffOn(StringBuffer buffer, bool needsSeparator, String label,
11580 DataDescriptor descriptor, SourceEntry oldEntry) {
11581 CacheState oldState = oldEntry.getState(descriptor);
11582 CacheState newState = getState(descriptor);
11583 if (oldState != newState) {
11584 if (needsSeparator) {
11585 buffer.write("; ");
11586 }
11587 buffer.write(label);
11588 buffer.write(" = ");
11589 buffer.write(oldState);
11590 buffer.write(" -> ");
11591 buffer.write(newState);
11592 return true;
11593 }
11594 return needsSeparator;
11595 }
11596
11597 /**
11598 * Write a textual representation of the state of the value described by the
11599 * given [descriptor] to the given bugger, prefixed by the given [label] to
11600 * the given [buffer].
11601 */
11602 void _writeStateOn(
11603 StringBuffer buffer, String label, DataDescriptor descriptor) {
11604 CachedResult result = resultMap[descriptor];
11605 buffer.write("; ");
11606 buffer.write(label);
11607 buffer.write(" = ");
11608 buffer.write(result == null ? CacheState.INVALID : result.state);
11609 }
11610
11611 /**
11612 * Increment the count of the number of times that data represented by the
11613 * given [descriptor] was transitioned from the current state (as found in the
11614 * given [result] to a valid state.
11615 */
11616 static void countTransition(DataDescriptor descriptor, CachedResult result) {
11617 Map<CacheState, int> countMap = transitionMap.putIfAbsent(
11618 descriptor, () => new HashMap<CacheState, int>());
11619 int count = countMap[result.state];
11620 countMap[result.state] = count == null ? 1 : count + 1;
11621 }
11622 }
11623
11624 /**
11625 * The priority levels used to return sources in an optimal order. A smaller
11626 * ordinal value equates to a higher priority.
11627 */
11628 class SourcePriority extends Enum<SourcePriority> {
11629 /**
11630 * Used for a Dart source that is known to be a part contained in a library
11631 * that was recently resolved. These parts are given a higher priority because
11632 * there is a high probability that their AST structure is still in the cache
11633 * and therefore would not need to be re-created.
11634 */
11635 static const SourcePriority PRIORITY_PART =
11636 const SourcePriority('PRIORITY_PART', 0);
11637
11638 /**
11639 * Used for a Dart source that is known to be a library.
11640 */
11641 static const SourcePriority LIBRARY = const SourcePriority('LIBRARY', 1);
11642
11643 /**
11644 * Used for a Dart source whose kind is unknown.
11645 */
11646 static const SourcePriority UNKNOWN = const SourcePriority('UNKNOWN', 2);
11647
11648 /**
11649 * Used for a Dart source that is known to be a part but whose library has not
11650 * yet been resolved.
11651 */
11652 static const SourcePriority NORMAL_PART =
11653 const SourcePriority('NORMAL_PART', 3);
11654
11655 /**
11656 * Used for an HTML source.
11657 */
11658 static const SourcePriority HTML = const SourcePriority('HTML', 4);
11659
11660 static const List<SourcePriority> values = const [
11661 PRIORITY_PART,
11662 LIBRARY,
11663 UNKNOWN,
11664 NORMAL_PART,
11665 HTML
11666 ];
11667
11668 const SourcePriority(String name, int ordinal) : super(name, ordinal);
11669 }
11670
11671 /**
11672 * [SourcesChangedEvent] indicates which sources have been added, removed,
11673 * or whose contents have changed.
11674 */
11675 class SourcesChangedEvent {
11676 /**
11677 * The internal representation of what has changed. Clients should not access
11678 * this field directly.
11679 */
11680 final ChangeSet _changeSet;
11681
11682 /**
11683 * Construct an instance representing the given changes.
11684 */
11685 SourcesChangedEvent(ChangeSet changeSet) : _changeSet = changeSet;
11686
11687 /**
11688 * Construct an instance representing a source content change.
11689 */
11690 factory SourcesChangedEvent.changedContent(Source source, String contents) {
11691 ChangeSet changeSet = new ChangeSet();
11692 changeSet.changedContent(source, contents);
11693 return new SourcesChangedEvent(changeSet);
11694 }
11695
11696 /**
11697 * Construct an instance representing a source content change.
11698 */
11699 factory SourcesChangedEvent.changedRange(Source source, String contents,
11700 int offset, int oldLength, int newLength) {
11701 ChangeSet changeSet = new ChangeSet();
11702 changeSet.changedRange(source, contents, offset, oldLength, newLength);
11703 return new SourcesChangedEvent(changeSet);
11704 }
11705
11706 /**
11707 * Return the collection of sources for which content has changed.
11708 */
11709 Iterable<Source> get changedSources {
11710 List<Source> changedSources = new List.from(_changeSet.changedSources);
11711 changedSources.addAll(_changeSet.changedContents.keys);
11712 changedSources.addAll(_changeSet.changedRanges.keys);
11713 return changedSources;
11714 }
11715
11716 /**
11717 * Return `true` if any sources were added.
11718 */
11719 bool get wereSourcesAdded => _changeSet.addedSources.length > 0;
11720
11721 /**
11722 * Return `true` if any sources were removed or deleted.
11723 */
11724 bool get wereSourcesRemovedOrDeleted =>
11725 _changeSet.removedSources.length > 0 ||
11726 _changeSet.removedContainers.length > 0 ||
11727 _changeSet.deletedSources.length > 0;
11728 }
11729
11730 /**
11731 * Analysis data for which we have a modification time.
11732 */
11733 class TimestampedData<E> {
11734 /**
11735 * The modification time of the source from which the data was created.
11736 */
11737 final int modificationTime;
11738
11739 /**
11740 * The data that was created from the source.
11741 */
11742 final E data;
11743
11744 /**
11745 * Initialize a newly created holder to associate the given [data] with the
11746 * given [modificationTime].
11747 */
11748 TimestampedData(this.modificationTime, this.data);
11749 }
11750
11751 /**
11752 * A cache partition that contains all sources not contained in other
11753 * partitions.
11754 */
11755 class UniversalCachePartition extends CachePartition {
11756 /**
11757 * Initialize a newly created partition. The [context] is the context that
11758 * owns this partition. The [maxCacheSize] is the maximum number of sources
11759 * for which AST structures should be kept in the cache. The [retentionPolicy]
11760 * is the policy used to determine which pieces of data to remove from the
11761 * cache.
11762 */
11763 UniversalCachePartition(InternalAnalysisContext context, int maxCacheSize,
11764 CacheRetentionPolicy retentionPolicy)
11765 : super(context, maxCacheSize, retentionPolicy);
11766
11767 @override
11768 bool contains(Source source) => true;
11769 }
11770
11771 /**
11772 * The unique instances of the class `WaitForAsyncTask` represents a state in wh ich there is
11773 * no analysis work that can be done until some asynchronous task (such as IO) h as completed, but
11774 * where analysis is not yet complete.
11775 */
11776 class WaitForAsyncTask extends AnalysisTask {
11777 /**
11778 * The unique instance of this class.
11779 */
11780 static WaitForAsyncTask _UniqueInstance = new WaitForAsyncTask();
11781
11782 /**
11783 * Return the unique instance of this class.
11784 *
11785 * @return the unique instance of this class
11786 */
11787 static WaitForAsyncTask get instance => _UniqueInstance;
11788
11789 /**
11790 * Prevent the creation of instances of this class.
11791 */
11792 WaitForAsyncTask() : super(null);
11793
11794 @override
11795 String get taskDescription => "Waiting for async analysis";
11796
11797 @override
11798 accept(AnalysisTaskVisitor visitor) => null;
11799
11800 @override
11801 void internalPerform() {
11802 // There is no work to be done.
11803 }
11804 }
11805
11806 /**
11807 * An object that manages a list of sources that need to have analysis work
11808 * performed on them.
11809 */
11810 class WorkManager {
11811 /**
11812 * A list containing the various queues is priority order.
11813 */
11814 List<List<Source>> _workQueues;
11815
11816 /**
11817 * Initialize a newly created manager to have no work queued up.
11818 */
11819 WorkManager() {
11820 int queueCount = SourcePriority.values.length;
11821 _workQueues = new List<List<Source>>(queueCount);
11822 for (int i = 0; i < queueCount; i++) {
11823 _workQueues[i] = new List<Source>();
11824 }
11825 }
11826
11827 /**
11828 * Record that the given [source] needs to be analyzed. The [priority] level
11829 * is used to control when the source will be analyzed with respect to other
11830 * sources. If the source was previously added then it's priority is updated.
11831 * If it was previously added with the same priority then it's position in the
11832 * queue is unchanged.
11833 */
11834 void add(Source source, SourcePriority priority) {
11835 int queueCount = _workQueues.length;
11836 int ordinal = priority.ordinal;
11837 for (int i = 0; i < queueCount; i++) {
11838 List<Source> queue = _workQueues[i];
11839 if (i == ordinal) {
11840 if (!queue.contains(source)) {
11841 queue.add(source);
11842 }
11843 } else {
11844 queue.remove(source);
11845 }
11846 }
11847 }
11848
11849 /**
11850 * Record that the given [source] needs to be analyzed. The [priority] level
11851 * is used to control when the source will be analyzed with respect to other
11852 * sources. If the source was previously added then it's priority is updated.
11853 * In either case, it will be analyzed before other sources of the same
11854 * priority.
11855 */
11856 void addFirst(Source source, SourcePriority priority) {
11857 int queueCount = _workQueues.length;
11858 int ordinal = priority.ordinal;
11859 for (int i = 0; i < queueCount; i++) {
11860 List<Source> queue = _workQueues[i];
11861 if (i == ordinal) {
11862 queue.remove(source);
11863 queue.insert(0, source);
11864 } else {
11865 queue.remove(source);
11866 }
11867 }
11868 }
11869
11870 /**
11871 * Return an iterator that can be used to access the sources to be analyzed in
11872 * the order in which they should be analyzed.
11873 *
11874 * <b>Note:</b> As with other iterators, no sources can be added or removed
11875 * from this work manager while the iterator is being used. Unlike some
11876 * implementations, however, the iterator will not detect when this
11877 * requirement has been violated; it might work correctly, it might return the
11878 * wrong source, or it might throw an exception.
11879 */
11880 WorkManager_WorkIterator iterator() => new WorkManager_WorkIterator(this);
11881
11882 /**
11883 * Record that the given source is fully analyzed.
11884 */
11885 void remove(Source source) {
11886 int queueCount = _workQueues.length;
11887 for (int i = 0; i < queueCount; i++) {
11888 _workQueues[i].remove(source);
11889 }
11890 }
11891
11892 @override
11893 String toString() {
11894 StringBuffer buffer = new StringBuffer();
11895 List<SourcePriority> priorities = SourcePriority.values;
11896 bool needsSeparator = false;
11897 int queueCount = _workQueues.length;
11898 for (int i = 0; i < queueCount; i++) {
11899 List<Source> queue = _workQueues[i];
11900 if (!queue.isEmpty) {
11901 if (needsSeparator) {
11902 buffer.write("; ");
11903 }
11904 buffer.write(priorities[i]);
11905 buffer.write(": ");
11906 int queueSize = queue.length;
11907 for (int j = 0; j < queueSize; j++) {
11908 if (j > 0) {
11909 buffer.write(", ");
11910 }
11911 buffer.write(queue[j].fullName);
11912 }
11913 needsSeparator = true;
11914 }
11915 }
11916 return buffer.toString();
11917 }
11918 }
11919
11920 /**
11921 * An iterator that returns the sources in a work manager in the order in which
11922 * they are to be analyzed.
11923 */
11924 class WorkManager_WorkIterator {
11925 final WorkManager _manager;
11926
11927 /**
11928 * The index of the work queue through which we are currently iterating.
11929 */
11930 int _queueIndex = 0;
11931
11932 /**
11933 * The index of the next element of the work queue to be returned.
11934 */
11935 int _index = -1;
11936
11937 /**
11938 * Initialize a newly created iterator to be ready to return the first element
11939 * in the iteration.
11940 */
11941 WorkManager_WorkIterator(this._manager) {
11942 _advance();
11943 }
11944
11945 /**
11946 * Return `true` if there is another [Source] available for processing.
11947 */
11948 bool get hasNext => _queueIndex < _manager._workQueues.length;
11949
11950 /**
11951 * Return the next [Source] available for processing and advance so that the
11952 * returned source will not be returned again.
11953 */
11954 Source next() {
11955 if (!hasNext) {
11956 throw new NoSuchElementException();
11957 }
11958 Source source = _manager._workQueues[_queueIndex][_index];
11959 _advance();
11960 return source;
11961 }
11962
11963 /**
11964 * Increment the [index] and [queueIndex] so that they are either indicating
11965 * the next source to be returned or are indicating that there are no more
11966 * sources to be returned.
11967 */
11968 void _advance() {
11969 _index++;
11970 if (_index >= _manager._workQueues[_queueIndex].length) {
11971 _index = 0;
11972 _queueIndex++;
11973 while (_queueIndex < _manager._workQueues.length &&
11974 _manager._workQueues[_queueIndex].isEmpty) {
11975 _queueIndex++;
11976 }
11977 }
11978 }
11979 }
11980
11981 /**
11982 * A helper class used to create futures for AnalysisContextImpl. Using a helper
11983 * class allows us to preserve the generic parameter T.
11984 */
11985 class _AnalysisFutureHelper<T> {
11986 final AnalysisContextImpl _context;
11987
11988 _AnalysisFutureHelper(this._context);
11989
11990 /**
11991 * Return a future that will be completed with the result of calling
11992 * [computeValue]. If [computeValue] returns non-null, the future will be
11993 * completed immediately with the resulting value. If it returns null, then
11994 * it will be re-executed in the future, after the next time the cached
11995 * information for [source] has changed. If [computeValue] throws an
11996 * exception, the future will fail with that exception.
11997 *
11998 * If the [computeValue] still returns null after there is no further
11999 * analysis to be done for [source], then the future will be completed with
12000 * the error AnalysisNotScheduledError.
12001 *
12002 * Since [computeValue] will be called while the state of analysis is being
12003 * updated, it should be free of side effects so that it doesn't cause
12004 * reentrant changes to the analysis state.
12005 */
12006 CancelableFuture<T> computeAsync(
12007 Source source, T computeValue(SourceEntry sourceEntry)) {
12008 if (_context.isDisposed) {
12009 // No further analysis is expected, so return a future that completes
12010 // immediately with AnalysisNotScheduledError.
12011 return new CancelableFuture.error(new AnalysisNotScheduledError());
12012 }
12013 SourceEntry sourceEntry = _context.getReadableSourceEntryOrNull(source);
12014 if (sourceEntry == null) {
12015 return new CancelableFuture.error(new AnalysisNotScheduledError());
12016 }
12017 PendingFuture pendingFuture =
12018 new PendingFuture<T>(_context, source, computeValue);
12019 if (!pendingFuture.evaluate(sourceEntry)) {
12020 _context._pendingFutureSources
12021 .putIfAbsent(source, () => <PendingFuture>[])
12022 .add(pendingFuture);
12023 }
12024 return pendingFuture.future;
12025 }
12026 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698