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

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

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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 analyzer.src.context.context; 5 library analyzer.src.context.context;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 9
10 import 'package:analyzer/dart/ast/ast.dart';
11 import 'package:analyzer/dart/element/element.dart';
12 import 'package:analyzer/error/error.dart';
13 import 'package:analyzer/exception/exception.dart';
10 import 'package:analyzer/instrumentation/instrumentation.dart'; 14 import 'package:analyzer/instrumentation/instrumentation.dart';
15 import 'package:analyzer/plugin/resolver_provider.dart';
11 import 'package:analyzer/plugin/task.dart'; 16 import 'package:analyzer/plugin/task.dart';
12 import 'package:analyzer/src/cancelable_future.dart'; 17 import 'package:analyzer/src/cancelable_future.dart';
18 import 'package:analyzer/src/context/builder.dart' show EmbedderYamlLocator;
13 import 'package:analyzer/src/context/cache.dart'; 19 import 'package:analyzer/src/context/cache.dart';
14 import 'package:analyzer/src/generated/ast.dart'; 20 import 'package:analyzer/src/dart/element/element.dart';
15 import 'package:analyzer/src/generated/constant.dart'; 21 import 'package:analyzer/src/generated/constant.dart';
16 import 'package:analyzer/src/generated/element.dart'; 22 import 'package:analyzer/src/generated/engine.dart';
17 import 'package:analyzer/src/generated/engine.dart'
18 hide
19 AnalysisCache,
20 CachePartition,
21 SdkCachePartition,
22 UniversalCachePartition,
23 WorkManager;
24 import 'package:analyzer/src/generated/error.dart';
25 import 'package:analyzer/src/generated/html.dart' as ht show HtmlUnit;
26 import 'package:analyzer/src/generated/incremental_resolver.dart'; 23 import 'package:analyzer/src/generated/incremental_resolver.dart';
27 import 'package:analyzer/src/generated/java_core.dart';
28 import 'package:analyzer/src/generated/java_engine.dart';
29 import 'package:analyzer/src/generated/resolver.dart'; 24 import 'package:analyzer/src/generated/resolver.dart';
30 import 'package:analyzer/src/generated/sdk.dart' show DartSdk; 25 import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
31 import 'package:analyzer/src/generated/source.dart'; 26 import 'package:analyzer/src/generated/source.dart';
32 import 'package:analyzer/src/generated/utilities_collection.dart'; 27 import 'package:analyzer/src/generated/utilities_collection.dart';
33 import 'package:analyzer/src/task/dart.dart'; 28 import 'package:analyzer/src/task/dart.dart';
34 import 'package:analyzer/src/task/dart_work_manager.dart'; 29 import 'package:analyzer/src/task/dart_work_manager.dart';
35 import 'package:analyzer/src/task/driver.dart'; 30 import 'package:analyzer/src/task/driver.dart';
36 import 'package:analyzer/src/task/incremental_element_builder.dart'; 31 import 'package:analyzer/src/task/incremental_element_builder.dart';
37 import 'package:analyzer/src/task/manager.dart'; 32 import 'package:analyzer/src/task/manager.dart';
33 import 'package:analyzer/src/task/model.dart';
38 import 'package:analyzer/task/dart.dart'; 34 import 'package:analyzer/task/dart.dart';
39 import 'package:analyzer/task/general.dart'; 35 import 'package:analyzer/task/general.dart';
40 import 'package:analyzer/task/html.dart'; 36 import 'package:analyzer/task/html.dart';
41 import 'package:analyzer/task/model.dart'; 37 import 'package:analyzer/task/model.dart';
42 import 'package:html/dom.dart' show Document; 38 import 'package:html/dom.dart' show Document;
43 39
44 /** 40 /**
41 * The descriptor used to associate exclude patterns with an analysis context in
42 * configuration data.
43 */
44 final ListResultDescriptor<String> CONTEXT_EXCLUDES =
45 new ListResultDescriptorImpl('CONTEXT_EXCLUDES', const <String>[]);
46
47 /**
45 * Type of callback functions used by PendingFuture. Functions of this type 48 * Type of callback functions used by PendingFuture. Functions of this type
46 * should perform a computation based on the data in [entry] and return it. If 49 * should perform a computation based on the data in [entry] and return it. If
47 * the computation can't be performed yet because more analysis is needed, 50 * the computation can't be performed yet because more analysis is needed,
48 * `null` should be returned. 51 * `null` should be returned.
49 * 52 *
50 * The function may also throw an exception, in which case the corresponding 53 * The function may also throw an exception, in which case the corresponding
51 * future will be completed with failure. 54 * future will be completed with failure.
52 * 55 *
53 * Because this function is called while the state of analysis is being updated, 56 * Because this function is called while the state of analysis is being updated,
54 * it should be free of side effects so that it doesn't cause reentrant changes 57 * it should be free of side effects so that it doesn't cause reentrant changes
55 * to the analysis state. 58 * to the analysis state.
56 */ 59 */
57 typedef T PendingFutureComputer<T>(CacheEntry entry); 60 typedef T PendingFutureComputer<T>(CacheEntry entry);
58 61
59 /** 62 /**
60 * An [AnalysisContext] in which analysis can be performed. 63 * An [AnalysisContext] in which analysis can be performed.
61 */ 64 */
62 class AnalysisContextImpl implements InternalAnalysisContext { 65 class AnalysisContextImpl implements InternalAnalysisContext {
63 /** 66 /**
64 * The next context identifier. 67 * The next context identifier.
65 */ 68 */
66 static int _NEXT_ID = 0; 69 static int _NEXT_ID = 0;
67 70
68 /** 71 /**
69 * The unique identifier of this context. 72 * The unique identifier of this context.
70 */ 73 */
71 final int _id = _NEXT_ID++; 74 final int _id = _NEXT_ID++;
72 75
73 /** 76 /**
77 * The flag that is `true` if the context is being analyzed.
78 */
79 bool _isActive = false;
80
81 /**
74 * A client-provided name used to identify this context, or `null` if the 82 * A client-provided name used to identify this context, or `null` if the
75 * client has not provided a name. 83 * client has not provided a name.
76 */ 84 */
85 @override
77 String name; 86 String name;
78 87
79 /** 88 /**
80 * The set of analysis options controlling the behavior of this context. 89 * The set of analysis options controlling the behavior of this context.
81 */ 90 */
82 AnalysisOptionsImpl _options = new AnalysisOptionsImpl(); 91 AnalysisOptionsImpl _options = new AnalysisOptionsImpl();
83 92
84 /** 93 /**
94 * The embedder yaml locator for this context.
95 */
96 @deprecated
97 EmbedderYamlLocator _embedderYamlLocator = new EmbedderYamlLocator(null);
98
99 /**
85 * A flag indicating whether this context is disposed. 100 * A flag indicating whether this context is disposed.
86 */ 101 */
87 bool _disposed = false; 102 bool _disposed = false;
88 103
89 /** 104 /**
90 * A cache of content used to override the default content of a source. 105 * A cache of content used to override the default content of a source.
91 */ 106 */
92 ContentCache _contentCache = new ContentCache(); 107 ContentCache _contentCache = new ContentCache();
93 108
94 /** 109 /**
(...skipping 12 matching lines...) Expand all
107 * contexts. 122 * contexts.
108 */ 123 */
109 CachePartition _privatePartition; 124 CachePartition _privatePartition;
110 125
111 /** 126 /**
112 * The cache in which information about the results associated with targets 127 * The cache in which information about the results associated with targets
113 * are stored. 128 * are stored.
114 */ 129 */
115 AnalysisCache _cache; 130 AnalysisCache _cache;
116 131
132 @override
133 final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
134 new ReentrantSynchronousStream<InvalidatedResult>();
135
136 ReentrantSynchronousStreamSubscription onResultInvalidatedSubscription = null;
137
117 /** 138 /**
118 * Configuration data associated with this context. 139 * Configuration data associated with this context.
119 */ 140 */
120 final HashMap<ResultDescriptor, Object> _configurationData = 141 final HashMap<ResultDescriptor, Object> _configurationData =
121 new HashMap<ResultDescriptor, Object>(); 142 new HashMap<ResultDescriptor, Object>();
122 143
123 /** 144 /**
124 * The task manager used to manage the tasks used to analyze code. 145 * The task manager used to manage the tasks used to analyze code.
125 */ 146 */
126 TaskManager _taskManager; 147 TaskManager _taskManager;
127 148
128 /** 149 /**
129 * A list of all [WorkManager]s used by this context. 150 * A list of all [WorkManager]s used by this context.
130 */ 151 */
152 @override
131 final List<WorkManager> workManagers = <WorkManager>[]; 153 final List<WorkManager> workManagers = <WorkManager>[];
132 154
133 /** 155 /**
134 * The [DartWorkManager] instance that performs Dart specific scheduling. 156 * The [DartWorkManager] instance that performs Dart specific scheduling.
135 */ 157 */
136 DartWorkManager dartWorkManager; 158 DartWorkManager dartWorkManager;
137 159
138 /** 160 /**
139 * The analysis driver used to perform analysis. 161 * The analysis driver used to perform analysis.
140 */ 162 */
141 AnalysisDriver driver; 163 AnalysisDriver driver;
142 164
143 /** 165 /**
144 * A list containing sources for which data should not be flushed. 166 * A list containing sources for which data should not be flushed.
145 */ 167 */
146 List<Source> _priorityOrder = <Source>[]; 168 List<Source> _priorityOrder = <Source>[];
147 169
170 CacheConsistencyValidatorImpl _cacheConsistencyValidator;
171
148 /** 172 /**
149 * A map from all sources for which there are futures pending to a list of 173 * A map from all sources for which there are futures pending to a list of
150 * the corresponding PendingFuture objects. These sources will be analyzed 174 * the corresponding PendingFuture objects. These sources will be analyzed
151 * in the same way as priority sources, except with higher priority. 175 * in the same way as priority sources, except with higher priority.
152 */ 176 */
153 HashMap<AnalysisTarget, List<PendingFuture>> _pendingFutureTargets = 177 HashMap<AnalysisTarget, List<PendingFuture>> _pendingFutureTargets =
154 new HashMap<AnalysisTarget, List<PendingFuture>>(); 178 new HashMap<AnalysisTarget, List<PendingFuture>>();
155 179
156 /** 180 /**
157 * A table mapping sources to the change notices that are waiting to be 181 * A table mapping sources to the change notices that are waiting to be
(...skipping 22 matching lines...) Expand all
180 * not) being implicitly analyzed. 204 * not) being implicitly analyzed.
181 */ 205 */
182 StreamController<ImplicitAnalysisEvent> _implicitAnalysisEventsController; 206 StreamController<ImplicitAnalysisEvent> _implicitAnalysisEventsController;
183 207
184 /** 208 /**
185 * The listeners that are to be notified when various analysis results are 209 * The listeners that are to be notified when various analysis results are
186 * produced in this context. 210 * produced in this context.
187 */ 211 */
188 List<AnalysisListener> _listeners = new List<AnalysisListener>(); 212 List<AnalysisListener> _listeners = new List<AnalysisListener>();
189 213
214 @override
215 ResultProvider resultProvider;
216
217 /**
218 * The map of [ResultChangedEvent] controllers.
219 */
220 final Map<ResultDescriptor, StreamController<ResultChangedEvent>>
221 _resultChangedControllers =
222 <ResultDescriptor, StreamController<ResultChangedEvent>>{};
223
190 /** 224 /**
191 * The most recently incrementally resolved source, or `null` when it was 225 * The most recently incrementally resolved source, or `null` when it was
192 * already validated, or the most recent change was not incrementally resolved . 226 * already validated, or the most recent change was not incrementally resolved .
193 */ 227 */
194 Source incrementalResolutionValidation_lastUnitSource; 228 Source incrementalResolutionValidation_lastUnitSource;
195 229
196 /** 230 /**
197 * The most recently incrementally resolved library source, or `null` when it 231 * The most recently incrementally resolved library source, or `null` when it
198 * was already validated, or the most recent change was not incrementally 232 * was already validated, or the most recent change was not incrementally
199 * resolved. 233 * resolved.
200 */ 234 */
201 Source incrementalResolutionValidation_lastLibrarySource; 235 Source incrementalResolutionValidation_lastLibrarySource;
202 236
203 /** 237 /**
204 * The result of incremental resolution result of 238 * The result of incremental resolution result of
205 * [incrementalResolutionValidation_lastSource]. 239 * [incrementalResolutionValidation_lastUnitSource].
206 */ 240 */
207 CompilationUnit incrementalResolutionValidation_lastUnit; 241 CompilationUnit incrementalResolutionValidation_lastUnit;
208 242
209 /** 243 @override
210 * A factory to override how the [ResolverVisitor] is created. 244 ResolverProvider fileResolverProvider;
211 */
212 ResolverVisitorFactory resolverVisitorFactory;
213
214 /**
215 * A factory to override how the [TypeResolverVisitor] is created.
216 */
217 TypeResolverVisitorFactory typeResolverVisitorFactory;
218
219 /**
220 * A factory to override how [LibraryResolver] is created.
221 */
222 LibraryResolverFactory libraryResolverFactory;
223 245
224 /** 246 /**
225 * Initialize a newly created analysis context. 247 * Initialize a newly created analysis context.
226 */ 248 */
227 AnalysisContextImpl() { 249 AnalysisContextImpl() {
228 _privatePartition = new UniversalCachePartition(this); 250 _privatePartition = new UniversalCachePartition(this);
229 _cache = createCacheFromSourceFactory(null); 251 _cache = createCacheFromSourceFactory(null);
230 _taskManager = AnalysisEngine.instance.taskManager; 252 _taskManager = AnalysisEngine.instance.taskManager;
231 for (WorkManagerFactory factory 253 for (WorkManagerFactory factory
232 in AnalysisEngine.instance.enginePlugin.workManagerFactories) { 254 in AnalysisEngine.instance.enginePlugin.workManagerFactories) {
(...skipping 23 matching lines...) Expand all
256 bool needsRecompute = this._options.analyzeFunctionBodiesPredicate != 278 bool needsRecompute = this._options.analyzeFunctionBodiesPredicate !=
257 options.analyzeFunctionBodiesPredicate || 279 options.analyzeFunctionBodiesPredicate ||
258 this._options.generateImplicitErrors != 280 this._options.generateImplicitErrors !=
259 options.generateImplicitErrors || 281 options.generateImplicitErrors ||
260 this._options.generateSdkErrors != options.generateSdkErrors || 282 this._options.generateSdkErrors != options.generateSdkErrors ||
261 this._options.dart2jsHint != options.dart2jsHint || 283 this._options.dart2jsHint != options.dart2jsHint ||
262 (this._options.hint && !options.hint) || 284 (this._options.hint && !options.hint) ||
263 (this._options.lint && !options.lint) || 285 (this._options.lint && !options.lint) ||
264 this._options.preserveComments != options.preserveComments || 286 this._options.preserveComments != options.preserveComments ||
265 this._options.strongMode != options.strongMode || 287 this._options.strongMode != options.strongMode ||
288 this._options.enableAssertInitializer !=
289 options.enableAssertInitializer ||
290 this._options.enableAssertMessage != options.enableAssertMessage ||
291 this._options.enableInitializingFormalAccess !=
292 options.enableInitializingFormalAccess ||
293 ((options is AnalysisOptionsImpl)
294 ? this._options.strongModeHints != options.strongModeHints
295 : false) ||
296 ((options is AnalysisOptionsImpl)
297 ? this._options.implicitCasts != options.implicitCasts
298 : false) ||
299 ((options is AnalysisOptionsImpl)
300 ? this._options.nonnullableTypes != options.nonnullableTypes
301 : false) ||
302 ((options is AnalysisOptionsImpl)
303 ? this._options.implicitDynamic != options.implicitDynamic
304 : false) ||
266 this._options.enableStrictCallChecks != 305 this._options.enableStrictCallChecks !=
267 options.enableStrictCallChecks || 306 options.enableStrictCallChecks ||
307 this._options.enableGenericMethods != options.enableGenericMethods ||
268 this._options.enableSuperMixins != options.enableSuperMixins; 308 this._options.enableSuperMixins != options.enableSuperMixins;
269 int cacheSize = options.cacheSize; 309 int cacheSize = options.cacheSize;
270 if (this._options.cacheSize != cacheSize) { 310 if (this._options.cacheSize != cacheSize) {
271 this._options.cacheSize = cacheSize; 311 this._options.cacheSize = cacheSize;
272 } 312 }
273 this._options.analyzeFunctionBodiesPredicate = 313 this._options.analyzeFunctionBodiesPredicate =
274 options.analyzeFunctionBodiesPredicate; 314 options.analyzeFunctionBodiesPredicate;
275 this._options.generateImplicitErrors = options.generateImplicitErrors; 315 this._options.generateImplicitErrors = options.generateImplicitErrors;
276 this._options.generateSdkErrors = options.generateSdkErrors; 316 this._options.generateSdkErrors = options.generateSdkErrors;
277 this._options.dart2jsHint = options.dart2jsHint; 317 this._options.dart2jsHint = options.dart2jsHint;
318 this._options.enableGenericMethods = options.enableGenericMethods;
319 this._options.enableAssertInitializer = options.enableAssertInitializer;
320 this._options.enableAssertMessage = options.enableAssertMessage;
278 this._options.enableStrictCallChecks = options.enableStrictCallChecks; 321 this._options.enableStrictCallChecks = options.enableStrictCallChecks;
322 this._options.enableInitializingFormalAccess =
323 options.enableInitializingFormalAccess;
279 this._options.enableSuperMixins = options.enableSuperMixins; 324 this._options.enableSuperMixins = options.enableSuperMixins;
325 this._options.enableTiming = options.enableTiming;
280 this._options.hint = options.hint; 326 this._options.hint = options.hint;
281 this._options.incremental = options.incremental; 327 this._options.incremental = options.incremental;
282 this._options.incrementalApi = options.incrementalApi; 328 this._options.incrementalApi = options.incrementalApi;
283 this._options.incrementalValidation = options.incrementalValidation; 329 this._options.incrementalValidation = options.incrementalValidation;
284 this._options.lint = options.lint; 330 this._options.lint = options.lint;
285 this._options.preserveComments = options.preserveComments; 331 this._options.preserveComments = options.preserveComments;
332 if (this._options.strongMode != options.strongMode) {
333 _typeSystem = null;
334 }
286 this._options.strongMode = options.strongMode; 335 this._options.strongMode = options.strongMode;
336 this._options.trackCacheDependencies = options.trackCacheDependencies;
337 this._options.disableCacheFlushing = options.disableCacheFlushing;
338 this._options.finerGrainedInvalidation = options.finerGrainedInvalidation;
339 if (options is AnalysisOptionsImpl) {
340 this._options.strongModeHints = options.strongModeHints;
341 this._options.implicitCasts = options.implicitCasts;
342 this._options.nonnullableTypes = options.nonnullableTypes;
343 this._options.implicitDynamic = options.implicitDynamic;
344 }
287 if (needsRecompute) { 345 if (needsRecompute) {
288 for (WorkManager workManager in workManagers) { 346 for (WorkManager workManager in workManagers) {
289 workManager.onAnalysisOptionsChanged(); 347 workManager.onAnalysisOptionsChanged();
290 } 348 }
291 } 349 }
292 } 350 }
293 351
294 @override 352 @override
295 void set analysisPriorityOrder(List<Source> sources) { 353 void set analysisPriorityOrder(List<Source> sources) {
296 if (sources == null || sources.isEmpty) { 354 if (sources == null || sources.isEmpty) {
297 _priorityOrder = Source.EMPTY_LIST; 355 _priorityOrder = Source.EMPTY_LIST;
298 } else { 356 } else {
299 while (sources.remove(null)) { 357 while (sources.remove(null)) {
300 // Nothing else to do. 358 // Nothing else to do.
301 } 359 }
302 if (sources.isEmpty) { 360 if (sources.isEmpty) {
303 _priorityOrder = Source.EMPTY_LIST; 361 _priorityOrder = Source.EMPTY_LIST;
304 } else { 362 } else {
305 _priorityOrder = sources; 363 _priorityOrder = sources;
306 } 364 }
307 } 365 }
308 for (WorkManager workManager in workManagers) { 366 for (WorkManager workManager in workManagers) {
309 workManager.applyPriorityTargets(_priorityOrder); 367 workManager.applyPriorityTargets(_priorityOrder);
310 } 368 }
311 driver.reset(); 369 driver.reset();
312 } 370 }
313 371
372 CacheConsistencyValidator get cacheConsistencyValidator =>
373 _cacheConsistencyValidator ??= new CacheConsistencyValidatorImpl(this);
374
314 @override 375 @override
315 set contentCache(ContentCache value) { 376 set contentCache(ContentCache value) {
316 _contentCache = value; 377 _contentCache = value;
317 } 378 }
318 379
319 @override 380 @override
320 DeclaredVariables get declaredVariables => _declaredVariables; 381 DeclaredVariables get declaredVariables => _declaredVariables;
321 382
383 @deprecated
384 @override
385 EmbedderYamlLocator get embedderYamlLocator => _embedderYamlLocator;
386
322 @override 387 @override
323 List<AnalysisTarget> get explicitTargets { 388 List<AnalysisTarget> get explicitTargets {
324 List<AnalysisTarget> targets = <AnalysisTarget>[]; 389 List<AnalysisTarget> targets = <AnalysisTarget>[];
325 MapIterator<AnalysisTarget, CacheEntry> iterator = _cache.iterator(); 390 MapIterator<AnalysisTarget, CacheEntry> iterator = _cache.iterator();
326 while (iterator.moveNext()) { 391 while (iterator.moveNext()) {
327 if (iterator.value.explicitlyAdded) { 392 if (iterator.value.explicitlyAdded) {
328 targets.add(iterator.key); 393 targets.add(iterator.key);
329 } 394 }
330 } 395 }
331 return targets; 396 return targets;
332 } 397 }
333 398
334 @override 399 @override
335 List<Source> get htmlSources => _getSources(SourceKind.HTML); 400 List<Source> get htmlSources => _getSources(SourceKind.HTML);
336 401
337 @override 402 @override
338 Stream<ImplicitAnalysisEvent> get implicitAnalysisEvents => 403 Stream<ImplicitAnalysisEvent> get implicitAnalysisEvents =>
339 _implicitAnalysisEventsController.stream; 404 _implicitAnalysisEventsController.stream;
340 405
341 @override 406 @override
407 bool get isActive => _isActive;
408
409 @override
410 set isActive(bool active) {
411 if (active != _isActive) {
412 _isActive = active;
413 _privatePartition.isActive = active;
414 }
415 }
416
417 @override
342 bool get isDisposed => _disposed; 418 bool get isDisposed => _disposed;
343 419
344 @override 420 @override
345 List<Source> get launchableClientLibrarySources { 421 List<Source> get launchableClientLibrarySources {
346 List<Source> sources = <Source>[]; 422 List<Source> sources = <Source>[];
347 for (Source source in _cache.sources) { 423 for (Source source in _cache.sources) {
348 CacheEntry entry = _cache.get(source); 424 CacheEntry entry = _cache.get(source);
349 if (entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY && 425 if (entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY &&
350 !source.isInSystemLibrary && 426 !source.isInSystemLibrary &&
351 isClientLibrary(source)) { 427 isClientLibrary(source)) {
352 sources.add(source); 428 sources.add(source);
353 } 429 }
354 } 430 }
355 return sources; 431 return sources;
356 } 432 }
357 433
358 @override 434 @override
359 List<Source> get launchableServerLibrarySources { 435 List<Source> get launchableServerLibrarySources {
360 List<Source> sources = <Source>[]; 436 List<Source> sources = <Source>[];
361 for (Source source in _cache.sources) { 437 for (Source source in _cache.sources) {
362 CacheEntry entry = _cache.get(source); 438 CacheEntry entry = _cache.get(source);
363 if (source is Source && 439 if (entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY &&
364 entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY &&
365 !source.isInSystemLibrary && 440 !source.isInSystemLibrary &&
366 isServerLibrary(source)) { 441 isServerLibrary(source)) {
367 sources.add(source); 442 sources.add(source);
368 } 443 }
369 } 444 }
370 return sources; 445 return sources;
371 } 446 }
372 447
373 @override 448 @override
374 List<Source> get librarySources => _getSources(SourceKind.LIBRARY); 449 List<Source> get librarySources => _getSources(SourceKind.LIBRARY);
375 450
376 @override 451 @override
377 Stream<SourcesChangedEvent> get onSourcesChanged => 452 Stream<SourcesChangedEvent> get onSourcesChanged =>
378 _onSourcesChangedController.stream; 453 _onSourcesChangedController.stream;
379 454
380 /** 455 /**
381 * Make _pendingFutureSources available to unit tests. 456 * Make _pendingFutureSources available to unit tests.
382 */ 457 */
383 HashMap<AnalysisTarget, 458 HashMap<AnalysisTarget, List<PendingFuture>>
384 List<PendingFuture>> get pendingFutureSources_forTesting => 459 get pendingFutureSources_forTesting => _pendingFutureTargets;
385 _pendingFutureTargets;
386 460
387 @override 461 @override
388 List<Source> get prioritySources => _priorityOrder; 462 List<Source> get prioritySources => _priorityOrder;
389 463
390 @override 464 @override
391 List<AnalysisTarget> get priorityTargets => prioritySources; 465 List<AnalysisTarget> get priorityTargets => prioritySources;
392 466
393 @override 467 @override
394 CachePartition get privateAnalysisCachePartition => _privatePartition; 468 CachePartition get privateAnalysisCachePartition => _privatePartition;
395 469
396 @override 470 @override
397 SourceFactory get sourceFactory => _sourceFactory; 471 SourceFactory get sourceFactory => _sourceFactory;
398 472
399 @override 473 @override
400 void set sourceFactory(SourceFactory factory) { 474 void set sourceFactory(SourceFactory factory) {
401 if (identical(_sourceFactory, factory)) { 475 if (identical(_sourceFactory, factory)) {
402 return; 476 return;
403 } else if (factory.context != null) { 477 } else if (factory.context != null) {
404 throw new IllegalStateException( 478 throw new StateError(
405 "Source factories cannot be shared between contexts"); 479 "Source factories cannot be shared between contexts");
406 } 480 }
407 if (_sourceFactory != null) { 481 if (_sourceFactory != null) {
408 _sourceFactory.context = null; 482 _sourceFactory.context = null;
409 } 483 }
410 factory.context = this; 484 factory.context = this;
411 _sourceFactory = factory; 485 _sourceFactory = factory;
486 _cache?.dispose();
412 _cache = createCacheFromSourceFactory(factory); 487 _cache = createCacheFromSourceFactory(factory);
413 for (WorkManager workManager in workManagers) { 488 for (WorkManager workManager in workManagers) {
414 workManager.onSourceFactoryChanged(); 489 workManager.onSourceFactoryChanged();
415 } 490 }
416 } 491 }
417 492
418 /**
419 * Invalidate analysis cache.
420 */
421 void invalidateCachedResults() {
422 _cache = createCacheFromSourceFactory(_sourceFactory);
423 }
424
425 @override 493 @override
426 List<Source> get sources { 494 List<Source> get sources {
427 return _cache.sources.toList(); 495 return _cache.sources.toList();
428 } 496 }
429 497
430 /** 498 /**
431 * Return a list of the sources that would be processed by 499 * Return a list of the sources that would be processed by
432 * [performAnalysisTask]. This method duplicates, and must therefore be kept 500 * [performAnalysisTask]. This method duplicates, and must therefore be kept
433 * in sync with, [getNextAnalysisTask]. This method is intended to be used for 501 * in sync with, [getNextAnalysisTask]. This method is intended to be used for
434 * testing purposes only. 502 * testing purposes only.
435 */ 503 */
436 List<Source> get sourcesNeedingProcessing { 504 List<Source> get sourcesNeedingProcessing {
437 HashSet<Source> sources = new HashSet<Source>(); 505 HashSet<Source> sources = new HashSet<Source>();
438 bool hintsEnabled = _options.hint; 506 bool hintsEnabled = _options.hint;
439 bool lintsEnabled = _options.lint; 507 bool lintsEnabled = _options.lint;
440 508
441 MapIterator<AnalysisTarget, CacheEntry> iterator = 509 MapIterator<AnalysisTarget, CacheEntry> iterator =
442 _privatePartition.iterator(); 510 _privatePartition.iterator();
443 while (iterator.moveNext()) { 511 while (iterator.moveNext()) {
444 AnalysisTarget target = iterator.key; 512 AnalysisTarget target = iterator.key;
445 if (target is Source) { 513 if (target is Source) {
446 _getSourcesNeedingProcessing( 514 _getSourcesNeedingProcessing(
447 target, iterator.value, false, hintsEnabled, lintsEnabled, sources); 515 target, iterator.value, false, hintsEnabled, lintsEnabled, sources);
448 } 516 }
449 } 517 }
450 return new List<Source>.from(sources); 518 return new List<Source>.from(sources);
451 } 519 }
452 520
453 @override
454 AnalysisContextStatistics get statistics {
455 AnalysisContextStatisticsImpl statistics =
456 new AnalysisContextStatisticsImpl();
457 // TODO(brianwilkerson) Implement this.
458 // visitCacheItems(statistics._internalPutCacheItem);
459 // statistics.partitionData = _cache.partitionData;
460 return statistics;
461 }
462
463 List<Source> get test_priorityOrder => _priorityOrder; 521 List<Source> get test_priorityOrder => _priorityOrder;
464 522
465 @override 523 @override
466 TypeProvider get typeProvider { 524 TypeProvider get typeProvider {
525 // The `AnalysisContextTarget.request` results go into the SDK partition,
526 // and the TYPE_PROVIDER result is computed and put into the SDK partition
527 // only by the first non-SDK analysis context. So, in order to reuse it
528 // in other analysis contexts, we need to ask for it from the cache.
529 _typeProvider ??= getResult(AnalysisContextTarget.request, TYPE_PROVIDER);
530 if (_typeProvider != null) {
531 return _typeProvider;
532 }
533
467 // Make sure a task didn't accidentally try to call back into the context 534 // Make sure a task didn't accidentally try to call back into the context
468 // to retrieve the type provider. 535 // to retrieve the type provider.
469 assert(!driver.isTaskRunning); 536 assert(!driver.isTaskRunning);
470 537
471 if (_typeProvider != null) {
472 return _typeProvider;
473 }
474 Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE); 538 Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE);
475 if (coreSource == null) { 539 if (coreSource == null) {
476 throw new AnalysisException("Could not create a source for dart:core"); 540 throw new AnalysisException("Could not create a source for dart:core");
477 } 541 }
478 LibraryElement coreElement = computeLibraryElement(coreSource); 542 LibraryElement coreElement = computeLibraryElement(coreSource);
479 if (coreElement == null) { 543 if (coreElement == null) {
480 throw new AnalysisException("Could not create an element for dart:core"); 544 throw new AnalysisException("Could not create an element for dart:core");
481 } 545 }
546
482 Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC); 547 Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
483 if (asyncSource == null) { 548 if (asyncSource == null) {
484 throw new AnalysisException("Could not create a source for dart:async"); 549 throw new AnalysisException("Could not create a source for dart:async");
485 } 550 }
486 LibraryElement asyncElement = computeLibraryElement(asyncSource); 551 LibraryElement asyncElement = computeLibraryElement(asyncSource);
487 if (asyncElement == null) { 552 if (asyncElement == null) {
488 throw new AnalysisException("Could not create an element for dart:async"); 553 throw new AnalysisException("Could not create an element for dart:async");
489 } 554 }
490 _typeProvider = new TypeProviderImpl(coreElement, asyncElement); 555 _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
491 return _typeProvider; 556 return _typeProvider;
492 } 557 }
493 558
494 /** 559 /**
495 * Sets the [TypeProvider] for this context. 560 * Sets the [TypeProvider] for this context.
496 */ 561 */
562 @override
497 void set typeProvider(TypeProvider typeProvider) { 563 void set typeProvider(TypeProvider typeProvider) {
498 _typeProvider = typeProvider; 564 _typeProvider = typeProvider;
499 } 565 }
500 566
501 @override 567 @override
502 TypeSystem get typeSystem { 568 TypeSystem get typeSystem {
503 if (_typeSystem == null) { 569 if (_typeSystem == null) {
504 _typeSystem = TypeSystem.create(this); 570 _typeSystem = TypeSystem.create(this);
505 } 571 }
506 return _typeSystem; 572 return _typeSystem;
507 } 573 }
508 574
509 @override 575 @override
576 bool aboutToComputeResult(CacheEntry entry, ResultDescriptor result) {
577 return PerformanceStatistics.summary.makeCurrentWhile(() {
578 // Use this helper if it is set.
579 if (resultProvider != null && resultProvider.compute(entry, result)) {
580 return true;
581 }
582 // Ask the SDK.
583 DartSdk dartSdk = sourceFactory.dartSdk;
584 if (dartSdk != null) {
585 AnalysisContext sdkContext = dartSdk.context;
586 if (!identical(sdkContext, this) &&
587 sdkContext is InternalAnalysisContext) {
588 return sdkContext.aboutToComputeResult(entry, result);
589 }
590 }
591 // Cannot provide the result.
592 return false;
593 });
594 }
595
596 @override
510 void addListener(AnalysisListener listener) { 597 void addListener(AnalysisListener listener) {
511 if (!_listeners.contains(listener)) { 598 if (!_listeners.contains(listener)) {
512 _listeners.add(listener); 599 _listeners.add(listener);
513 } 600 }
514 } 601 }
515 602
516 @override 603 @override
517 void applyAnalysisDelta(AnalysisDelta delta) { 604 void applyAnalysisDelta(AnalysisDelta delta) {
518 ChangeSet changeSet = new ChangeSet(); 605 ChangeSet changeSet = new ChangeSet();
519 delta.analysisLevels.forEach((Source source, AnalysisLevel level) { 606 delta.analysisLevels.forEach((Source source, AnalysisLevel level) {
520 if (level == AnalysisLevel.NONE) { 607 if (level == AnalysisLevel.NONE) {
521 changeSet.removedSource(source); 608 changeSet.removedSource(source);
522 } else { 609 } else {
523 changeSet.addedSource(source); 610 changeSet.addedSource(source);
524 } 611 }
525 }); 612 });
526 applyChanges(changeSet); 613 applyChanges(changeSet);
527 } 614 }
528 615
529 @override 616 @override
530 void applyChanges(ChangeSet changeSet) { 617 void applyChanges(ChangeSet changeSet) {
531 if (changeSet.isEmpty) { 618 if (changeSet.isEmpty) {
532 return; 619 return;
533 } 620 }
534 // 621 //
535 // First, compute the list of sources that have been removed. 622 // First, compute the list of sources that have been removed.
536 // 623 //
537 List<Source> removedSources = 624 List<Source> removedSources = changeSet.removedSources.toList();
538 new List<Source>.from(changeSet.removedSources);
539 for (SourceContainer container in changeSet.removedContainers) { 625 for (SourceContainer container in changeSet.removedContainers) {
540 _addSourcesInContainer(removedSources, container); 626 _addSourcesInContainer(removedSources, container);
541 } 627 }
542 // 628 //
543 // Then determine which cached results are no longer valid. 629 // Then determine which cached results are no longer valid.
544 // 630 //
545 for (Source source in changeSet.addedSources) { 631 for (Source source in changeSet.addedSources) {
546 _sourceAvailable(source); 632 _sourceAvailable(source);
547 } 633 }
548 for (Source source in changeSet.changedSources) { 634 // Exclude sources that are overridden in the content cache, so the change
549 if (_contentCache.getContents(source) != null) { 635 // will have no effect. Just ignore it to avoid wasting time doing
550 // This source is overridden in the content cache, so the change will 636 // re-analysis.
551 // have no effect. Just ignore it to avoid wasting time doing 637 List<Source> changedSources = changeSet.changedSources
552 // re-analysis. 638 .where((s) => _contentCache.getContents(s) == null)
553 continue; 639 .toList();
554 } 640 for (Source source in changedSources) {
555 _sourceChanged(source); 641 _sourceChanged(source);
556 } 642 }
557 changeSet.changedContents.forEach((Source key, String value) { 643 changeSet.changedContents.forEach((Source key, String value) {
558 _contentsChanged(key, value, false); 644 _contentsChanged(key, value, false);
559 }); 645 });
560 changeSet.changedRanges 646 changeSet.changedRanges
561 .forEach((Source source, ChangeSet_ContentChange change) { 647 .forEach((Source source, ChangeSet_ContentChange change) {
562 _contentRangeChanged(source, change.contents, change.offset, 648 _contentRangeChanged(source, change.contents, change.offset,
563 change.oldLength, change.newLength); 649 change.oldLength, change.newLength);
564 }); 650 });
565 for (Source source in changeSet.deletedSources) {
566 _sourceDeleted(source);
567 }
568 for (Source source in removedSources) { 651 for (Source source in removedSources) {
569 _sourceRemoved(source); 652 _sourceRemoved(source);
570 } 653 }
571 for (WorkManager workManager in workManagers) { 654 for (WorkManager workManager in workManagers) {
572 workManager.applyChange( 655 workManager.applyChange(
573 changeSet.addedSources, changeSet.changedSources, removedSources); 656 changeSet.addedSources, changedSources, removedSources);
574 } 657 }
575 _onSourcesChangedController.add(new SourcesChangedEvent(changeSet)); 658 _onSourcesChangedController.add(new SourcesChangedEvent(changeSet));
576 } 659 }
577 660
578 @override 661 @override
579 String computeDocumentationComment(Element element) { 662 String computeDocumentationComment(Element element) =>
580 if (element == null) { 663 element?.documentationComment;
581 return null;
582 }
583 Source source = element.source;
584 if (source == null) {
585 return null;
586 }
587 SourceRange docRange = element.docRange;
588 if (docRange == null) {
589 return null;
590 }
591 String code = getContents(source).data;
592 String comment = code.substring(docRange.offset, docRange.end);
593 return comment.replaceAll('\r\n', '\n');
594 }
595 664
596 @override 665 @override
597 List<AnalysisError> computeErrors(Source source) { 666 List<AnalysisError> computeErrors(Source source) {
598 String name = source.shortName; 667 String name = source.shortName;
599 if (AnalysisEngine.isHtmlFileName(name)) { 668 if (AnalysisEngine.isHtmlFileName(name)) {
600 return computeResult(source, HTML_ERRORS); 669 return computeResult(source, HTML_ERRORS);
601 } 670 }
602 return computeResult(source, DART_ERRORS); 671 return computeResult(source, DART_ERRORS);
603 } 672 }
604 673
605 @override 674 @override
606 List<Source> computeExportedLibraries(Source source) => 675 List<Source> computeExportedLibraries(Source source) =>
607 computeResult(source, EXPORTED_LIBRARIES); 676 computeResult(source, EXPORTED_LIBRARIES);
608 677
609 @override 678 @override
610 @deprecated
611 HtmlElement computeHtmlElement(Source source) {
612 // TODO(brianwilkerson) Remove this method after switching to the new task
613 // model.
614 throw new UnimplementedError('Not supported in the new task model');
615 }
616
617 @override
618 List<Source> computeImportedLibraries(Source source) => 679 List<Source> computeImportedLibraries(Source source) =>
619 computeResult(source, EXPLICITLY_IMPORTED_LIBRARIES); 680 computeResult(source, EXPLICITLY_IMPORTED_LIBRARIES);
620 681
621 @override 682 @override
622 SourceKind computeKindOf(Source source) { 683 SourceKind computeKindOf(Source source) {
623 String name = source.shortName; 684 String name = source.shortName;
624 if (AnalysisEngine.isDartFileName(name)) { 685 if (AnalysisEngine.isDartFileName(name)) {
625 return computeResult(source, SOURCE_KIND); 686 return computeResult(source, SOURCE_KIND);
626 } else if (AnalysisEngine.isHtmlFileName(name)) { 687 } else if (AnalysisEngine.isHtmlFileName(name)) {
627 return SourceKind.HTML; 688 return SourceKind.HTML;
628 } 689 }
629 return SourceKind.UNKNOWN; 690 return SourceKind.UNKNOWN;
630 } 691 }
631 692
632 @override 693 @override
633 LibraryElement computeLibraryElement(Source source) { 694 LibraryElement computeLibraryElement(Source source) {
634 //_computeResult(source, HtmlEntry.ELEMENT); 695 //_computeResult(source, HtmlEntry.ELEMENT);
635 return computeResult(source, LIBRARY_ELEMENT); 696 return computeResult(source, LIBRARY_ELEMENT);
636 } 697 }
637 698
638 @override 699 @override
639 LineInfo computeLineInfo(Source source) => computeResult(source, LINE_INFO); 700 LineInfo computeLineInfo(Source source) => computeResult(source, LINE_INFO);
640 701
641 @override 702 @override
642 @deprecated
643 CompilationUnit computeResolvableCompilationUnit(Source source) {
644 return null;
645 }
646
647 @override
648 CancelableFuture<CompilationUnit> computeResolvedCompilationUnitAsync( 703 CancelableFuture<CompilationUnit> computeResolvedCompilationUnitAsync(
649 Source unitSource, Source librarySource) { 704 Source unitSource, Source librarySource) {
650 if (!AnalysisEngine.isDartFileName(unitSource.shortName) || 705 if (!AnalysisEngine.isDartFileName(unitSource.shortName) ||
651 !AnalysisEngine.isDartFileName(librarySource.shortName)) { 706 !AnalysisEngine.isDartFileName(librarySource.shortName)) {
652 return new CancelableFuture.error(new AnalysisNotScheduledError()); 707 return new CancelableFuture.error(new AnalysisNotScheduledError());
653 } 708 }
654 var unitTarget = new LibrarySpecificUnit(librarySource, unitSource); 709 return new AnalysisFutureHelper<CompilationUnit>(this,
655 return new _AnalysisFutureHelper<CompilationUnit>(this) 710 new LibrarySpecificUnit(librarySource, unitSource), RESOLVED_UNIT)
656 .computeAsync(unitTarget, (CacheEntry entry) { 711 .computeAsync();
657 CacheState state = entry.getState(RESOLVED_UNIT);
658 if (state == CacheState.ERROR) {
659 throw entry.exception;
660 } else if (state == CacheState.INVALID) {
661 return null;
662 }
663 return entry.getValue(RESOLVED_UNIT);
664 }, () {
665 dartWorkManager.addPriorityResult(unitTarget, RESOLVED_UNIT);
666 });
667 } 712 }
668 713
669 @override 714 @override
670 Object /*V*/ computeResult( 715 Object/*=V*/ computeResult/*<V>*/(
671 AnalysisTarget target, ResultDescriptor /*<V>*/ descriptor) { 716 AnalysisTarget target, ResultDescriptor/*<V>*/ descriptor) {
717 // Make sure we are not trying to invoke the task model in a reentrant
718 // fashion.
719 assert(!driver.isTaskRunning);
672 CacheEntry entry = getCacheEntry(target); 720 CacheEntry entry = getCacheEntry(target);
673 CacheState state = entry.getState(descriptor); 721 CacheState state = entry.getState(descriptor);
674 if (state == CacheState.FLUSHED || state == CacheState.INVALID) { 722 if (state == CacheState.FLUSHED || state == CacheState.INVALID) {
675 driver.computeResult(target, descriptor); 723 driver.computeResult(target, descriptor);
724 entry = getCacheEntry(target);
676 } 725 }
677 state = entry.getState(descriptor); 726 state = entry.getState(descriptor);
678 if (state == CacheState.ERROR) { 727 if (state == CacheState.ERROR) {
679 throw new AnalysisException( 728 throw new AnalysisException(
680 'Cannot compute $descriptor for $target', entry.exception); 729 'Cannot compute $descriptor for $target', entry.exception);
681 } 730 }
682 return entry.getValue(descriptor); 731 return entry.getValue(descriptor);
683 } 732 }
684 733
685 /** 734 /**
686 * Create an analysis cache based on the given source [factory]. 735 * Create an analysis cache based on the given source [factory].
687 */ 736 */
688 AnalysisCache createCacheFromSourceFactory(SourceFactory factory) { 737 AnalysisCache createCacheFromSourceFactory(SourceFactory factory) {
689 if (factory == null) { 738 AnalysisCache createCache() {
690 return new AnalysisCache(<CachePartition>[_privatePartition]); 739 if (factory == null) {
740 return new AnalysisCache(<CachePartition>[_privatePartition]);
741 }
742 DartSdk sdk = factory.dartSdk;
743 if (sdk == null) {
744 return new AnalysisCache(<CachePartition>[_privatePartition]);
745 }
746 return new AnalysisCache(<CachePartition>[
747 AnalysisEngine.instance.partitionManager.forSdk(sdk),
748 _privatePartition
749 ]);
691 } 750 }
692 DartSdk sdk = factory.dartSdk; 751
693 if (sdk == null) { 752 AnalysisCache cache = createCache();
694 return new AnalysisCache(<CachePartition>[_privatePartition]); 753 onResultInvalidatedSubscription?.cancel();
695 } 754 onResultInvalidatedSubscription =
696 return new AnalysisCache(<CachePartition>[ 755 cache.onResultInvalidated.listen((InvalidatedResult event) {
697 AnalysisEngine.instance.partitionManager_new.forSdk(sdk), 756 onResultInvalidated.add(event);
698 _privatePartition 757 StreamController<ResultChangedEvent> controller =
699 ]); 758 _resultChangedControllers[event.descriptor];
759 if (controller != null) {
760 controller.add(new ResultChangedEvent(
761 this, event.entry.target, event.descriptor, event.value, false));
762 }
763 });
764 return cache;
700 } 765 }
701 766
702 @override 767 @override
703 void dispose() { 768 void dispose() {
704 _disposed = true; 769 _disposed = true;
705 for (List<PendingFuture> pendingFutures in _pendingFutureTargets.values) { 770 for (List<PendingFuture> pendingFutures in _pendingFutureTargets.values) {
706 for (PendingFuture pendingFuture in pendingFutures) { 771 for (PendingFuture pendingFuture in pendingFutures) {
707 pendingFuture.forciblyComplete(); 772 pendingFuture.forciblyComplete();
708 } 773 }
709 } 774 }
710 _pendingFutureTargets.clear(); 775 _pendingFutureTargets.clear();
711 _privatePartition.dispose(); 776 _privatePartition.dispose();
777 _cache.dispose();
712 } 778 }
713 779
714 @override 780 @override
715 List<CompilationUnit> ensureResolvedDartUnits(Source unitSource) { 781 List<CompilationUnit> ensureResolvedDartUnits(Source unitSource) {
716 // Check every library. 782 // Check every library.
717 List<CompilationUnit> units = <CompilationUnit>[]; 783 List<CompilationUnit> units = <CompilationUnit>[];
718 List<Source> containingLibraries = getLibrariesContaining(unitSource); 784 List<Source> containingLibraries = getLibrariesContaining(unitSource);
719 for (Source librarySource in containingLibraries) { 785 for (Source librarySource in containingLibraries) {
720 LibrarySpecificUnit target = 786 LibrarySpecificUnit target =
721 new LibrarySpecificUnit(librarySource, unitSource); 787 new LibrarySpecificUnit(librarySource, unitSource);
722 CompilationUnit unit = getResult(target, RESOLVED_UNIT); 788 CompilationUnit unit = getResult(target, RESOLVED_UNIT);
723 if (unit == null) { 789 if (unit == null) {
724 units = null; 790 units = null;
725 break; 791 break;
726 } 792 }
727 units.add(unit); 793 units.add(unit);
728 } 794 }
729 // If we have results, then we're done. 795 // If we have results, then we're done.
730 if (units != null) { 796 if (units != null) {
731 return units; 797 return units;
732 } 798 }
733 // Schedule recomputing RESOLVED_UNIT results. 799 // Schedule computing of RESOLVED_UNIT results.
734 for (Source librarySource in containingLibraries) { 800 for (Source librarySource in containingLibraries) {
735 LibrarySpecificUnit target = 801 LibrarySpecificUnit target =
736 new LibrarySpecificUnit(librarySource, unitSource); 802 new LibrarySpecificUnit(librarySource, unitSource);
737 if (_cache.getState(target, RESOLVED_UNIT) == CacheState.FLUSHED) { 803 dartWorkManager.addPriorityResult(target, RESOLVED_UNIT);
738 dartWorkManager.addPriorityResult(target, RESOLVED_UNIT);
739 }
740 } 804 }
741 return null; 805 return null;
742 } 806 }
743 807
744 @override 808 @override
745 bool exists(Source source) { 809 bool exists(Source source) {
746 if (source == null) { 810 if (source == null) {
747 return false; 811 return false;
748 } 812 }
749 if (_contentCache.getContents(source) != null) { 813 if (_contentCache.getContents(source) != null) {
750 return true; 814 return true;
751 } 815 }
752 return source.exists(); 816 return source.exists();
753 } 817 }
754 818
755 @override 819 @override
756 CacheEntry getCacheEntry(AnalysisTarget target) { 820 CacheEntry getCacheEntry(AnalysisTarget target) {
757 CacheEntry entry = _cache.get(target); 821 CacheEntry entry = _cache.get(target);
758 if (entry == null) { 822 if (entry == null) {
759 entry = new CacheEntry(target); 823 entry = new CacheEntry(target);
824 ImplicitAnalysisEvent event = null;
760 if (target is Source) { 825 if (target is Source) {
761 entry.modificationTime = getModificationStamp(target); 826 entry.modificationTime = getModificationStamp(target);
827 event = new ImplicitAnalysisEvent(target, true);
762 } 828 }
763 _cache.put(entry); 829 _cache.put(entry);
764 if (target is Source) { 830 if (event != null) {
765 _implicitAnalysisEventsController 831 _implicitAnalysisEventsController.add(event);
766 .add(new ImplicitAnalysisEvent(target, true));
767 } 832 }
768 } 833 }
769 return entry; 834 return entry;
770 } 835 }
771 836
772 @override 837 @override
773 CompilationUnitElement getCompilationUnitElement( 838 CompilationUnitElement getCompilationUnitElement(
774 Source unitSource, Source librarySource) { 839 Source unitSource, Source librarySource) {
775 AnalysisTarget target = new LibrarySpecificUnit(librarySource, unitSource); 840 AnalysisTarget target = new LibrarySpecificUnit(librarySource, unitSource);
776 return getResult(target, COMPILATION_UNIT_ELEMENT); 841 return getResult(target, COMPILATION_UNIT_ELEMENT);
777 } 842 }
778 843
779 @override 844 @override
780 Object getConfigurationData(ResultDescriptor key) => _configurationData[key]; 845 Object/*=V*/ getConfigurationData/*<V>*/(ResultDescriptor/*<V>*/ key) =>
846 (_configurationData[key] ?? key?.defaultValue) as Object/*=V*/;
781 847
782 @override 848 @override
783 TimestampedData<String> getContents(Source source) { 849 TimestampedData<String> getContents(Source source) {
784 String contents = _contentCache.getContents(source); 850 String contents = _contentCache.getContents(source);
785 if (contents != null) { 851 if (contents != null) {
786 return new TimestampedData<String>( 852 return new TimestampedData<String>(
787 _contentCache.getModificationStamp(source), contents); 853 _contentCache.getModificationStamp(source), contents);
788 } 854 }
789 return source.contents; 855 return source.contents;
790 } 856 }
791 857
792 @override 858 @override
793 InternalAnalysisContext getContextFor(Source source) { 859 InternalAnalysisContext getContextFor(Source source) =>
794 InternalAnalysisContext context = _cache.getContextFor(source); 860 _cache.getContextFor(source) ?? this;
795 return context == null ? this : context;
796 }
797 861
798 @override 862 @override
799 Element getElement(ElementLocation location) { 863 Element getElement(ElementLocation location) {
800 // TODO(brianwilkerson) This should not be a "get" method. 864 // TODO(brianwilkerson) This should not be a "get" method.
801 try { 865 try {
802 List<String> components = location.components; 866 List<String> components = location.components;
803 Source source = _computeSourceFromEncoding(components[0]); 867 Source source = _computeSourceFromEncoding(components[0]);
804 String sourceName = source.shortName; 868 String sourceName = source.shortName;
805 if (AnalysisEngine.isDartFileName(sourceName)) { 869 if (AnalysisEngine.isDartFileName(sourceName)) {
806 ElementImpl element = computeLibraryElement(source) as ElementImpl; 870 ElementImpl element = computeLibraryElement(source) as ElementImpl;
(...skipping 18 matching lines...) Expand all
825 List<AnalysisError> allErrors = <AnalysisError>[]; 889 List<AnalysisError> allErrors = <AnalysisError>[];
826 for (WorkManager workManager in workManagers) { 890 for (WorkManager workManager in workManagers) {
827 List<AnalysisError> errors = workManager.getErrors(source); 891 List<AnalysisError> errors = workManager.getErrors(source);
828 allErrors.addAll(errors); 892 allErrors.addAll(errors);
829 } 893 }
830 LineInfo lineInfo = getLineInfo(source); 894 LineInfo lineInfo = getLineInfo(source);
831 return new AnalysisErrorInfoImpl(allErrors, lineInfo); 895 return new AnalysisErrorInfoImpl(allErrors, lineInfo);
832 } 896 }
833 897
834 @override 898 @override
835 @deprecated
836 HtmlElement getHtmlElement(Source source) {
837 // TODO(brianwilkerson) Remove this method after switching to the new task
838 // model.
839 throw new UnimplementedError('Not supported in the new task model');
840 }
841
842 @override
843 List<Source> getHtmlFilesReferencing(Source source) { 899 List<Source> getHtmlFilesReferencing(Source source) {
844 if (!AnalysisEngine.isDartFileName(source.shortName)) { 900 if (!AnalysisEngine.isDartFileName(source.shortName)) {
845 return Source.EMPTY_LIST; 901 return Source.EMPTY_LIST;
846 } 902 }
847 List<Source> htmlSources = <Source>[]; 903 List<Source> htmlSources = <Source>[];
848 List<Source> librarySources = getLibrariesContaining(source); 904 List<Source> librarySources = getLibrariesContaining(source);
849 for (Source source in _cache.sources) { 905 for (Source source in _cache.sources) {
850 if (AnalysisEngine.isHtmlFileName(source.shortName)) { 906 if (AnalysisEngine.isHtmlFileName(source.shortName)) {
851 List<Source> referencedLibraries = 907 List<Source> referencedLibraries =
852 getResult(source, REFERENCED_LIBRARIES); 908 getResult(source, REFERENCED_LIBRARIES);
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
964 Source unitSource, Source librarySource) { 1020 Source unitSource, Source librarySource) {
965 if (!AnalysisEngine.isDartFileName(unitSource.shortName) || 1021 if (!AnalysisEngine.isDartFileName(unitSource.shortName) ||
966 !AnalysisEngine.isDartFileName(librarySource.shortName)) { 1022 !AnalysisEngine.isDartFileName(librarySource.shortName)) {
967 return null; 1023 return null;
968 } 1024 }
969 return getResult( 1025 return getResult(
970 new LibrarySpecificUnit(librarySource, unitSource), RESOLVED_UNIT); 1026 new LibrarySpecificUnit(librarySource, unitSource), RESOLVED_UNIT);
971 } 1027 }
972 1028
973 @override 1029 @override
974 @deprecated 1030 Object/*=V*/ getResult/*<V>*/(
975 ht.HtmlUnit getResolvedHtmlUnit(Source htmlSource) { 1031 AnalysisTarget target, ResultDescriptor/*<V>*/ result) {
976 // TODO(brianwilkerson) Remove this method after switching to the new task
977 // model.
978 throw new UnimplementedError('Not supported in the new task model');
979 }
980
981 @override
982 Object getResult(AnalysisTarget target, ResultDescriptor result) {
983 return _cache.getValue(target, result); 1032 return _cache.getValue(target, result);
984 } 1033 }
985 1034
986 @override 1035 @override
987 List<Source> getSourcesWithFullName(String path) { 1036 List<Source> getSourcesWithFullName(String path) {
988 return analysisCache.getSourcesWithFullName(path); 1037 return analysisCache.getSourcesWithFullName(path);
989 } 1038 }
990 1039
991 @override 1040 @override
992 bool handleContentsChanged( 1041 bool handleContentsChanged(
993 Source source, String originalContents, String newContents, bool notify) { 1042 Source source, String originalContents, String newContents, bool notify) {
994 CacheEntry entry = _cache.get(source); 1043 CacheEntry entry = _cache.get(source);
995 if (entry == null) { 1044 if (entry == null) {
996 return false; 1045 return false;
997 } 1046 }
1047 // If there were no "originalContents" in the content cache,
1048 // use the contents of the file instead.
1049 if (originalContents == null) {
1050 try {
1051 TimestampedData<String> fileContents = source.contents;
1052 if (fileContents.modificationTime == entry.modificationTime) {
1053 originalContents = fileContents.data;
1054 }
1055 } catch (e) {}
1056 }
998 bool changed = newContents != originalContents; 1057 bool changed = newContents != originalContents;
999 if (newContents != null) { 1058 if (newContents != null) {
1000 if (changed) { 1059 if (changed) {
1060 entry.modificationTime = _contentCache.getModificationStamp(source);
1001 if (!analysisOptions.incremental || 1061 if (!analysisOptions.incremental ||
1002 !_tryPoorMansIncrementalResolution(source, newContents)) { 1062 !_tryPoorMansIncrementalResolution(source, newContents)) {
1003 _sourceChanged(source); 1063 // Don't compare with old contents because the cache has already been
1064 // updated, and we know at this point that it changed.
1065 _sourceChanged(source, compareWithOld: false);
1004 } 1066 }
1005 entry.modificationTime = _contentCache.getModificationStamp(source);
1006 entry.setValue(CONTENT, newContents, TargetedResult.EMPTY_LIST); 1067 entry.setValue(CONTENT, newContents, TargetedResult.EMPTY_LIST);
1007 } else { 1068 } else {
1008 entry.modificationTime = _contentCache.getModificationStamp(source); 1069 entry.modificationTime = _contentCache.getModificationStamp(source);
1009 } 1070 }
1010 } else if (originalContents != null) { 1071 } else if (originalContents != null) {
1011 // We are removing the overlay for the file, check if the file's 1072 // We are removing the overlay for the file, check if the file's
1012 // contents is the same as it was in the overlay. 1073 // contents is the same as it was in the overlay.
1013 try { 1074 try {
1014 TimestampedData<String> fileContents = getContents(source); 1075 TimestampedData<String> fileContents = getContents(source);
1015 newContents = fileContents.data; 1076 newContents = fileContents.data;
1016 entry.modificationTime = fileContents.modificationTime; 1077 entry.modificationTime = fileContents.modificationTime;
1017 if (newContents == originalContents) { 1078 if (newContents == originalContents) {
1018 entry.setValue(CONTENT, newContents, TargetedResult.EMPTY_LIST); 1079 entry.setValue(CONTENT, newContents, TargetedResult.EMPTY_LIST);
1019 changed = false; 1080 changed = false;
1020 } 1081 }
1021 } catch (e) {} 1082 } catch (e) {}
1022 // If not the same content (e.g. the file is being closed without save), 1083 // If not the same content (e.g. the file is being closed without save),
1023 // then force analysis. 1084 // then force analysis.
1024 if (changed) { 1085 if (changed) {
1025 if (!analysisOptions.incremental || 1086 if (newContents == null ||
1087 !analysisOptions.incremental ||
1026 !_tryPoorMansIncrementalResolution(source, newContents)) { 1088 !_tryPoorMansIncrementalResolution(source, newContents)) {
1027 _sourceChanged(source); 1089 _sourceChanged(source);
1028 } 1090 }
1029 } 1091 }
1030 } 1092 }
1031 if (notify && changed) { 1093 if (notify && changed) {
1032 _onSourcesChangedController 1094 _onSourcesChangedController
1033 .add(new SourcesChangedEvent.changedContent(source, newContents)); 1095 .add(new SourcesChangedEvent.changedContent(source, newContents));
1034 } 1096 }
1035 return changed; 1097 return changed;
1036 } 1098 }
1037 1099
1100 /**
1101 * Invalidate analysis cache and notify work managers that they have work
1102 * to do.
1103 */
1104 void invalidateCachedResults() {
1105 _cache?.dispose();
1106 _cache = createCacheFromSourceFactory(_sourceFactory);
1107 for (WorkManager workManager in workManagers) {
1108 workManager.onAnalysisOptionsChanged();
1109 }
1110 }
1111
1038 @override 1112 @override
1039 void invalidateLibraryHints(Source librarySource) { 1113 void invalidateLibraryHints(Source librarySource) {
1040 List<Source> sources = getResult(librarySource, UNITS); 1114 List<Source> sources = getResult(librarySource, UNITS);
1041 if (sources != null) { 1115 if (sources != null) {
1042 for (Source source in sources) { 1116 for (Source source in sources) {
1043 getCacheEntry(source).setState(HINTS, CacheState.INVALID); 1117 getCacheEntry(source).setState(HINTS, CacheState.INVALID);
1044 } 1118 }
1045 } 1119 }
1046 } 1120 }
1047 1121
1048 @override 1122 @override
1049 bool isClientLibrary(Source librarySource) { 1123 bool isClientLibrary(Source librarySource) {
1050 CacheEntry entry = _cache.get(librarySource); 1124 CacheEntry entry = _cache.get(librarySource);
1051 return entry.getValue(IS_CLIENT) && entry.getValue(IS_LAUNCHABLE); 1125 return entry != null &&
1126 _referencesDartHtml(librarySource) &&
1127 entry.getValue(IS_LAUNCHABLE);
1052 } 1128 }
1053 1129
1054 @override 1130 @override
1055 bool isServerLibrary(Source librarySource) { 1131 bool isServerLibrary(Source librarySource) {
1056 CacheEntry entry = _cache.get(librarySource); 1132 CacheEntry entry = _cache.get(librarySource);
1057 return !entry.getValue(IS_CLIENT) && entry.getValue(IS_LAUNCHABLE); 1133 return entry != null &&
1134 !_referencesDartHtml(librarySource) &&
1135 entry.getValue(IS_LAUNCHABLE);
1058 } 1136 }
1059 1137
1060 @override 1138 @override
1061 Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor) { 1139 Stream<ResultChangedEvent> onResultChanged(ResultDescriptor descriptor) {
1062 return driver.onResultComputed(descriptor); 1140 driver.onResultComputed(descriptor).listen((ResultChangedEvent event) {
1141 _resultChangedControllers[descriptor]?.add(event);
1142 });
1143 return _resultChangedControllers.putIfAbsent(descriptor, () {
1144 return new StreamController<ResultChangedEvent>.broadcast(sync: true);
1145 }).stream;
1063 } 1146 }
1064 1147
1065 @override 1148 @override
1149 @deprecated
1150 Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor) {
1151 return onResultChanged(descriptor)
1152 .where((event) => event.wasComputed)
1153 .map((event) {
1154 return new ComputedResult(
1155 event.context, event.descriptor, event.target, event.value);
1156 });
1157 }
1158
1159 @override
1066 CompilationUnit parseCompilationUnit(Source source) { 1160 CompilationUnit parseCompilationUnit(Source source) {
1067 if (!AnalysisEngine.isDartFileName(source.shortName)) { 1161 if (!AnalysisEngine.isDartFileName(source.shortName)) {
1068 return null; 1162 return null;
1069 } 1163 }
1070 try { 1164 try {
1071 getContents(source); 1165 getContents(source);
1072 } catch (exception, stackTrace) { 1166 } catch (exception, stackTrace) {
1073 throw new AnalysisException('Could not get contents of $source', 1167 throw new AnalysisException('Could not get contents of $source',
1074 new CaughtException(exception, stackTrace)); 1168 new CaughtException(exception, stackTrace));
1075 } 1169 }
1076 return computeResult(source, PARSED_UNIT); 1170 return computeResult(source, PARSED_UNIT);
1077 } 1171 }
1078 1172
1079 @override 1173 @override
1080 Document parseHtmlDocument(Source source) { 1174 Document parseHtmlDocument(Source source) {
1081 if (!AnalysisEngine.isHtmlFileName(source.shortName)) { 1175 if (!AnalysisEngine.isHtmlFileName(source.shortName)) {
1082 return null; 1176 return null;
1083 } 1177 }
1084 return computeResult(source, HTML_DOCUMENT); 1178 return computeResult(source, HTML_DOCUMENT);
1085 } 1179 }
1086 1180
1087 @override 1181 @override
1088 @deprecated // use parseHtmlDocument(source)
1089 ht.HtmlUnit parseHtmlUnit(Source source) {
1090 // TODO(brianwilkerson) Remove this method after switching to the new task
1091 // model.
1092 throw new UnimplementedError('Not supported in the new task model');
1093 }
1094
1095 @override
1096 AnalysisResult performAnalysisTask() { 1182 AnalysisResult performAnalysisTask() {
1097 return PerformanceStatistics.performAnaysis.makeCurrentWhile(() { 1183 return PerformanceStatistics.performAnalysis.makeCurrentWhile(() {
1098 _evaluatePendingFutures(); 1184 _evaluatePendingFutures();
1099 bool done = !driver.performAnalysisTask(); 1185 bool done = !driver.performAnalysisTask();
1100 List<ChangeNotice> notices = _getChangeNotices(done); 1186 List<ChangeNotice> notices = _getChangeNotices(done);
1101 if (notices != null) { 1187 if (notices != null) {
1102 int noticeCount = notices.length; 1188 int noticeCount = notices.length;
1103 for (int i = 0; i < noticeCount; i++) { 1189 for (int i = 0; i < noticeCount; i++) {
1104 ChangeNotice notice = notices[i]; 1190 ChangeNotice notice = notices[i];
1105 _notifyErrors(notice.source, notice.errors, notice.lineInfo); 1191 _notifyErrors(notice.source, notice.errors, notice.lineInfo);
1106 } 1192 }
1107 } 1193 }
1108 return new AnalysisResult(notices, -1, '', -1); 1194 return new AnalysisResult(notices, -1, '', -1);
1109 }); 1195 });
1110 } 1196 }
1111 1197
1112 @override 1198 @override
1113 void recordLibraryElements(Map<Source, LibraryElement> elementMap) { 1199 void recordLibraryElements(Map<Source, LibraryElement> elementMap) {
1114 elementMap.forEach((Source librarySource, LibraryElement library) { 1200 elementMap.forEach((Source librarySource, LibraryElement library) {
1115 // 1201 //
1116 // Cache the element in the library's info. 1202 // Cache the element in the library's info.
1117 // 1203 //
1118 CacheEntry entry = getCacheEntry(librarySource); 1204 CacheEntry entry = getCacheEntry(librarySource);
1119 setValue(ResultDescriptor result, value) { 1205 setValue(ResultDescriptor result, value) {
1120 entry.setValue(result, value, TargetedResult.EMPTY_LIST); 1206 entry.setValue(result, value, TargetedResult.EMPTY_LIST);
1121 } 1207 }
1208
1122 setValue(BUILD_DIRECTIVES_ERRORS, AnalysisError.NO_ERRORS); 1209 setValue(BUILD_DIRECTIVES_ERRORS, AnalysisError.NO_ERRORS);
1123 setValue(BUILD_LIBRARY_ERRORS, AnalysisError.NO_ERRORS); 1210 setValue(BUILD_LIBRARY_ERRORS, AnalysisError.NO_ERRORS);
1124 // CLASS_ELEMENTS 1211 // CLASS_ELEMENTS
1125 setValue(COMPILATION_UNIT_ELEMENT, library.definingCompilationUnit); 1212 setValue(COMPILATION_UNIT_ELEMENT, library.definingCompilationUnit);
1126 // CONSTRUCTORS 1213 // CONSTRUCTORS
1127 // CONSTRUCTORS_ERRORS 1214 // CONSTRUCTORS_ERRORS
1128 entry.setState(CONTENT, CacheState.FLUSHED); 1215 entry.setState(CONTENT, CacheState.FLUSHED);
1129 setValue(EXPORTED_LIBRARIES, Source.EMPTY_LIST); 1216 setValue(EXPORTED_LIBRARIES, Source.EMPTY_LIST);
1130 // EXPORT_SOURCE_CLOSURE 1217 // EXPORT_SOURCE_CLOSURE
1131 setValue(IMPORTED_LIBRARIES, Source.EMPTY_LIST); 1218 setValue(IMPORTED_LIBRARIES, Source.EMPTY_LIST);
1132 // IMPORT_SOURCE_CLOSURE 1219 // IMPORT_SOURCE_CLOSURE
1133 setValue(INCLUDED_PARTS, Source.EMPTY_LIST); 1220 setValue(INCLUDED_PARTS, Source.EMPTY_LIST);
1134 setValue(IS_CLIENT, true);
1135 setValue(IS_LAUNCHABLE, false); 1221 setValue(IS_LAUNCHABLE, false);
1136 setValue(LIBRARY_ELEMENT, library); 1222 setValue(LIBRARY_ELEMENT, library);
1137 setValue(LIBRARY_ELEMENT1, library); 1223 setValue(LIBRARY_ELEMENT1, library);
1138 setValue(LIBRARY_ELEMENT2, library); 1224 setValue(LIBRARY_ELEMENT2, library);
1139 setValue(LIBRARY_ELEMENT3, library); 1225 setValue(LIBRARY_ELEMENT3, library);
1140 setValue(LIBRARY_ELEMENT4, library); 1226 setValue(LIBRARY_ELEMENT4, library);
1141 setValue(LIBRARY_ELEMENT5, library); 1227 setValue(LIBRARY_ELEMENT5, library);
1228 setValue(LIBRARY_ELEMENT6, library);
1229 setValue(LIBRARY_ELEMENT7, library);
1230 setValue(LIBRARY_ELEMENT8, library);
1231 setValue(LIBRARY_ELEMENT9, library);
1142 setValue(LINE_INFO, new LineInfo(<int>[0])); 1232 setValue(LINE_INFO, new LineInfo(<int>[0]));
1143 setValue(PARSE_ERRORS, AnalysisError.NO_ERRORS); 1233 setValue(PARSE_ERRORS, AnalysisError.NO_ERRORS);
1144 entry.setState(PARSED_UNIT, CacheState.FLUSHED); 1234 entry.setState(PARSED_UNIT, CacheState.FLUSHED);
1145 entry.setState(RESOLVE_TYPE_NAMES_ERRORS, CacheState.FLUSHED); 1235 entry.setState(RESOLVE_TYPE_NAMES_ERRORS, CacheState.FLUSHED);
1236 entry.setState(RESOLVE_TYPE_BOUNDS_ERRORS, CacheState.FLUSHED);
1146 setValue(SCAN_ERRORS, AnalysisError.NO_ERRORS); 1237 setValue(SCAN_ERRORS, AnalysisError.NO_ERRORS);
1147 setValue(SOURCE_KIND, SourceKind.LIBRARY); 1238 setValue(SOURCE_KIND, SourceKind.LIBRARY);
1148 entry.setState(TOKEN_STREAM, CacheState.FLUSHED); 1239 entry.setState(TOKEN_STREAM, CacheState.FLUSHED);
1149 setValue(UNITS, <Source>[librarySource]); 1240 setValue(UNITS, <Source>[librarySource]);
1150 1241
1151 LibrarySpecificUnit unit = 1242 LibrarySpecificUnit unit =
1152 new LibrarySpecificUnit(librarySource, librarySource); 1243 new LibrarySpecificUnit(librarySource, librarySource);
1153 entry = getCacheEntry(unit); 1244 entry = getCacheEntry(unit);
1154 setValue(HINTS, AnalysisError.NO_ERRORS); 1245 setValue(HINTS, AnalysisError.NO_ERRORS);
1155 setValue(LINTS, AnalysisError.NO_ERRORS); 1246 setValue(LINTS, AnalysisError.NO_ERRORS);
1156 setValue(LIBRARY_UNIT_ERRORS, AnalysisError.NO_ERRORS); 1247 setValue(LIBRARY_UNIT_ERRORS, AnalysisError.NO_ERRORS);
1157 setValue(RESOLVE_TYPE_NAMES_ERRORS, AnalysisError.NO_ERRORS); 1248 setValue(RESOLVE_TYPE_NAMES_ERRORS, AnalysisError.NO_ERRORS);
1158 setValue(RESOLVE_UNIT_ERRORS, AnalysisError.NO_ERRORS); 1249 setValue(RESOLVE_UNIT_ERRORS, AnalysisError.NO_ERRORS);
1159 entry.setState(RESOLVED_UNIT, CacheState.FLUSHED); 1250 entry.setState(RESOLVED_UNIT, CacheState.FLUSHED);
1160 entry.setState(RESOLVED_UNIT1, CacheState.FLUSHED); 1251 entry.setState(RESOLVED_UNIT1, CacheState.FLUSHED);
1161 entry.setState(RESOLVED_UNIT2, CacheState.FLUSHED); 1252 entry.setState(RESOLVED_UNIT2, CacheState.FLUSHED);
1162 entry.setState(RESOLVED_UNIT3, CacheState.FLUSHED); 1253 entry.setState(RESOLVED_UNIT3, CacheState.FLUSHED);
1163 entry.setState(RESOLVED_UNIT4, CacheState.FLUSHED); 1254 entry.setState(RESOLVED_UNIT4, CacheState.FLUSHED);
1164 entry.setState(RESOLVED_UNIT5, CacheState.FLUSHED); 1255 entry.setState(RESOLVED_UNIT5, CacheState.FLUSHED);
1165 entry.setState(RESOLVED_UNIT6, CacheState.FLUSHED); 1256 entry.setState(RESOLVED_UNIT6, CacheState.FLUSHED);
1166 entry.setState(RESOLVED_UNIT7, CacheState.FLUSHED); 1257 entry.setState(RESOLVED_UNIT7, CacheState.FLUSHED);
1167 entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED); 1258 entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED);
1168 entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED); 1259 entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED);
1169 entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED); 1260 entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED);
1261 entry.setState(RESOLVED_UNIT11, CacheState.FLUSHED);
1262 entry.setState(RESOLVED_UNIT12, CacheState.FLUSHED);
1170 // USED_IMPORTED_ELEMENTS 1263 // USED_IMPORTED_ELEMENTS
1171 // USED_LOCAL_ELEMENTS 1264 // USED_LOCAL_ELEMENTS
1172 setValue(STRONG_MODE_ERRORS, AnalysisError.NO_ERRORS); 1265 setValue(STRONG_MODE_ERRORS, AnalysisError.NO_ERRORS);
1173 setValue(VARIABLE_REFERENCE_ERRORS, AnalysisError.NO_ERRORS); 1266 setValue(VARIABLE_REFERENCE_ERRORS, AnalysisError.NO_ERRORS);
1174 setValue(VERIFY_ERRORS, AnalysisError.NO_ERRORS); 1267 setValue(VERIFY_ERRORS, AnalysisError.NO_ERRORS);
1175 }); 1268 });
1176 1269
1177 CacheEntry entry = getCacheEntry(AnalysisContextTarget.request); 1270 CacheEntry entry = getCacheEntry(AnalysisContextTarget.request);
1178 entry.setValue(TYPE_PROVIDER, typeProvider, TargetedResult.EMPTY_LIST); 1271 entry.setValue(TYPE_PROVIDER, typeProvider, TargetedResult.EMPTY_LIST);
1179 } 1272 }
(...skipping 13 matching lines...) Expand all
1193 } 1286 }
1194 1287
1195 @override 1288 @override
1196 CompilationUnit resolveCompilationUnit2( 1289 CompilationUnit resolveCompilationUnit2(
1197 Source unitSource, Source librarySource) { 1290 Source unitSource, Source librarySource) {
1198 return computeResult( 1291 return computeResult(
1199 new LibrarySpecificUnit(librarySource, unitSource), RESOLVED_UNIT); 1292 new LibrarySpecificUnit(librarySource, unitSource), RESOLVED_UNIT);
1200 } 1293 }
1201 1294
1202 @override 1295 @override
1203 @deprecated
1204 ht.HtmlUnit resolveHtmlUnit(Source htmlSource) {
1205 // TODO(brianwilkerson) Remove this method after switching to the new task
1206 // model.
1207 throw new UnimplementedError('Not supported in the new task model');
1208 }
1209
1210 @override
1211 void setChangedContents(Source source, String contents, int offset, 1296 void setChangedContents(Source source, String contents, int offset,
1212 int oldLength, int newLength) { 1297 int oldLength, int newLength) {
1213 if (_contentRangeChanged(source, contents, offset, oldLength, newLength)) { 1298 if (_contentRangeChanged(source, contents, offset, oldLength, newLength)) {
1214 _onSourcesChangedController.add(new SourcesChangedEvent.changedRange( 1299 _onSourcesChangedController.add(new SourcesChangedEvent.changedRange(
1215 source, contents, offset, oldLength, newLength)); 1300 source, contents, offset, oldLength, newLength));
1216 } 1301 }
1217 } 1302 }
1218 1303
1219 @override 1304 @override
1220 void setConfigurationData(ResultDescriptor key, Object data) { 1305 void setConfigurationData(ResultDescriptor key, Object data) {
1221 _configurationData[key] = data; 1306 _configurationData[key] = data;
1222 } 1307 }
1223 1308
1224 @override 1309 @override
1225 void setContents(Source source, String contents) { 1310 void setContents(Source source, String contents) {
1226 _contentsChanged(source, contents, true); 1311 _contentsChanged(source, contents, true);
1227 } 1312 }
1228 1313
1229 @override 1314 @override
1230 bool shouldErrorsBeAnalyzed(Source source, Object entry) { 1315 bool shouldErrorsBeAnalyzed(Source source) {
1231 CacheEntry entry = analysisCache.get(source); 1316 CacheEntry entry = analysisCache.get(source);
1232 if (source.isInSystemLibrary) { 1317 if (source.isInSystemLibrary) {
1233 return _options.generateSdkErrors; 1318 return _options.generateSdkErrors;
1234 } else if (!entry.explicitlyAdded) { 1319 } else if (!entry.explicitlyAdded) {
1235 return _options.generateImplicitErrors; 1320 return _options.generateImplicitErrors;
1236 } else { 1321 } else {
1237 return true; 1322 return true;
1238 } 1323 }
1239 } 1324 }
1240 1325
1241 @override 1326 @override
1242 void test_flushAstStructures(Source source) { 1327 void test_flushAstStructures(Source source) {
1243 CacheEntry entry = getCacheEntry(source); 1328 CacheEntry entry = getCacheEntry(source);
1244 entry.setState(PARSED_UNIT, CacheState.FLUSHED); 1329 entry.setState(PARSED_UNIT, CacheState.FLUSHED);
1245 entry.setState(RESOLVED_UNIT1, CacheState.FLUSHED); 1330 entry.setState(RESOLVED_UNIT1, CacheState.FLUSHED);
1246 entry.setState(RESOLVED_UNIT2, CacheState.FLUSHED); 1331 entry.setState(RESOLVED_UNIT2, CacheState.FLUSHED);
1247 entry.setState(RESOLVED_UNIT3, CacheState.FLUSHED); 1332 entry.setState(RESOLVED_UNIT3, CacheState.FLUSHED);
1248 entry.setState(RESOLVED_UNIT4, CacheState.FLUSHED); 1333 entry.setState(RESOLVED_UNIT4, CacheState.FLUSHED);
1249 entry.setState(RESOLVED_UNIT5, CacheState.FLUSHED); 1334 entry.setState(RESOLVED_UNIT5, CacheState.FLUSHED);
1250 entry.setState(RESOLVED_UNIT6, CacheState.FLUSHED); 1335 entry.setState(RESOLVED_UNIT6, CacheState.FLUSHED);
1251 entry.setState(RESOLVED_UNIT7, CacheState.FLUSHED); 1336 entry.setState(RESOLVED_UNIT7, CacheState.FLUSHED);
1252 entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED); 1337 entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED);
1253 entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED); 1338 entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED);
1254 entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED); 1339 entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED);
1340 entry.setState(RESOLVED_UNIT11, CacheState.FLUSHED);
1341 entry.setState(RESOLVED_UNIT12, CacheState.FLUSHED);
1255 entry.setState(RESOLVED_UNIT, CacheState.FLUSHED); 1342 entry.setState(RESOLVED_UNIT, CacheState.FLUSHED);
1256 } 1343 }
1257 1344
1258 @override 1345 @override
1259 bool validateCacheConsistency() {
1260 int consistencyCheckStart = JavaSystem.nanoTime();
1261 HashSet<Source> changedSources = new HashSet<Source>();
1262 HashSet<Source> missingSources = new HashSet<Source>();
1263 for (Source source in _cache.sources) {
1264 CacheEntry entry = _cache.get(source);
1265 int sourceTime = getModificationStamp(source);
1266 if (sourceTime != entry.modificationTime) {
1267 changedSources.add(source);
1268 }
1269 if (entry.exception != null) {
1270 if (!exists(source)) {
1271 missingSources.add(source);
1272 }
1273 }
1274 }
1275 for (Source source in changedSources) {
1276 _sourceChanged(source);
1277 }
1278 int removalCount = 0;
1279 for (Source source in missingSources) {
1280 if (getLibrariesContaining(source).isEmpty &&
1281 getLibrariesDependingOn(source).isEmpty) {
1282 _removeFromCache(source);
1283 removalCount++;
1284 }
1285 }
1286 int consistencyCheckEnd = JavaSystem.nanoTime();
1287 if (changedSources.length > 0 || missingSources.length > 0) {
1288 StringBuffer buffer = new StringBuffer();
1289 buffer.write("Consistency check took ");
1290 buffer.write((consistencyCheckEnd - consistencyCheckStart) / 1000000.0);
1291 buffer.writeln(" ms and found");
1292 buffer.write(" ");
1293 buffer.write(changedSources.length);
1294 buffer.writeln(" inconsistent entries");
1295 buffer.write(" ");
1296 buffer.write(missingSources.length);
1297 buffer.write(" missing sources (");
1298 buffer.write(removalCount);
1299 buffer.writeln(" removed");
1300 for (Source source in missingSources) {
1301 buffer.write(" ");
1302 buffer.writeln(source.fullName);
1303 }
1304 _logInformation(buffer.toString());
1305 }
1306 return changedSources.length > 0;
1307 }
1308
1309 @deprecated
1310 @override
1311 void visitCacheItems(void callback(Source source, SourceEntry dartEntry,
1312 DataDescriptor rowDesc, CacheState state)) {
1313 // TODO(brianwilkerson) Figure out where this is used and either remove it
1314 // or adjust the call sites to use CacheEntry's.
1315 // bool hintsEnabled = _options.hint;
1316 // bool lintsEnabled = _options.lint;
1317 // MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator() ;
1318 // while (iterator.moveNext()) {
1319 // Source source = iterator.key;
1320 // cache.CacheEntry entry = iterator.value;
1321 // for (DataDescriptor descriptor in entry.descriptors) {
1322 // if (descriptor == DartEntry.SOURCE_KIND) {
1323 // // The source kind is always valid, so the state isn't interesting.
1324 // continue;
1325 // } else if (descriptor == DartEntry.CONTAINING_LIBRARIES) {
1326 // // The list of containing libraries is always valid, so the state
1327 // // isn't interesting.
1328 // continue;
1329 // } else if (descriptor == DartEntry.PUBLIC_NAMESPACE) {
1330 // // The public namespace isn't computed by performAnalysisTask()
1331 // // and therefore isn't interesting.
1332 // continue;
1333 // } else if (descriptor == HtmlEntry.HINTS) {
1334 // // We are not currently recording any hints related to HTML.
1335 // continue;
1336 // }
1337 // callback(
1338 // source, entry, descriptor, entry.getState(descriptor));
1339 // }
1340 // if (entry is DartEntry) {
1341 // // get library-specific values
1342 // List<Source> librarySources = getLibrariesContaining(source);
1343 // for (Source librarySource in librarySources) {
1344 // for (DataDescriptor descriptor in entry.libraryDescriptors) {
1345 // if (descriptor == DartEntry.BUILT_ELEMENT ||
1346 // descriptor == DartEntry.BUILT_UNIT) {
1347 // // These values are not currently being computed, so their state
1348 // // is not interesting.
1349 // continue;
1350 // } else if (!entry.explicitlyAdded &&
1351 // !_generateImplicitErrors &&
1352 // (descriptor == DartEntry.VERIFICATION_ERRORS ||
1353 // descriptor == DartEntry.HINTS ||
1354 // descriptor == DartEntry.LINTS)) {
1355 // continue;
1356 // } else if (source.isInSystemLibrary &&
1357 // !_generateSdkErrors &&
1358 // (descriptor == DartEntry.VERIFICATION_ERRORS ||
1359 // descriptor == DartEntry.HINTS ||
1360 // descriptor == DartEntry.LINTS)) {
1361 // continue;
1362 // } else if (!hintsEnabled && descriptor == DartEntry.HINTS) {
1363 // continue;
1364 // } else if (!lintsEnabled && descriptor == DartEntry.LINTS) {
1365 // continue;
1366 // }
1367 // callback(librarySource, entry, descriptor,
1368 // entry.getStateInLibrary(descriptor, librarySource));
1369 // }
1370 // }
1371 // }
1372 // }
1373 }
1374
1375 @override
1376 void visitContentCache(ContentCacheVisitor visitor) { 1346 void visitContentCache(ContentCacheVisitor visitor) {
1377 _contentCache.accept(visitor); 1347 _contentCache.accept(visitor);
1378 } 1348 }
1379 1349
1380 /** 1350 /**
1381 * Add all of the sources contained in the given source [container] to the 1351 * Add all of the sources contained in the given source [container] to the
1382 * given list of [sources]. 1352 * given list of [sources].
1383 */ 1353 */
1384 void _addSourcesInContainer(List<Source> sources, SourceContainer container) { 1354 void _addSourcesInContainer(List<Source> sources, SourceContainer container) {
1385 for (Source source in _cache.sources) { 1355 for (Source source in _cache.sources) {
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
1507 } 1477 }
1508 } 1478 }
1509 return entries; 1479 return entries;
1510 } 1480 }
1511 1481
1512 void _evaluatePendingFutures() { 1482 void _evaluatePendingFutures() {
1513 for (AnalysisTarget target in _pendingFutureTargets.keys) { 1483 for (AnalysisTarget target in _pendingFutureTargets.keys) {
1514 CacheEntry cacheEntry = _cache.get(target); 1484 CacheEntry cacheEntry = _cache.get(target);
1515 List<PendingFuture> pendingFutures = _pendingFutureTargets[target]; 1485 List<PendingFuture> pendingFutures = _pendingFutureTargets[target];
1516 for (int i = 0; i < pendingFutures.length;) { 1486 for (int i = 0; i < pendingFutures.length;) {
1517 if (pendingFutures[i].evaluate(cacheEntry)) { 1487 if (cacheEntry == null) {
1488 pendingFutures[i].forciblyComplete();
1489 pendingFutures.removeAt(i);
1490 } else if (pendingFutures[i].evaluate(cacheEntry)) {
1518 pendingFutures.removeAt(i); 1491 pendingFutures.removeAt(i);
1519 } else { 1492 } else {
1520 i++; 1493 i++;
1521 } 1494 }
1522 } 1495 }
1523 } 1496 }
1524 } 1497 }
1525 1498
1526 /** 1499 /**
1527 * Return a list containing all of the change notices that are waiting to be 1500 * Return a list containing all of the change notices that are waiting to be
1528 * returned. If there are no notices, then return either `null` or an empty 1501 * returned. If there are no notices, then return either `null` or an empty
1529 * list, depending on the value of [nullIfEmpty]. 1502 * list, depending on the value of [nullIfEmpty].
1530 */ 1503 */
1531 List<ChangeNotice> _getChangeNotices(bool nullIfEmpty) { 1504 List<ChangeNotice> _getChangeNotices(bool nullIfEmpty) {
1532 if (_pendingNotices.isEmpty) { 1505 if (_pendingNotices.isEmpty) {
1533 if (nullIfEmpty) { 1506 if (nullIfEmpty) {
1534 return null; 1507 return null;
1535 } 1508 }
1536 return ChangeNoticeImpl.EMPTY_LIST; 1509 return ChangeNoticeImpl.EMPTY_LIST;
1537 } 1510 }
1538 List<ChangeNotice> notices = new List.from(_pendingNotices.values); 1511 List<ChangeNotice> notices = new List.from(_pendingNotices.values);
1539 _pendingNotices.clear(); 1512 _pendingNotices.clear();
1540 return notices; 1513 return notices;
1541 } 1514 }
1542 1515
1543 /** 1516 /**
1517 * Return a [CompilationUnit] for the given library and unit sources, which
1518 * can be incrementally resolved.
1519 */
1520 CompilationUnit _getIncrementallyResolvableUnit(
1521 Source librarySource, Source unitSource) {
1522 LibrarySpecificUnit target =
1523 new LibrarySpecificUnit(librarySource, unitSource);
1524 for (ResultDescriptor<CompilationUnit> result in [
1525 RESOLVED_UNIT,
1526 RESOLVED_UNIT12,
1527 RESOLVED_UNIT11,
1528 RESOLVED_UNIT10,
1529 RESOLVED_UNIT9,
1530 RESOLVED_UNIT8
1531 ]) {
1532 CompilationUnit unit = getResult(target, result);
1533 if (unit != null) {
1534 return unit;
1535 }
1536 }
1537 return null;
1538 }
1539
1540 /**
1544 * Return a list containing all of the sources known to this context that have 1541 * Return a list containing all of the sources known to this context that have
1545 * the given [kind]. 1542 * the given [kind].
1546 */ 1543 */
1547 List<Source> _getSources(SourceKind kind) { 1544 List<Source> _getSources(SourceKind kind) {
1548 List<Source> sources = <Source>[]; 1545 List<Source> sources = <Source>[];
1549 if (kind == SourceKind.LIBRARY || kind == SourceKind.PART) { 1546 if (kind == SourceKind.LIBRARY || kind == SourceKind.PART) {
1550 for (Source source in _cache.sources) { 1547 for (Source source in _cache.sources) {
1551 CacheEntry entry = _cache.get(source); 1548 CacheEntry entry = _cache.get(source);
1552 if (entry.getValue(SOURCE_KIND) == kind) { 1549 if (entry.getValue(SOURCE_KIND) == kind) {
1553 sources.add(source); 1550 sources.add(source);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
1631 CacheEntry unitEntry = 1628 CacheEntry unitEntry =
1632 _cache.get(new LibrarySpecificUnit(librarySource, source)); 1629 _cache.get(new LibrarySpecificUnit(librarySource, source));
1633 state = unitEntry.getState(RESOLVED_UNIT); 1630 state = unitEntry.getState(RESOLVED_UNIT);
1634 if (state == CacheState.INVALID || 1631 if (state == CacheState.INVALID ||
1635 (isPriority && state == CacheState.FLUSHED)) { 1632 (isPriority && state == CacheState.FLUSHED)) {
1636 sources.add(source); 1633 sources.add(source);
1637 return; 1634 return;
1638 } else if (state == CacheState.ERROR) { 1635 } else if (state == CacheState.ERROR) {
1639 return; 1636 return;
1640 } 1637 }
1641 if (shouldErrorsBeAnalyzed(source, unitEntry)) { 1638 if (shouldErrorsBeAnalyzed(source)) {
1642 state = unitEntry.getState(VERIFY_ERRORS); 1639 state = unitEntry.getState(VERIFY_ERRORS);
1643 if (state == CacheState.INVALID || 1640 if (state == CacheState.INVALID ||
1644 (isPriority && state == CacheState.FLUSHED)) { 1641 (isPriority && state == CacheState.FLUSHED)) {
1645 sources.add(source); 1642 sources.add(source);
1646 return; 1643 return;
1647 } else if (state == CacheState.ERROR) { 1644 } else if (state == CacheState.ERROR) {
1648 return; 1645 return;
1649 } 1646 }
1650 if (hintsEnabled) { 1647 if (hintsEnabled) {
1651 state = unitEntry.getState(HINTS); 1648 state = unitEntry.getState(HINTS);
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1698 * given [source] has been updated to the given [errors]. 1695 * given [source] has been updated to the given [errors].
1699 */ 1696 */
1700 void _notifyErrors( 1697 void _notifyErrors(
1701 Source source, List<AnalysisError> errors, LineInfo lineInfo) { 1698 Source source, List<AnalysisError> errors, LineInfo lineInfo) {
1702 int count = _listeners.length; 1699 int count = _listeners.length;
1703 for (int i = 0; i < count; i++) { 1700 for (int i = 0; i < count; i++) {
1704 _listeners[i].computedErrors(this, source, errors, lineInfo); 1701 _listeners[i].computedErrors(this, source, errors, lineInfo);
1705 } 1702 }
1706 } 1703 }
1707 1704
1705 bool _referencesDartHtml(Source librarySource) {
1706 Source htmlSource = sourceFactory.forUri(DartSdk.DART_HTML);
1707 Set<Source> checkedSources = new Set<Source>();
1708 bool _refHtml(Source source) {
1709 if (!checkedSources.add(source)) {
1710 return false;
1711 }
1712 if (source == htmlSource) {
1713 return true;
1714 }
1715 LibraryElement library = _cache.getValue(source, LIBRARY_ELEMENT);
1716 if (library != null) {
1717 return library.importedLibraries.any((x) => _refHtml(x.source)) ||
1718 library.exportedLibraries.any((x) => _refHtml(x.source));
1719 }
1720 return false;
1721 }
1722
1723 return _refHtml(librarySource);
1724 }
1725
1708 void _removeFromCache(Source source) { 1726 void _removeFromCache(Source source) {
1709 CacheEntry entry = _cache.remove(source); 1727 CacheEntry entry = _cache.remove(source);
1710 if (entry != null && !entry.explicitlyAdded) { 1728 if (entry != null && !entry.explicitlyAdded) {
1711 _implicitAnalysisEventsController 1729 _implicitAnalysisEventsController
1712 .add(new ImplicitAnalysisEvent(source, false)); 1730 .add(new ImplicitAnalysisEvent(source, false));
1713 } 1731 }
1714 } 1732 }
1715 1733
1716 /** 1734 /**
1717 * Remove the given [source] from the priority order if it is in the list. 1735 * Remove the given [source] from the priority order if it is in the list.
1718 */ 1736 */
1719 void _removeFromPriorityOrder(Source source) { 1737 void _removeFromPriorityOrder(Source source) {
1720 int count = _priorityOrder.length; 1738 int count = _priorityOrder.length;
1721 List<Source> newOrder = <Source>[]; 1739 List<Source> newOrder = <Source>[];
1722 for (int i = 0; i < count; i++) { 1740 for (int i = 0; i < count; i++) {
1723 if (_priorityOrder[i] != source) { 1741 if (_priorityOrder[i] != source) {
1724 newOrder.add(_priorityOrder[i]); 1742 newOrder.add(_priorityOrder[i]);
1725 } 1743 }
1726 } 1744 }
1727 if (newOrder.length < count) { 1745 if (newOrder.length < count) {
1728 analysisPriorityOrder = newOrder; 1746 analysisPriorityOrder = newOrder;
1729 } 1747 }
1730 } 1748 }
1731 1749
1732 /** 1750 /**
1733 * Create an entry for the newly added [source] and invalidate any sources 1751 * Create an entry for the newly added [source] and invalidate any sources
1734 * that referenced the source before it existed. 1752 * that referenced the source before it existed.
1735 */ 1753 */
1736 void _sourceAvailable(Source source) { 1754 void _sourceAvailable(Source source) {
1755 driver.reset();
1737 // TODO(brianwilkerson) This method needs to check whether the source was 1756 // TODO(brianwilkerson) This method needs to check whether the source was
1738 // previously being implicitly analyzed. If so, the cache entry needs to be 1757 // previously being implicitly analyzed. If so, the cache entry needs to be
1739 // update to reflect the new status and an event needs to be generated to 1758 // update to reflect the new status and an event needs to be generated to
1740 // inform clients that it is no longer being implicitly analyzed. 1759 // inform clients that it is no longer being implicitly analyzed.
1741 CacheEntry entry = _cache.get(source); 1760 CacheEntry entry = _cache.get(source);
1742 if (entry == null) { 1761 if (entry == null) {
1743 _createCacheEntry(source, true); 1762 _createCacheEntry(source, true);
1744 } else { 1763 } else {
1764 entry.explicitlyAdded = true;
1745 entry.modificationTime = getModificationStamp(source); 1765 entry.modificationTime = getModificationStamp(source);
1746 entry.setState(CONTENT, CacheState.INVALID); 1766 entry.setState(CONTENT, CacheState.INVALID);
1767 entry.setState(MODIFICATION_TIME, CacheState.INVALID);
1747 } 1768 }
1748 } 1769 }
1749 1770
1750 /** 1771 /**
1751 * Invalidate the [source] that was changed and any sources that referenced 1772 * Invalidate the [source] that was changed and any sources that referenced
1752 * the source before it existed. 1773 * the source before it existed.
1774 *
1775 * Note: source may be considered "changed" if it was previously missing,
1776 * but pointed to by an import or export directive.
1753 */ 1777 */
1754 void _sourceChanged(Source source) { 1778 void _sourceChanged(Source source, {bool compareWithOld: true}) {
1755 CacheEntry entry = _cache.get(source); 1779 CacheEntry entry = _cache.get(source);
1756 // If the source is removed, we don't care about it. 1780 // If the source has no cache entry, there is nothing to invalidate.
1757 if (entry == null) { 1781 if (entry == null) {
1758 return; 1782 return;
1759 } 1783 }
1760 // Check whether the content of the source is the same as it was the last 1784
1761 // time. 1785 String oldContents = compareWithOld ? entry.getValue(CONTENT) : null;
1762 String sourceContent = entry.getValue(CONTENT); 1786
1763 if (sourceContent != null) { 1787 // Flush so that from now on we will get new contents.
1764 entry.setState(CONTENT, CacheState.FLUSHED); 1788 // (For example, in getLibrariesContaining.)
1765 try { 1789 entry.setState(CONTENT, CacheState.FLUSHED);
1766 TimestampedData<String> fileContents = getContents(source); 1790
1767 if (fileContents.data == sourceContent) { 1791 // Prepare the new contents.
1768 int time = fileContents.modificationTime; 1792 TimestampedData<String> fileContents;
1769 for (CacheEntry entry in _entriesFor(source)) { 1793 try {
1770 entry.modificationTime = time; 1794 fileContents = getContents(source);
1771 } 1795 } catch (e) {}
1772 return; 1796
1773 } 1797 // Update 'modificationTime' - we are going to update the entry.
1774 } catch (e) { 1798 {
1775 entry.modificationTime = -1; 1799 int time = fileContents?.modificationTime ?? -1;
1800 for (CacheEntry entry in _entriesFor(source)) {
1801 entry.modificationTime = time;
1776 } 1802 }
1777 } 1803 }
1804
1805 // Fast path if the contents is the same as it was last time.
1806 if (oldContents != null && fileContents?.data == oldContents) {
1807 return;
1808 }
1809
1810 // We're going to update the cache, so reset the driver.
1811 driver.reset();
1812
1778 // We need to invalidate the cache. 1813 // We need to invalidate the cache.
1779 { 1814 {
1780 Object delta = null; 1815 if (analysisOptions.finerGrainedInvalidation &&
1781 if (AnalysisEngine.instance.limitInvalidationInTaskModel &&
1782 AnalysisEngine.isDartFileName(source.fullName)) { 1816 AnalysisEngine.isDartFileName(source.fullName)) {
1783 // TODO(scheglov) Incorrect implementation in general. 1817 // TODO(scheglov) Incorrect implementation in general.
1784 entry.setState(TOKEN_STREAM, CacheState.FLUSHED); 1818 entry.setState(TOKEN_STREAM, CacheState.FLUSHED);
1785 entry.setState(PARSED_UNIT, CacheState.FLUSHED); 1819 entry.setState(PARSED_UNIT, CacheState.FLUSHED);
1786 List<Source> librarySources = getLibrariesContaining(source); 1820 SourceKind sourceKind = getKindOf(source);
1787 if (librarySources.length == 1) { 1821 List<Source> partSources = getResult(source, INCLUDED_PARTS);
1788 Source librarySource = librarySources[0]; 1822 if (sourceKind == SourceKind.LIBRARY && partSources.isEmpty) {
1789 CompilationUnit oldUnit = 1823 Source librarySource = source;
1790 getResolvedCompilationUnit2(source, librarySource); 1824 // Try to find an old unit which has element model.
1825 CacheEntry unitEntry =
1826 getCacheEntry(new LibrarySpecificUnit(librarySource, source));
1827 CompilationUnit oldUnit = RESOLVED_UNIT_RESULTS
1828 .skipWhile((result) => result != RESOLVED_UNIT2)
1829 .map(unitEntry.getValue)
1830 .firstWhere((unit) => unit != null, orElse: () => null);
1831 // If we have the old unit, we can try to update it.
1791 if (oldUnit != null) { 1832 if (oldUnit != null) {
1792 CompilationUnit newUnit = parseCompilationUnit(source); 1833 // Safely parse the source.
1793 IncrementalCompilationUnitElementBuilder builder = 1834 CompilationUnit newUnit;
1794 new IncrementalCompilationUnitElementBuilder(oldUnit, newUnit); 1835 try {
1795 builder.build(); 1836 newUnit = parseCompilationUnit(source);
1796 CompilationUnitElementDelta unitDelta = builder.unitDelta; 1837 } catch (_) {
1797 if (!unitDelta.hasDirectiveChange) { 1838 // The source might have been removed by this time.
1798 DartDelta dartDelta = new DartDelta(source); 1839 // We cannot perform incremental invalidation.
1799 dartDelta.hasDirectiveChange = unitDelta.hasDirectiveChange; 1840 }
1800 unitDelta.addedDeclarations.forEach(dartDelta.elementAdded); 1841 // If the new unit was parsed successfully, continue.
1801 unitDelta.removedDeclarations.forEach(dartDelta.elementRemoved); 1842 if (newUnit != null) {
1802 // print( 1843 IncrementalCompilationUnitElementBuilder builder =
1803 // 'dartDelta: add=${dartDelta.addedNames} remove=${dartDelta.r emovedNames}'); 1844 new IncrementalCompilationUnitElementBuilder(
1804 delta = dartDelta; 1845 oldUnit, newUnit);
1805 entry.setState(CONTENT, CacheState.INVALID, delta: delta); 1846 builder.build();
1806 return; 1847 CompilationUnitElementDelta unitDelta = builder.unitDelta;
1848 if (!unitDelta.hasDirectiveChange) {
1849 unitEntry.setValueIncremental(
1850 COMPILATION_UNIT_CONSTANTS, builder.unitConstants, false);
1851 DartDelta dartDelta = new DartDelta(source);
1852 unitDelta.addedDeclarations.forEach(dartDelta.elementChanged);
1853 unitDelta.removedDeclarations.forEach(dartDelta.elementChanged);
1854 unitDelta.classDeltas.values.forEach(dartDelta.classChanged);
1855 entry.setState(CONTENT, CacheState.INVALID, delta: dartDelta);
1856 return;
1857 }
1807 } 1858 }
1808 } 1859 }
1809 } 1860 }
1810 } 1861 }
1811 entry.setState(CONTENT, CacheState.INVALID); 1862 entry.setState(CONTENT, CacheState.INVALID);
1863 entry.setState(MODIFICATION_TIME, CacheState.INVALID);
1864 entry.setState(SOURCE_KIND, CacheState.INVALID);
1812 } 1865 }
1813 for (WorkManager workManager in workManagers) { 1866 for (WorkManager workManager in workManagers) {
1814 workManager.applyChange( 1867 workManager.applyChange(
1815 Source.EMPTY_LIST, <Source>[source], Source.EMPTY_LIST); 1868 Source.EMPTY_LIST, <Source>[source], Source.EMPTY_LIST);
1816 } 1869 }
1817 } 1870 }
1818 1871
1819 /** 1872 /**
1820 * Record that the give [source] has been deleted.
1821 */
1822 void _sourceDeleted(Source source) {
1823 // TODO(brianwilkerson) Implement or remove this.
1824 // SourceEntry sourceEntry = _cache.get(source);
1825 // if (sourceEntry is HtmlEntry) {
1826 // HtmlEntry htmlEntry = sourceEntry;
1827 // htmlEntry.recordContentError(new CaughtException(
1828 // new AnalysisException("This source was marked as being deleted"),
1829 // null));
1830 // } else if (sourceEntry is DartEntry) {
1831 // DartEntry dartEntry = sourceEntry;
1832 // HashSet<Source> libraries = new HashSet<Source>();
1833 // for (Source librarySource in getLibrariesContaining(source)) {
1834 // libraries.add(librarySource);
1835 // for (Source dependentLibrary
1836 // in getLibrariesDependingOn(librarySource)) {
1837 // libraries.add(dependentLibrary);
1838 // }
1839 // }
1840 // for (Source librarySource in libraries) {
1841 // _invalidateLibraryResolution(librarySource);
1842 // }
1843 // dartEntry.recordContentError(new CaughtException(
1844 // new AnalysisException("This source was marked as being deleted"),
1845 // null));
1846 // }
1847 _removeFromPriorityOrder(source);
1848 }
1849
1850 /**
1851 * Record that the given [source] has been removed. 1873 * Record that the given [source] has been removed.
1852 */ 1874 */
1853 void _sourceRemoved(Source source) { 1875 void _sourceRemoved(Source source) {
1876 driver.reset();
1854 _removeFromCache(source); 1877 _removeFromCache(source);
1855 _removeFromPriorityOrder(source); 1878 _removeFromPriorityOrder(source);
1856 } 1879 }
1857 1880
1858 /** 1881 /**
1859 * TODO(scheglov) A hackish, limited incremental resolution implementation. 1882 * TODO(scheglov) A hackish, limited incremental resolution implementation.
1860 */ 1883 */
1861 bool _tryPoorMansIncrementalResolution(Source unitSource, String newCode) { 1884 bool _tryPoorMansIncrementalResolution(Source unitSource, String newCode) {
1862 return PerformanceStatistics.incrementalAnalysis.makeCurrentWhile(() { 1885 return PerformanceStatistics.incrementalAnalysis.makeCurrentWhile(() {
1863 incrementalResolutionValidation_lastUnitSource = null; 1886 incrementalResolutionValidation_lastUnitSource = null;
1864 incrementalResolutionValidation_lastLibrarySource = null; 1887 incrementalResolutionValidation_lastLibrarySource = null;
1865 incrementalResolutionValidation_lastUnit = null; 1888 incrementalResolutionValidation_lastUnit = null;
1866 // prepare the entry 1889 // prepare the source entry
1867 CacheEntry sourceEntry = _cache.get(unitSource); 1890 CacheEntry sourceEntry = _cache.get(unitSource);
1868 if (sourceEntry == null) { 1891 if (sourceEntry == null) {
1869 return false; 1892 return false;
1870 } 1893 }
1871 // prepare the (only) library source 1894 // prepare the (only) library source
1872 List<Source> librarySources = getLibrariesContaining(unitSource); 1895 List<Source> librarySources = getLibrariesContaining(unitSource);
1873 if (librarySources.length != 1) { 1896 if (librarySources.length != 1) {
1874 return false; 1897 return false;
1875 } 1898 }
1876 Source librarySource = librarySources[0]; 1899 Source librarySource = librarySources[0];
1900 // prepare the unit entry
1877 CacheEntry unitEntry = 1901 CacheEntry unitEntry =
1878 _cache.get(new LibrarySpecificUnit(librarySource, unitSource)); 1902 _cache.get(new LibrarySpecificUnit(librarySource, unitSource));
1879 if (unitEntry == null) { 1903 if (unitEntry == null) {
1880 return false; 1904 return false;
1881 } 1905 }
1882 // prepare the library element
1883 LibraryElement libraryElement = getLibraryElement(librarySource);
1884 if (libraryElement == null) {
1885 return false;
1886 }
1887 // prepare the existing unit 1906 // prepare the existing unit
1888 CompilationUnit oldUnit = 1907 CompilationUnit oldUnit =
1889 getResolvedCompilationUnit2(unitSource, librarySource); 1908 _getIncrementallyResolvableUnit(librarySource, unitSource);
1890 if (oldUnit == null) { 1909 if (oldUnit == null) {
1891 return false; 1910 return false;
1892 } 1911 }
1893 // do resolution 1912 // do resolution
1894 Stopwatch perfCounter = new Stopwatch()..start(); 1913 Stopwatch perfCounter = new Stopwatch()..start();
1895 PoorMansIncrementalResolver resolver = new PoorMansIncrementalResolver( 1914 PoorMansIncrementalResolver resolver = new PoorMansIncrementalResolver(
1896 typeProvider, 1915 typeProvider,
1897 unitSource, 1916 unitSource,
1898 null, 1917 _cache,
1899 sourceEntry, 1918 sourceEntry,
1900 unitEntry, 1919 unitEntry,
1901 oldUnit, 1920 oldUnit,
1902 analysisOptions.incrementalApi); 1921 analysisOptions.incrementalApi);
1903 bool success = resolver.resolve(newCode); 1922 bool success = resolver.resolve(newCode);
1904 AnalysisEngine.instance.instrumentationService.logPerformance( 1923 AnalysisEngine.instance.instrumentationService.logPerformance(
1905 AnalysisPerformanceKind.INCREMENTAL, 1924 AnalysisPerformanceKind.INCREMENTAL,
1906 perfCounter, 1925 perfCounter,
1907 'success=$success,context_id=$_id,code_length=${newCode.length}'); 1926 'success=$success,context_id=$_id,code_length=${newCode.length}');
1908 if (!success) { 1927 if (!success) {
(...skipping 10 matching lines...) Expand all
1919 // prepare notice 1938 // prepare notice
1920 { 1939 {
1921 ChangeNoticeImpl notice = getNotice(unitSource); 1940 ChangeNoticeImpl notice = getNotice(unitSource);
1922 notice.resolvedDartUnit = oldUnit; 1941 notice.resolvedDartUnit = oldUnit;
1923 AnalysisErrorInfo errorInfo = getErrors(unitSource); 1942 AnalysisErrorInfo errorInfo = getErrors(unitSource);
1924 notice.setErrors(errorInfo.errors, errorInfo.lineInfo); 1943 notice.setErrors(errorInfo.errors, errorInfo.lineInfo);
1925 } 1944 }
1926 // schedule 1945 // schedule
1927 dartWorkManager.unitIncrementallyResolved(librarySource, unitSource); 1946 dartWorkManager.unitIncrementallyResolved(librarySource, unitSource);
1928 // OK 1947 // OK
1948 driver.reset();
1929 return true; 1949 return true;
1930 }); 1950 });
1931 } 1951 }
1932 } 1952 }
1933 1953
1934 /** 1954 /**
1955 * A helper class used to create futures for [AnalysisContextImpl].
1956 * Using a helper class allows us to preserve the generic parameter T.
1957 */
1958 class AnalysisFutureHelper<T> {
1959 final AnalysisContextImpl _context;
1960 final AnalysisTarget _target;
1961 final ResultDescriptor<T> _descriptor;
1962
1963 AnalysisFutureHelper(this._context, this._target, this._descriptor);
1964
1965 /**
1966 * Return a future that will be completed with the result specified
1967 * in the constructor. If the result is cached, the future will be
1968 * completed immediately with the resulting value. If not, then
1969 * analysis is scheduled that will produce the required result.
1970 * If the result cannot be generated, then the future will be completed with
1971 * the error AnalysisNotScheduledError.
1972 */
1973 CancelableFuture<T> computeAsync() {
1974 if (_context.isDisposed) {
1975 // No further analysis is expected, so return a future that completes
1976 // immediately with AnalysisNotScheduledError.
1977 return new CancelableFuture.error(new AnalysisNotScheduledError());
1978 }
1979 CacheEntry entry = _context.getCacheEntry(_target);
1980 PendingFuture<T> pendingFuture =
1981 new PendingFuture<T>(_context, _target, (CacheEntry entry) {
1982 CacheState state = entry.getState(_descriptor);
1983 if (state == CacheState.ERROR) {
1984 throw entry.exception;
1985 } else if (state == CacheState.INVALID) {
1986 return null;
1987 }
1988 return entry.getValue(_descriptor);
1989 });
1990 if (!pendingFuture.evaluate(entry)) {
1991 _context._pendingFutureTargets
1992 .putIfAbsent(_target, () => <PendingFuture>[])
1993 .add(pendingFuture);
1994 _context.dartWorkManager.addPriorityResult(_target, _descriptor);
1995 }
1996 return pendingFuture.future;
1997 }
1998 }
1999
2000 class CacheConsistencyValidatorImpl implements CacheConsistencyValidator {
2001 final AnalysisContextImpl context;
2002
2003 CacheConsistencyValidatorImpl(this.context);
2004
2005 @override
2006 List<Source> getSourcesToComputeModificationTimes() {
2007 return context._privatePartition.sources.toList();
2008 }
2009
2010 @override
2011 bool sourceModificationTimesComputed(List<Source> sources, List<int> times) {
2012 Stopwatch timer = new Stopwatch()..start();
2013 HashSet<Source> changedSources = new HashSet<Source>();
2014 HashSet<Source> removedSources = new HashSet<Source>();
2015 for (int i = 0; i < sources.length; i++) {
2016 Source source = sources[i];
2017 // When a source is in the content cache,
2018 // its modification time in the file system does not matter.
2019 if (context._contentCache.getModificationStamp(source) != null) {
2020 continue;
2021 }
2022 // When we were not able to compute the modification time in the
2023 // file system, there is nothing to compare with, so skip the source.
2024 int sourceTime = times[i];
2025 if (sourceTime == null) {
2026 continue;
2027 }
2028 // Compare with the modification time in the cache entry.
2029 CacheEntry entry = context._privatePartition.get(source);
2030 if (entry != null) {
2031 if (entry.modificationTime != sourceTime) {
2032 if (sourceTime == -1) {
2033 removedSources.add(source);
2034 PerformanceStatistics
2035 .cacheConsistencyValidationStatistics.numOfRemoved++;
2036 } else {
2037 changedSources.add(source);
2038 PerformanceStatistics
2039 .cacheConsistencyValidationStatistics.numOfChanged++;
2040 }
2041 }
2042 }
2043 }
2044 for (Source source in changedSources) {
2045 context._sourceChanged(source);
2046 }
2047 for (Source source in removedSources) {
2048 context._sourceRemoved(source);
2049 }
2050 if (changedSources.length > 0 || removedSources.length > 0) {
2051 StringBuffer buffer = new StringBuffer();
2052 buffer.write("Consistency check took ");
2053 buffer.write(timer.elapsedMilliseconds);
2054 buffer.writeln(" ms and found");
2055 buffer.write(" ");
2056 buffer.write(changedSources.length);
2057 buffer.writeln(" changed sources");
2058 buffer.write(" ");
2059 buffer.write(removedSources.length);
2060 buffer.write(" removed sources.");
2061 context._logInformation(buffer.toString());
2062 }
2063 return changedSources.isNotEmpty || removedSources.isNotEmpty;
2064 }
2065 }
2066
2067 /**
1935 * An object that manages the partitions that can be shared between analysis 2068 * An object that manages the partitions that can be shared between analysis
1936 * contexts. 2069 * contexts.
1937 */ 2070 */
1938 class PartitionManager { 2071 class PartitionManager {
1939 /** 2072 /**
1940 * A table mapping SDK's to the partitions used for those SDK's. 2073 * A table mapping SDK's to the partitions used for those SDK's.
1941 */ 2074 */
1942 HashMap<DartSdk, SdkCachePartition> _sdkPartitions = 2075 HashMap<DartSdk, SdkCachePartition> _sdkPartitions =
1943 new HashMap<DartSdk, SdkCachePartition>(); 2076 new HashMap<DartSdk, SdkCachePartition>();
1944 2077
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
2045 _completer.completeError(exception, stackTrace); 2178 _completer.completeError(exception, stackTrace);
2046 } 2179 }
2047 } 2180 }
2048 2181
2049 void _onCancel() { 2182 void _onCancel() {
2050 _context._cancelFuture(this); 2183 _context._cancelFuture(this);
2051 } 2184 }
2052 } 2185 }
2053 2186
2054 /** 2187 /**
2188 * Provider for analysis results.
2189 */
2190 abstract class ResultProvider {
2191 /**
2192 * This method is invoked by an [InternalAnalysisContext] when the state of
2193 * the [result] of the [entry] is [CacheState.INVALID], so it is about to be
2194 * computed.
2195 *
2196 * If the provider knows how to provide the value, it sets the value into
2197 * the [entry] with all required dependencies, and returns `true`.
2198 *
2199 * Otherwise, it returns `false` to indicate that the result should be
2200 * computed as usually.
2201 */
2202 bool compute(CacheEntry entry, ResultDescriptor result);
2203 }
2204
2205 /**
2055 * An [AnalysisContext] that only contains sources for a Dart SDK. 2206 * An [AnalysisContext] that only contains sources for a Dart SDK.
2056 */ 2207 */
2057 class SdkAnalysisContext extends AnalysisContextImpl { 2208 class SdkAnalysisContext extends AnalysisContextImpl {
2209 /**
2210 * Initialize a newly created SDK analysis context with the given [options].
2211 * Analysis options cannot be changed afterwards. If the given [options] are
2212 * `null`, then default options are used.
2213 */
2214 SdkAnalysisContext(AnalysisOptions options) {
2215 if (options != null) {
2216 super.analysisOptions = options;
2217 }
2218 }
2219
2220 @override
2221 void set analysisOptions(AnalysisOptions options) {
2222 throw new StateError('AnalysisOptions of SDK context cannot be changed.');
2223 }
2224
2058 @override 2225 @override
2059 AnalysisCache createCacheFromSourceFactory(SourceFactory factory) { 2226 AnalysisCache createCacheFromSourceFactory(SourceFactory factory) {
2060 if (factory == null) { 2227 if (factory == null) {
2061 return super.createCacheFromSourceFactory(factory); 2228 return super.createCacheFromSourceFactory(factory);
2062 } 2229 }
2063 DartSdk sdk = factory.dartSdk; 2230 DartSdk sdk = factory.dartSdk;
2064 if (sdk == null) { 2231 if (sdk == null) {
2065 throw new IllegalArgumentException( 2232 throw new ArgumentError(
2066 "The source factory for an SDK analysis context must have a DartUriRes olver"); 2233 "The source factory for an SDK analysis context must have a DartUriRes olver");
2067 } 2234 }
2068 return new AnalysisCache(<CachePartition>[ 2235 return new AnalysisCache(
2069 AnalysisEngine.instance.partitionManager_new.forSdk(sdk) 2236 <CachePartition>[AnalysisEngine.instance.partitionManager.forSdk(sdk)]);
2070 ]);
2071 } 2237 }
2072 } 2238 }
2073
2074 /**
2075 * A helper class used to create futures for [AnalysisContextImpl].
2076 * Using a helper class allows us to preserve the generic parameter T.
2077 */
2078 class _AnalysisFutureHelper<T> {
2079 final AnalysisContextImpl _context;
2080
2081 _AnalysisFutureHelper(this._context);
2082
2083 /**
2084 * Return a future that will be completed with the result of calling
2085 * [computeValue]. If [computeValue] returns non-`null`, the future will be
2086 * completed immediately with the resulting value. If it returns `null`, then
2087 * [scheduleComputation] is invoked to schedule analysis that will produce
2088 * the required result, and [computeValue] will be re-executed in the future,
2089 * after the next time the cached information for [target] has changed. If
2090 * [computeValue] throws an exception, the future will fail with that
2091 * exception.
2092 *
2093 * If the [computeValue] still returns `null` after there is no further
2094 * analysis to be done for [target], then the future will be completed with
2095 * the error AnalysisNotScheduledError.
2096 *
2097 * Since [computeValue] will be called while the state of analysis is being
2098 * updated, it should be free of side effects so that it doesn't cause
2099 * reentrant changes to the analysis state.
2100 */
2101 CancelableFuture<T> computeAsync(AnalysisTarget target,
2102 T computeValue(CacheEntry entry), void scheduleComputation()) {
2103 if (_context.isDisposed) {
2104 // No further analysis is expected, so return a future that completes
2105 // immediately with AnalysisNotScheduledError.
2106 return new CancelableFuture.error(new AnalysisNotScheduledError());
2107 }
2108 CacheEntry entry = _context.getCacheEntry(target);
2109 PendingFuture pendingFuture =
2110 new PendingFuture<T>(_context, target, computeValue);
2111 if (!pendingFuture.evaluate(entry)) {
2112 _context._pendingFutureTargets
2113 .putIfAbsent(target, () => <PendingFuture>[])
2114 .add(pendingFuture);
2115 scheduleComputation();
2116 }
2117 return pendingFuture.future;
2118 }
2119 }
OLDNEW
« no previous file with comments | « packages/analyzer/lib/src/context/cache.dart ('k') | packages/analyzer/lib/src/context/source.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698