| OLD | NEW | 
|    1 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file |    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 |    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. |    3 // BSD-style license that can be found in the LICENSE file. | 
|    4  |    4  | 
|    5 library analyzer.task.model; |    5 library analyzer.task.model; | 
|    6  |    6  | 
|    7 import 'dart:collection'; |    7 import 'dart:collection'; | 
 |    8 import 'dart:developer'; | 
|    8  |    9  | 
|    9 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask; |   10 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask; | 
 |   11 import 'package:analyzer/src/generated/error.dart' show AnalysisError; | 
|   10 import 'package:analyzer/src/generated/java_engine.dart'; |   12 import 'package:analyzer/src/generated/java_engine.dart'; | 
|   11 import 'package:analyzer/src/generated/source.dart'; |   13 import 'package:analyzer/src/generated/source.dart'; | 
 |   14 import 'package:analyzer/src/generated/utilities_general.dart'; | 
|   12 import 'package:analyzer/src/task/driver.dart'; |   15 import 'package:analyzer/src/task/driver.dart'; | 
|   13 import 'package:analyzer/src/task/model.dart'; |   16 import 'package:analyzer/src/task/model.dart'; | 
|   14  |   17  | 
|   15 /** |   18 /** | 
|   16  * A function that converts the given [key] and [value] into a [TaskInput]. |   19  * A function that converts the given [key] and [value] into a [TaskInput]. | 
|   17  */ |   20  */ | 
|   18 typedef TaskInput<E> BinaryFunction<K, V, E>(K key, V value); |   21 typedef TaskInput<E> BinaryFunction<K, V, E>(K key, V value); | 
|   19  |   22  | 
|   20 /** |   23 /** | 
|   21  * A function that takes an analysis [context] and an analysis [target] and |   24  * A function that takes an analysis [context] and an analysis [target] and | 
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   75  * Clients are expected to extend this class when creating new tasks. |   78  * Clients are expected to extend this class when creating new tasks. | 
|   76  */ |   79  */ | 
|   77 abstract class AnalysisTask { |   80 abstract class AnalysisTask { | 
|   78   /** |   81   /** | 
|   79    * A table mapping the types of analysis tasks to the number of times each |   82    * A table mapping the types of analysis tasks to the number of times each | 
|   80    * kind of task has been performed. |   83    * kind of task has been performed. | 
|   81    */ |   84    */ | 
|   82   static final Map<Type, int> countMap = new HashMap<Type, int>(); |   85   static final Map<Type, int> countMap = new HashMap<Type, int>(); | 
|   83  |   86  | 
|   84   /** |   87   /** | 
 |   88    * A table mapping the types of analysis tasks to user tags used to collect | 
 |   89    * timing data for the Observatory. | 
 |   90    */ | 
 |   91   static Map<Type, UserTag> tagMap = new HashMap<Type, UserTag>(); | 
 |   92  | 
 |   93   /** | 
|   85    * A table mapping the types of analysis tasks to stopwatches used to compute |   94    * A table mapping the types of analysis tasks to stopwatches used to compute | 
|   86    * how much time was spent executing each kind of task. |   95    * how much time was spent executing each kind of task. | 
|   87    */ |   96    */ | 
|   88   static final Map<Type, Stopwatch> stopwatchMap = |   97   static final Map<Type, Stopwatch> stopwatchMap = | 
|   89       new HashMap<Type, Stopwatch>(); |   98       new HashMap<Type, Stopwatch>(); | 
|   90  |   99  | 
|   91   /** |  100   /** | 
|   92    * The context in which the task is to be performed. |  101    * The context in which the task is to be performed. | 
|   93    */ |  102    */ | 
|   94   final AnalysisContext context; |  103   final AnalysisContext context; | 
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  189    * map should be fully populated (have a key/value pair for each result that |  198    * 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. |  199    * this task is expected to produce) or the [caughtException] should be set. | 
|  191    * |  200    * | 
|  192    * Clients should not override this method. |  201    * Clients should not override this method. | 
|  193    */ |  202    */ | 
|  194   void perform() { |  203   void perform() { | 
|  195     try { |  204     try { | 
|  196       _safelyPerform(); |  205       _safelyPerform(); | 
|  197     } on AnalysisException catch (exception, stackTrace) { |  206     } on AnalysisException catch (exception, stackTrace) { | 
|  198       caughtException = new CaughtException(exception, stackTrace); |  207       caughtException = new CaughtException(exception, stackTrace); | 
|  199       AnalysisEngine.instance.logger.logInformation( |  208       AnalysisEngine.instance.logger | 
|  200           "Task failed: ${description}", caughtException); |  209           .logInformation("Task failed: ${description}", caughtException); | 
|  201     } |  210     } | 
|  202   } |  211   } | 
|  203  |  212  | 
|  204   @override |  213   @override | 
|  205   String toString() => description; |  214   String toString() => description; | 
|  206  |  215  | 
|  207   /** |  216   /** | 
|  208    * Perform this analysis task, ensuring that all exceptions are wrapped in an |  217    * Perform this analysis task, ensuring that all exceptions are wrapped in an | 
|  209    * [AnalysisException]. |  218    * [AnalysisException]. | 
|  210    * |  219    * | 
|  211    * Clients should not override this method. |  220    * Clients should not override this method. | 
|  212    */ |  221    */ | 
|  213   void _safelyPerform() { |  222   void _safelyPerform() { | 
|  214     try { |  223     try { | 
|  215       // |  224       // | 
|  216       // Report that this task is being performed. |  225       // Report that this task is being performed. | 
|  217       // |  226       // | 
|  218       String contextName = context.name; |  227       String contextName = context.name; | 
|  219       if (contextName == null) { |  228       if (contextName == null) { | 
|  220         contextName = 'unnamed'; |  229         contextName = 'unnamed'; | 
|  221       } |  230       } | 
|  222       AnalysisEngine.instance.instrumentationService.logAnalysisTask( |  231       AnalysisEngine.instance.instrumentationService | 
|  223           contextName, this); |  232           .logAnalysisTask(contextName, this); | 
|  224       // |  233       // | 
|  225       // Gather statistics on the performance of the task. |  234       // Gather statistics on the performance of the task. | 
|  226       // |  235       // | 
|  227       int count = countMap[runtimeType]; |  236       int count = countMap[runtimeType]; | 
|  228       countMap[runtimeType] = count == null ? 1 : count + 1; |  237       countMap[runtimeType] = count == null ? 1 : count + 1; | 
 |  238 //      UserTag tag = tagMap.putIfAbsent( | 
 |  239 //          runtimeType, () => new UserTag(runtimeType.toString())); | 
|  229       Stopwatch stopwatch = stopwatchMap[runtimeType]; |  240       Stopwatch stopwatch = stopwatchMap[runtimeType]; | 
|  230       if (stopwatch == null) { |  241       if (stopwatch == null) { | 
|  231         stopwatch = new Stopwatch(); |  242         stopwatch = new Stopwatch(); | 
|  232         stopwatchMap[runtimeType] = stopwatch; |  243         stopwatchMap[runtimeType] = stopwatch; | 
|  233       } |  244       } | 
 |  245 //      UserTag previousTag = tag.makeCurrent(); | 
 |  246 //      try { | 
|  234       stopwatch.start(); |  247       stopwatch.start(); | 
|  235       // |  248       // | 
|  236       // Actually perform the task. |  249       // Actually perform the task. | 
|  237       // |  250       // | 
|  238       try { |  251       try { | 
|  239         if (dependencyCycle != null && !handlesDependencyCycles) { |  252         if (dependencyCycle != null && !handlesDependencyCycles) { | 
|  240           throw new InfiniteTaskLoopException(this, dependencyCycle); |  253           throw new InfiniteTaskLoopException(this, dependencyCycle); | 
|  241         } |  254         } | 
|  242         internalPerform(); |  255         internalPerform(); | 
|  243       } finally { |  256       } finally { | 
|  244         stopwatch.stop(); |  257         stopwatch.stop(); | 
|  245       } |  258       } | 
 |  259 //      } finally { | 
 |  260 //        previousTag.makeCurrent(); | 
 |  261 //      } | 
|  246     } on AnalysisException { |  262     } on AnalysisException { | 
|  247       rethrow; |  263       rethrow; | 
|  248     } catch (exception, stackTrace) { |  264     } catch (exception, stackTrace) { | 
|  249       throw new AnalysisException( |  265       throw new AnalysisException( | 
|  250           'Unexpected exception while performing $description', |  266           'Unexpected exception while performing $description', | 
|  251           new CaughtException(exception, stackTrace)); |  267           new CaughtException(exception, stackTrace)); | 
|  252     } |  268     } | 
|  253   } |  269   } | 
|  254 } |  270 } | 
|  255  |  271  | 
|  256 /** |  272 /** | 
|  257  * A description of a [List]-based analysis result that can be computed by an |  273  * A description of a [List]-based analysis result that can be computed by an | 
|  258  * [AnalysisTask]. |  274  * [AnalysisTask]. | 
|  259  * |  275  * | 
|  260  * Clients are not expected to subtype this class. |  276  * Clients are not expected to subtype this class. | 
|  261  */ |  277  */ | 
|  262 abstract class ListResultDescriptor<E> implements ResultDescriptor<List<E>> { |  278 abstract class ListResultDescriptor<E> implements ResultDescriptor<List<E>> { | 
|  263   /** |  279   /** | 
|  264    * Initialize a newly created analysis result to have the given [name] and |  280    * Initialize a newly created analysis result to have the given [name] and | 
|  265    * [defaultValue]. If a [cachingPolicy] is provided, it will control how long |  281    * [defaultValue]. If a [cachingPolicy] is provided, it will control how long | 
|  266    * values associated with this result will remain in the cache. |  282    * values associated with this result will remain in the cache. | 
|  267    */ |  283    */ | 
|  268   factory ListResultDescriptor(String name, List<E> defaultValue, |  284   factory ListResultDescriptor(String name, List<E> defaultValue, | 
|  269       {ResultCachingPolicy<List<E>> cachingPolicy}) = ListResultDescriptorImpl<E
     >; |  285       {ResultCachingPolicy<List<E>> cachingPolicy}) = ListResultDescriptorImpl< | 
 |  286       E>; | 
|  270  |  287  | 
|  271   @override |  288   @override | 
|  272   ListTaskInput<E> of(AnalysisTarget target); |  289   ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false}); | 
|  273 } |  290 } | 
|  274  |  291  | 
|  275 /** |  292 /** | 
|  276  * A description of an input to an [AnalysisTask] that can be used to compute |  293  * A description of an input to an [AnalysisTask] that can be used to compute | 
|  277  * that input. |  294  * that input. | 
|  278  * |  295  * | 
|  279  * Clients are not expected to subtype this class. |  296  * Clients are not expected to subtype this class. | 
|  280  */ |  297  */ | 
|  281 abstract class ListTaskInput<E> extends TaskInput<List<E>> { |  298 abstract class ListTaskInput<E> extends TaskInput<List<E>> { | 
|  282   /** |  299   /** | 
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  377    */ |  394    */ | 
|  378   V get defaultValue; |  395   V get defaultValue; | 
|  379  |  396  | 
|  380   /** |  397   /** | 
|  381    * Return the name of this descriptor. |  398    * Return the name of this descriptor. | 
|  382    */ |  399    */ | 
|  383   String get name; |  400   String get name; | 
|  384  |  401  | 
|  385   /** |  402   /** | 
|  386    * Return a task input that can be used to compute this result for the given |  403    * Return a task input that can be used to compute this result for the given | 
|  387    * [target]. |  404    * [target]. If [flushOnAccess] is `true` then the value of this result that | 
 |  405    * is associated with the [target] will be flushed when it is accessed. | 
|  388    */ |  406    */ | 
|  389   TaskInput<V> of(AnalysisTarget target); |  407   TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false}); | 
|  390 } |  408 } | 
|  391  |  409  | 
|  392 /** |  410 /** | 
 |  411  * A specification of the given [result] for the given [target]. | 
 |  412  * | 
 |  413  * Clients are not expected to subtype this class. | 
 |  414  */ | 
 |  415 class TargetedResult { | 
 |  416   /** | 
 |  417    * An empty list of results. | 
 |  418    */ | 
 |  419   static final List<TargetedResult> EMPTY_LIST = const <TargetedResult>[]; | 
 |  420  | 
 |  421   /** | 
 |  422    * The target with which the result is associated. | 
 |  423    */ | 
 |  424   final AnalysisTarget target; | 
 |  425  | 
 |  426   /** | 
 |  427    * The result associated with the target. | 
 |  428    */ | 
 |  429   final ResultDescriptor result; | 
 |  430  | 
 |  431   /** | 
 |  432    * Initialize a new targeted result. | 
 |  433    */ | 
 |  434   TargetedResult(this.target, this.result); | 
 |  435  | 
 |  436   @override | 
 |  437   int get hashCode { | 
 |  438     return JenkinsSmiHash.combine(target.hashCode, result.hashCode); | 
 |  439   } | 
 |  440  | 
 |  441   @override | 
 |  442   bool operator ==(other) { | 
 |  443     return other is TargetedResult && | 
 |  444         other.target == target && | 
 |  445         other.result == result; | 
 |  446   } | 
 |  447  | 
 |  448   @override | 
 |  449   String toString() => '$result for $target'; | 
 |  450 } | 
 |  451  | 
 |  452 /** | 
|  393  * A description of an [AnalysisTask]. |  453  * A description of an [AnalysisTask]. | 
|  394  */ |  454  */ | 
|  395 abstract class TaskDescriptor { |  455 abstract class TaskDescriptor { | 
|  396   /** |  456   /** | 
|  397    * Initialize a newly created task descriptor to have the given [name] and to |  457    * 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], |  458    * 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 |  459    * and produces the given [results]. The [buildTask] will be used to create | 
|  400    * the instance of [AnalysisTask] thusly described. |  460    * the instance of [AnalysisTask] thusly described. | 
|  401    */ |  461    */ | 
|  402   factory TaskDescriptor(String name, BuildTask buildTask, |  462   factory TaskDescriptor( | 
 |  463       String name, | 
 |  464       BuildTask buildTask, | 
|  403       CreateTaskInputs inputBuilder, |  465       CreateTaskInputs inputBuilder, | 
|  404       List<ResultDescriptor> results) = TaskDescriptorImpl; |  466       List<ResultDescriptor> results) = TaskDescriptorImpl; | 
|  405  |  467  | 
|  406   /** |  468   /** | 
|  407    * Return the builder used to build the inputs to the task. |  469    * Return the builder used to build the inputs to the task. | 
|  408    */ |  470    */ | 
|  409   CreateTaskInputs get createTaskInputs; |  471   CreateTaskInputs get createTaskInputs; | 
|  410  |  472  | 
|  411   /** |  473   /** | 
|  412    * Return the name of the task being described. |  474    * Return the name of the task being described. | 
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  476  |  538  | 
|  477   /** |  539   /** | 
|  478    * Set the [value] that was computed for the current result. |  540    * Set the [value] that was computed for the current result. | 
|  479    * |  541    * | 
|  480    * Throws a [StateError] if [moveNext] has not been invoked or if the last |  542    * Throws a [StateError] if [moveNext] has not been invoked or if the last | 
|  481    * invocation of [moveNext] returned `false`. |  543    * invocation of [moveNext] returned `false`. | 
|  482    */ |  544    */ | 
|  483   void set currentValue(Object value); |  545   void set currentValue(Object value); | 
|  484  |  546  | 
|  485   /** |  547   /** | 
 |  548    * Return `true` if the value accessed by this input builder should be flushed | 
 |  549    * from the cache at the time it is retrieved. | 
 |  550    */ | 
 |  551   bool get flushOnAccess; | 
 |  552  | 
 |  553   /** | 
|  486    * Return the [value] that was computed by this builder. |  554    * Return the [value] that was computed by this builder. | 
|  487    * |  555    * | 
|  488    * Throws a [StateError] if [moveNext] has not been invoked or if the last |  556    * Throws a [StateError] if [moveNext] has not been invoked or if the last | 
|  489    * invocation of [moveNext] returned `true`. |  557    * invocation of [moveNext] returned `true`. | 
|  490    * |  558    * | 
|  491    * Returns `null` if no value could be computed due to a circular dependency. |  559    * Returns `null` if no value could be computed due to a circular dependency. | 
|  492    */ |  560    */ | 
|  493   V get inputValue; |  561   V get inputValue; | 
|  494  |  562  | 
|  495   /** |  563   /** | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
|  507    * be computed, or `false` if the inputs have been computed. |  575    * be computed, or `false` if the inputs have been computed. | 
|  508    * |  576    * | 
|  509    * It is safe to invoke [moveNext] after it has returned `false`. In this case |  577    * It is safe to invoke [moveNext] after it has returned `false`. In this case | 
|  510    * [moveNext] has no effect and will again return `false`. |  578    * [moveNext] has no effect and will again return `false`. | 
|  511    * |  579    * | 
|  512    * Throws a [StateError] if the value of the current result has not been |  580    * Throws a [StateError] if the value of the current result has not been | 
|  513    * provided using [currentValue]. |  581    * provided using [currentValue]. | 
|  514    */ |  582    */ | 
|  515   bool moveNext(); |  583   bool moveNext(); | 
|  516 } |  584 } | 
 |  585  | 
 |  586 /** | 
 |  587  * [WorkManager]s are used to drive analysis. | 
 |  588  * | 
 |  589  * They know specific of the targets and results they care about, | 
 |  590  * so they can request analysis results in optimal order. | 
 |  591  */ | 
 |  592 abstract class WorkManager { | 
 |  593   /** | 
 |  594    * Notifies the manager about changes in the explicit source list. | 
 |  595    */ | 
 |  596   void applyChange(List<Source> addedSources, List<Source> changedSources, | 
 |  597       List<Source> removedSources); | 
 |  598  | 
 |  599   /** | 
 |  600    * Notifies the managers that the given set of priority [targets] was set. | 
 |  601    */ | 
 |  602   void applyPriorityTargets(List<AnalysisTarget> targets); | 
 |  603  | 
 |  604   /** | 
 |  605    * Return a list of all of the errors associated with the given [source]. | 
 |  606    * The list of errors will be empty if the source is not known to the context | 
 |  607    * or if there are no errors in the source. The errors contained in the list | 
 |  608    * can be incomplete. | 
 |  609    */ | 
 |  610   List<AnalysisError> getErrors(Source source); | 
 |  611  | 
 |  612   /** | 
 |  613    * Return the next [TargetedResult] that this work manager wants to be | 
 |  614    * computed, or `null` if this manager doesn't need any new results. | 
 |  615    * | 
 |  616    * Note, that it is not guaranteed that this result will be computed, it is | 
 |  617    * up to the work manager to check whether the result is already computed | 
 |  618    * (for example during the next [getNextResult] invocation) or computation | 
 |  619    * of the same result should be requested again. | 
 |  620    */ | 
 |  621   TargetedResult getNextResult(); | 
 |  622  | 
 |  623   /** | 
 |  624    * Return the priority if the next work order this work manager want to be | 
 |  625    * computed. The [AnalysisDriver] will perform the work order with | 
 |  626    * the highest priority. | 
 |  627    * | 
 |  628    * Even if the returned value is [WorkOrderPriority.NONE], it still does not | 
 |  629    * guarantee that [getNextResult] will return not `null`. | 
 |  630    */ | 
 |  631   WorkOrderPriority getNextResultPriority(); | 
 |  632  | 
 |  633   /** | 
 |  634    * Notifies the manager about analysis options changes. | 
 |  635    */ | 
 |  636   void onAnalysisOptionsChanged(); | 
 |  637  | 
 |  638   /** | 
 |  639    * Notifies the manager about [SourceFactory] changes. | 
 |  640    */ | 
 |  641   void onSourceFactoryChanged(); | 
 |  642  | 
 |  643   /** | 
 |  644    * Notifies the manager that the given [outputs] were produced for | 
 |  645    * the given [target]. | 
 |  646    */ | 
 |  647   void resultsComputed( | 
 |  648       AnalysisTarget target, Map<ResultDescriptor, dynamic> outputs); | 
 |  649 } | 
 |  650  | 
 |  651 /** | 
 |  652  * The priorities of work orders returned by [WorkManager]s. | 
 |  653  * | 
 |  654  * New priorities may be added with time, clients need to tolerate this. | 
 |  655  */ | 
 |  656 enum WorkOrderPriority { | 
 |  657   /** | 
 |  658    * Responding to an user's action. | 
 |  659    */ | 
 |  660   INTERACTIVE, | 
 |  661  | 
 |  662   /** | 
 |  663    * Computing information for priority sources. | 
 |  664    */ | 
 |  665   PRIORITY, | 
 |  666  | 
 |  667   /** | 
 |  668    * A work should be done, but without any special urgency. | 
 |  669    */ | 
 |  670   NORMAL, | 
 |  671  | 
 |  672   /** | 
 |  673    * Nothing to do. | 
 |  674    */ | 
 |  675   NONE | 
 |  676 } | 
| OLD | NEW |