Chromium Code Reviews| 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..09ffc4373ce0afe89bcfda9a1000fea1b0dbe77d |
| --- /dev/null |
| +++ b/pkg/analyzer/lib/src/task/options_work_manager.dart |
| @@ -0,0 +1,177 @@ |
| +// 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); |
| + } |
| + // If analysis is in progress, combine all known partial results. |
| + List<AnalysisError> errors = <AnalysisError>[]; |
| + errors.addAll(analysisCache.getValue(source, ANALYSIS_OPTIONS_ERRORS)); |
| + |
| + return 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 htmlSource = sourceQueue.first; |
|
scheglov
2015/10/20 21:22:20
Rename?
pquitslund
2015/10/20 21:25:54
Done.
|
| + if (!_needsComputing(htmlSource, ANALYSIS_OPTIONS_ERRORS)) { |
| + sourceQueue.remove(htmlSource); |
| + continue; |
| + } |
| + return new TargetedResult(htmlSource, 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); |
| +} |