Index: pkg/analyzer/lib/src/task/options_work_manager.dart |
diff --git a/pkg/analyzer/lib/src/task/options_work_manager.dart b/pkg/analyzer/lib/src/task/options_work_manager.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4447f30193bf286bf5a93b0ce3361095b37bf1fe |
--- /dev/null |
+++ b/pkg/analyzer/lib/src/task/options_work_manager.dart |
@@ -0,0 +1,174 @@ |
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+library analyzer.src.task.options_work_manager; |
+ |
+import 'dart:collection'; |
+ |
+import 'package:analyzer/src/context/cache.dart'; |
+import 'package:analyzer/src/generated/engine.dart' |
+ show |
+ AnalysisEngine, |
+ AnalysisErrorInfo, |
+ AnalysisErrorInfoImpl, |
+ AnalysisOptions, |
+ CacheState, |
+ InternalAnalysisContext; |
+import 'package:analyzer/src/generated/error.dart'; |
+import 'package:analyzer/src/generated/source.dart'; |
+import 'package:analyzer/src/task/options.dart'; |
+import 'package:analyzer/task/model.dart'; |
+ |
+/// The manager for `.analysis_options` specific analysis. |
+class OptionsWorkManager implements WorkManager { |
+ /// The context for which work is being managed. |
+ final InternalAnalysisContext context; |
+ |
+ /// The options file sources. |
+ final LinkedHashSet<Source> sourceQueue = new LinkedHashSet<Source>(); |
+ |
+ /// The [TargetedResult]s that should be computed with priority. |
+ final LinkedHashSet<TargetedResult> priorityResultQueue = |
+ new LinkedHashSet<TargetedResult>(); |
+ |
+ /// Initialize a newly created manager. |
+ OptionsWorkManager(this.context) { |
+ analysisCache.onResultInvalidated.listen(onResultInvalidated); |
+ } |
+ |
+ /// Returns the correctly typed result of `context.analysisCache`. |
+ AnalysisCache get analysisCache => context.analysisCache; |
+ |
+ /// Specifies that the client wants the given [result] of the given [target] |
+ /// to be computed with priority. |
+ void addPriorityResult(AnalysisTarget target, ResultDescriptor result) { |
+ priorityResultQueue.add(new TargetedResult(target, result)); |
+ } |
+ |
+ @override |
+ void applyChange(List<Source> addedSources, List<Source> changedSources, |
+ List<Source> removedSources) { |
+ addedSources = addedSources.where(_isOptionsSource).toList(); |
+ changedSources = changedSources.where(_isOptionsSource).toList(); |
+ removedSources = removedSources.where(_isOptionsSource).toList(); |
+ // source queue |
+ sourceQueue.addAll(addedSources); |
+ sourceQueue.addAll(changedSources); |
+ sourceQueue.removeAll(removedSources); |
+ } |
+ |
+ @override |
+ void applyPriorityTargets(List<AnalysisTarget> targets) { |
+ // Unschedule the old targets. |
+ List<TargetedResult> resultsToUnschedule = <TargetedResult>[]; |
+ for (TargetedResult result in priorityResultQueue) { |
+ if (result.result == ANALYSIS_OPTIONS_ERRORS) { |
+ resultsToUnschedule.add(result); |
+ } |
+ } |
+ priorityResultQueue.removeAll(resultsToUnschedule); |
+ // Schedule new targets. |
+ for (AnalysisTarget target in targets) { |
+ if (_isOptionsSource(target)) { |
+ addPriorityResult(target, ANALYSIS_OPTIONS_ERRORS); |
+ } |
+ } |
+ } |
+ |
+ @override |
+ List<AnalysisError> getErrors(Source source) { |
+ if (!_isOptionsSource(source)) { |
+ return AnalysisError.NO_ERRORS; |
+ } |
+ // If analysis is finished, use all the errors. |
+ if (analysisCache.getState(source, ANALYSIS_OPTIONS_ERRORS) == |
+ CacheState.VALID) { |
+ return analysisCache.getValue(source, ANALYSIS_OPTIONS_ERRORS); |
+ } |
+ // No partial results. |
+ return AnalysisError.NO_ERRORS; |
+ } |
+ |
+ @override |
+ TargetedResult getNextResult() { |
+ // Try to find a priority result to compute. |
+ while (priorityResultQueue.isNotEmpty) { |
+ TargetedResult result = priorityResultQueue.first; |
+ if (!_needsComputing(result.target, result.result)) { |
+ priorityResultQueue.remove(result); |
+ continue; |
+ } |
+ return result; |
+ } |
+ // Try to find a new options file to analyze. |
+ while (sourceQueue.isNotEmpty) { |
+ Source optionsSource = sourceQueue.first; |
+ if (!_needsComputing(optionsSource, ANALYSIS_OPTIONS_ERRORS)) { |
+ sourceQueue.remove(optionsSource); |
+ continue; |
+ } |
+ return new TargetedResult(optionsSource, ANALYSIS_OPTIONS_ERRORS); |
+ } |
+ // No results to compute. |
+ return null; |
+ } |
+ |
+ @override |
+ WorkOrderPriority getNextResultPriority() { |
+ if (priorityResultQueue.isNotEmpty) { |
+ return WorkOrderPriority.PRIORITY; |
+ } |
+ if (sourceQueue.isNotEmpty) { |
+ return WorkOrderPriority.NORMAL; |
+ } |
+ return WorkOrderPriority.NONE; |
+ } |
+ |
+ @override |
+ void onAnalysisOptionsChanged() { |
+ // Do nothing. |
+ } |
+ |
+ /// Notifies the manager that a result has been invalidated. |
+ void onResultInvalidated(InvalidatedResult event) { |
+ ResultDescriptor descriptor = event.descriptor; |
+ if (descriptor == ANALYSIS_OPTIONS_ERRORS) { |
+ sourceQueue.add(event.entry.target); |
+ } |
+ } |
+ |
+ @override |
+ void onSourceFactoryChanged() { |
+ // Do nothing. |
+ } |
+ |
+ @override |
+ void resultsComputed( |
+ AnalysisTarget target, Map<ResultDescriptor, dynamic> outputs) { |
+ // Update notice. |
+ if (_isOptionsSource(target)) { |
+ bool shouldSetErrors = false; |
+ outputs.forEach((ResultDescriptor descriptor, value) { |
+ if (descriptor == ANALYSIS_OPTIONS_ERRORS) { |
+ shouldSetErrors = true; |
+ } |
+ }); |
+ if (shouldSetErrors) { |
+ AnalysisErrorInfo info = context.getErrors(target); |
+ context.getNotice(target).setErrors(info.errors, info.lineInfo); |
+ } |
+ } |
+ } |
+ |
+ /// Returns `true` if the given [result] of the given [target] needs |
+ /// computing, i.e. it is not in the valid and not in the error state. |
+ bool _needsComputing(AnalysisTarget target, ResultDescriptor result) { |
+ CacheState state = analysisCache.getState(target, result); |
+ return state != CacheState.VALID && state != CacheState.ERROR; |
+ } |
+ |
+ /// Return `true` if the given target is an `.analysis_options` source. |
+ static bool _isOptionsSource(AnalysisTarget target) => target is Source && |
+ AnalysisEngine.isAnalysisOptionsFileName(target.fullName); |
+} |