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

Side by Side Diff: analyzer/lib/src/task/dart_work_manager.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « analyzer/lib/src/task/dart.dart ('k') | analyzer/lib/src/task/driver.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library analyzer.src.task.dart_work_manager;
6
7 import 'dart:collection';
8
9 import 'package:analyzer/src/context/cache.dart';
10 import 'package:analyzer/src/generated/engine.dart'
11 show
12 AnalysisEngine,
13 AnalysisErrorInfo,
14 AnalysisErrorInfoImpl,
15 AnalysisOptions,
16 CacheState,
17 InternalAnalysisContext;
18 import 'package:analyzer/src/generated/error.dart';
19 import 'package:analyzer/src/generated/source.dart';
20 import 'package:analyzer/src/generated/utilities_collection.dart';
21 import 'package:analyzer/src/task/dart.dart';
22 import 'package:analyzer/src/task/driver.dart';
23 import 'package:analyzer/task/dart.dart';
24 import 'package:analyzer/task/general.dart';
25 import 'package:analyzer/task/model.dart';
26
27 /**
28 * The manager for Dart specific analysis.
29 */
30 class DartWorkManager implements WorkManager {
31 /**
32 * The list of errors that are reported for raw Dart [Source]s.
33 */
34 static final List<ResultDescriptor> _SOURCE_ERRORS = <ResultDescriptor>[
35 BUILD_DIRECTIVES_ERRORS,
36 BUILD_LIBRARY_ERRORS,
37 PARSE_ERRORS,
38 SCAN_ERRORS
39 ];
40
41 /**
42 * The list of errors that are reported for raw Dart [LibrarySpecificUnit]s.
43 */
44 static final List<ResultDescriptor> _UNIT_ERRORS = <ResultDescriptor>[
45 HINTS,
46 RESOLVE_REFERENCES_ERRORS,
47 RESOLVE_TYPE_NAMES_ERRORS,
48 VARIABLE_REFERENCE_ERRORS,
49 VERIFY_ERRORS
50 ];
51
52 final InternalAnalysisContext context;
53
54 /**
55 * The [TargetedResult]s that should be computed with priority.
56 */
57 final LinkedHashSet<TargetedResult> priorityResultQueue =
58 new LinkedHashSet<TargetedResult>();
59
60 /**
61 * The sources whose kind we don't know yet.
62 */
63 final LinkedHashSet<Source> unknownSourceQueue = new LinkedHashSet<Source>();
64
65 /**
66 * The queue of library sources to process.
67 */
68 final LinkedHashSet<Source> librarySourceQueue = new LinkedHashSet<Source>();
69
70 /**
71 * A table mapping library sources to the part sources they include.
72 */
73 final HashMap<Source, List<Source>> libraryPartsMap =
74 new HashMap<Source, List<Source>>();
75
76 /**
77 * A table mapping part sources to the library sources that include them.
78 */
79 final HashMap<Source, List<Source>> partLibrariesMap =
80 new HashMap<Source, List<Source>>();
81
82 /**
83 * Initialize a newly created manager.
84 */
85 DartWorkManager(this.context) {
86 analysisCache.onResultInvalidated.listen((InvalidatedResult event) {
87 if (event.descriptor == LIBRARY_ERRORS_READY) {
88 CacheEntry entry = event.entry;
89 if (entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY) {
90 librarySourceQueue.add(entry.target);
91 }
92 }
93 });
94 }
95
96 /**
97 * Returns the correctly typed result of `context.analysisCache`.
98 */
99 AnalysisCache get analysisCache => context.analysisCache;
100
101 /**
102 * The partition that contains analysis results that are not shared with other
103 * contexts.
104 */
105 CachePartition get privateAnalysisCachePartition =>
106 context.privateAnalysisCachePartition;
107
108 /**
109 * Specifies that the client want the given [result] of the given [target]
110 * to be computed with priority.
111 */
112 void addPriorityResult(AnalysisTarget target, ResultDescriptor result) {
113 priorityResultQueue.add(new TargetedResult(target, result));
114 }
115
116 /**
117 * Notifies the manager about changes in the explicit source list.
118 */
119 void applyChange(List<Source> addedSources, List<Source> changedSources,
120 List<Source> removedSources) {
121 addedSources = addedSources.where(_isDartSource).toList();
122 changedSources = changedSources.where(_isDartSource).toList();
123 removedSources = removedSources.where(_isDartSource).toList();
124 // unknown queue
125 unknownSourceQueue.addAll(addedSources);
126 unknownSourceQueue.addAll(changedSources);
127 unknownSourceQueue.removeAll(removedSources);
128 // library queue
129 librarySourceQueue.removeAll(changedSources);
130 librarySourceQueue.removeAll(removedSources);
131 // parts in libraries
132 for (Source changedSource in changedSources) {
133 _onLibrarySourceChangedOrRemoved(changedSource);
134 }
135 for (Source removedSource in removedSources) {
136 partLibrariesMap.remove(removedSource);
137 _onLibrarySourceChangedOrRemoved(removedSource);
138 }
139 }
140
141 @override
142 void applyPriorityTargets(List<AnalysisTarget> targets) {
143 // Unschedule the old targets.
144 List<TargetedResult> resultsToUnschedule = <TargetedResult>[];
145 for (TargetedResult result in priorityResultQueue) {
146 if (result.result == LIBRARY_ERRORS_READY) {
147 resultsToUnschedule.add(result);
148 }
149 }
150 priorityResultQueue.removeAll(resultsToUnschedule);
151 // Schedule new targets.
152 for (AnalysisTarget target in targets) {
153 if (_isDartSource(target)) {
154 SourceKind sourceKind = analysisCache.getValue(target, SOURCE_KIND);
155 if (sourceKind == SourceKind.UNKNOWN) {
156 addPriorityResult(target, SOURCE_KIND);
157 } else if (sourceKind == SourceKind.LIBRARY) {
158 _schedulePriorityLibrarySourceAnalysis(target);
159 } else if (sourceKind == SourceKind.PART) {
160 List<Source> libraries = context.getLibrariesContaining(target);
161 for (Source library in libraries) {
162 addPriorityResult(library, LIBRARY_ERRORS_READY);
163 }
164 }
165 }
166 }
167 }
168
169 /**
170 * Return an [AnalysisErrorInfo] containing the list of all of the errors and
171 * the line info associated with the given [source]. The list of errors will
172 * be empty if the source is not known to the context or if there are no
173 * errors in the source. The errors contained in the list can be incomplete.
174 */
175 AnalysisErrorInfo getErrors(Source source) {
176 if (analysisCache.getState(source, DART_ERRORS) == CacheState.VALID) {
177 List<AnalysisError> errors = analysisCache.getValue(source, DART_ERRORS);
178 LineInfo lineInfo = analysisCache.getValue(source, LINE_INFO);
179 return new AnalysisErrorInfoImpl(errors, lineInfo);
180 }
181 List<AnalysisError> errors = <AnalysisError>[];
182 for (ResultDescriptor descriptor in _SOURCE_ERRORS) {
183 errors.addAll(analysisCache.getValue(source, descriptor));
184 }
185 for (Source library in context.getLibrariesContaining(source)) {
186 LibrarySpecificUnit unit = new LibrarySpecificUnit(library, source);
187 for (ResultDescriptor descriptor in _UNIT_ERRORS) {
188 errors.addAll(analysisCache.getValue(unit, descriptor));
189 }
190 }
191 LineInfo lineInfo = analysisCache.getValue(source, LINE_INFO);
192 return new AnalysisErrorInfoImpl(errors, lineInfo);
193 }
194
195 /**
196 * Returns libraries containing the given [part].
197 * Maybe empty, but not null.
198 */
199 List<Source> getLibrariesContainingPart(Source part) {
200 List<Source> libraries = partLibrariesMap[part];
201 return libraries != null ? libraries : Source.EMPTY_LIST;
202 }
203
204 @override
205 TargetedResult getNextResult() {
206 // Try to find a priority result to compute.
207 while (priorityResultQueue.isNotEmpty) {
208 TargetedResult result = priorityResultQueue.first;
209 if (!_needsComputing(result.target, result.result)) {
210 priorityResultQueue.remove(result);
211 continue;
212 }
213 return result;
214 }
215 // Try to find a new library to analyze.
216 while (librarySourceQueue.isNotEmpty) {
217 Source librarySource = librarySourceQueue.first;
218 // Maybe done with this library.
219 if (!_needsComputing(librarySource, LIBRARY_ERRORS_READY)) {
220 librarySourceQueue.remove(librarySource);
221 continue;
222 }
223 // Analyze this library.
224 return new TargetedResult(librarySource, LIBRARY_ERRORS_READY);
225 }
226 // No libraries in the queue, check whether there are sources to organize.
227 while (unknownSourceQueue.isNotEmpty) {
228 Source source = unknownSourceQueue.first;
229 // Maybe done with this source.
230 if (!_needsComputing(source, SOURCE_KIND)) {
231 unknownSourceQueue.remove(source);
232 continue;
233 }
234 // Compute the kind of this source.
235 return new TargetedResult(source, SOURCE_KIND);
236 }
237 // TODO(scheglov) Report errors for parts that remained in the queue after
238 // all libraries had been processed.
239 // No results to compute.
240 return null;
241 }
242
243 @override
244 WorkOrderPriority getNextResultPriority() {
245 if (priorityResultQueue.isNotEmpty) {
246 return WorkOrderPriority.PRIORITY;
247 }
248 if (unknownSourceQueue.isNotEmpty || librarySourceQueue.isNotEmpty) {
249 return WorkOrderPriority.NORMAL;
250 }
251 return WorkOrderPriority.NONE;
252 }
253
254 /**
255 * Notifies the manager about analysis options changes.
256 */
257 void onAnalysisOptionsChanged() {
258 _invalidateAllLocalResolutionInformation(false);
259 }
260
261 /**
262 * Notifies the manager about [SourceFactory] changes.
263 */
264 void onSourceFactoryChanged() {
265 _invalidateAllLocalResolutionInformation(true);
266 }
267
268 @override
269 void resultsComputed(
270 AnalysisTarget target, Map<ResultDescriptor, dynamic> outputs) {
271 // Organize sources.
272 if (_isDartSource(target)) {
273 Source source = target;
274 SourceKind kind = outputs[SOURCE_KIND];
275 if (kind != null) {
276 unknownSourceQueue.remove(source);
277 if (kind == SourceKind.LIBRARY) {
278 if (context.prioritySources.contains(source)) {
279 _schedulePriorityLibrarySourceAnalysis(source);
280 } else {
281 bool needErrors = _shouldErrorsBeComputed(source);
282 if (needErrors) {
283 librarySourceQueue.add(target);
284 }
285 }
286 }
287 }
288 }
289 // Update parts in libraries.
290 if (_isDartSource(target)) {
291 Source library = target;
292 List<Source> includedParts = outputs[INCLUDED_PARTS];
293 if (includedParts != null) {
294 libraryPartsMap[library] = includedParts;
295 for (Source part in includedParts) {
296 List<Source> libraries =
297 partLibrariesMap.putIfAbsent(part, () => <Source>[]);
298 if (!libraries.contains(library)) {
299 libraries.add(library);
300 _invalidateContainingLibraries(part);
301 }
302 }
303 }
304 }
305 // Update notice.
306 if (_isDartSource(target)) {
307 bool shouldSetErrors = false;
308 outputs.forEach((ResultDescriptor descriptor, value) {
309 if (descriptor == PARSED_UNIT && value != null) {
310 context.getNotice(target).parsedDartUnit = value;
311 shouldSetErrors = true;
312 }
313 if (descriptor == DART_ERRORS) {
314 shouldSetErrors = true;
315 }
316 });
317 if (shouldSetErrors) {
318 AnalysisErrorInfo info = getErrors(target);
319 context.getNotice(target).setErrors(info.errors, info.lineInfo);
320 }
321 }
322 if (target is LibrarySpecificUnit) {
323 Source source = target.source;
324 bool shouldSetErrors = false;
325 outputs.forEach((ResultDescriptor descriptor, value) {
326 if (descriptor == RESOLVED_UNIT && value != null) {
327 context.getNotice(source).resolvedDartUnit = value;
328 shouldSetErrors = true;
329 }
330 });
331 if (shouldSetErrors) {
332 AnalysisErrorInfo info = getErrors(source);
333 context.getNotice(source).setErrors(info.errors, info.lineInfo);
334 }
335 }
336 }
337
338 void unitIncrementallyResolved(Source librarySource, Source unitSource) {
339 librarySourceQueue.add(librarySource);
340 }
341
342 /**
343 * Invalidate all of the resolution results computed by this context. The flag
344 * [invalidateUris] should be `true` if the cached results of converting URIs
345 * to source files should also be invalidated.
346 */
347 void _invalidateAllLocalResolutionInformation(bool invalidateUris) {
348 CachePartition partition = privateAnalysisCachePartition;
349 // Prepare targets and values to invalidate.
350 List<Source> dartSources = <Source>[];
351 List<LibrarySpecificUnit> unitTargets = <LibrarySpecificUnit>[];
352 MapIterator<AnalysisTarget, CacheEntry> iterator = partition.iterator();
353 while (iterator.moveNext()) {
354 AnalysisTarget target = iterator.key;
355 // Optionally gather Dart sources to invalidate URIs resolution.
356 if (invalidateUris && _isDartSource(target)) {
357 dartSources.add(target);
358 }
359 // LibrarySpecificUnit(s) are roots of Dart resolution.
360 // When one is invalidated, invalidation is propagated to all resolution.
361 if (target is LibrarySpecificUnit) {
362 unitTargets.add(target);
363 Source library = target.library;
364 if (context.exists(library)) {
365 librarySourceQueue.add(library);
366 }
367 }
368 }
369 // Invalidate targets and values.
370 unitTargets.forEach(partition.remove);
371 for (Source dartSource in dartSources) {
372 CacheEntry entry = partition.get(dartSource);
373 if (dartSource != null) {
374 // TODO(scheglov) we invalidate too much.
375 // Would be nice to invalidate just URLs resolution.
376 entry.setState(PARSED_UNIT, CacheState.INVALID);
377 entry.setState(IMPORTED_LIBRARIES, CacheState.INVALID);
378 entry.setState(EXPLICITLY_IMPORTED_LIBRARIES, CacheState.INVALID);
379 entry.setState(EXPORTED_LIBRARIES, CacheState.INVALID);
380 entry.setState(INCLUDED_PARTS, CacheState.INVALID);
381 }
382 }
383 }
384
385 /**
386 * Invalidate [CONTAINING_LIBRARIES] for the given [source].
387 * [CONTAINING_LIBRARIES] does not have dependencies, so we manage it here.
388 * The [source] may be a part, or a library whose contents is updated so
389 * will be a part.
390 */
391 void _invalidateContainingLibraries(Source source) {
392 CacheEntry entry = analysisCache.get(source);
393 if (entry != null) {
394 entry.setState(CONTAINING_LIBRARIES, CacheState.INVALID);
395 }
396 }
397
398 /**
399 * Returns `true` if the given [result] of the given [target] needs
400 * computing, i.e. it is not in the valid and not in the error state.
401 */
402 bool _needsComputing(AnalysisTarget target, ResultDescriptor result) {
403 CacheState state = analysisCache.getState(target, result);
404 return state != CacheState.VALID && state != CacheState.ERROR;
405 }
406
407 /**
408 * The given [library] source was changed or removed.
409 * Update [libraryPartsMap] and [partLibrariesMap].
410 */
411 void _onLibrarySourceChangedOrRemoved(Source library) {
412 List<Source> parts = libraryPartsMap.remove(library);
413 if (parts != null) {
414 for (Source part in parts) {
415 List<Source> libraries = partLibrariesMap[part];
416 if (libraries != null) {
417 libraries.remove(library);
418 _invalidateContainingLibraries(part);
419 }
420 }
421 }
422 _invalidateContainingLibraries(library);
423 }
424
425 /**
426 * Schedule computing [RESOLVED_UNIT] for the given [librarySource].
427 * If errors should be computed, then schedule [LIBRARY_ERRORS_READY] instead,
428 * it also computes [RESOLVED_UNIT] in process.
429 */
430 void _schedulePriorityLibrarySourceAnalysis(Source librarySource) {
431 bool needErrors = _shouldErrorsBeComputed(librarySource);
432 if (needErrors) {
433 addPriorityResult(librarySource, LIBRARY_ERRORS_READY);
434 } else {
435 var target = new LibrarySpecificUnit(librarySource, librarySource);
436 addPriorityResult(target, RESOLVED_UNIT);
437 }
438 }
439
440 bool _shouldErrorsBeComputed(Source source) =>
441 context.shouldErrorsBeAnalyzed(source, null);
442
443 static bool _isDartSource(AnalysisTarget target) {
444 return target is Source && AnalysisEngine.isDartFileName(target.fullName);
445 }
446 }
OLDNEW
« no previous file with comments | « analyzer/lib/src/task/dart.dart ('k') | analyzer/lib/src/task/driver.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698