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

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

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

Powered by Google App Engine
This is Rietveld 408576698