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

Side by Side Diff: packages/analyzer/lib/src/generated/engine.dart

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

Powered by Google App Engine
This is Rietveld 408576698