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

Side by Side Diff: mojo/public/dart/third_party/analyzer/lib/task/model.dart

Issue 1346773002: Stop running pub get at gclient sync time and fix build bugs (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 3 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
(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.task.model;
6
7 import 'dart:collection';
8
9 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
10 import 'package:analyzer/src/generated/error.dart' show AnalysisError;
11 import 'package:analyzer/src/generated/java_engine.dart';
12 import 'package:analyzer/src/generated/source.dart';
13 import 'package:analyzer/src/generated/utilities_general.dart';
14 import 'package:analyzer/src/task/driver.dart';
15 import 'package:analyzer/src/task/model.dart';
16
17 /**
18 * A function that converts the given [key] and [value] into a [TaskInput].
19 */
20 typedef TaskInput<E> BinaryFunction<K, V, E>(K key, V value);
21
22 /**
23 * A function that takes an analysis [context] and an analysis [target] and
24 * returns an analysis task. Such functions are passed to a [TaskDescriptor] to
25 * be used to create the described task.
26 */
27 typedef AnalysisTask BuildTask(AnalysisContext context, AnalysisTarget target);
28
29 /**
30 * A function that takes the target for which a task will produce results and
31 * returns a map from input names to descriptions of the analysis results needed
32 * by the task in order for the task to be performed. Such functions are passed
33 * to a [TaskDescriptor] to be used to determine the inputs needed by the task.
34 */
35 typedef Map<String, TaskInput> CreateTaskInputs(AnalysisTarget target);
36
37 /**
38 * A function that converts an object of the type [B] into a [TaskInput].
39 * This is used, for example, by a [ListTaskInput] to create task inputs
40 * for each value in a list of values.
41 */
42 typedef TaskInput<E> UnaryFunction<B, E>(B object);
43
44 /**
45 * An [AnalysisTarget] wrapper for an [AnalysisContext].
46 */
47 class AnalysisContextTarget implements AnalysisTarget {
48 static final AnalysisContextTarget request = new AnalysisContextTarget(null);
49
50 final AnalysisContext context;
51
52 AnalysisContextTarget(this.context);
53
54 @override
55 Source get source => null;
56 }
57
58 /**
59 * An object with which an analysis result can be associated.
60 *
61 * Clients are allowed to subtype this class when creating new kinds of targets.
62 * Instances of this type are used in hashed data structures, so subtypes are
63 * required to correctly implement [==] and [hashCode].
64 */
65 abstract class AnalysisTarget {
66 /**
67 * Return the source associated with this target, or `null` if this target is
68 * not associated with a source.
69 */
70 Source get source;
71 }
72
73 /**
74 * An object used to compute one or more analysis results associated with a
75 * single target.
76 *
77 * Clients are expected to extend this class when creating new tasks.
78 */
79 abstract class AnalysisTask {
80 /**
81 * A table mapping the types of analysis tasks to the number of times each
82 * kind of task has been performed.
83 */
84 static final Map<Type, int> countMap = new HashMap<Type, int>();
85
86 /**
87 * A table mapping the types of analysis tasks to stopwatches used to compute
88 * how much time was spent executing each kind of task.
89 */
90 static final Map<Type, Stopwatch> stopwatchMap =
91 new HashMap<Type, Stopwatch>();
92
93 /**
94 * The context in which the task is to be performed.
95 */
96 final AnalysisContext context;
97
98 /**
99 * The target for which result values are being produced.
100 */
101 final AnalysisTarget target;
102
103 /**
104 * A table mapping input names to input values.
105 */
106 Map<String, dynamic> inputs;
107
108 /**
109 * A table mapping result descriptors whose values are produced by this task
110 * to the values that were produced.
111 */
112 Map<ResultDescriptor, dynamic> outputs =
113 new HashMap<ResultDescriptor, dynamic>();
114
115 /**
116 * The exception that was thrown while performing this task, or `null` if the
117 * task completed successfully.
118 */
119 CaughtException caughtException;
120
121 /**
122 * If a dependency cycle was found while computing the inputs for the task,
123 * the set of [WorkItem]s contained in the cycle (if there are overlapping
124 * cycles, this is the set of all [WorkItem]s in the entire strongly
125 * connected component). Otherwise, `null`.
126 */
127 List<WorkItem> dependencyCycle;
128
129 /**
130 * Initialize a newly created task to perform analysis within the given
131 * [context] in order to produce results for the given [target].
132 */
133 AnalysisTask(this.context, this.target);
134
135 /**
136 * Return a textual description of this task.
137 */
138 String get description;
139
140 /**
141 * Return the descriptor that describes this task.
142 */
143 TaskDescriptor get descriptor;
144
145 /**
146 * Indicates whether the task is capable of handling dependency cycles. A
147 * task that overrides this getter to return `true` must be prepared for the
148 * possibility that it will be invoked with a non-`null` value of
149 * [dependencyCycle], and with not all of its inputs computed.
150 */
151 bool get handlesDependencyCycles => false;
152
153 /**
154 * Return the value of the input with the given [name]. Throw an exception if
155 * the input value is not defined.
156 */
157 Object getRequiredInput(String name) {
158 if (inputs == null || !inputs.containsKey(name)) {
159 throw new AnalysisException("Could not $description: missing $name");
160 }
161 return inputs[name];
162 }
163
164 /**
165 * Return the source associated with the target. Throw an exception if
166 * the target is not associated with a source.
167 */
168 Source getRequiredSource() {
169 Source source = target.source;
170 if (source == null) {
171 throw new AnalysisException("Could not $description: missing source");
172 }
173 return source;
174 }
175
176 /**
177 * Perform this analysis task, protected by an exception handler.
178 *
179 * This method should throw an [AnalysisException] if an exception occurs
180 * while performing the task. If other kinds of exceptions are thrown they
181 * will be wrapped in an [AnalysisException].
182 *
183 * If no exception is thrown, this method must fully populate the [outputs]
184 * map (have a key/value pair for each result that this task is expected to
185 * produce).
186 */
187 void internalPerform();
188
189 /**
190 * Perform this analysis task. When this method returns, either the [outputs]
191 * map should be fully populated (have a key/value pair for each result that
192 * this task is expected to produce) or the [caughtException] should be set.
193 *
194 * Clients should not override this method.
195 */
196 void perform() {
197 try {
198 _safelyPerform();
199 } on AnalysisException catch (exception, stackTrace) {
200 caughtException = new CaughtException(exception, stackTrace);
201 AnalysisEngine.instance.logger.logInformation(
202 "Task failed: ${description}", caughtException);
203 }
204 }
205
206 @override
207 String toString() => description;
208
209 /**
210 * Perform this analysis task, ensuring that all exceptions are wrapped in an
211 * [AnalysisException].
212 *
213 * Clients should not override this method.
214 */
215 void _safelyPerform() {
216 try {
217 //
218 // Report that this task is being performed.
219 //
220 String contextName = context.name;
221 if (contextName == null) {
222 contextName = 'unnamed';
223 }
224 AnalysisEngine.instance.instrumentationService.logAnalysisTask(
225 contextName, this);
226 //
227 // Gather statistics on the performance of the task.
228 //
229 int count = countMap[runtimeType];
230 countMap[runtimeType] = count == null ? 1 : count + 1;
231 Stopwatch stopwatch = stopwatchMap[runtimeType];
232 if (stopwatch == null) {
233 stopwatch = new Stopwatch();
234 stopwatchMap[runtimeType] = stopwatch;
235 }
236 stopwatch.start();
237 //
238 // Actually perform the task.
239 //
240 try {
241 if (dependencyCycle != null && !handlesDependencyCycles) {
242 throw new InfiniteTaskLoopException(this, dependencyCycle);
243 }
244 internalPerform();
245 } finally {
246 stopwatch.stop();
247 }
248 } on AnalysisException {
249 rethrow;
250 } catch (exception, stackTrace) {
251 throw new AnalysisException(
252 'Unexpected exception while performing $description',
253 new CaughtException(exception, stackTrace));
254 }
255 }
256 }
257
258 /**
259 * A description of a [List]-based analysis result that can be computed by an
260 * [AnalysisTask].
261 *
262 * Clients are not expected to subtype this class.
263 */
264 abstract class ListResultDescriptor<E> implements ResultDescriptor<List<E>> {
265 /**
266 * Initialize a newly created analysis result to have the given [name] and
267 * [defaultValue]. If a [cachingPolicy] is provided, it will control how long
268 * values associated with this result will remain in the cache.
269 */
270 factory ListResultDescriptor(String name, List<E> defaultValue,
271 {ResultCachingPolicy<List<E>> cachingPolicy}) = ListResultDescriptorImpl<E >;
272
273 @override
274 ListTaskInput<E> of(AnalysisTarget target);
275 }
276
277 /**
278 * A description of an input to an [AnalysisTask] that can be used to compute
279 * that input.
280 *
281 * Clients are not expected to subtype this class.
282 */
283 abstract class ListTaskInput<E> extends TaskInput<List<E>> {
284 /**
285 * Return a task input that can be used to compute a list whose elements are
286 * the result of passing the elements of this input to the [mapper] function.
287 */
288 ListTaskInput /*<V>*/ toList(UnaryFunction<E, dynamic /*<V>*/ > mapper);
289
290 /**
291 * Return a task input that can be used to compute a list whose elements are
292 * [valueResult]'s associated with those elements.
293 */
294 ListTaskInput /*<V>*/ toListOf(ResultDescriptor /*<V>*/ valueResult);
295
296 /**
297 * Return a task input that can be used to compute a map whose keys are the
298 * elements of this input and whose values are the result of passing the
299 * corresponding key to the [mapper] function.
300 */
301 MapTaskInput<E, dynamic /*V*/ > toMap(
302 UnaryFunction<E, dynamic /*<V>*/ > mapper);
303
304 /**
305 * Return a task input that can be used to compute a map whose keys are the
306 * elements of this input and whose values are the [valueResult]'s associated
307 * with those elements.
308 */
309 MapTaskInput<AnalysisTarget, dynamic /*V*/ > toMapOf(
310 ResultDescriptor /*<V>*/ valueResult);
311 }
312
313 /**
314 * A description of an input with a [Map] based values.
315 *
316 * Clients are not expected to subtype this class.
317 */
318 abstract class MapTaskInput<K, V> extends TaskInput<Map<K, V>> {
319 /**
320 * [V] must be a [List].
321 * Return a task input that can be used to compute a list whose elements are
322 * the result of passing keys [K] and the corresponding elements of [V] to
323 * the [mapper] function.
324 */
325 TaskInput<List /*<E>*/ > toFlattenList(
326 BinaryFunction<K, dynamic /*element of V*/, dynamic /*<E>*/ > mapper);
327 }
328
329 /**
330 * A policy object that can compute sizes of results and provide the maximum
331 * active and idle sizes that can be kept in the cache.
332 *
333 * All the [ResultDescriptor]s with the same [ResultCachingPolicy] instance
334 * share the same total size in a cache.
335 */
336 abstract class ResultCachingPolicy<T> {
337 /**
338 * Return the maximum total size of results that can be kept in the cache
339 * while analysis is in progress.
340 */
341 int get maxActiveSize;
342
343 /**
344 * Return the maximum total size of results that can be kept in the cache
345 * while analysis is idle.
346 */
347 int get maxIdleSize;
348
349 /**
350 * Return the size of the given [object].
351 */
352 int measure(T object);
353 }
354
355 /**
356 * A description of an analysis result that can be computed by an [AnalysisTask] .
357 *
358 * Clients are not expected to subtype this class.
359 */
360 abstract class ResultDescriptor<V> {
361 /**
362 * Initialize a newly created analysis result to have the given [name] and
363 * [defaultValue].
364 *
365 * The given [cachingPolicy] is used to limit the total size of results
366 * described by this descriptor. If no policy is specified, the results are
367 * never evicted from the cache, and removed only when they are invalidated.
368 */
369 factory ResultDescriptor(String name, V defaultValue,
370 {ResultCachingPolicy<V> cachingPolicy}) = ResultDescriptorImpl;
371
372 /**
373 * Return the caching policy for results described by this descriptor.
374 */
375 ResultCachingPolicy<V> get cachingPolicy;
376
377 /**
378 * Return the default value for results described by this descriptor.
379 */
380 V get defaultValue;
381
382 /**
383 * Return the name of this descriptor.
384 */
385 String get name;
386
387 /**
388 * Return a task input that can be used to compute this result for the given
389 * [target].
390 */
391 TaskInput<V> of(AnalysisTarget target);
392 }
393
394 /**
395 * A specification of the given [result] for the given [target].
396 *
397 * Clients are not expected to subtype this class.
398 */
399 class TargetedResult {
400 /**
401 * An empty list of results.
402 */
403 static final List<TargetedResult> EMPTY_LIST = const <TargetedResult>[];
404
405 /**
406 * The target with which the result is associated.
407 */
408 final AnalysisTarget target;
409
410 /**
411 * The result associated with the target.
412 */
413 final ResultDescriptor result;
414
415 /**
416 * Initialize a new targeted result.
417 */
418 TargetedResult(this.target, this.result);
419
420 @override
421 int get hashCode {
422 return JenkinsSmiHash.combine(target.hashCode, result.hashCode);
423 }
424
425 @override
426 bool operator ==(other) {
427 return other is TargetedResult &&
428 other.target == target &&
429 other.result == result;
430 }
431
432 @override
433 String toString() => '$result for $target';
434 }
435
436 /**
437 * A description of an [AnalysisTask].
438 */
439 abstract class TaskDescriptor {
440 /**
441 * Initialize a newly created task descriptor to have the given [name] and to
442 * describe a task that takes the inputs built using the given [inputBuilder],
443 * and produces the given [results]. The [buildTask] will be used to create
444 * the instance of [AnalysisTask] thusly described.
445 */
446 factory TaskDescriptor(String name, BuildTask buildTask,
447 CreateTaskInputs inputBuilder,
448 List<ResultDescriptor> results) = TaskDescriptorImpl;
449
450 /**
451 * Return the builder used to build the inputs to the task.
452 */
453 CreateTaskInputs get createTaskInputs;
454
455 /**
456 * Return the name of the task being described.
457 */
458 String get name;
459
460 /**
461 * Return a list of the analysis results that will be computed by this task.
462 */
463 List<ResultDescriptor> get results;
464
465 /**
466 * Create and return a task that is described by this descriptor that can be
467 * used to compute results based on the given [inputs].
468 */
469 AnalysisTask createTask(AnalysisContext context, AnalysisTarget target,
470 Map<String, dynamic> inputs);
471 }
472
473 /**
474 * A description of an input to an [AnalysisTask] that can be used to compute
475 * that input.
476 *
477 * Clients are not expected to subtype this class.
478 */
479 abstract class TaskInput<V> {
480 /**
481 * Create and return a builder that can be used to build this task input.
482 */
483 TaskInputBuilder<V> createBuilder();
484
485 /**
486 * Return a task input that can be used to compute a list whose elements are
487 * the result of passing the result of this input to the [mapper] function.
488 */
489 ListTaskInput /*<E>*/ mappedToList(List /*<E>*/ mapper(V value));
490 }
491
492 /**
493 * An object used to build the value associated with a single [TaskInput].
494 *
495 * All builders work by requesting one or more results (each result being
496 * associated with a target). The interaction pattern is modeled after the class
497 * [Iterator], in which the method [moveNext] is invoked to move from one result
498 * request to the next. The getters [currentResult] and [currentTarget] are used
499 * to get the result and target of the current request. The value of the result
500 * must be supplied using the [currentValue] setter before [moveNext] can be
501 * invoked to move to the next request. When [moveNext] returns `false`,
502 * indicating that there are no more requests, the method [inputValue] can be
503 * used to access the value of the input that was built.
504 *
505 * Clients are not expected to subtype this class.
506 */
507 abstract class TaskInputBuilder<V> {
508 /**
509 * Return the result that needs to be computed, or `null` if [moveNext] has
510 * not been invoked or if the last invocation of [moveNext] returned `false`.
511 */
512 ResultDescriptor get currentResult;
513
514 /**
515 * Return the target for which the result needs to be computed, or `null` if
516 * [moveNext] has not been invoked or if the last invocation of [moveNext]
517 * returned `false`.
518 */
519 AnalysisTarget get currentTarget;
520
521 /**
522 * Set the [value] that was computed for the current result.
523 *
524 * Throws a [StateError] if [moveNext] has not been invoked or if the last
525 * invocation of [moveNext] returned `false`.
526 */
527 void set currentValue(Object value);
528
529 /**
530 * Return the [value] that was computed by this builder.
531 *
532 * Throws a [StateError] if [moveNext] has not been invoked or if the last
533 * invocation of [moveNext] returned `true`.
534 *
535 * Returns `null` if no value could be computed due to a circular dependency.
536 */
537 V get inputValue;
538
539 /**
540 * Record that no value is available for the current result, due to a
541 * circular dependency.
542 *
543 * Throws a [StateError] if [moveNext] has not been invoked or if the last
544 * invocation of [moveNext] returned `false`.
545 */
546 void currentValueNotAvailable();
547
548 /**
549 * Move to the next result that needs to be computed in order to build the
550 * inputs for a task. Return `true` if there is another result that needs to
551 * be computed, or `false` if the inputs have been computed.
552 *
553 * It is safe to invoke [moveNext] after it has returned `false`. In this case
554 * [moveNext] has no effect and will again return `false`.
555 *
556 * Throws a [StateError] if the value of the current result has not been
557 * provided using [currentValue].
558 */
559 bool moveNext();
560 }
561
562 /**
563 * [WorkManager]s are used to drive analysis.
564 *
565 * They know specific of the targets and results they care about,
566 * so they can request analysis results in optimal order.
567 */
568 abstract class WorkManager {
569 /**
570 * Notifies the manager about changes in the explicit source list.
571 */
572 void applyChange(List<Source> addedSources, List<Source> changedSources,
573 List<Source> removedSources);
574
575 /**
576 * Notifies the managers that the given set of priority [targets] was set.
577 */
578 void applyPriorityTargets(List<AnalysisTarget> targets);
579
580 /**
581 * Return a list of all of the errors associated with the given [source].
582 * The list of errors will be empty if the source is not known to the context
583 * or if there are no errors in the source. The errors contained in the list
584 * can be incomplete.
585 */
586 List<AnalysisError> getErrors(Source source);
587
588 /**
589 * Return the next [TargetedResult] that this work manager wants to be
590 * computed, or `null` if this manager doesn't need any new results.
591 */
592 TargetedResult getNextResult();
593
594 /**
595 * Return the priority if the next work order this work manager want to be
596 * computed. The [AnalysisDriver] will perform the work order with
597 * the highest priority.
598 *
599 * Even if the returned value is [WorkOrderPriority.NONE], it still does not
600 * guarantee that [getNextResult] will return not `null`.
601 */
602 WorkOrderPriority getNextResultPriority();
603
604 /**
605 * Notifies the manager about analysis options changes.
606 */
607 void onAnalysisOptionsChanged();
608
609 /**
610 * Notifies the manager about [SourceFactory] changes.
611 */
612 void onSourceFactoryChanged();
613
614 /**
615 * Notifies the manager that the given [outputs] were produced for
616 * the given [target].
617 */
618 void resultsComputed(
619 AnalysisTarget target, Map<ResultDescriptor, dynamic> outputs);
620 }
621
622 /**
623 * The priorities of work orders returned by [WorkManager]s.
624 *
625 * New priorities may be added with time, clients need to tolerate this.
626 */
627 enum WorkOrderPriority {
628 /**
629 * Responding to an user's action.
630 */
631 INTERACTIVE,
632
633 /**
634 * Computing information for priority sources.
635 */
636 PRIORITY,
637
638 /**
639 * A work should be done, but without any special urgency.
640 */
641 NORMAL,
642
643 /**
644 * Nothing to do.
645 */
646 NONE
647 }
OLDNEW
« no previous file with comments | « mojo/public/dart/third_party/analyzer/lib/task/html.dart ('k') | mojo/public/dart/third_party/analyzer/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698