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

Side by Side Diff: analyzer/lib/task/model.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/task/html.dart ('k') | analyzer/pubspec.yaml » ('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.task.model;
6
7 import 'dart:collection';
8
9 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
10 import 'package:analyzer/src/generated/java_engine.dart';
11 import 'package:analyzer/src/generated/source.dart';
12 import 'package:analyzer/src/task/driver.dart';
13 import 'package:analyzer/src/task/model.dart';
14
15 /**
16 * A function that converts the given [key] and [value] into a [TaskInput].
17 */
18 typedef TaskInput<E> BinaryFunction<K, V, E>(K key, V value);
19
20 /**
21 * A function that takes an analysis [context] and an analysis [target] and
22 * returns an analysis task. Such functions are passed to a [TaskDescriptor] to
23 * be used to create the described task.
24 */
25 typedef AnalysisTask BuildTask(AnalysisContext context, AnalysisTarget target);
26
27 /**
28 * A function that takes the target for which a task will produce results and
29 * returns a map from input names to descriptions of the analysis results needed
30 * by the task in order for the task to be performed. Such functions are passed
31 * to a [TaskDescriptor] to be used to determine the inputs needed by the task.
32 */
33 typedef Map<String, TaskInput> CreateTaskInputs(AnalysisTarget target);
34
35 /**
36 * A function that converts an object of the type [B] into a [TaskInput].
37 * This is used, for example, by a [ListTaskInput] to create task inputs
38 * for each value in a list of values.
39 */
40 typedef TaskInput<E> UnaryFunction<B, E>(B object);
41
42 /**
43 * An [AnalysisTarget] wrapper for an [AnalysisContext].
44 */
45 class AnalysisContextTarget implements AnalysisTarget {
46 static final AnalysisContextTarget request = new AnalysisContextTarget(null);
47
48 final AnalysisContext context;
49
50 AnalysisContextTarget(this.context);
51
52 @override
53 Source get source => null;
54 }
55
56 /**
57 * An object with which an analysis result can be associated.
58 *
59 * Clients are allowed to subtype this class when creating new kinds of targets.
60 * Instances of this type are used in hashed data structures, so subtypes are
61 * required to correctly implement [==] and [hashCode].
62 */
63 abstract class AnalysisTarget {
64 /**
65 * Return the source associated with this target, or `null` if this target is
66 * not associated with a source.
67 */
68 Source get source;
69 }
70
71 /**
72 * An object used to compute one or more analysis results associated with a
73 * single target.
74 *
75 * Clients are expected to extend this class when creating new tasks.
76 */
77 abstract class AnalysisTask {
78 /**
79 * A table mapping the types of analysis tasks to the number of times each
80 * kind of task has been performed.
81 */
82 static final Map<Type, int> countMap = new HashMap<Type, int>();
83
84 /**
85 * A table mapping the types of analysis tasks to stopwatches used to compute
86 * how much time was spent executing each kind of task.
87 */
88 static final Map<Type, Stopwatch> stopwatchMap =
89 new HashMap<Type, Stopwatch>();
90
91 /**
92 * The context in which the task is to be performed.
93 */
94 final AnalysisContext context;
95
96 /**
97 * The target for which result values are being produced.
98 */
99 final AnalysisTarget target;
100
101 /**
102 * A table mapping input names to input values.
103 */
104 Map<String, dynamic> inputs;
105
106 /**
107 * A table mapping result descriptors whose values are produced by this task
108 * to the values that were produced.
109 */
110 Map<ResultDescriptor, dynamic> outputs =
111 new HashMap<ResultDescriptor, dynamic>();
112
113 /**
114 * The exception that was thrown while performing this task, or `null` if the
115 * task completed successfully.
116 */
117 CaughtException caughtException;
118
119 /**
120 * If a dependency cycle was found while computing the inputs for the task,
121 * the set of [WorkItem]s contained in the cycle (if there are overlapping
122 * cycles, this is the set of all [WorkItem]s in the entire strongly
123 * connected component). Otherwise, `null`.
124 */
125 List<WorkItem> dependencyCycle;
126
127 /**
128 * Initialize a newly created task to perform analysis within the given
129 * [context] in order to produce results for the given [target].
130 */
131 AnalysisTask(this.context, this.target);
132
133 /**
134 * Return a textual description of this task.
135 */
136 String get description;
137
138 /**
139 * Return the descriptor that describes this task.
140 */
141 TaskDescriptor get descriptor;
142
143 /**
144 * Indicates whether the task is capable of handling dependency cycles. A
145 * task that overrides this getter to return `true` must be prepared for the
146 * possibility that it will be invoked with a non-`null` value of
147 * [dependencyCycle], and with not all of its inputs computed.
148 */
149 bool get handlesDependencyCycles => false;
150
151 /**
152 * Return the value of the input with the given [name]. Throw an exception if
153 * the input value is not defined.
154 */
155 Object getRequiredInput(String name) {
156 if (inputs == null || !inputs.containsKey(name)) {
157 throw new AnalysisException("Could not $description: missing $name");
158 }
159 return inputs[name];
160 }
161
162 /**
163 * Return the source associated with the target. Throw an exception if
164 * the target is not associated with a source.
165 */
166 Source getRequiredSource() {
167 Source source = target.source;
168 if (source == null) {
169 throw new AnalysisException("Could not $description: missing source");
170 }
171 return source;
172 }
173
174 /**
175 * Perform this analysis task, protected by an exception handler.
176 *
177 * This method should throw an [AnalysisException] if an exception occurs
178 * while performing the task. If other kinds of exceptions are thrown they
179 * will be wrapped in an [AnalysisException].
180 *
181 * If no exception is thrown, this method must fully populate the [outputs]
182 * map (have a key/value pair for each result that this task is expected to
183 * produce).
184 */
185 void internalPerform();
186
187 /**
188 * Perform this analysis task. When this method returns, either the [outputs]
189 * map should be fully populated (have a key/value pair for each result that
190 * this task is expected to produce) or the [caughtException] should be set.
191 *
192 * Clients should not override this method.
193 */
194 void perform() {
195 try {
196 _safelyPerform();
197 } on AnalysisException catch (exception, stackTrace) {
198 caughtException = new CaughtException(exception, stackTrace);
199 AnalysisEngine.instance.logger.logInformation(
200 "Task failed: ${description}", caughtException);
201 }
202 }
203
204 @override
205 String toString() => description;
206
207 /**
208 * Perform this analysis task, ensuring that all exceptions are wrapped in an
209 * [AnalysisException].
210 *
211 * Clients should not override this method.
212 */
213 void _safelyPerform() {
214 try {
215 //
216 // Report that this task is being performed.
217 //
218 String contextName = context.name;
219 if (contextName == null) {
220 contextName = 'unnamed';
221 }
222 AnalysisEngine.instance.instrumentationService.logAnalysisTask(
223 contextName, this);
224 //
225 // Gather statistics on the performance of the task.
226 //
227 int count = countMap[runtimeType];
228 countMap[runtimeType] = count == null ? 1 : count + 1;
229 Stopwatch stopwatch = stopwatchMap[runtimeType];
230 if (stopwatch == null) {
231 stopwatch = new Stopwatch();
232 stopwatchMap[runtimeType] = stopwatch;
233 }
234 stopwatch.start();
235 //
236 // Actually perform the task.
237 //
238 try {
239 if (dependencyCycle != null && !handlesDependencyCycles) {
240 throw new InfiniteTaskLoopException(this, dependencyCycle);
241 }
242 internalPerform();
243 } finally {
244 stopwatch.stop();
245 }
246 } on AnalysisException {
247 rethrow;
248 } catch (exception, stackTrace) {
249 throw new AnalysisException(
250 'Unexpected exception while performing $description',
251 new CaughtException(exception, stackTrace));
252 }
253 }
254 }
255
256 /**
257 * A description of a [List]-based analysis result that can be computed by an
258 * [AnalysisTask].
259 *
260 * Clients are not expected to subtype this class.
261 */
262 abstract class ListResultDescriptor<E> implements ResultDescriptor<List<E>> {
263 /**
264 * Initialize a newly created analysis result to have the given [name] and
265 * [defaultValue]. If a [cachingPolicy] is provided, it will control how long
266 * values associated with this result will remain in the cache.
267 */
268 factory ListResultDescriptor(String name, List<E> defaultValue,
269 {ResultCachingPolicy<List<E>> cachingPolicy}) = ListResultDescriptorImpl<E >;
270
271 @override
272 ListTaskInput<E> of(AnalysisTarget target);
273 }
274
275 /**
276 * A description of an input to an [AnalysisTask] that can be used to compute
277 * that input.
278 *
279 * Clients are not expected to subtype this class.
280 */
281 abstract class ListTaskInput<E> extends TaskInput<List<E>> {
282 /**
283 * Return a task input that can be used to compute a list whose elements are
284 * the result of passing the elements of this input to the [mapper] function.
285 */
286 ListTaskInput /*<V>*/ toList(UnaryFunction<E, dynamic /*<V>*/ > mapper);
287
288 /**
289 * Return a task input that can be used to compute a list whose elements are
290 * [valueResult]'s associated with those elements.
291 */
292 ListTaskInput /*<V>*/ toListOf(ResultDescriptor /*<V>*/ valueResult);
293
294 /**
295 * Return a task input that can be used to compute a map whose keys are the
296 * elements of this input and whose values are the result of passing the
297 * corresponding key to the [mapper] function.
298 */
299 MapTaskInput<E, dynamic /*V*/ > toMap(
300 UnaryFunction<E, dynamic /*<V>*/ > mapper);
301
302 /**
303 * Return a task input that can be used to compute a map whose keys are the
304 * elements of this input and whose values are the [valueResult]'s associated
305 * with those elements.
306 */
307 MapTaskInput<AnalysisTarget, dynamic /*V*/ > toMapOf(
308 ResultDescriptor /*<V>*/ valueResult);
309 }
310
311 /**
312 * A description of an input with a [Map] based values.
313 *
314 * Clients are not expected to subtype this class.
315 */
316 abstract class MapTaskInput<K, V> extends TaskInput<Map<K, V>> {
317 /**
318 * [V] must be a [List].
319 * Return a task input that can be used to compute a list whose elements are
320 * the result of passing keys [K] and the corresponding elements of [V] to
321 * the [mapper] function.
322 */
323 TaskInput<List /*<E>*/ > toFlattenList(
324 BinaryFunction<K, dynamic /*element of V*/, dynamic /*<E>*/ > mapper);
325 }
326
327 /**
328 * A policy object that can compute sizes of results and provide the maximum
329 * active and idle sizes that can be kept in the cache.
330 *
331 * All the [ResultDescriptor]s with the same [ResultCachingPolicy] instance
332 * share the same total size in a cache.
333 */
334 abstract class ResultCachingPolicy<T> {
335 /**
336 * Return the maximum total size of results that can be kept in the cache
337 * while analysis is in progress.
338 */
339 int get maxActiveSize;
340
341 /**
342 * Return the maximum total size of results that can be kept in the cache
343 * while analysis is idle.
344 */
345 int get maxIdleSize;
346
347 /**
348 * Return the size of the given [object].
349 */
350 int measure(T object);
351 }
352
353 /**
354 * A description of an analysis result that can be computed by an [AnalysisTask] .
355 *
356 * Clients are not expected to subtype this class.
357 */
358 abstract class ResultDescriptor<V> {
359 /**
360 * Initialize a newly created analysis result to have the given [name] and
361 * [defaultValue].
362 *
363 * The given [cachingPolicy] is used to limit the total size of results
364 * described by this descriptor. If no policy is specified, the results are
365 * never evicted from the cache, and removed only when they are invalidated.
366 */
367 factory ResultDescriptor(String name, V defaultValue,
368 {ResultCachingPolicy<V> cachingPolicy}) = ResultDescriptorImpl;
369
370 /**
371 * Return the caching policy for results described by this descriptor.
372 */
373 ResultCachingPolicy<V> get cachingPolicy;
374
375 /**
376 * Return the default value for results described by this descriptor.
377 */
378 V get defaultValue;
379
380 /**
381 * Return the name of this descriptor.
382 */
383 String get name;
384
385 /**
386 * Return a task input that can be used to compute this result for the given
387 * [target].
388 */
389 TaskInput<V> of(AnalysisTarget target);
390 }
391
392 /**
393 * A description of an [AnalysisTask].
394 */
395 abstract class TaskDescriptor {
396 /**
397 * Initialize a newly created task descriptor to have the given [name] and to
398 * describe a task that takes the inputs built using the given [inputBuilder],
399 * and produces the given [results]. The [buildTask] will be used to create
400 * the instance of [AnalysisTask] thusly described.
401 */
402 factory TaskDescriptor(String name, BuildTask buildTask,
403 CreateTaskInputs inputBuilder,
404 List<ResultDescriptor> results) = TaskDescriptorImpl;
405
406 /**
407 * Return the builder used to build the inputs to the task.
408 */
409 CreateTaskInputs get createTaskInputs;
410
411 /**
412 * Return the name of the task being described.
413 */
414 String get name;
415
416 /**
417 * Return a list of the analysis results that will be computed by this task.
418 */
419 List<ResultDescriptor> get results;
420
421 /**
422 * Create and return a task that is described by this descriptor that can be
423 * used to compute results based on the given [inputs].
424 */
425 AnalysisTask createTask(AnalysisContext context, AnalysisTarget target,
426 Map<String, dynamic> inputs);
427 }
428
429 /**
430 * A description of an input to an [AnalysisTask] that can be used to compute
431 * that input.
432 *
433 * Clients are not expected to subtype this class.
434 */
435 abstract class TaskInput<V> {
436 /**
437 * Create and return a builder that can be used to build this task input.
438 */
439 TaskInputBuilder<V> createBuilder();
440
441 /**
442 * Return a task input that can be used to compute a list whose elements are
443 * the result of passing the result of this input to the [mapper] function.
444 */
445 ListTaskInput /*<E>*/ mappedToList(List /*<E>*/ mapper(V value));
446 }
447
448 /**
449 * An object used to build the value associated with a single [TaskInput].
450 *
451 * All builders work by requesting one or more results (each result being
452 * associated with a target). The interaction pattern is modeled after the class
453 * [Iterator], in which the method [moveNext] is invoked to move from one result
454 * request to the next. The getters [currentResult] and [currentTarget] are used
455 * to get the result and target of the current request. The value of the result
456 * must be supplied using the [currentValue] setter before [moveNext] can be
457 * invoked to move to the next request. When [moveNext] returns `false`,
458 * indicating that there are no more requests, the method [inputValue] can be
459 * used to access the value of the input that was built.
460 *
461 * Clients are not expected to subtype this class.
462 */
463 abstract class TaskInputBuilder<V> {
464 /**
465 * Return the result that needs to be computed, or `null` if [moveNext] has
466 * not been invoked or if the last invocation of [moveNext] returned `false`.
467 */
468 ResultDescriptor get currentResult;
469
470 /**
471 * Return the target for which the result needs to be computed, or `null` if
472 * [moveNext] has not been invoked or if the last invocation of [moveNext]
473 * returned `false`.
474 */
475 AnalysisTarget get currentTarget;
476
477 /**
478 * Set the [value] that was computed for the current result.
479 *
480 * Throws a [StateError] if [moveNext] has not been invoked or if the last
481 * invocation of [moveNext] returned `false`.
482 */
483 void set currentValue(Object value);
484
485 /**
486 * Return the [value] that was computed by this builder.
487 *
488 * Throws a [StateError] if [moveNext] has not been invoked or if the last
489 * invocation of [moveNext] returned `true`.
490 *
491 * Returns `null` if no value could be computed due to a circular dependency.
492 */
493 V get inputValue;
494
495 /**
496 * Record that no value is available for the current result, due to a
497 * circular dependency.
498 *
499 * Throws a [StateError] if [moveNext] has not been invoked or if the last
500 * invocation of [moveNext] returned `false`.
501 */
502 void currentValueNotAvailable();
503
504 /**
505 * Move to the next result that needs to be computed in order to build the
506 * inputs for a task. Return `true` if there is another result that needs to
507 * be computed, or `false` if the inputs have been computed.
508 *
509 * It is safe to invoke [moveNext] after it has returned `false`. In this case
510 * [moveNext] has no effect and will again return `false`.
511 *
512 * Throws a [StateError] if the value of the current result has not been
513 * provided using [currentValue].
514 */
515 bool moveNext();
516 }
OLDNEW
« no previous file with comments | « analyzer/lib/task/html.dart ('k') | analyzer/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698