| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 // Copyright (c) 2014, 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 // This code was auto-generated, is not intended to be edited, and is subject to |  | 
| 6 // significant change. Please see the README file for more information. |  | 
| 7 |  | 
| 8 library engine; |  | 
| 9 |  | 
| 10 import 'dart:async'; |  | 
| 11 import 'dart:collection'; |  | 
| 12 import 'dart:math' as math; |  | 
| 13 |  | 
| 14 import 'package:analyzer/src/cancelable_future.dart'; |  | 
| 15 import 'package:analyzer/src/context/cache.dart' as cache; |  | 
| 16 import 'package:analyzer/src/context/context.dart' as newContext; |  | 
| 17 import 'package:analyzer/src/generated/incremental_resolution_validator.dart'; |  | 
| 18 import 'package:analyzer/src/plugin/command_line_plugin.dart'; |  | 
| 19 import 'package:analyzer/src/plugin/engine_plugin.dart'; |  | 
| 20 import 'package:analyzer/src/plugin/options_plugin.dart'; |  | 
| 21 import 'package:analyzer/src/services/lint.dart'; |  | 
| 22 import 'package:analyzer/src/task/manager.dart'; |  | 
| 23 import 'package:analyzer/task/dart.dart'; |  | 
| 24 import 'package:analyzer/task/model.dart'; |  | 
| 25 import 'package:html/dom.dart' show Document; |  | 
| 26 import 'package:plugin/manager.dart'; |  | 
| 27 import 'package:plugin/plugin.dart'; |  | 
| 28 |  | 
| 29 import '../../instrumentation/instrumentation.dart'; |  | 
| 30 import 'ast.dart'; |  | 
| 31 import 'constant.dart'; |  | 
| 32 import 'element.dart'; |  | 
| 33 import 'error.dart'; |  | 
| 34 import 'error_verifier.dart'; |  | 
| 35 import 'html.dart' as ht; |  | 
| 36 import 'incremental_resolver.dart' |  | 
| 37     show IncrementalResolver, PoorMansIncrementalResolver; |  | 
| 38 import 'incremental_scanner.dart'; |  | 
| 39 import 'java_core.dart'; |  | 
| 40 import 'java_engine.dart'; |  | 
| 41 import 'parser.dart' show Parser, IncrementalParser; |  | 
| 42 import 'resolver.dart'; |  | 
| 43 import 'scanner.dart'; |  | 
| 44 import 'sdk.dart' show DartSdk; |  | 
| 45 import 'source.dart'; |  | 
| 46 import 'utilities_collection.dart'; |  | 
| 47 import 'utilities_general.dart'; |  | 
| 48 |  | 
| 49 /** |  | 
| 50  * Used by [AnalysisOptions] to allow function bodies to be analyzed in some |  | 
| 51  * sources but not others. |  | 
| 52  */ |  | 
| 53 typedef bool AnalyzeFunctionBodiesPredicate(Source source); |  | 
| 54 |  | 
| 55 /** |  | 
| 56  * Type of callback functions used by PendingFuture.  Functions of this type |  | 
| 57  * should perform a computation based on the data in [sourceEntry] and return |  | 
| 58  * it.  If the computation can't be performed yet because more analysis is |  | 
| 59  * needed, null should be returned. |  | 
| 60  * |  | 
| 61  * The function may also throw an exception, in which case the corresponding |  | 
| 62  * future will be completed with failure. |  | 
| 63  * |  | 
| 64  * Since this function is called while the state of analysis is being updated, |  | 
| 65  * it should be free of side effects so that it doesn't cause reentrant |  | 
| 66  * changes to the analysis state. |  | 
| 67  */ |  | 
| 68 typedef T PendingFutureComputer<T>(SourceEntry sourceEntry); |  | 
| 69 |  | 
| 70 /** |  | 
| 71  * An LRU cache of information related to analysis. |  | 
| 72  */ |  | 
| 73 class AnalysisCache { |  | 
| 74   /** |  | 
| 75    * A flag used to control whether trace information should be produced when |  | 
| 76    * the content of the cache is modified. |  | 
| 77    */ |  | 
| 78   static bool _TRACE_CHANGES = false; |  | 
| 79 |  | 
| 80   /** |  | 
| 81    * A list containing the partitions of which this cache is comprised. |  | 
| 82    */ |  | 
| 83   final List<CachePartition> _partitions; |  | 
| 84 |  | 
| 85   /** |  | 
| 86    * Initialize a newly created cache to have the given [_partitions]. The |  | 
| 87    * partitions will be searched in the order in which they appear in the list, |  | 
| 88    * so the most specific partition (usually an [SdkCachePartition]) should be |  | 
| 89    * first and the most general (usually a [UniversalCachePartition]) last. |  | 
| 90    */ |  | 
| 91   AnalysisCache(this._partitions); |  | 
| 92 |  | 
| 93   /** |  | 
| 94    * Return the number of entries in this cache that have an AST associated with |  | 
| 95    * them. |  | 
| 96    */ |  | 
| 97   int get astSize => _partitions[_partitions.length - 1].astSize; |  | 
| 98 |  | 
| 99   /** |  | 
| 100    * Return information about each of the partitions in this cache. |  | 
| 101    */ |  | 
| 102   List<AnalysisContextStatistics_PartitionData> get partitionData { |  | 
| 103     int count = _partitions.length; |  | 
| 104     List<AnalysisContextStatistics_PartitionData> data = |  | 
| 105         new List<AnalysisContextStatistics_PartitionData>(count); |  | 
| 106     for (int i = 0; i < count; i++) { |  | 
| 107       CachePartition partition = _partitions[i]; |  | 
| 108       data[i] = new AnalysisContextStatisticsImpl_PartitionDataImpl( |  | 
| 109           partition.astSize, partition.map.length); |  | 
| 110     } |  | 
| 111     return data; |  | 
| 112   } |  | 
| 113 |  | 
| 114   /** |  | 
| 115    * Record that the AST associated with the given [source] was just read from |  | 
| 116    * the cache. |  | 
| 117    */ |  | 
| 118   void accessedAst(Source source) { |  | 
| 119     int count = _partitions.length; |  | 
| 120     for (int i = 0; i < count; i++) { |  | 
| 121       if (_partitions[i].contains(source)) { |  | 
| 122         _partitions[i].accessedAst(source); |  | 
| 123         return; |  | 
| 124       } |  | 
| 125     } |  | 
| 126   } |  | 
| 127 |  | 
| 128   /** |  | 
| 129    * Return the entry associated with the given [source]. |  | 
| 130    */ |  | 
| 131   SourceEntry get(Source source) { |  | 
| 132     int count = _partitions.length; |  | 
| 133     for (int i = 0; i < count; i++) { |  | 
| 134       if (_partitions[i].contains(source)) { |  | 
| 135         return _partitions[i].get(source); |  | 
| 136       } |  | 
| 137     } |  | 
| 138     // |  | 
| 139     // We should never get to this point because the last partition should |  | 
| 140     // always be a universal partition, except in the case of the SDK context, |  | 
| 141     // in which case the source should always be part of the SDK. |  | 
| 142     // |  | 
| 143     return null; |  | 
| 144   } |  | 
| 145 |  | 
| 146   /** |  | 
| 147    * Return context that owns the given [source]. |  | 
| 148    */ |  | 
| 149   InternalAnalysisContext getContextFor(Source source) { |  | 
| 150     int count = _partitions.length; |  | 
| 151     for (int i = 0; i < count; i++) { |  | 
| 152       if (_partitions[i].contains(source)) { |  | 
| 153         return _partitions[i].context; |  | 
| 154       } |  | 
| 155     } |  | 
| 156     // |  | 
| 157     // We should never get to this point because the last partition should |  | 
| 158     // always be a universal partition, except in the case of the SDK context, |  | 
| 159     // in which case the source should always be part of the SDK. |  | 
| 160     // |  | 
| 161     AnalysisEngine.instance.logger.logInformation( |  | 
| 162         "Could not find context for ${source.fullName}", |  | 
| 163         new CaughtException(new AnalysisException(), null)); |  | 
| 164     return null; |  | 
| 165   } |  | 
| 166 |  | 
| 167   /** |  | 
| 168    * Return an iterator returning all of the map entries mapping sources to |  | 
| 169    * cache entries. |  | 
| 170    */ |  | 
| 171   MapIterator<Source, SourceEntry> iterator() { |  | 
| 172     int count = _partitions.length; |  | 
| 173     List<Map<Source, SourceEntry>> maps = |  | 
| 174         new List<Map<Source, SourceEntry>>(count); |  | 
| 175     for (int i = 0; i < count; i++) { |  | 
| 176       maps[i] = _partitions[i].map; |  | 
| 177     } |  | 
| 178     return new MultipleMapIterator<Source, SourceEntry>(maps); |  | 
| 179   } |  | 
| 180 |  | 
| 181   /** |  | 
| 182    * Associate the given [entry] with the given [source]. |  | 
| 183    */ |  | 
| 184   void put(Source source, SourceEntry entry) { |  | 
| 185     entry.fixExceptionState(); |  | 
| 186     int count = _partitions.length; |  | 
| 187     for (int i = 0; i < count; i++) { |  | 
| 188       if (_partitions[i].contains(source)) { |  | 
| 189         if (_TRACE_CHANGES) { |  | 
| 190           try { |  | 
| 191             SourceEntry oldEntry = _partitions[i].get(source); |  | 
| 192             if (oldEntry == null) { |  | 
| 193               AnalysisEngine.instance.logger.logInformation( |  | 
| 194                   "Added a cache entry for '${source.fullName}'."); |  | 
| 195             } else { |  | 
| 196               AnalysisEngine.instance.logger.logInformation( |  | 
| 197                   "Modified the cache entry for ${source.fullName}'. Diff = ${en
       try.getDiff(oldEntry)}"); |  | 
| 198             } |  | 
| 199           } catch (exception) { |  | 
| 200             // Ignored |  | 
| 201             JavaSystem.currentTimeMillis(); |  | 
| 202           } |  | 
| 203         } |  | 
| 204         _partitions[i].put(source, entry); |  | 
| 205         return; |  | 
| 206       } |  | 
| 207     } |  | 
| 208   } |  | 
| 209 |  | 
| 210   /** |  | 
| 211    * Remove all information related to the given [source] from this cache. |  | 
| 212    */ |  | 
| 213   void remove(Source source) { |  | 
| 214     int count = _partitions.length; |  | 
| 215     for (int i = 0; i < count; i++) { |  | 
| 216       if (_partitions[i].contains(source)) { |  | 
| 217         if (_TRACE_CHANGES) { |  | 
| 218           try { |  | 
| 219             AnalysisEngine.instance.logger.logInformation( |  | 
| 220                 "Removed the cache entry for ${source.fullName}'."); |  | 
| 221           } catch (exception) { |  | 
| 222             // Ignored |  | 
| 223             JavaSystem.currentTimeMillis(); |  | 
| 224           } |  | 
| 225         } |  | 
| 226         _partitions[i].remove(source); |  | 
| 227         return; |  | 
| 228       } |  | 
| 229     } |  | 
| 230   } |  | 
| 231 |  | 
| 232   /** |  | 
| 233    * Record that the AST associated with the given [source] was just removed |  | 
| 234    * from the cache. |  | 
| 235    */ |  | 
| 236   void removedAst(Source source) { |  | 
| 237     int count = _partitions.length; |  | 
| 238     for (int i = 0; i < count; i++) { |  | 
| 239       if (_partitions[i].contains(source)) { |  | 
| 240         _partitions[i].removedAst(source); |  | 
| 241         return; |  | 
| 242       } |  | 
| 243     } |  | 
| 244   } |  | 
| 245 |  | 
| 246   /** |  | 
| 247    * Return the number of sources that are mapped to cache entries. |  | 
| 248    */ |  | 
| 249   int size() { |  | 
| 250     int size = 0; |  | 
| 251     int count = _partitions.length; |  | 
| 252     for (int i = 0; i < count; i++) { |  | 
| 253       size += _partitions[i].size(); |  | 
| 254     } |  | 
| 255     return size; |  | 
| 256   } |  | 
| 257 |  | 
| 258   /** |  | 
| 259    * Record that the AST associated with the given [source] was just stored to |  | 
| 260    * the cache. |  | 
| 261    */ |  | 
| 262   void storedAst(Source source) { |  | 
| 263     int count = _partitions.length; |  | 
| 264     for (int i = 0; i < count; i++) { |  | 
| 265       if (_partitions[i].contains(source)) { |  | 
| 266         _partitions[i].storedAst(source); |  | 
| 267         return; |  | 
| 268       } |  | 
| 269     } |  | 
| 270   } |  | 
| 271 } |  | 
| 272 |  | 
| 273 /** |  | 
| 274  * A context in which a single analysis can be performed and incrementally |  | 
| 275  * maintained. The context includes such information as the version of the SDK |  | 
| 276  * being analyzed against as well as the package-root used to resolve 'package:' |  | 
| 277  * URI's. (Both of which are known indirectly through the [SourceFactory].) |  | 
| 278  * |  | 
| 279  * An analysis context also represents the state of the analysis, which includes |  | 
| 280  * knowing which sources have been included in the analysis (either directly or |  | 
| 281  * indirectly) and the results of the analysis. Sources must be added and |  | 
| 282  * removed from the context using the method [applyChanges], which is also used |  | 
| 283  * to notify the context when sources have been modified and, consequently, |  | 
| 284  * previously known results might have been invalidated. |  | 
| 285  * |  | 
| 286  * There are two ways to access the results of the analysis. The most common is |  | 
| 287  * to use one of the 'get' methods to access the results. The 'get' methods have |  | 
| 288  * the advantage that they will always return quickly, but have the disadvantage |  | 
| 289  * that if the results are not currently available they will return either |  | 
| 290  * nothing or in some cases an incomplete result. The second way to access |  | 
| 291  * results is by using one of the 'compute' methods. The 'compute' methods will |  | 
| 292  * always attempt to compute the requested results but might block the caller |  | 
| 293  * for a significant period of time. |  | 
| 294  * |  | 
| 295  * When results have been invalidated, have never been computed (as is the case |  | 
| 296  * for newly added sources), or have been removed from the cache, they are |  | 
| 297  * <b>not</b> automatically recreated. They will only be recreated if one of the |  | 
| 298  * 'compute' methods is invoked. |  | 
| 299  * |  | 
| 300  * However, this is not always acceptable. Some clients need to keep the |  | 
| 301  * analysis results up-to-date. For such clients there is a mechanism that |  | 
| 302  * allows them to incrementally perform needed analysis and get notified of the |  | 
| 303  * consequent changes to the analysis results. This mechanism is realized by the |  | 
| 304  * method [performAnalysisTask]. |  | 
| 305  * |  | 
| 306  * Analysis engine allows for having more than one context. This can be used, |  | 
| 307  * for example, to perform one analysis based on the state of files on disk and |  | 
| 308  * a separate analysis based on the state of those files in open editors. It can |  | 
| 309  * also be used to perform an analysis based on a proposed future state, such as |  | 
| 310  * the state after a refactoring. |  | 
| 311  */ |  | 
| 312 abstract class AnalysisContext { |  | 
| 313   /** |  | 
| 314    * An empty list of contexts. |  | 
| 315    */ |  | 
| 316   static const List<AnalysisContext> EMPTY_LIST = const <AnalysisContext>[]; |  | 
| 317 |  | 
| 318   /** |  | 
| 319    * Return the set of analysis options controlling the behavior of this |  | 
| 320    * context. Clients should not modify the returned set of options. The options |  | 
| 321    * should only be set by invoking the method [setAnalysisOptions]. |  | 
| 322    */ |  | 
| 323   AnalysisOptions get analysisOptions; |  | 
| 324 |  | 
| 325   /** |  | 
| 326    * Set the set of analysis options controlling the behavior of this context to |  | 
| 327    * the given [options]. Clients can safely assume that all necessary analysis |  | 
| 328    * results have been invalidated. |  | 
| 329    */ |  | 
| 330   void set analysisOptions(AnalysisOptions options); |  | 
| 331 |  | 
| 332   /** |  | 
| 333    * Set the order in which sources will be analyzed by [performAnalysisTask] to |  | 
| 334    * match the order of the sources in the given list of [sources]. If a source |  | 
| 335    * that needs to be analyzed is not contained in the list, then it will be |  | 
| 336    * treated as if it were at the end of the list. If the list is empty (or |  | 
| 337    * `null`) then no sources will be given priority over other sources. |  | 
| 338    * |  | 
| 339    * Changes made to the list after this method returns will <b>not</b> be |  | 
| 340    * reflected in the priority order. |  | 
| 341    */ |  | 
| 342   void set analysisPriorityOrder(List<Source> sources); |  | 
| 343 |  | 
| 344   /** |  | 
| 345    * Return the set of declared variables used when computing constant values. |  | 
| 346    */ |  | 
| 347   DeclaredVariables get declaredVariables; |  | 
| 348 |  | 
| 349   /** |  | 
| 350    * Return a list containing all of the sources known to this context that |  | 
| 351    * represent HTML files. The contents of the list can be incomplete. |  | 
| 352    */ |  | 
| 353   List<Source> get htmlSources; |  | 
| 354 |  | 
| 355   /** |  | 
| 356    * Returns `true` if this context was disposed using [dispose]. |  | 
| 357    */ |  | 
| 358   bool get isDisposed; |  | 
| 359 |  | 
| 360   /** |  | 
| 361    * Return a list containing all of the sources known to this context that |  | 
| 362    * represent the defining compilation unit of a library that can be run within |  | 
| 363    * a browser. The sources that are returned represent libraries that have a |  | 
| 364    * 'main' method and are either referenced by an HTML file or import, directly |  | 
| 365    * or indirectly, a client-only library. The contents of the list can be |  | 
| 366    * incomplete. |  | 
| 367    */ |  | 
| 368   List<Source> get launchableClientLibrarySources; |  | 
| 369 |  | 
| 370   /** |  | 
| 371    * Return a list containing all of the sources known to this context that |  | 
| 372    * represent the defining compilation unit of a library that can be run |  | 
| 373    * outside of a browser. The contents of the list can be incomplete. |  | 
| 374    */ |  | 
| 375   List<Source> get launchableServerLibrarySources; |  | 
| 376 |  | 
| 377   /** |  | 
| 378    * Return a list containing all of the sources known to this context that |  | 
| 379    * represent the defining compilation unit of a library. The contents of the |  | 
| 380    * list can be incomplete. |  | 
| 381    */ |  | 
| 382   List<Source> get librarySources; |  | 
| 383 |  | 
| 384   /** |  | 
| 385    * Return a client-provided name used to identify this context, or `null` if |  | 
| 386    * the client has not provided a name. |  | 
| 387    */ |  | 
| 388   String get name; |  | 
| 389 |  | 
| 390   /** |  | 
| 391    * Set the client-provided name used to identify this context to the given |  | 
| 392    * [name]. |  | 
| 393    */ |  | 
| 394   set name(String name); |  | 
| 395 |  | 
| 396   /** |  | 
| 397    * The stream that is notified when sources have been added or removed, |  | 
| 398    * or the source's content has changed. |  | 
| 399    */ |  | 
| 400   Stream<SourcesChangedEvent> get onSourcesChanged; |  | 
| 401 |  | 
| 402   /** |  | 
| 403    * Return the source factory used to create the sources that can be analyzed |  | 
| 404    * in this context. |  | 
| 405    */ |  | 
| 406   SourceFactory get sourceFactory; |  | 
| 407 |  | 
| 408   /** |  | 
| 409    * Set the source factory used to create the sources that can be analyzed in |  | 
| 410    * this context to the given source [factory]. Clients can safely assume that |  | 
| 411    * all analysis results have been invalidated. |  | 
| 412    */ |  | 
| 413   void set sourceFactory(SourceFactory factory); |  | 
| 414 |  | 
| 415   /** |  | 
| 416    * Return a list containing all of the sources known to this context. |  | 
| 417    */ |  | 
| 418   List<Source> get sources; |  | 
| 419 |  | 
| 420   /** |  | 
| 421    * Return a type provider for this context or throw [AnalysisException] if |  | 
| 422    * either `dart:core` or `dart:async` cannot be resolved. |  | 
| 423    */ |  | 
| 424   TypeProvider get typeProvider; |  | 
| 425 |  | 
| 426   /** |  | 
| 427    * Add the given [listener] to the list of objects that are to be notified |  | 
| 428    * when various analysis results are produced in this context. |  | 
| 429    */ |  | 
| 430   void addListener(AnalysisListener listener); |  | 
| 431 |  | 
| 432   /** |  | 
| 433    * Apply the given [delta] to change the level of analysis that will be |  | 
| 434    * performed for the sources known to this context. |  | 
| 435    */ |  | 
| 436   void applyAnalysisDelta(AnalysisDelta delta); |  | 
| 437 |  | 
| 438   /** |  | 
| 439    * Apply the changes specified by the given [changeSet] to this context. Any |  | 
| 440    * analysis results that have been invalidated by these changes will be |  | 
| 441    * removed. |  | 
| 442    */ |  | 
| 443   void applyChanges(ChangeSet changeSet); |  | 
| 444 |  | 
| 445   /** |  | 
| 446    * Return the documentation comment for the given [element] as it appears in |  | 
| 447    * the original source (complete with the beginning and ending delimiters) for |  | 
| 448    * block documentation comments, or lines starting with `"///"` and separated |  | 
| 449    * with `"\n"` characters for end-of-line documentation comments, or `null` if |  | 
| 450    * the element does not have a documentation comment associated with it. This |  | 
| 451    * can be a long-running operation if the information needed to access the |  | 
| 452    * comment is not cached. |  | 
| 453    * |  | 
| 454    * Throws an [AnalysisException] if the documentation comment could not be |  | 
| 455    * determined because the analysis could not be performed. |  | 
| 456    * |  | 
| 457    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 458    */ |  | 
| 459   String computeDocumentationComment(Element element); |  | 
| 460 |  | 
| 461   /** |  | 
| 462    * Return a list containing all of the errors associated with the given |  | 
| 463    * [source]. If the errors are not already known then the source will be |  | 
| 464    * analyzed in order to determine the errors associated with it. |  | 
| 465    * |  | 
| 466    * Throws an [AnalysisException] if the errors could not be determined because |  | 
| 467    * the analysis could not be performed. |  | 
| 468    * |  | 
| 469    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 470    * |  | 
| 471    * See [getErrors]. |  | 
| 472    */ |  | 
| 473   List<AnalysisError> computeErrors(Source source); |  | 
| 474 |  | 
| 475   /** |  | 
| 476    * Return the element model corresponding to the HTML file defined by the |  | 
| 477    * given [source]. If the element model does not yet exist it will be created. |  | 
| 478    * The process of creating an element model for an HTML file can be |  | 
| 479    * long-running, depending on the size of the file and the number of libraries |  | 
| 480    * that are defined in it (via script tags) that also need to have a model |  | 
| 481    * built for them. |  | 
| 482    * |  | 
| 483    * Throws AnalysisException if the element model could not be determined |  | 
| 484    * because the analysis could not be performed. |  | 
| 485    * |  | 
| 486    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 487    * |  | 
| 488    * See [getHtmlElement]. |  | 
| 489    */ |  | 
| 490   @deprecated |  | 
| 491   HtmlElement computeHtmlElement(Source source); |  | 
| 492 |  | 
| 493   /** |  | 
| 494    * Return the kind of the given [source], computing it's kind if it is not |  | 
| 495    * already known. Return [SourceKind.UNKNOWN] if the source is not contained |  | 
| 496    * in this context. |  | 
| 497    * |  | 
| 498    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 499    * |  | 
| 500    * See [getKindOf]. |  | 
| 501    */ |  | 
| 502   SourceKind computeKindOf(Source source); |  | 
| 503 |  | 
| 504   /** |  | 
| 505    * Return the element model corresponding to the library defined by the given |  | 
| 506    * [source]. If the element model does not yet exist it will be created. The |  | 
| 507    * process of creating an element model for a library can long-running, |  | 
| 508    * depending on the size of the library and the number of libraries that are |  | 
| 509    * imported into it that also need to have a model built for them. |  | 
| 510    * |  | 
| 511    * Throws an [AnalysisException] if the element model could not be determined |  | 
| 512    * because the analysis could not be performed. |  | 
| 513    * |  | 
| 514    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 515    * |  | 
| 516    * See [getLibraryElement]. |  | 
| 517    */ |  | 
| 518   LibraryElement computeLibraryElement(Source source); |  | 
| 519 |  | 
| 520   /** |  | 
| 521    * Return the line information for the given [source], or `null` if the source |  | 
| 522    * is not of a recognized kind (neither a Dart nor HTML file). If the line |  | 
| 523    * information was not previously known it will be created. The line |  | 
| 524    * information is used to map offsets from the beginning of the source to line |  | 
| 525    * and column pairs. |  | 
| 526    * |  | 
| 527    * Throws an [AnalysisException] if the line information could not be |  | 
| 528    * determined because the analysis could not be performed. |  | 
| 529    * |  | 
| 530    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 531    * |  | 
| 532    * See [getLineInfo]. |  | 
| 533    */ |  | 
| 534   LineInfo computeLineInfo(Source source); |  | 
| 535 |  | 
| 536   /** |  | 
| 537    * Return a future which will be completed with the fully resolved AST for a |  | 
| 538    * single compilation unit within the given library, once that AST is up to |  | 
| 539    * date. |  | 
| 540    * |  | 
| 541    * If the resolved AST can't be computed for some reason, the future will be |  | 
| 542    * completed with an error.  One possible error is AnalysisNotScheduledError, |  | 
| 543    * which means that the resolved AST can't be computed because the given |  | 
| 544    * source file is not scheduled to be analyzed within the context of the |  | 
| 545    * given library. |  | 
| 546    */ |  | 
| 547   CancelableFuture<CompilationUnit> computeResolvedCompilationUnitAsync( |  | 
| 548       Source source, Source librarySource); |  | 
| 549 |  | 
| 550   /** |  | 
| 551    * Notifies the context that the client is going to stop using this context. |  | 
| 552    */ |  | 
| 553   void dispose(); |  | 
| 554 |  | 
| 555   /** |  | 
| 556    * Return `true` if the given [source] exists. |  | 
| 557    * |  | 
| 558    * This method should be used rather than the method [Source.exists] because |  | 
| 559    * contexts can have local overrides of the content of a source that the |  | 
| 560    * source is not aware of and a source with local content is considered to |  | 
| 561    * exist even if there is no file on disk. |  | 
| 562    */ |  | 
| 563   bool exists(Source source); |  | 
| 564 |  | 
| 565   /** |  | 
| 566    * Return the element model corresponding to the compilation unit defined by |  | 
| 567    * the given [unitSource] in the library defined by the given [librarySource], |  | 
| 568    * or `null` if the element model does not currently exist or if the library |  | 
| 569    * cannot be analyzed for some reason. |  | 
| 570    */ |  | 
| 571   CompilationUnitElement getCompilationUnitElement( |  | 
| 572       Source unitSource, Source librarySource); |  | 
| 573 |  | 
| 574   /** |  | 
| 575    * Return the contents and timestamp of the given [source]. |  | 
| 576    * |  | 
| 577    * This method should be used rather than the method [Source.getContents] |  | 
| 578    * because contexts can have local overrides of the content of a source that |  | 
| 579    * the source is not aware of. |  | 
| 580    */ |  | 
| 581   TimestampedData<String> getContents(Source source); |  | 
| 582 |  | 
| 583   /** |  | 
| 584    * Return the element referenced by the given [location], or `null` if the |  | 
| 585    * element is not immediately available or if there is no element with the |  | 
| 586    * given location. The latter condition can occur, for example, if the |  | 
| 587    * location describes an element from a different context or if the element |  | 
| 588    * has been removed from this context as a result of some change since it was |  | 
| 589    * originally obtained. |  | 
| 590    */ |  | 
| 591   Element getElement(ElementLocation location); |  | 
| 592 |  | 
| 593   /** |  | 
| 594    * Return an analysis error info containing the list of all of the errors and |  | 
| 595    * the line info associated with the given [source]. The list of errors will |  | 
| 596    * be empty if the source is not known to this context or if there are no |  | 
| 597    * errors in the source. The errors contained in the list can be incomplete. |  | 
| 598    * |  | 
| 599    * See [computeErrors]. |  | 
| 600    */ |  | 
| 601   AnalysisErrorInfo getErrors(Source source); |  | 
| 602 |  | 
| 603   /** |  | 
| 604    * Return the element model corresponding to the HTML file defined by the |  | 
| 605    * given [source], or `null` if the source does not represent an HTML file, |  | 
| 606    * the element representing the file has not yet been created, or the analysis |  | 
| 607    * of the HTML file failed for some reason. |  | 
| 608    * |  | 
| 609    * See [computeHtmlElement]. |  | 
| 610    */ |  | 
| 611   @deprecated |  | 
| 612   HtmlElement getHtmlElement(Source source); |  | 
| 613 |  | 
| 614   /** |  | 
| 615    * Return the sources for the HTML files that reference the compilation unit |  | 
| 616    * with the given [source]. If the source does not represent a Dart source or |  | 
| 617    * is not known to this context, the returned list will be empty. The contents |  | 
| 618    * of the list can be incomplete. |  | 
| 619    */ |  | 
| 620   List<Source> getHtmlFilesReferencing(Source source); |  | 
| 621 |  | 
| 622   /** |  | 
| 623    * Return the kind of the given [source], or `null` if the kind is not known |  | 
| 624    * to this context. |  | 
| 625    * |  | 
| 626    * See [computeKindOf]. |  | 
| 627    */ |  | 
| 628   SourceKind getKindOf(Source source); |  | 
| 629 |  | 
| 630   /** |  | 
| 631    * Return the sources for the defining compilation units of any libraries of |  | 
| 632    * which the given [source] is a part. The list will normally contain a single |  | 
| 633    * library because most Dart sources are only included in a single library, |  | 
| 634    * but it is possible to have a part that is contained in multiple identically |  | 
| 635    * named libraries. If the source represents the defining compilation unit of |  | 
| 636    * a library, then the returned list will contain the given source as its only |  | 
| 637    * element. If the source does not represent a Dart source or is not known to |  | 
| 638    * this context, the returned list will be empty. The contents of the list can |  | 
| 639    * be incomplete. |  | 
| 640    */ |  | 
| 641   List<Source> getLibrariesContaining(Source source); |  | 
| 642 |  | 
| 643   /** |  | 
| 644    * Return the sources for the defining compilation units of any libraries that |  | 
| 645    * depend on the library defined by the given [librarySource]. One library |  | 
| 646    * depends on another if it either imports or exports that library. |  | 
| 647    */ |  | 
| 648   List<Source> getLibrariesDependingOn(Source librarySource); |  | 
| 649 |  | 
| 650   /** |  | 
| 651    * Return the sources for the defining compilation units of any libraries that |  | 
| 652    * are referenced from the HTML file defined by the given [htmlSource]. |  | 
| 653    */ |  | 
| 654   List<Source> getLibrariesReferencedFromHtml(Source htmlSource); |  | 
| 655 |  | 
| 656   /** |  | 
| 657    * Return the element model corresponding to the library defined by the given |  | 
| 658    * [source], or `null` if the element model does not currently exist or if the |  | 
| 659    * library cannot be analyzed for some reason. |  | 
| 660    */ |  | 
| 661   LibraryElement getLibraryElement(Source source); |  | 
| 662 |  | 
| 663   /** |  | 
| 664    * Return the line information for the given [source], or `null` if the line |  | 
| 665    * information is not known. The line information is used to map offsets from |  | 
| 666    * the beginning of the source to line and column pairs. |  | 
| 667    * |  | 
| 668    * See [computeLineInfo]. |  | 
| 669    */ |  | 
| 670   LineInfo getLineInfo(Source source); |  | 
| 671 |  | 
| 672   /** |  | 
| 673    * Return the modification stamp for the [source], or a negative value if the |  | 
| 674    * source does not exist. A modification stamp is a non-negative integer with |  | 
| 675    * the property that if the contents of the source have not been modified |  | 
| 676    * since the last time the modification stamp was accessed then the same value |  | 
| 677    * will be returned, but if the contents of the source have been modified one |  | 
| 678    * or more times (even if the net change is zero) the stamps will be different
       . |  | 
| 679    * |  | 
| 680    * This method should be used rather than the method |  | 
| 681    * [Source.getModificationStamp] because contexts can have local overrides of |  | 
| 682    * the content of a source that the source is not aware of. |  | 
| 683    */ |  | 
| 684   int getModificationStamp(Source source); |  | 
| 685 |  | 
| 686   /** |  | 
| 687    * Return a fully resolved AST for the compilation unit defined by the given |  | 
| 688    * [unitSource] within the given [library], or `null` if the resolved AST is |  | 
| 689    * not already computed. |  | 
| 690    * |  | 
| 691    * See [resolveCompilationUnit]. |  | 
| 692    */ |  | 
| 693   CompilationUnit getResolvedCompilationUnit( |  | 
| 694       Source unitSource, LibraryElement library); |  | 
| 695 |  | 
| 696   /** |  | 
| 697    * Return a fully resolved AST for the compilation unit defined by the given |  | 
| 698    * [unitSource] within the library defined by the given [librarySource], or |  | 
| 699    * `null` if the resolved AST is not already computed. |  | 
| 700    * |  | 
| 701    * See [resolveCompilationUnit2]. |  | 
| 702    */ |  | 
| 703   CompilationUnit getResolvedCompilationUnit2( |  | 
| 704       Source unitSource, Source librarySource); |  | 
| 705 |  | 
| 706   /** |  | 
| 707    * Return the fully resolved HTML unit defined by the given [htmlSource], or |  | 
| 708    * `null` if the resolved unit is not already computed. |  | 
| 709    * |  | 
| 710    * See [resolveHtmlUnit]. |  | 
| 711    */ |  | 
| 712   @deprecated |  | 
| 713   ht.HtmlUnit getResolvedHtmlUnit(Source htmlSource); |  | 
| 714 |  | 
| 715   /** |  | 
| 716    * Return a list of the sources being analyzed in this context whose full path |  | 
| 717    * is equal to the given [path]. |  | 
| 718    */ |  | 
| 719   List<Source> getSourcesWithFullName(String path); |  | 
| 720 |  | 
| 721   /** |  | 
| 722    * Invalidates hints in the given [librarySource] and included parts. |  | 
| 723    */ |  | 
| 724   void invalidateLibraryHints(Source librarySource); |  | 
| 725 |  | 
| 726   /** |  | 
| 727    * Return `true` if the given [librarySource] is known to be the defining |  | 
| 728    * compilation unit of a library that can be run on a client (references |  | 
| 729    * 'dart:html', either directly or indirectly). |  | 
| 730    * |  | 
| 731    * <b>Note:</b> In addition to the expected case of returning `false` if the |  | 
| 732    * source is known to be a library that cannot be run on a client, this method |  | 
| 733    * will also return `false` if the source is not known to be a library or if |  | 
| 734    * we do not know whether it can be run on a client. |  | 
| 735    */ |  | 
| 736   bool isClientLibrary(Source librarySource); |  | 
| 737 |  | 
| 738   /** |  | 
| 739    * Return `true` if the given [librarySource] is known to be the defining |  | 
| 740    * compilation unit of a library that can be run on the server (does not |  | 
| 741    * reference 'dart:html', either directly or indirectly). |  | 
| 742    * |  | 
| 743    * <b>Note:</b> In addition to the expected case of returning `false` if the |  | 
| 744    * source is known to be a library that cannot be run on the server, this |  | 
| 745    * method will also return `false` if the source is not known to be a library |  | 
| 746    * or if we do not know whether it can be run on the server. |  | 
| 747    */ |  | 
| 748   bool isServerLibrary(Source librarySource); |  | 
| 749 |  | 
| 750   /** |  | 
| 751    * Return the stream that is notified when a new value for the given |  | 
| 752    * [descriptor] is computed. |  | 
| 753    */ |  | 
| 754   Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor); |  | 
| 755 |  | 
| 756   /** |  | 
| 757    * Parse the content of the given [source] to produce an AST structure. The |  | 
| 758    * resulting AST structure may or may not be resolved, and may have a slightly |  | 
| 759    * different structure depending upon whether it is resolved. |  | 
| 760    * |  | 
| 761    * Throws an [AnalysisException] if the analysis could not be performed |  | 
| 762    * |  | 
| 763    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 764    */ |  | 
| 765   CompilationUnit parseCompilationUnit(Source source); |  | 
| 766 |  | 
| 767   /** |  | 
| 768    * Parse a single HTML [source] to produce a document model. |  | 
| 769    * |  | 
| 770    * Throws an [AnalysisException] if the analysis could not be performed |  | 
| 771    * |  | 
| 772    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 773    */ |  | 
| 774   Document parseHtmlDocument(Source source); |  | 
| 775 |  | 
| 776   /** |  | 
| 777    * Parse a single HTML [source] to produce an AST structure. The resulting |  | 
| 778    * HTML AST structure may or may not be resolved, and may have a slightly |  | 
| 779    * different structure depending upon whether it is resolved. |  | 
| 780    * |  | 
| 781    * Throws an [AnalysisException] if the analysis could not be performed |  | 
| 782    * |  | 
| 783    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 784    */ |  | 
| 785   @deprecated // use parseHtmlDocument(source) |  | 
| 786   ht.HtmlUnit parseHtmlUnit(Source source); |  | 
| 787 |  | 
| 788   /** |  | 
| 789    * Perform the next unit of work required to keep the analysis results |  | 
| 790    * up-to-date and return information about the consequent changes to the |  | 
| 791    * analysis results. This method can be long running. |  | 
| 792    * |  | 
| 793    * The implementation that uses the task model notifies subscribers of |  | 
| 794    * [onResultComputed] about computed results. |  | 
| 795    * |  | 
| 796    * The following results are computed for Dart sources. |  | 
| 797    * |  | 
| 798    * 1. For explicit and implicit sources: |  | 
| 799    *    [PARSED_UNIT] |  | 
| 800    *    [RESOLVED_UNIT] |  | 
| 801    * |  | 
| 802    * 2. For explicit sources: |  | 
| 803    *    [DART_ERRORS]. |  | 
| 804    * |  | 
| 805    * 3. For explicit and implicit library sources: |  | 
| 806    *    [LIBRARY_ELEMENT]. |  | 
| 807    */ |  | 
| 808   AnalysisResult performAnalysisTask(); |  | 
| 809 |  | 
| 810   /** |  | 
| 811    * Remove the given [listener] from the list of objects that are to be |  | 
| 812    * notified when various analysis results are produced in this context. |  | 
| 813    */ |  | 
| 814   void removeListener(AnalysisListener listener); |  | 
| 815 |  | 
| 816   /** |  | 
| 817    * Return a fully resolved AST for the compilation unit defined by the given |  | 
| 818    * [unitSource] within the given [library]. |  | 
| 819    * |  | 
| 820    * Throws an [AnalysisException] if the analysis could not be performed. |  | 
| 821    * |  | 
| 822    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 823    * |  | 
| 824    * See [getResolvedCompilationUnit]. |  | 
| 825    */ |  | 
| 826   CompilationUnit resolveCompilationUnit( |  | 
| 827       Source unitSource, LibraryElement library); |  | 
| 828 |  | 
| 829   /** |  | 
| 830    * Return a fully resolved AST for the compilation unit defined by the given |  | 
| 831    * [unitSource] within the library defined by the given [librarySource]. |  | 
| 832    * |  | 
| 833    * Throws an [AnalysisException] if the analysis could not be performed. |  | 
| 834    * |  | 
| 835    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 836    * |  | 
| 837    * See [getResolvedCompilationUnit2]. |  | 
| 838    */ |  | 
| 839   CompilationUnit resolveCompilationUnit2( |  | 
| 840       Source unitSource, Source librarySource); |  | 
| 841 |  | 
| 842   /** |  | 
| 843    * Parse and resolve a single [htmlSource] within the given context to produce |  | 
| 844    * a fully resolved AST. |  | 
| 845    * |  | 
| 846    * Throws an [AnalysisException] if the analysis could not be performed. |  | 
| 847    * |  | 
| 848    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 849    */ |  | 
| 850   @deprecated |  | 
| 851   ht.HtmlUnit resolveHtmlUnit(Source htmlSource); |  | 
| 852 |  | 
| 853   /** |  | 
| 854    * Set the contents of the given [source] to the given [contents] and mark the |  | 
| 855    * source as having changed. The additional [offset] and [length] information |  | 
| 856    * is used by the context to determine what reanalysis is necessary. |  | 
| 857    */ |  | 
| 858   void setChangedContents( |  | 
| 859       Source source, String contents, int offset, int oldLength, int newLength); |  | 
| 860 |  | 
| 861   /** |  | 
| 862    * Set the contents of the given [source] to the given [contents] and mark the |  | 
| 863    * source as having changed. This has the effect of overriding the default |  | 
| 864    * contents of the source. If the contents are `null` the override is removed |  | 
| 865    * so that the default contents will be returned. |  | 
| 866    */ |  | 
| 867   void setContents(Source source, String contents); |  | 
| 868 |  | 
| 869   /** |  | 
| 870    * Check the cache for any invalid entries (entries whose modification time |  | 
| 871    * does not match the modification time of the source associated with the |  | 
| 872    * entry). Invalid entries will be marked as invalid so that the source will |  | 
| 873    * be re-analyzed. Return `true` if at least one entry was invalid. |  | 
| 874    */ |  | 
| 875   bool validateCacheConsistency(); |  | 
| 876 } |  | 
| 877 |  | 
| 878 /** |  | 
| 879  * An [AnalysisContext]. |  | 
| 880  */ |  | 
| 881 class AnalysisContextImpl implements InternalAnalysisContext { |  | 
| 882   /** |  | 
| 883    * The difference between the maximum cache size and the maximum priority |  | 
| 884    * order size. The priority list must be capped so that it is less than the |  | 
| 885    * cache size. Failure to do so can result in an infinite loop in |  | 
| 886    * performAnalysisTask() because re-caching one AST structure can cause |  | 
| 887    * another priority source's AST structure to be flushed. |  | 
| 888    */ |  | 
| 889   static int _PRIORITY_ORDER_SIZE_DELTA = 4; |  | 
| 890 |  | 
| 891   /** |  | 
| 892    * A flag indicating whether trace output should be produced as analysis tasks |  | 
| 893    * are performed. Used for debugging. |  | 
| 894    */ |  | 
| 895   static bool _TRACE_PERFORM_TASK = false; |  | 
| 896 |  | 
| 897   /** |  | 
| 898    * The next context identifier. |  | 
| 899    */ |  | 
| 900   static int _NEXT_ID = 0; |  | 
| 901 |  | 
| 902   /** |  | 
| 903    * The unique identifier of this context. |  | 
| 904    */ |  | 
| 905   final int _id = _NEXT_ID++; |  | 
| 906 |  | 
| 907   /** |  | 
| 908    * A client-provided name used to identify this context, or `null` if the |  | 
| 909    * client has not provided a name. |  | 
| 910    */ |  | 
| 911   String name; |  | 
| 912 |  | 
| 913   /** |  | 
| 914    * The set of analysis options controlling the behavior of this context. |  | 
| 915    */ |  | 
| 916   AnalysisOptionsImpl _options = new AnalysisOptionsImpl(); |  | 
| 917 |  | 
| 918   /** |  | 
| 919    * A flag indicating whether errors related to implicitly analyzed sources |  | 
| 920    * should be generated and reported. |  | 
| 921    */ |  | 
| 922   bool _generateImplicitErrors = true; |  | 
| 923 |  | 
| 924   /** |  | 
| 925    * A flag indicating whether errors related to sources in the SDK should be |  | 
| 926    * generated and reported. |  | 
| 927    */ |  | 
| 928   bool _generateSdkErrors = true; |  | 
| 929 |  | 
| 930   /** |  | 
| 931    * A flag indicating whether this context is disposed. |  | 
| 932    */ |  | 
| 933   bool _disposed = false; |  | 
| 934 |  | 
| 935   /** |  | 
| 936    * A cache of content used to override the default content of a source. |  | 
| 937    */ |  | 
| 938   ContentCache _contentCache = new ContentCache(); |  | 
| 939 |  | 
| 940   /** |  | 
| 941    * The source factory used to create the sources that can be analyzed in this |  | 
| 942    * context. |  | 
| 943    */ |  | 
| 944   SourceFactory _sourceFactory; |  | 
| 945 |  | 
| 946   /** |  | 
| 947    * The set of declared variables used when computing constant values. |  | 
| 948    */ |  | 
| 949   DeclaredVariables _declaredVariables = new DeclaredVariables(); |  | 
| 950 |  | 
| 951   /** |  | 
| 952    * A source representing the core library. |  | 
| 953    */ |  | 
| 954   Source _coreLibrarySource; |  | 
| 955 |  | 
| 956   /** |  | 
| 957    * A source representing the async library. |  | 
| 958    */ |  | 
| 959   Source _asyncLibrarySource; |  | 
| 960 |  | 
| 961   /** |  | 
| 962    * The partition that contains analysis results that are not shared with other |  | 
| 963    * contexts. |  | 
| 964    */ |  | 
| 965   CachePartition _privatePartition; |  | 
| 966 |  | 
| 967   /** |  | 
| 968    * A table mapping the sources known to the context to the information known |  | 
| 969    * about the source. |  | 
| 970    */ |  | 
| 971   AnalysisCache _cache; |  | 
| 972 |  | 
| 973   /** |  | 
| 974    * A list containing sources for which data should not be flushed. |  | 
| 975    */ |  | 
| 976   List<Source> _priorityOrder = Source.EMPTY_LIST; |  | 
| 977 |  | 
| 978   /** |  | 
| 979    * A map from all sources for which there are futures pending to a list of |  | 
| 980    * the corresponding PendingFuture objects.  These sources will be analyzed |  | 
| 981    * in the same way as priority sources, except with higher priority. |  | 
| 982    * |  | 
| 983    * TODO(paulberry): since the size of this map is not constrained (as it is |  | 
| 984    * for _priorityOrder), we run the risk of creating an analysis loop if |  | 
| 985    * re-caching one AST structure causes the AST structure for another source |  | 
| 986    * with pending futures to be flushed.  However, this is unlikely to happen |  | 
| 987    * in practice since sources are removed from this hash set as soon as their |  | 
| 988    * futures have completed. |  | 
| 989    */ |  | 
| 990   HashMap<Source, List<PendingFuture>> _pendingFutureSources = |  | 
| 991       new HashMap<Source, List<PendingFuture>>(); |  | 
| 992 |  | 
| 993   /** |  | 
| 994    * A list containing sources whose AST structure is needed in order to resolve |  | 
| 995    * the next library to be resolved. |  | 
| 996    */ |  | 
| 997   HashSet<Source> _neededForResolution = null; |  | 
| 998 |  | 
| 999   /** |  | 
| 1000    * A table mapping sources to the change notices that are waiting to be |  | 
| 1001    * returned related to that source. |  | 
| 1002    */ |  | 
| 1003   HashMap<Source, ChangeNoticeImpl> _pendingNotices = |  | 
| 1004       new HashMap<Source, ChangeNoticeImpl>(); |  | 
| 1005 |  | 
| 1006   /** |  | 
| 1007    * The object used to record the results of performing an analysis task. |  | 
| 1008    */ |  | 
| 1009   AnalysisContextImpl_AnalysisTaskResultRecorder _resultRecorder; |  | 
| 1010 |  | 
| 1011   /** |  | 
| 1012    * Cached information used in incremental analysis or `null` if none. |  | 
| 1013    */ |  | 
| 1014   IncrementalAnalysisCache _incrementalAnalysisCache; |  | 
| 1015 |  | 
| 1016   /** |  | 
| 1017    * The [TypeProvider] for this context, `null` if not yet created. |  | 
| 1018    */ |  | 
| 1019   TypeProvider _typeProvider; |  | 
| 1020 |  | 
| 1021   /** |  | 
| 1022    * The object used to manage the list of sources that need to be analyzed. |  | 
| 1023    */ |  | 
| 1024   WorkManager _workManager = new WorkManager(); |  | 
| 1025 |  | 
| 1026   /** |  | 
| 1027    * The [Stopwatch] of the current "perform tasks cycle". |  | 
| 1028    */ |  | 
| 1029   Stopwatch _performAnalysisTaskStopwatch; |  | 
| 1030 |  | 
| 1031   /** |  | 
| 1032    * The controller for sending [SourcesChangedEvent]s. |  | 
| 1033    */ |  | 
| 1034   StreamController<SourcesChangedEvent> _onSourcesChangedController; |  | 
| 1035 |  | 
| 1036   /** |  | 
| 1037    * The listeners that are to be notified when various analysis results are |  | 
| 1038    * produced in this context. |  | 
| 1039    */ |  | 
| 1040   List<AnalysisListener> _listeners = new List<AnalysisListener>(); |  | 
| 1041 |  | 
| 1042   /** |  | 
| 1043    * The most recently incrementally resolved source, or `null` when it was |  | 
| 1044    * already validated, or the most recent change was not incrementally resolved
       . |  | 
| 1045    */ |  | 
| 1046   Source incrementalResolutionValidation_lastUnitSource; |  | 
| 1047 |  | 
| 1048   /** |  | 
| 1049    * The most recently incrementally resolved library source, or `null` when it |  | 
| 1050    * was already validated, or the most recent change was not incrementally |  | 
| 1051    * resolved. |  | 
| 1052    */ |  | 
| 1053   Source incrementalResolutionValidation_lastLibrarySource; |  | 
| 1054 |  | 
| 1055   /** |  | 
| 1056    * The result of incremental resolution result of |  | 
| 1057    * [incrementalResolutionValidation_lastSource]. |  | 
| 1058    */ |  | 
| 1059   CompilationUnit incrementalResolutionValidation_lastUnit; |  | 
| 1060 |  | 
| 1061   /** |  | 
| 1062    * A factory to override how the [ResolverVisitor] is created. |  | 
| 1063    */ |  | 
| 1064   ResolverVisitorFactory resolverVisitorFactory; |  | 
| 1065 |  | 
| 1066   /** |  | 
| 1067    * A factory to override how the [TypeResolverVisitor] is created. |  | 
| 1068    */ |  | 
| 1069   TypeResolverVisitorFactory typeResolverVisitorFactory; |  | 
| 1070 |  | 
| 1071   /** |  | 
| 1072    * A factory to override how [LibraryResolver] is created. |  | 
| 1073    */ |  | 
| 1074   LibraryResolverFactory libraryResolverFactory; |  | 
| 1075 |  | 
| 1076   /** |  | 
| 1077    * Initialize a newly created analysis context. |  | 
| 1078    */ |  | 
| 1079   AnalysisContextImpl() { |  | 
| 1080     _resultRecorder = new AnalysisContextImpl_AnalysisTaskResultRecorder(this); |  | 
| 1081     _privatePartition = new UniversalCachePartition(this, |  | 
| 1082         AnalysisOptionsImpl.DEFAULT_CACHE_SIZE, |  | 
| 1083         new AnalysisContextImpl_ContextRetentionPolicy(this)); |  | 
| 1084     _cache = createCacheFromSourceFactory(null); |  | 
| 1085     _onSourcesChangedController = |  | 
| 1086         new StreamController<SourcesChangedEvent>.broadcast(); |  | 
| 1087   } |  | 
| 1088 |  | 
| 1089   @override |  | 
| 1090   AnalysisCache get analysisCache => _cache; |  | 
| 1091 |  | 
| 1092   @override |  | 
| 1093   AnalysisOptions get analysisOptions => _options; |  | 
| 1094 |  | 
| 1095   @override |  | 
| 1096   void set analysisOptions(AnalysisOptions options) { |  | 
| 1097     bool needsRecompute = this._options.analyzeFunctionBodiesPredicate != |  | 
| 1098             options.analyzeFunctionBodiesPredicate || |  | 
| 1099         this._options.generateImplicitErrors != |  | 
| 1100             options.generateImplicitErrors || |  | 
| 1101         this._options.generateSdkErrors != options.generateSdkErrors || |  | 
| 1102         this._options.dart2jsHint != options.dart2jsHint || |  | 
| 1103         (this._options.hint && !options.hint) || |  | 
| 1104         this._options.preserveComments != options.preserveComments || |  | 
| 1105         this._options.enableStrictCallChecks != options.enableStrictCallChecks; |  | 
| 1106     int cacheSize = options.cacheSize; |  | 
| 1107     if (this._options.cacheSize != cacheSize) { |  | 
| 1108       this._options.cacheSize = cacheSize; |  | 
| 1109       //cache.setMaxCacheSize(cacheSize); |  | 
| 1110       _privatePartition.maxCacheSize = cacheSize; |  | 
| 1111       // |  | 
| 1112       // Cap the size of the priority list to being less than the cache size. |  | 
| 1113       // Failure to do so can result in an infinite loop in |  | 
| 1114       // performAnalysisTask() because re-caching one AST structure |  | 
| 1115       // can cause another priority source's AST structure to be flushed. |  | 
| 1116       // |  | 
| 1117       // TODO(brianwilkerson) Remove this constraint when the new task model is |  | 
| 1118       // implemented. |  | 
| 1119       // |  | 
| 1120       int maxPriorityOrderSize = cacheSize - _PRIORITY_ORDER_SIZE_DELTA; |  | 
| 1121       if (_priorityOrder.length > maxPriorityOrderSize) { |  | 
| 1122         _priorityOrder = _priorityOrder.sublist(0, maxPriorityOrderSize); |  | 
| 1123       } |  | 
| 1124     } |  | 
| 1125     this._options.analyzeFunctionBodiesPredicate = |  | 
| 1126         options.analyzeFunctionBodiesPredicate; |  | 
| 1127     this._options.generateImplicitErrors = options.generateImplicitErrors; |  | 
| 1128     this._options.generateSdkErrors = options.generateSdkErrors; |  | 
| 1129     this._options.dart2jsHint = options.dart2jsHint; |  | 
| 1130     this._options.enableStrictCallChecks = options.enableStrictCallChecks; |  | 
| 1131     this._options.hint = options.hint; |  | 
| 1132     this._options.incremental = options.incremental; |  | 
| 1133     this._options.incrementalApi = options.incrementalApi; |  | 
| 1134     this._options.incrementalValidation = options.incrementalValidation; |  | 
| 1135     this._options.lint = options.lint; |  | 
| 1136     this._options.preserveComments = options.preserveComments; |  | 
| 1137     _generateImplicitErrors = options.generateImplicitErrors; |  | 
| 1138     _generateSdkErrors = options.generateSdkErrors; |  | 
| 1139     if (needsRecompute) { |  | 
| 1140       _invalidateAllLocalResolutionInformation(false); |  | 
| 1141     } |  | 
| 1142   } |  | 
| 1143 |  | 
| 1144   @override |  | 
| 1145   void set analysisPriorityOrder(List<Source> sources) { |  | 
| 1146     if (sources == null || sources.isEmpty) { |  | 
| 1147       _priorityOrder = Source.EMPTY_LIST; |  | 
| 1148     } else { |  | 
| 1149       while (sources.remove(null)) { |  | 
| 1150         // Nothing else to do. |  | 
| 1151       } |  | 
| 1152       if (sources.isEmpty) { |  | 
| 1153         _priorityOrder = Source.EMPTY_LIST; |  | 
| 1154       } |  | 
| 1155       // |  | 
| 1156       // Cap the size of the priority list to being less than the cache size. |  | 
| 1157       // Failure to do so can result in an infinite loop in |  | 
| 1158       // performAnalysisTask() because re-caching one AST structure |  | 
| 1159       // can cause another priority source's AST structure to be flushed. |  | 
| 1160       // |  | 
| 1161       int count = math.min( |  | 
| 1162           sources.length, _options.cacheSize - _PRIORITY_ORDER_SIZE_DELTA); |  | 
| 1163       _priorityOrder = new List<Source>(count); |  | 
| 1164       for (int i = 0; i < count; i++) { |  | 
| 1165         _priorityOrder[i] = sources[i]; |  | 
| 1166       } |  | 
| 1167       // Ensure entries for every priority source. |  | 
| 1168       for (var source in _priorityOrder) { |  | 
| 1169         SourceEntry entry = _getReadableSourceEntry(source); |  | 
| 1170         if (entry == null) { |  | 
| 1171           _createSourceEntry(source, false); |  | 
| 1172         } |  | 
| 1173       } |  | 
| 1174     } |  | 
| 1175   } |  | 
| 1176 |  | 
| 1177   @override |  | 
| 1178   set contentCache(ContentCache value) { |  | 
| 1179     _contentCache = value; |  | 
| 1180   } |  | 
| 1181 |  | 
| 1182   @override |  | 
| 1183   DeclaredVariables get declaredVariables => _declaredVariables; |  | 
| 1184 |  | 
| 1185   @override |  | 
| 1186   List<AnalysisTarget> get explicitTargets { |  | 
| 1187     List<AnalysisTarget> targets = <AnalysisTarget>[]; |  | 
| 1188     MapIterator<Source, SourceEntry> iterator = _cache.iterator(); |  | 
| 1189     while (iterator.moveNext()) { |  | 
| 1190       if (iterator.value.explicitlyAdded) { |  | 
| 1191         targets.add(iterator.key); |  | 
| 1192       } |  | 
| 1193     } |  | 
| 1194     return targets; |  | 
| 1195   } |  | 
| 1196 |  | 
| 1197   @override |  | 
| 1198   List<Source> get htmlSources => _getSources(SourceKind.HTML); |  | 
| 1199 |  | 
| 1200   @override |  | 
| 1201   bool get isDisposed => _disposed; |  | 
| 1202 |  | 
| 1203   @override |  | 
| 1204   List<Source> get launchableClientLibrarySources { |  | 
| 1205     // TODO(brianwilkerson) This needs to filter out libraries that do not |  | 
| 1206     // reference dart:html, either directly or indirectly. |  | 
| 1207     List<Source> sources = new List<Source>(); |  | 
| 1208     MapIterator<Source, SourceEntry> iterator = _cache.iterator(); |  | 
| 1209     while (iterator.moveNext()) { |  | 
| 1210       Source source = iterator.key; |  | 
| 1211       SourceEntry sourceEntry = iterator.value; |  | 
| 1212       if (sourceEntry.kind == SourceKind.LIBRARY && !source.isInSystemLibrary) { |  | 
| 1213 //          DartEntry dartEntry = (DartEntry) sourceEntry; |  | 
| 1214 //          if (dartEntry.getValue(DartEntry.IS_LAUNCHABLE) && dartEntry.getValu
       e(DartEntry.IS_CLIENT)) { |  | 
| 1215         sources.add(source); |  | 
| 1216 //          } |  | 
| 1217       } |  | 
| 1218     } |  | 
| 1219     return sources; |  | 
| 1220   } |  | 
| 1221 |  | 
| 1222   @override |  | 
| 1223   List<Source> get launchableServerLibrarySources { |  | 
| 1224     // TODO(brianwilkerson) This needs to filter out libraries that reference |  | 
| 1225     // dart:html, either directly or indirectly. |  | 
| 1226     List<Source> sources = new List<Source>(); |  | 
| 1227     MapIterator<Source, SourceEntry> iterator = _cache.iterator(); |  | 
| 1228     while (iterator.moveNext()) { |  | 
| 1229       Source source = iterator.key; |  | 
| 1230       SourceEntry sourceEntry = iterator.value; |  | 
| 1231       if (sourceEntry.kind == SourceKind.LIBRARY && !source.isInSystemLibrary) { |  | 
| 1232 //          DartEntry dartEntry = (DartEntry) sourceEntry; |  | 
| 1233 //          if (dartEntry.getValue(DartEntry.IS_LAUNCHABLE) && !dartEntry.getVal
       ue(DartEntry.IS_CLIENT)) { |  | 
| 1234         sources.add(source); |  | 
| 1235 //          } |  | 
| 1236       } |  | 
| 1237     } |  | 
| 1238     return sources; |  | 
| 1239   } |  | 
| 1240 |  | 
| 1241   @override |  | 
| 1242   List<Source> get librarySources => _getSources(SourceKind.LIBRARY); |  | 
| 1243 |  | 
| 1244   /** |  | 
| 1245    * Look through the cache for a task that needs to be performed. Return the |  | 
| 1246    * task that was found, or `null` if there is no more work to be done. |  | 
| 1247    */ |  | 
| 1248   AnalysisTask get nextAnalysisTask { |  | 
| 1249     bool hintsEnabled = _options.hint; |  | 
| 1250     bool lintsEnabled = _options.lint; |  | 
| 1251     bool hasBlockedTask = false; |  | 
| 1252     // |  | 
| 1253     // Look for incremental analysis |  | 
| 1254     // |  | 
| 1255     if (_incrementalAnalysisCache != null && |  | 
| 1256         _incrementalAnalysisCache.hasWork) { |  | 
| 1257       AnalysisTask task = |  | 
| 1258           new IncrementalAnalysisTask(this, _incrementalAnalysisCache); |  | 
| 1259       _incrementalAnalysisCache = null; |  | 
| 1260       return task; |  | 
| 1261     } |  | 
| 1262     // |  | 
| 1263     // Look for a source that needs to be analyzed because it has futures |  | 
| 1264     // pending. |  | 
| 1265     // |  | 
| 1266     if (_pendingFutureSources.isNotEmpty) { |  | 
| 1267       List<Source> sourcesToRemove = <Source>[]; |  | 
| 1268       AnalysisTask task; |  | 
| 1269       for (Source source in _pendingFutureSources.keys) { |  | 
| 1270         SourceEntry sourceEntry = _cache.get(source); |  | 
| 1271         List<PendingFuture> pendingFutures = _pendingFutureSources[source]; |  | 
| 1272         for (int i = 0; i < pendingFutures.length;) { |  | 
| 1273           if (pendingFutures[i].evaluate(sourceEntry)) { |  | 
| 1274             pendingFutures.removeAt(i); |  | 
| 1275           } else { |  | 
| 1276             i++; |  | 
| 1277           } |  | 
| 1278         } |  | 
| 1279         if (pendingFutures.isEmpty) { |  | 
| 1280           sourcesToRemove.add(source); |  | 
| 1281           continue; |  | 
| 1282         } |  | 
| 1283         AnalysisContextImpl_TaskData taskData = _getNextAnalysisTaskForSource( |  | 
| 1284             source, sourceEntry, true, hintsEnabled, lintsEnabled); |  | 
| 1285         task = taskData.task; |  | 
| 1286         if (task != null) { |  | 
| 1287           break; |  | 
| 1288         } else if (taskData.isBlocked) { |  | 
| 1289           hasBlockedTask = true; |  | 
| 1290         } else { |  | 
| 1291           // There is no more work to do for this task, so forcibly complete |  | 
| 1292           // all its pending futures. |  | 
| 1293           for (PendingFuture pendingFuture in pendingFutures) { |  | 
| 1294             pendingFuture.forciblyComplete(); |  | 
| 1295           } |  | 
| 1296           sourcesToRemove.add(source); |  | 
| 1297         } |  | 
| 1298       } |  | 
| 1299       for (Source source in sourcesToRemove) { |  | 
| 1300         _pendingFutureSources.remove(source); |  | 
| 1301       } |  | 
| 1302       if (task != null) { |  | 
| 1303         return task; |  | 
| 1304       } |  | 
| 1305     } |  | 
| 1306     // |  | 
| 1307     // Look for a priority source that needs to be analyzed. |  | 
| 1308     // |  | 
| 1309     int priorityCount = _priorityOrder.length; |  | 
| 1310     for (int i = 0; i < priorityCount; i++) { |  | 
| 1311       Source source = _priorityOrder[i]; |  | 
| 1312       AnalysisContextImpl_TaskData taskData = _getNextAnalysisTaskForSource( |  | 
| 1313           source, _cache.get(source), true, hintsEnabled, lintsEnabled); |  | 
| 1314       AnalysisTask task = taskData.task; |  | 
| 1315       if (task != null) { |  | 
| 1316         return task; |  | 
| 1317       } else if (taskData.isBlocked) { |  | 
| 1318         hasBlockedTask = true; |  | 
| 1319       } |  | 
| 1320     } |  | 
| 1321     if (_neededForResolution != null) { |  | 
| 1322       List<Source> sourcesToRemove = new List<Source>(); |  | 
| 1323       for (Source source in _neededForResolution) { |  | 
| 1324         SourceEntry sourceEntry = _cache.get(source); |  | 
| 1325         if (sourceEntry is DartEntry) { |  | 
| 1326           DartEntry dartEntry = sourceEntry; |  | 
| 1327           if (!dartEntry.hasResolvableCompilationUnit) { |  | 
| 1328             if (dartEntry.getState(DartEntry.PARSED_UNIT) == CacheState.ERROR) { |  | 
| 1329               sourcesToRemove.add(source); |  | 
| 1330             } else { |  | 
| 1331               AnalysisContextImpl_TaskData taskData = |  | 
| 1332                   _createParseDartTask(source, dartEntry); |  | 
| 1333               AnalysisTask task = taskData.task; |  | 
| 1334               if (task != null) { |  | 
| 1335                 return task; |  | 
| 1336               } else if (taskData.isBlocked) { |  | 
| 1337                 hasBlockedTask = true; |  | 
| 1338               } |  | 
| 1339             } |  | 
| 1340           } |  | 
| 1341         } |  | 
| 1342       } |  | 
| 1343       int count = sourcesToRemove.length; |  | 
| 1344       for (int i = 0; i < count; i++) { |  | 
| 1345         _neededForResolution.remove(sourcesToRemove[i]); |  | 
| 1346       } |  | 
| 1347     } |  | 
| 1348     // |  | 
| 1349     // Look for a non-priority source that needs to be analyzed. |  | 
| 1350     // |  | 
| 1351     List<Source> sourcesToRemove = new List<Source>(); |  | 
| 1352     WorkManager_WorkIterator sources = _workManager.iterator(); |  | 
| 1353     try { |  | 
| 1354       while (sources.hasNext) { |  | 
| 1355         Source source = sources.next(); |  | 
| 1356         AnalysisContextImpl_TaskData taskData = _getNextAnalysisTaskForSource( |  | 
| 1357             source, _cache.get(source), false, hintsEnabled, lintsEnabled); |  | 
| 1358         AnalysisTask task = taskData.task; |  | 
| 1359         if (task != null) { |  | 
| 1360           return task; |  | 
| 1361         } else if (taskData.isBlocked) { |  | 
| 1362           hasBlockedTask = true; |  | 
| 1363         } else { |  | 
| 1364           sourcesToRemove.add(source); |  | 
| 1365         } |  | 
| 1366       } |  | 
| 1367     } finally { |  | 
| 1368       int count = sourcesToRemove.length; |  | 
| 1369       for (int i = 0; i < count; i++) { |  | 
| 1370         _workManager.remove(sourcesToRemove[i]); |  | 
| 1371       } |  | 
| 1372     } |  | 
| 1373     if (hasBlockedTask) { |  | 
| 1374       // All of the analysis work is blocked waiting for an asynchronous task |  | 
| 1375       // to complete. |  | 
| 1376       return WaitForAsyncTask.instance; |  | 
| 1377     } |  | 
| 1378     return null; |  | 
| 1379   } |  | 
| 1380 |  | 
| 1381   @override |  | 
| 1382   Stream<SourcesChangedEvent> get onSourcesChanged => |  | 
| 1383       _onSourcesChangedController.stream; |  | 
| 1384 |  | 
| 1385   /** |  | 
| 1386    * Make _pendingFutureSources available to unit tests. |  | 
| 1387    */ |  | 
| 1388   HashMap<Source, List<PendingFuture>> get pendingFutureSources_forTesting => |  | 
| 1389       _pendingFutureSources; |  | 
| 1390 |  | 
| 1391   @override |  | 
| 1392   List<Source> get prioritySources => _priorityOrder; |  | 
| 1393 |  | 
| 1394   @override |  | 
| 1395   List<AnalysisTarget> get priorityTargets => prioritySources; |  | 
| 1396 |  | 
| 1397   @override |  | 
| 1398   CachePartition get privateAnalysisCachePartition => _privatePartition; |  | 
| 1399 |  | 
| 1400   @override |  | 
| 1401   SourceFactory get sourceFactory => _sourceFactory; |  | 
| 1402 |  | 
| 1403   @override |  | 
| 1404   void set sourceFactory(SourceFactory factory) { |  | 
| 1405     if (identical(_sourceFactory, factory)) { |  | 
| 1406       return; |  | 
| 1407     } else if (factory.context != null) { |  | 
| 1408       throw new IllegalStateException( |  | 
| 1409           "Source factories cannot be shared between contexts"); |  | 
| 1410     } |  | 
| 1411     if (_sourceFactory != null) { |  | 
| 1412       _sourceFactory.context = null; |  | 
| 1413     } |  | 
| 1414     factory.context = this; |  | 
| 1415     _sourceFactory = factory; |  | 
| 1416     _coreLibrarySource = _sourceFactory.forUri(DartSdk.DART_CORE); |  | 
| 1417     _asyncLibrarySource = _sourceFactory.forUri(DartSdk.DART_ASYNC); |  | 
| 1418     _cache = createCacheFromSourceFactory(factory); |  | 
| 1419     _invalidateAllLocalResolutionInformation(true); |  | 
| 1420   } |  | 
| 1421 |  | 
| 1422   @override |  | 
| 1423   List<Source> get sources { |  | 
| 1424     List<Source> sources = new List<Source>(); |  | 
| 1425     MapIterator<Source, SourceEntry> iterator = _cache.iterator(); |  | 
| 1426     while (iterator.moveNext()) { |  | 
| 1427       sources.add(iterator.key); |  | 
| 1428     } |  | 
| 1429     return sources; |  | 
| 1430   } |  | 
| 1431 |  | 
| 1432   /** |  | 
| 1433    * Return a list of the sources that would be processed by |  | 
| 1434    * [performAnalysisTask]. This method duplicates, and must therefore be kept |  | 
| 1435    * in sync with, [getNextAnalysisTask]. This method is intended to be used for |  | 
| 1436    * testing purposes only. |  | 
| 1437    */ |  | 
| 1438   List<Source> get sourcesNeedingProcessing { |  | 
| 1439     HashSet<Source> sources = new HashSet<Source>(); |  | 
| 1440     bool hintsEnabled = _options.hint; |  | 
| 1441     bool lintsEnabled = _options.lint; |  | 
| 1442 |  | 
| 1443     // |  | 
| 1444     // Look for priority sources that need to be analyzed. |  | 
| 1445     // |  | 
| 1446     for (Source source in _priorityOrder) { |  | 
| 1447       _getSourcesNeedingProcessing(source, _cache.get(source), true, |  | 
| 1448           hintsEnabled, lintsEnabled, sources); |  | 
| 1449     } |  | 
| 1450     // |  | 
| 1451     // Look for non-priority sources that need to be analyzed. |  | 
| 1452     // |  | 
| 1453     WorkManager_WorkIterator iterator = _workManager.iterator(); |  | 
| 1454     while (iterator.hasNext) { |  | 
| 1455       Source source = iterator.next(); |  | 
| 1456       _getSourcesNeedingProcessing(source, _cache.get(source), false, |  | 
| 1457           hintsEnabled, lintsEnabled, sources); |  | 
| 1458     } |  | 
| 1459     return new List<Source>.from(sources); |  | 
| 1460   } |  | 
| 1461 |  | 
| 1462   @override |  | 
| 1463   AnalysisContextStatistics get statistics { |  | 
| 1464     AnalysisContextStatisticsImpl statistics = |  | 
| 1465         new AnalysisContextStatisticsImpl(); |  | 
| 1466     visitCacheItems(statistics._internalPutCacheItem); |  | 
| 1467     statistics.partitionData = _cache.partitionData; |  | 
| 1468     return statistics; |  | 
| 1469   } |  | 
| 1470 |  | 
| 1471   IncrementalAnalysisCache get test_incrementalAnalysisCache { |  | 
| 1472     return _incrementalAnalysisCache; |  | 
| 1473   } |  | 
| 1474 |  | 
| 1475   set test_incrementalAnalysisCache(IncrementalAnalysisCache value) { |  | 
| 1476     _incrementalAnalysisCache = value; |  | 
| 1477   } |  | 
| 1478 |  | 
| 1479   List<Source> get test_priorityOrder => _priorityOrder; |  | 
| 1480 |  | 
| 1481   @override |  | 
| 1482   TypeProvider get typeProvider { |  | 
| 1483     if (_typeProvider != null) { |  | 
| 1484       return _typeProvider; |  | 
| 1485     } |  | 
| 1486     Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE); |  | 
| 1487     if (coreSource == null) { |  | 
| 1488       throw new AnalysisException("Could not create a source for dart:core"); |  | 
| 1489     } |  | 
| 1490     LibraryElement coreElement = computeLibraryElement(coreSource); |  | 
| 1491     if (coreElement == null) { |  | 
| 1492       throw new AnalysisException("Could not create an element for dart:core"); |  | 
| 1493     } |  | 
| 1494     Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC); |  | 
| 1495     if (asyncSource == null) { |  | 
| 1496       throw new AnalysisException("Could not create a source for dart:async"); |  | 
| 1497     } |  | 
| 1498     LibraryElement asyncElement = computeLibraryElement(asyncSource); |  | 
| 1499     if (asyncElement == null) { |  | 
| 1500       throw new AnalysisException("Could not create an element for dart:async"); |  | 
| 1501     } |  | 
| 1502     _typeProvider = new TypeProviderImpl(coreElement, asyncElement); |  | 
| 1503     return _typeProvider; |  | 
| 1504   } |  | 
| 1505 |  | 
| 1506   /** |  | 
| 1507    * Sets the [TypeProvider] for this context. |  | 
| 1508    */ |  | 
| 1509   void set typeProvider(TypeProvider typeProvider) { |  | 
| 1510     _typeProvider = typeProvider; |  | 
| 1511   } |  | 
| 1512 |  | 
| 1513   @override |  | 
| 1514   void addListener(AnalysisListener listener) { |  | 
| 1515     if (!_listeners.contains(listener)) { |  | 
| 1516       _listeners.add(listener); |  | 
| 1517     } |  | 
| 1518   } |  | 
| 1519 |  | 
| 1520   @override |  | 
| 1521   void applyAnalysisDelta(AnalysisDelta delta) { |  | 
| 1522     ChangeSet changeSet = new ChangeSet(); |  | 
| 1523     delta.analysisLevels.forEach((Source source, AnalysisLevel level) { |  | 
| 1524       if (level == AnalysisLevel.NONE) { |  | 
| 1525         changeSet.removedSource(source); |  | 
| 1526       } else { |  | 
| 1527         changeSet.addedSource(source); |  | 
| 1528       } |  | 
| 1529     }); |  | 
| 1530     applyChanges(changeSet); |  | 
| 1531   } |  | 
| 1532 |  | 
| 1533   @override |  | 
| 1534   void applyChanges(ChangeSet changeSet) { |  | 
| 1535     if (changeSet.isEmpty) { |  | 
| 1536       return; |  | 
| 1537     } |  | 
| 1538     // |  | 
| 1539     // First, compute the list of sources that have been removed. |  | 
| 1540     // |  | 
| 1541     List<Source> removedSources = |  | 
| 1542         new List<Source>.from(changeSet.removedSources); |  | 
| 1543     for (SourceContainer container in changeSet.removedContainers) { |  | 
| 1544       _addSourcesInContainer(removedSources, container); |  | 
| 1545     } |  | 
| 1546     // |  | 
| 1547     // Then determine which cached results are no longer valid. |  | 
| 1548     // |  | 
| 1549     for (Source source in changeSet.addedSources) { |  | 
| 1550       _sourceAvailable(source); |  | 
| 1551     } |  | 
| 1552     for (Source source in changeSet.changedSources) { |  | 
| 1553       if (_contentCache.getContents(source) != null) { |  | 
| 1554         // This source is overridden in the content cache, so the change will |  | 
| 1555         // have no effect. Just ignore it to avoid wasting time doing |  | 
| 1556         // re-analysis. |  | 
| 1557         continue; |  | 
| 1558       } |  | 
| 1559       _sourceChanged(source); |  | 
| 1560     } |  | 
| 1561     changeSet.changedContents.forEach((Source key, String value) { |  | 
| 1562       _contentsChanged(key, value, false); |  | 
| 1563     }); |  | 
| 1564     changeSet.changedRanges |  | 
| 1565         .forEach((Source source, ChangeSet_ContentChange change) { |  | 
| 1566       _contentRangeChanged(source, change.contents, change.offset, |  | 
| 1567           change.oldLength, change.newLength); |  | 
| 1568     }); |  | 
| 1569     for (Source source in changeSet.deletedSources) { |  | 
| 1570       _sourceDeleted(source); |  | 
| 1571     } |  | 
| 1572     for (Source source in removedSources) { |  | 
| 1573       _sourceRemoved(source); |  | 
| 1574     } |  | 
| 1575     _onSourcesChangedController.add(new SourcesChangedEvent(changeSet)); |  | 
| 1576   } |  | 
| 1577 |  | 
| 1578   @override |  | 
| 1579   String computeDocumentationComment(Element element) { |  | 
| 1580     if (element == null) { |  | 
| 1581       return null; |  | 
| 1582     } |  | 
| 1583     Source source = element.source; |  | 
| 1584     if (source == null) { |  | 
| 1585       return null; |  | 
| 1586     } |  | 
| 1587     CompilationUnit unit = parseCompilationUnit(source); |  | 
| 1588     if (unit == null) { |  | 
| 1589       return null; |  | 
| 1590     } |  | 
| 1591     NodeLocator locator = new NodeLocator(element.nameOffset); |  | 
| 1592     AstNode nameNode = locator.searchWithin(unit); |  | 
| 1593     while (nameNode != null) { |  | 
| 1594       if (nameNode is AnnotatedNode) { |  | 
| 1595         Comment comment = nameNode.documentationComment; |  | 
| 1596         if (comment == null) { |  | 
| 1597           return null; |  | 
| 1598         } |  | 
| 1599         StringBuffer buffer = new StringBuffer(); |  | 
| 1600         List<Token> tokens = comment.tokens; |  | 
| 1601         for (int i = 0; i < tokens.length; i++) { |  | 
| 1602           if (i > 0) { |  | 
| 1603             buffer.write("\n"); |  | 
| 1604           } |  | 
| 1605           buffer.write(tokens[i].lexeme); |  | 
| 1606         } |  | 
| 1607         return buffer.toString(); |  | 
| 1608       } |  | 
| 1609       nameNode = nameNode.parent; |  | 
| 1610     } |  | 
| 1611     return null; |  | 
| 1612   } |  | 
| 1613 |  | 
| 1614   @override |  | 
| 1615   List<AnalysisError> computeErrors(Source source) { |  | 
| 1616     bool enableHints = _options.hint; |  | 
| 1617     bool enableLints = _options.lint; |  | 
| 1618 |  | 
| 1619     SourceEntry sourceEntry = _getReadableSourceEntry(source); |  | 
| 1620     if (sourceEntry is DartEntry) { |  | 
| 1621       List<AnalysisError> errors = new List<AnalysisError>(); |  | 
| 1622       try { |  | 
| 1623         DartEntry dartEntry = sourceEntry; |  | 
| 1624         ListUtilities.addAll( |  | 
| 1625             errors, _getDartScanData(source, dartEntry, DartEntry.SCAN_ERRORS)); |  | 
| 1626         dartEntry = _getReadableDartEntry(source); |  | 
| 1627         ListUtilities.addAll(errors, |  | 
| 1628             _getDartParseData(source, dartEntry, DartEntry.PARSE_ERRORS)); |  | 
| 1629         dartEntry = _getReadableDartEntry(source); |  | 
| 1630         if (dartEntry.getValue(DartEntry.SOURCE_KIND) == SourceKind.LIBRARY) { |  | 
| 1631           ListUtilities.addAll(errors, _getDartResolutionData( |  | 
| 1632               source, source, dartEntry, DartEntry.RESOLUTION_ERRORS)); |  | 
| 1633           dartEntry = _getReadableDartEntry(source); |  | 
| 1634           ListUtilities.addAll(errors, _getDartVerificationData( |  | 
| 1635               source, source, dartEntry, DartEntry.VERIFICATION_ERRORS)); |  | 
| 1636           if (enableHints) { |  | 
| 1637             dartEntry = _getReadableDartEntry(source); |  | 
| 1638             ListUtilities.addAll(errors, |  | 
| 1639                 _getDartHintData(source, source, dartEntry, DartEntry.HINTS)); |  | 
| 1640           } |  | 
| 1641           if (enableLints) { |  | 
| 1642             dartEntry = _getReadableDartEntry(source); |  | 
| 1643             ListUtilities.addAll(errors, |  | 
| 1644                 _getDartLintData(source, source, dartEntry, DartEntry.LINTS)); |  | 
| 1645           } |  | 
| 1646         } else { |  | 
| 1647           List<Source> libraries = getLibrariesContaining(source); |  | 
| 1648           for (Source librarySource in libraries) { |  | 
| 1649             ListUtilities.addAll(errors, _getDartResolutionData( |  | 
| 1650                 source, librarySource, dartEntry, DartEntry.RESOLUTION_ERRORS)); |  | 
| 1651             dartEntry = _getReadableDartEntry(source); |  | 
| 1652             ListUtilities.addAll(errors, _getDartVerificationData(source, |  | 
| 1653                 librarySource, dartEntry, DartEntry.VERIFICATION_ERRORS)); |  | 
| 1654             if (enableHints) { |  | 
| 1655               dartEntry = _getReadableDartEntry(source); |  | 
| 1656               ListUtilities.addAll(errors, _getDartHintData( |  | 
| 1657                   source, librarySource, dartEntry, DartEntry.HINTS)); |  | 
| 1658             } |  | 
| 1659             if (enableLints) { |  | 
| 1660               dartEntry = _getReadableDartEntry(source); |  | 
| 1661               ListUtilities.addAll(errors, _getDartLintData( |  | 
| 1662                   source, librarySource, dartEntry, DartEntry.LINTS)); |  | 
| 1663             } |  | 
| 1664           } |  | 
| 1665         } |  | 
| 1666       } on ObsoleteSourceAnalysisException catch (exception, stackTrace) { |  | 
| 1667         AnalysisEngine.instance.logger.logInformation( |  | 
| 1668             "Could not compute errors", |  | 
| 1669             new CaughtException(exception, stackTrace)); |  | 
| 1670       } |  | 
| 1671       if (errors.isEmpty) { |  | 
| 1672         return AnalysisError.NO_ERRORS; |  | 
| 1673       } |  | 
| 1674       return errors; |  | 
| 1675     } else if (sourceEntry is HtmlEntry) { |  | 
| 1676       HtmlEntry htmlEntry = sourceEntry; |  | 
| 1677       try { |  | 
| 1678         return _getHtmlResolutionData2( |  | 
| 1679             source, htmlEntry, HtmlEntry.RESOLUTION_ERRORS); |  | 
| 1680       } on ObsoleteSourceAnalysisException catch (exception, stackTrace) { |  | 
| 1681         AnalysisEngine.instance.logger.logInformation( |  | 
| 1682             "Could not compute errors", |  | 
| 1683             new CaughtException(exception, stackTrace)); |  | 
| 1684       } |  | 
| 1685     } |  | 
| 1686     return AnalysisError.NO_ERRORS; |  | 
| 1687   } |  | 
| 1688 |  | 
| 1689   @override |  | 
| 1690   List<Source> computeExportedLibraries(Source source) => _getDartParseData2( |  | 
| 1691       source, DartEntry.EXPORTED_LIBRARIES, Source.EMPTY_LIST); |  | 
| 1692 |  | 
| 1693   @override |  | 
| 1694   @deprecated |  | 
| 1695   HtmlElement computeHtmlElement(Source source) => |  | 
| 1696       _getHtmlResolutionData(source, HtmlEntry.ELEMENT, null); |  | 
| 1697 |  | 
| 1698   @override |  | 
| 1699   List<Source> computeImportedLibraries(Source source) => _getDartParseData2( |  | 
| 1700       source, DartEntry.IMPORTED_LIBRARIES, Source.EMPTY_LIST); |  | 
| 1701 |  | 
| 1702   @override |  | 
| 1703   SourceKind computeKindOf(Source source) { |  | 
| 1704     SourceEntry sourceEntry = _getReadableSourceEntry(source); |  | 
| 1705     if (sourceEntry == null) { |  | 
| 1706       return SourceKind.UNKNOWN; |  | 
| 1707     } else if (sourceEntry is DartEntry) { |  | 
| 1708       try { |  | 
| 1709         return _getDartParseData(source, sourceEntry, DartEntry.SOURCE_KIND); |  | 
| 1710       } on AnalysisException { |  | 
| 1711         return SourceKind.UNKNOWN; |  | 
| 1712       } |  | 
| 1713     } |  | 
| 1714     return sourceEntry.kind; |  | 
| 1715   } |  | 
| 1716 |  | 
| 1717   @override |  | 
| 1718   LibraryElement computeLibraryElement(Source source) => |  | 
| 1719       _getDartResolutionData2(source, source, DartEntry.ELEMENT, null); |  | 
| 1720 |  | 
| 1721   @override |  | 
| 1722   LineInfo computeLineInfo(Source source) { |  | 
| 1723     SourceEntry sourceEntry = _getReadableSourceEntry(source); |  | 
| 1724     try { |  | 
| 1725       if (sourceEntry is HtmlEntry) { |  | 
| 1726         return _getHtmlParseData(source, SourceEntry.LINE_INFO, null); |  | 
| 1727       } else if (sourceEntry is DartEntry) { |  | 
| 1728         return _getDartScanData2(source, SourceEntry.LINE_INFO, null); |  | 
| 1729       } |  | 
| 1730     } on ObsoleteSourceAnalysisException catch (exception, stackTrace) { |  | 
| 1731       AnalysisEngine.instance.logger.logInformation( |  | 
| 1732           "Could not compute ${SourceEntry.LINE_INFO}", |  | 
| 1733           new CaughtException(exception, stackTrace)); |  | 
| 1734     } |  | 
| 1735     return null; |  | 
| 1736   } |  | 
| 1737 |  | 
| 1738   @override |  | 
| 1739   CompilationUnit computeResolvableCompilationUnit(Source source) { |  | 
| 1740     DartEntry dartEntry = _getReadableDartEntry(source); |  | 
| 1741     if (dartEntry == null) { |  | 
| 1742       throw new AnalysisException( |  | 
| 1743           "computeResolvableCompilationUnit for non-Dart: ${source.fullName}"); |  | 
| 1744     } |  | 
| 1745     dartEntry = _cacheDartParseData(source, dartEntry, DartEntry.PARSED_UNIT); |  | 
| 1746     CompilationUnit unit = dartEntry.resolvableCompilationUnit; |  | 
| 1747     if (unit == null) { |  | 
| 1748       throw new AnalysisException( |  | 
| 1749           "Internal error: computeResolvableCompilationUnit could not parse ${so
       urce.fullName}", |  | 
| 1750           new CaughtException(dartEntry.exception, null)); |  | 
| 1751     } |  | 
| 1752     return unit; |  | 
| 1753   } |  | 
| 1754 |  | 
| 1755   @override |  | 
| 1756   CancelableFuture<CompilationUnit> computeResolvedCompilationUnitAsync( |  | 
| 1757       Source unitSource, Source librarySource) { |  | 
| 1758     return new _AnalysisFutureHelper<CompilationUnit>(this).computeAsync( |  | 
| 1759         unitSource, (SourceEntry sourceEntry) { |  | 
| 1760       if (sourceEntry is DartEntry) { |  | 
| 1761         if (sourceEntry.getStateInLibrary( |  | 
| 1762                 DartEntry.RESOLVED_UNIT, librarySource) == |  | 
| 1763             CacheState.ERROR) { |  | 
| 1764           throw sourceEntry.exception; |  | 
| 1765         } |  | 
| 1766         return sourceEntry.getValueInLibrary( |  | 
| 1767             DartEntry.RESOLVED_UNIT, librarySource); |  | 
| 1768       } |  | 
| 1769       throw new AnalysisNotScheduledError(); |  | 
| 1770     }); |  | 
| 1771   } |  | 
| 1772 |  | 
| 1773   /** |  | 
| 1774    * Create an analysis cache based on the given source [factory]. |  | 
| 1775    */ |  | 
| 1776   AnalysisCache createCacheFromSourceFactory(SourceFactory factory) { |  | 
| 1777     if (factory == null) { |  | 
| 1778       return new AnalysisCache(<CachePartition>[_privatePartition]); |  | 
| 1779     } |  | 
| 1780     DartSdk sdk = factory.dartSdk; |  | 
| 1781     if (sdk == null) { |  | 
| 1782       return new AnalysisCache(<CachePartition>[_privatePartition]); |  | 
| 1783     } |  | 
| 1784     return new AnalysisCache(<CachePartition>[ |  | 
| 1785       AnalysisEngine.instance.partitionManager.forSdk(sdk), |  | 
| 1786       _privatePartition |  | 
| 1787     ]); |  | 
| 1788   } |  | 
| 1789 |  | 
| 1790   @override |  | 
| 1791   void dispose() { |  | 
| 1792     _disposed = true; |  | 
| 1793     for (List<PendingFuture> pendingFutures in _pendingFutureSources.values) { |  | 
| 1794       for (PendingFuture pendingFuture in pendingFutures) { |  | 
| 1795         pendingFuture.forciblyComplete(); |  | 
| 1796       } |  | 
| 1797     } |  | 
| 1798     _pendingFutureSources.clear(); |  | 
| 1799   } |  | 
| 1800 |  | 
| 1801   @override |  | 
| 1802   List<CompilationUnit> ensureResolvedDartUnits(Source unitSource) { |  | 
| 1803     SourceEntry sourceEntry = _cache.get(unitSource); |  | 
| 1804     if (sourceEntry is! DartEntry) { |  | 
| 1805       return null; |  | 
| 1806     } |  | 
| 1807     DartEntry dartEntry = sourceEntry; |  | 
| 1808     // Check every library. |  | 
| 1809     List<CompilationUnit> units = <CompilationUnit>[]; |  | 
| 1810     List<Source> containingLibraries = dartEntry.containingLibraries; |  | 
| 1811     for (Source librarySource in containingLibraries) { |  | 
| 1812       CompilationUnit unit = |  | 
| 1813           dartEntry.getValueInLibrary(DartEntry.RESOLVED_UNIT, librarySource); |  | 
| 1814       if (unit == null) { |  | 
| 1815         units = null; |  | 
| 1816         break; |  | 
| 1817       } |  | 
| 1818       units.add(unit); |  | 
| 1819     } |  | 
| 1820     // Invalidate the flushed RESOLVED_UNIT to force it eventually. |  | 
| 1821     if (units == null) { |  | 
| 1822       bool shouldBeScheduled = false; |  | 
| 1823       for (Source librarySource in containingLibraries) { |  | 
| 1824         if (dartEntry.getStateInLibrary( |  | 
| 1825                 DartEntry.RESOLVED_UNIT, librarySource) == |  | 
| 1826             CacheState.FLUSHED) { |  | 
| 1827           dartEntry.setStateInLibrary( |  | 
| 1828               DartEntry.RESOLVED_UNIT, librarySource, CacheState.INVALID); |  | 
| 1829           shouldBeScheduled = true; |  | 
| 1830         } |  | 
| 1831       } |  | 
| 1832       if (shouldBeScheduled) { |  | 
| 1833         _workManager.add(unitSource, SourcePriority.UNKNOWN); |  | 
| 1834       } |  | 
| 1835       // We cannot provide resolved units right now, |  | 
| 1836       // but the future analysis will. |  | 
| 1837       return null; |  | 
| 1838     } |  | 
| 1839     // done |  | 
| 1840     return units; |  | 
| 1841   } |  | 
| 1842 |  | 
| 1843   @override |  | 
| 1844   bool exists(Source source) { |  | 
| 1845     if (source == null) { |  | 
| 1846       return false; |  | 
| 1847     } |  | 
| 1848     if (_contentCache.getContents(source) != null) { |  | 
| 1849       return true; |  | 
| 1850     } |  | 
| 1851     return source.exists(); |  | 
| 1852   } |  | 
| 1853 |  | 
| 1854   @override |  | 
| 1855   cache.CacheEntry getCacheEntry(AnalysisTarget target) { |  | 
| 1856     return null; |  | 
| 1857   } |  | 
| 1858 |  | 
| 1859   @override |  | 
| 1860   CompilationUnitElement getCompilationUnitElement( |  | 
| 1861       Source unitSource, Source librarySource) { |  | 
| 1862     LibraryElement libraryElement = getLibraryElement(librarySource); |  | 
| 1863     if (libraryElement != null) { |  | 
| 1864       // try defining unit |  | 
| 1865       CompilationUnitElement definingUnit = |  | 
| 1866           libraryElement.definingCompilationUnit; |  | 
| 1867       if (definingUnit.source == unitSource) { |  | 
| 1868         return definingUnit; |  | 
| 1869       } |  | 
| 1870       // try parts |  | 
| 1871       for (CompilationUnitElement partUnit in libraryElement.parts) { |  | 
| 1872         if (partUnit.source == unitSource) { |  | 
| 1873           return partUnit; |  | 
| 1874         } |  | 
| 1875       } |  | 
| 1876     } |  | 
| 1877     return null; |  | 
| 1878   } |  | 
| 1879 |  | 
| 1880   @override |  | 
| 1881   TimestampedData<String> getContents(Source source) { |  | 
| 1882     String contents = _contentCache.getContents(source); |  | 
| 1883     if (contents != null) { |  | 
| 1884       return new TimestampedData<String>( |  | 
| 1885           _contentCache.getModificationStamp(source), contents); |  | 
| 1886     } |  | 
| 1887     return source.contents; |  | 
| 1888   } |  | 
| 1889 |  | 
| 1890   @override |  | 
| 1891   InternalAnalysisContext getContextFor(Source source) { |  | 
| 1892     InternalAnalysisContext context = _cache.getContextFor(source); |  | 
| 1893     return context == null ? this : context; |  | 
| 1894   } |  | 
| 1895 |  | 
| 1896   @override |  | 
| 1897   Element getElement(ElementLocation location) { |  | 
| 1898     // TODO(brianwilkerson) This should not be a "get" method. |  | 
| 1899     try { |  | 
| 1900       List<String> components = location.components; |  | 
| 1901       Source source = _computeSourceFromEncoding(components[0]); |  | 
| 1902       String sourceName = source.shortName; |  | 
| 1903       if (AnalysisEngine.isDartFileName(sourceName)) { |  | 
| 1904         ElementImpl element = computeLibraryElement(source) as ElementImpl; |  | 
| 1905         for (int i = 1; i < components.length; i++) { |  | 
| 1906           if (element == null) { |  | 
| 1907             return null; |  | 
| 1908           } |  | 
| 1909           element = element.getChild(components[i]); |  | 
| 1910         } |  | 
| 1911         return element; |  | 
| 1912       } |  | 
| 1913       if (AnalysisEngine.isHtmlFileName(sourceName)) { |  | 
| 1914         return computeHtmlElement(source); |  | 
| 1915       } |  | 
| 1916     } catch (exception) { |  | 
| 1917       // If the location cannot be decoded for some reason then the underlying |  | 
| 1918       // cause should have been logged already and we can fall though to return |  | 
| 1919       // null. |  | 
| 1920     } |  | 
| 1921     return null; |  | 
| 1922   } |  | 
| 1923 |  | 
| 1924   @override |  | 
| 1925   AnalysisErrorInfo getErrors(Source source) { |  | 
| 1926     SourceEntry sourceEntry = getReadableSourceEntryOrNull(source); |  | 
| 1927     if (sourceEntry is DartEntry) { |  | 
| 1928       DartEntry dartEntry = sourceEntry; |  | 
| 1929       return new AnalysisErrorInfoImpl( |  | 
| 1930           dartEntry.allErrors, dartEntry.getValue(SourceEntry.LINE_INFO)); |  | 
| 1931     } else if (sourceEntry is HtmlEntry) { |  | 
| 1932       HtmlEntry htmlEntry = sourceEntry; |  | 
| 1933       return new AnalysisErrorInfoImpl( |  | 
| 1934           htmlEntry.allErrors, htmlEntry.getValue(SourceEntry.LINE_INFO)); |  | 
| 1935     } |  | 
| 1936     return new AnalysisErrorInfoImpl(AnalysisError.NO_ERRORS, null); |  | 
| 1937   } |  | 
| 1938 |  | 
| 1939   @override |  | 
| 1940   @deprecated |  | 
| 1941   HtmlElement getHtmlElement(Source source) { |  | 
| 1942     SourceEntry sourceEntry = getReadableSourceEntryOrNull(source); |  | 
| 1943     if (sourceEntry is HtmlEntry) { |  | 
| 1944       return sourceEntry.getValue(HtmlEntry.ELEMENT); |  | 
| 1945     } |  | 
| 1946     return null; |  | 
| 1947   } |  | 
| 1948 |  | 
| 1949   @override |  | 
| 1950   List<Source> getHtmlFilesReferencing(Source source) { |  | 
| 1951     SourceKind sourceKind = getKindOf(source); |  | 
| 1952     if (sourceKind == null) { |  | 
| 1953       return Source.EMPTY_LIST; |  | 
| 1954     } |  | 
| 1955     List<Source> htmlSources = new List<Source>(); |  | 
| 1956     while (true) { |  | 
| 1957       if (sourceKind == SourceKind.PART) { |  | 
| 1958         List<Source> librarySources = getLibrariesContaining(source); |  | 
| 1959         MapIterator<Source, SourceEntry> partIterator = _cache.iterator(); |  | 
| 1960         while (partIterator.moveNext()) { |  | 
| 1961           SourceEntry sourceEntry = partIterator.value; |  | 
| 1962           if (sourceEntry.kind == SourceKind.HTML) { |  | 
| 1963             List<Source> referencedLibraries = (sourceEntry as HtmlEntry) |  | 
| 1964                 .getValue(HtmlEntry.REFERENCED_LIBRARIES); |  | 
| 1965             if (_containsAny(referencedLibraries, librarySources)) { |  | 
| 1966               htmlSources.add(partIterator.key); |  | 
| 1967             } |  | 
| 1968           } |  | 
| 1969         } |  | 
| 1970       } else { |  | 
| 1971         MapIterator<Source, SourceEntry> iterator = _cache.iterator(); |  | 
| 1972         while (iterator.moveNext()) { |  | 
| 1973           SourceEntry sourceEntry = iterator.value; |  | 
| 1974           if (sourceEntry.kind == SourceKind.HTML) { |  | 
| 1975             List<Source> referencedLibraries = (sourceEntry as HtmlEntry) |  | 
| 1976                 .getValue(HtmlEntry.REFERENCED_LIBRARIES); |  | 
| 1977             if (_contains(referencedLibraries, source)) { |  | 
| 1978               htmlSources.add(iterator.key); |  | 
| 1979             } |  | 
| 1980           } |  | 
| 1981         } |  | 
| 1982       } |  | 
| 1983       break; |  | 
| 1984     } |  | 
| 1985     if (htmlSources.isEmpty) { |  | 
| 1986       return Source.EMPTY_LIST; |  | 
| 1987     } |  | 
| 1988     return htmlSources; |  | 
| 1989   } |  | 
| 1990 |  | 
| 1991   @override |  | 
| 1992   SourceKind getKindOf(Source source) { |  | 
| 1993     SourceEntry sourceEntry = getReadableSourceEntryOrNull(source); |  | 
| 1994     if (sourceEntry == null) { |  | 
| 1995       return SourceKind.UNKNOWN; |  | 
| 1996     } |  | 
| 1997     return sourceEntry.kind; |  | 
| 1998   } |  | 
| 1999 |  | 
| 2000   @override |  | 
| 2001   List<Source> getLibrariesContaining(Source source) { |  | 
| 2002     SourceEntry sourceEntry = getReadableSourceEntryOrNull(source); |  | 
| 2003     if (sourceEntry is DartEntry) { |  | 
| 2004       return sourceEntry.containingLibraries; |  | 
| 2005     } |  | 
| 2006     return Source.EMPTY_LIST; |  | 
| 2007   } |  | 
| 2008 |  | 
| 2009   @override |  | 
| 2010   List<Source> getLibrariesDependingOn(Source librarySource) { |  | 
| 2011     List<Source> dependentLibraries = new List<Source>(); |  | 
| 2012     MapIterator<Source, SourceEntry> iterator = _cache.iterator(); |  | 
| 2013     while (iterator.moveNext()) { |  | 
| 2014       SourceEntry sourceEntry = iterator.value; |  | 
| 2015       if (sourceEntry.kind == SourceKind.LIBRARY) { |  | 
| 2016         if (_contains( |  | 
| 2017             (sourceEntry as DartEntry).getValue(DartEntry.EXPORTED_LIBRARIES), |  | 
| 2018             librarySource)) { |  | 
| 2019           dependentLibraries.add(iterator.key); |  | 
| 2020         } |  | 
| 2021         if (_contains( |  | 
| 2022             (sourceEntry as DartEntry).getValue(DartEntry.IMPORTED_LIBRARIES), |  | 
| 2023             librarySource)) { |  | 
| 2024           dependentLibraries.add(iterator.key); |  | 
| 2025         } |  | 
| 2026       } |  | 
| 2027     } |  | 
| 2028     if (dependentLibraries.isEmpty) { |  | 
| 2029       return Source.EMPTY_LIST; |  | 
| 2030     } |  | 
| 2031     return dependentLibraries; |  | 
| 2032   } |  | 
| 2033 |  | 
| 2034   @override |  | 
| 2035   List<Source> getLibrariesReferencedFromHtml(Source htmlSource) { |  | 
| 2036     SourceEntry sourceEntry = getReadableSourceEntryOrNull(htmlSource); |  | 
| 2037     if (sourceEntry is HtmlEntry) { |  | 
| 2038       HtmlEntry htmlEntry = sourceEntry; |  | 
| 2039       return htmlEntry.getValue(HtmlEntry.REFERENCED_LIBRARIES); |  | 
| 2040     } |  | 
| 2041     return Source.EMPTY_LIST; |  | 
| 2042   } |  | 
| 2043 |  | 
| 2044   @override |  | 
| 2045   LibraryElement getLibraryElement(Source source) { |  | 
| 2046     SourceEntry sourceEntry = getReadableSourceEntryOrNull(source); |  | 
| 2047     if (sourceEntry is DartEntry) { |  | 
| 2048       return sourceEntry.getValue(DartEntry.ELEMENT); |  | 
| 2049     } |  | 
| 2050     return null; |  | 
| 2051   } |  | 
| 2052 |  | 
| 2053   @override |  | 
| 2054   LineInfo getLineInfo(Source source) { |  | 
| 2055     SourceEntry sourceEntry = getReadableSourceEntryOrNull(source); |  | 
| 2056     if (sourceEntry != null) { |  | 
| 2057       return sourceEntry.getValue(SourceEntry.LINE_INFO); |  | 
| 2058     } |  | 
| 2059     return null; |  | 
| 2060   } |  | 
| 2061 |  | 
| 2062   @override |  | 
| 2063   int getModificationStamp(Source source) { |  | 
| 2064     int stamp = _contentCache.getModificationStamp(source); |  | 
| 2065     if (stamp != null) { |  | 
| 2066       return stamp; |  | 
| 2067     } |  | 
| 2068     return source.modificationStamp; |  | 
| 2069   } |  | 
| 2070 |  | 
| 2071   @override |  | 
| 2072   ChangeNoticeImpl getNotice(Source source) { |  | 
| 2073     ChangeNoticeImpl notice = _pendingNotices[source]; |  | 
| 2074     if (notice == null) { |  | 
| 2075       notice = new ChangeNoticeImpl(source); |  | 
| 2076       _pendingNotices[source] = notice; |  | 
| 2077     } |  | 
| 2078     return notice; |  | 
| 2079   } |  | 
| 2080 |  | 
| 2081   @override |  | 
| 2082   Namespace getPublicNamespace(LibraryElement library) { |  | 
| 2083     // TODO(brianwilkerson) Rename this to not start with 'get'. |  | 
| 2084     // Note that this is not part of the API of the interface. |  | 
| 2085     Source source = library.definingCompilationUnit.source; |  | 
| 2086     DartEntry dartEntry = _getReadableDartEntry(source); |  | 
| 2087     if (dartEntry == null) { |  | 
| 2088       return null; |  | 
| 2089     } |  | 
| 2090     Namespace namespace = null; |  | 
| 2091     if (identical(dartEntry.getValue(DartEntry.ELEMENT), library)) { |  | 
| 2092       namespace = dartEntry.getValue(DartEntry.PUBLIC_NAMESPACE); |  | 
| 2093     } |  | 
| 2094     if (namespace == null) { |  | 
| 2095       NamespaceBuilder builder = new NamespaceBuilder(); |  | 
| 2096       namespace = builder.createPublicNamespaceForLibrary(library); |  | 
| 2097       if (dartEntry == null) { |  | 
| 2098         AnalysisEngine.instance.logger.logError( |  | 
| 2099             "Could not compute the public namespace for ${library.source.fullNam
       e}", |  | 
| 2100             new CaughtException(new AnalysisException( |  | 
| 2101                     "A Dart file became a non-Dart file: ${source.fullName}"), |  | 
| 2102                 null)); |  | 
| 2103         return null; |  | 
| 2104       } |  | 
| 2105       if (identical(dartEntry.getValue(DartEntry.ELEMENT), library)) { |  | 
| 2106         dartEntry.setValue(DartEntry.PUBLIC_NAMESPACE, namespace); |  | 
| 2107       } |  | 
| 2108     } |  | 
| 2109     return namespace; |  | 
| 2110   } |  | 
| 2111 |  | 
| 2112   /** |  | 
| 2113    * Return the cache entry associated with the given [source], or `null` if |  | 
| 2114    * there is no entry associated with the source. |  | 
| 2115    */ |  | 
| 2116   SourceEntry getReadableSourceEntryOrNull(Source source) => _cache.get(source); |  | 
| 2117 |  | 
| 2118   @override |  | 
| 2119   CompilationUnit getResolvedCompilationUnit( |  | 
| 2120       Source unitSource, LibraryElement library) { |  | 
| 2121     if (library == null) { |  | 
| 2122       return null; |  | 
| 2123     } |  | 
| 2124     return getResolvedCompilationUnit2(unitSource, library.source); |  | 
| 2125   } |  | 
| 2126 |  | 
| 2127   @override |  | 
| 2128   CompilationUnit getResolvedCompilationUnit2( |  | 
| 2129       Source unitSource, Source librarySource) { |  | 
| 2130     SourceEntry sourceEntry = getReadableSourceEntryOrNull(unitSource); |  | 
| 2131     if (sourceEntry is DartEntry) { |  | 
| 2132       return sourceEntry.getValueInLibrary( |  | 
| 2133           DartEntry.RESOLVED_UNIT, librarySource); |  | 
| 2134     } |  | 
| 2135     return null; |  | 
| 2136   } |  | 
| 2137 |  | 
| 2138   @override |  | 
| 2139   @deprecated |  | 
| 2140   ht.HtmlUnit getResolvedHtmlUnit(Source htmlSource) { |  | 
| 2141     SourceEntry sourceEntry = getReadableSourceEntryOrNull(htmlSource); |  | 
| 2142     if (sourceEntry is HtmlEntry) { |  | 
| 2143       HtmlEntry htmlEntry = sourceEntry; |  | 
| 2144       return htmlEntry.getValue(HtmlEntry.RESOLVED_UNIT); |  | 
| 2145     } |  | 
| 2146     return null; |  | 
| 2147   } |  | 
| 2148 |  | 
| 2149   @override |  | 
| 2150   List<Source> getSourcesWithFullName(String path) { |  | 
| 2151     List<Source> sources = <Source>[]; |  | 
| 2152     MapIterator<Source, SourceEntry> iterator = _cache.iterator(); |  | 
| 2153     while (iterator.moveNext()) { |  | 
| 2154       if (iterator.key.fullName == path) { |  | 
| 2155         sources.add(iterator.key); |  | 
| 2156       } |  | 
| 2157     } |  | 
| 2158     return sources; |  | 
| 2159   } |  | 
| 2160 |  | 
| 2161   @override |  | 
| 2162   bool handleContentsChanged( |  | 
| 2163       Source source, String originalContents, String newContents, bool notify) { |  | 
| 2164     SourceEntry sourceEntry = _cache.get(source); |  | 
| 2165     if (sourceEntry == null) { |  | 
| 2166       return false; |  | 
| 2167     } |  | 
| 2168     bool changed = newContents != originalContents; |  | 
| 2169     if (newContents != null) { |  | 
| 2170       if (changed) { |  | 
| 2171         _incrementalAnalysisCache = |  | 
| 2172             IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source); |  | 
| 2173         if (!analysisOptions.incremental || |  | 
| 2174             !_tryPoorMansIncrementalResolution(source, newContents)) { |  | 
| 2175           _sourceChanged(source); |  | 
| 2176         } |  | 
| 2177         sourceEntry.modificationTime = |  | 
| 2178             _contentCache.getModificationStamp(source); |  | 
| 2179         sourceEntry.setValue(SourceEntry.CONTENT, newContents); |  | 
| 2180       } else { |  | 
| 2181         sourceEntry.modificationTime = |  | 
| 2182             _contentCache.getModificationStamp(source); |  | 
| 2183       } |  | 
| 2184     } else if (originalContents != null) { |  | 
| 2185       _incrementalAnalysisCache = |  | 
| 2186           IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source); |  | 
| 2187       // We are removing the overlay for the file, check if the file's |  | 
| 2188       // contents is the same as it was in the overlay. |  | 
| 2189       try { |  | 
| 2190         TimestampedData<String> fileContents = getContents(source); |  | 
| 2191         newContents = fileContents.data; |  | 
| 2192         sourceEntry.modificationTime = fileContents.modificationTime; |  | 
| 2193         if (newContents == originalContents) { |  | 
| 2194           sourceEntry.setValue(SourceEntry.CONTENT, newContents); |  | 
| 2195           changed = false; |  | 
| 2196         } |  | 
| 2197       } catch (e) {} |  | 
| 2198       // If not the same content (e.g. the file is being closed without save), |  | 
| 2199       // then force analysis. |  | 
| 2200       if (changed) { |  | 
| 2201         if (!analysisOptions.incremental || |  | 
| 2202             !_tryPoorMansIncrementalResolution(source, newContents)) { |  | 
| 2203           _sourceChanged(source); |  | 
| 2204         } |  | 
| 2205       } |  | 
| 2206     } |  | 
| 2207     if (notify && changed) { |  | 
| 2208       _onSourcesChangedController |  | 
| 2209           .add(new SourcesChangedEvent.changedContent(source, newContents)); |  | 
| 2210     } |  | 
| 2211     return changed; |  | 
| 2212   } |  | 
| 2213 |  | 
| 2214   @override |  | 
| 2215   void invalidateLibraryHints(Source librarySource) { |  | 
| 2216     SourceEntry sourceEntry = _cache.get(librarySource); |  | 
| 2217     if (sourceEntry is! DartEntry) { |  | 
| 2218       return; |  | 
| 2219     } |  | 
| 2220     DartEntry dartEntry = sourceEntry; |  | 
| 2221     // Prepare sources to invalidate hints in. |  | 
| 2222     List<Source> sources = <Source>[librarySource]; |  | 
| 2223     sources.addAll(dartEntry.getValue(DartEntry.INCLUDED_PARTS)); |  | 
| 2224     // Invalidate hints and lints. |  | 
| 2225     for (Source source in sources) { |  | 
| 2226       DartEntry dartEntry = _cache.get(source); |  | 
| 2227       if (dartEntry.getStateInLibrary(DartEntry.HINTS, librarySource) == |  | 
| 2228           CacheState.VALID) { |  | 
| 2229         dartEntry.setStateInLibrary( |  | 
| 2230             DartEntry.HINTS, librarySource, CacheState.INVALID); |  | 
| 2231       } |  | 
| 2232       if (dartEntry.getStateInLibrary(DartEntry.LINTS, librarySource) == |  | 
| 2233           CacheState.VALID) { |  | 
| 2234         dartEntry.setStateInLibrary( |  | 
| 2235             DartEntry.LINTS, librarySource, CacheState.INVALID); |  | 
| 2236       } |  | 
| 2237     } |  | 
| 2238   } |  | 
| 2239 |  | 
| 2240   @override |  | 
| 2241   bool isClientLibrary(Source librarySource) { |  | 
| 2242     SourceEntry sourceEntry = _getReadableSourceEntry(librarySource); |  | 
| 2243     if (sourceEntry is DartEntry) { |  | 
| 2244       DartEntry dartEntry = sourceEntry; |  | 
| 2245       return dartEntry.getValue(DartEntry.IS_CLIENT) && |  | 
| 2246           dartEntry.getValue(DartEntry.IS_LAUNCHABLE); |  | 
| 2247     } |  | 
| 2248     return false; |  | 
| 2249   } |  | 
| 2250 |  | 
| 2251   @override |  | 
| 2252   bool isServerLibrary(Source librarySource) { |  | 
| 2253     SourceEntry sourceEntry = _getReadableSourceEntry(librarySource); |  | 
| 2254     if (sourceEntry is DartEntry) { |  | 
| 2255       DartEntry dartEntry = sourceEntry; |  | 
| 2256       return !dartEntry.getValue(DartEntry.IS_CLIENT) && |  | 
| 2257           dartEntry.getValue(DartEntry.IS_LAUNCHABLE); |  | 
| 2258     } |  | 
| 2259     return false; |  | 
| 2260   } |  | 
| 2261 |  | 
| 2262   @override |  | 
| 2263   Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor) { |  | 
| 2264     throw new NotImplementedException('In not task-based AnalysisContext.'); |  | 
| 2265   } |  | 
| 2266 |  | 
| 2267   @override |  | 
| 2268   CompilationUnit parseCompilationUnit(Source source) => |  | 
| 2269       _getDartParseData2(source, DartEntry.PARSED_UNIT, null); |  | 
| 2270 |  | 
| 2271   @override |  | 
| 2272   Document parseHtmlDocument(Source source) { |  | 
| 2273     return null; |  | 
| 2274   } |  | 
| 2275 |  | 
| 2276   @override |  | 
| 2277   @deprecated |  | 
| 2278   ht.HtmlUnit parseHtmlUnit(Source source) => |  | 
| 2279       _getHtmlParseData(source, HtmlEntry.PARSED_UNIT, null); |  | 
| 2280 |  | 
| 2281   @override |  | 
| 2282   AnalysisResult performAnalysisTask() { |  | 
| 2283     if (_TRACE_PERFORM_TASK) { |  | 
| 2284       print("----------------------------------------"); |  | 
| 2285     } |  | 
| 2286     return PerformanceStatistics.performAnaysis.makeCurrentWhile(() { |  | 
| 2287       int getStart = JavaSystem.currentTimeMillis(); |  | 
| 2288       AnalysisTask task = PerformanceStatistics.nextTask |  | 
| 2289           .makeCurrentWhile(() => nextAnalysisTask); |  | 
| 2290       int getEnd = JavaSystem.currentTimeMillis(); |  | 
| 2291       if (task == null) { |  | 
| 2292         _validateLastIncrementalResolutionResult(); |  | 
| 2293         if (_performAnalysisTaskStopwatch != null) { |  | 
| 2294           AnalysisEngine.instance.instrumentationService.logPerformance( |  | 
| 2295               AnalysisPerformanceKind.FULL, _performAnalysisTaskStopwatch, |  | 
| 2296               'context_id=$_id'); |  | 
| 2297           _performAnalysisTaskStopwatch = null; |  | 
| 2298         } |  | 
| 2299         return new AnalysisResult( |  | 
| 2300             _getChangeNotices(true), getEnd - getStart, null, -1); |  | 
| 2301       } |  | 
| 2302       if (_performAnalysisTaskStopwatch == null) { |  | 
| 2303         _performAnalysisTaskStopwatch = new Stopwatch()..start(); |  | 
| 2304       } |  | 
| 2305       String taskDescription = task.toString(); |  | 
| 2306       _notifyAboutToPerformTask(taskDescription); |  | 
| 2307       if (_TRACE_PERFORM_TASK) { |  | 
| 2308         print(taskDescription); |  | 
| 2309       } |  | 
| 2310       int performStart = JavaSystem.currentTimeMillis(); |  | 
| 2311       try { |  | 
| 2312         task.perform(_resultRecorder); |  | 
| 2313       } on ObsoleteSourceAnalysisException catch (exception, stackTrace) { |  | 
| 2314         AnalysisEngine.instance.logger.logInformation( |  | 
| 2315             "Could not perform analysis task: $taskDescription", |  | 
| 2316             new CaughtException(exception, stackTrace)); |  | 
| 2317       } on AnalysisException catch (exception, stackTrace) { |  | 
| 2318         if (exception.cause is! JavaIOException) { |  | 
| 2319           AnalysisEngine.instance.logger.logError( |  | 
| 2320               "Internal error while performing the task: $task", |  | 
| 2321               new CaughtException(exception, stackTrace)); |  | 
| 2322         } |  | 
| 2323       } |  | 
| 2324       int performEnd = JavaSystem.currentTimeMillis(); |  | 
| 2325       List<ChangeNotice> notices = _getChangeNotices(false); |  | 
| 2326       int noticeCount = notices.length; |  | 
| 2327       for (int i = 0; i < noticeCount; i++) { |  | 
| 2328         ChangeNotice notice = notices[i]; |  | 
| 2329         Source source = notice.source; |  | 
| 2330         // TODO(brianwilkerson) Figure out whether the compilation unit is |  | 
| 2331         // always resolved, or whether we need to decide whether to invoke the |  | 
| 2332         // "parsed" or "resolved" method. This might be better done when |  | 
| 2333         // recording task results in order to reduce the chance of errors. |  | 
| 2334 //        if (notice.getCompilationUnit() != null) { |  | 
| 2335 //          notifyResolvedDart(source, notice.getCompilationUnit()); |  | 
| 2336 //        } else if (notice.getHtmlUnit() != null) { |  | 
| 2337 //          notifyResolvedHtml(source, notice.getHtmlUnit()); |  | 
| 2338 //        } |  | 
| 2339         _notifyErrors(source, notice.errors, notice.lineInfo); |  | 
| 2340       } |  | 
| 2341       return new AnalysisResult(notices, getEnd - getStart, |  | 
| 2342           task.runtimeType.toString(), performEnd - performStart); |  | 
| 2343     }); |  | 
| 2344   } |  | 
| 2345 |  | 
| 2346   @override |  | 
| 2347   void recordLibraryElements(Map<Source, LibraryElement> elementMap) { |  | 
| 2348     Source htmlSource = _sourceFactory.forUri(DartSdk.DART_HTML); |  | 
| 2349     elementMap.forEach((Source librarySource, LibraryElement library) { |  | 
| 2350       // |  | 
| 2351       // Cache the element in the library's info. |  | 
| 2352       // |  | 
| 2353       DartEntry dartEntry = _getReadableDartEntry(librarySource); |  | 
| 2354       if (dartEntry != null) { |  | 
| 2355         _recordElementData(dartEntry, library, library.source, htmlSource); |  | 
| 2356         dartEntry.setState(SourceEntry.CONTENT, CacheState.FLUSHED); |  | 
| 2357         dartEntry.setValue(SourceEntry.LINE_INFO, new LineInfo(<int>[0])); |  | 
| 2358         // DartEntry.ELEMENT - set in recordElementData |  | 
| 2359         dartEntry.setValue(DartEntry.EXPORTED_LIBRARIES, Source.EMPTY_LIST); |  | 
| 2360         dartEntry.setValue(DartEntry.IMPORTED_LIBRARIES, Source.EMPTY_LIST); |  | 
| 2361         dartEntry.setValue(DartEntry.INCLUDED_PARTS, Source.EMPTY_LIST); |  | 
| 2362         // DartEntry.IS_CLIENT - set in recordElementData |  | 
| 2363         // DartEntry.IS_LAUNCHABLE - set in recordElementData |  | 
| 2364         dartEntry.setValue(DartEntry.PARSE_ERRORS, AnalysisError.NO_ERRORS); |  | 
| 2365         dartEntry.setState(DartEntry.PARSED_UNIT, CacheState.FLUSHED); |  | 
| 2366         dartEntry.setState(DartEntry.PUBLIC_NAMESPACE, CacheState.FLUSHED); |  | 
| 2367         dartEntry.setValue(DartEntry.SCAN_ERRORS, AnalysisError.NO_ERRORS); |  | 
| 2368         dartEntry.setValue(DartEntry.SOURCE_KIND, SourceKind.LIBRARY); |  | 
| 2369         dartEntry.setState(DartEntry.TOKEN_STREAM, CacheState.FLUSHED); |  | 
| 2370         dartEntry.setValueInLibrary(DartEntry.RESOLUTION_ERRORS, librarySource, |  | 
| 2371             AnalysisError.NO_ERRORS); |  | 
| 2372         dartEntry.setStateInLibrary( |  | 
| 2373             DartEntry.RESOLVED_UNIT, librarySource, CacheState.FLUSHED); |  | 
| 2374         dartEntry.setValueInLibrary(DartEntry.VERIFICATION_ERRORS, |  | 
| 2375             librarySource, AnalysisError.NO_ERRORS); |  | 
| 2376         dartEntry.setValueInLibrary( |  | 
| 2377             DartEntry.HINTS, librarySource, AnalysisError.NO_ERRORS); |  | 
| 2378         dartEntry.setValueInLibrary( |  | 
| 2379             DartEntry.LINTS, librarySource, AnalysisError.NO_ERRORS); |  | 
| 2380       } |  | 
| 2381     }); |  | 
| 2382   } |  | 
| 2383 |  | 
| 2384   /** |  | 
| 2385    * Record the results produced by performing a [task] and return the cache |  | 
| 2386    * entry associated with the results. |  | 
| 2387    */ |  | 
| 2388   DartEntry recordResolveDartLibraryCycleTaskResults( |  | 
| 2389       ResolveDartLibraryCycleTask task) { |  | 
| 2390     LibraryResolver2 resolver = task.libraryResolver; |  | 
| 2391     CaughtException thrownException = task.exception; |  | 
| 2392     Source unitSource = task.unitSource; |  | 
| 2393     DartEntry unitEntry = _getReadableDartEntry(unitSource); |  | 
| 2394     if (resolver != null) { |  | 
| 2395       // |  | 
| 2396       // The resolver should only be null if an exception was thrown before (or |  | 
| 2397       // while) it was being created. |  | 
| 2398       // |  | 
| 2399       List<ResolvableLibrary> resolvedLibraries = resolver.resolvedLibraries; |  | 
| 2400       if (resolvedLibraries == null) { |  | 
| 2401         // |  | 
| 2402         // The resolved libraries should only be null if an exception was thrown |  | 
| 2403         // during resolution. |  | 
| 2404         // |  | 
| 2405         if (thrownException == null) { |  | 
| 2406           var message = "In recordResolveDartLibraryCycleTaskResults, " |  | 
| 2407               "resolvedLibraries was null and there was no thrown exception"; |  | 
| 2408           unitEntry.recordResolutionError( |  | 
| 2409               new CaughtException(new AnalysisException(message), null)); |  | 
| 2410         } else { |  | 
| 2411           unitEntry.recordResolutionError(thrownException); |  | 
| 2412         } |  | 
| 2413         _cache.remove(unitSource); |  | 
| 2414         if (thrownException != null) { |  | 
| 2415           throw new AnalysisException('<rethrow>', thrownException); |  | 
| 2416         } |  | 
| 2417         return unitEntry; |  | 
| 2418       } |  | 
| 2419       Source htmlSource = sourceFactory.forUri(DartSdk.DART_HTML); |  | 
| 2420       RecordingErrorListener errorListener = resolver.errorListener; |  | 
| 2421       for (ResolvableLibrary library in resolvedLibraries) { |  | 
| 2422         Source librarySource = library.librarySource; |  | 
| 2423         for (Source source in library.compilationUnitSources) { |  | 
| 2424           CompilationUnit unit = library.getAST(source); |  | 
| 2425           List<AnalysisError> errors = errorListener.getErrorsForSource(source); |  | 
| 2426           LineInfo lineInfo = getLineInfo(source); |  | 
| 2427           DartEntry dartEntry = _cache.get(source); |  | 
| 2428           if (thrownException == null) { |  | 
| 2429             dartEntry.setState(DartEntry.PARSED_UNIT, CacheState.FLUSHED); |  | 
| 2430             dartEntry.setValueInLibrary( |  | 
| 2431                 DartEntry.RESOLVED_UNIT, librarySource, unit); |  | 
| 2432             dartEntry.setValueInLibrary( |  | 
| 2433                 DartEntry.RESOLUTION_ERRORS, librarySource, errors); |  | 
| 2434             if (source == librarySource) { |  | 
| 2435               _recordElementData( |  | 
| 2436                   dartEntry, library.libraryElement, librarySource, htmlSource); |  | 
| 2437             } |  | 
| 2438             _cache.storedAst(source); |  | 
| 2439           } else { |  | 
| 2440             dartEntry.recordResolutionErrorInLibrary( |  | 
| 2441                 librarySource, thrownException); |  | 
| 2442           } |  | 
| 2443           if (source != librarySource) { |  | 
| 2444             _workManager.add(source, SourcePriority.PRIORITY_PART); |  | 
| 2445           } |  | 
| 2446           ChangeNoticeImpl notice = getNotice(source); |  | 
| 2447           notice.resolvedDartUnit = unit; |  | 
| 2448           notice.setErrors(dartEntry.allErrors, lineInfo); |  | 
| 2449         } |  | 
| 2450       } |  | 
| 2451     } |  | 
| 2452     if (thrownException != null) { |  | 
| 2453       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 2454     } |  | 
| 2455     return unitEntry; |  | 
| 2456   } |  | 
| 2457 |  | 
| 2458   /** |  | 
| 2459    * Record the results produced by performing a [task] and return the cache |  | 
| 2460    * entry associated with the results. |  | 
| 2461    */ |  | 
| 2462   DartEntry recordResolveDartLibraryTaskResults(ResolveDartLibraryTask task) { |  | 
| 2463     LibraryResolver resolver = task.libraryResolver; |  | 
| 2464     CaughtException thrownException = task.exception; |  | 
| 2465     Source unitSource = task.unitSource; |  | 
| 2466     DartEntry unitEntry = _getReadableDartEntry(unitSource); |  | 
| 2467     if (resolver != null) { |  | 
| 2468       // |  | 
| 2469       // The resolver should only be null if an exception was thrown before (or |  | 
| 2470       // while) it was being created. |  | 
| 2471       // |  | 
| 2472       Set<Library> resolvedLibraries = resolver.resolvedLibraries; |  | 
| 2473       if (resolvedLibraries == null) { |  | 
| 2474         // |  | 
| 2475         // The resolved libraries should only be null if an exception was thrown |  | 
| 2476         // during resolution. |  | 
| 2477         // |  | 
| 2478         if (thrownException == null) { |  | 
| 2479           String message = "In recordResolveDartLibraryTaskResults, " |  | 
| 2480               "resolvedLibraries was null and there was no thrown exception"; |  | 
| 2481           unitEntry.recordResolutionError( |  | 
| 2482               new CaughtException(new AnalysisException(message), null)); |  | 
| 2483         } else { |  | 
| 2484           unitEntry.recordResolutionError(thrownException); |  | 
| 2485         } |  | 
| 2486         _cache.remove(unitSource); |  | 
| 2487         if (thrownException != null) { |  | 
| 2488           throw new AnalysisException('<rethrow>', thrownException); |  | 
| 2489         } |  | 
| 2490         return unitEntry; |  | 
| 2491       } |  | 
| 2492       Source htmlSource = sourceFactory.forUri(DartSdk.DART_HTML); |  | 
| 2493       RecordingErrorListener errorListener = resolver.errorListener; |  | 
| 2494       for (Library library in resolvedLibraries) { |  | 
| 2495         Source librarySource = library.librarySource; |  | 
| 2496         for (Source source in library.compilationUnitSources) { |  | 
| 2497           CompilationUnit unit = library.getAST(source); |  | 
| 2498           List<AnalysisError> errors = errorListener.getErrorsForSource(source); |  | 
| 2499           LineInfo lineInfo = getLineInfo(source); |  | 
| 2500           DartEntry dartEntry = _cache.get(source); |  | 
| 2501           if (thrownException == null) { |  | 
| 2502             dartEntry.setValue(SourceEntry.LINE_INFO, lineInfo); |  | 
| 2503             dartEntry.setState(DartEntry.PARSED_UNIT, CacheState.FLUSHED); |  | 
| 2504             dartEntry.setValueInLibrary( |  | 
| 2505                 DartEntry.RESOLVED_UNIT, librarySource, unit); |  | 
| 2506             dartEntry.setValueInLibrary( |  | 
| 2507                 DartEntry.RESOLUTION_ERRORS, librarySource, errors); |  | 
| 2508             if (source == librarySource) { |  | 
| 2509               _recordElementData( |  | 
| 2510                   dartEntry, library.libraryElement, librarySource, htmlSource); |  | 
| 2511             } |  | 
| 2512             _cache.storedAst(source); |  | 
| 2513           } else { |  | 
| 2514             dartEntry.recordResolutionErrorInLibrary( |  | 
| 2515                 librarySource, thrownException); |  | 
| 2516             _cache.remove(source); |  | 
| 2517           } |  | 
| 2518           if (source != librarySource) { |  | 
| 2519             _workManager.add(source, SourcePriority.PRIORITY_PART); |  | 
| 2520           } |  | 
| 2521           ChangeNoticeImpl notice = getNotice(source); |  | 
| 2522           notice.resolvedDartUnit = unit; |  | 
| 2523           notice.setErrors(dartEntry.allErrors, lineInfo); |  | 
| 2524         } |  | 
| 2525       } |  | 
| 2526     } |  | 
| 2527     if (thrownException != null) { |  | 
| 2528       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 2529     } |  | 
| 2530     return unitEntry; |  | 
| 2531   } |  | 
| 2532 |  | 
| 2533   @override |  | 
| 2534   void removeListener(AnalysisListener listener) { |  | 
| 2535     _listeners.remove(listener); |  | 
| 2536   } |  | 
| 2537 |  | 
| 2538   @override |  | 
| 2539   CompilationUnit resolveCompilationUnit( |  | 
| 2540       Source unitSource, LibraryElement library) { |  | 
| 2541     if (library == null) { |  | 
| 2542       return null; |  | 
| 2543     } |  | 
| 2544     return resolveCompilationUnit2(unitSource, library.source); |  | 
| 2545   } |  | 
| 2546 |  | 
| 2547   @override |  | 
| 2548   CompilationUnit resolveCompilationUnit2( |  | 
| 2549       Source unitSource, Source librarySource) => _getDartResolutionData2( |  | 
| 2550           unitSource, librarySource, DartEntry.RESOLVED_UNIT, null); |  | 
| 2551 |  | 
| 2552   @override |  | 
| 2553   @deprecated |  | 
| 2554   ht.HtmlUnit resolveHtmlUnit(Source htmlSource) { |  | 
| 2555     computeHtmlElement(htmlSource); |  | 
| 2556     return parseHtmlUnit(htmlSource); |  | 
| 2557   } |  | 
| 2558 |  | 
| 2559   @override |  | 
| 2560   void setChangedContents(Source source, String contents, int offset, |  | 
| 2561       int oldLength, int newLength) { |  | 
| 2562     if (_contentRangeChanged(source, contents, offset, oldLength, newLength)) { |  | 
| 2563       _onSourcesChangedController.add(new SourcesChangedEvent.changedRange( |  | 
| 2564           source, contents, offset, oldLength, newLength)); |  | 
| 2565     } |  | 
| 2566   } |  | 
| 2567 |  | 
| 2568   @override |  | 
| 2569   void setContents(Source source, String contents) { |  | 
| 2570     _contentsChanged(source, contents, true); |  | 
| 2571   } |  | 
| 2572 |  | 
| 2573   @override |  | 
| 2574   bool shouldErrorsBeAnalyzed(Source source, Object entry) { |  | 
| 2575     DartEntry dartEntry = entry; |  | 
| 2576     if (source.isInSystemLibrary) { |  | 
| 2577       return _generateSdkErrors; |  | 
| 2578     } else if (!dartEntry.explicitlyAdded) { |  | 
| 2579       return _generateImplicitErrors; |  | 
| 2580     } else { |  | 
| 2581       return true; |  | 
| 2582     } |  | 
| 2583   } |  | 
| 2584 |  | 
| 2585   @override |  | 
| 2586   void test_flushAstStructures(Source source) { |  | 
| 2587     DartEntry dartEntry = getReadableSourceEntryOrNull(source); |  | 
| 2588     dartEntry.flushAstStructures(); |  | 
| 2589   } |  | 
| 2590 |  | 
| 2591   @override |  | 
| 2592   bool validateCacheConsistency() { |  | 
| 2593     int consistencyCheckStart = JavaSystem.nanoTime(); |  | 
| 2594     List<Source> changedSources = new List<Source>(); |  | 
| 2595     List<Source> missingSources = new List<Source>(); |  | 
| 2596     MapIterator<Source, SourceEntry> iterator = _cache.iterator(); |  | 
| 2597     while (iterator.moveNext()) { |  | 
| 2598       Source source = iterator.key; |  | 
| 2599       SourceEntry sourceEntry = iterator.value; |  | 
| 2600       int sourceTime = getModificationStamp(source); |  | 
| 2601       if (sourceTime != sourceEntry.modificationTime) { |  | 
| 2602         changedSources.add(source); |  | 
| 2603       } |  | 
| 2604       if (sourceEntry.exception != null) { |  | 
| 2605         if (!exists(source)) { |  | 
| 2606           missingSources.add(source); |  | 
| 2607         } |  | 
| 2608       } |  | 
| 2609     } |  | 
| 2610     int count = changedSources.length; |  | 
| 2611     for (int i = 0; i < count; i++) { |  | 
| 2612       _sourceChanged(changedSources[i]); |  | 
| 2613     } |  | 
| 2614     int removalCount = 0; |  | 
| 2615     for (Source source in missingSources) { |  | 
| 2616       if (getLibrariesContaining(source).isEmpty && |  | 
| 2617           getLibrariesDependingOn(source).isEmpty) { |  | 
| 2618         _cache.remove(source); |  | 
| 2619         removalCount++; |  | 
| 2620       } |  | 
| 2621     } |  | 
| 2622     int consistencyCheckEnd = JavaSystem.nanoTime(); |  | 
| 2623     if (changedSources.length > 0 || missingSources.length > 0) { |  | 
| 2624       StringBuffer buffer = new StringBuffer(); |  | 
| 2625       buffer.write("Consistency check took "); |  | 
| 2626       buffer.write((consistencyCheckEnd - consistencyCheckStart) / 1000000.0); |  | 
| 2627       buffer.writeln(" ms and found"); |  | 
| 2628       buffer.write("  "); |  | 
| 2629       buffer.write(changedSources.length); |  | 
| 2630       buffer.writeln(" inconsistent entries"); |  | 
| 2631       buffer.write("  "); |  | 
| 2632       buffer.write(missingSources.length); |  | 
| 2633       buffer.write(" missing sources ("); |  | 
| 2634       buffer.write(removalCount); |  | 
| 2635       buffer.writeln(" removed"); |  | 
| 2636       for (Source source in missingSources) { |  | 
| 2637         buffer.write("    "); |  | 
| 2638         buffer.writeln(source.fullName); |  | 
| 2639       } |  | 
| 2640       _logInformation(buffer.toString()); |  | 
| 2641     } |  | 
| 2642     return changedSources.length > 0; |  | 
| 2643   } |  | 
| 2644 |  | 
| 2645   @deprecated |  | 
| 2646   @override |  | 
| 2647   void visitCacheItems(void callback(Source source, SourceEntry dartEntry, |  | 
| 2648       DataDescriptor rowDesc, CacheState state)) { |  | 
| 2649     bool hintsEnabled = _options.hint; |  | 
| 2650     bool lintsEnabled = _options.lint; |  | 
| 2651     MapIterator<Source, SourceEntry> iterator = _cache.iterator(); |  | 
| 2652     while (iterator.moveNext()) { |  | 
| 2653       Source source = iterator.key; |  | 
| 2654       SourceEntry sourceEntry = iterator.value; |  | 
| 2655       for (DataDescriptor descriptor in sourceEntry.descriptors) { |  | 
| 2656         if (descriptor == DartEntry.SOURCE_KIND) { |  | 
| 2657           // The source kind is always valid, so the state isn't interesting. |  | 
| 2658           continue; |  | 
| 2659         } else if (descriptor == DartEntry.CONTAINING_LIBRARIES) { |  | 
| 2660           // The list of containing libraries is always valid, so the state |  | 
| 2661           // isn't interesting. |  | 
| 2662           continue; |  | 
| 2663         } else if (descriptor == DartEntry.PUBLIC_NAMESPACE) { |  | 
| 2664           // The public namespace isn't computed by performAnalysisTask() |  | 
| 2665           // and therefore isn't interesting. |  | 
| 2666           continue; |  | 
| 2667         } else if (descriptor == HtmlEntry.HINTS) { |  | 
| 2668           // We are not currently recording any hints related to HTML. |  | 
| 2669           continue; |  | 
| 2670         } |  | 
| 2671         callback( |  | 
| 2672             source, sourceEntry, descriptor, sourceEntry.getState(descriptor)); |  | 
| 2673       } |  | 
| 2674       if (sourceEntry is DartEntry) { |  | 
| 2675         // get library-specific values |  | 
| 2676         List<Source> librarySources = getLibrariesContaining(source); |  | 
| 2677         for (Source librarySource in librarySources) { |  | 
| 2678           for (DataDescriptor descriptor in sourceEntry.libraryDescriptors) { |  | 
| 2679             if (descriptor == DartEntry.BUILT_ELEMENT || |  | 
| 2680                 descriptor == DartEntry.BUILT_UNIT) { |  | 
| 2681               // These values are not currently being computed, so their state |  | 
| 2682               // is not interesting. |  | 
| 2683               continue; |  | 
| 2684             } else if (!sourceEntry.explicitlyAdded && |  | 
| 2685                 !_generateImplicitErrors && |  | 
| 2686                 (descriptor == DartEntry.VERIFICATION_ERRORS || |  | 
| 2687                     descriptor == DartEntry.HINTS || |  | 
| 2688                     descriptor == DartEntry.LINTS)) { |  | 
| 2689               continue; |  | 
| 2690             } else if (source.isInSystemLibrary && |  | 
| 2691                 !_generateSdkErrors && |  | 
| 2692                 (descriptor == DartEntry.VERIFICATION_ERRORS || |  | 
| 2693                     descriptor == DartEntry.HINTS || |  | 
| 2694                     descriptor == DartEntry.LINTS)) { |  | 
| 2695               continue; |  | 
| 2696             } else if (!hintsEnabled && descriptor == DartEntry.HINTS) { |  | 
| 2697               continue; |  | 
| 2698             } else if (!lintsEnabled && descriptor == DartEntry.LINTS) { |  | 
| 2699               continue; |  | 
| 2700             } |  | 
| 2701             callback(librarySource, sourceEntry, descriptor, |  | 
| 2702                 sourceEntry.getStateInLibrary(descriptor, librarySource)); |  | 
| 2703           } |  | 
| 2704         } |  | 
| 2705       } |  | 
| 2706     } |  | 
| 2707   } |  | 
| 2708 |  | 
| 2709   @override |  | 
| 2710   void visitContentCache(ContentCacheVisitor visitor) { |  | 
| 2711     _contentCache.accept(visitor); |  | 
| 2712   } |  | 
| 2713 |  | 
| 2714   /** |  | 
| 2715    * Record that we have accessed the AST structure associated with the given |  | 
| 2716    * [source]. At the moment, there is no differentiation between the parsed and |  | 
| 2717    * resolved forms of the AST. |  | 
| 2718    */ |  | 
| 2719   void _accessedAst(Source source) { |  | 
| 2720     _cache.accessedAst(source); |  | 
| 2721   } |  | 
| 2722 |  | 
| 2723   /** |  | 
| 2724    * Add all of the sources contained in the given source [container] to the |  | 
| 2725    * given list of [sources]. |  | 
| 2726    */ |  | 
| 2727   void _addSourcesInContainer(List<Source> sources, SourceContainer container) { |  | 
| 2728     MapIterator<Source, SourceEntry> iterator = _cache.iterator(); |  | 
| 2729     while (iterator.moveNext()) { |  | 
| 2730       Source source = iterator.key; |  | 
| 2731       if (container.contains(source)) { |  | 
| 2732         sources.add(source); |  | 
| 2733       } |  | 
| 2734     } |  | 
| 2735   } |  | 
| 2736 |  | 
| 2737   /** |  | 
| 2738    * Given the [unitSource] of a Dart file and the [librarySource] of the |  | 
| 2739    * library that contains it, return a cache entry in which the state of the |  | 
| 2740    * data represented by the given [descriptor] is either [CacheState.VALID] or |  | 
| 2741    * [CacheState.ERROR]. This method assumes that the data can be produced by |  | 
| 2742    * generating hints for the library if the data is not already cached. The |  | 
| 2743    * [dartEntry] is the cache entry associated with the Dart file. |  | 
| 2744    * |  | 
| 2745    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 2746    * source could not be parsed. |  | 
| 2747    */ |  | 
| 2748   DartEntry _cacheDartHintData(Source unitSource, Source librarySource, |  | 
| 2749       DartEntry dartEntry, DataDescriptor descriptor) { |  | 
| 2750     // |  | 
| 2751     // Check to see whether we already have the information being requested. |  | 
| 2752     // |  | 
| 2753     CacheState state = dartEntry.getStateInLibrary(descriptor, librarySource); |  | 
| 2754     while (state != CacheState.ERROR && state != CacheState.VALID) { |  | 
| 2755       // |  | 
| 2756       // If not, compute the information. |  | 
| 2757       // Unless the modification date of the source continues to change, |  | 
| 2758       // this loop will eventually terminate. |  | 
| 2759       // |  | 
| 2760       DartEntry libraryEntry = _getReadableDartEntry(librarySource); |  | 
| 2761       libraryEntry = _cacheDartResolutionData( |  | 
| 2762           librarySource, librarySource, libraryEntry, DartEntry.ELEMENT); |  | 
| 2763       LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT); |  | 
| 2764       CompilationUnitElement definingUnit = |  | 
| 2765           libraryElement.definingCompilationUnit; |  | 
| 2766       List<CompilationUnitElement> parts = libraryElement.parts; |  | 
| 2767       List<TimestampedData<CompilationUnit>> units = |  | 
| 2768           new List<TimestampedData<CompilationUnit>>(parts.length + 1); |  | 
| 2769       units[0] = _getResolvedUnit(definingUnit, librarySource); |  | 
| 2770       if (units[0] == null) { |  | 
| 2771         Source source = definingUnit.source; |  | 
| 2772         units[0] = new TimestampedData<CompilationUnit>( |  | 
| 2773             getModificationStamp(source), |  | 
| 2774             resolveCompilationUnit(source, libraryElement)); |  | 
| 2775       } |  | 
| 2776       for (int i = 0; i < parts.length; i++) { |  | 
| 2777         units[i + 1] = _getResolvedUnit(parts[i], librarySource); |  | 
| 2778         if (units[i + 1] == null) { |  | 
| 2779           Source source = parts[i].source; |  | 
| 2780           units[i + 1] = new TimestampedData<CompilationUnit>( |  | 
| 2781               getModificationStamp(source), |  | 
| 2782               resolveCompilationUnit(source, libraryElement)); |  | 
| 2783         } |  | 
| 2784       } |  | 
| 2785       dartEntry = new GenerateDartHintsTask( |  | 
| 2786               this, units, getLibraryElement(librarySource)) |  | 
| 2787           .perform(_resultRecorder) as DartEntry; |  | 
| 2788       state = dartEntry.getStateInLibrary(descriptor, librarySource); |  | 
| 2789     } |  | 
| 2790     return dartEntry; |  | 
| 2791   } |  | 
| 2792 |  | 
| 2793   /** |  | 
| 2794    * Given a source for a Dart file and the library that contains it, return a |  | 
| 2795    * cache entry in which the state of the data represented by the given |  | 
| 2796    * descriptor is either [CacheState.VALID] or [CacheState.ERROR]. This method |  | 
| 2797    * assumes that the data can be produced by generating lints for the library |  | 
| 2798    * if the data is not already cached. |  | 
| 2799    * |  | 
| 2800    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 2801    */ |  | 
| 2802   DartEntry _cacheDartLintData(Source unitSource, Source librarySource, |  | 
| 2803       DartEntry dartEntry, DataDescriptor descriptor) { |  | 
| 2804     // |  | 
| 2805     // Check to see whether we already have the information being requested. |  | 
| 2806     // |  | 
| 2807     CacheState state = dartEntry.getStateInLibrary(descriptor, librarySource); |  | 
| 2808     while (state != CacheState.ERROR && state != CacheState.VALID) { |  | 
| 2809       // |  | 
| 2810       // If not, compute the information. |  | 
| 2811       // Unless the modification date of the source continues to change, |  | 
| 2812       // this loop will eventually terminate. |  | 
| 2813       // |  | 
| 2814       DartEntry libraryEntry = _getReadableDartEntry(librarySource); |  | 
| 2815       libraryEntry = _cacheDartResolutionData( |  | 
| 2816           librarySource, librarySource, libraryEntry, DartEntry.ELEMENT); |  | 
| 2817       LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT); |  | 
| 2818       CompilationUnitElement definingUnit = |  | 
| 2819           libraryElement.definingCompilationUnit; |  | 
| 2820       List<CompilationUnitElement> parts = libraryElement.parts; |  | 
| 2821       List<TimestampedData<CompilationUnit>> units = |  | 
| 2822           new List<TimestampedData<CompilationUnit>>(parts.length + 1); |  | 
| 2823       units[0] = _getResolvedUnit(definingUnit, librarySource); |  | 
| 2824       if (units[0] == null) { |  | 
| 2825         Source source = definingUnit.source; |  | 
| 2826         units[0] = new TimestampedData<CompilationUnit>( |  | 
| 2827             getModificationStamp(source), |  | 
| 2828             resolveCompilationUnit(source, libraryElement)); |  | 
| 2829       } |  | 
| 2830       for (int i = 0; i < parts.length; i++) { |  | 
| 2831         units[i + 1] = _getResolvedUnit(parts[i], librarySource); |  | 
| 2832         if (units[i + 1] == null) { |  | 
| 2833           Source source = parts[i].source; |  | 
| 2834           units[i + 1] = new TimestampedData<CompilationUnit>( |  | 
| 2835               getModificationStamp(source), |  | 
| 2836               resolveCompilationUnit(source, libraryElement)); |  | 
| 2837         } |  | 
| 2838       } |  | 
| 2839       //TODO(pquitslund): revisit if we need all units or whether one will do |  | 
| 2840       dartEntry = new GenerateDartLintsTask( |  | 
| 2841               this, units, getLibraryElement(librarySource)) |  | 
| 2842           .perform(_resultRecorder) as DartEntry; |  | 
| 2843       state = dartEntry.getStateInLibrary(descriptor, librarySource); |  | 
| 2844     } |  | 
| 2845     return dartEntry; |  | 
| 2846   } |  | 
| 2847 |  | 
| 2848   /** |  | 
| 2849    * Given a source for a Dart file, return a cache entry in which the state of |  | 
| 2850    * the data represented by the given descriptor is either [CacheState.VALID] |  | 
| 2851    * or [CacheState.ERROR]. This method assumes that the data can be produced by |  | 
| 2852    * parsing the source if it is not already cached. |  | 
| 2853    * |  | 
| 2854    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 2855    */ |  | 
| 2856   DartEntry _cacheDartParseData( |  | 
| 2857       Source source, DartEntry dartEntry, DataDescriptor descriptor) { |  | 
| 2858     if (identical(descriptor, DartEntry.PARSED_UNIT)) { |  | 
| 2859       if (dartEntry.hasResolvableCompilationUnit) { |  | 
| 2860         return dartEntry; |  | 
| 2861       } |  | 
| 2862     } |  | 
| 2863     // |  | 
| 2864     // Check to see whether we already have the information being requested. |  | 
| 2865     // |  | 
| 2866     CacheState state = dartEntry.getState(descriptor); |  | 
| 2867     while (state != CacheState.ERROR && state != CacheState.VALID) { |  | 
| 2868       // |  | 
| 2869       // If not, compute the information. Unless the modification date of the |  | 
| 2870       // source continues to change, this loop will eventually terminate. |  | 
| 2871       // |  | 
| 2872       dartEntry = _cacheDartScanData(source, dartEntry, DartEntry.TOKEN_STREAM); |  | 
| 2873       dartEntry = new ParseDartTask(this, source, |  | 
| 2874               dartEntry.getValue(DartEntry.TOKEN_STREAM), |  | 
| 2875               dartEntry.getValue(SourceEntry.LINE_INFO)) |  | 
| 2876           .perform(_resultRecorder) as DartEntry; |  | 
| 2877       state = dartEntry.getState(descriptor); |  | 
| 2878     } |  | 
| 2879     return dartEntry; |  | 
| 2880   } |  | 
| 2881 |  | 
| 2882   /** |  | 
| 2883    * Given a source for a Dart file and the library that contains it, return a |  | 
| 2884    * cache entry in which the state of the data represented by the given |  | 
| 2885    * descriptor is either [CacheState.VALID] or [CacheState.ERROR]. This method |  | 
| 2886    * assumes that the data can be produced by resolving the source in the |  | 
| 2887    * context of the library if it is not already cached. |  | 
| 2888    * |  | 
| 2889    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 2890    */ |  | 
| 2891   DartEntry _cacheDartResolutionData(Source unitSource, Source librarySource, |  | 
| 2892       DartEntry dartEntry, DataDescriptor descriptor) { |  | 
| 2893     // |  | 
| 2894     // Check to see whether we already have the information being requested. |  | 
| 2895     // |  | 
| 2896     CacheState state = (identical(descriptor, DartEntry.ELEMENT)) |  | 
| 2897         ? dartEntry.getState(descriptor) |  | 
| 2898         : dartEntry.getStateInLibrary(descriptor, librarySource); |  | 
| 2899     while (state != CacheState.ERROR && state != CacheState.VALID) { |  | 
| 2900       // |  | 
| 2901       // If not, compute the information. Unless the modification date of the |  | 
| 2902       // source continues to change, this loop will eventually terminate. |  | 
| 2903       // |  | 
| 2904       // TODO(brianwilkerson) As an optimization, if we already have the |  | 
| 2905       // element model for the library we can use ResolveDartUnitTask to produce |  | 
| 2906       // the resolved AST structure much faster. |  | 
| 2907       dartEntry = new ResolveDartLibraryTask(this, unitSource, librarySource) |  | 
| 2908           .perform(_resultRecorder) as DartEntry; |  | 
| 2909       state = (identical(descriptor, DartEntry.ELEMENT)) |  | 
| 2910           ? dartEntry.getState(descriptor) |  | 
| 2911           : dartEntry.getStateInLibrary(descriptor, librarySource); |  | 
| 2912     } |  | 
| 2913     return dartEntry; |  | 
| 2914   } |  | 
| 2915 |  | 
| 2916   /** |  | 
| 2917    * Given a source for a Dart file, return a cache entry in which the state of |  | 
| 2918    * the data represented by the given descriptor is either [CacheState.VALID] |  | 
| 2919    * or [CacheState.ERROR]. This method assumes that the data can be produced by |  | 
| 2920    * scanning the source if it is not already cached. |  | 
| 2921    * |  | 
| 2922    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 2923    */ |  | 
| 2924   DartEntry _cacheDartScanData( |  | 
| 2925       Source source, DartEntry dartEntry, DataDescriptor descriptor) { |  | 
| 2926     // |  | 
| 2927     // Check to see whether we already have the information being requested. |  | 
| 2928     // |  | 
| 2929     CacheState state = dartEntry.getState(descriptor); |  | 
| 2930     while (state != CacheState.ERROR && state != CacheState.VALID) { |  | 
| 2931       // |  | 
| 2932       // If not, compute the information. Unless the modification date of the |  | 
| 2933       // source continues to change, this loop will eventually terminate. |  | 
| 2934       // |  | 
| 2935       try { |  | 
| 2936         if (dartEntry.getState(SourceEntry.CONTENT) != CacheState.VALID) { |  | 
| 2937           dartEntry = new GetContentTask(this, source) |  | 
| 2938               .perform(_resultRecorder) as DartEntry; |  | 
| 2939         } |  | 
| 2940         dartEntry = new ScanDartTask( |  | 
| 2941                 this, source, dartEntry.getValue(SourceEntry.CONTENT)) |  | 
| 2942             .perform(_resultRecorder) as DartEntry; |  | 
| 2943       } on AnalysisException catch (exception) { |  | 
| 2944         throw exception; |  | 
| 2945       } catch (exception, stackTrace) { |  | 
| 2946         throw new AnalysisException( |  | 
| 2947             "Exception", new CaughtException(exception, stackTrace)); |  | 
| 2948       } |  | 
| 2949       state = dartEntry.getState(descriptor); |  | 
| 2950     } |  | 
| 2951     return dartEntry; |  | 
| 2952   } |  | 
| 2953 |  | 
| 2954   /** |  | 
| 2955    * Given a source for a Dart file and the library that contains it, return a |  | 
| 2956    * cache entry in which the state of the data represented by the given |  | 
| 2957    * descriptor is either [CacheState.VALID] or [CacheState.ERROR]. This method |  | 
| 2958    * assumes that the data can be produced by verifying the source in the given |  | 
| 2959    * library if the data is not already cached. |  | 
| 2960    * |  | 
| 2961    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 2962    */ |  | 
| 2963   DartEntry _cacheDartVerificationData(Source unitSource, Source librarySource, |  | 
| 2964       DartEntry dartEntry, DataDescriptor descriptor) { |  | 
| 2965     // |  | 
| 2966     // Check to see whether we already have the information being requested. |  | 
| 2967     // |  | 
| 2968     CacheState state = dartEntry.getStateInLibrary(descriptor, librarySource); |  | 
| 2969     while (state != CacheState.ERROR && state != CacheState.VALID) { |  | 
| 2970       // |  | 
| 2971       // If not, compute the information. Unless the modification date of the |  | 
| 2972       // source continues to change, this loop will eventually terminate. |  | 
| 2973       // |  | 
| 2974       LibraryElement library = computeLibraryElement(librarySource); |  | 
| 2975       CompilationUnit unit = resolveCompilationUnit(unitSource, library); |  | 
| 2976       if (unit == null) { |  | 
| 2977         throw new AnalysisException( |  | 
| 2978             "Could not resolve compilation unit ${unitSource.fullName} in ${libr
       arySource.fullName}"); |  | 
| 2979       } |  | 
| 2980       dartEntry = new GenerateDartErrorsTask(this, unitSource, unit, library) |  | 
| 2981           .perform(_resultRecorder) as DartEntry; |  | 
| 2982       state = dartEntry.getStateInLibrary(descriptor, librarySource); |  | 
| 2983     } |  | 
| 2984     return dartEntry; |  | 
| 2985   } |  | 
| 2986 |  | 
| 2987   /** |  | 
| 2988    * Given a source for an HTML file, return a cache entry in which all of the |  | 
| 2989    * data represented by the state of the given descriptors is either |  | 
| 2990    * [CacheState.VALID] or [CacheState.ERROR]. This method assumes that the data |  | 
| 2991    * can be produced by parsing the source if it is not already cached. |  | 
| 2992    * |  | 
| 2993    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 2994    */ |  | 
| 2995   HtmlEntry _cacheHtmlParseData( |  | 
| 2996       Source source, HtmlEntry htmlEntry, DataDescriptor descriptor) { |  | 
| 2997     if (identical(descriptor, HtmlEntry.PARSED_UNIT)) { |  | 
| 2998       ht.HtmlUnit unit = htmlEntry.anyParsedUnit; |  | 
| 2999       if (unit != null) { |  | 
| 3000         return htmlEntry; |  | 
| 3001       } |  | 
| 3002     } |  | 
| 3003     // |  | 
| 3004     // Check to see whether we already have the information being requested. |  | 
| 3005     // |  | 
| 3006     CacheState state = htmlEntry.getState(descriptor); |  | 
| 3007     while (state != CacheState.ERROR && state != CacheState.VALID) { |  | 
| 3008       // |  | 
| 3009       // If not, compute the information. Unless the modification date of the |  | 
| 3010       // source continues to change, this loop will eventually terminate. |  | 
| 3011       // |  | 
| 3012       try { |  | 
| 3013         if (htmlEntry.getState(SourceEntry.CONTENT) != CacheState.VALID) { |  | 
| 3014           htmlEntry = new GetContentTask(this, source) |  | 
| 3015               .perform(_resultRecorder) as HtmlEntry; |  | 
| 3016         } |  | 
| 3017         htmlEntry = new ParseHtmlTask( |  | 
| 3018                 this, source, htmlEntry.getValue(SourceEntry.CONTENT)) |  | 
| 3019             .perform(_resultRecorder) as HtmlEntry; |  | 
| 3020       } on AnalysisException catch (exception) { |  | 
| 3021         throw exception; |  | 
| 3022       } catch (exception, stackTrace) { |  | 
| 3023         throw new AnalysisException( |  | 
| 3024             "Exception", new CaughtException(exception, stackTrace)); |  | 
| 3025       } |  | 
| 3026       state = htmlEntry.getState(descriptor); |  | 
| 3027     } |  | 
| 3028     return htmlEntry; |  | 
| 3029   } |  | 
| 3030 |  | 
| 3031   /** |  | 
| 3032    * Given a source for an HTML file, return a cache entry in which the state of |  | 
| 3033    * the data represented by the given descriptor is either [CacheState.VALID] |  | 
| 3034    * or [CacheState.ERROR]. This method assumes that the data can be produced by |  | 
| 3035    * resolving the source if it is not already cached. |  | 
| 3036    * |  | 
| 3037    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3038    */ |  | 
| 3039   HtmlEntry _cacheHtmlResolutionData( |  | 
| 3040       Source source, HtmlEntry htmlEntry, DataDescriptor descriptor) { |  | 
| 3041     // |  | 
| 3042     // Check to see whether we already have the information being requested. |  | 
| 3043     // |  | 
| 3044     CacheState state = htmlEntry.getState(descriptor); |  | 
| 3045     while (state != CacheState.ERROR && state != CacheState.VALID) { |  | 
| 3046       // |  | 
| 3047       // If not, compute the information. Unless the modification date of the |  | 
| 3048       // source continues to change, this loop will eventually terminate. |  | 
| 3049       // |  | 
| 3050       htmlEntry = _cacheHtmlParseData(source, htmlEntry, HtmlEntry.PARSED_UNIT); |  | 
| 3051       htmlEntry = new ResolveHtmlTask(this, source, htmlEntry.modificationTime, |  | 
| 3052               htmlEntry.getValue(HtmlEntry.PARSED_UNIT)) |  | 
| 3053           .perform(_resultRecorder) as HtmlEntry; |  | 
| 3054       state = htmlEntry.getState(descriptor); |  | 
| 3055     } |  | 
| 3056     return htmlEntry; |  | 
| 3057   } |  | 
| 3058 |  | 
| 3059   /** |  | 
| 3060    * Remove the given [pendingFuture] from [_pendingFutureSources], since the |  | 
| 3061    * client has indicated its computation is not needed anymore. |  | 
| 3062    */ |  | 
| 3063   void _cancelFuture(PendingFuture pendingFuture) { |  | 
| 3064     List<PendingFuture> pendingFutures = |  | 
| 3065         _pendingFutureSources[pendingFuture.source]; |  | 
| 3066     if (pendingFutures != null) { |  | 
| 3067       pendingFutures.remove(pendingFuture); |  | 
| 3068       if (pendingFutures.isEmpty) { |  | 
| 3069         _pendingFutureSources.remove(pendingFuture.source); |  | 
| 3070       } |  | 
| 3071     } |  | 
| 3072   } |  | 
| 3073 |  | 
| 3074   /** |  | 
| 3075    * Compute the transitive closure of all libraries that depend on the given |  | 
| 3076    * [library] by adding such libraries to the given collection of |  | 
| 3077    * [librariesToInvalidate]. |  | 
| 3078    */ |  | 
| 3079   void _computeAllLibrariesDependingOn( |  | 
| 3080       Source library, HashSet<Source> librariesToInvalidate) { |  | 
| 3081     if (librariesToInvalidate.add(library)) { |  | 
| 3082       for (Source dependentLibrary in getLibrariesDependingOn(library)) { |  | 
| 3083         _computeAllLibrariesDependingOn( |  | 
| 3084             dependentLibrary, librariesToInvalidate); |  | 
| 3085       } |  | 
| 3086     } |  | 
| 3087   } |  | 
| 3088 |  | 
| 3089   /** |  | 
| 3090    * Return the priority that should be used when the source associated with |  | 
| 3091    * the given [dartEntry] is added to the work manager. |  | 
| 3092    */ |  | 
| 3093   SourcePriority _computePriority(DartEntry dartEntry) { |  | 
| 3094     SourceKind kind = dartEntry.kind; |  | 
| 3095     if (kind == SourceKind.LIBRARY) { |  | 
| 3096       return SourcePriority.LIBRARY; |  | 
| 3097     } else if (kind == SourceKind.PART) { |  | 
| 3098       return SourcePriority.NORMAL_PART; |  | 
| 3099     } |  | 
| 3100     return SourcePriority.UNKNOWN; |  | 
| 3101   } |  | 
| 3102 |  | 
| 3103   /** |  | 
| 3104    * Given the encoded form of a source ([encoding]), use the source factory to |  | 
| 3105    * reconstitute the original source. |  | 
| 3106    */ |  | 
| 3107   Source _computeSourceFromEncoding(String encoding) => |  | 
| 3108       _sourceFactory.fromEncoding(encoding); |  | 
| 3109 |  | 
| 3110   /** |  | 
| 3111    * Return `true` if the given list of [sources] contains the given |  | 
| 3112    * [targetSource]. |  | 
| 3113    */ |  | 
| 3114   bool _contains(List<Source> sources, Source targetSource) { |  | 
| 3115     for (Source source in sources) { |  | 
| 3116       if (source == targetSource) { |  | 
| 3117         return true; |  | 
| 3118       } |  | 
| 3119     } |  | 
| 3120     return false; |  | 
| 3121   } |  | 
| 3122 |  | 
| 3123   /** |  | 
| 3124    * Return `true` if the given list of [sources] contains any of the given |  | 
| 3125    * [targetSources]. |  | 
| 3126    */ |  | 
| 3127   bool _containsAny(List<Source> sources, List<Source> targetSources) { |  | 
| 3128     for (Source targetSource in targetSources) { |  | 
| 3129       if (_contains(sources, targetSource)) { |  | 
| 3130         return true; |  | 
| 3131       } |  | 
| 3132     } |  | 
| 3133     return false; |  | 
| 3134   } |  | 
| 3135 |  | 
| 3136   /** |  | 
| 3137    * Set the contents of the given [source] to the given [contents] and mark the |  | 
| 3138    * source as having changed. The additional [offset], [oldLength] and |  | 
| 3139    * [newLength] information is used by the context to determine what reanalysis |  | 
| 3140    * is necessary. The method [setChangedContents] triggers a source changed |  | 
| 3141    * event where as this method does not. |  | 
| 3142    */ |  | 
| 3143   bool _contentRangeChanged(Source source, String contents, int offset, |  | 
| 3144       int oldLength, int newLength) { |  | 
| 3145     bool changed = false; |  | 
| 3146     String originalContents = _contentCache.setContents(source, contents); |  | 
| 3147     if (contents != null) { |  | 
| 3148       if (contents != originalContents) { |  | 
| 3149         if (_options.incremental) { |  | 
| 3150           _incrementalAnalysisCache = IncrementalAnalysisCache.update( |  | 
| 3151               _incrementalAnalysisCache, source, originalContents, contents, |  | 
| 3152               offset, oldLength, newLength, _getReadableSourceEntry(source)); |  | 
| 3153         } |  | 
| 3154         _sourceChanged(source); |  | 
| 3155         changed = true; |  | 
| 3156         SourceEntry sourceEntry = _cache.get(source); |  | 
| 3157         if (sourceEntry != null) { |  | 
| 3158           sourceEntry.modificationTime = |  | 
| 3159               _contentCache.getModificationStamp(source); |  | 
| 3160           sourceEntry.setValue(SourceEntry.CONTENT, contents); |  | 
| 3161         } |  | 
| 3162       } |  | 
| 3163     } else if (originalContents != null) { |  | 
| 3164       _incrementalAnalysisCache = |  | 
| 3165           IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source); |  | 
| 3166       _sourceChanged(source); |  | 
| 3167       changed = true; |  | 
| 3168     } |  | 
| 3169     return changed; |  | 
| 3170   } |  | 
| 3171 |  | 
| 3172   /** |  | 
| 3173    * Set the contents of the given [source] to the given [contents] and mark the |  | 
| 3174    * source as having changed. This has the effect of overriding the default |  | 
| 3175    * contents of the source. If the contents are `null` the override is removed |  | 
| 3176    * so that the default contents will be returned. If [notify] is true, a |  | 
| 3177    * source changed event is triggered. |  | 
| 3178    */ |  | 
| 3179   void _contentsChanged(Source source, String contents, bool notify) { |  | 
| 3180     String originalContents = _contentCache.setContents(source, contents); |  | 
| 3181     handleContentsChanged(source, originalContents, contents, notify); |  | 
| 3182   } |  | 
| 3183 |  | 
| 3184   /** |  | 
| 3185    * Create a [GenerateDartErrorsTask] for the given [unitSource], marking the |  | 
| 3186    * verification errors as being in-process. The compilation unit and the |  | 
| 3187    * library can be the same if the compilation unit is the defining compilation |  | 
| 3188    * unit of the library. |  | 
| 3189    */ |  | 
| 3190   AnalysisContextImpl_TaskData _createGenerateDartErrorsTask(Source unitSource, |  | 
| 3191       DartEntry unitEntry, Source librarySource, DartEntry libraryEntry) { |  | 
| 3192     if (unitEntry.getStateInLibrary(DartEntry.RESOLVED_UNIT, librarySource) != |  | 
| 3193             CacheState.VALID || |  | 
| 3194         libraryEntry.getState(DartEntry.ELEMENT) != CacheState.VALID) { |  | 
| 3195       return _createResolveDartLibraryTask(librarySource, libraryEntry); |  | 
| 3196     } |  | 
| 3197     CompilationUnit unit = |  | 
| 3198         unitEntry.getValueInLibrary(DartEntry.RESOLVED_UNIT, librarySource); |  | 
| 3199     if (unit == null) { |  | 
| 3200       CaughtException exception = new CaughtException(new AnalysisException( |  | 
| 3201               "Entry has VALID state for RESOLVED_UNIT but null value for ${unit
       Source.fullName} in ${librarySource.fullName}"), |  | 
| 3202           null); |  | 
| 3203       AnalysisEngine.instance.logger.logInformation( |  | 
| 3204           exception.toString(), exception); |  | 
| 3205       unitEntry.recordResolutionError(exception); |  | 
| 3206       return new AnalysisContextImpl_TaskData(null, false); |  | 
| 3207     } |  | 
| 3208     LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT); |  | 
| 3209     return new AnalysisContextImpl_TaskData( |  | 
| 3210         new GenerateDartErrorsTask(this, unitSource, unit, libraryElement), |  | 
| 3211         false); |  | 
| 3212   } |  | 
| 3213 |  | 
| 3214   /** |  | 
| 3215    * Create a [GenerateDartHintsTask] for the given [source], marking the hints |  | 
| 3216    * as being in-process. |  | 
| 3217    */ |  | 
| 3218   AnalysisContextImpl_TaskData _createGenerateDartHintsTask(Source source, |  | 
| 3219       DartEntry dartEntry, Source librarySource, DartEntry libraryEntry) { |  | 
| 3220     if (libraryEntry.getState(DartEntry.ELEMENT) != CacheState.VALID) { |  | 
| 3221       return _createResolveDartLibraryTask(librarySource, libraryEntry); |  | 
| 3222     } |  | 
| 3223     LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT); |  | 
| 3224     CompilationUnitElement definingUnit = |  | 
| 3225         libraryElement.definingCompilationUnit; |  | 
| 3226     List<CompilationUnitElement> parts = libraryElement.parts; |  | 
| 3227     List<TimestampedData<CompilationUnit>> units = |  | 
| 3228         new List<TimestampedData<CompilationUnit>>(parts.length + 1); |  | 
| 3229     units[0] = _getResolvedUnit(definingUnit, librarySource); |  | 
| 3230     if (units[0] == null) { |  | 
| 3231       // TODO(brianwilkerson) We should return a ResolveDartUnitTask |  | 
| 3232       // (unless there are multiple ASTs that need to be resolved). |  | 
| 3233       return _createResolveDartLibraryTask(librarySource, libraryEntry); |  | 
| 3234     } |  | 
| 3235     for (int i = 0; i < parts.length; i++) { |  | 
| 3236       units[i + 1] = _getResolvedUnit(parts[i], librarySource); |  | 
| 3237       if (units[i + 1] == null) { |  | 
| 3238         // TODO(brianwilkerson) We should return a ResolveDartUnitTask |  | 
| 3239         // (unless there are multiple ASTs that need to be resolved). |  | 
| 3240         return _createResolveDartLibraryTask(librarySource, libraryEntry); |  | 
| 3241       } |  | 
| 3242     } |  | 
| 3243     return new AnalysisContextImpl_TaskData( |  | 
| 3244         new GenerateDartHintsTask(this, units, libraryElement), false); |  | 
| 3245   } |  | 
| 3246 |  | 
| 3247   /** |  | 
| 3248    * Create a [GenerateDartLintsTask] for the given [source], marking the lints |  | 
| 3249    * as being in-process. |  | 
| 3250    */ |  | 
| 3251   AnalysisContextImpl_TaskData _createGenerateDartLintsTask(Source source, |  | 
| 3252       DartEntry dartEntry, Source librarySource, DartEntry libraryEntry) { |  | 
| 3253     if (libraryEntry.getState(DartEntry.ELEMENT) != CacheState.VALID) { |  | 
| 3254       return _createResolveDartLibraryTask(librarySource, libraryEntry); |  | 
| 3255     } |  | 
| 3256     LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT); |  | 
| 3257     CompilationUnitElement definingUnit = |  | 
| 3258         libraryElement.definingCompilationUnit; |  | 
| 3259     List<CompilationUnitElement> parts = libraryElement.parts; |  | 
| 3260     List<TimestampedData<CompilationUnit>> units = |  | 
| 3261         new List<TimestampedData<CompilationUnit>>(parts.length + 1); |  | 
| 3262     units[0] = _getResolvedUnit(definingUnit, librarySource); |  | 
| 3263     if (units[0] == null) { |  | 
| 3264       // TODO(brianwilkerson) We should return a ResolveDartUnitTask |  | 
| 3265       // (unless there are multiple ASTs that need to be resolved). |  | 
| 3266       return _createResolveDartLibraryTask(librarySource, libraryEntry); |  | 
| 3267     } |  | 
| 3268     for (int i = 0; i < parts.length; i++) { |  | 
| 3269       units[i + 1] = _getResolvedUnit(parts[i], librarySource); |  | 
| 3270       if (units[i + 1] == null) { |  | 
| 3271         // TODO(brianwilkerson) We should return a ResolveDartUnitTask |  | 
| 3272         // (unless there are multiple ASTs that need to be resolved). |  | 
| 3273         return _createResolveDartLibraryTask(librarySource, libraryEntry); |  | 
| 3274       } |  | 
| 3275     } |  | 
| 3276     //TODO(pquitslund): revisit if we need all units or whether one will do |  | 
| 3277     return new AnalysisContextImpl_TaskData( |  | 
| 3278         new GenerateDartLintsTask(this, units, libraryElement), false); |  | 
| 3279   } |  | 
| 3280 |  | 
| 3281   /** |  | 
| 3282    * Create a [GetContentTask] for the given [source], marking the content as |  | 
| 3283    * being in-process. |  | 
| 3284    */ |  | 
| 3285   AnalysisContextImpl_TaskData _createGetContentTask( |  | 
| 3286       Source source, SourceEntry sourceEntry) { |  | 
| 3287     return new AnalysisContextImpl_TaskData( |  | 
| 3288         new GetContentTask(this, source), false); |  | 
| 3289   } |  | 
| 3290 |  | 
| 3291   /** |  | 
| 3292    * Create a [ParseDartTask] for the given [source]. |  | 
| 3293    */ |  | 
| 3294   AnalysisContextImpl_TaskData _createParseDartTask( |  | 
| 3295       Source source, DartEntry dartEntry) { |  | 
| 3296     if (dartEntry.getState(DartEntry.TOKEN_STREAM) != CacheState.VALID || |  | 
| 3297         dartEntry.getState(SourceEntry.LINE_INFO) != CacheState.VALID) { |  | 
| 3298       return _createScanDartTask(source, dartEntry); |  | 
| 3299     } |  | 
| 3300     Token tokenStream = dartEntry.getValue(DartEntry.TOKEN_STREAM); |  | 
| 3301     dartEntry.setState(DartEntry.TOKEN_STREAM, CacheState.FLUSHED); |  | 
| 3302     return new AnalysisContextImpl_TaskData(new ParseDartTask(this, source, |  | 
| 3303         tokenStream, dartEntry.getValue(SourceEntry.LINE_INFO)), false); |  | 
| 3304   } |  | 
| 3305 |  | 
| 3306   /** |  | 
| 3307    * Create a [ParseHtmlTask] for the given [source]. |  | 
| 3308    */ |  | 
| 3309   AnalysisContextImpl_TaskData _createParseHtmlTask( |  | 
| 3310       Source source, HtmlEntry htmlEntry) { |  | 
| 3311     if (htmlEntry.getState(SourceEntry.CONTENT) != CacheState.VALID) { |  | 
| 3312       return _createGetContentTask(source, htmlEntry); |  | 
| 3313     } |  | 
| 3314     String content = htmlEntry.getValue(SourceEntry.CONTENT); |  | 
| 3315     htmlEntry.setState(SourceEntry.CONTENT, CacheState.FLUSHED); |  | 
| 3316     return new AnalysisContextImpl_TaskData( |  | 
| 3317         new ParseHtmlTask(this, source, content), false); |  | 
| 3318   } |  | 
| 3319 |  | 
| 3320   /** |  | 
| 3321    * Create a [ResolveDartLibraryTask] for the given [source], marking ? as |  | 
| 3322    * being in-process. |  | 
| 3323    */ |  | 
| 3324   AnalysisContextImpl_TaskData _createResolveDartLibraryTask( |  | 
| 3325       Source source, DartEntry dartEntry) { |  | 
| 3326     try { |  | 
| 3327       AnalysisContextImpl_CycleBuilder builder = |  | 
| 3328           new AnalysisContextImpl_CycleBuilder(this); |  | 
| 3329       PerformanceStatistics.cycles.makeCurrentWhile(() { |  | 
| 3330         builder.computeCycleContaining(source); |  | 
| 3331       }); |  | 
| 3332       AnalysisContextImpl_TaskData taskData = builder.taskData; |  | 
| 3333       if (taskData != null) { |  | 
| 3334         return taskData; |  | 
| 3335       } |  | 
| 3336       return new AnalysisContextImpl_TaskData(new ResolveDartLibraryCycleTask( |  | 
| 3337           this, source, source, builder.librariesInCycle), false); |  | 
| 3338     } on AnalysisException catch (exception, stackTrace) { |  | 
| 3339       dartEntry |  | 
| 3340           .recordResolutionError(new CaughtException(exception, stackTrace)); |  | 
| 3341       AnalysisEngine.instance.logger.logError( |  | 
| 3342           "Internal error trying to create a ResolveDartLibraryTask", |  | 
| 3343           new CaughtException(exception, stackTrace)); |  | 
| 3344     } |  | 
| 3345     return new AnalysisContextImpl_TaskData(null, false); |  | 
| 3346   } |  | 
| 3347 |  | 
| 3348   /** |  | 
| 3349    * Create a [ResolveHtmlTask] for the given [source], marking the resolved |  | 
| 3350    * unit as being in-process. |  | 
| 3351    */ |  | 
| 3352   AnalysisContextImpl_TaskData _createResolveHtmlTask( |  | 
| 3353       Source source, HtmlEntry htmlEntry) { |  | 
| 3354     if (htmlEntry.getState(HtmlEntry.PARSED_UNIT) != CacheState.VALID) { |  | 
| 3355       return _createParseHtmlTask(source, htmlEntry); |  | 
| 3356     } |  | 
| 3357     return new AnalysisContextImpl_TaskData(new ResolveHtmlTask(this, source, |  | 
| 3358         htmlEntry.modificationTime, |  | 
| 3359         htmlEntry.getValue(HtmlEntry.PARSED_UNIT)), false); |  | 
| 3360   } |  | 
| 3361 |  | 
| 3362   /** |  | 
| 3363    * Create a [ScanDartTask] for the given [source], marking the scan errors as |  | 
| 3364    * being in-process. |  | 
| 3365    */ |  | 
| 3366   AnalysisContextImpl_TaskData _createScanDartTask( |  | 
| 3367       Source source, DartEntry dartEntry) { |  | 
| 3368     if (dartEntry.getState(SourceEntry.CONTENT) != CacheState.VALID) { |  | 
| 3369       return _createGetContentTask(source, dartEntry); |  | 
| 3370     } |  | 
| 3371     String content = dartEntry.getValue(SourceEntry.CONTENT); |  | 
| 3372     dartEntry.setState(SourceEntry.CONTENT, CacheState.FLUSHED); |  | 
| 3373     return new AnalysisContextImpl_TaskData( |  | 
| 3374         new ScanDartTask(this, source, content), false); |  | 
| 3375   } |  | 
| 3376 |  | 
| 3377   /** |  | 
| 3378    * Create a source entry for the given [source]. Return the source entry that |  | 
| 3379    * was created, or `null` if the source should not be tracked by this context. |  | 
| 3380    */ |  | 
| 3381   SourceEntry _createSourceEntry(Source source, bool explicitlyAdded) { |  | 
| 3382     String name = source.shortName; |  | 
| 3383     if (AnalysisEngine.isHtmlFileName(name)) { |  | 
| 3384       HtmlEntry htmlEntry = new HtmlEntry(); |  | 
| 3385       htmlEntry.modificationTime = getModificationStamp(source); |  | 
| 3386       htmlEntry.explicitlyAdded = explicitlyAdded; |  | 
| 3387       _cache.put(source, htmlEntry); |  | 
| 3388       return htmlEntry; |  | 
| 3389     } else { |  | 
| 3390       DartEntry dartEntry = new DartEntry(); |  | 
| 3391       dartEntry.modificationTime = getModificationStamp(source); |  | 
| 3392       dartEntry.explicitlyAdded = explicitlyAdded; |  | 
| 3393       _cache.put(source, dartEntry); |  | 
| 3394       return dartEntry; |  | 
| 3395     } |  | 
| 3396   } |  | 
| 3397 |  | 
| 3398   /** |  | 
| 3399    * Return a list containing all of the change notices that are waiting to be |  | 
| 3400    * returned. If there are no notices, then return either `null` or an empty |  | 
| 3401    * list, depending on the value of [nullIfEmpty]. |  | 
| 3402    */ |  | 
| 3403   List<ChangeNotice> _getChangeNotices(bool nullIfEmpty) { |  | 
| 3404     if (_pendingNotices.isEmpty) { |  | 
| 3405       if (nullIfEmpty) { |  | 
| 3406         return null; |  | 
| 3407       } |  | 
| 3408       return ChangeNoticeImpl.EMPTY_LIST; |  | 
| 3409     } |  | 
| 3410     List<ChangeNotice> notices = new List.from(_pendingNotices.values); |  | 
| 3411     _pendingNotices.clear(); |  | 
| 3412     return notices; |  | 
| 3413   } |  | 
| 3414 |  | 
| 3415   /** |  | 
| 3416    * Given a source for a Dart file and the library that contains it, return the |  | 
| 3417    * data represented by the given descriptor that is associated with that |  | 
| 3418    * source. This method assumes that the data can be produced by generating |  | 
| 3419    * hints for the library if it is not already cached. |  | 
| 3420    * |  | 
| 3421    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 3422    * source could not be resolved. |  | 
| 3423    * |  | 
| 3424    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3425    */ |  | 
| 3426   Object _getDartHintData(Source unitSource, Source librarySource, |  | 
| 3427       DartEntry dartEntry, DataDescriptor descriptor) { |  | 
| 3428     dartEntry = |  | 
| 3429         _cacheDartHintData(unitSource, librarySource, dartEntry, descriptor); |  | 
| 3430     if (identical(descriptor, DartEntry.ELEMENT)) { |  | 
| 3431       return dartEntry.getValue(descriptor); |  | 
| 3432     } |  | 
| 3433     return dartEntry.getValueInLibrary(descriptor, librarySource); |  | 
| 3434   } |  | 
| 3435 |  | 
| 3436   /** |  | 
| 3437    * Given a source for a Dart file and the library that contains it, return the |  | 
| 3438    * data represented by the given descriptor that is associated with that |  | 
| 3439    * source. This method assumes that the data can be produced by generating |  | 
| 3440    * lints for the library if it is not already cached. |  | 
| 3441    * |  | 
| 3442    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 3443    * source could not be resolved. |  | 
| 3444    * |  | 
| 3445    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3446    */ |  | 
| 3447   Object _getDartLintData(Source unitSource, Source librarySource, |  | 
| 3448       DartEntry dartEntry, DataDescriptor descriptor) { |  | 
| 3449     dartEntry = |  | 
| 3450         _cacheDartLintData(unitSource, librarySource, dartEntry, descriptor); |  | 
| 3451     if (identical(descriptor, DartEntry.ELEMENT)) { |  | 
| 3452       return dartEntry.getValue(descriptor); |  | 
| 3453     } |  | 
| 3454     return dartEntry.getValueInLibrary(descriptor, librarySource); |  | 
| 3455   } |  | 
| 3456 |  | 
| 3457   /** |  | 
| 3458    * Given a source for a Dart file, return the data represented by the given |  | 
| 3459    * descriptor that is associated with that source. This method assumes that |  | 
| 3460    * the data can be produced by parsing the source if it is not already cached. |  | 
| 3461    * |  | 
| 3462    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 3463    * source could not be parsed. |  | 
| 3464    * |  | 
| 3465    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3466    */ |  | 
| 3467   Object _getDartParseData( |  | 
| 3468       Source source, DartEntry dartEntry, DataDescriptor descriptor) { |  | 
| 3469     dartEntry = _cacheDartParseData(source, dartEntry, descriptor); |  | 
| 3470     if (identical(descriptor, DartEntry.PARSED_UNIT)) { |  | 
| 3471       _accessedAst(source); |  | 
| 3472       return dartEntry.anyParsedCompilationUnit; |  | 
| 3473     } |  | 
| 3474     return dartEntry.getValue(descriptor); |  | 
| 3475   } |  | 
| 3476 |  | 
| 3477   /** |  | 
| 3478    * Given a source for a Dart file, return the data represented by the given |  | 
| 3479    * descriptor that is associated with that source, or the given default value |  | 
| 3480    * if the source is not a Dart file. This method assumes that the data can be |  | 
| 3481    * produced by parsing the source if it is not already cached. |  | 
| 3482    * |  | 
| 3483    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 3484    * source could not be parsed. |  | 
| 3485    * |  | 
| 3486    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3487    */ |  | 
| 3488   Object _getDartParseData2( |  | 
| 3489       Source source, DataDescriptor descriptor, Object defaultValue) { |  | 
| 3490     DartEntry dartEntry = _getReadableDartEntry(source); |  | 
| 3491     if (dartEntry == null) { |  | 
| 3492       return defaultValue; |  | 
| 3493     } |  | 
| 3494     try { |  | 
| 3495       return _getDartParseData(source, dartEntry, descriptor); |  | 
| 3496     } on ObsoleteSourceAnalysisException catch (exception, stackTrace) { |  | 
| 3497       AnalysisEngine.instance.logger.logInformation( |  | 
| 3498           "Could not compute $descriptor", |  | 
| 3499           new CaughtException(exception, stackTrace)); |  | 
| 3500       return defaultValue; |  | 
| 3501     } |  | 
| 3502   } |  | 
| 3503 |  | 
| 3504   /** |  | 
| 3505    * Given a source for a Dart file and the library that contains it, return the |  | 
| 3506    * data represented by the given descriptor that is associated with that |  | 
| 3507    * source. This method assumes that the data can be produced by resolving the |  | 
| 3508    * source in the context of the library if it is not already cached. |  | 
| 3509    * |  | 
| 3510    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 3511    * source could not be resolved. |  | 
| 3512    * |  | 
| 3513    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3514    */ |  | 
| 3515   Object _getDartResolutionData(Source unitSource, Source librarySource, |  | 
| 3516       DartEntry dartEntry, DataDescriptor descriptor) { |  | 
| 3517     dartEntry = _cacheDartResolutionData( |  | 
| 3518         unitSource, librarySource, dartEntry, descriptor); |  | 
| 3519     if (identical(descriptor, DartEntry.ELEMENT)) { |  | 
| 3520       return dartEntry.getValue(descriptor); |  | 
| 3521     } else if (identical(descriptor, DartEntry.RESOLVED_UNIT)) { |  | 
| 3522       _accessedAst(unitSource); |  | 
| 3523     } |  | 
| 3524     return dartEntry.getValueInLibrary(descriptor, librarySource); |  | 
| 3525   } |  | 
| 3526 |  | 
| 3527   /** |  | 
| 3528    * Given a source for a Dart file and the library that contains it, return the |  | 
| 3529    * data represented by the given descriptor that is associated with that |  | 
| 3530    * source, or the given default value if the source is not a Dart file. This |  | 
| 3531    * method assumes that the data can be produced by resolving the source in the |  | 
| 3532    * context of the library if it is not already cached. |  | 
| 3533    * |  | 
| 3534    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 3535    * source could not be resolved. |  | 
| 3536    * |  | 
| 3537    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3538    */ |  | 
| 3539   Object _getDartResolutionData2(Source unitSource, Source librarySource, |  | 
| 3540       DataDescriptor descriptor, Object defaultValue) { |  | 
| 3541     DartEntry dartEntry = _getReadableDartEntry(unitSource); |  | 
| 3542     if (dartEntry == null) { |  | 
| 3543       return defaultValue; |  | 
| 3544     } |  | 
| 3545     try { |  | 
| 3546       return _getDartResolutionData( |  | 
| 3547           unitSource, librarySource, dartEntry, descriptor); |  | 
| 3548     } on ObsoleteSourceAnalysisException catch (exception, stackTrace) { |  | 
| 3549       AnalysisEngine.instance.logger.logInformation( |  | 
| 3550           "Could not compute $descriptor", |  | 
| 3551           new CaughtException(exception, stackTrace)); |  | 
| 3552       return defaultValue; |  | 
| 3553     } |  | 
| 3554   } |  | 
| 3555 |  | 
| 3556   /** |  | 
| 3557    * Given a source for a Dart file, return the data represented by the given |  | 
| 3558    * descriptor that is associated with that source. This method assumes that |  | 
| 3559    * the data can be produced by scanning the source if it is not already |  | 
| 3560    * cached. |  | 
| 3561    * |  | 
| 3562    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 3563    * source could not be scanned. |  | 
| 3564    * |  | 
| 3565    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3566    */ |  | 
| 3567   Object _getDartScanData( |  | 
| 3568       Source source, DartEntry dartEntry, DataDescriptor descriptor) { |  | 
| 3569     dartEntry = _cacheDartScanData(source, dartEntry, descriptor); |  | 
| 3570     return dartEntry.getValue(descriptor); |  | 
| 3571   } |  | 
| 3572 |  | 
| 3573   /** |  | 
| 3574    * Given a source for a Dart file, return the data represented by the given |  | 
| 3575    * descriptor that is associated with that source, or the given default value |  | 
| 3576    * if the source is not a Dart file. This method assumes that the data can be |  | 
| 3577    * produced by scanning the source if it is not already cached. |  | 
| 3578    * |  | 
| 3579    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 3580    * source could not be scanned. |  | 
| 3581    * |  | 
| 3582    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3583    */ |  | 
| 3584   Object _getDartScanData2( |  | 
| 3585       Source source, DataDescriptor descriptor, Object defaultValue) { |  | 
| 3586     DartEntry dartEntry = _getReadableDartEntry(source); |  | 
| 3587     if (dartEntry == null) { |  | 
| 3588       return defaultValue; |  | 
| 3589     } |  | 
| 3590     try { |  | 
| 3591       return _getDartScanData(source, dartEntry, descriptor); |  | 
| 3592     } on ObsoleteSourceAnalysisException catch (exception, stackTrace) { |  | 
| 3593       AnalysisEngine.instance.logger.logInformation( |  | 
| 3594           "Could not compute $descriptor", |  | 
| 3595           new CaughtException(exception, stackTrace)); |  | 
| 3596       return defaultValue; |  | 
| 3597     } |  | 
| 3598   } |  | 
| 3599 |  | 
| 3600   /** |  | 
| 3601    * Given a source for a Dart file and the library that contains it, return the |  | 
| 3602    * data represented by the given descriptor that is associated with that |  | 
| 3603    * source. This method assumes that the data can be produced by verifying the |  | 
| 3604    * source within the given library if it is not already cached. |  | 
| 3605    * |  | 
| 3606    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 3607    * source could not be resolved. |  | 
| 3608    * |  | 
| 3609    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3610    */ |  | 
| 3611   Object _getDartVerificationData(Source unitSource, Source librarySource, |  | 
| 3612       DartEntry dartEntry, DataDescriptor descriptor) { |  | 
| 3613     dartEntry = _cacheDartVerificationData( |  | 
| 3614         unitSource, librarySource, dartEntry, descriptor); |  | 
| 3615     return dartEntry.getValueInLibrary(descriptor, librarySource); |  | 
| 3616   } |  | 
| 3617 |  | 
| 3618   /** |  | 
| 3619    * Given a source for an HTML file, return the data represented by the given |  | 
| 3620    * descriptor that is associated with that source, or the given default value |  | 
| 3621    * if the source is not an HTML file. This method assumes that the data can be |  | 
| 3622    * produced by parsing the source if it is not already cached. |  | 
| 3623    * |  | 
| 3624    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 3625    * source could not be parsed. |  | 
| 3626    * |  | 
| 3627    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3628    */ |  | 
| 3629   Object _getHtmlParseData( |  | 
| 3630       Source source, DataDescriptor descriptor, Object defaultValue) { |  | 
| 3631     HtmlEntry htmlEntry = _getReadableHtmlEntry(source); |  | 
| 3632     if (htmlEntry == null) { |  | 
| 3633       return defaultValue; |  | 
| 3634     } |  | 
| 3635     htmlEntry = _cacheHtmlParseData(source, htmlEntry, descriptor); |  | 
| 3636     if (identical(descriptor, HtmlEntry.PARSED_UNIT)) { |  | 
| 3637       _accessedAst(source); |  | 
| 3638       return htmlEntry.anyParsedUnit; |  | 
| 3639     } |  | 
| 3640     return htmlEntry.getValue(descriptor); |  | 
| 3641   } |  | 
| 3642 |  | 
| 3643   /** |  | 
| 3644    * Given a source for an HTML file, return the data represented by the given |  | 
| 3645    * descriptor that is associated with that source, or the given default value |  | 
| 3646    * if the source is not an HTML file. This method assumes that the data can be |  | 
| 3647    * produced by resolving the source if it is not already cached. |  | 
| 3648    * |  | 
| 3649    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 3650    * source could not be resolved. |  | 
| 3651    * |  | 
| 3652    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3653    */ |  | 
| 3654   Object _getHtmlResolutionData( |  | 
| 3655       Source source, DataDescriptor descriptor, Object defaultValue) { |  | 
| 3656     HtmlEntry htmlEntry = _getReadableHtmlEntry(source); |  | 
| 3657     if (htmlEntry == null) { |  | 
| 3658       return defaultValue; |  | 
| 3659     } |  | 
| 3660     try { |  | 
| 3661       return _getHtmlResolutionData2(source, htmlEntry, descriptor); |  | 
| 3662     } on ObsoleteSourceAnalysisException catch (exception, stackTrace) { |  | 
| 3663       AnalysisEngine.instance.logger.logInformation( |  | 
| 3664           "Could not compute $descriptor", |  | 
| 3665           new CaughtException(exception, stackTrace)); |  | 
| 3666       return defaultValue; |  | 
| 3667     } |  | 
| 3668   } |  | 
| 3669 |  | 
| 3670   /** |  | 
| 3671    * Given a source for an HTML file, return the data represented by the given |  | 
| 3672    * descriptor that is associated with that source. This method assumes that |  | 
| 3673    * the data can be produced by resolving the source if it is not already |  | 
| 3674    * cached. |  | 
| 3675    * |  | 
| 3676    * Throws an [AnalysisException] if data could not be returned because the |  | 
| 3677    * source could not be resolved. |  | 
| 3678    * |  | 
| 3679    * <b>Note:</b> This method cannot be used in an async environment. |  | 
| 3680    */ |  | 
| 3681   Object _getHtmlResolutionData2( |  | 
| 3682       Source source, HtmlEntry htmlEntry, DataDescriptor descriptor) { |  | 
| 3683     htmlEntry = _cacheHtmlResolutionData(source, htmlEntry, descriptor); |  | 
| 3684     if (identical(descriptor, HtmlEntry.RESOLVED_UNIT)) { |  | 
| 3685       _accessedAst(source); |  | 
| 3686     } |  | 
| 3687     return htmlEntry.getValue(descriptor); |  | 
| 3688   } |  | 
| 3689 |  | 
| 3690   /** |  | 
| 3691    * Look at the given [source] to see whether a task needs to be performed |  | 
| 3692    * related to it. Return the task that should be performed, or `null` if there |  | 
| 3693    * is no more work to be done for the source. |  | 
| 3694    */ |  | 
| 3695   AnalysisContextImpl_TaskData _getNextAnalysisTaskForSource(Source source, |  | 
| 3696       SourceEntry sourceEntry, bool isPriority, bool hintsEnabled, |  | 
| 3697       bool lintsEnabled) { |  | 
| 3698     // Refuse to generate tasks for html based files that are above 1500 KB |  | 
| 3699     if (_isTooBigHtmlSourceEntry(source, sourceEntry)) { |  | 
| 3700       // TODO (jwren) we still need to report an error of some kind back to the |  | 
| 3701       // client. |  | 
| 3702       return new AnalysisContextImpl_TaskData(null, false); |  | 
| 3703     } |  | 
| 3704     if (sourceEntry == null) { |  | 
| 3705       return new AnalysisContextImpl_TaskData(null, false); |  | 
| 3706     } |  | 
| 3707     CacheState contentState = sourceEntry.getState(SourceEntry.CONTENT); |  | 
| 3708     if (contentState == CacheState.INVALID) { |  | 
| 3709       return _createGetContentTask(source, sourceEntry); |  | 
| 3710     } else if (contentState == CacheState.IN_PROCESS) { |  | 
| 3711       // We are already in the process of getting the content. |  | 
| 3712       // There's nothing else we can do with this source until that's complete. |  | 
| 3713       return new AnalysisContextImpl_TaskData(null, true); |  | 
| 3714     } else if (contentState == CacheState.ERROR) { |  | 
| 3715       // We have done all of the analysis we can for this source because we |  | 
| 3716       // cannot get its content. |  | 
| 3717       return new AnalysisContextImpl_TaskData(null, false); |  | 
| 3718     } |  | 
| 3719     if (sourceEntry is DartEntry) { |  | 
| 3720       DartEntry dartEntry = sourceEntry; |  | 
| 3721       CacheState scanErrorsState = dartEntry.getState(DartEntry.SCAN_ERRORS); |  | 
| 3722       if (scanErrorsState == CacheState.INVALID || |  | 
| 3723           (isPriority && scanErrorsState == CacheState.FLUSHED)) { |  | 
| 3724         return _createScanDartTask(source, dartEntry); |  | 
| 3725       } |  | 
| 3726       CacheState parseErrorsState = dartEntry.getState(DartEntry.PARSE_ERRORS); |  | 
| 3727       if (parseErrorsState == CacheState.INVALID || |  | 
| 3728           (isPriority && parseErrorsState == CacheState.FLUSHED)) { |  | 
| 3729         return _createParseDartTask(source, dartEntry); |  | 
| 3730       } |  | 
| 3731       if (isPriority && parseErrorsState != CacheState.ERROR) { |  | 
| 3732         if (!dartEntry.hasResolvableCompilationUnit) { |  | 
| 3733           return _createParseDartTask(source, dartEntry); |  | 
| 3734         } |  | 
| 3735       } |  | 
| 3736       SourceKind kind = dartEntry.getValue(DartEntry.SOURCE_KIND); |  | 
| 3737       if (kind == SourceKind.UNKNOWN) { |  | 
| 3738         return _createParseDartTask(source, dartEntry); |  | 
| 3739       } else if (kind == SourceKind.LIBRARY) { |  | 
| 3740         CacheState elementState = dartEntry.getState(DartEntry.ELEMENT); |  | 
| 3741         if (elementState == CacheState.INVALID) { |  | 
| 3742           return _createResolveDartLibraryTask(source, dartEntry); |  | 
| 3743         } |  | 
| 3744       } |  | 
| 3745       List<Source> librariesContaining = dartEntry.containingLibraries; |  | 
| 3746       for (Source librarySource in librariesContaining) { |  | 
| 3747         SourceEntry librarySourceEntry = _cache.get(librarySource); |  | 
| 3748         if (librarySourceEntry is DartEntry) { |  | 
| 3749           DartEntry libraryEntry = librarySourceEntry; |  | 
| 3750           CacheState elementState = libraryEntry.getState(DartEntry.ELEMENT); |  | 
| 3751           if (elementState == CacheState.INVALID || |  | 
| 3752               (isPriority && elementState == CacheState.FLUSHED)) { |  | 
| 3753 //            return createResolveDartLibraryTask(librarySource, (DartEntry) lib
       raryEntry); |  | 
| 3754             return new AnalysisContextImpl_TaskData( |  | 
| 3755                 new ResolveDartLibraryTask(this, source, librarySource), false); |  | 
| 3756           } |  | 
| 3757           CacheState resolvedUnitState = dartEntry.getStateInLibrary( |  | 
| 3758               DartEntry.RESOLVED_UNIT, librarySource); |  | 
| 3759           if (resolvedUnitState == CacheState.INVALID || |  | 
| 3760               (isPriority && resolvedUnitState == CacheState.FLUSHED)) { |  | 
| 3761             // |  | 
| 3762             // The commented out lines below are an optimization that doesn't |  | 
| 3763             // quite work yet. The problem is that if the source was not |  | 
| 3764             // resolved because it wasn't part of any library, then there won't |  | 
| 3765             // be any elements in the element model that we can use to resolve |  | 
| 3766             // it. |  | 
| 3767             // |  | 
| 3768 //            LibraryElement libraryElement = libraryEntry.getValue(DartEntry.EL
       EMENT); |  | 
| 3769 //            if (libraryElement != null) { |  | 
| 3770 //              return new ResolveDartUnitTask(this, source, libraryElement); |  | 
| 3771 //            } |  | 
| 3772             // Possibly replace with: |  | 
| 3773 //             return createResolveDartLibraryTask(librarySource, (DartEntry) li
       braryEntry); |  | 
| 3774             return new AnalysisContextImpl_TaskData( |  | 
| 3775                 new ResolveDartLibraryTask(this, source, librarySource), false); |  | 
| 3776           } |  | 
| 3777           if (shouldErrorsBeAnalyzed(source, dartEntry)) { |  | 
| 3778             CacheState verificationErrorsState = dartEntry.getStateInLibrary( |  | 
| 3779                 DartEntry.VERIFICATION_ERRORS, librarySource); |  | 
| 3780             if (verificationErrorsState == CacheState.INVALID || |  | 
| 3781                 (isPriority && verificationErrorsState == CacheState.FLUSHED)) { |  | 
| 3782               return _createGenerateDartErrorsTask( |  | 
| 3783                   source, dartEntry, librarySource, libraryEntry); |  | 
| 3784             } |  | 
| 3785             if (hintsEnabled) { |  | 
| 3786               CacheState hintsState = |  | 
| 3787                   dartEntry.getStateInLibrary(DartEntry.HINTS, librarySource); |  | 
| 3788               if (hintsState == CacheState.INVALID || |  | 
| 3789                   (isPriority && hintsState == CacheState.FLUSHED)) { |  | 
| 3790                 return _createGenerateDartHintsTask( |  | 
| 3791                     source, dartEntry, librarySource, libraryEntry); |  | 
| 3792               } |  | 
| 3793             } |  | 
| 3794             if (lintsEnabled) { |  | 
| 3795               CacheState lintsState = |  | 
| 3796                   dartEntry.getStateInLibrary(DartEntry.LINTS, librarySource); |  | 
| 3797               if (lintsState == CacheState.INVALID || |  | 
| 3798                   (isPriority && lintsState == CacheState.FLUSHED)) { |  | 
| 3799                 return _createGenerateDartLintsTask( |  | 
| 3800                     source, dartEntry, librarySource, libraryEntry); |  | 
| 3801               } |  | 
| 3802             } |  | 
| 3803           } |  | 
| 3804         } |  | 
| 3805       } |  | 
| 3806     } else if (sourceEntry is HtmlEntry) { |  | 
| 3807       HtmlEntry htmlEntry = sourceEntry; |  | 
| 3808       CacheState parseErrorsState = htmlEntry.getState(HtmlEntry.PARSE_ERRORS); |  | 
| 3809       if (parseErrorsState == CacheState.INVALID || |  | 
| 3810           (isPriority && parseErrorsState == CacheState.FLUSHED)) { |  | 
| 3811         return _createParseHtmlTask(source, htmlEntry); |  | 
| 3812       } |  | 
| 3813       if (isPriority && parseErrorsState != CacheState.ERROR) { |  | 
| 3814         ht.HtmlUnit parsedUnit = htmlEntry.anyParsedUnit; |  | 
| 3815         if (parsedUnit == null) { |  | 
| 3816           return _createParseHtmlTask(source, htmlEntry); |  | 
| 3817         } |  | 
| 3818       } |  | 
| 3819       CacheState resolvedUnitState = |  | 
| 3820           htmlEntry.getState(HtmlEntry.RESOLVED_UNIT); |  | 
| 3821       if (resolvedUnitState == CacheState.INVALID || |  | 
| 3822           (isPriority && resolvedUnitState == CacheState.FLUSHED)) { |  | 
| 3823         return _createResolveHtmlTask(source, htmlEntry); |  | 
| 3824       } |  | 
| 3825     } |  | 
| 3826     return new AnalysisContextImpl_TaskData(null, false); |  | 
| 3827   } |  | 
| 3828 |  | 
| 3829   /** |  | 
| 3830    * Return the cache entry associated with the given [source], or `null` if the |  | 
| 3831    * source is not a Dart file. |  | 
| 3832    * |  | 
| 3833    * @param source the source for which a cache entry is being sought |  | 
| 3834    * @return the source cache entry associated with the given source |  | 
| 3835    */ |  | 
| 3836   DartEntry _getReadableDartEntry(Source source) { |  | 
| 3837     SourceEntry sourceEntry = _cache.get(source); |  | 
| 3838     if (sourceEntry == null) { |  | 
| 3839       sourceEntry = _createSourceEntry(source, false); |  | 
| 3840     } |  | 
| 3841     if (sourceEntry is DartEntry) { |  | 
| 3842       return sourceEntry; |  | 
| 3843     } |  | 
| 3844     return null; |  | 
| 3845   } |  | 
| 3846 |  | 
| 3847   /** |  | 
| 3848    * Return the cache entry associated with the given [source], or `null` if the |  | 
| 3849    * source is not an HTML file. |  | 
| 3850    */ |  | 
| 3851   HtmlEntry _getReadableHtmlEntry(Source source) { |  | 
| 3852     SourceEntry sourceEntry = _cache.get(source); |  | 
| 3853     if (sourceEntry == null) { |  | 
| 3854       sourceEntry = _createSourceEntry(source, false); |  | 
| 3855     } |  | 
| 3856     if (sourceEntry is HtmlEntry) { |  | 
| 3857       return sourceEntry; |  | 
| 3858     } |  | 
| 3859     return null; |  | 
| 3860   } |  | 
| 3861 |  | 
| 3862   /** |  | 
| 3863    * Return the cache entry associated with the given [source], creating it if |  | 
| 3864    * necessary. |  | 
| 3865    */ |  | 
| 3866   SourceEntry _getReadableSourceEntry(Source source) { |  | 
| 3867     SourceEntry sourceEntry = _cache.get(source); |  | 
| 3868     if (sourceEntry == null) { |  | 
| 3869       sourceEntry = _createSourceEntry(source, false); |  | 
| 3870     } |  | 
| 3871     return sourceEntry; |  | 
| 3872   } |  | 
| 3873 |  | 
| 3874   /** |  | 
| 3875    * Return a resolved compilation unit corresponding to the given [element] in |  | 
| 3876    * the library defined by the given [librarySource], or `null` if the |  | 
| 3877    * information is not cached. |  | 
| 3878    */ |  | 
| 3879   TimestampedData<CompilationUnit> _getResolvedUnit( |  | 
| 3880       CompilationUnitElement element, Source librarySource) { |  | 
| 3881     SourceEntry sourceEntry = _cache.get(element.source); |  | 
| 3882     if (sourceEntry is DartEntry) { |  | 
| 3883       DartEntry dartEntry = sourceEntry; |  | 
| 3884       if (dartEntry.getStateInLibrary(DartEntry.RESOLVED_UNIT, librarySource) == |  | 
| 3885           CacheState.VALID) { |  | 
| 3886         return new TimestampedData<CompilationUnit>(dartEntry.modificationTime, |  | 
| 3887             dartEntry.getValueInLibrary( |  | 
| 3888                 DartEntry.RESOLVED_UNIT, librarySource)); |  | 
| 3889       } |  | 
| 3890     } |  | 
| 3891     return null; |  | 
| 3892   } |  | 
| 3893 |  | 
| 3894   /** |  | 
| 3895    * Return a list containing all of the sources known to this context that have |  | 
| 3896    * the given [kind]. |  | 
| 3897    */ |  | 
| 3898   List<Source> _getSources(SourceKind kind) { |  | 
| 3899     List<Source> sources = new List<Source>(); |  | 
| 3900     MapIterator<Source, SourceEntry> iterator = _cache.iterator(); |  | 
| 3901     while (iterator.moveNext()) { |  | 
| 3902       if (iterator.value.kind == kind) { |  | 
| 3903         sources.add(iterator.key); |  | 
| 3904       } |  | 
| 3905     } |  | 
| 3906     return sources; |  | 
| 3907   } |  | 
| 3908 |  | 
| 3909   /** |  | 
| 3910    * Look at the given [source] to see whether a task needs to be performed |  | 
| 3911    * related to it. If so, add the source to the set of sources that need to be |  | 
| 3912    * processed. This method duplicates, and must therefore be kept in sync with, |  | 
| 3913    * [_getNextAnalysisTaskForSource]. This method is intended to be used for |  | 
| 3914    * testing purposes only. |  | 
| 3915    */ |  | 
| 3916   void _getSourcesNeedingProcessing(Source source, SourceEntry sourceEntry, |  | 
| 3917       bool isPriority, bool hintsEnabled, bool lintsEnabled, |  | 
| 3918       HashSet<Source> sources) { |  | 
| 3919     if (sourceEntry is DartEntry) { |  | 
| 3920       DartEntry dartEntry = sourceEntry; |  | 
| 3921       CacheState scanErrorsState = dartEntry.getState(DartEntry.SCAN_ERRORS); |  | 
| 3922       if (scanErrorsState == CacheState.INVALID || |  | 
| 3923           (isPriority && scanErrorsState == CacheState.FLUSHED)) { |  | 
| 3924         sources.add(source); |  | 
| 3925         return; |  | 
| 3926       } |  | 
| 3927       CacheState parseErrorsState = dartEntry.getState(DartEntry.PARSE_ERRORS); |  | 
| 3928       if (parseErrorsState == CacheState.INVALID || |  | 
| 3929           (isPriority && parseErrorsState == CacheState.FLUSHED)) { |  | 
| 3930         sources.add(source); |  | 
| 3931         return; |  | 
| 3932       } |  | 
| 3933       if (isPriority) { |  | 
| 3934         if (!dartEntry.hasResolvableCompilationUnit) { |  | 
| 3935           sources.add(source); |  | 
| 3936           return; |  | 
| 3937         } |  | 
| 3938       } |  | 
| 3939       for (Source librarySource in getLibrariesContaining(source)) { |  | 
| 3940         SourceEntry libraryEntry = _cache.get(librarySource); |  | 
| 3941         if (libraryEntry is DartEntry) { |  | 
| 3942           CacheState elementState = libraryEntry.getState(DartEntry.ELEMENT); |  | 
| 3943           if (elementState == CacheState.INVALID || |  | 
| 3944               (isPriority && elementState == CacheState.FLUSHED)) { |  | 
| 3945             sources.add(source); |  | 
| 3946             return; |  | 
| 3947           } |  | 
| 3948           CacheState resolvedUnitState = dartEntry.getStateInLibrary( |  | 
| 3949               DartEntry.RESOLVED_UNIT, librarySource); |  | 
| 3950           if (resolvedUnitState == CacheState.INVALID || |  | 
| 3951               (isPriority && resolvedUnitState == CacheState.FLUSHED)) { |  | 
| 3952             LibraryElement libraryElement = |  | 
| 3953                 libraryEntry.getValue(DartEntry.ELEMENT); |  | 
| 3954             if (libraryElement != null) { |  | 
| 3955               sources.add(source); |  | 
| 3956               return; |  | 
| 3957             } |  | 
| 3958           } |  | 
| 3959           if (shouldErrorsBeAnalyzed(source, dartEntry)) { |  | 
| 3960             CacheState verificationErrorsState = dartEntry.getStateInLibrary( |  | 
| 3961                 DartEntry.VERIFICATION_ERRORS, librarySource); |  | 
| 3962             if (verificationErrorsState == CacheState.INVALID || |  | 
| 3963                 (isPriority && verificationErrorsState == CacheState.FLUSHED)) { |  | 
| 3964               LibraryElement libraryElement = |  | 
| 3965                   libraryEntry.getValue(DartEntry.ELEMENT); |  | 
| 3966               if (libraryElement != null) { |  | 
| 3967                 sources.add(source); |  | 
| 3968                 return; |  | 
| 3969               } |  | 
| 3970             } |  | 
| 3971             if (hintsEnabled) { |  | 
| 3972               CacheState hintsState = |  | 
| 3973                   dartEntry.getStateInLibrary(DartEntry.HINTS, librarySource); |  | 
| 3974               if (hintsState == CacheState.INVALID || |  | 
| 3975                   (isPriority && hintsState == CacheState.FLUSHED)) { |  | 
| 3976                 LibraryElement libraryElement = |  | 
| 3977                     libraryEntry.getValue(DartEntry.ELEMENT); |  | 
| 3978                 if (libraryElement != null) { |  | 
| 3979                   sources.add(source); |  | 
| 3980                   return; |  | 
| 3981                 } |  | 
| 3982               } |  | 
| 3983             } |  | 
| 3984             if (lintsEnabled) { |  | 
| 3985               CacheState lintsState = |  | 
| 3986                   dartEntry.getStateInLibrary(DartEntry.LINTS, librarySource); |  | 
| 3987               if (lintsState == CacheState.INVALID || |  | 
| 3988                   (isPriority && lintsState == CacheState.FLUSHED)) { |  | 
| 3989                 LibraryElement libraryElement = |  | 
| 3990                     libraryEntry.getValue(DartEntry.ELEMENT); |  | 
| 3991                 if (libraryElement != null) { |  | 
| 3992                   sources.add(source); |  | 
| 3993                   return; |  | 
| 3994                 } |  | 
| 3995               } |  | 
| 3996             } |  | 
| 3997           } |  | 
| 3998         } |  | 
| 3999       } |  | 
| 4000     } else if (sourceEntry is HtmlEntry) { |  | 
| 4001       HtmlEntry htmlEntry = sourceEntry; |  | 
| 4002       CacheState parsedUnitState = htmlEntry.getState(HtmlEntry.PARSED_UNIT); |  | 
| 4003       if (parsedUnitState == CacheState.INVALID || |  | 
| 4004           (isPriority && parsedUnitState == CacheState.FLUSHED)) { |  | 
| 4005         sources.add(source); |  | 
| 4006         return; |  | 
| 4007       } |  | 
| 4008       CacheState resolvedUnitState = |  | 
| 4009           htmlEntry.getState(HtmlEntry.RESOLVED_UNIT); |  | 
| 4010       if (resolvedUnitState == CacheState.INVALID || |  | 
| 4011           (isPriority && resolvedUnitState == CacheState.FLUSHED)) { |  | 
| 4012         sources.add(source); |  | 
| 4013         return; |  | 
| 4014       } |  | 
| 4015     } |  | 
| 4016   } |  | 
| 4017 |  | 
| 4018   /** |  | 
| 4019    * Invalidate all of the resolution results computed by this context. The flag |  | 
| 4020    * [invalidateUris] should be `true` if the cached results of converting URIs |  | 
| 4021    * to source files should also be invalidated. |  | 
| 4022    */ |  | 
| 4023   void _invalidateAllLocalResolutionInformation(bool invalidateUris) { |  | 
| 4024     HashMap<Source, List<Source>> oldPartMap = |  | 
| 4025         new HashMap<Source, List<Source>>(); |  | 
| 4026     MapIterator<Source, SourceEntry> iterator = _privatePartition.iterator(); |  | 
| 4027     while (iterator.moveNext()) { |  | 
| 4028       Source source = iterator.key; |  | 
| 4029       SourceEntry sourceEntry = iterator.value; |  | 
| 4030       if (sourceEntry is HtmlEntry) { |  | 
| 4031         HtmlEntry htmlEntry = sourceEntry; |  | 
| 4032         htmlEntry.invalidateAllResolutionInformation(invalidateUris); |  | 
| 4033         iterator.value = htmlEntry; |  | 
| 4034         _workManager.add(source, SourcePriority.HTML); |  | 
| 4035       } else if (sourceEntry is DartEntry) { |  | 
| 4036         DartEntry dartEntry = sourceEntry; |  | 
| 4037         oldPartMap[source] = dartEntry.getValue(DartEntry.INCLUDED_PARTS); |  | 
| 4038         dartEntry.invalidateAllResolutionInformation(invalidateUris); |  | 
| 4039         iterator.value = dartEntry; |  | 
| 4040         _workManager.add(source, _computePriority(dartEntry)); |  | 
| 4041       } |  | 
| 4042     } |  | 
| 4043     _removeFromPartsUsingMap(oldPartMap); |  | 
| 4044   } |  | 
| 4045 |  | 
| 4046   /** |  | 
| 4047    * In response to a change to at least one of the compilation units in the |  | 
| 4048    * library defined by the given [librarySource], invalidate any results that |  | 
| 4049    * are dependent on the result of resolving that library. |  | 
| 4050    * |  | 
| 4051    * <b>Note:</b> Any cache entries that were accessed before this method was |  | 
| 4052    * invoked must be re-accessed after this method returns. |  | 
| 4053    */ |  | 
| 4054   void _invalidateLibraryResolution(Source librarySource) { |  | 
| 4055     // TODO(brianwilkerson) This could be optimized. There's no need to flush |  | 
| 4056     // all of these entries if the public namespace hasn't changed, which will |  | 
| 4057     // be a fairly common case. The question is whether we can afford the time |  | 
| 4058     // to compute the namespace to look for differences. |  | 
| 4059     DartEntry libraryEntry = _getReadableDartEntry(librarySource); |  | 
| 4060     if (libraryEntry != null) { |  | 
| 4061       List<Source> includedParts = |  | 
| 4062           libraryEntry.getValue(DartEntry.INCLUDED_PARTS); |  | 
| 4063       libraryEntry.invalidateAllResolutionInformation(false); |  | 
| 4064       _workManager.add(librarySource, SourcePriority.LIBRARY); |  | 
| 4065       for (Source partSource in includedParts) { |  | 
| 4066         SourceEntry partEntry = _cache.get(partSource); |  | 
| 4067         if (partEntry is DartEntry) { |  | 
| 4068           partEntry.invalidateAllResolutionInformation(false); |  | 
| 4069         } |  | 
| 4070       } |  | 
| 4071     } |  | 
| 4072   } |  | 
| 4073 |  | 
| 4074   /** |  | 
| 4075    * Return `true` if the given [library] is, or depends on, 'dart:html'. The |  | 
| 4076    * [visitedLibraries] is a collection of the libraries that have been visited, |  | 
| 4077    * used to prevent infinite recursion. |  | 
| 4078    */ |  | 
| 4079   bool _isClient(LibraryElement library, Source htmlSource, |  | 
| 4080       HashSet<LibraryElement> visitedLibraries) { |  | 
| 4081     if (visitedLibraries.contains(library)) { |  | 
| 4082       return false; |  | 
| 4083     } |  | 
| 4084     if (library.source == htmlSource) { |  | 
| 4085       return true; |  | 
| 4086     } |  | 
| 4087     visitedLibraries.add(library); |  | 
| 4088     for (LibraryElement imported in library.importedLibraries) { |  | 
| 4089       if (_isClient(imported, htmlSource, visitedLibraries)) { |  | 
| 4090         return true; |  | 
| 4091       } |  | 
| 4092     } |  | 
| 4093     for (LibraryElement exported in library.exportedLibraries) { |  | 
| 4094       if (_isClient(exported, htmlSource, visitedLibraries)) { |  | 
| 4095         return true; |  | 
| 4096       } |  | 
| 4097     } |  | 
| 4098     return false; |  | 
| 4099   } |  | 
| 4100 |  | 
| 4101   bool _isTooBigHtmlSourceEntry(Source source, SourceEntry sourceEntry) => |  | 
| 4102       false; |  | 
| 4103 |  | 
| 4104   /** |  | 
| 4105    * Log the given debugging [message]. |  | 
| 4106    */ |  | 
| 4107   void _logInformation(String message) { |  | 
| 4108     AnalysisEngine.instance.logger.logInformation(message); |  | 
| 4109   } |  | 
| 4110 |  | 
| 4111 //  /** |  | 
| 4112 //   * Notify all of the analysis listeners that the given source is no longer i
       ncluded in the set of |  | 
| 4113 //   * sources that are being analyzed. |  | 
| 4114 //   * |  | 
| 4115 //   * @param source the source that is no longer being analyzed |  | 
| 4116 //   */ |  | 
| 4117 //  void _notifyExcludedSource(Source source) { |  | 
| 4118 //    int count = _listeners.length; |  | 
| 4119 //    for (int i = 0; i < count; i++) { |  | 
| 4120 //      _listeners[i].excludedSource(this, source); |  | 
| 4121 //    } |  | 
| 4122 //  } |  | 
| 4123 |  | 
| 4124 //  /** |  | 
| 4125 //   * Notify all of the analysis listeners that the given source is now include
       d in the set of |  | 
| 4126 //   * sources that are being analyzed. |  | 
| 4127 //   * |  | 
| 4128 //   * @param source the source that is now being analyzed |  | 
| 4129 //   */ |  | 
| 4130 //  void _notifyIncludedSource(Source source) { |  | 
| 4131 //    int count = _listeners.length; |  | 
| 4132 //    for (int i = 0; i < count; i++) { |  | 
| 4133 //      _listeners[i].includedSource(this, source); |  | 
| 4134 //    } |  | 
| 4135 //  } |  | 
| 4136 |  | 
| 4137 //  /** |  | 
| 4138 //   * Notify all of the analysis listeners that the given Dart source was parse
       d. |  | 
| 4139 //   * |  | 
| 4140 //   * @param source the source that was parsed |  | 
| 4141 //   * @param unit the result of parsing the source |  | 
| 4142 //   */ |  | 
| 4143 //  void _notifyParsedDart(Source source, CompilationUnit unit) { |  | 
| 4144 //    int count = _listeners.length; |  | 
| 4145 //    for (int i = 0; i < count; i++) { |  | 
| 4146 //      _listeners[i].parsedDart(this, source, unit); |  | 
| 4147 //    } |  | 
| 4148 //  } |  | 
| 4149 |  | 
| 4150 //  /** |  | 
| 4151 //   * Notify all of the analysis listeners that the given HTML source was parse
       d. |  | 
| 4152 //   * |  | 
| 4153 //   * @param source the source that was parsed |  | 
| 4154 //   * @param unit the result of parsing the source |  | 
| 4155 //   */ |  | 
| 4156 //  void _notifyParsedHtml(Source source, ht.HtmlUnit unit) { |  | 
| 4157 //    int count = _listeners.length; |  | 
| 4158 //    for (int i = 0; i < count; i++) { |  | 
| 4159 //      _listeners[i].parsedHtml(this, source, unit); |  | 
| 4160 //    } |  | 
| 4161 //  } |  | 
| 4162 |  | 
| 4163 //  /** |  | 
| 4164 //   * Notify all of the analysis listeners that the given Dart source was resol
       ved. |  | 
| 4165 //   * |  | 
| 4166 //   * @param source the source that was resolved |  | 
| 4167 //   * @param unit the result of resolving the source |  | 
| 4168 //   */ |  | 
| 4169 //  void _notifyResolvedDart(Source source, CompilationUnit unit) { |  | 
| 4170 //    int count = _listeners.length; |  | 
| 4171 //    for (int i = 0; i < count; i++) { |  | 
| 4172 //      _listeners[i].resolvedDart(this, source, unit); |  | 
| 4173 //    } |  | 
| 4174 //  } |  | 
| 4175 |  | 
| 4176 //  /** |  | 
| 4177 //   * Notify all of the analysis listeners that the given HTML source was resol
       ved. |  | 
| 4178 //   * |  | 
| 4179 //   * @param source the source that was resolved |  | 
| 4180 //   * @param unit the result of resolving the source |  | 
| 4181 //   */ |  | 
| 4182 //  void _notifyResolvedHtml(Source source, ht.HtmlUnit unit) { |  | 
| 4183 //    int count = _listeners.length; |  | 
| 4184 //    for (int i = 0; i < count; i++) { |  | 
| 4185 //      _listeners[i].resolvedHtml(this, source, unit); |  | 
| 4186 //    } |  | 
| 4187 //  } |  | 
| 4188 |  | 
| 4189   /** |  | 
| 4190    * Notify all of the analysis listeners that a task is about to be performed. |  | 
| 4191    */ |  | 
| 4192   void _notifyAboutToPerformTask(String taskDescription) { |  | 
| 4193     int count = _listeners.length; |  | 
| 4194     for (int i = 0; i < count; i++) { |  | 
| 4195       _listeners[i].aboutToPerformTask(this, taskDescription); |  | 
| 4196     } |  | 
| 4197   } |  | 
| 4198 |  | 
| 4199   /** |  | 
| 4200    * Notify all of the analysis listeners that the errors associated with the |  | 
| 4201    * given [source] has been updated to the given [errors]. |  | 
| 4202    */ |  | 
| 4203   void _notifyErrors( |  | 
| 4204       Source source, List<AnalysisError> errors, LineInfo lineInfo) { |  | 
| 4205     int count = _listeners.length; |  | 
| 4206     for (int i = 0; i < count; i++) { |  | 
| 4207       _listeners[i].computedErrors(this, source, errors, lineInfo); |  | 
| 4208     } |  | 
| 4209   } |  | 
| 4210 |  | 
| 4211   /** |  | 
| 4212    * Given that the given [source] (with the corresponding [sourceEntry]) has |  | 
| 4213    * been invalidated, invalidate all of the libraries that depend on it. |  | 
| 4214    */ |  | 
| 4215   void _propagateInvalidation(Source source, SourceEntry sourceEntry) { |  | 
| 4216     if (sourceEntry is HtmlEntry) { |  | 
| 4217       HtmlEntry htmlEntry = sourceEntry; |  | 
| 4218       htmlEntry.modificationTime = getModificationStamp(source); |  | 
| 4219       htmlEntry.invalidateAllInformation(); |  | 
| 4220       _cache.removedAst(source); |  | 
| 4221       _workManager.add(source, SourcePriority.HTML); |  | 
| 4222     } else if (sourceEntry is DartEntry) { |  | 
| 4223       List<Source> containingLibraries = getLibrariesContaining(source); |  | 
| 4224       List<Source> dependentLibraries = getLibrariesDependingOn(source); |  | 
| 4225       HashSet<Source> librariesToInvalidate = new HashSet<Source>(); |  | 
| 4226       for (Source containingLibrary in containingLibraries) { |  | 
| 4227         _computeAllLibrariesDependingOn( |  | 
| 4228             containingLibrary, librariesToInvalidate); |  | 
| 4229       } |  | 
| 4230       for (Source dependentLibrary in dependentLibraries) { |  | 
| 4231         _computeAllLibrariesDependingOn( |  | 
| 4232             dependentLibrary, librariesToInvalidate); |  | 
| 4233       } |  | 
| 4234       for (Source library in librariesToInvalidate) { |  | 
| 4235         _invalidateLibraryResolution(library); |  | 
| 4236       } |  | 
| 4237       DartEntry dartEntry = _cache.get(source); |  | 
| 4238       _removeFromParts(source, dartEntry); |  | 
| 4239       dartEntry.modificationTime = getModificationStamp(source); |  | 
| 4240       dartEntry.invalidateAllInformation(); |  | 
| 4241       _cache.removedAst(source); |  | 
| 4242       _workManager.add(source, SourcePriority.UNKNOWN); |  | 
| 4243     } |  | 
| 4244     // reset unit in the notification, it is out of date now |  | 
| 4245     ChangeNoticeImpl notice = _pendingNotices[source]; |  | 
| 4246     if (notice != null) { |  | 
| 4247       notice.resolvedDartUnit = null; |  | 
| 4248       notice.resolvedHtmlUnit = null; |  | 
| 4249     } |  | 
| 4250   } |  | 
| 4251 |  | 
| 4252   /** |  | 
| 4253    * Given a [dartEntry] and a [library] element, record the library element and |  | 
| 4254    * other information gleaned from the element in the cache entry. |  | 
| 4255    */ |  | 
| 4256   void _recordElementData(DartEntry dartEntry, LibraryElement library, |  | 
| 4257       Source librarySource, Source htmlSource) { |  | 
| 4258     dartEntry.setValue(DartEntry.ELEMENT, library); |  | 
| 4259     dartEntry.setValue(DartEntry.IS_LAUNCHABLE, library.entryPoint != null); |  | 
| 4260     dartEntry.setValue(DartEntry.IS_CLIENT, |  | 
| 4261         _isClient(library, htmlSource, new HashSet<LibraryElement>())); |  | 
| 4262   } |  | 
| 4263 |  | 
| 4264   /** |  | 
| 4265    * Record the results produced by performing a [task] and return the cache |  | 
| 4266    * entry associated with the results. |  | 
| 4267    */ |  | 
| 4268   DartEntry _recordGenerateDartErrorsTask(GenerateDartErrorsTask task) { |  | 
| 4269     Source source = task.source; |  | 
| 4270     DartEntry dartEntry = _cache.get(source); |  | 
| 4271     Source librarySource = task.libraryElement.source; |  | 
| 4272     CaughtException thrownException = task.exception; |  | 
| 4273     if (thrownException != null) { |  | 
| 4274       dartEntry.recordVerificationErrorInLibrary( |  | 
| 4275           librarySource, thrownException); |  | 
| 4276       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 4277     } |  | 
| 4278     dartEntry.setValueInLibrary( |  | 
| 4279         DartEntry.VERIFICATION_ERRORS, librarySource, task.errors); |  | 
| 4280     ChangeNoticeImpl notice = getNotice(source); |  | 
| 4281     LineInfo lineInfo = dartEntry.getValue(SourceEntry.LINE_INFO); |  | 
| 4282     notice.setErrors(dartEntry.allErrors, lineInfo); |  | 
| 4283     return dartEntry; |  | 
| 4284   } |  | 
| 4285 |  | 
| 4286   /** |  | 
| 4287    * Record the results produced by performing a [task] and return the cache |  | 
| 4288    * entry associated with the results. |  | 
| 4289    */ |  | 
| 4290   DartEntry _recordGenerateDartHintsTask(GenerateDartHintsTask task) { |  | 
| 4291     Source librarySource = task.libraryElement.source; |  | 
| 4292     CaughtException thrownException = task.exception; |  | 
| 4293     DartEntry libraryEntry = null; |  | 
| 4294     HashMap<Source, List<AnalysisError>> hintMap = task.hintMap; |  | 
| 4295     if (hintMap == null) { |  | 
| 4296       // We don't have any information about which sources to mark as invalid |  | 
| 4297       // other than the library source. |  | 
| 4298       DartEntry libraryEntry = _cache.get(librarySource); |  | 
| 4299       if (thrownException == null) { |  | 
| 4300         String message = "GenerateDartHintsTask returned a null hint map " |  | 
| 4301             "without throwing an exception: ${librarySource.fullName}"; |  | 
| 4302         thrownException = |  | 
| 4303             new CaughtException(new AnalysisException(message), null); |  | 
| 4304       } |  | 
| 4305       libraryEntry.recordHintErrorInLibrary(librarySource, thrownException); |  | 
| 4306       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 4307     } |  | 
| 4308     hintMap.forEach((Source unitSource, List<AnalysisError> hints) { |  | 
| 4309       DartEntry dartEntry = _cache.get(unitSource); |  | 
| 4310       if (unitSource == librarySource) { |  | 
| 4311         libraryEntry = dartEntry; |  | 
| 4312       } |  | 
| 4313       if (thrownException == null) { |  | 
| 4314         dartEntry.setValueInLibrary(DartEntry.HINTS, librarySource, hints); |  | 
| 4315         ChangeNoticeImpl notice = getNotice(unitSource); |  | 
| 4316         LineInfo lineInfo = dartEntry.getValue(SourceEntry.LINE_INFO); |  | 
| 4317         notice.setErrors(dartEntry.allErrors, lineInfo); |  | 
| 4318       } else { |  | 
| 4319         dartEntry.recordHintErrorInLibrary(librarySource, thrownException); |  | 
| 4320       } |  | 
| 4321     }); |  | 
| 4322     if (thrownException != null) { |  | 
| 4323       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 4324     } |  | 
| 4325     return libraryEntry; |  | 
| 4326   } |  | 
| 4327 |  | 
| 4328   /** |  | 
| 4329    * Record the results produced by performing a [task] and return the cache |  | 
| 4330    * entry associated with the results. |  | 
| 4331    */ |  | 
| 4332   DartEntry _recordGenerateDartLintsTask(GenerateDartLintsTask task) { |  | 
| 4333     Source librarySource = task.libraryElement.source; |  | 
| 4334     CaughtException thrownException = task.exception; |  | 
| 4335     DartEntry libraryEntry = null; |  | 
| 4336     HashMap<Source, List<AnalysisError>> lintMap = task.lintMap; |  | 
| 4337     if (lintMap == null) { |  | 
| 4338       // We don't have any information about which sources to mark as invalid |  | 
| 4339       // other than the library source. |  | 
| 4340       DartEntry libraryEntry = _cache.get(librarySource); |  | 
| 4341       if (thrownException == null) { |  | 
| 4342         String message = "GenerateDartLintsTask returned a null lint map " |  | 
| 4343             "without throwing an exception: ${librarySource.fullName}"; |  | 
| 4344         thrownException = |  | 
| 4345             new CaughtException(new AnalysisException(message), null); |  | 
| 4346       } |  | 
| 4347       libraryEntry.recordLintErrorInLibrary(librarySource, thrownException); |  | 
| 4348       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 4349     } |  | 
| 4350     lintMap.forEach((Source unitSource, List<AnalysisError> lints) { |  | 
| 4351       DartEntry dartEntry = _cache.get(unitSource); |  | 
| 4352       if (unitSource == librarySource) { |  | 
| 4353         libraryEntry = dartEntry; |  | 
| 4354       } |  | 
| 4355       if (thrownException == null) { |  | 
| 4356         dartEntry.setValueInLibrary(DartEntry.LINTS, librarySource, lints); |  | 
| 4357         ChangeNoticeImpl notice = getNotice(unitSource); |  | 
| 4358         LineInfo lineInfo = dartEntry.getValue(SourceEntry.LINE_INFO); |  | 
| 4359         notice.setErrors(dartEntry.allErrors, lineInfo); |  | 
| 4360       } else { |  | 
| 4361         dartEntry.recordLintErrorInLibrary(librarySource, thrownException); |  | 
| 4362       } |  | 
| 4363     }); |  | 
| 4364     if (thrownException != null) { |  | 
| 4365       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 4366     } |  | 
| 4367     return libraryEntry; |  | 
| 4368   } |  | 
| 4369 |  | 
| 4370   /** |  | 
| 4371    * Record the results produced by performing a [task] and return the cache |  | 
| 4372    * entry associated with the results. |  | 
| 4373    */ |  | 
| 4374   SourceEntry _recordGetContentsTask(GetContentTask task) { |  | 
| 4375     if (!task.isComplete) { |  | 
| 4376       return null; |  | 
| 4377     } |  | 
| 4378     Source source = task.source; |  | 
| 4379     SourceEntry sourceEntry = _cache.get(source); |  | 
| 4380     CaughtException thrownException = task.exception; |  | 
| 4381     if (thrownException != null) { |  | 
| 4382       sourceEntry.recordContentError(thrownException); |  | 
| 4383       { |  | 
| 4384         sourceEntry.setValue(SourceEntry.CONTENT_ERRORS, task.errors); |  | 
| 4385         ChangeNoticeImpl notice = getNotice(source); |  | 
| 4386         notice.setErrors(sourceEntry.allErrors, null); |  | 
| 4387       } |  | 
| 4388       _workManager.remove(source); |  | 
| 4389       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 4390     } |  | 
| 4391     sourceEntry.modificationTime = task.modificationTime; |  | 
| 4392     sourceEntry.setValue(SourceEntry.CONTENT, task.content); |  | 
| 4393     return sourceEntry; |  | 
| 4394   } |  | 
| 4395 |  | 
| 4396   /** |  | 
| 4397    * Record the results produced by performing a [task] and return the cache |  | 
| 4398    * entry associated with the results. |  | 
| 4399    */ |  | 
| 4400   DartEntry _recordIncrementalAnalysisTaskResults( |  | 
| 4401       IncrementalAnalysisTask task) { |  | 
| 4402     CompilationUnit unit = task.compilationUnit; |  | 
| 4403     if (unit != null) { |  | 
| 4404       ChangeNoticeImpl notice = getNotice(task.source); |  | 
| 4405       notice.resolvedDartUnit = unit; |  | 
| 4406       _incrementalAnalysisCache = |  | 
| 4407           IncrementalAnalysisCache.cacheResult(task.cache, unit); |  | 
| 4408     } |  | 
| 4409     return null; |  | 
| 4410   } |  | 
| 4411 |  | 
| 4412   /** |  | 
| 4413    * Record the results produced by performing a [task] and return the cache |  | 
| 4414    * entry associated with the results. |  | 
| 4415    */ |  | 
| 4416   DartEntry _recordParseDartTaskResults(ParseDartTask task) { |  | 
| 4417     Source source = task.source; |  | 
| 4418     DartEntry dartEntry = _cache.get(source); |  | 
| 4419     _removeFromParts(source, dartEntry); |  | 
| 4420     CaughtException thrownException = task.exception; |  | 
| 4421     if (thrownException != null) { |  | 
| 4422       _removeFromParts(source, dartEntry); |  | 
| 4423       dartEntry.recordParseError(thrownException); |  | 
| 4424       _cache.removedAst(source); |  | 
| 4425       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 4426     } |  | 
| 4427     if (task.hasNonPartOfDirective) { |  | 
| 4428       dartEntry.setValue(DartEntry.SOURCE_KIND, SourceKind.LIBRARY); |  | 
| 4429       dartEntry.containingLibrary = source; |  | 
| 4430       _workManager.add(source, SourcePriority.LIBRARY); |  | 
| 4431     } else if (task.hasPartOfDirective) { |  | 
| 4432       dartEntry.setValue(DartEntry.SOURCE_KIND, SourceKind.PART); |  | 
| 4433       dartEntry.removeContainingLibrary(source); |  | 
| 4434       _workManager.add(source, SourcePriority.NORMAL_PART); |  | 
| 4435     } else { |  | 
| 4436       // The file contains no directives. |  | 
| 4437       List<Source> containingLibraries = dartEntry.containingLibraries; |  | 
| 4438       if (containingLibraries.length > 1 || |  | 
| 4439           (containingLibraries.length == 1 && |  | 
| 4440               containingLibraries[0] != source)) { |  | 
| 4441         dartEntry.setValue(DartEntry.SOURCE_KIND, SourceKind.PART); |  | 
| 4442         dartEntry.removeContainingLibrary(source); |  | 
| 4443         _workManager.add(source, SourcePriority.NORMAL_PART); |  | 
| 4444       } else { |  | 
| 4445         dartEntry.setValue(DartEntry.SOURCE_KIND, SourceKind.LIBRARY); |  | 
| 4446         dartEntry.containingLibrary = source; |  | 
| 4447         _workManager.add(source, SourcePriority.LIBRARY); |  | 
| 4448       } |  | 
| 4449     } |  | 
| 4450     List<Source> newParts = task.includedSources; |  | 
| 4451     for (int i = 0; i < newParts.length; i++) { |  | 
| 4452       Source partSource = newParts[i]; |  | 
| 4453       DartEntry partEntry = _getReadableDartEntry(partSource); |  | 
| 4454       if (partEntry != null && !identical(partEntry, dartEntry)) { |  | 
| 4455         // TODO(brianwilkerson) Change the kind of the "part" if it was marked |  | 
| 4456         // as a library and it has no directives. |  | 
| 4457         partEntry.addContainingLibrary(source); |  | 
| 4458       } |  | 
| 4459     } |  | 
| 4460     dartEntry.setValue(DartEntry.PARSED_UNIT, task.compilationUnit); |  | 
| 4461     dartEntry.setValue(DartEntry.PARSE_ERRORS, task.errors); |  | 
| 4462     dartEntry.setValue(DartEntry.EXPORTED_LIBRARIES, task.exportedSources); |  | 
| 4463     dartEntry.setValue(DartEntry.IMPORTED_LIBRARIES, task.importedSources); |  | 
| 4464     dartEntry.setValue(DartEntry.INCLUDED_PARTS, newParts); |  | 
| 4465     _cache.storedAst(source); |  | 
| 4466     ChangeNoticeImpl notice = getNotice(source); |  | 
| 4467     if (notice.resolvedDartUnit == null) { |  | 
| 4468       notice.parsedDartUnit = task.compilationUnit; |  | 
| 4469     } |  | 
| 4470     notice.setErrors(dartEntry.allErrors, task.lineInfo); |  | 
| 4471     // Verify that the incrementally parsed and resolved unit in the incremental |  | 
| 4472     // cache is structurally equivalent to the fully parsed unit |  | 
| 4473     _incrementalAnalysisCache = IncrementalAnalysisCache.verifyStructure( |  | 
| 4474         _incrementalAnalysisCache, source, task.compilationUnit); |  | 
| 4475     return dartEntry; |  | 
| 4476   } |  | 
| 4477 |  | 
| 4478   /** |  | 
| 4479    * Record the results produced by performing a [task] and return the cache |  | 
| 4480    * entry associated with the results. |  | 
| 4481    */ |  | 
| 4482   HtmlEntry _recordParseHtmlTaskResults(ParseHtmlTask task) { |  | 
| 4483     Source source = task.source; |  | 
| 4484     HtmlEntry htmlEntry = _cache.get(source); |  | 
| 4485     CaughtException thrownException = task.exception; |  | 
| 4486     if (thrownException != null) { |  | 
| 4487       htmlEntry.recordParseError(thrownException); |  | 
| 4488       _cache.removedAst(source); |  | 
| 4489       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 4490     } |  | 
| 4491     LineInfo lineInfo = task.lineInfo; |  | 
| 4492     htmlEntry.setValue(SourceEntry.LINE_INFO, lineInfo); |  | 
| 4493     htmlEntry.setValue(HtmlEntry.PARSED_UNIT, task.htmlUnit); |  | 
| 4494     htmlEntry.setValue(HtmlEntry.PARSE_ERRORS, task.errors); |  | 
| 4495     htmlEntry.setValue( |  | 
| 4496         HtmlEntry.REFERENCED_LIBRARIES, task.referencedLibraries); |  | 
| 4497     _cache.storedAst(source); |  | 
| 4498     ChangeNoticeImpl notice = getNotice(source); |  | 
| 4499     notice.setErrors(htmlEntry.allErrors, lineInfo); |  | 
| 4500     return htmlEntry; |  | 
| 4501   } |  | 
| 4502 |  | 
| 4503   /** |  | 
| 4504    * Record the results produced by performing a [task] and return the cache |  | 
| 4505    * entry associated with the results. |  | 
| 4506    */ |  | 
| 4507   DartEntry _recordResolveDartUnitTaskResults(ResolveDartUnitTask task) { |  | 
| 4508     Source unitSource = task.source; |  | 
| 4509     DartEntry dartEntry = _cache.get(unitSource); |  | 
| 4510     Source librarySource = task.librarySource; |  | 
| 4511     CaughtException thrownException = task.exception; |  | 
| 4512     if (thrownException != null) { |  | 
| 4513       dartEntry.recordResolutionErrorInLibrary(librarySource, thrownException); |  | 
| 4514       _cache.removedAst(unitSource); |  | 
| 4515       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 4516     } |  | 
| 4517     dartEntry.setValueInLibrary( |  | 
| 4518         DartEntry.RESOLVED_UNIT, librarySource, task.resolvedUnit); |  | 
| 4519     _cache.storedAst(unitSource); |  | 
| 4520     return dartEntry; |  | 
| 4521   } |  | 
| 4522 |  | 
| 4523   /** |  | 
| 4524    * Record the results produced by performing a [task] and return the cache |  | 
| 4525    * entry associated with the results. |  | 
| 4526    */ |  | 
| 4527   HtmlEntry _recordResolveHtmlTaskResults(ResolveHtmlTask task) { |  | 
| 4528     Source source = task.source; |  | 
| 4529     HtmlEntry htmlEntry = _cache.get(source); |  | 
| 4530     CaughtException thrownException = task.exception; |  | 
| 4531     if (thrownException != null) { |  | 
| 4532       htmlEntry.recordResolutionError(thrownException); |  | 
| 4533       _cache.removedAst(source); |  | 
| 4534       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 4535     } |  | 
| 4536     htmlEntry.setState(HtmlEntry.PARSED_UNIT, CacheState.FLUSHED); |  | 
| 4537     htmlEntry.setValue(HtmlEntry.RESOLVED_UNIT, task.resolvedUnit); |  | 
| 4538     htmlEntry.setValue(HtmlEntry.ELEMENT, task.element); |  | 
| 4539     htmlEntry.setValue(HtmlEntry.RESOLUTION_ERRORS, task.resolutionErrors); |  | 
| 4540     _cache.storedAst(source); |  | 
| 4541     ChangeNoticeImpl notice = getNotice(source); |  | 
| 4542     notice.resolvedHtmlUnit = task.resolvedUnit; |  | 
| 4543     LineInfo lineInfo = htmlEntry.getValue(SourceEntry.LINE_INFO); |  | 
| 4544     notice.setErrors(htmlEntry.allErrors, lineInfo); |  | 
| 4545     return htmlEntry; |  | 
| 4546   } |  | 
| 4547 |  | 
| 4548   /** |  | 
| 4549    * Record the results produced by performing a [task] and return the cache |  | 
| 4550    * entry associated with the results. |  | 
| 4551    */ |  | 
| 4552   DartEntry _recordScanDartTaskResults(ScanDartTask task) { |  | 
| 4553     Source source = task.source; |  | 
| 4554     DartEntry dartEntry = _cache.get(source); |  | 
| 4555     CaughtException thrownException = task.exception; |  | 
| 4556     if (thrownException != null) { |  | 
| 4557       _removeFromParts(source, dartEntry); |  | 
| 4558       dartEntry.recordScanError(thrownException); |  | 
| 4559       _cache.removedAst(source); |  | 
| 4560       throw new AnalysisException('<rethrow>', thrownException); |  | 
| 4561     } |  | 
| 4562     LineInfo lineInfo = task.lineInfo; |  | 
| 4563     dartEntry.setValue(SourceEntry.LINE_INFO, lineInfo); |  | 
| 4564     dartEntry.setValue(DartEntry.TOKEN_STREAM, task.tokenStream); |  | 
| 4565     dartEntry.setValue(DartEntry.SCAN_ERRORS, task.errors); |  | 
| 4566     _cache.storedAst(source); |  | 
| 4567     ChangeNoticeImpl notice = getNotice(source); |  | 
| 4568     notice.setErrors(dartEntry.allErrors, lineInfo); |  | 
| 4569     return dartEntry; |  | 
| 4570   } |  | 
| 4571 |  | 
| 4572   /** |  | 
| 4573    * Remove the given [librarySource] from the list of containing libraries for |  | 
| 4574    * all of the parts referenced by the given [dartEntry]. |  | 
| 4575    */ |  | 
| 4576   void _removeFromParts(Source librarySource, DartEntry dartEntry) { |  | 
| 4577     List<Source> oldParts = dartEntry.getValue(DartEntry.INCLUDED_PARTS); |  | 
| 4578     for (int i = 0; i < oldParts.length; i++) { |  | 
| 4579       Source partSource = oldParts[i]; |  | 
| 4580       DartEntry partEntry = _getReadableDartEntry(partSource); |  | 
| 4581       if (partEntry != null && !identical(partEntry, dartEntry)) { |  | 
| 4582         partEntry.removeContainingLibrary(librarySource); |  | 
| 4583         if (partEntry.containingLibraries.length == 0 && !exists(partSource)) { |  | 
| 4584           _cache.remove(partSource); |  | 
| 4585         } |  | 
| 4586       } |  | 
| 4587     } |  | 
| 4588   } |  | 
| 4589 |  | 
| 4590   /** |  | 
| 4591    * Remove the given libraries that are keys in the given map from the list of |  | 
| 4592    * containing libraries for each of the parts in the corresponding value. |  | 
| 4593    */ |  | 
| 4594   void _removeFromPartsUsingMap(HashMap<Source, List<Source>> oldPartMap) { |  | 
| 4595     oldPartMap.forEach((Source librarySource, List<Source> oldParts) { |  | 
| 4596       for (int i = 0; i < oldParts.length; i++) { |  | 
| 4597         Source partSource = oldParts[i]; |  | 
| 4598         if (partSource != librarySource) { |  | 
| 4599           DartEntry partEntry = _getReadableDartEntry(partSource); |  | 
| 4600           if (partEntry != null) { |  | 
| 4601             partEntry.removeContainingLibrary(librarySource); |  | 
| 4602             if (partEntry.containingLibraries.length == 0 && |  | 
| 4603                 !exists(partSource)) { |  | 
| 4604               _cache.remove(partSource); |  | 
| 4605             } |  | 
| 4606           } |  | 
| 4607         } |  | 
| 4608       } |  | 
| 4609     }); |  | 
| 4610   } |  | 
| 4611 |  | 
| 4612   /** |  | 
| 4613    * Remove the given [source] from the priority order if it is in the list. |  | 
| 4614    */ |  | 
| 4615   void _removeFromPriorityOrder(Source source) { |  | 
| 4616     int count = _priorityOrder.length; |  | 
| 4617     List<Source> newOrder = new List<Source>(); |  | 
| 4618     for (int i = 0; i < count; i++) { |  | 
| 4619       if (_priorityOrder[i] != source) { |  | 
| 4620         newOrder.add(_priorityOrder[i]); |  | 
| 4621       } |  | 
| 4622     } |  | 
| 4623     if (newOrder.length < count) { |  | 
| 4624       analysisPriorityOrder = newOrder; |  | 
| 4625     } |  | 
| 4626   } |  | 
| 4627 |  | 
| 4628   /** |  | 
| 4629    * Create an entry for the newly added [source] and invalidate any sources |  | 
| 4630    * that referenced the source before it existed. |  | 
| 4631    */ |  | 
| 4632   void _sourceAvailable(Source source) { |  | 
| 4633     SourceEntry sourceEntry = _cache.get(source); |  | 
| 4634     if (sourceEntry == null) { |  | 
| 4635       sourceEntry = _createSourceEntry(source, true); |  | 
| 4636     } else { |  | 
| 4637       _propagateInvalidation(source, sourceEntry); |  | 
| 4638       sourceEntry = _cache.get(source); |  | 
| 4639     } |  | 
| 4640     if (sourceEntry is HtmlEntry) { |  | 
| 4641       _workManager.add(source, SourcePriority.HTML); |  | 
| 4642     } else if (sourceEntry is DartEntry) { |  | 
| 4643       _workManager.add(source, _computePriority(sourceEntry)); |  | 
| 4644     } |  | 
| 4645   } |  | 
| 4646 |  | 
| 4647   /** |  | 
| 4648    * Invalidate the [source] that was changed and any sources that referenced |  | 
| 4649    * the source before it existed. |  | 
| 4650    */ |  | 
| 4651   void _sourceChanged(Source source) { |  | 
| 4652     SourceEntry sourceEntry = _cache.get(source); |  | 
| 4653     // If the source is removed, we don't care about it. |  | 
| 4654     if (sourceEntry == null) { |  | 
| 4655       return; |  | 
| 4656     } |  | 
| 4657     // Check if the content of the source is the same as it was the last time. |  | 
| 4658     String sourceContent = sourceEntry.getValue(SourceEntry.CONTENT); |  | 
| 4659     if (sourceContent != null) { |  | 
| 4660       sourceEntry.setState(SourceEntry.CONTENT, CacheState.FLUSHED); |  | 
| 4661       try { |  | 
| 4662         TimestampedData<String> fileContents = getContents(source); |  | 
| 4663         if (fileContents.data == sourceContent) { |  | 
| 4664           return; |  | 
| 4665         } |  | 
| 4666       } catch (e) {} |  | 
| 4667     } |  | 
| 4668     // We have to invalidate the cache. |  | 
| 4669     _propagateInvalidation(source, sourceEntry); |  | 
| 4670   } |  | 
| 4671 |  | 
| 4672   /** |  | 
| 4673    * Record that the give [source] has been deleted. |  | 
| 4674    */ |  | 
| 4675   void _sourceDeleted(Source source) { |  | 
| 4676     SourceEntry sourceEntry = _cache.get(source); |  | 
| 4677     if (sourceEntry is HtmlEntry) { |  | 
| 4678       HtmlEntry htmlEntry = sourceEntry; |  | 
| 4679       htmlEntry.recordContentError(new CaughtException( |  | 
| 4680           new AnalysisException("This source was marked as being deleted"), |  | 
| 4681           null)); |  | 
| 4682     } else if (sourceEntry is DartEntry) { |  | 
| 4683       DartEntry dartEntry = sourceEntry; |  | 
| 4684       HashSet<Source> libraries = new HashSet<Source>(); |  | 
| 4685       for (Source librarySource in getLibrariesContaining(source)) { |  | 
| 4686         libraries.add(librarySource); |  | 
| 4687         for (Source dependentLibrary |  | 
| 4688             in getLibrariesDependingOn(librarySource)) { |  | 
| 4689           libraries.add(dependentLibrary); |  | 
| 4690         } |  | 
| 4691       } |  | 
| 4692       for (Source librarySource in libraries) { |  | 
| 4693         _invalidateLibraryResolution(librarySource); |  | 
| 4694       } |  | 
| 4695       dartEntry.recordContentError(new CaughtException( |  | 
| 4696           new AnalysisException("This source was marked as being deleted"), |  | 
| 4697           null)); |  | 
| 4698     } |  | 
| 4699     _workManager.remove(source); |  | 
| 4700     _removeFromPriorityOrder(source); |  | 
| 4701   } |  | 
| 4702 |  | 
| 4703   /** |  | 
| 4704    * Record that the given [source] has been removed. |  | 
| 4705    */ |  | 
| 4706   void _sourceRemoved(Source source) { |  | 
| 4707     SourceEntry sourceEntry = _cache.get(source); |  | 
| 4708     if (sourceEntry is HtmlEntry) {} else if (sourceEntry is DartEntry) { |  | 
| 4709       HashSet<Source> libraries = new HashSet<Source>(); |  | 
| 4710       for (Source librarySource in getLibrariesContaining(source)) { |  | 
| 4711         libraries.add(librarySource); |  | 
| 4712         for (Source dependentLibrary |  | 
| 4713             in getLibrariesDependingOn(librarySource)) { |  | 
| 4714           libraries.add(dependentLibrary); |  | 
| 4715         } |  | 
| 4716       } |  | 
| 4717       for (Source librarySource in libraries) { |  | 
| 4718         _invalidateLibraryResolution(librarySource); |  | 
| 4719       } |  | 
| 4720     } |  | 
| 4721     _cache.remove(source); |  | 
| 4722     _workManager.remove(source); |  | 
| 4723     _removeFromPriorityOrder(source); |  | 
| 4724   } |  | 
| 4725 |  | 
| 4726   /** |  | 
| 4727    * TODO(scheglov) A hackish, limited incremental resolution implementation. |  | 
| 4728    */ |  | 
| 4729   bool _tryPoorMansIncrementalResolution(Source unitSource, String newCode) { |  | 
| 4730     return PerformanceStatistics.incrementalAnalysis.makeCurrentWhile(() { |  | 
| 4731       incrementalResolutionValidation_lastUnitSource = null; |  | 
| 4732       incrementalResolutionValidation_lastLibrarySource = null; |  | 
| 4733       incrementalResolutionValidation_lastUnit = null; |  | 
| 4734       // prepare the entry |  | 
| 4735       DartEntry dartEntry = _cache.get(unitSource); |  | 
| 4736       if (dartEntry == null) { |  | 
| 4737         return false; |  | 
| 4738       } |  | 
| 4739       // prepare the (only) library source |  | 
| 4740       List<Source> librarySources = getLibrariesContaining(unitSource); |  | 
| 4741       if (librarySources.length != 1) { |  | 
| 4742         return false; |  | 
| 4743       } |  | 
| 4744       Source librarySource = librarySources[0]; |  | 
| 4745       // prepare the library element |  | 
| 4746       LibraryElement libraryElement = getLibraryElement(librarySource); |  | 
| 4747       if (libraryElement == null) { |  | 
| 4748         return false; |  | 
| 4749       } |  | 
| 4750       // prepare the existing unit |  | 
| 4751       CompilationUnit oldUnit = |  | 
| 4752           getResolvedCompilationUnit2(unitSource, librarySource); |  | 
| 4753       if (oldUnit == null) { |  | 
| 4754         return false; |  | 
| 4755       } |  | 
| 4756       // do resolution |  | 
| 4757       Stopwatch perfCounter = new Stopwatch()..start(); |  | 
| 4758       PoorMansIncrementalResolver resolver = new PoorMansIncrementalResolver( |  | 
| 4759           typeProvider, unitSource, getReadableSourceEntryOrNull(unitSource), |  | 
| 4760           null, null, oldUnit, analysisOptions.incrementalApi, analysisOptions); |  | 
| 4761       bool success = resolver.resolve(newCode); |  | 
| 4762       AnalysisEngine.instance.instrumentationService.logPerformance( |  | 
| 4763           AnalysisPerformanceKind.INCREMENTAL, perfCounter, |  | 
| 4764           'success=$success,context_id=$_id,code_length=${newCode.length}'); |  | 
| 4765       if (!success) { |  | 
| 4766         return false; |  | 
| 4767       } |  | 
| 4768       // if validation, remember the result, but throw it away |  | 
| 4769       if (analysisOptions.incrementalValidation) { |  | 
| 4770         incrementalResolutionValidation_lastUnitSource = oldUnit.element.source; |  | 
| 4771         incrementalResolutionValidation_lastLibrarySource = |  | 
| 4772             oldUnit.element.library.source; |  | 
| 4773         incrementalResolutionValidation_lastUnit = oldUnit; |  | 
| 4774         return false; |  | 
| 4775       } |  | 
| 4776       // prepare notice |  | 
| 4777       { |  | 
| 4778         LineInfo lineInfo = getLineInfo(unitSource); |  | 
| 4779         ChangeNoticeImpl notice = getNotice(unitSource); |  | 
| 4780         notice.resolvedDartUnit = oldUnit; |  | 
| 4781         notice.setErrors(dartEntry.allErrors, lineInfo); |  | 
| 4782       } |  | 
| 4783       // OK |  | 
| 4784       return true; |  | 
| 4785     }); |  | 
| 4786   } |  | 
| 4787 |  | 
| 4788   void _validateLastIncrementalResolutionResult() { |  | 
| 4789     if (incrementalResolutionValidation_lastUnitSource == null || |  | 
| 4790         incrementalResolutionValidation_lastLibrarySource == null || |  | 
| 4791         incrementalResolutionValidation_lastUnit == null) { |  | 
| 4792       return; |  | 
| 4793     } |  | 
| 4794     CompilationUnit fullUnit = getResolvedCompilationUnit2( |  | 
| 4795         incrementalResolutionValidation_lastUnitSource, |  | 
| 4796         incrementalResolutionValidation_lastLibrarySource); |  | 
| 4797     if (fullUnit != null) { |  | 
| 4798       try { |  | 
| 4799         assertSameResolution( |  | 
| 4800             incrementalResolutionValidation_lastUnit, fullUnit); |  | 
| 4801       } on IncrementalResolutionMismatch catch (mismatch, stack) { |  | 
| 4802         String failure = mismatch.message; |  | 
| 4803         String message = |  | 
| 4804             'Incremental resolution mismatch:\n$failure\nat\n$stack'; |  | 
| 4805         AnalysisEngine.instance.logger.logError(message); |  | 
| 4806       } |  | 
| 4807     } |  | 
| 4808     incrementalResolutionValidation_lastUnitSource = null; |  | 
| 4809     incrementalResolutionValidation_lastLibrarySource = null; |  | 
| 4810     incrementalResolutionValidation_lastUnit = null; |  | 
| 4811   } |  | 
| 4812 } |  | 
| 4813 |  | 
| 4814 /** |  | 
| 4815  * An object used by an analysis context to record the results of a task. |  | 
| 4816  */ |  | 
| 4817 class AnalysisContextImpl_AnalysisTaskResultRecorder |  | 
| 4818     implements AnalysisTaskVisitor<SourceEntry> { |  | 
| 4819   final AnalysisContextImpl AnalysisContextImpl_this; |  | 
| 4820 |  | 
| 4821   AnalysisContextImpl_AnalysisTaskResultRecorder(this.AnalysisContextImpl_this); |  | 
| 4822 |  | 
| 4823   @override |  | 
| 4824   DartEntry visitGenerateDartErrorsTask(GenerateDartErrorsTask task) => |  | 
| 4825       AnalysisContextImpl_this._recordGenerateDartErrorsTask(task); |  | 
| 4826 |  | 
| 4827   @override |  | 
| 4828   DartEntry visitGenerateDartHintsTask(GenerateDartHintsTask task) => |  | 
| 4829       AnalysisContextImpl_this._recordGenerateDartHintsTask(task); |  | 
| 4830 |  | 
| 4831   @override |  | 
| 4832   DartEntry visitGenerateDartLintsTask(GenerateDartLintsTask task) => |  | 
| 4833       AnalysisContextImpl_this._recordGenerateDartLintsTask(task); |  | 
| 4834 |  | 
| 4835   @override |  | 
| 4836   SourceEntry visitGetContentTask(GetContentTask task) => |  | 
| 4837       AnalysisContextImpl_this._recordGetContentsTask(task); |  | 
| 4838 |  | 
| 4839   @override |  | 
| 4840   DartEntry visitIncrementalAnalysisTask(IncrementalAnalysisTask task) => |  | 
| 4841       AnalysisContextImpl_this._recordIncrementalAnalysisTaskResults(task); |  | 
| 4842 |  | 
| 4843   @override |  | 
| 4844   DartEntry visitParseDartTask(ParseDartTask task) => |  | 
| 4845       AnalysisContextImpl_this._recordParseDartTaskResults(task); |  | 
| 4846 |  | 
| 4847   @override |  | 
| 4848   HtmlEntry visitParseHtmlTask(ParseHtmlTask task) => |  | 
| 4849       AnalysisContextImpl_this._recordParseHtmlTaskResults(task); |  | 
| 4850 |  | 
| 4851   @override |  | 
| 4852   DartEntry visitResolveDartLibraryCycleTask( |  | 
| 4853           ResolveDartLibraryCycleTask task) => |  | 
| 4854       AnalysisContextImpl_this.recordResolveDartLibraryCycleTaskResults(task); |  | 
| 4855 |  | 
| 4856   @override |  | 
| 4857   DartEntry visitResolveDartLibraryTask(ResolveDartLibraryTask task) => |  | 
| 4858       AnalysisContextImpl_this.recordResolveDartLibraryTaskResults(task); |  | 
| 4859 |  | 
| 4860   @override |  | 
| 4861   DartEntry visitResolveDartUnitTask(ResolveDartUnitTask task) => |  | 
| 4862       AnalysisContextImpl_this._recordResolveDartUnitTaskResults(task); |  | 
| 4863 |  | 
| 4864   @override |  | 
| 4865   HtmlEntry visitResolveHtmlTask(ResolveHtmlTask task) => |  | 
| 4866       AnalysisContextImpl_this._recordResolveHtmlTaskResults(task); |  | 
| 4867 |  | 
| 4868   @override |  | 
| 4869   DartEntry visitScanDartTask(ScanDartTask task) => |  | 
| 4870       AnalysisContextImpl_this._recordScanDartTaskResults(task); |  | 
| 4871 } |  | 
| 4872 |  | 
| 4873 class AnalysisContextImpl_ContextRetentionPolicy |  | 
| 4874     implements CacheRetentionPolicy { |  | 
| 4875   final AnalysisContextImpl AnalysisContextImpl_this; |  | 
| 4876 |  | 
| 4877   AnalysisContextImpl_ContextRetentionPolicy(this.AnalysisContextImpl_this); |  | 
| 4878 |  | 
| 4879   @override |  | 
| 4880   RetentionPriority getAstPriority(Source source, SourceEntry sourceEntry) { |  | 
| 4881     int priorityCount = AnalysisContextImpl_this._priorityOrder.length; |  | 
| 4882     for (int i = 0; i < priorityCount; i++) { |  | 
| 4883       if (source == AnalysisContextImpl_this._priorityOrder[i]) { |  | 
| 4884         return RetentionPriority.HIGH; |  | 
| 4885       } |  | 
| 4886     } |  | 
| 4887     if (AnalysisContextImpl_this._neededForResolution != null && |  | 
| 4888         AnalysisContextImpl_this._neededForResolution.contains(source)) { |  | 
| 4889       return RetentionPriority.HIGH; |  | 
| 4890     } |  | 
| 4891     if (sourceEntry is DartEntry) { |  | 
| 4892       DartEntry dartEntry = sourceEntry; |  | 
| 4893       if (_astIsNeeded(dartEntry)) { |  | 
| 4894         return RetentionPriority.MEDIUM; |  | 
| 4895       } |  | 
| 4896     } |  | 
| 4897     return RetentionPriority.LOW; |  | 
| 4898   } |  | 
| 4899 |  | 
| 4900   bool _astIsNeeded(DartEntry dartEntry) => |  | 
| 4901       dartEntry.hasInvalidData(DartEntry.HINTS) || |  | 
| 4902           dartEntry.hasInvalidData(DartEntry.LINTS) || |  | 
| 4903           dartEntry.hasInvalidData(DartEntry.VERIFICATION_ERRORS) || |  | 
| 4904           dartEntry.hasInvalidData(DartEntry.RESOLUTION_ERRORS); |  | 
| 4905 } |  | 
| 4906 |  | 
| 4907 /** |  | 
| 4908  * An object used to construct a list of the libraries that must be resolved |  | 
| 4909  * together in order to resolve any one of the libraries. |  | 
| 4910  */ |  | 
| 4911 class AnalysisContextImpl_CycleBuilder { |  | 
| 4912   final AnalysisContextImpl AnalysisContextImpl_this; |  | 
| 4913 |  | 
| 4914   /** |  | 
| 4915    * A table mapping the sources of the defining compilation units of libraries |  | 
| 4916    * to the representation of the library that has the information needed to |  | 
| 4917    * resolve the library. |  | 
| 4918    */ |  | 
| 4919   HashMap<Source, ResolvableLibrary> _libraryMap = |  | 
| 4920       new HashMap<Source, ResolvableLibrary>(); |  | 
| 4921 |  | 
| 4922   /** |  | 
| 4923    * The dependency graph used to compute the libraries in the cycle. |  | 
| 4924    */ |  | 
| 4925   DirectedGraph<ResolvableLibrary> _dependencyGraph; |  | 
| 4926 |  | 
| 4927   /** |  | 
| 4928    * A list containing the libraries that are ready to be resolved. |  | 
| 4929    */ |  | 
| 4930   List<ResolvableLibrary> _librariesInCycle; |  | 
| 4931 |  | 
| 4932   /** |  | 
| 4933    * The analysis task that needs to be performed before the cycle of libraries |  | 
| 4934    * can be resolved, or `null` if the libraries are ready to be resolved. |  | 
| 4935    */ |  | 
| 4936   AnalysisContextImpl_TaskData _taskData; |  | 
| 4937 |  | 
| 4938   /** |  | 
| 4939    * Initialize a newly created cycle builder. |  | 
| 4940    */ |  | 
| 4941   AnalysisContextImpl_CycleBuilder(this.AnalysisContextImpl_this) : super(); |  | 
| 4942 |  | 
| 4943   /** |  | 
| 4944    * Return a list containing the libraries that are ready to be resolved |  | 
| 4945    * (assuming that [getTaskData] returns `null`). |  | 
| 4946    */ |  | 
| 4947   List<ResolvableLibrary> get librariesInCycle => _librariesInCycle; |  | 
| 4948 |  | 
| 4949   /** |  | 
| 4950    * Return a representation of an analysis task that needs to be performed |  | 
| 4951    * before the cycle of libraries can be resolved, or `null` if the libraries |  | 
| 4952    * are ready to be resolved. |  | 
| 4953    */ |  | 
| 4954   AnalysisContextImpl_TaskData get taskData => _taskData; |  | 
| 4955 |  | 
| 4956   /** |  | 
| 4957    * Compute a list of the libraries that need to be resolved together in orde |  | 
| 4958    *  to resolve the given [librarySource]. |  | 
| 4959    */ |  | 
| 4960   void computeCycleContaining(Source librarySource) { |  | 
| 4961     // |  | 
| 4962     // Create the object representing the library being resolved. |  | 
| 4963     // |  | 
| 4964     ResolvableLibrary targetLibrary = _createLibrary(librarySource); |  | 
| 4965     // |  | 
| 4966     // Compute the set of libraries that need to be resolved together. |  | 
| 4967     // |  | 
| 4968     _dependencyGraph = new DirectedGraph<ResolvableLibrary>(); |  | 
| 4969     _computeLibraryDependencies(targetLibrary); |  | 
| 4970     if (_taskData != null) { |  | 
| 4971       return; |  | 
| 4972     } |  | 
| 4973     _librariesInCycle = _dependencyGraph.findCycleContaining(targetLibrary); |  | 
| 4974     // |  | 
| 4975     // Ensure that all of the data needed to resolve them has been computed. |  | 
| 4976     // |  | 
| 4977     _ensureImportsAndExports(); |  | 
| 4978     if (_taskData != null) { |  | 
| 4979       // At least one imported library needs to be resolved before the target |  | 
| 4980       // library. |  | 
| 4981       AnalysisTask task = _taskData.task; |  | 
| 4982       if (task is ResolveDartLibraryTask) { |  | 
| 4983         AnalysisContextImpl_this._workManager.addFirst( |  | 
| 4984             task.librarySource, SourcePriority.LIBRARY); |  | 
| 4985       } |  | 
| 4986       return; |  | 
| 4987     } |  | 
| 4988     _computePartsInCycle(librarySource); |  | 
| 4989     if (_taskData != null) { |  | 
| 4990       // At least one part needs to be parsed. |  | 
| 4991       return; |  | 
| 4992     } |  | 
| 4993     // All of the AST's necessary to perform a resolution of the library cycle |  | 
| 4994     // have been gathered, so it is no longer necessary to retain them in the |  | 
| 4995     // cache. |  | 
| 4996     AnalysisContextImpl_this._neededForResolution = null; |  | 
| 4997   } |  | 
| 4998 |  | 
| 4999   bool _addDependency(ResolvableLibrary dependant, Source dependency, |  | 
| 5000       List<ResolvableLibrary> dependencyList) { |  | 
| 5001     if (dependant.librarySource == dependency) { |  | 
| 5002       // Don't add a dependency of a library on itself; there's no point. |  | 
| 5003       return true; |  | 
| 5004     } |  | 
| 5005     ResolvableLibrary importedLibrary = _libraryMap[dependency]; |  | 
| 5006     if (importedLibrary == null) { |  | 
| 5007       importedLibrary = _createLibraryOrNull(dependency); |  | 
| 5008       if (importedLibrary != null) { |  | 
| 5009         _computeLibraryDependencies(importedLibrary); |  | 
| 5010         if (_taskData != null) { |  | 
| 5011           return false; |  | 
| 5012         } |  | 
| 5013       } |  | 
| 5014     } |  | 
| 5015     if (importedLibrary != null) { |  | 
| 5016       if (dependencyList != null) { |  | 
| 5017         dependencyList.add(importedLibrary); |  | 
| 5018       } |  | 
| 5019       _dependencyGraph.addEdge(dependant, importedLibrary); |  | 
| 5020     } |  | 
| 5021     return true; |  | 
| 5022   } |  | 
| 5023 |  | 
| 5024   /** |  | 
| 5025    * Recursively traverse the libraries reachable from the given [library], |  | 
| 5026    * creating instances of the class [Library] to represent them, and record the |  | 
| 5027    * references in the library objects. |  | 
| 5028    * |  | 
| 5029    * Throws an [AnalysisException] if some portion of the library graph could |  | 
| 5030    * not be traversed. |  | 
| 5031    */ |  | 
| 5032   void _computeLibraryDependencies(ResolvableLibrary library) { |  | 
| 5033     Source librarySource = library.librarySource; |  | 
| 5034     DartEntry dartEntry = |  | 
| 5035         AnalysisContextImpl_this._getReadableDartEntry(librarySource); |  | 
| 5036     List<Source> importedSources = |  | 
| 5037         _getSources(librarySource, dartEntry, DartEntry.IMPORTED_LIBRARIES); |  | 
| 5038     if (_taskData != null) { |  | 
| 5039       return; |  | 
| 5040     } |  | 
| 5041     List<Source> exportedSources = |  | 
| 5042         _getSources(librarySource, dartEntry, DartEntry.EXPORTED_LIBRARIES); |  | 
| 5043     if (_taskData != null) { |  | 
| 5044       return; |  | 
| 5045     } |  | 
| 5046     _computeLibraryDependenciesFromDirectives( |  | 
| 5047         library, importedSources, exportedSources); |  | 
| 5048   } |  | 
| 5049 |  | 
| 5050   /** |  | 
| 5051    * Recursively traverse the libraries reachable from the given [library], |  | 
| 5052    * creating instances of the class [Library] to represent them, and record the |  | 
| 5053    * references in the library objects. The [importedSources] is a list |  | 
| 5054    * containing the sources that are imported into the given library. The |  | 
| 5055    * [exportedSources] is a list containing the sources that are exported from |  | 
| 5056    * the given library. |  | 
| 5057    */ |  | 
| 5058   void _computeLibraryDependenciesFromDirectives(ResolvableLibrary library, |  | 
| 5059       List<Source> importedSources, List<Source> exportedSources) { |  | 
| 5060     int importCount = importedSources.length; |  | 
| 5061     List<ResolvableLibrary> importedLibraries = new List<ResolvableLibrary>(); |  | 
| 5062     bool explicitlyImportsCore = false; |  | 
| 5063     bool importsAsync = false; |  | 
| 5064     for (int i = 0; i < importCount; i++) { |  | 
| 5065       Source importedSource = importedSources[i]; |  | 
| 5066       if (importedSource == AnalysisContextImpl_this._coreLibrarySource) { |  | 
| 5067         explicitlyImportsCore = true; |  | 
| 5068       } else if (importedSource == |  | 
| 5069           AnalysisContextImpl_this._asyncLibrarySource) { |  | 
| 5070         importsAsync = true; |  | 
| 5071       } |  | 
| 5072       if (!_addDependency(library, importedSource, importedLibraries)) { |  | 
| 5073         return; |  | 
| 5074       } |  | 
| 5075     } |  | 
| 5076     library.explicitlyImportsCore = explicitlyImportsCore; |  | 
| 5077     if (!explicitlyImportsCore) { |  | 
| 5078       if (!_addDependency(library, AnalysisContextImpl_this._coreLibrarySource, |  | 
| 5079           importedLibraries)) { |  | 
| 5080         return; |  | 
| 5081       } |  | 
| 5082     } |  | 
| 5083     if (!importsAsync) { |  | 
| 5084       // Add a dependency on async to ensure that the Future element will be |  | 
| 5085       // built before we generate errors and warnings for async methods.  Also |  | 
| 5086       // include it in importedLibraries, so that it will be picked up by |  | 
| 5087       // LibraryResolver2._buildLibraryMap(). |  | 
| 5088       // TODO(paulberry): this is a bit of a hack, since the async library |  | 
| 5089       // isn't actually being imported.  Also, it's not clear whether it should |  | 
| 5090       // be necessary: in theory, dart:core already (indirectly) imports |  | 
| 5091       // dart:async, so if core has been built, async should have been built |  | 
| 5092       // too.  However, removing this code causes unit test failures. |  | 
| 5093       if (!_addDependency(library, AnalysisContextImpl_this._asyncLibrarySource, |  | 
| 5094           importedLibraries)) { |  | 
| 5095         return; |  | 
| 5096       } |  | 
| 5097     } |  | 
| 5098     library.importedLibraries = importedLibraries; |  | 
| 5099     int exportCount = exportedSources.length; |  | 
| 5100     if (exportCount > 0) { |  | 
| 5101       List<ResolvableLibrary> exportedLibraries = new List<ResolvableLibrary>(); |  | 
| 5102       for (int i = 0; i < exportCount; i++) { |  | 
| 5103         Source exportedSource = exportedSources[i]; |  | 
| 5104         if (!_addDependency(library, exportedSource, exportedLibraries)) { |  | 
| 5105           return; |  | 
| 5106         } |  | 
| 5107       } |  | 
| 5108       library.exportedLibraries = exportedLibraries; |  | 
| 5109     } |  | 
| 5110   } |  | 
| 5111 |  | 
| 5112   /** |  | 
| 5113    * Gather the resolvable AST structures for each of the compilation units in |  | 
| 5114    * each of the libraries in the cycle. This is done in two phases: first we |  | 
| 5115    * ensure that we have cached an AST structure for each compilation unit, then |  | 
| 5116    * we gather them. We split the work this way because getting the AST |  | 
| 5117    * structures can change the state of the cache in such a way that we would |  | 
| 5118    * have more work to do if any compilation unit didn't have a resolvable AST |  | 
| 5119    * structure. |  | 
| 5120    */ |  | 
| 5121   void _computePartsInCycle(Source librarySource) { |  | 
| 5122     int count = _librariesInCycle.length; |  | 
| 5123     List<CycleBuilder_LibraryPair> libraryData = |  | 
| 5124         new List<CycleBuilder_LibraryPair>(); |  | 
| 5125     for (int i = 0; i < count; i++) { |  | 
| 5126       ResolvableLibrary library = _librariesInCycle[i]; |  | 
| 5127       libraryData.add(new CycleBuilder_LibraryPair( |  | 
| 5128           library, _ensurePartsInLibrary(library))); |  | 
| 5129     } |  | 
| 5130     AnalysisContextImpl_this._neededForResolution = _gatherSources(libraryData); |  | 
| 5131     if (AnalysisContextImpl._TRACE_PERFORM_TASK) { |  | 
| 5132       print( |  | 
| 5133           "  preserve resolution data for ${AnalysisContextImpl_this._neededForR
       esolution.length} sources while resolving ${librarySource.fullName}"); |  | 
| 5134     } |  | 
| 5135     if (_taskData != null) { |  | 
| 5136       return; |  | 
| 5137     } |  | 
| 5138     for (int i = 0; i < count; i++) { |  | 
| 5139       _computePartsInLibrary(libraryData[i]); |  | 
| 5140     } |  | 
| 5141   } |  | 
| 5142 |  | 
| 5143   /** |  | 
| 5144    * Gather the resolvable compilation units for each of the compilation units |  | 
| 5145    * in the library represented by the [libraryPair]. |  | 
| 5146    */ |  | 
| 5147   void _computePartsInLibrary(CycleBuilder_LibraryPair libraryPair) { |  | 
| 5148     ResolvableLibrary library = libraryPair.library; |  | 
| 5149     List<CycleBuilder_SourceEntryPair> entryPairs = libraryPair.entryPairs; |  | 
| 5150     int count = entryPairs.length; |  | 
| 5151     List<ResolvableCompilationUnit> units = |  | 
| 5152         new List<ResolvableCompilationUnit>(count); |  | 
| 5153     for (int i = 0; i < count; i++) { |  | 
| 5154       CycleBuilder_SourceEntryPair entryPair = entryPairs[i]; |  | 
| 5155       Source source = entryPair.source; |  | 
| 5156       DartEntry dartEntry = entryPair.entry; |  | 
| 5157       units[i] = new ResolvableCompilationUnit( |  | 
| 5158           source, dartEntry.resolvableCompilationUnit); |  | 
| 5159     } |  | 
| 5160     library.resolvableCompilationUnits = units; |  | 
| 5161   } |  | 
| 5162 |  | 
| 5163   /** |  | 
| 5164    * Create an object to represent the information about the library defined by |  | 
| 5165    * the compilation unit with the given [librarySource]. |  | 
| 5166    */ |  | 
| 5167   ResolvableLibrary _createLibrary(Source librarySource) { |  | 
| 5168     ResolvableLibrary library = new ResolvableLibrary(librarySource); |  | 
| 5169     SourceEntry sourceEntry = |  | 
| 5170         AnalysisContextImpl_this._cache.get(librarySource); |  | 
| 5171     if (sourceEntry is DartEntry) { |  | 
| 5172       LibraryElementImpl libraryElement = |  | 
| 5173           sourceEntry.getValue(DartEntry.ELEMENT) as LibraryElementImpl; |  | 
| 5174       if (libraryElement != null) { |  | 
| 5175         library.libraryElement = libraryElement; |  | 
| 5176       } |  | 
| 5177     } |  | 
| 5178     _libraryMap[librarySource] = library; |  | 
| 5179     return library; |  | 
| 5180   } |  | 
| 5181 |  | 
| 5182   /** |  | 
| 5183    * Create an object to represent the information about the library defined by |  | 
| 5184    * the compilation unit with the given [librarySource]. |  | 
| 5185    */ |  | 
| 5186   ResolvableLibrary _createLibraryOrNull(Source librarySource) { |  | 
| 5187     ResolvableLibrary library = new ResolvableLibrary(librarySource); |  | 
| 5188     SourceEntry sourceEntry = |  | 
| 5189         AnalysisContextImpl_this._cache.get(librarySource); |  | 
| 5190     if (sourceEntry is DartEntry) { |  | 
| 5191       LibraryElementImpl libraryElement = |  | 
| 5192           sourceEntry.getValue(DartEntry.ELEMENT) as LibraryElementImpl; |  | 
| 5193       if (libraryElement != null) { |  | 
| 5194         library.libraryElement = libraryElement; |  | 
| 5195       } |  | 
| 5196     } |  | 
| 5197     _libraryMap[librarySource] = library; |  | 
| 5198     return library; |  | 
| 5199   } |  | 
| 5200 |  | 
| 5201   /** |  | 
| 5202    * Ensure that the given [library] has an element model built for it. If |  | 
| 5203    * another task needs to be executed first in order to build the element |  | 
| 5204    * model, that task is placed in [taskData]. |  | 
| 5205    */ |  | 
| 5206   void _ensureElementModel(ResolvableLibrary library) { |  | 
| 5207     Source librarySource = library.librarySource; |  | 
| 5208     DartEntry libraryEntry = |  | 
| 5209         AnalysisContextImpl_this._getReadableDartEntry(librarySource); |  | 
| 5210     if (libraryEntry != null && |  | 
| 5211         libraryEntry.getState(DartEntry.PARSED_UNIT) != CacheState.ERROR) { |  | 
| 5212       AnalysisContextImpl_this._workManager.addFirst( |  | 
| 5213           librarySource, SourcePriority.LIBRARY); |  | 
| 5214       if (_taskData == null) { |  | 
| 5215         _taskData = AnalysisContextImpl_this._createResolveDartLibraryTask( |  | 
| 5216             librarySource, libraryEntry); |  | 
| 5217       } |  | 
| 5218     } |  | 
| 5219   } |  | 
| 5220 |  | 
| 5221   /** |  | 
| 5222    * Ensure that all of the libraries that are exported by the given [library] |  | 
| 5223    * (but are not themselves in the cycle) have element models built for them. |  | 
| 5224    * If another task needs to be executed first in order to build the element |  | 
| 5225    * model, that task is placed in [taskData]. |  | 
| 5226    */ |  | 
| 5227   void _ensureExports( |  | 
| 5228       ResolvableLibrary library, HashSet<Source> visitedLibraries) { |  | 
| 5229     List<ResolvableLibrary> dependencies = library.exports; |  | 
| 5230     int dependencyCount = dependencies.length; |  | 
| 5231     for (int i = 0; i < dependencyCount; i++) { |  | 
| 5232       ResolvableLibrary dependency = dependencies[i]; |  | 
| 5233       if (!_librariesInCycle.contains(dependency) && |  | 
| 5234           visitedLibraries.add(dependency.librarySource)) { |  | 
| 5235         if (dependency.libraryElement == null) { |  | 
| 5236           _ensureElementModel(dependency); |  | 
| 5237         } else { |  | 
| 5238           _ensureExports(dependency, visitedLibraries); |  | 
| 5239         } |  | 
| 5240         if (_taskData != null) { |  | 
| 5241           return; |  | 
| 5242         } |  | 
| 5243       } |  | 
| 5244     } |  | 
| 5245   } |  | 
| 5246 |  | 
| 5247   /** |  | 
| 5248    * Ensure that all of the libraries that are exported by the given [library] |  | 
| 5249    * (but are not themselves in the cycle) have element models built for them. |  | 
| 5250    * If another task needs to be executed first in order to build the element |  | 
| 5251    * model, that task is placed in [taskData]. |  | 
| 5252    */ |  | 
| 5253   void _ensureImports(ResolvableLibrary library) { |  | 
| 5254     List<ResolvableLibrary> dependencies = library.imports; |  | 
| 5255     int dependencyCount = dependencies.length; |  | 
| 5256     for (int i = 0; i < dependencyCount; i++) { |  | 
| 5257       ResolvableLibrary dependency = dependencies[i]; |  | 
| 5258       if (!_librariesInCycle.contains(dependency) && |  | 
| 5259           dependency.libraryElement == null) { |  | 
| 5260         _ensureElementModel(dependency); |  | 
| 5261         if (_taskData != null) { |  | 
| 5262           return; |  | 
| 5263         } |  | 
| 5264       } |  | 
| 5265     } |  | 
| 5266   } |  | 
| 5267 |  | 
| 5268   /** |  | 
| 5269    * Ensure that all of the libraries that are either imported or exported by |  | 
| 5270    * libraries in the cycle (but are not themselves in the cycle) have element |  | 
| 5271    * models built for them. |  | 
| 5272    */ |  | 
| 5273   void _ensureImportsAndExports() { |  | 
| 5274     HashSet<Source> visitedLibraries = new HashSet<Source>(); |  | 
| 5275     int libraryCount = _librariesInCycle.length; |  | 
| 5276     for (int i = 0; i < libraryCount; i++) { |  | 
| 5277       ResolvableLibrary library = _librariesInCycle[i]; |  | 
| 5278       _ensureImports(library); |  | 
| 5279       if (_taskData != null) { |  | 
| 5280         return; |  | 
| 5281       } |  | 
| 5282       _ensureExports(library, visitedLibraries); |  | 
| 5283       if (_taskData != null) { |  | 
| 5284         return; |  | 
| 5285       } |  | 
| 5286     } |  | 
| 5287   } |  | 
| 5288 |  | 
| 5289   /** |  | 
| 5290    * Ensure that there is a resolvable compilation unit available for all of the |  | 
| 5291    * compilation units in the given [library]. |  | 
| 5292    */ |  | 
| 5293   List<CycleBuilder_SourceEntryPair> _ensurePartsInLibrary( |  | 
| 5294       ResolvableLibrary library) { |  | 
| 5295     List<CycleBuilder_SourceEntryPair> pairs = |  | 
| 5296         new List<CycleBuilder_SourceEntryPair>(); |  | 
| 5297     Source librarySource = library.librarySource; |  | 
| 5298     DartEntry libraryEntry = |  | 
| 5299         AnalysisContextImpl_this._getReadableDartEntry(librarySource); |  | 
| 5300     if (libraryEntry == null) { |  | 
| 5301       throw new AnalysisException( |  | 
| 5302           "Cannot find entry for ${librarySource.fullName}"); |  | 
| 5303     } else if (libraryEntry.getState(DartEntry.PARSED_UNIT) == |  | 
| 5304         CacheState.ERROR) { |  | 
| 5305       String message = |  | 
| 5306           "Cannot compute parsed unit for ${librarySource.fullName}"; |  | 
| 5307       CaughtException exception = libraryEntry.exception; |  | 
| 5308       if (exception == null) { |  | 
| 5309         throw new AnalysisException(message); |  | 
| 5310       } |  | 
| 5311       throw new AnalysisException( |  | 
| 5312           message, new CaughtException(exception, null)); |  | 
| 5313     } |  | 
| 5314     _ensureResolvableCompilationUnit(librarySource, libraryEntry); |  | 
| 5315     pairs.add(new CycleBuilder_SourceEntryPair(librarySource, libraryEntry)); |  | 
| 5316     List<Source> partSources = |  | 
| 5317         _getSources(librarySource, libraryEntry, DartEntry.INCLUDED_PARTS); |  | 
| 5318     int count = partSources.length; |  | 
| 5319     for (int i = 0; i < count; i++) { |  | 
| 5320       Source partSource = partSources[i]; |  | 
| 5321       DartEntry partEntry = |  | 
| 5322           AnalysisContextImpl_this._getReadableDartEntry(partSource); |  | 
| 5323       if (partEntry != null && |  | 
| 5324           partEntry.getState(DartEntry.PARSED_UNIT) != CacheState.ERROR) { |  | 
| 5325         _ensureResolvableCompilationUnit(partSource, partEntry); |  | 
| 5326         pairs.add(new CycleBuilder_SourceEntryPair(partSource, partEntry)); |  | 
| 5327       } |  | 
| 5328     } |  | 
| 5329     return pairs; |  | 
| 5330   } |  | 
| 5331 |  | 
| 5332   /** |  | 
| 5333    * Ensure that there is a resolvable compilation unit available for the given |  | 
| 5334    * [source]. |  | 
| 5335    */ |  | 
| 5336   void _ensureResolvableCompilationUnit(Source source, DartEntry dartEntry) { |  | 
| 5337     // The entry will be null if the source represents a non-Dart file. |  | 
| 5338     if (dartEntry != null && !dartEntry.hasResolvableCompilationUnit) { |  | 
| 5339       if (_taskData == null) { |  | 
| 5340         _taskData = |  | 
| 5341             AnalysisContextImpl_this._createParseDartTask(source, dartEntry); |  | 
| 5342       } |  | 
| 5343     } |  | 
| 5344   } |  | 
| 5345 |  | 
| 5346   HashSet<Source> _gatherSources(List<CycleBuilder_LibraryPair> libraryData) { |  | 
| 5347     int libraryCount = libraryData.length; |  | 
| 5348     HashSet<Source> sources = new HashSet<Source>(); |  | 
| 5349     for (int i = 0; i < libraryCount; i++) { |  | 
| 5350       List<CycleBuilder_SourceEntryPair> entryPairs = libraryData[i].entryPairs; |  | 
| 5351       int entryCount = entryPairs.length; |  | 
| 5352       for (int j = 0; j < entryCount; j++) { |  | 
| 5353         sources.add(entryPairs[j].source); |  | 
| 5354       } |  | 
| 5355     } |  | 
| 5356     return sources; |  | 
| 5357   } |  | 
| 5358 |  | 
| 5359   /** |  | 
| 5360    * Return the sources described by the given [descriptor]. |  | 
| 5361    */ |  | 
| 5362   List<Source> _getSources(Source source, DartEntry dartEntry, |  | 
| 5363       DataDescriptor<List<Source>> descriptor) { |  | 
| 5364     if (dartEntry == null) { |  | 
| 5365       return Source.EMPTY_LIST; |  | 
| 5366     } |  | 
| 5367     CacheState exportState = dartEntry.getState(descriptor); |  | 
| 5368     if (exportState == CacheState.ERROR) { |  | 
| 5369       return Source.EMPTY_LIST; |  | 
| 5370     } else if (exportState != CacheState.VALID) { |  | 
| 5371       if (_taskData == null) { |  | 
| 5372         _taskData = |  | 
| 5373             AnalysisContextImpl_this._createParseDartTask(source, dartEntry); |  | 
| 5374       } |  | 
| 5375       return Source.EMPTY_LIST; |  | 
| 5376     } |  | 
| 5377     return dartEntry.getValue(descriptor); |  | 
| 5378   } |  | 
| 5379 } |  | 
| 5380 |  | 
| 5381 /** |  | 
| 5382  * Information about the next task to be performed. Each data has an implicit |  | 
| 5383  * associated source: the source that might need to be analyzed. There are |  | 
| 5384  * essentially three states that can be represented: |  | 
| 5385  * |  | 
| 5386  * * If [getTask] returns a non-`null` value, then that is the task that should |  | 
| 5387  *   be executed to further analyze the associated source. |  | 
| 5388  * * Otherwise, if [isBlocked] returns `true`, then there is no work that can be |  | 
| 5389  *   done, but analysis for the associated source is not complete. |  | 
| 5390  * * Otherwise, [getDependentSource] should return a source that needs to be |  | 
| 5391  *   analyzed before the analysis of the associated source can be completed. |  | 
| 5392  */ |  | 
| 5393 class AnalysisContextImpl_TaskData { |  | 
| 5394   /** |  | 
| 5395    * The task that is to be performed. |  | 
| 5396    */ |  | 
| 5397   final AnalysisTask task; |  | 
| 5398 |  | 
| 5399   /** |  | 
| 5400    * A flag indicating whether the associated source is blocked waiting for its |  | 
| 5401    * contents to be loaded. |  | 
| 5402    */ |  | 
| 5403   final bool _blocked; |  | 
| 5404 |  | 
| 5405   /** |  | 
| 5406    * Initialize a newly created data holder. |  | 
| 5407    */ |  | 
| 5408   AnalysisContextImpl_TaskData(this.task, this._blocked); |  | 
| 5409 |  | 
| 5410   /** |  | 
| 5411    * Return `true` if the associated source is blocked waiting for its contents |  | 
| 5412    * to be loaded. |  | 
| 5413    */ |  | 
| 5414   bool get isBlocked => _blocked; |  | 
| 5415 |  | 
| 5416   @override |  | 
| 5417   String toString() { |  | 
| 5418     if (task == null) { |  | 
| 5419       return "blocked: $_blocked"; |  | 
| 5420     } |  | 
| 5421     return task.toString(); |  | 
| 5422   } |  | 
| 5423 } |  | 
| 5424 |  | 
| 5425 /** |  | 
| 5426  * Statistics and information about a single [AnalysisContext]. |  | 
| 5427  */ |  | 
| 5428 abstract class AnalysisContextStatistics { |  | 
| 5429   /** |  | 
| 5430    * Return the statistics for each kind of cached data. |  | 
| 5431    */ |  | 
| 5432   List<AnalysisContextStatistics_CacheRow> get cacheRows; |  | 
| 5433 |  | 
| 5434   /** |  | 
| 5435    * Return the exceptions that caused some entries to have a state of |  | 
| 5436    * [CacheState.ERROR]. |  | 
| 5437    */ |  | 
| 5438   List<CaughtException> get exceptions; |  | 
| 5439 |  | 
| 5440   /** |  | 
| 5441    * Return information about each of the partitions in the cache. |  | 
| 5442    */ |  | 
| 5443   List<AnalysisContextStatistics_PartitionData> get partitionData; |  | 
| 5444 |  | 
| 5445   /** |  | 
| 5446    * Return a list containing all of the sources in the cache. |  | 
| 5447    */ |  | 
| 5448   List<Source> get sources; |  | 
| 5449 } |  | 
| 5450 |  | 
| 5451 /** |  | 
| 5452  * Information about single piece of data in the cache. |  | 
| 5453  */ |  | 
| 5454 abstract class AnalysisContextStatistics_CacheRow { |  | 
| 5455   /** |  | 
| 5456    * List of possible states which can be queried. |  | 
| 5457    */ |  | 
| 5458   static const List<CacheState> STATES = const <CacheState>[ |  | 
| 5459     CacheState.ERROR, |  | 
| 5460     CacheState.FLUSHED, |  | 
| 5461     CacheState.IN_PROCESS, |  | 
| 5462     CacheState.INVALID, |  | 
| 5463     CacheState.VALID |  | 
| 5464   ]; |  | 
| 5465 |  | 
| 5466   /** |  | 
| 5467    * Return the number of entries whose state is [CacheState.ERROR]. |  | 
| 5468    */ |  | 
| 5469   int get errorCount; |  | 
| 5470 |  | 
| 5471   /** |  | 
| 5472    * Return the number of entries whose state is [CacheState.FLUSHED]. |  | 
| 5473    */ |  | 
| 5474   int get flushedCount; |  | 
| 5475 |  | 
| 5476   /** |  | 
| 5477    * Return the number of entries whose state is [CacheState.IN_PROCESS]. |  | 
| 5478    */ |  | 
| 5479   int get inProcessCount; |  | 
| 5480 |  | 
| 5481   /** |  | 
| 5482    * Return the number of entries whose state is [CacheState.INVALID]. |  | 
| 5483    */ |  | 
| 5484   int get invalidCount; |  | 
| 5485 |  | 
| 5486   /** |  | 
| 5487    * Return the name of the data represented by this object. |  | 
| 5488    */ |  | 
| 5489   String get name; |  | 
| 5490 |  | 
| 5491   /** |  | 
| 5492    * Return the number of entries whose state is [CacheState.VALID]. |  | 
| 5493    */ |  | 
| 5494   int get validCount; |  | 
| 5495 |  | 
| 5496   /** |  | 
| 5497    * Return the number of entries whose state is [state]. |  | 
| 5498    */ |  | 
| 5499   int getCount(CacheState state); |  | 
| 5500 } |  | 
| 5501 |  | 
| 5502 /** |  | 
| 5503  * Information about a single partition in the cache. |  | 
| 5504  */ |  | 
| 5505 abstract class AnalysisContextStatistics_PartitionData { |  | 
| 5506   /** |  | 
| 5507    * Return the number of entries in the partition that have an AST structure in |  | 
| 5508    * one state or another. |  | 
| 5509    */ |  | 
| 5510   int get astCount; |  | 
| 5511 |  | 
| 5512   /** |  | 
| 5513    * Return the total number of entries in the partition. |  | 
| 5514    */ |  | 
| 5515   int get totalCount; |  | 
| 5516 } |  | 
| 5517 |  | 
| 5518 /** |  | 
| 5519  * Implementation of the [AnalysisContextStatistics]. |  | 
| 5520  */ |  | 
| 5521 class AnalysisContextStatisticsImpl implements AnalysisContextStatistics { |  | 
| 5522   Map<String, AnalysisContextStatistics_CacheRow> _dataMap = |  | 
| 5523       new HashMap<String, AnalysisContextStatistics_CacheRow>(); |  | 
| 5524 |  | 
| 5525   List<Source> _sources = new List<Source>(); |  | 
| 5526 |  | 
| 5527   HashSet<CaughtException> _exceptions = new HashSet<CaughtException>(); |  | 
| 5528 |  | 
| 5529   List<AnalysisContextStatistics_PartitionData> _partitionData; |  | 
| 5530 |  | 
| 5531   @override |  | 
| 5532   List<AnalysisContextStatistics_CacheRow> get cacheRows => |  | 
| 5533       _dataMap.values.toList(); |  | 
| 5534 |  | 
| 5535   @override |  | 
| 5536   List<CaughtException> get exceptions => new List.from(_exceptions); |  | 
| 5537 |  | 
| 5538   @override |  | 
| 5539   List<AnalysisContextStatistics_PartitionData> get partitionData => |  | 
| 5540       _partitionData; |  | 
| 5541 |  | 
| 5542   /** |  | 
| 5543    * Set the partition data returned by this object to the given data. |  | 
| 5544    */ |  | 
| 5545   void set partitionData(List<AnalysisContextStatistics_PartitionData> data) { |  | 
| 5546     _partitionData = data; |  | 
| 5547   } |  | 
| 5548 |  | 
| 5549   @override |  | 
| 5550   List<Source> get sources => _sources; |  | 
| 5551 |  | 
| 5552   void addSource(Source source) { |  | 
| 5553     _sources.add(source); |  | 
| 5554   } |  | 
| 5555 |  | 
| 5556   void _internalPutCacheItem(Source source, SourceEntry dartEntry, |  | 
| 5557       DataDescriptor rowDesc, CacheState state) { |  | 
| 5558     String rowName = rowDesc.toString(); |  | 
| 5559     AnalysisContextStatisticsImpl_CacheRowImpl row = |  | 
| 5560         _dataMap[rowName] as AnalysisContextStatisticsImpl_CacheRowImpl; |  | 
| 5561     if (row == null) { |  | 
| 5562       row = new AnalysisContextStatisticsImpl_CacheRowImpl(rowName); |  | 
| 5563       _dataMap[rowName] = row; |  | 
| 5564     } |  | 
| 5565     row._incState(state); |  | 
| 5566     if (state == CacheState.ERROR) { |  | 
| 5567       CaughtException exception = dartEntry.exception; |  | 
| 5568       if (exception != null) { |  | 
| 5569         _exceptions.add(exception); |  | 
| 5570       } |  | 
| 5571     } |  | 
| 5572   } |  | 
| 5573 } |  | 
| 5574 |  | 
| 5575 class AnalysisContextStatisticsImpl_CacheRowImpl |  | 
| 5576     implements AnalysisContextStatistics_CacheRow { |  | 
| 5577   final String name; |  | 
| 5578 |  | 
| 5579   Map<CacheState, int> _counts = <CacheState, int>{}; |  | 
| 5580 |  | 
| 5581   AnalysisContextStatisticsImpl_CacheRowImpl(this.name); |  | 
| 5582 |  | 
| 5583   @override |  | 
| 5584   int get errorCount => getCount(CacheState.ERROR); |  | 
| 5585 |  | 
| 5586   @override |  | 
| 5587   int get flushedCount => getCount(CacheState.FLUSHED); |  | 
| 5588 |  | 
| 5589   @override |  | 
| 5590   int get hashCode => name.hashCode; |  | 
| 5591 |  | 
| 5592   @override |  | 
| 5593   int get inProcessCount => getCount(CacheState.IN_PROCESS); |  | 
| 5594 |  | 
| 5595   @override |  | 
| 5596   int get invalidCount => getCount(CacheState.INVALID); |  | 
| 5597 |  | 
| 5598   @override |  | 
| 5599   int get validCount => getCount(CacheState.VALID); |  | 
| 5600 |  | 
| 5601   @override |  | 
| 5602   bool operator ==(Object obj) => |  | 
| 5603       obj is AnalysisContextStatisticsImpl_CacheRowImpl && obj.name == name; |  | 
| 5604 |  | 
| 5605   @override |  | 
| 5606   int getCount(CacheState state) { |  | 
| 5607     int count = _counts[state]; |  | 
| 5608     if (count != null) { |  | 
| 5609       return count; |  | 
| 5610     } else { |  | 
| 5611       return 0; |  | 
| 5612     } |  | 
| 5613   } |  | 
| 5614 |  | 
| 5615   void _incState(CacheState state) { |  | 
| 5616     if (_counts[state] == null) { |  | 
| 5617       _counts[state] = 1; |  | 
| 5618     } else { |  | 
| 5619       _counts[state]++; |  | 
| 5620     } |  | 
| 5621   } |  | 
| 5622 } |  | 
| 5623 |  | 
| 5624 class AnalysisContextStatisticsImpl_PartitionDataImpl |  | 
| 5625     implements AnalysisContextStatistics_PartitionData { |  | 
| 5626   final int astCount; |  | 
| 5627 |  | 
| 5628   final int totalCount; |  | 
| 5629 |  | 
| 5630   AnalysisContextStatisticsImpl_PartitionDataImpl( |  | 
| 5631       this.astCount, this.totalCount); |  | 
| 5632 } |  | 
| 5633 |  | 
| 5634 /** |  | 
| 5635  * A representation of changes to the types of analysis that should be |  | 
| 5636  * performed. |  | 
| 5637  */ |  | 
| 5638 class AnalysisDelta { |  | 
| 5639   /** |  | 
| 5640    * A mapping from source to what type of analysis should be performed on that |  | 
| 5641    * source. |  | 
| 5642    */ |  | 
| 5643   HashMap<Source, AnalysisLevel> _analysisMap = |  | 
| 5644       new HashMap<Source, AnalysisLevel>(); |  | 
| 5645 |  | 
| 5646   /** |  | 
| 5647    * Return a collection of the sources that have been added. This is equivalent |  | 
| 5648    * to calling [getAnalysisLevels] and collecting all sources that do not have |  | 
| 5649    * an analysis level of [AnalysisLevel.NONE]. |  | 
| 5650    */ |  | 
| 5651   List<Source> get addedSources { |  | 
| 5652     List<Source> result = new List<Source>(); |  | 
| 5653     _analysisMap.forEach((Source source, AnalysisLevel level) { |  | 
| 5654       if (level != AnalysisLevel.NONE) { |  | 
| 5655         result.add(source); |  | 
| 5656       } |  | 
| 5657     }); |  | 
| 5658     return result; |  | 
| 5659   } |  | 
| 5660 |  | 
| 5661   /** |  | 
| 5662    * Return a mapping of sources to the level of analysis that should be |  | 
| 5663    * performed. |  | 
| 5664    */ |  | 
| 5665   Map<Source, AnalysisLevel> get analysisLevels => _analysisMap; |  | 
| 5666 |  | 
| 5667   /** |  | 
| 5668    * Record that the given [source] should be analyzed at the given [level]. |  | 
| 5669    */ |  | 
| 5670   void setAnalysisLevel(Source source, AnalysisLevel level) { |  | 
| 5671     _analysisMap[source] = level; |  | 
| 5672   } |  | 
| 5673 |  | 
| 5674   @override |  | 
| 5675   String toString() { |  | 
| 5676     StringBuffer buffer = new StringBuffer(); |  | 
| 5677     bool needsSeparator = _appendSources(buffer, false, AnalysisLevel.ALL); |  | 
| 5678     needsSeparator = |  | 
| 5679         _appendSources(buffer, needsSeparator, AnalysisLevel.RESOLVED); |  | 
| 5680     _appendSources(buffer, needsSeparator, AnalysisLevel.NONE); |  | 
| 5681     return buffer.toString(); |  | 
| 5682   } |  | 
| 5683 |  | 
| 5684   /** |  | 
| 5685    * Appendto the given [buffer] all sources with the given analysis [level], |  | 
| 5686    * prefixed with a label and a separator if [needsSeparator] is `true`. |  | 
| 5687    */ |  | 
| 5688   bool _appendSources( |  | 
| 5689       StringBuffer buffer, bool needsSeparator, AnalysisLevel level) { |  | 
| 5690     bool first = true; |  | 
| 5691     _analysisMap.forEach((Source source, AnalysisLevel sourceLevel) { |  | 
| 5692       if (sourceLevel == level) { |  | 
| 5693         if (first) { |  | 
| 5694           first = false; |  | 
| 5695           if (needsSeparator) { |  | 
| 5696             buffer.write("; "); |  | 
| 5697           } |  | 
| 5698           buffer.write(level); |  | 
| 5699           buffer.write(" "); |  | 
| 5700         } else { |  | 
| 5701           buffer.write(", "); |  | 
| 5702         } |  | 
| 5703         buffer.write(source.fullName); |  | 
| 5704       } |  | 
| 5705     }); |  | 
| 5706     return needsSeparator || !first; |  | 
| 5707   } |  | 
| 5708 } |  | 
| 5709 |  | 
| 5710 /** |  | 
| 5711  * The entry point for the functionality provided by the analysis engine. There |  | 
| 5712  * is a single instance of this class. |  | 
| 5713  */ |  | 
| 5714 class AnalysisEngine { |  | 
| 5715   /** |  | 
| 5716    * The suffix used for Dart source files. |  | 
| 5717    */ |  | 
| 5718   static const String SUFFIX_DART = "dart"; |  | 
| 5719 |  | 
| 5720   /** |  | 
| 5721    * The short suffix used for HTML files. |  | 
| 5722    */ |  | 
| 5723   static const String SUFFIX_HTM = "htm"; |  | 
| 5724 |  | 
| 5725   /** |  | 
| 5726    * The long suffix used for HTML files. |  | 
| 5727    */ |  | 
| 5728   static const String SUFFIX_HTML = "html"; |  | 
| 5729 |  | 
| 5730   /** |  | 
| 5731    * The unique instance of this class. |  | 
| 5732    */ |  | 
| 5733   static final AnalysisEngine instance = new AnalysisEngine._(); |  | 
| 5734 |  | 
| 5735   /** |  | 
| 5736    * The logger that should receive information about errors within the analysis |  | 
| 5737    * engine. |  | 
| 5738    */ |  | 
| 5739   Logger _logger = Logger.NULL; |  | 
| 5740 |  | 
| 5741   /** |  | 
| 5742    * The plugin that defines the extension points and extensions that are define
       d by |  | 
| 5743    * command-line applications using the analysis engine. |  | 
| 5744    */ |  | 
| 5745   final CommandLinePlugin commandLinePlugin = new CommandLinePlugin(); |  | 
| 5746 |  | 
| 5747   /** |  | 
| 5748    * The plugin that defines the extension points and extensions that are |  | 
| 5749    * inherently defined by the analysis engine. |  | 
| 5750    */ |  | 
| 5751   final EnginePlugin enginePlugin = new EnginePlugin(); |  | 
| 5752 |  | 
| 5753   /*** |  | 
| 5754    * The plugin that defines the extension points and extensions that are define
       d |  | 
| 5755    * by applications that want to consume options defined in the analysis |  | 
| 5756    * options file. |  | 
| 5757    */ |  | 
| 5758   final OptionsPlugin optionsPlugin = new OptionsPlugin(); |  | 
| 5759 |  | 
| 5760   /** |  | 
| 5761    * The instrumentation service that is to be used by this analysis engine. |  | 
| 5762    */ |  | 
| 5763   InstrumentationService _instrumentationService = |  | 
| 5764       InstrumentationService.NULL_SERVICE; |  | 
| 5765 |  | 
| 5766   /** |  | 
| 5767    * The list of supported plugins for processing by clients. |  | 
| 5768    */ |  | 
| 5769   List<Plugin> _supportedPlugins; |  | 
| 5770 |  | 
| 5771   /** |  | 
| 5772    * The partition manager being used to manage the shared partitions. |  | 
| 5773    */ |  | 
| 5774   final PartitionManager partitionManager = new PartitionManager(); |  | 
| 5775 |  | 
| 5776   /** |  | 
| 5777    * The partition manager being used to manage the shared partitions. |  | 
| 5778    */ |  | 
| 5779   final newContext.PartitionManager partitionManager_new = |  | 
| 5780       new newContext.PartitionManager(); |  | 
| 5781 |  | 
| 5782   /** |  | 
| 5783    * A flag indicating whether the (new) task model should be used to perform |  | 
| 5784    * analysis. |  | 
| 5785    */ |  | 
| 5786   bool useTaskModel = false; |  | 
| 5787 |  | 
| 5788   /** |  | 
| 5789    * A flag indicating whether the task model should attempt to limit |  | 
| 5790    * invalidation after a change. |  | 
| 5791    */ |  | 
| 5792   bool limitInvalidationInTaskModel = false; |  | 
| 5793 |  | 
| 5794   /** |  | 
| 5795    * The task manager used to manage the tasks used to analyze code. |  | 
| 5796    */ |  | 
| 5797   TaskManager _taskManager; |  | 
| 5798 |  | 
| 5799   AnalysisEngine._(); |  | 
| 5800 |  | 
| 5801   /** |  | 
| 5802    * Return the instrumentation service that is to be used by this analysis |  | 
| 5803    * engine. |  | 
| 5804    */ |  | 
| 5805   InstrumentationService get instrumentationService => _instrumentationService; |  | 
| 5806 |  | 
| 5807   /** |  | 
| 5808    * Set the instrumentation service that is to be used by this analysis engine |  | 
| 5809    * to the given [service]. |  | 
| 5810    */ |  | 
| 5811   void set instrumentationService(InstrumentationService service) { |  | 
| 5812     if (service == null) { |  | 
| 5813       _instrumentationService = InstrumentationService.NULL_SERVICE; |  | 
| 5814     } else { |  | 
| 5815       _instrumentationService = service; |  | 
| 5816     } |  | 
| 5817   } |  | 
| 5818 |  | 
| 5819   /** |  | 
| 5820    * Return the logger that should receive information about errors within the |  | 
| 5821    * analysis engine. |  | 
| 5822    */ |  | 
| 5823   Logger get logger => _logger; |  | 
| 5824 |  | 
| 5825   /** |  | 
| 5826    * Set the logger that should receive information about errors within the |  | 
| 5827    * analysis engine to the given [logger]. |  | 
| 5828    */ |  | 
| 5829   void set logger(Logger logger) { |  | 
| 5830     this._logger = logger == null ? Logger.NULL : logger; |  | 
| 5831   } |  | 
| 5832 |  | 
| 5833   /** |  | 
| 5834    * Return the list of supported plugins for processing by clients. |  | 
| 5835    */ |  | 
| 5836   List<Plugin> get supportedPlugins { |  | 
| 5837     if (_supportedPlugins == null) { |  | 
| 5838       _supportedPlugins = <Plugin>[ |  | 
| 5839         enginePlugin, |  | 
| 5840         commandLinePlugin, |  | 
| 5841         optionsPlugin |  | 
| 5842       ]; |  | 
| 5843     } |  | 
| 5844     return _supportedPlugins; |  | 
| 5845   } |  | 
| 5846 |  | 
| 5847   /** |  | 
| 5848    * Return the task manager used to manage the tasks used to analyze code. |  | 
| 5849    */ |  | 
| 5850   TaskManager get taskManager { |  | 
| 5851     if (_taskManager == null) { |  | 
| 5852       if (enginePlugin.taskExtensionPoint == null) { |  | 
| 5853         // The plugin wasn't used, so tasks are not registered. |  | 
| 5854         new ExtensionManager().processPlugins([enginePlugin]); |  | 
| 5855       } |  | 
| 5856       _taskManager = new TaskManager(); |  | 
| 5857       _taskManager.addTaskDescriptors(enginePlugin.taskDescriptors); |  | 
| 5858       // TODO(brianwilkerson) Create a way to associate different results with |  | 
| 5859       // different file suffixes, then make this pluggable. |  | 
| 5860       _taskManager.addGeneralResult(DART_ERRORS); |  | 
| 5861     } |  | 
| 5862     return _taskManager; |  | 
| 5863   } |  | 
| 5864 |  | 
| 5865   /** |  | 
| 5866    * Clear any caches holding on to analysis results so that a full re-analysis |  | 
| 5867    * will be performed the next time an analysis context is created. |  | 
| 5868    */ |  | 
| 5869   void clearCaches() { |  | 
| 5870     partitionManager.clearCache(); |  | 
| 5871   } |  | 
| 5872 |  | 
| 5873   /** |  | 
| 5874    * Create and return a new context in which analysis can be performed. |  | 
| 5875    */ |  | 
| 5876   AnalysisContext createAnalysisContext() { |  | 
| 5877     if (useTaskModel) { |  | 
| 5878       return new newContext.AnalysisContextImpl(); |  | 
| 5879     } |  | 
| 5880     return new AnalysisContextImpl(); |  | 
| 5881   } |  | 
| 5882 |  | 
| 5883   /** |  | 
| 5884    * Return `true` if the given [fileName] is assumed to contain Dart source |  | 
| 5885    * code. |  | 
| 5886    */ |  | 
| 5887   static bool isDartFileName(String fileName) { |  | 
| 5888     if (fileName == null) { |  | 
| 5889       return false; |  | 
| 5890     } |  | 
| 5891     return javaStringEqualsIgnoreCase( |  | 
| 5892         FileNameUtilities.getExtension(fileName), SUFFIX_DART); |  | 
| 5893   } |  | 
| 5894 |  | 
| 5895   /** |  | 
| 5896    * Return `true` if the given [fileName] is assumed to contain HTML. |  | 
| 5897    */ |  | 
| 5898   static bool isHtmlFileName(String fileName) { |  | 
| 5899     if (fileName == null) { |  | 
| 5900       return false; |  | 
| 5901     } |  | 
| 5902     String extension = FileNameUtilities.getExtension(fileName); |  | 
| 5903     return javaStringEqualsIgnoreCase(extension, SUFFIX_HTML) || |  | 
| 5904         javaStringEqualsIgnoreCase(extension, SUFFIX_HTM); |  | 
| 5905   } |  | 
| 5906 } |  | 
| 5907 |  | 
| 5908 /** |  | 
| 5909  * The analysis errors and line information for the errors. |  | 
| 5910  */ |  | 
| 5911 abstract class AnalysisErrorInfo { |  | 
| 5912   /** |  | 
| 5913    * Return the errors that as a result of the analysis, or `null` if there were |  | 
| 5914    * no errors. |  | 
| 5915    */ |  | 
| 5916   List<AnalysisError> get errors; |  | 
| 5917 |  | 
| 5918   /** |  | 
| 5919    * Return the line information associated with the errors, or `null` if there |  | 
| 5920    * were no errors. |  | 
| 5921    */ |  | 
| 5922   LineInfo get lineInfo; |  | 
| 5923 } |  | 
| 5924 |  | 
| 5925 /** |  | 
| 5926  * The analysis errors and line info associated with a source. |  | 
| 5927  */ |  | 
| 5928 class AnalysisErrorInfoImpl implements AnalysisErrorInfo { |  | 
| 5929   /** |  | 
| 5930    * The analysis errors associated with a source, or `null` if there are no |  | 
| 5931    * errors. |  | 
| 5932    */ |  | 
| 5933   final List<AnalysisError> errors; |  | 
| 5934 |  | 
| 5935   /** |  | 
| 5936    * The line information associated with the errors, or `null` if there are no |  | 
| 5937    * errors. |  | 
| 5938    */ |  | 
| 5939   final LineInfo lineInfo; |  | 
| 5940 |  | 
| 5941   /** |  | 
| 5942    * Initialize an newly created error info with the given [errors] and |  | 
| 5943    * [lineInfo]. |  | 
| 5944    */ |  | 
| 5945   AnalysisErrorInfoImpl(this.errors, this.lineInfo); |  | 
| 5946 } |  | 
| 5947 |  | 
| 5948 /** |  | 
| 5949  * The levels at which a source can be analyzed. |  | 
| 5950  */ |  | 
| 5951 class AnalysisLevel extends Enum<AnalysisLevel> { |  | 
| 5952   /** |  | 
| 5953    * Indicates a source should be fully analyzed. |  | 
| 5954    */ |  | 
| 5955   static const AnalysisLevel ALL = const AnalysisLevel('ALL', 0); |  | 
| 5956 |  | 
| 5957   /** |  | 
| 5958    * Indicates a source should be resolved and that errors, warnings and hints a
       re needed. |  | 
| 5959    */ |  | 
| 5960   static const AnalysisLevel ERRORS = const AnalysisLevel('ERRORS', 1); |  | 
| 5961 |  | 
| 5962   /** |  | 
| 5963    * Indicates a source should be resolved, but that errors, warnings and hints 
       are not needed. |  | 
| 5964    */ |  | 
| 5965   static const AnalysisLevel RESOLVED = const AnalysisLevel('RESOLVED', 2); |  | 
| 5966 |  | 
| 5967   /** |  | 
| 5968    * Indicates a source is not of interest to the client. |  | 
| 5969    */ |  | 
| 5970   static const AnalysisLevel NONE = const AnalysisLevel('NONE', 3); |  | 
| 5971 |  | 
| 5972   static const List<AnalysisLevel> values = const [ALL, ERRORS, RESOLVED, NONE]; |  | 
| 5973 |  | 
| 5974   const AnalysisLevel(String name, int ordinal) : super(name, ordinal); |  | 
| 5975 } |  | 
| 5976 |  | 
| 5977 /** |  | 
| 5978  * An object that is listening for results being produced by an analysis |  | 
| 5979  * context. |  | 
| 5980  */ |  | 
| 5981 abstract class AnalysisListener { |  | 
| 5982   /** |  | 
| 5983    * Reports that a task, described by the given [taskDescription] is about to |  | 
| 5984    * be performed by the given [context]. |  | 
| 5985    */ |  | 
| 5986   void aboutToPerformTask(AnalysisContext context, String taskDescription); |  | 
| 5987 |  | 
| 5988   /** |  | 
| 5989    * Reports that the [errors] associated with the given [source] in the given |  | 
| 5990    * [context] has been updated to the given errors. The [lineInfo] is the line |  | 
| 5991    * information associated with the source. |  | 
| 5992    */ |  | 
| 5993   void computedErrors(AnalysisContext context, Source source, |  | 
| 5994       List<AnalysisError> errors, LineInfo lineInfo); |  | 
| 5995 |  | 
| 5996   /** |  | 
| 5997    * Reports that the given [source] is no longer included in the set of sources |  | 
| 5998    * that are being analyzed by the given analysis [context]. |  | 
| 5999    */ |  | 
| 6000   void excludedSource(AnalysisContext context, Source source); |  | 
| 6001 |  | 
| 6002   /** |  | 
| 6003    * Reports that the given [source] is now included in the set of sources that |  | 
| 6004    * are being analyzed by the given analysis [context]. |  | 
| 6005    */ |  | 
| 6006   void includedSource(AnalysisContext context, Source source); |  | 
| 6007 |  | 
| 6008   /** |  | 
| 6009    * Reports that the given Dart [source] was parsed in the given [context], |  | 
| 6010    * producing the given [unit]. |  | 
| 6011    */ |  | 
| 6012   void parsedDart(AnalysisContext context, Source source, CompilationUnit unit); |  | 
| 6013 |  | 
| 6014   /** |  | 
| 6015    * Reports that the given HTML [source] was parsed in the given [context]. |  | 
| 6016    */ |  | 
| 6017   @deprecated |  | 
| 6018   void parsedHtml(AnalysisContext context, Source source, ht.HtmlUnit unit); |  | 
| 6019 |  | 
| 6020   /** |  | 
| 6021    * Reports that the given Dart [source] was resolved in the given [context]. |  | 
| 6022    */ |  | 
| 6023   void resolvedDart( |  | 
| 6024       AnalysisContext context, Source source, CompilationUnit unit); |  | 
| 6025 |  | 
| 6026   /** |  | 
| 6027    * Reports that the given HTML [source] was resolved in the given [context]. |  | 
| 6028    */ |  | 
| 6029   @deprecated |  | 
| 6030   void resolvedHtml(AnalysisContext context, Source source, ht.HtmlUnit unit); |  | 
| 6031 } |  | 
| 6032 |  | 
| 6033 /** |  | 
| 6034  * Futures returned by [AnalysisContext] for pending analysis results will |  | 
| 6035  * complete with this error if it is determined that analysis results will |  | 
| 6036  * never become available (e.g. because the requested source is not subject to |  | 
| 6037  * analysis, or because the requested source is a part file which is not a part |  | 
| 6038  * of any known library). |  | 
| 6039  */ |  | 
| 6040 class AnalysisNotScheduledError implements Exception {} |  | 
| 6041 |  | 
| 6042 /** |  | 
| 6043  * A set of analysis options used to control the behavior of an analysis |  | 
| 6044  * context. |  | 
| 6045  */ |  | 
| 6046 abstract class AnalysisOptions { |  | 
| 6047   /** |  | 
| 6048    * If analysis is to parse and analyze all function bodies, return `true`. |  | 
| 6049    * If analysis is to skip all function bodies, return `false`.  If analysis |  | 
| 6050    * is to parse and analyze function bodies in some sources and not in others, |  | 
| 6051    * throw an exception. |  | 
| 6052    * |  | 
| 6053    * This getter is deprecated; consider using [analyzeFunctionBodiesPredicate] |  | 
| 6054    * instead. |  | 
| 6055    */ |  | 
| 6056   @deprecated // Use this.analyzeFunctionBodiesPredicate |  | 
| 6057   bool get analyzeFunctionBodies; |  | 
| 6058 |  | 
| 6059   /** |  | 
| 6060    * Function that returns `true` if analysis is to parse and analyze function |  | 
| 6061    * bodies for a given source. |  | 
| 6062    */ |  | 
| 6063   AnalyzeFunctionBodiesPredicate get analyzeFunctionBodiesPredicate; |  | 
| 6064 |  | 
| 6065   /** |  | 
| 6066    * Return the maximum number of sources for which AST structures should be |  | 
| 6067    * kept in the cache. |  | 
| 6068    */ |  | 
| 6069   int get cacheSize; |  | 
| 6070 |  | 
| 6071   /** |  | 
| 6072    * Return `true` if analysis is to generate dart2js related hint results. |  | 
| 6073    */ |  | 
| 6074   bool get dart2jsHint; |  | 
| 6075 |  | 
| 6076   /** |  | 
| 6077    * Return `true` if analysis is to include the new async support. |  | 
| 6078    */ |  | 
| 6079   @deprecated // Always true |  | 
| 6080   bool get enableAsync; |  | 
| 6081 |  | 
| 6082   /** |  | 
| 6083    * Return `true` if analysis is to include the new deferred loading support. |  | 
| 6084    */ |  | 
| 6085   @deprecated // Always true |  | 
| 6086   bool get enableDeferredLoading; |  | 
| 6087 |  | 
| 6088   /** |  | 
| 6089    * Return `true` if analysis is to include the new enum support. |  | 
| 6090    */ |  | 
| 6091   @deprecated // Always true |  | 
| 6092   bool get enableEnum; |  | 
| 6093 |  | 
| 6094   /** |  | 
| 6095    * Return `true` to enable generic methods (DEP 22). |  | 
| 6096    */ |  | 
| 6097   bool get enableGenericMethods => null; |  | 
| 6098 |  | 
| 6099   /** |  | 
| 6100    * Return `true` to enable null-aware operators (DEP 9). |  | 
| 6101    */ |  | 
| 6102   @deprecated // Always true |  | 
| 6103   bool get enableNullAwareOperators; |  | 
| 6104 |  | 
| 6105   /** |  | 
| 6106    * Return `true` to strictly follow the specification when generating |  | 
| 6107    * warnings on "call" methods (fixes dartbug.com/21938). |  | 
| 6108    */ |  | 
| 6109   bool get enableStrictCallChecks; |  | 
| 6110 |  | 
| 6111   /** |  | 
| 6112    * Return `true` if errors, warnings and hints should be generated for sources |  | 
| 6113    * that are implicitly being analyzed. The default value is `true`. |  | 
| 6114    */ |  | 
| 6115   bool get generateImplicitErrors; |  | 
| 6116 |  | 
| 6117   /** |  | 
| 6118    * Return `true` if errors, warnings and hints should be generated for sources |  | 
| 6119    * in the SDK. The default value is `false`. |  | 
| 6120    */ |  | 
| 6121   bool get generateSdkErrors; |  | 
| 6122 |  | 
| 6123   /** |  | 
| 6124    * Return `true` if analysis is to generate hint results (e.g. type inference |  | 
| 6125    * based information and pub best practices). |  | 
| 6126    */ |  | 
| 6127   bool get hint; |  | 
| 6128 |  | 
| 6129   /** |  | 
| 6130    * Return `true` if incremental analysis should be used. |  | 
| 6131    */ |  | 
| 6132   bool get incremental; |  | 
| 6133 |  | 
| 6134   /** |  | 
| 6135    * A flag indicating whether incremental analysis should be used for API |  | 
| 6136    * changes. |  | 
| 6137    */ |  | 
| 6138   bool get incrementalApi; |  | 
| 6139 |  | 
| 6140   /** |  | 
| 6141    * A flag indicating whether validation should be performed after incremental |  | 
| 6142    * analysis. |  | 
| 6143    */ |  | 
| 6144   bool get incrementalValidation; |  | 
| 6145 |  | 
| 6146   /** |  | 
| 6147    * Return `true` if analysis is to generate lint warnings. |  | 
| 6148    */ |  | 
| 6149   bool get lint; |  | 
| 6150 |  | 
| 6151   /** |  | 
| 6152    * Return `true` if analysis is to parse comments. |  | 
| 6153    */ |  | 
| 6154   bool get preserveComments; |  | 
| 6155 } |  | 
| 6156 |  | 
| 6157 /** |  | 
| 6158  * A set of analysis options used to control the behavior of an analysis |  | 
| 6159  * context. |  | 
| 6160  */ |  | 
| 6161 class AnalysisOptionsImpl implements AnalysisOptions { |  | 
| 6162   /** |  | 
| 6163    * The maximum number of sources for which data should be kept in the cache. |  | 
| 6164    */ |  | 
| 6165   static const int DEFAULT_CACHE_SIZE = 64; |  | 
| 6166 |  | 
| 6167   /** |  | 
| 6168    * The default value for enabling deferred loading. |  | 
| 6169    */ |  | 
| 6170   @deprecated |  | 
| 6171   static bool DEFAULT_ENABLE_DEFERRED_LOADING = true; |  | 
| 6172 |  | 
| 6173   /** |  | 
| 6174    * The default value for enabling enum support. |  | 
| 6175    */ |  | 
| 6176   @deprecated |  | 
| 6177   static bool DEFAULT_ENABLE_ENUM = true; |  | 
| 6178 |  | 
| 6179   /** |  | 
| 6180    * A predicate indicating whether analysis is to parse and analyze function |  | 
| 6181    * bodies. |  | 
| 6182    */ |  | 
| 6183   AnalyzeFunctionBodiesPredicate _analyzeFunctionBodiesPredicate = |  | 
| 6184       _analyzeAllFunctionBodies; |  | 
| 6185 |  | 
| 6186   /** |  | 
| 6187    * The maximum number of sources for which AST structures should be kept in |  | 
| 6188    * the cache. |  | 
| 6189    */ |  | 
| 6190   int cacheSize = DEFAULT_CACHE_SIZE; |  | 
| 6191 |  | 
| 6192   /** |  | 
| 6193    * A flag indicating whether analysis is to generate dart2js related hint |  | 
| 6194    * results. |  | 
| 6195    */ |  | 
| 6196   bool dart2jsHint = true; |  | 
| 6197 |  | 
| 6198   /** |  | 
| 6199    * A flag indicating whether generic methods are to be supported (DEP 22). |  | 
| 6200    */ |  | 
| 6201   bool enableGenericMethods = false; |  | 
| 6202 |  | 
| 6203   /** |  | 
| 6204    * A flag indicating whether analysis is to strictly follow the specification |  | 
| 6205    * when generating warnings on "call" methods (fixes dartbug.com/21938). |  | 
| 6206    */ |  | 
| 6207   bool enableStrictCallChecks = false; |  | 
| 6208 |  | 
| 6209   /** |  | 
| 6210    * A flag indicating whether errors, warnings and hints should be generated |  | 
| 6211    * for sources that are implicitly being analyzed. |  | 
| 6212    */ |  | 
| 6213   bool generateImplicitErrors = true; |  | 
| 6214 |  | 
| 6215   /** |  | 
| 6216    * A flag indicating whether errors, warnings and hints should be generated |  | 
| 6217    * for sources in the SDK. |  | 
| 6218    */ |  | 
| 6219   bool generateSdkErrors = false; |  | 
| 6220 |  | 
| 6221   /** |  | 
| 6222    * A flag indicating whether analysis is to generate hint results (e.g. type |  | 
| 6223    * inference based information and pub best practices). |  | 
| 6224    */ |  | 
| 6225   bool hint = true; |  | 
| 6226 |  | 
| 6227   /** |  | 
| 6228    * A flag indicating whether incremental analysis should be used. |  | 
| 6229    */ |  | 
| 6230   bool incremental = false; |  | 
| 6231 |  | 
| 6232   /** |  | 
| 6233    * A flag indicating whether incremental analysis should be used for API |  | 
| 6234    * changes. |  | 
| 6235    */ |  | 
| 6236   bool incrementalApi = false; |  | 
| 6237 |  | 
| 6238   /** |  | 
| 6239    * A flag indicating whether validation should be performed after incremental |  | 
| 6240    * analysis. |  | 
| 6241    */ |  | 
| 6242   bool incrementalValidation = false; |  | 
| 6243 |  | 
| 6244   /** |  | 
| 6245    * A flag indicating whether analysis is to generate lint warnings. |  | 
| 6246    */ |  | 
| 6247   bool lint = false; |  | 
| 6248 |  | 
| 6249   /** |  | 
| 6250    * A flag indicating whether analysis is to parse comments. |  | 
| 6251    */ |  | 
| 6252   bool preserveComments = true; |  | 
| 6253 |  | 
| 6254   /** |  | 
| 6255    * Initialize a newly created set of analysis options to have their default |  | 
| 6256    * values. |  | 
| 6257    */ |  | 
| 6258   AnalysisOptionsImpl(); |  | 
| 6259 |  | 
| 6260   /** |  | 
| 6261    * Initialize a newly created set of analysis options to have the same values |  | 
| 6262    * as those in the given set of analysis [options]. |  | 
| 6263    */ |  | 
| 6264   @deprecated // Use new AnalysisOptionsImpl.from(options) |  | 
| 6265   AnalysisOptionsImpl.con1(AnalysisOptions options) { |  | 
| 6266     analyzeFunctionBodiesPredicate = options.analyzeFunctionBodiesPredicate; |  | 
| 6267     cacheSize = options.cacheSize; |  | 
| 6268     dart2jsHint = options.dart2jsHint; |  | 
| 6269     enableStrictCallChecks = options.enableStrictCallChecks; |  | 
| 6270     generateImplicitErrors = options.generateImplicitErrors; |  | 
| 6271     generateSdkErrors = options.generateSdkErrors; |  | 
| 6272     hint = options.hint; |  | 
| 6273     incremental = options.incremental; |  | 
| 6274     incrementalApi = options.incrementalApi; |  | 
| 6275     incrementalValidation = options.incrementalValidation; |  | 
| 6276     lint = options.lint; |  | 
| 6277     preserveComments = options.preserveComments; |  | 
| 6278   } |  | 
| 6279 |  | 
| 6280   /** |  | 
| 6281    * Initialize a newly created set of analysis options to have the same values |  | 
| 6282    * as those in the given set of analysis [options]. |  | 
| 6283    */ |  | 
| 6284   AnalysisOptionsImpl.from(AnalysisOptions options) { |  | 
| 6285     analyzeFunctionBodiesPredicate = options.analyzeFunctionBodiesPredicate; |  | 
| 6286     cacheSize = options.cacheSize; |  | 
| 6287     dart2jsHint = options.dart2jsHint; |  | 
| 6288     enableStrictCallChecks = options.enableStrictCallChecks; |  | 
| 6289     generateImplicitErrors = options.generateImplicitErrors; |  | 
| 6290     generateSdkErrors = options.generateSdkErrors; |  | 
| 6291     hint = options.hint; |  | 
| 6292     incremental = options.incremental; |  | 
| 6293     incrementalApi = options.incrementalApi; |  | 
| 6294     incrementalValidation = options.incrementalValidation; |  | 
| 6295     lint = options.lint; |  | 
| 6296     preserveComments = options.preserveComments; |  | 
| 6297   } |  | 
| 6298 |  | 
| 6299   bool get analyzeFunctionBodies { |  | 
| 6300     if (identical(analyzeFunctionBodiesPredicate, _analyzeAllFunctionBodies)) { |  | 
| 6301       return true; |  | 
| 6302     } else if (identical( |  | 
| 6303         analyzeFunctionBodiesPredicate, _analyzeNoFunctionBodies)) { |  | 
| 6304       return false; |  | 
| 6305     } else { |  | 
| 6306       throw new StateError('analyzeFunctionBodiesPredicate in use'); |  | 
| 6307     } |  | 
| 6308   } |  | 
| 6309 |  | 
| 6310   set analyzeFunctionBodies(bool value) { |  | 
| 6311     if (value) { |  | 
| 6312       analyzeFunctionBodiesPredicate = _analyzeAllFunctionBodies; |  | 
| 6313     } else { |  | 
| 6314       analyzeFunctionBodiesPredicate = _analyzeNoFunctionBodies; |  | 
| 6315     } |  | 
| 6316   } |  | 
| 6317 |  | 
| 6318   @override |  | 
| 6319   AnalyzeFunctionBodiesPredicate get analyzeFunctionBodiesPredicate => |  | 
| 6320       _analyzeFunctionBodiesPredicate; |  | 
| 6321 |  | 
| 6322   set analyzeFunctionBodiesPredicate(AnalyzeFunctionBodiesPredicate value) { |  | 
| 6323     if (value == null) { |  | 
| 6324       throw new ArgumentError.notNull('analyzeFunctionBodiesPredicate'); |  | 
| 6325     } |  | 
| 6326     _analyzeFunctionBodiesPredicate = value; |  | 
| 6327   } |  | 
| 6328 |  | 
| 6329   @deprecated |  | 
| 6330   @override |  | 
| 6331   bool get enableAsync => true; |  | 
| 6332 |  | 
| 6333   @deprecated |  | 
| 6334   void set enableAsync(bool enable) { |  | 
| 6335     // Async support cannot be disabled |  | 
| 6336   } |  | 
| 6337 |  | 
| 6338   @deprecated |  | 
| 6339   @override |  | 
| 6340   bool get enableDeferredLoading => true; |  | 
| 6341 |  | 
| 6342   @deprecated |  | 
| 6343   void set enableDeferredLoading(bool enable) { |  | 
| 6344     // Deferred loading support cannot be disabled |  | 
| 6345   } |  | 
| 6346 |  | 
| 6347   @deprecated |  | 
| 6348   @override |  | 
| 6349   bool get enableEnum => true; |  | 
| 6350 |  | 
| 6351   @deprecated |  | 
| 6352   void set enableEnum(bool enable) { |  | 
| 6353     // Enum support cannot be disabled |  | 
| 6354   } |  | 
| 6355 |  | 
| 6356   @deprecated |  | 
| 6357   @override |  | 
| 6358   bool get enableNullAwareOperators => true; |  | 
| 6359 |  | 
| 6360   @deprecated |  | 
| 6361   void set enableNullAwareOperators(bool enable) { |  | 
| 6362     // Null-aware operator support cannot be disabled |  | 
| 6363   } |  | 
| 6364 |  | 
| 6365   /** |  | 
| 6366    * Predicate used for [analyzeFunctionBodiesPredicate] when |  | 
| 6367    * [analyzeFunctionBodies] is set to `true`. |  | 
| 6368    */ |  | 
| 6369   static bool _analyzeAllFunctionBodies(Source _) => true; |  | 
| 6370 |  | 
| 6371   /** |  | 
| 6372    * Predicate used for [analyzeFunctionBodiesPredicate] when |  | 
| 6373    * [analyzeFunctionBodies] is set to `false`. |  | 
| 6374    */ |  | 
| 6375   static bool _analyzeNoFunctionBodies(Source _) => false; |  | 
| 6376 } |  | 
| 6377 |  | 
| 6378 /** |  | 
| 6379  * |  | 
| 6380  */ |  | 
| 6381 class AnalysisResult { |  | 
| 6382   /** |  | 
| 6383    * The change notices associated with this result, or `null` if there were no |  | 
| 6384    * changes and there is no more work to be done. |  | 
| 6385    */ |  | 
| 6386   final List<ChangeNotice> _notices; |  | 
| 6387 |  | 
| 6388   /** |  | 
| 6389    * The number of milliseconds required to determine which task was to be |  | 
| 6390    * performed. |  | 
| 6391    */ |  | 
| 6392   final int getTime; |  | 
| 6393 |  | 
| 6394   /** |  | 
| 6395    * The name of the class of the task that was performed. |  | 
| 6396    */ |  | 
| 6397   final String taskClassName; |  | 
| 6398 |  | 
| 6399   /** |  | 
| 6400    * The number of milliseconds required to perform the task. |  | 
| 6401    */ |  | 
| 6402   final int performTime; |  | 
| 6403 |  | 
| 6404   /** |  | 
| 6405    * Initialize a newly created analysis result to have the given values. The |  | 
| 6406    * [notices] is the change notices associated with this result. The [getTime] |  | 
| 6407    * is the number of milliseconds required to determine which task was to be |  | 
| 6408    * performed. The [taskClassName] is the name of the class of the task that |  | 
| 6409    * was performed. The [performTime] is the number of milliseconds required to |  | 
| 6410    * perform the task. |  | 
| 6411    */ |  | 
| 6412   AnalysisResult( |  | 
| 6413       this._notices, this.getTime, this.taskClassName, this.performTime); |  | 
| 6414 |  | 
| 6415   /** |  | 
| 6416    * Return the change notices associated with this result, or `null` if there |  | 
| 6417    * were no changes and there is no more work to be done. |  | 
| 6418    */ |  | 
| 6419   List<ChangeNotice> get changeNotices => _notices; |  | 
| 6420 |  | 
| 6421   /** |  | 
| 6422    * Return `true` if there is more to be performed after the task that was |  | 
| 6423    * performed. |  | 
| 6424    */ |  | 
| 6425   bool get hasMoreWork => _notices != null; |  | 
| 6426 } |  | 
| 6427 |  | 
| 6428 /** |  | 
| 6429  * An analysis task. |  | 
| 6430  */ |  | 
| 6431 abstract class AnalysisTask { |  | 
| 6432   /** |  | 
| 6433    * The context in which the task is to be performed. |  | 
| 6434    */ |  | 
| 6435   final InternalAnalysisContext context; |  | 
| 6436 |  | 
| 6437   /** |  | 
| 6438    * The exception that was thrown while performing this task, or `null` if the |  | 
| 6439    * task completed successfully. |  | 
| 6440    */ |  | 
| 6441   CaughtException _thrownException; |  | 
| 6442 |  | 
| 6443   /** |  | 
| 6444    * Initialize a newly created task to perform analysis within the given |  | 
| 6445    * [context]. |  | 
| 6446    */ |  | 
| 6447   AnalysisTask(this.context); |  | 
| 6448 |  | 
| 6449   /** |  | 
| 6450    * Return the exception that was thrown while performing this task, or `null` |  | 
| 6451    * if the task completed successfully. |  | 
| 6452    */ |  | 
| 6453   CaughtException get exception => _thrownException; |  | 
| 6454 |  | 
| 6455   /** |  | 
| 6456    * Return a textual description of this task. |  | 
| 6457    */ |  | 
| 6458   String get taskDescription; |  | 
| 6459 |  | 
| 6460   /** |  | 
| 6461    * Use the given [visitor] to visit this task. Throws an [AnalysisException] |  | 
| 6462    * if the visitor throws the exception. |  | 
| 6463    */ |  | 
| 6464   accept(AnalysisTaskVisitor visitor); |  | 
| 6465 |  | 
| 6466   /** |  | 
| 6467    * Perform this analysis task, protected by an exception handler. Throws an |  | 
| 6468    * [AnalysisException] if an exception occurs while performing the task. |  | 
| 6469    */ |  | 
| 6470   void internalPerform(); |  | 
| 6471 |  | 
| 6472   /** |  | 
| 6473    * Perform this analysis task and use the given [visitor] to visit this task |  | 
| 6474    * after it has completed. Throws an [AnalysisException] if the visitor throws |  | 
| 6475    * the exception. |  | 
| 6476    */ |  | 
| 6477   Object perform(AnalysisTaskVisitor visitor) { |  | 
| 6478     try { |  | 
| 6479       _safelyPerform(); |  | 
| 6480     } on AnalysisException catch (exception, stackTrace) { |  | 
| 6481       _thrownException = new CaughtException(exception, stackTrace); |  | 
| 6482       AnalysisEngine.instance.logger.logInformation( |  | 
| 6483           "Task failed: $taskDescription", |  | 
| 6484           new CaughtException(exception, stackTrace)); |  | 
| 6485     } |  | 
| 6486     return PerformanceStatistics.analysisTaskVisitor |  | 
| 6487         .makeCurrentWhile(() => accept(visitor)); |  | 
| 6488   } |  | 
| 6489 |  | 
| 6490   @override |  | 
| 6491   String toString() => taskDescription; |  | 
| 6492 |  | 
| 6493   /** |  | 
| 6494    * Perform this analysis task, ensuring that all exceptions are wrapped in an |  | 
| 6495    * [AnalysisException]. Throws an [AnalysisException] if any exception occurs |  | 
| 6496    * while performing the task |  | 
| 6497    */ |  | 
| 6498   void _safelyPerform() { |  | 
| 6499     try { |  | 
| 6500       String contextName = context.name; |  | 
| 6501       if (contextName == null) { |  | 
| 6502         contextName = 'unnamed'; |  | 
| 6503       } |  | 
| 6504       AnalysisEngine.instance.instrumentationService.logAnalysisTask( |  | 
| 6505           contextName, taskDescription); |  | 
| 6506       internalPerform(); |  | 
| 6507     } on AnalysisException { |  | 
| 6508       rethrow; |  | 
| 6509     } catch (exception, stackTrace) { |  | 
| 6510       throw new AnalysisException( |  | 
| 6511           exception.toString(), new CaughtException(exception, stackTrace)); |  | 
| 6512     } |  | 
| 6513   } |  | 
| 6514 } |  | 
| 6515 |  | 
| 6516 /** |  | 
| 6517  * An object used to visit tasks. While tasks are not structured in any |  | 
| 6518  * interesting way, this class provides the ability to dispatch to an |  | 
| 6519  * appropriate method. |  | 
| 6520  */ |  | 
| 6521 abstract class AnalysisTaskVisitor<E> { |  | 
| 6522   /** |  | 
| 6523    * Visit the given [task], returning the result of the visit. This method will |  | 
| 6524    * throw an AnalysisException if the visitor throws an exception. |  | 
| 6525    */ |  | 
| 6526   E visitGenerateDartErrorsTask(GenerateDartErrorsTask task); |  | 
| 6527 |  | 
| 6528   /** |  | 
| 6529    * Visit the given [task], returning the result of the visit. This method will |  | 
| 6530    * throw an AnalysisException if the visitor throws an exception. |  | 
| 6531    */ |  | 
| 6532   E visitGenerateDartHintsTask(GenerateDartHintsTask task); |  | 
| 6533 |  | 
| 6534   /** |  | 
| 6535    * Visit the given [task], returning the result of the visit. This method will |  | 
| 6536    * throw an AnalysisException if the visitor throws an exception. |  | 
| 6537    */ |  | 
| 6538   E visitGenerateDartLintsTask(GenerateDartLintsTask task); |  | 
| 6539 |  | 
| 6540   /** |  | 
| 6541    * Visit the given [task], returning the result of the visit. This method will |  | 
| 6542    * throw an AnalysisException if the visitor throws an exception. |  | 
| 6543    */ |  | 
| 6544   E visitGetContentTask(GetContentTask task); |  | 
| 6545 |  | 
| 6546   /** |  | 
| 6547    * Visit the given [task], returning the result of the visit. This method will |  | 
| 6548    * throw an AnalysisException if the visitor throws an exception. |  | 
| 6549    */ |  | 
| 6550   E visitIncrementalAnalysisTask( |  | 
| 6551       IncrementalAnalysisTask incrementalAnalysisTask); |  | 
| 6552 |  | 
| 6553   /** |  | 
| 6554    * Visit the given [task], returning the result of the visit. This method will |  | 
| 6555    * throw an AnalysisException if the visitor throws an exception. |  | 
| 6556    */ |  | 
| 6557   E visitParseDartTask(ParseDartTask task); |  | 
| 6558 |  | 
| 6559   /** |  | 
| 6560    * Visit the given [task], returning the result of the visit. This method will |  | 
| 6561    * throw an AnalysisException if the visitor throws an exception. |  | 
| 6562    */ |  | 
| 6563   E visitParseHtmlTask(ParseHtmlTask task); |  | 
| 6564 |  | 
| 6565   /** |  | 
| 6566    * Visit the given [task], returning the result of the visit. This method will |  | 
| 6567    * throw an AnalysisException if the visitor throws an exception. |  | 
| 6568    */ |  | 
| 6569   E visitResolveDartLibraryCycleTask(ResolveDartLibraryCycleTask task); |  | 
| 6570 |  | 
| 6571   /** |  | 
| 6572    * Visit the given [task], returning the result of the visit. This method will |  | 
| 6573    * throw an AnalysisException if the visitor throws an exception. |  | 
| 6574    */ |  | 
| 6575   E visitResolveDartLibraryTask(ResolveDartLibraryTask task); |  | 
| 6576 |  | 
| 6577   /** |  | 
| 6578    * Visit the given [task], returning the result of the visit. This method will |  | 
| 6579    * throw an AnalysisException if the visitor throws an exception. |  | 
| 6580    */ |  | 
| 6581   E visitResolveDartUnitTask(ResolveDartUnitTask task); |  | 
| 6582 |  | 
| 6583   /** |  | 
| 6584    * Visit the given [task], returning the result of the visit. This method will |  | 
| 6585    * throw an AnalysisException if the visitor throws an exception. |  | 
| 6586    */ |  | 
| 6587   E visitResolveHtmlTask(ResolveHtmlTask task); |  | 
| 6588 |  | 
| 6589   /** |  | 
| 6590    * Visit the given [task], returning the result of the visit. This method will |  | 
| 6591    * throw an AnalysisException if the visitor throws an exception. |  | 
| 6592    */ |  | 
| 6593   E visitScanDartTask(ScanDartTask task); |  | 
| 6594 } |  | 
| 6595 |  | 
| 6596 /** |  | 
| 6597  * A `CachedResult` is a single analysis result that is stored in a |  | 
| 6598  * [SourceEntry]. |  | 
| 6599  */ |  | 
| 6600 class CachedResult<E> { |  | 
| 6601   /** |  | 
| 6602    * The state of the cached value. |  | 
| 6603    */ |  | 
| 6604   CacheState state; |  | 
| 6605 |  | 
| 6606   /** |  | 
| 6607    * The value being cached, or `null` if there is no value (for example, when |  | 
| 6608    * the [state] is [CacheState.INVALID]. |  | 
| 6609    */ |  | 
| 6610   E value; |  | 
| 6611 |  | 
| 6612   /** |  | 
| 6613    * Initialize a newly created result holder to represent the value of data |  | 
| 6614    * described by the given [descriptor]. |  | 
| 6615    */ |  | 
| 6616   CachedResult(DataDescriptor descriptor) { |  | 
| 6617     state = CacheState.INVALID; |  | 
| 6618     value = descriptor.defaultValue; |  | 
| 6619   } |  | 
| 6620 } |  | 
| 6621 |  | 
| 6622 /** |  | 
| 6623  * A single partition in an LRU cache of information related to analysis. |  | 
| 6624  */ |  | 
| 6625 abstract class CachePartition { |  | 
| 6626   /** |  | 
| 6627    * The context that owns this partition. Multiple contexts can reference a |  | 
| 6628    * partition, but only one context can own it. |  | 
| 6629    */ |  | 
| 6630   final InternalAnalysisContext context; |  | 
| 6631 |  | 
| 6632   /** |  | 
| 6633    * The maximum number of sources for which AST structures should be kept in |  | 
| 6634    * the cache. |  | 
| 6635    */ |  | 
| 6636   int _maxCacheSize = 0; |  | 
| 6637 |  | 
| 6638   /** |  | 
| 6639    * The policy used to determine which pieces of data to remove from the cache. |  | 
| 6640    */ |  | 
| 6641   final CacheRetentionPolicy _retentionPolicy; |  | 
| 6642 |  | 
| 6643   /** |  | 
| 6644    * A table mapping the sources belonging to this partition to the information |  | 
| 6645    * known about those sources. |  | 
| 6646    */ |  | 
| 6647   HashMap<Source, SourceEntry> _sourceMap = new HashMap<Source, SourceEntry>(); |  | 
| 6648 |  | 
| 6649   /** |  | 
| 6650    * A list containing the most recently accessed sources with the most recently |  | 
| 6651    * used at the end of the list. When more sources are added than the maximum |  | 
| 6652    * allowed then the least recently used source will be removed and will have |  | 
| 6653    * it's cached AST structure flushed. |  | 
| 6654    */ |  | 
| 6655   List<Source> _recentlyUsed; |  | 
| 6656 |  | 
| 6657   /** |  | 
| 6658    * Initialize a newly created cache to maintain at most [maxCacheSize] AST |  | 
| 6659    * structures in the cache. The cache is owned by the give [context], and the |  | 
| 6660    * [retentionPolicy] will be used to determine which pieces of data to remove |  | 
| 6661    * from the cache. |  | 
| 6662    */ |  | 
| 6663   CachePartition(this.context, int maxCacheSize, this._retentionPolicy) { |  | 
| 6664     this._maxCacheSize = maxCacheSize; |  | 
| 6665     _recentlyUsed = new List<Source>(); |  | 
| 6666   } |  | 
| 6667 |  | 
| 6668   /** |  | 
| 6669    * Return the number of entries in this partition that have an AST associated |  | 
| 6670    * with them. |  | 
| 6671    */ |  | 
| 6672   int get astSize { |  | 
| 6673     int astSize = 0; |  | 
| 6674     int count = _recentlyUsed.length; |  | 
| 6675     for (int i = 0; i < count; i++) { |  | 
| 6676       Source source = _recentlyUsed[i]; |  | 
| 6677       SourceEntry sourceEntry = _sourceMap[source]; |  | 
| 6678       if (sourceEntry is DartEntry) { |  | 
| 6679         if (sourceEntry.anyParsedCompilationUnit != null) { |  | 
| 6680           astSize++; |  | 
| 6681         } |  | 
| 6682       } else if (sourceEntry is HtmlEntry) { |  | 
| 6683         if (sourceEntry.anyParsedUnit != null) { |  | 
| 6684           astSize++; |  | 
| 6685         } |  | 
| 6686       } |  | 
| 6687     } |  | 
| 6688     return astSize; |  | 
| 6689   } |  | 
| 6690 |  | 
| 6691   /** |  | 
| 6692    * Return a table mapping the sources known to the context to the information |  | 
| 6693    * known about the source. |  | 
| 6694    * |  | 
| 6695    * <b>Note:</b> This method is only visible for use by [AnalysisCache] and |  | 
| 6696    * should not be used for any other purpose. |  | 
| 6697    */ |  | 
| 6698   Map<Source, SourceEntry> get map => _sourceMap; |  | 
| 6699 |  | 
| 6700   /** |  | 
| 6701    * Set the maximum size of the cache to the given [size]. |  | 
| 6702    */ |  | 
| 6703   void set maxCacheSize(int size) { |  | 
| 6704     _maxCacheSize = size; |  | 
| 6705     while (_recentlyUsed.length > _maxCacheSize) { |  | 
| 6706       if (!_flushAstFromCache()) { |  | 
| 6707         break; |  | 
| 6708       } |  | 
| 6709     } |  | 
| 6710   } |  | 
| 6711 |  | 
| 6712   /** |  | 
| 6713    * Record that the AST associated with the given source was just read from the |  | 
| 6714    * cache. |  | 
| 6715    */ |  | 
| 6716   void accessedAst(Source source) { |  | 
| 6717     if (_recentlyUsed.remove(source)) { |  | 
| 6718       _recentlyUsed.add(source); |  | 
| 6719       return; |  | 
| 6720     } |  | 
| 6721     while (_recentlyUsed.length >= _maxCacheSize) { |  | 
| 6722       if (!_flushAstFromCache()) { |  | 
| 6723         break; |  | 
| 6724       } |  | 
| 6725     } |  | 
| 6726     _recentlyUsed.add(source); |  | 
| 6727   } |  | 
| 6728 |  | 
| 6729   /** |  | 
| 6730    * Return `true` if the given [source] is contained in this partition. |  | 
| 6731    */ |  | 
| 6732   bool contains(Source source); |  | 
| 6733 |  | 
| 6734   /** |  | 
| 6735    * Return the entry associated with the given [source]. |  | 
| 6736    */ |  | 
| 6737   SourceEntry get(Source source) => _sourceMap[source]; |  | 
| 6738 |  | 
| 6739   /** |  | 
| 6740    * Return an iterator returning all of the map entries mapping sources to |  | 
| 6741    * cache entries. |  | 
| 6742    */ |  | 
| 6743   MapIterator<Source, SourceEntry> iterator() => |  | 
| 6744       new SingleMapIterator<Source, SourceEntry>(_sourceMap); |  | 
| 6745 |  | 
| 6746   /** |  | 
| 6747    * Associate the given [entry] with the given [source]. |  | 
| 6748    */ |  | 
| 6749   void put(Source source, SourceEntry entry) { |  | 
| 6750     entry.fixExceptionState(); |  | 
| 6751     _sourceMap[source] = entry; |  | 
| 6752   } |  | 
| 6753 |  | 
| 6754   /** |  | 
| 6755    * Remove all information related to the given [source] from this cache. |  | 
| 6756    */ |  | 
| 6757   void remove(Source source) { |  | 
| 6758     _recentlyUsed.remove(source); |  | 
| 6759     _sourceMap.remove(source); |  | 
| 6760   } |  | 
| 6761 |  | 
| 6762   /** |  | 
| 6763    * Record that the AST associated with the given [source] was just removed |  | 
| 6764    * from the cache. |  | 
| 6765    */ |  | 
| 6766   void removedAst(Source source) { |  | 
| 6767     _recentlyUsed.remove(source); |  | 
| 6768   } |  | 
| 6769 |  | 
| 6770   /** |  | 
| 6771    * Return the number of sources that are mapped to cache entries. |  | 
| 6772    */ |  | 
| 6773   int size() => _sourceMap.length; |  | 
| 6774 |  | 
| 6775   /** |  | 
| 6776    * Record that the AST associated with the given [source] was just stored to |  | 
| 6777    * the cache. |  | 
| 6778    */ |  | 
| 6779   void storedAst(Source source) { |  | 
| 6780     if (_recentlyUsed.contains(source)) { |  | 
| 6781       return; |  | 
| 6782     } |  | 
| 6783     while (_recentlyUsed.length >= _maxCacheSize) { |  | 
| 6784       if (!_flushAstFromCache()) { |  | 
| 6785         break; |  | 
| 6786       } |  | 
| 6787     } |  | 
| 6788     _recentlyUsed.add(source); |  | 
| 6789   } |  | 
| 6790 |  | 
| 6791   /** |  | 
| 6792    * Attempt to flush one AST structure from the cache. Return `true` if a |  | 
| 6793    * structure was flushed. |  | 
| 6794    */ |  | 
| 6795   bool _flushAstFromCache() { |  | 
| 6796     Source removedSource = _removeAstToFlush(); |  | 
| 6797     if (removedSource == null) { |  | 
| 6798       return false; |  | 
| 6799     } |  | 
| 6800     SourceEntry sourceEntry = _sourceMap[removedSource]; |  | 
| 6801     if (sourceEntry is HtmlEntry) { |  | 
| 6802       HtmlEntry htmlEntry = sourceEntry; |  | 
| 6803       htmlEntry.flushAstStructures(); |  | 
| 6804     } else if (sourceEntry is DartEntry) { |  | 
| 6805       DartEntry dartEntry = sourceEntry; |  | 
| 6806       dartEntry.flushAstStructures(); |  | 
| 6807     } |  | 
| 6808     return true; |  | 
| 6809   } |  | 
| 6810 |  | 
| 6811   /** |  | 
| 6812    * Remove and return one source from the list of recently used sources whose |  | 
| 6813    * AST structure can be flushed from the cache. The source that will be |  | 
| 6814    * returned will be the source that has been unreferenced for the longest |  | 
| 6815    * period of time but that is not a priority for analysis. |  | 
| 6816    */ |  | 
| 6817   Source _removeAstToFlush() { |  | 
| 6818     int sourceToRemove = -1; |  | 
| 6819     for (int i = 0; i < _recentlyUsed.length; i++) { |  | 
| 6820       Source source = _recentlyUsed[i]; |  | 
| 6821       RetentionPriority priority = |  | 
| 6822           _retentionPolicy.getAstPriority(source, _sourceMap[source]); |  | 
| 6823       if (priority == RetentionPriority.LOW) { |  | 
| 6824         return _recentlyUsed.removeAt(i); |  | 
| 6825       } else if (priority == RetentionPriority.MEDIUM && sourceToRemove < 0) { |  | 
| 6826         sourceToRemove = i; |  | 
| 6827       } |  | 
| 6828     } |  | 
| 6829     if (sourceToRemove < 0) { |  | 
| 6830       // This happens if the retention policy returns a priority of HIGH for all |  | 
| 6831       // of the sources that have been recently used. This is the case, for |  | 
| 6832       // example, when the list of priority sources is bigger than the current |  | 
| 6833       // cache size. |  | 
| 6834       return null; |  | 
| 6835     } |  | 
| 6836     return _recentlyUsed.removeAt(sourceToRemove); |  | 
| 6837   } |  | 
| 6838 } |  | 
| 6839 |  | 
| 6840 /** |  | 
| 6841  * An object used to determine how important it is for data to be retained in |  | 
| 6842  * the analysis cache. |  | 
| 6843  */ |  | 
| 6844 abstract class CacheRetentionPolicy { |  | 
| 6845   /** |  | 
| 6846    * Return the priority of retaining the AST structure for the given [source]. |  | 
| 6847    */ |  | 
| 6848   RetentionPriority getAstPriority(Source source, SourceEntry sourceEntry); |  | 
| 6849 } |  | 
| 6850 |  | 
| 6851 /** |  | 
| 6852  * The possible states of cached data. |  | 
| 6853  */ |  | 
| 6854 class CacheState extends Enum<CacheState> { |  | 
| 6855   /** |  | 
| 6856    * The data is not in the cache and the last time an attempt was made to |  | 
| 6857    * compute the data an exception occurred, making it pointless to attempt to |  | 
| 6858    * compute the data again. |  | 
| 6859    * |  | 
| 6860    * Valid Transitions: |  | 
| 6861    * * [INVALID] if a source was modified that might cause the data to be |  | 
| 6862    *   computable |  | 
| 6863    */ |  | 
| 6864   static const CacheState ERROR = const CacheState('ERROR', 0); |  | 
| 6865 |  | 
| 6866   /** |  | 
| 6867    * The data is not in the cache because it was flushed from the cache in order |  | 
| 6868    * to control memory usage. If the data is recomputed, results do not need to |  | 
| 6869    * be reported. |  | 
| 6870    * |  | 
| 6871    * Valid Transitions: |  | 
| 6872    * * [IN_PROCESS] if the data is being recomputed |  | 
| 6873    * * [INVALID] if a source was modified that causes the data to need to be |  | 
| 6874    *   recomputed |  | 
| 6875    */ |  | 
| 6876   static const CacheState FLUSHED = const CacheState('FLUSHED', 1); |  | 
| 6877 |  | 
| 6878   /** |  | 
| 6879    * The data might or might not be in the cache but is in the process of being |  | 
| 6880    * recomputed. |  | 
| 6881    * |  | 
| 6882    * Valid Transitions: |  | 
| 6883    * * [ERROR] if an exception occurred while trying to compute the data |  | 
| 6884    * * [VALID] if the data was successfully computed and stored in the cache |  | 
| 6885    */ |  | 
| 6886   static const CacheState IN_PROCESS = const CacheState('IN_PROCESS', 2); |  | 
| 6887 |  | 
| 6888   /** |  | 
| 6889    * The data is not in the cache and needs to be recomputed so that results can |  | 
| 6890    * be reported. |  | 
| 6891    * |  | 
| 6892    * Valid Transitions: |  | 
| 6893    * * [IN_PROCESS] if an attempt is being made to recompute the data |  | 
| 6894    */ |  | 
| 6895   static const CacheState INVALID = const CacheState('INVALID', 3); |  | 
| 6896 |  | 
| 6897   /** |  | 
| 6898    * The data is in the cache and up-to-date. |  | 
| 6899    * |  | 
| 6900    * Valid Transitions: |  | 
| 6901    * * [FLUSHED] if the data is removed in order to manage memory usage |  | 
| 6902    * * [INVALID] if a source was modified in such a way as to invalidate the |  | 
| 6903    *   previous data |  | 
| 6904    */ |  | 
| 6905   static const CacheState VALID = const CacheState('VALID', 4); |  | 
| 6906 |  | 
| 6907   static const List<CacheState> values = const [ |  | 
| 6908     ERROR, |  | 
| 6909     FLUSHED, |  | 
| 6910     IN_PROCESS, |  | 
| 6911     INVALID, |  | 
| 6912     VALID |  | 
| 6913   ]; |  | 
| 6914 |  | 
| 6915   const CacheState(String name, int ordinal) : super(name, ordinal); |  | 
| 6916 } |  | 
| 6917 |  | 
| 6918 /** |  | 
| 6919  * An object that represents a change to the analysis results associated with a |  | 
| 6920  * given source. |  | 
| 6921  */ |  | 
| 6922 abstract class ChangeNotice implements AnalysisErrorInfo { |  | 
| 6923   /** |  | 
| 6924    * The parsed, but maybe not resolved Dart AST that changed as a result of |  | 
| 6925    * the analysis, or `null` if the AST was not changed. |  | 
| 6926    */ |  | 
| 6927   CompilationUnit get parsedDartUnit; |  | 
| 6928 |  | 
| 6929   /** |  | 
| 6930    * The fully resolved Dart AST that changed as a result of the analysis, or |  | 
| 6931    * `null` if the AST was not changed. |  | 
| 6932    */ |  | 
| 6933   CompilationUnit get resolvedDartUnit; |  | 
| 6934 |  | 
| 6935   /** |  | 
| 6936    * The fully resolved HTML AST that changed as a result of the analysis, or |  | 
| 6937    * `null` if the AST was not changed. |  | 
| 6938    */ |  | 
| 6939   @deprecated |  | 
| 6940   ht.HtmlUnit get resolvedHtmlUnit; |  | 
| 6941 |  | 
| 6942   /** |  | 
| 6943    * Return the source for which the result is being reported. |  | 
| 6944    */ |  | 
| 6945   Source get source; |  | 
| 6946 } |  | 
| 6947 |  | 
| 6948 /** |  | 
| 6949  * An implementation of a [ChangeNotice]. |  | 
| 6950  */ |  | 
| 6951 class ChangeNoticeImpl implements ChangeNotice { |  | 
| 6952   /** |  | 
| 6953    * An empty list of change notices. |  | 
| 6954    */ |  | 
| 6955   static const List<ChangeNoticeImpl> EMPTY_LIST = const <ChangeNoticeImpl>[]; |  | 
| 6956 |  | 
| 6957   /** |  | 
| 6958    * The source for which the result is being reported. |  | 
| 6959    */ |  | 
| 6960   final Source source; |  | 
| 6961 |  | 
| 6962   /** |  | 
| 6963    * The parsed, but maybe not resolved Dart AST that changed as a result of |  | 
| 6964    * the analysis, or `null` if the AST was not changed. |  | 
| 6965    */ |  | 
| 6966   CompilationUnit parsedDartUnit; |  | 
| 6967 |  | 
| 6968   /** |  | 
| 6969    * The fully resolved Dart AST that changed as a result of the analysis, or |  | 
| 6970    * `null` if the AST was not changed. |  | 
| 6971    */ |  | 
| 6972   CompilationUnit resolvedDartUnit; |  | 
| 6973 |  | 
| 6974   /** |  | 
| 6975    * The fully resolved HTML AST that changed as a result of the analysis, or |  | 
| 6976    * `null` if the AST was not changed. |  | 
| 6977    */ |  | 
| 6978   @deprecated |  | 
| 6979   ht.HtmlUnit resolvedHtmlUnit; |  | 
| 6980 |  | 
| 6981   /** |  | 
| 6982    * The errors that changed as a result of the analysis, or `null` if errors |  | 
| 6983    * were not changed. |  | 
| 6984    */ |  | 
| 6985   List<AnalysisError> _errors; |  | 
| 6986 |  | 
| 6987   /** |  | 
| 6988    * The line information associated with the source, or `null` if errors were |  | 
| 6989    * not changed. |  | 
| 6990    */ |  | 
| 6991   LineInfo _lineInfo; |  | 
| 6992 |  | 
| 6993   /** |  | 
| 6994    * Initialize a newly created notice associated with the given source. |  | 
| 6995    * |  | 
| 6996    * @param source the source for which the change is being reported |  | 
| 6997    */ |  | 
| 6998   ChangeNoticeImpl(this.source); |  | 
| 6999 |  | 
| 7000   @override |  | 
| 7001   List<AnalysisError> get errors => _errors; |  | 
| 7002 |  | 
| 7003   @override |  | 
| 7004   LineInfo get lineInfo => _lineInfo; |  | 
| 7005 |  | 
| 7006   /** |  | 
| 7007    * Set the errors that changed as a result of the analysis to the given |  | 
| 7008    * [errors] and set the line information to the given [lineInfo]. |  | 
| 7009    */ |  | 
| 7010   void setErrors(List<AnalysisError> errors, LineInfo lineInfo) { |  | 
| 7011     this._errors = errors; |  | 
| 7012     this._lineInfo = lineInfo; |  | 
| 7013     if (lineInfo == null) { |  | 
| 7014       AnalysisEngine.instance.logger.logInformation("No line info: $source", |  | 
| 7015           new CaughtException(new AnalysisException(), null)); |  | 
| 7016     } |  | 
| 7017   } |  | 
| 7018 |  | 
| 7019   @override |  | 
| 7020   String toString() => "Changes for ${source.fullName}"; |  | 
| 7021 } |  | 
| 7022 |  | 
| 7023 /** |  | 
| 7024  * An indication of which sources have been added, changed, removed, or deleted. |  | 
| 7025  * In the case of a changed source, there are multiple ways of indicating the |  | 
| 7026  * nature of the change. |  | 
| 7027  * |  | 
| 7028  * No source should be added to the change set more than once, either with the |  | 
| 7029  * same or a different kind of change. It does not make sense, for example, for |  | 
| 7030  * a source to be both added and removed, and it is redundant for a source to be |  | 
| 7031  * marked as changed in its entirety and changed in some specific range. |  | 
| 7032  */ |  | 
| 7033 class ChangeSet { |  | 
| 7034   /** |  | 
| 7035    * A list containing the sources that have been added. |  | 
| 7036    */ |  | 
| 7037   final List<Source> addedSources = new List<Source>(); |  | 
| 7038 |  | 
| 7039   /** |  | 
| 7040    * A list containing the sources that have been changed. |  | 
| 7041    */ |  | 
| 7042   final List<Source> changedSources = new List<Source>(); |  | 
| 7043 |  | 
| 7044   /** |  | 
| 7045    * A table mapping the sources whose content has been changed to the current |  | 
| 7046    * content of those sources. |  | 
| 7047    */ |  | 
| 7048   HashMap<Source, String> _changedContent = new HashMap<Source, String>(); |  | 
| 7049 |  | 
| 7050   /** |  | 
| 7051    * A table mapping the sources whose content has been changed within a single |  | 
| 7052    * range to the current content of those sources and information about the |  | 
| 7053    * affected range. |  | 
| 7054    */ |  | 
| 7055   final HashMap<Source, ChangeSet_ContentChange> changedRanges = |  | 
| 7056       new HashMap<Source, ChangeSet_ContentChange>(); |  | 
| 7057 |  | 
| 7058   /** |  | 
| 7059    * A list containing the sources that have been removed. |  | 
| 7060    */ |  | 
| 7061   final List<Source> removedSources = new List<Source>(); |  | 
| 7062 |  | 
| 7063   /** |  | 
| 7064    * A list containing the source containers specifying additional sources that |  | 
| 7065    * have been removed. |  | 
| 7066    */ |  | 
| 7067   final List<SourceContainer> removedContainers = new List<SourceContainer>(); |  | 
| 7068 |  | 
| 7069   /** |  | 
| 7070    * A list containing the sources that have been deleted. |  | 
| 7071    */ |  | 
| 7072   final List<Source> deletedSources = new List<Source>(); |  | 
| 7073 |  | 
| 7074   /** |  | 
| 7075    * Return a table mapping the sources whose content has been changed to the |  | 
| 7076    * current content of those sources. |  | 
| 7077    */ |  | 
| 7078   Map<Source, String> get changedContents => _changedContent; |  | 
| 7079 |  | 
| 7080   /** |  | 
| 7081    * Return `true` if this change set does not contain any changes. |  | 
| 7082    */ |  | 
| 7083   bool get isEmpty => addedSources.isEmpty && |  | 
| 7084       changedSources.isEmpty && |  | 
| 7085       _changedContent.isEmpty && |  | 
| 7086       changedRanges.isEmpty && |  | 
| 7087       removedSources.isEmpty && |  | 
| 7088       removedContainers.isEmpty && |  | 
| 7089       deletedSources.isEmpty; |  | 
| 7090 |  | 
| 7091   /** |  | 
| 7092    * Record that the specified [source] has been added and that its content is |  | 
| 7093    * the default contents of the source. |  | 
| 7094    */ |  | 
| 7095   void addedSource(Source source) { |  | 
| 7096     addedSources.add(source); |  | 
| 7097   } |  | 
| 7098 |  | 
| 7099   /** |  | 
| 7100    * Record that the specified [source] has been changed and that its content is |  | 
| 7101    * the given [contents]. |  | 
| 7102    */ |  | 
| 7103   void changedContent(Source source, String contents) { |  | 
| 7104     _changedContent[source] = contents; |  | 
| 7105   } |  | 
| 7106 |  | 
| 7107   /** |  | 
| 7108    * Record that the specified [source] has been changed and that its content is |  | 
| 7109    * the given [contents]. The [offset] is the offset into the current contents. |  | 
| 7110    * The [oldLength] is the number of characters in the original contents that |  | 
| 7111    * were replaced. The [newLength] is the number of characters in the |  | 
| 7112    * replacement text. |  | 
| 7113    */ |  | 
| 7114   void changedRange(Source source, String contents, int offset, int oldLength, |  | 
| 7115       int newLength) { |  | 
| 7116     changedRanges[source] = |  | 
| 7117         new ChangeSet_ContentChange(contents, offset, oldLength, newLength); |  | 
| 7118   } |  | 
| 7119 |  | 
| 7120   /** |  | 
| 7121    * Record that the specified [source] has been changed. If the content of the |  | 
| 7122    * source was previously overridden, this has no effect (the content remains |  | 
| 7123    * overridden). To cancel (or change) the override, use [changedContent] |  | 
| 7124    * instead. |  | 
| 7125    */ |  | 
| 7126   void changedSource(Source source) { |  | 
| 7127     changedSources.add(source); |  | 
| 7128   } |  | 
| 7129 |  | 
| 7130   /** |  | 
| 7131    * Record that the specified [source] has been deleted. |  | 
| 7132    */ |  | 
| 7133   void deletedSource(Source source) { |  | 
| 7134     deletedSources.add(source); |  | 
| 7135   } |  | 
| 7136 |  | 
| 7137   /** |  | 
| 7138    * Record that the specified source [container] has been removed. |  | 
| 7139    */ |  | 
| 7140   void removedContainer(SourceContainer container) { |  | 
| 7141     if (container != null) { |  | 
| 7142       removedContainers.add(container); |  | 
| 7143     } |  | 
| 7144   } |  | 
| 7145 |  | 
| 7146   /** |  | 
| 7147    * Record that the specified [source] has been removed. |  | 
| 7148    */ |  | 
| 7149   void removedSource(Source source) { |  | 
| 7150     if (source != null) { |  | 
| 7151       removedSources.add(source); |  | 
| 7152     } |  | 
| 7153   } |  | 
| 7154 |  | 
| 7155   @override |  | 
| 7156   String toString() { |  | 
| 7157     StringBuffer buffer = new StringBuffer(); |  | 
| 7158     bool needsSeparator = |  | 
| 7159         _appendSources(buffer, addedSources, false, "addedSources"); |  | 
| 7160     needsSeparator = _appendSources( |  | 
| 7161         buffer, changedSources, needsSeparator, "changedSources"); |  | 
| 7162     needsSeparator = _appendSources2( |  | 
| 7163         buffer, _changedContent, needsSeparator, "changedContent"); |  | 
| 7164     needsSeparator = |  | 
| 7165         _appendSources2(buffer, changedRanges, needsSeparator, "changedRanges"); |  | 
| 7166     needsSeparator = _appendSources( |  | 
| 7167         buffer, deletedSources, needsSeparator, "deletedSources"); |  | 
| 7168     needsSeparator = _appendSources( |  | 
| 7169         buffer, removedSources, needsSeparator, "removedSources"); |  | 
| 7170     int count = removedContainers.length; |  | 
| 7171     if (count > 0) { |  | 
| 7172       if (removedSources.isEmpty) { |  | 
| 7173         if (needsSeparator) { |  | 
| 7174           buffer.write("; "); |  | 
| 7175         } |  | 
| 7176         buffer.write("removed: from "); |  | 
| 7177         buffer.write(count); |  | 
| 7178         buffer.write(" containers"); |  | 
| 7179       } else { |  | 
| 7180         buffer.write(", and more from "); |  | 
| 7181         buffer.write(count); |  | 
| 7182         buffer.write(" containers"); |  | 
| 7183       } |  | 
| 7184     } |  | 
| 7185     return buffer.toString(); |  | 
| 7186   } |  | 
| 7187 |  | 
| 7188   /** |  | 
| 7189    * Append the given [sources] to the given [buffer], prefixed with the given |  | 
| 7190    * [label] and a separator if [needsSeparator] is `true`. Return `true` if |  | 
| 7191    * future lists of sources will need a separator. |  | 
| 7192    */ |  | 
| 7193   bool _appendSources(StringBuffer buffer, List<Source> sources, |  | 
| 7194       bool needsSeparator, String label) { |  | 
| 7195     if (sources.isEmpty) { |  | 
| 7196       return needsSeparator; |  | 
| 7197     } |  | 
| 7198     if (needsSeparator) { |  | 
| 7199       buffer.write("; "); |  | 
| 7200     } |  | 
| 7201     buffer.write(label); |  | 
| 7202     String prefix = " "; |  | 
| 7203     for (Source source in sources) { |  | 
| 7204       buffer.write(prefix); |  | 
| 7205       buffer.write(source.fullName); |  | 
| 7206       prefix = ", "; |  | 
| 7207     } |  | 
| 7208     return true; |  | 
| 7209   } |  | 
| 7210 |  | 
| 7211   /** |  | 
| 7212    * Append the given [sources] to the given [builder], prefixed with the given |  | 
| 7213    * [label] and a separator if [needsSeparator] is `true`. Return `true` if |  | 
| 7214    * future lists of sources will need a separator. |  | 
| 7215    */ |  | 
| 7216   bool _appendSources2(StringBuffer buffer, HashMap<Source, dynamic> sources, |  | 
| 7217       bool needsSeparator, String label) { |  | 
| 7218     if (sources.isEmpty) { |  | 
| 7219       return needsSeparator; |  | 
| 7220     } |  | 
| 7221     if (needsSeparator) { |  | 
| 7222       buffer.write("; "); |  | 
| 7223     } |  | 
| 7224     buffer.write(label); |  | 
| 7225     String prefix = " "; |  | 
| 7226     for (Source source in sources.keys.toSet()) { |  | 
| 7227       buffer.write(prefix); |  | 
| 7228       buffer.write(source.fullName); |  | 
| 7229       prefix = ", "; |  | 
| 7230     } |  | 
| 7231     return true; |  | 
| 7232   } |  | 
| 7233 } |  | 
| 7234 |  | 
| 7235 /** |  | 
| 7236  * A change to the content of a source. |  | 
| 7237  */ |  | 
| 7238 class ChangeSet_ContentChange { |  | 
| 7239   /** |  | 
| 7240    * The new contents of the source. |  | 
| 7241    */ |  | 
| 7242   final String contents; |  | 
| 7243 |  | 
| 7244   /** |  | 
| 7245    * The offset into the current contents. |  | 
| 7246    */ |  | 
| 7247   final int offset; |  | 
| 7248 |  | 
| 7249   /** |  | 
| 7250    * The number of characters in the original contents that were replaced |  | 
| 7251    */ |  | 
| 7252   final int oldLength; |  | 
| 7253 |  | 
| 7254   /** |  | 
| 7255    * The number of characters in the replacement text. |  | 
| 7256    */ |  | 
| 7257   final int newLength; |  | 
| 7258 |  | 
| 7259   /** |  | 
| 7260    * Initialize a newly created change object to represent a change to the |  | 
| 7261    * content of a source. The [contents] is the new contents of the source. The |  | 
| 7262    * [offse] ist the offset into the current contents. The [oldLength] is the |  | 
| 7263    * number of characters in the original contents that were replaced. The |  | 
| 7264    * [newLength] is the number of characters in the replacement text. |  | 
| 7265    */ |  | 
| 7266   ChangeSet_ContentChange( |  | 
| 7267       this.contents, this.offset, this.oldLength, this.newLength); |  | 
| 7268 } |  | 
| 7269 |  | 
| 7270 /** |  | 
| 7271  * [ComputedResult] describes a value computed for a [ResultDescriptor]. |  | 
| 7272  */ |  | 
| 7273 class ComputedResult<V> { |  | 
| 7274   /** |  | 
| 7275    * The context in which the value was computed. |  | 
| 7276    */ |  | 
| 7277   final AnalysisContext context; |  | 
| 7278 |  | 
| 7279   /** |  | 
| 7280    * The descriptor of the result which was computed. |  | 
| 7281    */ |  | 
| 7282   final ResultDescriptor<V> descriptor; |  | 
| 7283 |  | 
| 7284   /** |  | 
| 7285    * The target for which the result was computed. |  | 
| 7286    */ |  | 
| 7287   final AnalysisTarget target; |  | 
| 7288 |  | 
| 7289   /** |  | 
| 7290    * The computed value. |  | 
| 7291    */ |  | 
| 7292   final V value; |  | 
| 7293 |  | 
| 7294   ComputedResult(this.context, this.descriptor, this.target, this.value); |  | 
| 7295 |  | 
| 7296   @override |  | 
| 7297   String toString() => '$descriptor of $target in $context'; |  | 
| 7298 } |  | 
| 7299 |  | 
| 7300 /** |  | 
| 7301  * A pair containing a library and a list of the (source, entry) pairs for |  | 
| 7302  * compilation units in the library. |  | 
| 7303  */ |  | 
| 7304 class CycleBuilder_LibraryPair { |  | 
| 7305   /** |  | 
| 7306    * The library containing the compilation units. |  | 
| 7307    */ |  | 
| 7308   ResolvableLibrary library; |  | 
| 7309 |  | 
| 7310   /** |  | 
| 7311    * The (source, entry) pairs representing the compilation units in the |  | 
| 7312    * library. |  | 
| 7313    */ |  | 
| 7314   List<CycleBuilder_SourceEntryPair> entryPairs; |  | 
| 7315 |  | 
| 7316   /** |  | 
| 7317    * Initialize a newly created pair from the given [library] and [entryPairs]. |  | 
| 7318    */ |  | 
| 7319   CycleBuilder_LibraryPair(ResolvableLibrary library, |  | 
| 7320       List<CycleBuilder_SourceEntryPair> entryPairs) { |  | 
| 7321     this.library = library; |  | 
| 7322     this.entryPairs = entryPairs; |  | 
| 7323   } |  | 
| 7324 } |  | 
| 7325 |  | 
| 7326 /** |  | 
| 7327  * A pair containing a source and the cache entry associated with that source. |  | 
| 7328  * They are used to reduce the number of times an entry must be looked up in the |  | 
| 7329  * cache. |  | 
| 7330  */ |  | 
| 7331 class CycleBuilder_SourceEntryPair { |  | 
| 7332   /** |  | 
| 7333    * The source associated with the entry. |  | 
| 7334    */ |  | 
| 7335   Source source; |  | 
| 7336 |  | 
| 7337   /** |  | 
| 7338    * The entry associated with the source. |  | 
| 7339    */ |  | 
| 7340   DartEntry entry; |  | 
| 7341 |  | 
| 7342   /** |  | 
| 7343    * Initialize a newly created pair from the given [source] and [entry]. |  | 
| 7344    */ |  | 
| 7345   CycleBuilder_SourceEntryPair(Source source, DartEntry entry) { |  | 
| 7346     this.source = source; |  | 
| 7347     this.entry = entry; |  | 
| 7348   } |  | 
| 7349 } |  | 
| 7350 |  | 
| 7351 /** |  | 
| 7352  * The information cached by an analysis context about an individual Dart file. |  | 
| 7353  */ |  | 
| 7354 class DartEntry extends SourceEntry { |  | 
| 7355   /** |  | 
| 7356    * The data descriptor representing the element model representing a single |  | 
| 7357    * compilation unit. This model is incomplete and should not be used except as |  | 
| 7358    * input to another task. |  | 
| 7359    */ |  | 
| 7360   static final DataDescriptor<List<AnalysisError>> BUILT_ELEMENT = |  | 
| 7361       new DataDescriptor<List<AnalysisError>>("DartEntry.BUILT_ELEMENT"); |  | 
| 7362 |  | 
| 7363   /** |  | 
| 7364    * The data descriptor representing the AST structure after the element model |  | 
| 7365    * has been built (and declarations are resolved) but before other resolution |  | 
| 7366    * has been performed. |  | 
| 7367    */ |  | 
| 7368   static final DataDescriptor<CompilationUnit> BUILT_UNIT = |  | 
| 7369       new DataDescriptor<CompilationUnit>("DartEntry.BUILT_UNIT"); |  | 
| 7370 |  | 
| 7371   /** |  | 
| 7372    * The data descriptor representing the list of libraries that contain this |  | 
| 7373    * compilation unit. |  | 
| 7374    */ |  | 
| 7375   static final DataDescriptor<List<Source>> CONTAINING_LIBRARIES = |  | 
| 7376       new DataDescriptor<List<Source>>( |  | 
| 7377           "DartEntry.CONTAINING_LIBRARIES", Source.EMPTY_LIST); |  | 
| 7378 |  | 
| 7379   /** |  | 
| 7380    * The data descriptor representing the library element for the library. This |  | 
| 7381    * data is only available for Dart files that are the defining compilation |  | 
| 7382    * unit of a library. |  | 
| 7383    */ |  | 
| 7384   static final DataDescriptor<LibraryElement> ELEMENT = |  | 
| 7385       new DataDescriptor<LibraryElement>("DartEntry.ELEMENT"); |  | 
| 7386 |  | 
| 7387   /** |  | 
| 7388    * The data descriptor representing the list of exported libraries. This data |  | 
| 7389    * is only available for Dart files that are the defining compilation unit of |  | 
| 7390    * a library. |  | 
| 7391    */ |  | 
| 7392   static final DataDescriptor<List<Source>> EXPORTED_LIBRARIES = |  | 
| 7393       new DataDescriptor<List<Source>>( |  | 
| 7394           "DartEntry.EXPORTED_LIBRARIES", Source.EMPTY_LIST); |  | 
| 7395 |  | 
| 7396   /** |  | 
| 7397    * The data descriptor representing the hints resulting from auditing the |  | 
| 7398    * source. |  | 
| 7399    */ |  | 
| 7400   static final DataDescriptor<List<AnalysisError>> HINTS = |  | 
| 7401       new DataDescriptor<List<AnalysisError>>( |  | 
| 7402           "DartEntry.HINTS", AnalysisError.NO_ERRORS); |  | 
| 7403 |  | 
| 7404   /** |  | 
| 7405    * The data descriptor representing the list of imported libraries. This data |  | 
| 7406    * is only available for Dart files that are the defining compilation unit of |  | 
| 7407    * a library. |  | 
| 7408    */ |  | 
| 7409   static final DataDescriptor<List<Source>> IMPORTED_LIBRARIES = |  | 
| 7410       new DataDescriptor<List<Source>>( |  | 
| 7411           "DartEntry.IMPORTED_LIBRARIES", Source.EMPTY_LIST); |  | 
| 7412 |  | 
| 7413   /** |  | 
| 7414    * The data descriptor representing the list of included parts. This data is |  | 
| 7415    * only available for Dart files that are the defining compilation unit of a |  | 
| 7416    * library. |  | 
| 7417    */ |  | 
| 7418   static final DataDescriptor<List<Source>> INCLUDED_PARTS = |  | 
| 7419       new DataDescriptor<List<Source>>( |  | 
| 7420           "DartEntry.INCLUDED_PARTS", Source.EMPTY_LIST); |  | 
| 7421 |  | 
| 7422   /** |  | 
| 7423    * The data descriptor representing the client flag. This data is only |  | 
| 7424    * available for Dart files that are the defining compilation unit of a |  | 
| 7425    * library. |  | 
| 7426    */ |  | 
| 7427   static final DataDescriptor<bool> IS_CLIENT = |  | 
| 7428       new DataDescriptor<bool>("DartEntry.IS_CLIENT", false); |  | 
| 7429 |  | 
| 7430   /** |  | 
| 7431    * The data descriptor representing the launchable flag. This data is only |  | 
| 7432    * available for Dart files that are the defining compilation unit of a |  | 
| 7433    * library. |  | 
| 7434    */ |  | 
| 7435   static final DataDescriptor<bool> IS_LAUNCHABLE = |  | 
| 7436       new DataDescriptor<bool>("DartEntry.IS_LAUNCHABLE", false); |  | 
| 7437 |  | 
| 7438   /** |  | 
| 7439    * The data descriptor representing lint warnings resulting from auditing the |  | 
| 7440    * source. |  | 
| 7441    */ |  | 
| 7442   static final DataDescriptor<List<AnalysisError>> LINTS = |  | 
| 7443       new DataDescriptor<List<AnalysisError>>( |  | 
| 7444           "DartEntry.LINTS", AnalysisError.NO_ERRORS); |  | 
| 7445 |  | 
| 7446   /** |  | 
| 7447    * The data descriptor representing the errors resulting from parsing the |  | 
| 7448    * source. |  | 
| 7449    */ |  | 
| 7450   static final DataDescriptor<List<AnalysisError>> PARSE_ERRORS = |  | 
| 7451       new DataDescriptor<List<AnalysisError>>( |  | 
| 7452           "DartEntry.PARSE_ERRORS", AnalysisError.NO_ERRORS); |  | 
| 7453 |  | 
| 7454   /** |  | 
| 7455    * The data descriptor representing the parsed AST structure. |  | 
| 7456    */ |  | 
| 7457   static final DataDescriptor<CompilationUnit> PARSED_UNIT = |  | 
| 7458       new DataDescriptor<CompilationUnit>("DartEntry.PARSED_UNIT"); |  | 
| 7459 |  | 
| 7460   /** |  | 
| 7461    * The data descriptor representing the public namespace of the library. This |  | 
| 7462    * data is only available for Dart files that are the defining compilation |  | 
| 7463    * unit of a library. |  | 
| 7464    */ |  | 
| 7465   static final DataDescriptor<Namespace> PUBLIC_NAMESPACE = |  | 
| 7466       new DataDescriptor<Namespace>("DartEntry.PUBLIC_NAMESPACE"); |  | 
| 7467 |  | 
| 7468   /** |  | 
| 7469    * The data descriptor representing the errors resulting from resolving the |  | 
| 7470    * source. |  | 
| 7471    */ |  | 
| 7472   static final DataDescriptor<List<AnalysisError>> RESOLUTION_ERRORS = |  | 
| 7473       new DataDescriptor<List<AnalysisError>>( |  | 
| 7474           "DartEntry.RESOLUTION_ERRORS", AnalysisError.NO_ERRORS); |  | 
| 7475 |  | 
| 7476   /** |  | 
| 7477    * The data descriptor representing the resolved AST structure. |  | 
| 7478    */ |  | 
| 7479   static final DataDescriptor<CompilationUnit> RESOLVED_UNIT = |  | 
| 7480       new DataDescriptor<CompilationUnit>("DartEntry.RESOLVED_UNIT"); |  | 
| 7481 |  | 
| 7482   /** |  | 
| 7483    * The data descriptor representing the errors resulting from scanning the |  | 
| 7484    * source. |  | 
| 7485    */ |  | 
| 7486   static final DataDescriptor<List<AnalysisError>> SCAN_ERRORS = |  | 
| 7487       new DataDescriptor<List<AnalysisError>>( |  | 
| 7488           "DartEntry.SCAN_ERRORS", AnalysisError.NO_ERRORS); |  | 
| 7489 |  | 
| 7490   /** |  | 
| 7491    * The data descriptor representing the source kind. |  | 
| 7492    */ |  | 
| 7493   static final DataDescriptor<SourceKind> SOURCE_KIND = |  | 
| 7494       new DataDescriptor<SourceKind>( |  | 
| 7495           "DartEntry.SOURCE_KIND", SourceKind.UNKNOWN); |  | 
| 7496 |  | 
| 7497   /** |  | 
| 7498    * The data descriptor representing the token stream. |  | 
| 7499    */ |  | 
| 7500   static final DataDescriptor<Token> TOKEN_STREAM = |  | 
| 7501       new DataDescriptor<Token>("DartEntry.TOKEN_STREAM"); |  | 
| 7502 |  | 
| 7503   /** |  | 
| 7504    * The data descriptor representing the errors resulting from verifying the |  | 
| 7505    * source. |  | 
| 7506    */ |  | 
| 7507   static final DataDescriptor<List<AnalysisError>> VERIFICATION_ERRORS = |  | 
| 7508       new DataDescriptor<List<AnalysisError>>( |  | 
| 7509           "DartEntry.VERIFICATION_ERRORS", AnalysisError.NO_ERRORS); |  | 
| 7510 |  | 
| 7511   /** |  | 
| 7512    * The list of libraries that contain this compilation unit. The list will be |  | 
| 7513    * empty if there are no known libraries that contain this compilation unit. |  | 
| 7514    */ |  | 
| 7515   List<Source> _containingLibraries = new List<Source>(); |  | 
| 7516 |  | 
| 7517   /** |  | 
| 7518    * The information known as a result of resolving this compilation unit as |  | 
| 7519    * part of the library that contains this unit. This field will never be |  | 
| 7520    * `null`. |  | 
| 7521    */ |  | 
| 7522   ResolutionState _resolutionState = new ResolutionState(); |  | 
| 7523 |  | 
| 7524   /** |  | 
| 7525    * Return all of the errors associated with the compilation unit that are |  | 
| 7526    * currently cached. |  | 
| 7527    */ |  | 
| 7528   List<AnalysisError> get allErrors { |  | 
| 7529     List<AnalysisError> errors = new List<AnalysisError>(); |  | 
| 7530     errors.addAll(super.allErrors); |  | 
| 7531     errors.addAll(getValue(SCAN_ERRORS)); |  | 
| 7532     errors.addAll(getValue(PARSE_ERRORS)); |  | 
| 7533     ResolutionState state = _resolutionState; |  | 
| 7534     while (state != null) { |  | 
| 7535       errors.addAll(state.getValue(RESOLUTION_ERRORS)); |  | 
| 7536       errors.addAll(state.getValue(VERIFICATION_ERRORS)); |  | 
| 7537       errors.addAll(state.getValue(HINTS)); |  | 
| 7538       errors.addAll(state.getValue(LINTS)); |  | 
| 7539       state = state._nextState; |  | 
| 7540     } |  | 
| 7541     if (errors.length == 0) { |  | 
| 7542       return AnalysisError.NO_ERRORS; |  | 
| 7543     } |  | 
| 7544     return errors; |  | 
| 7545   } |  | 
| 7546 |  | 
| 7547   /** |  | 
| 7548    * Return a valid parsed compilation unit, either an unresolved AST structure |  | 
| 7549    * or the result of resolving the AST structure in the context of some |  | 
| 7550    * library, or `null` if there is no parsed compilation unit available. |  | 
| 7551    */ |  | 
| 7552   CompilationUnit get anyParsedCompilationUnit { |  | 
| 7553     if (getState(PARSED_UNIT) == CacheState.VALID) { |  | 
| 7554       return getValue(PARSED_UNIT); |  | 
| 7555     } |  | 
| 7556     ResolutionState state = _resolutionState; |  | 
| 7557     while (state != null) { |  | 
| 7558       if (state.getState(BUILT_UNIT) == CacheState.VALID) { |  | 
| 7559         return state.getValue(BUILT_UNIT); |  | 
| 7560       } |  | 
| 7561       state = state._nextState; |  | 
| 7562     } |  | 
| 7563 |  | 
| 7564     return anyResolvedCompilationUnit; |  | 
| 7565   } |  | 
| 7566 |  | 
| 7567   /** |  | 
| 7568    * Return the result of resolving the compilation unit as part of any library, |  | 
| 7569    * or `null` if there is no cached resolved compilation unit. |  | 
| 7570    */ |  | 
| 7571   CompilationUnit get anyResolvedCompilationUnit { |  | 
| 7572     ResolutionState state = _resolutionState; |  | 
| 7573     while (state != null) { |  | 
| 7574       if (state.getState(RESOLVED_UNIT) == CacheState.VALID) { |  | 
| 7575         return state.getValue(RESOLVED_UNIT); |  | 
| 7576       } |  | 
| 7577       state = state._nextState; |  | 
| 7578     } |  | 
| 7579     return null; |  | 
| 7580   } |  | 
| 7581 |  | 
| 7582   /** |  | 
| 7583    * The libraries that are known to contain this part. |  | 
| 7584    */ |  | 
| 7585   List<Source> get containingLibraries => _containingLibraries; |  | 
| 7586 |  | 
| 7587   /** |  | 
| 7588    * Set the list of libraries that contain this compilation unit to contain |  | 
| 7589    * only the given [librarySource]. This method should only be invoked on |  | 
| 7590    * entries that represent a library. |  | 
| 7591    */ |  | 
| 7592   void set containingLibrary(Source librarySource) { |  | 
| 7593     _containingLibraries.clear(); |  | 
| 7594     _containingLibraries.add(librarySource); |  | 
| 7595   } |  | 
| 7596 |  | 
| 7597   @override |  | 
| 7598   List<DataDescriptor> get descriptors { |  | 
| 7599     List<DataDescriptor> result = super.descriptors; |  | 
| 7600     result.addAll(<DataDescriptor>[ |  | 
| 7601       DartEntry.SOURCE_KIND, |  | 
| 7602       DartEntry.CONTAINING_LIBRARIES, |  | 
| 7603       DartEntry.PARSE_ERRORS, |  | 
| 7604       DartEntry.PARSED_UNIT, |  | 
| 7605       DartEntry.SCAN_ERRORS, |  | 
| 7606       DartEntry.SOURCE_KIND, |  | 
| 7607       DartEntry.TOKEN_STREAM |  | 
| 7608     ]); |  | 
| 7609     SourceKind kind = getValue(DartEntry.SOURCE_KIND); |  | 
| 7610     if (kind == SourceKind.LIBRARY) { |  | 
| 7611       result.addAll(<DataDescriptor>[ |  | 
| 7612         DartEntry.ELEMENT, |  | 
| 7613         DartEntry.EXPORTED_LIBRARIES, |  | 
| 7614         DartEntry.IMPORTED_LIBRARIES, |  | 
| 7615         DartEntry.INCLUDED_PARTS, |  | 
| 7616         DartEntry.IS_CLIENT, |  | 
| 7617         DartEntry.IS_LAUNCHABLE, |  | 
| 7618         DartEntry.PUBLIC_NAMESPACE |  | 
| 7619       ]); |  | 
| 7620     } |  | 
| 7621     return result; |  | 
| 7622   } |  | 
| 7623 |  | 
| 7624   /** |  | 
| 7625    * Return `true` if this entry has an AST structure that can be resolved, even |  | 
| 7626    * if it needs to be copied. Returning `true` implies that the method |  | 
| 7627    * [resolvableCompilationUnit] will return a non-`null` result. |  | 
| 7628    */ |  | 
| 7629   bool get hasResolvableCompilationUnit { |  | 
| 7630     if (getState(PARSED_UNIT) == CacheState.VALID) { |  | 
| 7631       return true; |  | 
| 7632     } |  | 
| 7633     ResolutionState state = _resolutionState; |  | 
| 7634     while (state != null) { |  | 
| 7635       if (state.getState(BUILT_UNIT) == CacheState.VALID || |  | 
| 7636           state.getState(RESOLVED_UNIT) == CacheState.VALID) { |  | 
| 7637         return true; |  | 
| 7638       } |  | 
| 7639       state = state._nextState; |  | 
| 7640     } |  | 
| 7641 |  | 
| 7642     return false; |  | 
| 7643   } |  | 
| 7644 |  | 
| 7645   @override |  | 
| 7646   SourceKind get kind => getValue(SOURCE_KIND); |  | 
| 7647 |  | 
| 7648   /** |  | 
| 7649    * The library sources containing the receiver's source. |  | 
| 7650    */ |  | 
| 7651   List<Source> get librariesContaining { |  | 
| 7652     ResolutionState state = _resolutionState; |  | 
| 7653     List<Source> result = new List<Source>(); |  | 
| 7654     while (state != null) { |  | 
| 7655       if (state._librarySource != null) { |  | 
| 7656         result.add(state._librarySource); |  | 
| 7657       } |  | 
| 7658       state = state._nextState; |  | 
| 7659     } |  | 
| 7660     return result; |  | 
| 7661   } |  | 
| 7662 |  | 
| 7663   /** |  | 
| 7664    * Get a list of all the library-dependent descriptors for which values may |  | 
| 7665    * be stored in this SourceEntry. |  | 
| 7666    */ |  | 
| 7667   List<DataDescriptor> get libraryDescriptors { |  | 
| 7668     return <DataDescriptor>[ |  | 
| 7669       DartEntry.BUILT_ELEMENT, |  | 
| 7670       DartEntry.BUILT_UNIT, |  | 
| 7671       DartEntry.RESOLUTION_ERRORS, |  | 
| 7672       DartEntry.RESOLVED_UNIT, |  | 
| 7673       DartEntry.VERIFICATION_ERRORS, |  | 
| 7674       DartEntry.HINTS, |  | 
| 7675       DartEntry.LINTS |  | 
| 7676     ]; |  | 
| 7677   } |  | 
| 7678 |  | 
| 7679   /** |  | 
| 7680    * A compilation unit that has not been accessed by any other client and can |  | 
| 7681    * therefore safely be modified by the reconciler, or `null` if the source has |  | 
| 7682    * not been parsed. |  | 
| 7683    */ |  | 
| 7684   CompilationUnit get resolvableCompilationUnit { |  | 
| 7685     if (getState(PARSED_UNIT) == CacheState.VALID) { |  | 
| 7686       CompilationUnit unit = getValue(PARSED_UNIT); |  | 
| 7687       setState(PARSED_UNIT, CacheState.FLUSHED); |  | 
| 7688       return unit; |  | 
| 7689     } |  | 
| 7690     ResolutionState state = _resolutionState; |  | 
| 7691     while (state != null) { |  | 
| 7692       if (state.getState(BUILT_UNIT) == CacheState.VALID) { |  | 
| 7693         // TODO(brianwilkerson) We're cloning the structure to remove any |  | 
| 7694         // previous resolution data, but I'm not sure that's necessary. |  | 
| 7695         return state.getValue(BUILT_UNIT).accept(new AstCloner()); |  | 
| 7696       } |  | 
| 7697       if (state.getState(RESOLVED_UNIT) == CacheState.VALID) { |  | 
| 7698         return state.getValue(RESOLVED_UNIT).accept(new AstCloner()); |  | 
| 7699       } |  | 
| 7700       state = state._nextState; |  | 
| 7701     } |  | 
| 7702     return null; |  | 
| 7703   } |  | 
| 7704 |  | 
| 7705   /** |  | 
| 7706    * Add the given [librarySource] to the list of libraries that contain this |  | 
| 7707    * part. This method should only be invoked on entries that represent a part. |  | 
| 7708    */ |  | 
| 7709   void addContainingLibrary(Source librarySource) { |  | 
| 7710     _containingLibraries.add(librarySource); |  | 
| 7711   } |  | 
| 7712 |  | 
| 7713   /** |  | 
| 7714    * Flush any AST structures being maintained by this entry. |  | 
| 7715    */ |  | 
| 7716   void flushAstStructures() { |  | 
| 7717     _flush(TOKEN_STREAM); |  | 
| 7718     _flush(PARSED_UNIT); |  | 
| 7719     _resolutionState.flushAstStructures(); |  | 
| 7720   } |  | 
| 7721 |  | 
| 7722   /** |  | 
| 7723    * Return the state of the data represented by the given [descriptor] in the |  | 
| 7724    * context of the given [librarySource]. |  | 
| 7725    */ |  | 
| 7726   CacheState getStateInLibrary( |  | 
| 7727       DataDescriptor descriptor, Source librarySource) { |  | 
| 7728     if (!_isValidLibraryDescriptor(descriptor)) { |  | 
| 7729       throw new ArgumentError("Invalid descriptor: $descriptor"); |  | 
| 7730     } |  | 
| 7731     ResolutionState state = _resolutionState; |  | 
| 7732     while (state != null) { |  | 
| 7733       if (librarySource == state._librarySource) { |  | 
| 7734         return state.getState(descriptor); |  | 
| 7735       } |  | 
| 7736       state = state._nextState; |  | 
| 7737     } |  | 
| 7738     return CacheState.INVALID; |  | 
| 7739   } |  | 
| 7740 |  | 
| 7741   /** |  | 
| 7742    * Return the value of the data represented by the given [descriptor] in the |  | 
| 7743    * context of the given [librarySource], or `null` if the data represented by |  | 
| 7744    * the descriptor is not in the cache. |  | 
| 7745    */ |  | 
| 7746   Object getValueInLibrary(DataDescriptor descriptor, Source librarySource) { |  | 
| 7747     if (!_isValidLibraryDescriptor(descriptor)) { |  | 
| 7748       throw new ArgumentError("Invalid descriptor: $descriptor"); |  | 
| 7749     } |  | 
| 7750     ResolutionState state = _resolutionState; |  | 
| 7751     while (state != null) { |  | 
| 7752       if (librarySource == state._librarySource) { |  | 
| 7753         return state.getValue(descriptor); |  | 
| 7754       } |  | 
| 7755       state = state._nextState; |  | 
| 7756     } |  | 
| 7757     return descriptor.defaultValue; |  | 
| 7758   } |  | 
| 7759 |  | 
| 7760   /** |  | 
| 7761    * Return `true` if the data represented by the given [descriptor] is marked |  | 
| 7762    * as being invalid. If the descriptor represents library-specific data then |  | 
| 7763    * this method will return `true` if the data associated with any library it |  | 
| 7764    * marked as invalid. |  | 
| 7765    */ |  | 
| 7766   bool hasInvalidData(DataDescriptor descriptor) { |  | 
| 7767     if (_isValidDescriptor(descriptor)) { |  | 
| 7768       return getState(descriptor) == CacheState.INVALID; |  | 
| 7769     } else if (_isValidLibraryDescriptor(descriptor)) { |  | 
| 7770       ResolutionState state = _resolutionState; |  | 
| 7771       while (state != null) { |  | 
| 7772         if (state.getState(descriptor) == CacheState.INVALID) { |  | 
| 7773           return true; |  | 
| 7774         } |  | 
| 7775         state = state._nextState; |  | 
| 7776       } |  | 
| 7777     } |  | 
| 7778     return false; |  | 
| 7779   } |  | 
| 7780 |  | 
| 7781   @override |  | 
| 7782   void invalidateAllInformation() { |  | 
| 7783     super.invalidateAllInformation(); |  | 
| 7784     setState(SCAN_ERRORS, CacheState.INVALID); |  | 
| 7785     setState(TOKEN_STREAM, CacheState.INVALID); |  | 
| 7786     setState(SOURCE_KIND, CacheState.INVALID); |  | 
| 7787     setState(PARSE_ERRORS, CacheState.INVALID); |  | 
| 7788     setState(PARSED_UNIT, CacheState.INVALID); |  | 
| 7789     _discardCachedResolutionInformation(true); |  | 
| 7790   } |  | 
| 7791 |  | 
| 7792   /** |  | 
| 7793    * Invalidate all of the resolution information associated with the |  | 
| 7794    * compilation unit. The flag [invalidateUris] should be `true` if the cached |  | 
| 7795    * results of converting URIs to source files should also be invalidated. |  | 
| 7796    */ |  | 
| 7797   void invalidateAllResolutionInformation(bool invalidateUris) { |  | 
| 7798     if (getState(PARSED_UNIT) == CacheState.FLUSHED) { |  | 
| 7799       ResolutionState state = _resolutionState; |  | 
| 7800       while (state != null) { |  | 
| 7801         if (state.getState(BUILT_UNIT) == CacheState.VALID) { |  | 
| 7802           CompilationUnit unit = state.getValue(BUILT_UNIT); |  | 
| 7803           setValue(PARSED_UNIT, unit.accept(new AstCloner())); |  | 
| 7804           break; |  | 
| 7805         } else if (state.getState(RESOLVED_UNIT) == CacheState.VALID) { |  | 
| 7806           CompilationUnit unit = state.getValue(RESOLVED_UNIT); |  | 
| 7807           setValue(PARSED_UNIT, unit.accept(new AstCloner())); |  | 
| 7808           break; |  | 
| 7809         } |  | 
| 7810         state = state._nextState; |  | 
| 7811       } |  | 
| 7812     } |  | 
| 7813     _discardCachedResolutionInformation(invalidateUris); |  | 
| 7814   } |  | 
| 7815 |  | 
| 7816   /** |  | 
| 7817    * Invalidate all of the parse and resolution information associated with |  | 
| 7818    * this source. |  | 
| 7819    */ |  | 
| 7820   void invalidateParseInformation() { |  | 
| 7821     setState(SOURCE_KIND, CacheState.INVALID); |  | 
| 7822     setState(PARSE_ERRORS, CacheState.INVALID); |  | 
| 7823     setState(PARSED_UNIT, CacheState.INVALID); |  | 
| 7824     _containingLibraries.clear(); |  | 
| 7825     _discardCachedResolutionInformation(true); |  | 
| 7826   } |  | 
| 7827 |  | 
| 7828   /** |  | 
| 7829    * Record that an [exception] occurred while attempting to build the element |  | 
| 7830    * model for the source represented by this entry in the context of the given |  | 
| 7831    * [library]. This will set the state of all resolution-based information as |  | 
| 7832    * being in error, but will not change the state of any parse results. |  | 
| 7833    */ |  | 
| 7834   void recordBuildElementErrorInLibrary( |  | 
| 7835       Source librarySource, CaughtException exception) { |  | 
| 7836     setStateInLibrary(BUILT_ELEMENT, librarySource, CacheState.ERROR); |  | 
| 7837     setStateInLibrary(BUILT_UNIT, librarySource, CacheState.ERROR); |  | 
| 7838     recordResolutionErrorInLibrary(librarySource, exception); |  | 
| 7839   } |  | 
| 7840 |  | 
| 7841   @override |  | 
| 7842   void recordContentError(CaughtException exception) { |  | 
| 7843     super.recordContentError(exception); |  | 
| 7844     recordScanError(exception); |  | 
| 7845   } |  | 
| 7846 |  | 
| 7847   /** |  | 
| 7848    * Record that an error occurred while attempting to generate hints for the |  | 
| 7849    * source represented by this entry. This will set the state of all |  | 
| 7850    * verification information as being in error. The [librarySource] is the |  | 
| 7851    * source of the library in which hints were being generated. The [exception] |  | 
| 7852    * is the exception that shows where the error occurred. |  | 
| 7853    */ |  | 
| 7854   void recordHintErrorInLibrary( |  | 
| 7855       Source librarySource, CaughtException exception) { |  | 
| 7856     this.exception = exception; |  | 
| 7857     ResolutionState state = _getOrCreateResolutionState(librarySource); |  | 
| 7858     state.recordHintError(); |  | 
| 7859   } |  | 
| 7860 |  | 
| 7861   /** |  | 
| 7862    * Record that an error occurred while attempting to generate lints for the |  | 
| 7863    * source represented by this entry. This will set the state of all |  | 
| 7864    * verification information as being in error. The [librarySource] is the |  | 
| 7865    * source of the library in which lints were being generated. The [exception] |  | 
| 7866    * is the exception that shows where the error occurred. |  | 
| 7867    */ |  | 
| 7868   void recordLintErrorInLibrary( |  | 
| 7869       Source librarySource, CaughtException exception) { |  | 
| 7870     this.exception = exception; |  | 
| 7871     ResolutionState state = _getOrCreateResolutionState(librarySource); |  | 
| 7872     state.recordLintError(); |  | 
| 7873   } |  | 
| 7874 |  | 
| 7875   /** |  | 
| 7876    * Record that an [exception] occurred while attempting to scan or parse the |  | 
| 7877    * entry represented by this entry. This will set the state of all information
       , |  | 
| 7878    * including any resolution-based information, as being in error. |  | 
| 7879    */ |  | 
| 7880   void recordParseError(CaughtException exception) { |  | 
| 7881     setState(SOURCE_KIND, CacheState.ERROR); |  | 
| 7882     setState(PARSE_ERRORS, CacheState.ERROR); |  | 
| 7883     setState(PARSED_UNIT, CacheState.ERROR); |  | 
| 7884     setState(EXPORTED_LIBRARIES, CacheState.ERROR); |  | 
| 7885     setState(IMPORTED_LIBRARIES, CacheState.ERROR); |  | 
| 7886     setState(INCLUDED_PARTS, CacheState.ERROR); |  | 
| 7887     recordResolutionError(exception); |  | 
| 7888   } |  | 
| 7889 |  | 
| 7890   /** |  | 
| 7891    * Record that an [exception] occurred while attempting to resolve the source |  | 
| 7892    * represented by this entry. This will set the state of all resolution-based |  | 
| 7893    * information as being in error, but will not change the state of any parse |  | 
| 7894    * results. |  | 
| 7895    */ |  | 
| 7896   void recordResolutionError(CaughtException exception) { |  | 
| 7897     this.exception = exception; |  | 
| 7898     setState(ELEMENT, CacheState.ERROR); |  | 
| 7899     setState(IS_CLIENT, CacheState.ERROR); |  | 
| 7900     setState(IS_LAUNCHABLE, CacheState.ERROR); |  | 
| 7901     setState(PUBLIC_NAMESPACE, CacheState.ERROR); |  | 
| 7902     _resolutionState.recordResolutionErrorsInAllLibraries(); |  | 
| 7903   } |  | 
| 7904 |  | 
| 7905   /** |  | 
| 7906    * Record that an error occurred while attempting to resolve the source |  | 
| 7907    * represented by this entry. This will set the state of all resolution-based |  | 
| 7908    * information as being in error, but will not change the state of any parse |  | 
| 7909    * results. The [librarySource] is the source of the library in which |  | 
| 7910    * resolution was being performed. The [exception] is the exception that shows |  | 
| 7911    * where the error occurred. |  | 
| 7912    */ |  | 
| 7913   void recordResolutionErrorInLibrary( |  | 
| 7914       Source librarySource, CaughtException exception) { |  | 
| 7915     this.exception = exception; |  | 
| 7916     setState(ELEMENT, CacheState.ERROR); |  | 
| 7917     setState(IS_CLIENT, CacheState.ERROR); |  | 
| 7918     setState(IS_LAUNCHABLE, CacheState.ERROR); |  | 
| 7919     setState(PUBLIC_NAMESPACE, CacheState.ERROR); |  | 
| 7920     ResolutionState state = _getOrCreateResolutionState(librarySource); |  | 
| 7921     state.recordResolutionError(); |  | 
| 7922   } |  | 
| 7923 |  | 
| 7924   /** |  | 
| 7925    * Record that an [exception] occurred while attempting to scan or parse the |  | 
| 7926    * entry represented by this entry. This will set the state of all |  | 
| 7927    * information, including any resolution-based information, as being in error. |  | 
| 7928    */ |  | 
| 7929   @override |  | 
| 7930   void recordScanError(CaughtException exception) { |  | 
| 7931     super.recordScanError(exception); |  | 
| 7932     setState(SCAN_ERRORS, CacheState.ERROR); |  | 
| 7933     setState(TOKEN_STREAM, CacheState.ERROR); |  | 
| 7934     recordParseError(exception); |  | 
| 7935   } |  | 
| 7936 |  | 
| 7937   /** |  | 
| 7938    * Record that an [exception] occurred while attempting to generate errors and |  | 
| 7939    * warnings for the source represented by this entry. This will set the state |  | 
| 7940    * of all verification information as being in error. The [librarySource] is |  | 
| 7941    * the source of the library in which verification was being performed. The |  | 
| 7942    * [exception] is the exception that shows where the error occurred. |  | 
| 7943    */ |  | 
| 7944   void recordVerificationErrorInLibrary( |  | 
| 7945       Source librarySource, CaughtException exception) { |  | 
| 7946     this.exception = exception; |  | 
| 7947     ResolutionState state = _getOrCreateResolutionState(librarySource); |  | 
| 7948     state.recordVerificationError(); |  | 
| 7949   } |  | 
| 7950 |  | 
| 7951   /** |  | 
| 7952    * Remove the given [library] from the list of libraries that contain this |  | 
| 7953    * part. This method should only be invoked on entries that represent a part. |  | 
| 7954    */ |  | 
| 7955   void removeContainingLibrary(Source library) { |  | 
| 7956     _containingLibraries.remove(library); |  | 
| 7957   } |  | 
| 7958 |  | 
| 7959   /** |  | 
| 7960    * Remove any resolution information associated with this compilation unit |  | 
| 7961    * being part of the given [library], presumably because it is no longer part |  | 
| 7962    * of the library. |  | 
| 7963    */ |  | 
| 7964   void removeResolution(Source library) { |  | 
| 7965     if (library != null) { |  | 
| 7966       if (library == _resolutionState._librarySource) { |  | 
| 7967         if (_resolutionState._nextState == null) { |  | 
| 7968           _resolutionState.invalidateAllResolutionInformation(); |  | 
| 7969         } else { |  | 
| 7970           _resolutionState = _resolutionState._nextState; |  | 
| 7971         } |  | 
| 7972       } else { |  | 
| 7973         ResolutionState priorState = _resolutionState; |  | 
| 7974         ResolutionState state = _resolutionState._nextState; |  | 
| 7975         while (state != null) { |  | 
| 7976           if (library == state._librarySource) { |  | 
| 7977             priorState._nextState = state._nextState; |  | 
| 7978             break; |  | 
| 7979           } |  | 
| 7980           priorState = state; |  | 
| 7981           state = state._nextState; |  | 
| 7982         } |  | 
| 7983       } |  | 
| 7984     } |  | 
| 7985   } |  | 
| 7986 |  | 
| 7987   /** |  | 
| 7988    * Set the state of the data represented by the given [descriptor] in the |  | 
| 7989    * context of the given [library] to the given [state]. |  | 
| 7990    */ |  | 
| 7991   void setStateInLibrary( |  | 
| 7992       DataDescriptor descriptor, Source library, CacheState state) { |  | 
| 7993     if (!_isValidLibraryDescriptor(descriptor)) { |  | 
| 7994       throw new ArgumentError("Invalid descriptor: $descriptor"); |  | 
| 7995     } |  | 
| 7996     ResolutionState resolutionState = _getOrCreateResolutionState(library); |  | 
| 7997     resolutionState.setState(descriptor, state); |  | 
| 7998   } |  | 
| 7999 |  | 
| 8000   /** |  | 
| 8001    * Set the value of the data represented by the given [descriptor] in the |  | 
| 8002    * context of the given [library] to the given [value], and set the state of |  | 
| 8003    * that data to [CacheState.VALID]. |  | 
| 8004    */ |  | 
| 8005   void setValueInLibrary( |  | 
| 8006       DataDescriptor descriptor, Source library, Object value) { |  | 
| 8007     if (!_isValidLibraryDescriptor(descriptor)) { |  | 
| 8008       throw new ArgumentError("Invalid descriptor: $descriptor"); |  | 
| 8009     } |  | 
| 8010     ResolutionState state = _getOrCreateResolutionState(library); |  | 
| 8011     state.setValue(descriptor, value); |  | 
| 8012   } |  | 
| 8013 |  | 
| 8014   /** |  | 
| 8015    * Invalidate all of the resolution information associated with the |  | 
| 8016    * compilation unit. The flag [invalidateUris] should be `true` if the cached |  | 
| 8017    * results of converting URIs to source files should also be invalidated. |  | 
| 8018    */ |  | 
| 8019   void _discardCachedResolutionInformation(bool invalidateUris) { |  | 
| 8020     setState(ELEMENT, CacheState.INVALID); |  | 
| 8021     setState(IS_CLIENT, CacheState.INVALID); |  | 
| 8022     setState(IS_LAUNCHABLE, CacheState.INVALID); |  | 
| 8023     setState(PUBLIC_NAMESPACE, CacheState.INVALID); |  | 
| 8024     _resolutionState.invalidateAllResolutionInformation(); |  | 
| 8025     if (invalidateUris) { |  | 
| 8026       setState(EXPORTED_LIBRARIES, CacheState.INVALID); |  | 
| 8027       setState(IMPORTED_LIBRARIES, CacheState.INVALID); |  | 
| 8028       setState(INCLUDED_PARTS, CacheState.INVALID); |  | 
| 8029     } |  | 
| 8030   } |  | 
| 8031 |  | 
| 8032   /** |  | 
| 8033    * Return a resolution state for the specified [library], creating one as |  | 
| 8034    * necessary. |  | 
| 8035    */ |  | 
| 8036   ResolutionState _getOrCreateResolutionState(Source library) { |  | 
| 8037     ResolutionState state = _resolutionState; |  | 
| 8038     if (state._librarySource == null) { |  | 
| 8039       state._librarySource = library; |  | 
| 8040       return state; |  | 
| 8041     } |  | 
| 8042     while (state._librarySource != library) { |  | 
| 8043       if (state._nextState == null) { |  | 
| 8044         ResolutionState newState = new ResolutionState(); |  | 
| 8045         newState._librarySource = library; |  | 
| 8046         state._nextState = newState; |  | 
| 8047         return newState; |  | 
| 8048       } |  | 
| 8049       state = state._nextState; |  | 
| 8050     } |  | 
| 8051     return state; |  | 
| 8052   } |  | 
| 8053 |  | 
| 8054   @override |  | 
| 8055   bool _isValidDescriptor(DataDescriptor descriptor) { |  | 
| 8056     return descriptor == CONTAINING_LIBRARIES || |  | 
| 8057         descriptor == ELEMENT || |  | 
| 8058         descriptor == EXPORTED_LIBRARIES || |  | 
| 8059         descriptor == IMPORTED_LIBRARIES || |  | 
| 8060         descriptor == INCLUDED_PARTS || |  | 
| 8061         descriptor == IS_CLIENT || |  | 
| 8062         descriptor == IS_LAUNCHABLE || |  | 
| 8063         descriptor == PARSED_UNIT || |  | 
| 8064         descriptor == PARSE_ERRORS || |  | 
| 8065         descriptor == PUBLIC_NAMESPACE || |  | 
| 8066         descriptor == SCAN_ERRORS || |  | 
| 8067         descriptor == SOURCE_KIND || |  | 
| 8068         descriptor == TOKEN_STREAM || |  | 
| 8069         super._isValidDescriptor(descriptor); |  | 
| 8070   } |  | 
| 8071 |  | 
| 8072   /** |  | 
| 8073    * Return `true` if the [descriptor] is valid for this entry when the data is |  | 
| 8074    * relative to a library. |  | 
| 8075    */ |  | 
| 8076   bool _isValidLibraryDescriptor(DataDescriptor descriptor) { |  | 
| 8077     return descriptor == BUILT_ELEMENT || |  | 
| 8078         descriptor == BUILT_UNIT || |  | 
| 8079         descriptor == HINTS || |  | 
| 8080         descriptor == LINTS || |  | 
| 8081         descriptor == RESOLUTION_ERRORS || |  | 
| 8082         descriptor == RESOLVED_UNIT || |  | 
| 8083         descriptor == VERIFICATION_ERRORS; |  | 
| 8084   } |  | 
| 8085 |  | 
| 8086   @override |  | 
| 8087   bool _writeDiffOn(StringBuffer buffer, SourceEntry oldEntry) { |  | 
| 8088     bool needsSeparator = super._writeDiffOn(buffer, oldEntry); |  | 
| 8089     if (oldEntry is! DartEntry) { |  | 
| 8090       if (needsSeparator) { |  | 
| 8091         buffer.write("; "); |  | 
| 8092       } |  | 
| 8093       buffer.write("entry type changed; was "); |  | 
| 8094       buffer.write(oldEntry.runtimeType.toString()); |  | 
| 8095       return true; |  | 
| 8096     } |  | 
| 8097     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "tokenStream", |  | 
| 8098         DartEntry.TOKEN_STREAM, oldEntry); |  | 
| 8099     needsSeparator = _writeStateDiffOn( |  | 
| 8100         buffer, needsSeparator, "scanErrors", DartEntry.SCAN_ERRORS, oldEntry); |  | 
| 8101     needsSeparator = _writeStateDiffOn( |  | 
| 8102         buffer, needsSeparator, "sourceKind", DartEntry.SOURCE_KIND, oldEntry); |  | 
| 8103     needsSeparator = _writeStateDiffOn( |  | 
| 8104         buffer, needsSeparator, "parsedUnit", DartEntry.PARSED_UNIT, oldEntry); |  | 
| 8105     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "parseErrors", |  | 
| 8106         DartEntry.PARSE_ERRORS, oldEntry); |  | 
| 8107     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, |  | 
| 8108         "importedLibraries", DartEntry.IMPORTED_LIBRARIES, oldEntry); |  | 
| 8109     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, |  | 
| 8110         "exportedLibraries", DartEntry.EXPORTED_LIBRARIES, oldEntry); |  | 
| 8111     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "includedParts", |  | 
| 8112         DartEntry.INCLUDED_PARTS, oldEntry); |  | 
| 8113     needsSeparator = _writeStateDiffOn( |  | 
| 8114         buffer, needsSeparator, "element", DartEntry.ELEMENT, oldEntry); |  | 
| 8115     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, |  | 
| 8116         "publicNamespace", DartEntry.PUBLIC_NAMESPACE, oldEntry); |  | 
| 8117     needsSeparator = _writeStateDiffOn( |  | 
| 8118         buffer, needsSeparator, "clientServer", DartEntry.IS_CLIENT, oldEntry); |  | 
| 8119     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "launchable", |  | 
| 8120         DartEntry.IS_LAUNCHABLE, oldEntry); |  | 
| 8121     // TODO(brianwilkerson) Add better support for containingLibraries. |  | 
| 8122     // It would be nice to be able to report on size-preserving changes. |  | 
| 8123     int oldLibraryCount = (oldEntry as DartEntry)._containingLibraries.length; |  | 
| 8124     int libraryCount = _containingLibraries.length; |  | 
| 8125     if (oldLibraryCount != libraryCount) { |  | 
| 8126       if (needsSeparator) { |  | 
| 8127         buffer.write("; "); |  | 
| 8128       } |  | 
| 8129       buffer.write("containingLibraryCount = "); |  | 
| 8130       buffer.write(oldLibraryCount); |  | 
| 8131       buffer.write(" -> "); |  | 
| 8132       buffer.write(libraryCount); |  | 
| 8133       needsSeparator = true; |  | 
| 8134     } |  | 
| 8135     // |  | 
| 8136     // Report change to the per-library state. |  | 
| 8137     // |  | 
| 8138     HashMap<Source, ResolutionState> oldStateMap = |  | 
| 8139         new HashMap<Source, ResolutionState>(); |  | 
| 8140     ResolutionState state = (oldEntry as DartEntry)._resolutionState; |  | 
| 8141     while (state != null) { |  | 
| 8142       Source librarySource = state._librarySource; |  | 
| 8143       if (librarySource != null) { |  | 
| 8144         oldStateMap[librarySource] = state; |  | 
| 8145       } |  | 
| 8146       state = state._nextState; |  | 
| 8147     } |  | 
| 8148     state = _resolutionState; |  | 
| 8149     while (state != null) { |  | 
| 8150       Source librarySource = state._librarySource; |  | 
| 8151       if (librarySource != null) { |  | 
| 8152         ResolutionState oldState = oldStateMap.remove(librarySource); |  | 
| 8153         if (oldState == null) { |  | 
| 8154           if (needsSeparator) { |  | 
| 8155             buffer.write("; "); |  | 
| 8156           } |  | 
| 8157           buffer.write("added resolution for "); |  | 
| 8158           buffer.write(librarySource.fullName); |  | 
| 8159           needsSeparator = true; |  | 
| 8160         } else { |  | 
| 8161           needsSeparator = oldState._writeDiffOn( |  | 
| 8162               buffer, needsSeparator, oldEntry as DartEntry); |  | 
| 8163         } |  | 
| 8164       } |  | 
| 8165       state = state._nextState; |  | 
| 8166     } |  | 
| 8167     for (Source librarySource in oldStateMap.keys.toSet()) { |  | 
| 8168       if (needsSeparator) { |  | 
| 8169         buffer.write("; "); |  | 
| 8170       } |  | 
| 8171       buffer.write("removed resolution for "); |  | 
| 8172       buffer.write(librarySource.fullName); |  | 
| 8173       needsSeparator = true; |  | 
| 8174     } |  | 
| 8175     return needsSeparator; |  | 
| 8176   } |  | 
| 8177 |  | 
| 8178   @override |  | 
| 8179   void _writeOn(StringBuffer buffer) { |  | 
| 8180     buffer.write("Dart: "); |  | 
| 8181     super._writeOn(buffer); |  | 
| 8182     _writeStateOn(buffer, "tokenStream", TOKEN_STREAM); |  | 
| 8183     _writeStateOn(buffer, "scanErrors", SCAN_ERRORS); |  | 
| 8184     _writeStateOn(buffer, "sourceKind", SOURCE_KIND); |  | 
| 8185     _writeStateOn(buffer, "parsedUnit", PARSED_UNIT); |  | 
| 8186     _writeStateOn(buffer, "parseErrors", PARSE_ERRORS); |  | 
| 8187     _writeStateOn(buffer, "exportedLibraries", EXPORTED_LIBRARIES); |  | 
| 8188     _writeStateOn(buffer, "importedLibraries", IMPORTED_LIBRARIES); |  | 
| 8189     _writeStateOn(buffer, "includedParts", INCLUDED_PARTS); |  | 
| 8190     _writeStateOn(buffer, "element", ELEMENT); |  | 
| 8191     _writeStateOn(buffer, "publicNamespace", PUBLIC_NAMESPACE); |  | 
| 8192     _writeStateOn(buffer, "clientServer", IS_CLIENT); |  | 
| 8193     _writeStateOn(buffer, "launchable", IS_LAUNCHABLE); |  | 
| 8194     _resolutionState._writeOn(buffer); |  | 
| 8195   } |  | 
| 8196 } |  | 
| 8197 |  | 
| 8198 /** |  | 
| 8199  * An immutable constant representing data that can be stored in the cache. |  | 
| 8200  */ |  | 
| 8201 class DataDescriptor<E> { |  | 
| 8202   /** |  | 
| 8203    * The next artificial hash code. |  | 
| 8204    */ |  | 
| 8205   static int _NEXT_HASH_CODE = 0; |  | 
| 8206 |  | 
| 8207   /** |  | 
| 8208    * The artifitial hash code for this object. |  | 
| 8209    */ |  | 
| 8210   final int _hashCode = _NEXT_HASH_CODE++; |  | 
| 8211 |  | 
| 8212   /** |  | 
| 8213    * The name of the descriptor, used for debugging purposes. |  | 
| 8214    */ |  | 
| 8215   final String _name; |  | 
| 8216 |  | 
| 8217   /** |  | 
| 8218    * The default value used when the data does not exist. |  | 
| 8219    */ |  | 
| 8220   final E defaultValue; |  | 
| 8221 |  | 
| 8222   /** |  | 
| 8223    * Initialize a newly created descriptor to have the given [name] and |  | 
| 8224    * [defaultValue]. |  | 
| 8225    */ |  | 
| 8226   DataDescriptor(this._name, [this.defaultValue = null]); |  | 
| 8227 |  | 
| 8228   @override |  | 
| 8229   int get hashCode => _hashCode; |  | 
| 8230 |  | 
| 8231   @override |  | 
| 8232   String toString() => _name; |  | 
| 8233 } |  | 
| 8234 |  | 
| 8235 /** |  | 
| 8236  * A retention policy that will keep AST's in the cache if there is analysis |  | 
| 8237  * information that needs to be computed for a source, where the computation is |  | 
| 8238  * dependent on having the AST. |  | 
| 8239  */ |  | 
| 8240 class DefaultRetentionPolicy implements CacheRetentionPolicy { |  | 
| 8241   /** |  | 
| 8242    * An instance of this class that can be shared. |  | 
| 8243    */ |  | 
| 8244   static DefaultRetentionPolicy POLICY = new DefaultRetentionPolicy(); |  | 
| 8245 |  | 
| 8246   /** |  | 
| 8247    * Return `true` if there is analysis information in the given [dartEntry] |  | 
| 8248    * that needs to be computed, where the computation is dependent on having the |  | 
| 8249    * AST. |  | 
| 8250    */ |  | 
| 8251   bool astIsNeeded(DartEntry dartEntry) => |  | 
| 8252       dartEntry.hasInvalidData(DartEntry.HINTS) || |  | 
| 8253           dartEntry.hasInvalidData(DartEntry.LINTS) || |  | 
| 8254           dartEntry.hasInvalidData(DartEntry.VERIFICATION_ERRORS) || |  | 
| 8255           dartEntry.hasInvalidData(DartEntry.RESOLUTION_ERRORS); |  | 
| 8256 |  | 
| 8257   @override |  | 
| 8258   RetentionPriority getAstPriority(Source source, SourceEntry sourceEntry) { |  | 
| 8259     if (sourceEntry is DartEntry) { |  | 
| 8260       DartEntry dartEntry = sourceEntry; |  | 
| 8261       if (astIsNeeded(dartEntry)) { |  | 
| 8262         return RetentionPriority.MEDIUM; |  | 
| 8263       } |  | 
| 8264     } |  | 
| 8265     return RetentionPriority.LOW; |  | 
| 8266   } |  | 
| 8267 } |  | 
| 8268 |  | 
| 8269 /** |  | 
| 8270  * Instances of the class `GenerateDartErrorsTask` generate errors and warnings 
       for a single |  | 
| 8271  * Dart source. |  | 
| 8272  */ |  | 
| 8273 class GenerateDartErrorsTask extends AnalysisTask { |  | 
| 8274   /** |  | 
| 8275    * The source for which errors and warnings are to be produced. |  | 
| 8276    */ |  | 
| 8277   final Source source; |  | 
| 8278 |  | 
| 8279   /** |  | 
| 8280    * The compilation unit used to resolve the dependencies. |  | 
| 8281    */ |  | 
| 8282   final CompilationUnit _unit; |  | 
| 8283 |  | 
| 8284   /** |  | 
| 8285    * The element model for the library containing the source. |  | 
| 8286    */ |  | 
| 8287   final LibraryElement libraryElement; |  | 
| 8288 |  | 
| 8289   /** |  | 
| 8290    * The errors that were generated for the source. |  | 
| 8291    */ |  | 
| 8292   List<AnalysisError> _errors; |  | 
| 8293 |  | 
| 8294   /** |  | 
| 8295    * Initialize a newly created task to perform analysis within the given contex
       t. |  | 
| 8296    * |  | 
| 8297    * @param context the context in which the task is to be performed |  | 
| 8298    * @param source the source for which errors and warnings are to be produced |  | 
| 8299    * @param unit the compilation unit used to resolve the dependencies |  | 
| 8300    * @param libraryElement the element model for the library containing the sour
       ce |  | 
| 8301    */ |  | 
| 8302   GenerateDartErrorsTask(InternalAnalysisContext context, this.source, |  | 
| 8303       this._unit, this.libraryElement) |  | 
| 8304       : super(context); |  | 
| 8305 |  | 
| 8306   /** |  | 
| 8307    * Return the errors that were generated for the source. |  | 
| 8308    * |  | 
| 8309    * @return the errors that were generated for the source |  | 
| 8310    */ |  | 
| 8311   List<AnalysisError> get errors => _errors; |  | 
| 8312 |  | 
| 8313   @override |  | 
| 8314   String get taskDescription => |  | 
| 8315       "generate errors and warnings for ${source.fullName}"; |  | 
| 8316 |  | 
| 8317   @override |  | 
| 8318   accept(AnalysisTaskVisitor visitor) => |  | 
| 8319       visitor.visitGenerateDartErrorsTask(this); |  | 
| 8320 |  | 
| 8321   @override |  | 
| 8322   void internalPerform() { |  | 
| 8323     PerformanceStatistics.errors.makeCurrentWhile(() { |  | 
| 8324       RecordingErrorListener errorListener = new RecordingErrorListener(); |  | 
| 8325       ErrorReporter errorReporter = new ErrorReporter(errorListener, source); |  | 
| 8326       TypeProvider typeProvider = context.typeProvider; |  | 
| 8327       // |  | 
| 8328       // Validate the directives |  | 
| 8329       // |  | 
| 8330       validateDirectives(context, source, _unit, errorListener); |  | 
| 8331       // |  | 
| 8332       // Use the ConstantVerifier to verify the use of constants. |  | 
| 8333       // This needs to happen before using the ErrorVerifier because some error |  | 
| 8334       // codes need the computed constant values. |  | 
| 8335       // |  | 
| 8336       // TODO(paulberry): as a temporary workaround for issue 21572, |  | 
| 8337       // ConstantVerifier is being run right after ConstantValueComputer, so we |  | 
| 8338       // don't need to run it here.  Once issue 21572 is fixed, re-enable the |  | 
| 8339       // call to ConstantVerifier. |  | 
| 8340 //      ConstantVerifier constantVerifier = new ConstantVerifier(errorReporter, 
       libraryElement, typeProvider); |  | 
| 8341 //      _unit.accept(constantVerifier); |  | 
| 8342       // |  | 
| 8343       // Use the ErrorVerifier to compute the rest of the errors. |  | 
| 8344       // |  | 
| 8345       ErrorVerifier errorVerifier = new ErrorVerifier(errorReporter, |  | 
| 8346           libraryElement, typeProvider, new InheritanceManager(libraryElement)); |  | 
| 8347       _unit.accept(errorVerifier); |  | 
| 8348       _errors = errorListener.getErrorsForSource(source); |  | 
| 8349     }); |  | 
| 8350   } |  | 
| 8351 |  | 
| 8352   /** |  | 
| 8353    * Check each directive in the given compilation unit to see if the referenced
        source exists and |  | 
| 8354    * report an error if it does not. |  | 
| 8355    * |  | 
| 8356    * @param context the context in which the library exists |  | 
| 8357    * @param librarySource the source representing the library containing the dir
       ectives |  | 
| 8358    * @param unit the compilation unit containing the directives to be validated |  | 
| 8359    * @param errorListener the error listener to which errors should be reported |  | 
| 8360    */ |  | 
| 8361   static void validateDirectives(AnalysisContext context, Source librarySource, |  | 
| 8362       CompilationUnit unit, AnalysisErrorListener errorListener) { |  | 
| 8363     for (Directive directive in unit.directives) { |  | 
| 8364       if (directive is UriBasedDirective) { |  | 
| 8365         validateReferencedSource( |  | 
| 8366             context, librarySource, directive, errorListener); |  | 
| 8367       } |  | 
| 8368     } |  | 
| 8369   } |  | 
| 8370 |  | 
| 8371   /** |  | 
| 8372    * Check the given directive to see if the referenced source exists and report
        an error if it does |  | 
| 8373    * not. |  | 
| 8374    * |  | 
| 8375    * @param context the context in which the library exists |  | 
| 8376    * @param librarySource the source representing the library containing the dir
       ective |  | 
| 8377    * @param directive the directive to be verified |  | 
| 8378    * @param errorListener the error listener to which errors should be reported |  | 
| 8379    */ |  | 
| 8380   static void validateReferencedSource(AnalysisContext context, |  | 
| 8381       Source librarySource, UriBasedDirective directive, |  | 
| 8382       AnalysisErrorListener errorListener) { |  | 
| 8383     Source source = directive.source; |  | 
| 8384     if (source != null) { |  | 
| 8385       if (context.exists(source)) { |  | 
| 8386         return; |  | 
| 8387       } |  | 
| 8388     } else { |  | 
| 8389       // Don't report errors already reported by ParseDartTask.resolveDirective |  | 
| 8390       if (directive.validate() != null) { |  | 
| 8391         return; |  | 
| 8392       } |  | 
| 8393     } |  | 
| 8394     StringLiteral uriLiteral = directive.uri; |  | 
| 8395     errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset, |  | 
| 8396         uriLiteral.length, CompileTimeErrorCode.URI_DOES_NOT_EXIST, |  | 
| 8397         [directive.uriContent])); |  | 
| 8398   } |  | 
| 8399 } |  | 
| 8400 |  | 
| 8401 /** |  | 
| 8402  * Instances of the class `GenerateDartHintsTask` generate hints for a single Da
       rt library. |  | 
| 8403  */ |  | 
| 8404 class GenerateDartHintsTask extends AnalysisTask { |  | 
| 8405   /** |  | 
| 8406    * The compilation units that comprise the library, with the defining compilat
       ion unit appearing |  | 
| 8407    * first in the list. |  | 
| 8408    */ |  | 
| 8409   final List<TimestampedData<CompilationUnit>> _units; |  | 
| 8410 |  | 
| 8411   /** |  | 
| 8412    * The element model for the library being analyzed. |  | 
| 8413    */ |  | 
| 8414   final LibraryElement libraryElement; |  | 
| 8415 |  | 
| 8416   /** |  | 
| 8417    * A table mapping the sources that were analyzed to the hints that were |  | 
| 8418    * generated for the sources. |  | 
| 8419    */ |  | 
| 8420   HashMap<Source, List<AnalysisError>> _hintMap; |  | 
| 8421 |  | 
| 8422   /** |  | 
| 8423    * Initialize a newly created task to perform analysis within the given contex
       t. |  | 
| 8424    * |  | 
| 8425    * @param context the context in which the task is to be performed |  | 
| 8426    * @param units the compilation units that comprise the library, with the defi
       ning compilation |  | 
| 8427    *          unit appearing first in the list |  | 
| 8428    * @param libraryElement the element model for the library being analyzed |  | 
| 8429    */ |  | 
| 8430   GenerateDartHintsTask( |  | 
| 8431       InternalAnalysisContext context, this._units, this.libraryElement) |  | 
| 8432       : super(context); |  | 
| 8433 |  | 
| 8434   /** |  | 
| 8435    * Return a table mapping the sources that were analyzed to the hints that wer
       e generated for the |  | 
| 8436    * sources, or `null` if the task has not been performed or if the analysis di
       d not complete |  | 
| 8437    * normally. |  | 
| 8438    * |  | 
| 8439    * @return a table mapping the sources that were analyzed to the hints that we
       re generated for the |  | 
| 8440    *         sources |  | 
| 8441    */ |  | 
| 8442   HashMap<Source, List<AnalysisError>> get hintMap => _hintMap; |  | 
| 8443 |  | 
| 8444   @override |  | 
| 8445   String get taskDescription { |  | 
| 8446     Source librarySource = libraryElement.source; |  | 
| 8447     if (librarySource == null) { |  | 
| 8448       return "generate Dart hints for library without source"; |  | 
| 8449     } |  | 
| 8450     return "generate Dart hints for ${librarySource.fullName}"; |  | 
| 8451   } |  | 
| 8452 |  | 
| 8453   @override |  | 
| 8454   accept(AnalysisTaskVisitor visitor) => |  | 
| 8455       visitor.visitGenerateDartHintsTask(this); |  | 
| 8456 |  | 
| 8457   @override |  | 
| 8458   void internalPerform() { |  | 
| 8459     // |  | 
| 8460     // Gather the compilation units. |  | 
| 8461     // |  | 
| 8462     int unitCount = _units.length; |  | 
| 8463     List<CompilationUnit> compilationUnits = |  | 
| 8464         new List<CompilationUnit>(unitCount); |  | 
| 8465     for (int i = 0; i < unitCount; i++) { |  | 
| 8466       compilationUnits[i] = _units[i].data; |  | 
| 8467     } |  | 
| 8468     // |  | 
| 8469     // Analyze all of the units. |  | 
| 8470     // |  | 
| 8471     RecordingErrorListener errorListener = new RecordingErrorListener(); |  | 
| 8472     HintGenerator hintGenerator = |  | 
| 8473         new HintGenerator(compilationUnits, context, errorListener); |  | 
| 8474     hintGenerator.generateForLibrary(); |  | 
| 8475     // |  | 
| 8476     // Store the results. |  | 
| 8477     // |  | 
| 8478     _hintMap = new HashMap<Source, List<AnalysisError>>(); |  | 
| 8479     for (int i = 0; i < unitCount; i++) { |  | 
| 8480       Source source = _units[i].data.element.source; |  | 
| 8481       _hintMap[source] = errorListener.getErrorsForSource(source); |  | 
| 8482     } |  | 
| 8483   } |  | 
| 8484 } |  | 
| 8485 |  | 
| 8486 /// Generates lint feedback for a single Dart library. |  | 
| 8487 class GenerateDartLintsTask extends AnalysisTask { |  | 
| 8488 |  | 
| 8489   ///The compilation units that comprise the library, with the defining |  | 
| 8490   ///compilation unit appearing first in the list. |  | 
| 8491   final List<TimestampedData<CompilationUnit>> _units; |  | 
| 8492 |  | 
| 8493   /// The element model for the library being analyzed. |  | 
| 8494   final LibraryElement libraryElement; |  | 
| 8495 |  | 
| 8496   /// A mapping of analyzed sources to their associated lint warnings. |  | 
| 8497   /// May be [null] if the task has not been performed or if analysis did not |  | 
| 8498   /// complete normally. |  | 
| 8499   HashMap<Source, List<AnalysisError>> lintMap; |  | 
| 8500 |  | 
| 8501   /// Initialize a newly created task to perform lint checking over these |  | 
| 8502   /// [_units] belonging to this [libraryElement] within the given [context]. |  | 
| 8503   GenerateDartLintsTask(context, this._units, this.libraryElement) |  | 
| 8504       : super(context); |  | 
| 8505 |  | 
| 8506   @override |  | 
| 8507   String get taskDescription { |  | 
| 8508     Source librarySource = libraryElement.source; |  | 
| 8509     return (librarySource == null) |  | 
| 8510         ? "generate Dart lints for library without source" |  | 
| 8511         : "generate Dart lints for ${librarySource.fullName}"; |  | 
| 8512   } |  | 
| 8513 |  | 
| 8514   @override |  | 
| 8515   accept(AnalysisTaskVisitor visitor) => |  | 
| 8516       visitor.visitGenerateDartLintsTask(this); |  | 
| 8517 |  | 
| 8518   @override |  | 
| 8519   void internalPerform() { |  | 
| 8520     Iterable<CompilationUnit> compilationUnits = |  | 
| 8521         _units.map((TimestampedData<CompilationUnit> unit) => unit.data); |  | 
| 8522     RecordingErrorListener errorListener = new RecordingErrorListener(); |  | 
| 8523     LintGenerator lintGenerator = |  | 
| 8524         new LintGenerator(compilationUnits, errorListener); |  | 
| 8525     lintGenerator.generate(); |  | 
| 8526 |  | 
| 8527     lintMap = new HashMap<Source, List<AnalysisError>>(); |  | 
| 8528     compilationUnits.forEach((CompilationUnit unit) { |  | 
| 8529       Source source = unit.element.source; |  | 
| 8530       lintMap[source] = errorListener.getErrorsForSource(source); |  | 
| 8531     }); |  | 
| 8532   } |  | 
| 8533 } |  | 
| 8534 |  | 
| 8535 /** |  | 
| 8536  * Instances of the class `GetContentTask` get the contents of a source. |  | 
| 8537  */ |  | 
| 8538 class GetContentTask extends AnalysisTask { |  | 
| 8539   /** |  | 
| 8540    * The source to be read. |  | 
| 8541    */ |  | 
| 8542   final Source source; |  | 
| 8543 |  | 
| 8544   /** |  | 
| 8545    * A flag indicating whether this task is complete. |  | 
| 8546    */ |  | 
| 8547   bool _complete = false; |  | 
| 8548 |  | 
| 8549   /** |  | 
| 8550    * The contents of the source. |  | 
| 8551    */ |  | 
| 8552   String _content; |  | 
| 8553 |  | 
| 8554   /** |  | 
| 8555    * The errors that were produced by getting the source content. |  | 
| 8556    */ |  | 
| 8557   final List<AnalysisError> errors = <AnalysisError>[]; |  | 
| 8558 |  | 
| 8559   /** |  | 
| 8560    * The time at which the contents of the source were last modified. |  | 
| 8561    */ |  | 
| 8562   int _modificationTime = -1; |  | 
| 8563 |  | 
| 8564   /** |  | 
| 8565    * Initialize a newly created task to perform analysis within the given contex
       t. |  | 
| 8566    * |  | 
| 8567    * @param context the context in which the task is to be performed |  | 
| 8568    * @param source the source to be parsed |  | 
| 8569    * @param contentData the time-stamped contents of the source |  | 
| 8570    */ |  | 
| 8571   GetContentTask(InternalAnalysisContext context, this.source) |  | 
| 8572       : super(context) { |  | 
| 8573     if (source == null) { |  | 
| 8574       throw new IllegalArgumentException("Cannot get contents of null source"); |  | 
| 8575     } |  | 
| 8576   } |  | 
| 8577 |  | 
| 8578   /** |  | 
| 8579    * Return the contents of the source, or `null` if the task has not completed 
       or if there |  | 
| 8580    * was an exception while getting the contents. |  | 
| 8581    * |  | 
| 8582    * @return the contents of the source |  | 
| 8583    */ |  | 
| 8584   String get content => _content; |  | 
| 8585 |  | 
| 8586   /** |  | 
| 8587    * Return `true` if this task is complete. Unlike most tasks, this task is all
       owed to be |  | 
| 8588    * visited more than once in order to support asynchronous IO. If the task is 
       not complete when it |  | 
| 8589    * is visited synchronously as part of the [AnalysisTask.perform] |  | 
| 8590    * method, it will be visited again, using the same visitor, when the IO opera
       tion has been |  | 
| 8591    * performed. |  | 
| 8592    * |  | 
| 8593    * @return `true` if this task is complete |  | 
| 8594    */ |  | 
| 8595   bool get isComplete => _complete; |  | 
| 8596 |  | 
| 8597   /** |  | 
| 8598    * Return the time at which the contents of the source that was parsed were la
       st modified, or a |  | 
| 8599    * negative value if the task has not yet been performed or if an exception oc
       curred. |  | 
| 8600    * |  | 
| 8601    * @return the time at which the contents of the source that was parsed were l
       ast modified |  | 
| 8602    */ |  | 
| 8603   int get modificationTime => _modificationTime; |  | 
| 8604 |  | 
| 8605   @override |  | 
| 8606   String get taskDescription => "get contents of ${source.fullName}"; |  | 
| 8607 |  | 
| 8608   @override |  | 
| 8609   accept(AnalysisTaskVisitor visitor) => visitor.visitGetContentTask(this); |  | 
| 8610 |  | 
| 8611   @override |  | 
| 8612   void internalPerform() { |  | 
| 8613     _complete = true; |  | 
| 8614     try { |  | 
| 8615       TimestampedData<String> data = context.getContents(source); |  | 
| 8616       _content = data.data; |  | 
| 8617       _modificationTime = data.modificationTime; |  | 
| 8618       AnalysisEngine.instance.instrumentationService.logFileRead( |  | 
| 8619           source.fullName, _modificationTime, _content); |  | 
| 8620     } catch (exception, stackTrace) { |  | 
| 8621       errors.add(new AnalysisError( |  | 
| 8622           source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [exception])); |  | 
| 8623       throw new AnalysisException("Could not get contents of $source", |  | 
| 8624           new CaughtException(exception, stackTrace)); |  | 
| 8625     } |  | 
| 8626   } |  | 
| 8627 } |  | 
| 8628 |  | 
| 8629 /** |  | 
| 8630  * The information cached by an analysis context about an individual HTML file. |  | 
| 8631  */ |  | 
| 8632 class HtmlEntry extends SourceEntry { |  | 
| 8633   /** |  | 
| 8634    * The data descriptor representing the HTML element. |  | 
| 8635    */ |  | 
| 8636   static final DataDescriptor<HtmlElement> ELEMENT = |  | 
| 8637       new DataDescriptor<HtmlElement>("HtmlEntry.ELEMENT"); |  | 
| 8638 |  | 
| 8639   /** |  | 
| 8640    * The data descriptor representing the hints resulting from auditing the |  | 
| 8641    * source. |  | 
| 8642    */ |  | 
| 8643   static final DataDescriptor<List<AnalysisError>> HINTS = |  | 
| 8644       new DataDescriptor<List<AnalysisError>>( |  | 
| 8645           "HtmlEntry.HINTS", AnalysisError.NO_ERRORS); |  | 
| 8646 |  | 
| 8647   /** |  | 
| 8648    * The data descriptor representing the errors resulting from parsing the |  | 
| 8649    * source. |  | 
| 8650    */ |  | 
| 8651   static final DataDescriptor<List<AnalysisError>> PARSE_ERRORS = |  | 
| 8652       new DataDescriptor<List<AnalysisError>>( |  | 
| 8653           "HtmlEntry.PARSE_ERRORS", AnalysisError.NO_ERRORS); |  | 
| 8654 |  | 
| 8655   /** |  | 
| 8656    * The data descriptor representing the parsed AST structure. |  | 
| 8657    */ |  | 
| 8658   static final DataDescriptor<ht.HtmlUnit> PARSED_UNIT = |  | 
| 8659       new DataDescriptor<ht.HtmlUnit>("HtmlEntry.PARSED_UNIT"); |  | 
| 8660 |  | 
| 8661   /** |  | 
| 8662    * The data descriptor representing the resolved AST structure. |  | 
| 8663    */ |  | 
| 8664   static final DataDescriptor<ht.HtmlUnit> RESOLVED_UNIT = |  | 
| 8665       new DataDescriptor<ht.HtmlUnit>("HtmlEntry.RESOLVED_UNIT"); |  | 
| 8666 |  | 
| 8667   /** |  | 
| 8668    * The data descriptor representing the list of referenced libraries. |  | 
| 8669    */ |  | 
| 8670   static final DataDescriptor<List<Source>> REFERENCED_LIBRARIES = |  | 
| 8671       new DataDescriptor<List<Source>>( |  | 
| 8672           "HtmlEntry.REFERENCED_LIBRARIES", Source.EMPTY_LIST); |  | 
| 8673 |  | 
| 8674   /** |  | 
| 8675    * The data descriptor representing the errors resulting from resolving the |  | 
| 8676    * source. |  | 
| 8677    */ |  | 
| 8678   static final DataDescriptor<List<AnalysisError>> RESOLUTION_ERRORS = |  | 
| 8679       new DataDescriptor<List<AnalysisError>>( |  | 
| 8680           "HtmlEntry.RESOLUTION_ERRORS", AnalysisError.NO_ERRORS); |  | 
| 8681 |  | 
| 8682   /** |  | 
| 8683    * Return all of the errors associated with the HTML file that are currently |  | 
| 8684    * cached. |  | 
| 8685    */ |  | 
| 8686   List<AnalysisError> get allErrors { |  | 
| 8687     List<AnalysisError> errors = new List<AnalysisError>(); |  | 
| 8688     errors.addAll(super.allErrors); |  | 
| 8689     errors.addAll(getValue(PARSE_ERRORS)); |  | 
| 8690     errors.addAll(getValue(RESOLUTION_ERRORS)); |  | 
| 8691     errors.addAll(getValue(HINTS)); |  | 
| 8692     if (errors.length == 0) { |  | 
| 8693       return AnalysisError.NO_ERRORS; |  | 
| 8694     } |  | 
| 8695     return errors; |  | 
| 8696   } |  | 
| 8697 |  | 
| 8698   /** |  | 
| 8699    * Return a valid parsed unit, either an unresolved AST structure or the |  | 
| 8700    * result of resolving the AST structure, or `null` if there is no parsed unit |  | 
| 8701    * available. |  | 
| 8702    */ |  | 
| 8703   ht.HtmlUnit get anyParsedUnit { |  | 
| 8704     if (getState(PARSED_UNIT) == CacheState.VALID) { |  | 
| 8705       return getValue(PARSED_UNIT); |  | 
| 8706     } |  | 
| 8707     if (getState(RESOLVED_UNIT) == CacheState.VALID) { |  | 
| 8708       return getValue(RESOLVED_UNIT); |  | 
| 8709     } |  | 
| 8710     return null; |  | 
| 8711   } |  | 
| 8712 |  | 
| 8713   @override |  | 
| 8714   List<DataDescriptor> get descriptors { |  | 
| 8715     List<DataDescriptor> result = super.descriptors; |  | 
| 8716     result.addAll([ |  | 
| 8717       HtmlEntry.ELEMENT, |  | 
| 8718       HtmlEntry.PARSE_ERRORS, |  | 
| 8719       HtmlEntry.PARSED_UNIT, |  | 
| 8720       HtmlEntry.RESOLUTION_ERRORS, |  | 
| 8721       HtmlEntry.RESOLVED_UNIT, |  | 
| 8722       HtmlEntry.HINTS |  | 
| 8723     ]); |  | 
| 8724     return result; |  | 
| 8725   } |  | 
| 8726 |  | 
| 8727   @override |  | 
| 8728   SourceKind get kind => SourceKind.HTML; |  | 
| 8729 |  | 
| 8730   /** |  | 
| 8731    * Flush any AST structures being maintained by this entry. |  | 
| 8732    */ |  | 
| 8733   void flushAstStructures() { |  | 
| 8734     _flush(PARSED_UNIT); |  | 
| 8735     _flush(RESOLVED_UNIT); |  | 
| 8736   } |  | 
| 8737 |  | 
| 8738   @override |  | 
| 8739   void invalidateAllInformation() { |  | 
| 8740     super.invalidateAllInformation(); |  | 
| 8741     setState(PARSE_ERRORS, CacheState.INVALID); |  | 
| 8742     setState(PARSED_UNIT, CacheState.INVALID); |  | 
| 8743     setState(RESOLVED_UNIT, CacheState.INVALID); |  | 
| 8744     invalidateAllResolutionInformation(true); |  | 
| 8745   } |  | 
| 8746 |  | 
| 8747   /** |  | 
| 8748    * Invalidate all of the resolution information associated with the HTML file. |  | 
| 8749    * If [invalidateUris] is `true`, the cached results of converting URIs to |  | 
| 8750    * source files should also be invalidated. |  | 
| 8751    */ |  | 
| 8752   void invalidateAllResolutionInformation(bool invalidateUris) { |  | 
| 8753     setState(RESOLVED_UNIT, CacheState.INVALID); |  | 
| 8754     setState(ELEMENT, CacheState.INVALID); |  | 
| 8755     setState(RESOLUTION_ERRORS, CacheState.INVALID); |  | 
| 8756     setState(HINTS, CacheState.INVALID); |  | 
| 8757     if (invalidateUris) { |  | 
| 8758       setState(REFERENCED_LIBRARIES, CacheState.INVALID); |  | 
| 8759     } |  | 
| 8760   } |  | 
| 8761 |  | 
| 8762   /** |  | 
| 8763    * Invalidate all of the parse and resolution information associated with |  | 
| 8764    * this source. |  | 
| 8765    */ |  | 
| 8766   void invalidateParseInformation() { |  | 
| 8767     setState(PARSE_ERRORS, CacheState.INVALID); |  | 
| 8768     setState(PARSED_UNIT, CacheState.INVALID); |  | 
| 8769     invalidateAllResolutionInformation(true); |  | 
| 8770   } |  | 
| 8771 |  | 
| 8772   @override |  | 
| 8773   void recordContentError(CaughtException exception) { |  | 
| 8774     super.recordContentError(exception); |  | 
| 8775     recordParseError(exception); |  | 
| 8776   } |  | 
| 8777 |  | 
| 8778   /** |  | 
| 8779    * Record that an [exception] was encountered while attempting to parse the |  | 
| 8780    * source associated with this entry. |  | 
| 8781    */ |  | 
| 8782   void recordParseError(CaughtException exception) { |  | 
| 8783     // If the scanning and parsing of HTML are separated, |  | 
| 8784     // the following line can be removed. |  | 
| 8785     recordScanError(exception); |  | 
| 8786     setState(PARSE_ERRORS, CacheState.ERROR); |  | 
| 8787     setState(PARSED_UNIT, CacheState.ERROR); |  | 
| 8788     setState(REFERENCED_LIBRARIES, CacheState.ERROR); |  | 
| 8789     recordResolutionError(exception); |  | 
| 8790   } |  | 
| 8791 |  | 
| 8792   /** |  | 
| 8793    * Record that an [exception] was encountered while attempting to resolve the |  | 
| 8794    * source associated with this entry. |  | 
| 8795    */ |  | 
| 8796   void recordResolutionError(CaughtException exception) { |  | 
| 8797     this.exception = exception; |  | 
| 8798     setState(RESOLVED_UNIT, CacheState.ERROR); |  | 
| 8799     setState(ELEMENT, CacheState.ERROR); |  | 
| 8800     setState(RESOLUTION_ERRORS, CacheState.ERROR); |  | 
| 8801     setState(HINTS, CacheState.ERROR); |  | 
| 8802   } |  | 
| 8803 |  | 
| 8804   @override |  | 
| 8805   bool _isValidDescriptor(DataDescriptor descriptor) { |  | 
| 8806     return descriptor == ELEMENT || |  | 
| 8807         descriptor == HINTS || |  | 
| 8808         descriptor == PARSED_UNIT || |  | 
| 8809         descriptor == PARSE_ERRORS || |  | 
| 8810         descriptor == REFERENCED_LIBRARIES || |  | 
| 8811         descriptor == RESOLUTION_ERRORS || |  | 
| 8812         descriptor == RESOLVED_UNIT || |  | 
| 8813         super._isValidDescriptor(descriptor); |  | 
| 8814   } |  | 
| 8815 |  | 
| 8816   @override |  | 
| 8817   bool _writeDiffOn(StringBuffer buffer, SourceEntry oldEntry) { |  | 
| 8818     bool needsSeparator = super._writeDiffOn(buffer, oldEntry); |  | 
| 8819     if (oldEntry is! HtmlEntry) { |  | 
| 8820       if (needsSeparator) { |  | 
| 8821         buffer.write("; "); |  | 
| 8822       } |  | 
| 8823       buffer.write("entry type changed; was "); |  | 
| 8824       buffer.write(oldEntry.runtimeType); |  | 
| 8825       return true; |  | 
| 8826     } |  | 
| 8827     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "parseErrors", |  | 
| 8828         HtmlEntry.PARSE_ERRORS, oldEntry); |  | 
| 8829     needsSeparator = _writeStateDiffOn( |  | 
| 8830         buffer, needsSeparator, "parsedUnit", HtmlEntry.PARSED_UNIT, oldEntry); |  | 
| 8831     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "resolvedUnit", |  | 
| 8832         HtmlEntry.RESOLVED_UNIT, oldEntry); |  | 
| 8833     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, |  | 
| 8834         "resolutionErrors", HtmlEntry.RESOLUTION_ERRORS, oldEntry); |  | 
| 8835     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, |  | 
| 8836         "referencedLibraries", HtmlEntry.REFERENCED_LIBRARIES, oldEntry); |  | 
| 8837     needsSeparator = _writeStateDiffOn( |  | 
| 8838         buffer, needsSeparator, "element", HtmlEntry.ELEMENT, oldEntry); |  | 
| 8839     return needsSeparator; |  | 
| 8840   } |  | 
| 8841 |  | 
| 8842   @override |  | 
| 8843   void _writeOn(StringBuffer buffer) { |  | 
| 8844     buffer.write("Html: "); |  | 
| 8845     super._writeOn(buffer); |  | 
| 8846     _writeStateOn(buffer, "parseErrors", PARSE_ERRORS); |  | 
| 8847     _writeStateOn(buffer, "parsedUnit", PARSED_UNIT); |  | 
| 8848     _writeStateOn(buffer, "resolvedUnit", RESOLVED_UNIT); |  | 
| 8849     _writeStateOn(buffer, "resolutionErrors", RESOLUTION_ERRORS); |  | 
| 8850     _writeStateOn(buffer, "referencedLibraries", REFERENCED_LIBRARIES); |  | 
| 8851     _writeStateOn(buffer, "element", ELEMENT); |  | 
| 8852   } |  | 
| 8853 } |  | 
| 8854 |  | 
| 8855 /** |  | 
| 8856  * Instances of the class `IncrementalAnalysisCache` hold information used to pe
       rform |  | 
| 8857  * incremental analysis. |  | 
| 8858  * |  | 
| 8859  * See [AnalysisContextImpl.setChangedContents]. |  | 
| 8860  */ |  | 
| 8861 class IncrementalAnalysisCache { |  | 
| 8862   final Source librarySource; |  | 
| 8863 |  | 
| 8864   final Source source; |  | 
| 8865 |  | 
| 8866   final String oldContents; |  | 
| 8867 |  | 
| 8868   final CompilationUnit resolvedUnit; |  | 
| 8869 |  | 
| 8870   String _newContents; |  | 
| 8871 |  | 
| 8872   int _offset = 0; |  | 
| 8873 |  | 
| 8874   int _oldLength = 0; |  | 
| 8875 |  | 
| 8876   int _newLength = 0; |  | 
| 8877 |  | 
| 8878   IncrementalAnalysisCache(this.librarySource, this.source, this.resolvedUnit, |  | 
| 8879       this.oldContents, String newContents, int offset, int oldLength, |  | 
| 8880       int newLength) { |  | 
| 8881     this._newContents = newContents; |  | 
| 8882     this._offset = offset; |  | 
| 8883     this._oldLength = oldLength; |  | 
| 8884     this._newLength = newLength; |  | 
| 8885   } |  | 
| 8886 |  | 
| 8887   /** |  | 
| 8888    * Determine if the cache contains source changes that need to be analyzed |  | 
| 8889    * |  | 
| 8890    * @return `true` if the cache contains changes to be analyzed, else `false` |  | 
| 8891    */ |  | 
| 8892   bool get hasWork => _oldLength > 0 || _newLength > 0; |  | 
| 8893 |  | 
| 8894   /** |  | 
| 8895    * Return the current contents for the receiver's source. |  | 
| 8896    * |  | 
| 8897    * @return the contents (not `null`) |  | 
| 8898    */ |  | 
| 8899   String get newContents => _newContents; |  | 
| 8900 |  | 
| 8901   /** |  | 
| 8902    * Return the number of characters in the replacement text. |  | 
| 8903    * |  | 
| 8904    * @return the replacement length (zero or greater) |  | 
| 8905    */ |  | 
| 8906   int get newLength => _newLength; |  | 
| 8907 |  | 
| 8908   /** |  | 
| 8909    * Return the character position of the first changed character. |  | 
| 8910    * |  | 
| 8911    * @return the offset (zero or greater) |  | 
| 8912    */ |  | 
| 8913   int get offset => _offset; |  | 
| 8914 |  | 
| 8915   /** |  | 
| 8916    * Return the number of characters that were replaced. |  | 
| 8917    * |  | 
| 8918    * @return the replaced length (zero or greater) |  | 
| 8919    */ |  | 
| 8920   int get oldLength => _oldLength; |  | 
| 8921 |  | 
| 8922   /** |  | 
| 8923    * Determine if the incremental analysis result can be cached for the next inc
       remental analysis. |  | 
| 8924    * |  | 
| 8925    * @param cache the prior incremental analysis cache |  | 
| 8926    * @param unit the incrementally updated compilation unit |  | 
| 8927    * @return the cache used for incremental analysis or `null` if incremental an
       alysis results |  | 
| 8928    *         cannot be cached for the next incremental analysis |  | 
| 8929    */ |  | 
| 8930   static IncrementalAnalysisCache cacheResult( |  | 
| 8931       IncrementalAnalysisCache cache, CompilationUnit unit) { |  | 
| 8932     if (cache != null && unit != null) { |  | 
| 8933       return new IncrementalAnalysisCache(cache.librarySource, cache.source, |  | 
| 8934           unit, cache._newContents, cache._newContents, 0, 0, 0); |  | 
| 8935     } |  | 
| 8936     return null; |  | 
| 8937   } |  | 
| 8938 |  | 
| 8939   /** |  | 
| 8940    * Determine if the cache should be cleared. |  | 
| 8941    * |  | 
| 8942    * @param cache the prior cache or `null` if none |  | 
| 8943    * @param source the source being updated (not `null`) |  | 
| 8944    * @return the cache used for incremental analysis or `null` if incremental an
       alysis cannot |  | 
| 8945    *         be performed |  | 
| 8946    */ |  | 
| 8947   static IncrementalAnalysisCache clear( |  | 
| 8948       IncrementalAnalysisCache cache, Source source) { |  | 
| 8949     if (cache == null || cache.source == source) { |  | 
| 8950       return null; |  | 
| 8951     } |  | 
| 8952     return cache; |  | 
| 8953   } |  | 
| 8954 |  | 
| 8955   /** |  | 
| 8956    * Determine if incremental analysis can be performed from the given informati
       on. |  | 
| 8957    * |  | 
| 8958    * @param cache the prior cache or `null` if none |  | 
| 8959    * @param source the source being updated (not `null`) |  | 
| 8960    * @param oldContents the original source contents prior to this update (may b
       e `null`) |  | 
| 8961    * @param newContents the new contents after this incremental change (not `nul
       l`) |  | 
| 8962    * @param offset the offset at which the change occurred |  | 
| 8963    * @param oldLength the length of the text being replaced |  | 
| 8964    * @param newLength the length of the replacement text |  | 
| 8965    * @param sourceEntry the cached entry for the given source or `null` if none |  | 
| 8966    * @return the cache used for incremental analysis or `null` if incremental an
       alysis cannot |  | 
| 8967    *         be performed |  | 
| 8968    */ |  | 
| 8969   static IncrementalAnalysisCache update(IncrementalAnalysisCache cache, |  | 
| 8970       Source source, String oldContents, String newContents, int offset, |  | 
| 8971       int oldLength, int newLength, SourceEntry sourceEntry) { |  | 
| 8972     // Determine the cache resolved unit |  | 
| 8973     Source librarySource = null; |  | 
| 8974     CompilationUnit unit = null; |  | 
| 8975     if (sourceEntry is DartEntry) { |  | 
| 8976       DartEntry dartEntry = sourceEntry; |  | 
| 8977       List<Source> librarySources = dartEntry.librariesContaining; |  | 
| 8978       if (librarySources.length == 1) { |  | 
| 8979         librarySource = librarySources[0]; |  | 
| 8980         if (librarySource != null) { |  | 
| 8981           unit = dartEntry.getValueInLibrary( |  | 
| 8982               DartEntry.RESOLVED_UNIT, librarySource); |  | 
| 8983         } |  | 
| 8984       } |  | 
| 8985     } |  | 
| 8986     // Create a new cache if there is not an existing cache or the source is |  | 
| 8987     // different or a new resolved compilation unit is available. |  | 
| 8988     if (cache == null || cache.source != source || unit != null) { |  | 
| 8989       if (unit == null) { |  | 
| 8990         return null; |  | 
| 8991       } |  | 
| 8992       if (oldContents == null) { |  | 
| 8993         if (oldLength != 0) { |  | 
| 8994           return null; |  | 
| 8995         } |  | 
| 8996         oldContents = |  | 
| 8997             "${newContents.substring(0, offset)}${newContents.substring(offset +
        newLength)}"; |  | 
| 8998       } |  | 
| 8999       return new IncrementalAnalysisCache(librarySource, source, unit, |  | 
| 9000           oldContents, newContents, offset, oldLength, newLength); |  | 
| 9001     } |  | 
| 9002     // Update the existing cache if the change is contiguous |  | 
| 9003     if (cache._oldLength == 0 && cache._newLength == 0) { |  | 
| 9004       cache._offset = offset; |  | 
| 9005       cache._oldLength = oldLength; |  | 
| 9006       cache._newLength = newLength; |  | 
| 9007     } else { |  | 
| 9008       if (cache._offset > offset || offset > cache._offset + cache._newLength) { |  | 
| 9009         return null; |  | 
| 9010       } |  | 
| 9011       cache._newLength += newLength - oldLength; |  | 
| 9012     } |  | 
| 9013     cache._newContents = newContents; |  | 
| 9014     return cache; |  | 
| 9015   } |  | 
| 9016 |  | 
| 9017   /** |  | 
| 9018    * Verify that the incrementally parsed and resolved unit in the incremental c
       ache is structurally |  | 
| 9019    * equivalent to the fully parsed unit. |  | 
| 9020    * |  | 
| 9021    * @param cache the prior cache or `null` if none |  | 
| 9022    * @param source the source of the compilation unit that was parsed (not `null
       `) |  | 
| 9023    * @param unit the compilation unit that was just parsed |  | 
| 9024    * @return the cache used for incremental analysis or `null` if incremental an
       alysis results |  | 
| 9025    *         cannot be cached for the next incremental analysis |  | 
| 9026    */ |  | 
| 9027   static IncrementalAnalysisCache verifyStructure( |  | 
| 9028       IncrementalAnalysisCache cache, Source source, CompilationUnit unit) { |  | 
| 9029     if (cache != null && unit != null && cache.source == source) { |  | 
| 9030       if (!AstComparator.equalNodes(cache.resolvedUnit, unit)) { |  | 
| 9031         return null; |  | 
| 9032       } |  | 
| 9033     } |  | 
| 9034     return cache; |  | 
| 9035   } |  | 
| 9036 } |  | 
| 9037 |  | 
| 9038 /** |  | 
| 9039  * Instances of the class `IncrementalAnalysisTask` incrementally update existin
       g analysis. |  | 
| 9040  */ |  | 
| 9041 class IncrementalAnalysisTask extends AnalysisTask { |  | 
| 9042   /** |  | 
| 9043    * The information used to perform incremental analysis. |  | 
| 9044    */ |  | 
| 9045   final IncrementalAnalysisCache cache; |  | 
| 9046 |  | 
| 9047   /** |  | 
| 9048    * The compilation unit that was produced by incrementally updating the existi
       ng unit. |  | 
| 9049    */ |  | 
| 9050   CompilationUnit _updatedUnit; |  | 
| 9051 |  | 
| 9052   /** |  | 
| 9053    * Initialize a newly created task to perform analysis within the given contex
       t. |  | 
| 9054    * |  | 
| 9055    * @param context the context in which the task is to be performed |  | 
| 9056    * @param cache the incremental analysis cache used to perform the analysis |  | 
| 9057    */ |  | 
| 9058   IncrementalAnalysisTask(InternalAnalysisContext context, this.cache) |  | 
| 9059       : super(context); |  | 
| 9060 |  | 
| 9061   /** |  | 
| 9062    * Return the compilation unit that was produced by incrementally updating the
        existing |  | 
| 9063    * compilation unit, or `null` if the task has not yet been performed, could n
       ot be |  | 
| 9064    * performed, or if an exception occurred. |  | 
| 9065    * |  | 
| 9066    * @return the compilation unit |  | 
| 9067    */ |  | 
| 9068   CompilationUnit get compilationUnit => _updatedUnit; |  | 
| 9069 |  | 
| 9070   /** |  | 
| 9071    * Return the source that is to be incrementally analyzed. |  | 
| 9072    * |  | 
| 9073    * @return the source |  | 
| 9074    */ |  | 
| 9075   Source get source => cache != null ? cache.source : null; |  | 
| 9076 |  | 
| 9077   @override |  | 
| 9078   String get taskDescription => |  | 
| 9079       "incremental analysis ${cache != null ? cache.source : "null"}"; |  | 
| 9080 |  | 
| 9081   /** |  | 
| 9082    * Return the type provider used for incremental resolution. |  | 
| 9083    * |  | 
| 9084    * @return the type provider (or `null` if an exception occurs) |  | 
| 9085    */ |  | 
| 9086   TypeProvider get typeProvider { |  | 
| 9087     try { |  | 
| 9088       return context.typeProvider; |  | 
| 9089     } on AnalysisException { |  | 
| 9090       return null; |  | 
| 9091     } |  | 
| 9092   } |  | 
| 9093 |  | 
| 9094   @override |  | 
| 9095   accept(AnalysisTaskVisitor visitor) => |  | 
| 9096       visitor.visitIncrementalAnalysisTask(this); |  | 
| 9097 |  | 
| 9098   @override |  | 
| 9099   void internalPerform() { |  | 
| 9100     if (cache == null) { |  | 
| 9101       return; |  | 
| 9102     } |  | 
| 9103     // Only handle small changes |  | 
| 9104     if (cache.oldLength > 0 || cache.newLength > 30) { |  | 
| 9105       return; |  | 
| 9106     } |  | 
| 9107     // Produce an updated token stream |  | 
| 9108     CharacterReader reader = new CharSequenceReader(cache.newContents); |  | 
| 9109     BooleanErrorListener errorListener = new BooleanErrorListener(); |  | 
| 9110     IncrementalScanner scanner = new IncrementalScanner( |  | 
| 9111         cache.source, reader, errorListener, context.analysisOptions); |  | 
| 9112     scanner.rescan(cache.resolvedUnit.beginToken, cache.offset, cache.oldLength, |  | 
| 9113         cache.newLength); |  | 
| 9114     if (errorListener.errorReported) { |  | 
| 9115       return; |  | 
| 9116     } |  | 
| 9117     // Produce an updated AST |  | 
| 9118     IncrementalParser parser = new IncrementalParser( |  | 
| 9119         cache.source, scanner.tokenMap, AnalysisErrorListener.NULL_LISTENER); |  | 
| 9120     _updatedUnit = parser.reparse(cache.resolvedUnit, scanner.leftToken, |  | 
| 9121         scanner.rightToken, cache.offset, cache.offset + cache.oldLength); |  | 
| 9122     // Update the resolution |  | 
| 9123     TypeProvider typeProvider = this.typeProvider; |  | 
| 9124     if (_updatedUnit != null && typeProvider != null) { |  | 
| 9125       CompilationUnitElement element = _updatedUnit.element; |  | 
| 9126       if (element != null) { |  | 
| 9127         LibraryElement library = element.library; |  | 
| 9128         if (library != null) { |  | 
| 9129           IncrementalResolver resolver = new IncrementalResolver(null, null, |  | 
| 9130               null, element, cache.offset, cache.oldLength, cache.newLength); |  | 
| 9131           resolver.resolve(parser.updatedNode); |  | 
| 9132         } |  | 
| 9133       } |  | 
| 9134     } |  | 
| 9135   } |  | 
| 9136 } |  | 
| 9137 |  | 
| 9138 /** |  | 
| 9139  * Additional behavior for an analysis context that is required by internal |  | 
| 9140  * users of the context. |  | 
| 9141  */ |  | 
| 9142 abstract class InternalAnalysisContext implements AnalysisContext { |  | 
| 9143   /** |  | 
| 9144    * A table mapping the sources known to the context to the information known |  | 
| 9145    * about the source. |  | 
| 9146    * |  | 
| 9147    * TODO(scheglov) add the type, once we have only one cache. |  | 
| 9148    */ |  | 
| 9149   dynamic get analysisCache; |  | 
| 9150 |  | 
| 9151   /** |  | 
| 9152    * Allow the client to supply its own content cache.  This will take the |  | 
| 9153    * place of the content cache created by default, allowing clients to share |  | 
| 9154    * the content cache between contexts. |  | 
| 9155    */ |  | 
| 9156   set contentCache(ContentCache value); |  | 
| 9157 |  | 
| 9158   /** |  | 
| 9159    * Return a list of the explicit targets being analyzed by this context. |  | 
| 9160    */ |  | 
| 9161   List<AnalysisTarget> get explicitTargets; |  | 
| 9162 |  | 
| 9163   /** |  | 
| 9164    * A factory to override how [LibraryResolver] is created. |  | 
| 9165    */ |  | 
| 9166   LibraryResolverFactory get libraryResolverFactory; |  | 
| 9167 |  | 
| 9168   /** |  | 
| 9169    * Return a list containing all of the sources that have been marked as |  | 
| 9170    * priority sources. Clients must not modify the returned list. |  | 
| 9171    */ |  | 
| 9172   List<Source> get prioritySources; |  | 
| 9173 |  | 
| 9174   /** |  | 
| 9175    * Return a list of the priority targets being analyzed by this context. |  | 
| 9176    */ |  | 
| 9177   List<AnalysisTarget> get priorityTargets; |  | 
| 9178 |  | 
| 9179   /** |  | 
| 9180    * The partition that contains analysis results that are not shared with other |  | 
| 9181    * contexts. |  | 
| 9182    * |  | 
| 9183    * TODO(scheglov) add the type, once we have only one cache. |  | 
| 9184    */ |  | 
| 9185   dynamic get privateAnalysisCachePartition; |  | 
| 9186 |  | 
| 9187   /** |  | 
| 9188    * A factory to override how [ResolverVisitor] is created. |  | 
| 9189    */ |  | 
| 9190   ResolverVisitorFactory get resolverVisitorFactory; |  | 
| 9191 |  | 
| 9192   /** |  | 
| 9193    * Returns a statistics about this context. |  | 
| 9194    */ |  | 
| 9195   AnalysisContextStatistics get statistics; |  | 
| 9196 |  | 
| 9197   /** |  | 
| 9198    * Sets the [TypeProvider] for this context. |  | 
| 9199    */ |  | 
| 9200   void set typeProvider(TypeProvider typeProvider); |  | 
| 9201 |  | 
| 9202   /** |  | 
| 9203    * A factory to override how [TypeResolverVisitor] is created. |  | 
| 9204    */ |  | 
| 9205   TypeResolverVisitorFactory get typeResolverVisitorFactory; |  | 
| 9206 |  | 
| 9207   /** |  | 
| 9208    * Return a list containing the sources of the libraries that are exported by |  | 
| 9209    * the library with the given [source]. The list will be empty if the given |  | 
| 9210    * source is invalid, if the given source does not represent a library, or if |  | 
| 9211    * the library does not export any other libraries. |  | 
| 9212    * |  | 
| 9213    * Throws an [AnalysisException] if the exported libraries could not be |  | 
| 9214    * computed. |  | 
| 9215    */ |  | 
| 9216   List<Source> computeExportedLibraries(Source source); |  | 
| 9217 |  | 
| 9218   /** |  | 
| 9219    * Return a list containing the sources of the libraries that are imported by |  | 
| 9220    * the library with the given [source]. The list will be empty if the given |  | 
| 9221    * source is invalid, if the given source does not represent a library, or if |  | 
| 9222    * the library does not import any other libraries. |  | 
| 9223    * |  | 
| 9224    * Throws an [AnalysisException] if the imported libraries could not be |  | 
| 9225    * computed. |  | 
| 9226    */ |  | 
| 9227   List<Source> computeImportedLibraries(Source source); |  | 
| 9228 |  | 
| 9229   /** |  | 
| 9230    * Return an AST structure corresponding to the given [source], but ensure |  | 
| 9231    * that the structure has not already been resolved and will not be resolved |  | 
| 9232    * by any other threads or in any other library. |  | 
| 9233    * |  | 
| 9234    * Throws an [AnalysisException] if the analysis could not be performed. |  | 
| 9235    * |  | 
| 9236    * <b>Note:</b> This method cannot be used in an async environment |  | 
| 9237    */ |  | 
| 9238   CompilationUnit computeResolvableCompilationUnit(Source source); |  | 
| 9239 |  | 
| 9240   /** |  | 
| 9241    * Return all the resolved [CompilationUnit]s for the given [source] if not |  | 
| 9242    * flushed, otherwise return `null` and ensures that the [CompilationUnit]s |  | 
| 9243    * will be eventually returned to the client from [performAnalysisTask]. |  | 
| 9244    */ |  | 
| 9245   List<CompilationUnit> ensureResolvedDartUnits(Source source); |  | 
| 9246 |  | 
| 9247   /** |  | 
| 9248    * Return the cache entry associated with the given [target]. |  | 
| 9249    */ |  | 
| 9250   cache.CacheEntry getCacheEntry(AnalysisTarget target); |  | 
| 9251 |  | 
| 9252   /** |  | 
| 9253    * Return context that owns the given [source]. |  | 
| 9254    */ |  | 
| 9255   InternalAnalysisContext getContextFor(Source source); |  | 
| 9256 |  | 
| 9257   /** |  | 
| 9258    * Return a change notice for the given [source], creating one if one does not |  | 
| 9259    * already exist. |  | 
| 9260    */ |  | 
| 9261   ChangeNoticeImpl getNotice(Source source); |  | 
| 9262 |  | 
| 9263   /** |  | 
| 9264    * Return a namespace containing mappings for all of the public names defined |  | 
| 9265    * by the given [library]. |  | 
| 9266    */ |  | 
| 9267   Namespace getPublicNamespace(LibraryElement library); |  | 
| 9268 |  | 
| 9269   /** |  | 
| 9270    * Respond to a change which has been made to the given [source] file. |  | 
| 9271    * [originalContents] is the former contents of the file, and [newContents] |  | 
| 9272    * is the updated contents.  If [notify] is true, a source changed event is |  | 
| 9273    * triggered. |  | 
| 9274    * |  | 
| 9275    * Normally it should not be necessary for clients to call this function, |  | 
| 9276    * since it will be automatically invoked in response to a call to |  | 
| 9277    * [applyChanges] or [setContents].  However, if this analysis context is |  | 
| 9278    * sharing its content cache with other contexts, then the client must |  | 
| 9279    * manually update the content cache and call this function for each context. |  | 
| 9280    * |  | 
| 9281    * Return `true` if the change was significant to this context (i.e. [source] |  | 
| 9282    * is either implicitly or explicitly analyzed by this context, and a change |  | 
| 9283    * actually occurred). |  | 
| 9284    */ |  | 
| 9285   bool handleContentsChanged( |  | 
| 9286       Source source, String originalContents, String newContents, bool notify); |  | 
| 9287 |  | 
| 9288   /** |  | 
| 9289    * Given an [elementMap] mapping the source for the libraries represented by |  | 
| 9290    * the corresponding elements to the elements representing the libraries, |  | 
| 9291    * record those mappings. |  | 
| 9292    */ |  | 
| 9293   void recordLibraryElements(Map<Source, LibraryElement> elementMap); |  | 
| 9294 |  | 
| 9295   /** |  | 
| 9296    * Return `true` if errors should be produced for the given [source]. |  | 
| 9297    * The [entry] associated with the source is passed in for efficiency. |  | 
| 9298    * |  | 
| 9299    * TODO(scheglov) remove [entry] after migration to the new task model. |  | 
| 9300    * It is not used there anyway. |  | 
| 9301    */ |  | 
| 9302   bool shouldErrorsBeAnalyzed(Source source, Object entry); |  | 
| 9303 |  | 
| 9304   /** |  | 
| 9305    * For testing only: flush all representations of the AST (both resolved and |  | 
| 9306    * unresolved) for the given [source] out of the cache. |  | 
| 9307    */ |  | 
| 9308   void test_flushAstStructures(Source source); |  | 
| 9309 |  | 
| 9310   /** |  | 
| 9311    * Call the given callback function for eache cache item in the context. |  | 
| 9312    */ |  | 
| 9313   @deprecated |  | 
| 9314   void visitCacheItems(void callback(Source source, SourceEntry dartEntry, |  | 
| 9315       DataDescriptor rowDesc, CacheState state)); |  | 
| 9316 |  | 
| 9317   /** |  | 
| 9318    * Visit all entries of the content cache. |  | 
| 9319    */ |  | 
| 9320   void visitContentCache(ContentCacheVisitor visitor); |  | 
| 9321 } |  | 
| 9322 |  | 
| 9323 /** |  | 
| 9324  * An object that can be used to receive information about errors within the |  | 
| 9325  * analysis engine. Implementations usually write this information to a file, |  | 
| 9326  * but can also record the information for later use (such as during testing) or |  | 
| 9327  * even ignore the information. |  | 
| 9328  */ |  | 
| 9329 abstract class Logger { |  | 
| 9330   /** |  | 
| 9331    * A logger that ignores all logging. |  | 
| 9332    */ |  | 
| 9333   static final Logger NULL = new NullLogger(); |  | 
| 9334 |  | 
| 9335   /** |  | 
| 9336    * Log the given message as an error. The [message] is expected to be an |  | 
| 9337    * explanation of why the error occurred or what it means. The [exception] is |  | 
| 9338    * expected to be the reason for the error. At least one argument must be |  | 
| 9339    * provided. |  | 
| 9340    */ |  | 
| 9341   void logError(String message, [CaughtException exception]); |  | 
| 9342 |  | 
| 9343   /** |  | 
| 9344    * Log the given [exception] as one representing an error. The [message] is an |  | 
| 9345    * explanation of why the error occurred or what it means. |  | 
| 9346    */ |  | 
| 9347   @deprecated // Use logError(message, exception) |  | 
| 9348   void logError2(String message, Object exception); |  | 
| 9349 |  | 
| 9350   /** |  | 
| 9351    * Log the given informational message. The [message] is expected to be an |  | 
| 9352    * explanation of why the error occurred or what it means. The [exception] is |  | 
| 9353    * expected to be the reason for the error. |  | 
| 9354    */ |  | 
| 9355   void logInformation(String message, [CaughtException exception]); |  | 
| 9356 |  | 
| 9357   /** |  | 
| 9358    * Log the given [exception] as one representing an informational message. The |  | 
| 9359    * [message] is an explanation of why the error occurred or what it means. |  | 
| 9360    */ |  | 
| 9361   @deprecated // Use logInformation(message, exception) |  | 
| 9362   void logInformation2(String message, Object exception); |  | 
| 9363 } |  | 
| 9364 |  | 
| 9365 /** |  | 
| 9366  * An implementation of [Logger] that does nothing. |  | 
| 9367  */ |  | 
| 9368 class NullLogger implements Logger { |  | 
| 9369   @override |  | 
| 9370   void logError(String message, [CaughtException exception]) {} |  | 
| 9371 |  | 
| 9372   @override |  | 
| 9373   void logError2(String message, Object exception) {} |  | 
| 9374 |  | 
| 9375   @override |  | 
| 9376   void logInformation(String message, [CaughtException exception]) {} |  | 
| 9377 |  | 
| 9378   @override |  | 
| 9379   void logInformation2(String message, Object exception) {} |  | 
| 9380 } |  | 
| 9381 |  | 
| 9382 /** |  | 
| 9383  * An exception created when an analysis attempt fails because a source was |  | 
| 9384  * deleted between the time the analysis started and the time the results of the |  | 
| 9385  * analysis were ready to be recorded. |  | 
| 9386  */ |  | 
| 9387 class ObsoleteSourceAnalysisException extends AnalysisException { |  | 
| 9388   /** |  | 
| 9389    * The source that was removed while it was being analyzed. |  | 
| 9390    */ |  | 
| 9391   Source _source; |  | 
| 9392 |  | 
| 9393   /** |  | 
| 9394    * Initialize a newly created exception to represent the removal of the given |  | 
| 9395    * [source]. |  | 
| 9396    */ |  | 
| 9397   ObsoleteSourceAnalysisException(Source source) : super( |  | 
| 9398           "The source '${source.fullName}' was removed while it was being analyz
       ed") { |  | 
| 9399     this._source = source; |  | 
| 9400   } |  | 
| 9401 |  | 
| 9402   /** |  | 
| 9403    * Return the source that was removed while it was being analyzed. |  | 
| 9404    */ |  | 
| 9405   Source get source => _source; |  | 
| 9406 } |  | 
| 9407 |  | 
| 9408 /** |  | 
| 9409  * Instances of the class `ParseDartTask` parse a specific source as a Dart file
       . |  | 
| 9410  */ |  | 
| 9411 class ParseDartTask extends AnalysisTask { |  | 
| 9412   /** |  | 
| 9413    * The source to be parsed. |  | 
| 9414    */ |  | 
| 9415   final Source source; |  | 
| 9416 |  | 
| 9417   /** |  | 
| 9418    * The head of the token stream used for parsing. |  | 
| 9419    */ |  | 
| 9420   final Token _tokenStream; |  | 
| 9421 |  | 
| 9422   /** |  | 
| 9423    * The line information associated with the source. |  | 
| 9424    */ |  | 
| 9425   final LineInfo lineInfo; |  | 
| 9426 |  | 
| 9427   /** |  | 
| 9428    * The compilation unit that was produced by parsing the source. |  | 
| 9429    */ |  | 
| 9430   CompilationUnit _unit; |  | 
| 9431 |  | 
| 9432   /** |  | 
| 9433    * A flag indicating whether the source contains a 'part of' directive. |  | 
| 9434    */ |  | 
| 9435   bool _containsPartOfDirective = false; |  | 
| 9436 |  | 
| 9437   /** |  | 
| 9438    * A flag indicating whether the source contains any directive other than a 'p
       art of' directive. |  | 
| 9439    */ |  | 
| 9440   bool _containsNonPartOfDirective = false; |  | 
| 9441 |  | 
| 9442   /** |  | 
| 9443    * A set containing the sources referenced by 'export' directives. |  | 
| 9444    */ |  | 
| 9445   HashSet<Source> _exportedSources = new HashSet<Source>(); |  | 
| 9446 |  | 
| 9447   /** |  | 
| 9448    * A set containing the sources referenced by 'import' directives. |  | 
| 9449    */ |  | 
| 9450   HashSet<Source> _importedSources = new HashSet<Source>(); |  | 
| 9451 |  | 
| 9452   /** |  | 
| 9453    * A set containing the sources referenced by 'part' directives. |  | 
| 9454    */ |  | 
| 9455   HashSet<Source> _includedSources = new HashSet<Source>(); |  | 
| 9456 |  | 
| 9457   /** |  | 
| 9458    * The errors that were produced by scanning and parsing the source. |  | 
| 9459    */ |  | 
| 9460   List<AnalysisError> _errors = AnalysisError.NO_ERRORS; |  | 
| 9461 |  | 
| 9462   /** |  | 
| 9463    * Initialize a newly created task to perform analysis within the given contex
       t. |  | 
| 9464    * |  | 
| 9465    * @param context the context in which the task is to be performed |  | 
| 9466    * @param source the source to be parsed |  | 
| 9467    * @param tokenStream the head of the token stream used for parsing |  | 
| 9468    * @param lineInfo the line information associated with the source |  | 
| 9469    */ |  | 
| 9470   ParseDartTask(InternalAnalysisContext context, this.source, this._tokenStream, |  | 
| 9471       this.lineInfo) |  | 
| 9472       : super(context); |  | 
| 9473 |  | 
| 9474   /** |  | 
| 9475    * Return the compilation unit that was produced by parsing the source, or `nu
       ll` if the |  | 
| 9476    * task has not yet been performed or if an exception occurred. |  | 
| 9477    * |  | 
| 9478    * @return the compilation unit that was produced by parsing the source |  | 
| 9479    */ |  | 
| 9480   CompilationUnit get compilationUnit => _unit; |  | 
| 9481 |  | 
| 9482   /** |  | 
| 9483    * Return the errors that were produced by scanning and parsing the source, or
        an empty list if |  | 
| 9484    * the task has not yet been performed or if an exception occurred. |  | 
| 9485    * |  | 
| 9486    * @return the errors that were produced by scanning and parsing the source |  | 
| 9487    */ |  | 
| 9488   List<AnalysisError> get errors => _errors; |  | 
| 9489 |  | 
| 9490   /** |  | 
| 9491    * Return a list containing the sources referenced by 'export' directives, or 
       an empty list if |  | 
| 9492    * the task has not yet been performed or if an exception occurred. |  | 
| 9493    * |  | 
| 9494    * @return an list containing the sources referenced by 'export' directives |  | 
| 9495    */ |  | 
| 9496   List<Source> get exportedSources => _toArray(_exportedSources); |  | 
| 9497 |  | 
| 9498   /** |  | 
| 9499    * Return `true` if the source contains any directive other than a 'part of' d
       irective, or |  | 
| 9500    * `false` if the task has not yet been performed or if an exception occurred. |  | 
| 9501    * |  | 
| 9502    * @return `true` if the source contains any directive other than a 'part of' 
       directive |  | 
| 9503    */ |  | 
| 9504   bool get hasNonPartOfDirective => _containsNonPartOfDirective; |  | 
| 9505 |  | 
| 9506   /** |  | 
| 9507    * Return `true` if the source contains a 'part of' directive, or `false` if t
       he task |  | 
| 9508    * has not yet been performed or if an exception occurred. |  | 
| 9509    * |  | 
| 9510    * @return `true` if the source contains a 'part of' directive |  | 
| 9511    */ |  | 
| 9512   bool get hasPartOfDirective => _containsPartOfDirective; |  | 
| 9513 |  | 
| 9514   /** |  | 
| 9515    * Return a list containing the sources referenced by 'import' directives, or 
       an empty list if |  | 
| 9516    * the task has not yet been performed or if an exception occurred. |  | 
| 9517    * |  | 
| 9518    * @return a list containing the sources referenced by 'import' directives |  | 
| 9519    */ |  | 
| 9520   List<Source> get importedSources => _toArray(_importedSources); |  | 
| 9521 |  | 
| 9522   /** |  | 
| 9523    * Return a list containing the sources referenced by 'part' directives, or an
        empty list if |  | 
| 9524    * the task has not yet been performed or if an exception occurred. |  | 
| 9525    * |  | 
| 9526    * @return a list containing the sources referenced by 'part' directives |  | 
| 9527    */ |  | 
| 9528   List<Source> get includedSources => _toArray(_includedSources); |  | 
| 9529 |  | 
| 9530   @override |  | 
| 9531   String get taskDescription { |  | 
| 9532     if (source == null) { |  | 
| 9533       return "parse as dart null source"; |  | 
| 9534     } |  | 
| 9535     return "parse as dart ${source.fullName}"; |  | 
| 9536   } |  | 
| 9537 |  | 
| 9538   @override |  | 
| 9539   accept(AnalysisTaskVisitor visitor) => visitor.visitParseDartTask(this); |  | 
| 9540 |  | 
| 9541   @override |  | 
| 9542   void internalPerform() { |  | 
| 9543     // |  | 
| 9544     // Then parse the token stream. |  | 
| 9545     // |  | 
| 9546     PerformanceStatistics.parse.makeCurrentWhile(() { |  | 
| 9547       RecordingErrorListener errorListener = new RecordingErrorListener(); |  | 
| 9548       Parser parser = new Parser(source, errorListener); |  | 
| 9549       AnalysisOptions options = context.analysisOptions; |  | 
| 9550       parser.parseFunctionBodies = |  | 
| 9551           options.analyzeFunctionBodiesPredicate(source); |  | 
| 9552       parser.parseGenericMethods = options.enableGenericMethods; |  | 
| 9553       _unit = parser.parseCompilationUnit(_tokenStream); |  | 
| 9554       _unit.lineInfo = lineInfo; |  | 
| 9555       AnalysisContext analysisContext = context; |  | 
| 9556       for (Directive directive in _unit.directives) { |  | 
| 9557         if (directive is PartOfDirective) { |  | 
| 9558           _containsPartOfDirective = true; |  | 
| 9559         } else { |  | 
| 9560           _containsNonPartOfDirective = true; |  | 
| 9561           if (directive is UriBasedDirective) { |  | 
| 9562             Source referencedSource = resolveDirective( |  | 
| 9563                 analysisContext, source, directive, errorListener); |  | 
| 9564             if (referencedSource != null) { |  | 
| 9565               if (directive is ExportDirective) { |  | 
| 9566                 _exportedSources.add(referencedSource); |  | 
| 9567               } else if (directive is ImportDirective) { |  | 
| 9568                 _importedSources.add(referencedSource); |  | 
| 9569               } else if (directive is PartDirective) { |  | 
| 9570                 if (referencedSource != source) { |  | 
| 9571                   _includedSources.add(referencedSource); |  | 
| 9572                 } |  | 
| 9573               } else { |  | 
| 9574                 throw new AnalysisException( |  | 
| 9575                     "$runtimeType failed to handle a ${directive.runtimeType}"); |  | 
| 9576               } |  | 
| 9577             } |  | 
| 9578           } |  | 
| 9579         } |  | 
| 9580       } |  | 
| 9581       _errors = errorListener.getErrorsForSource(source); |  | 
| 9582     }); |  | 
| 9583   } |  | 
| 9584 |  | 
| 9585   /** |  | 
| 9586    * Efficiently convert the given set of [sources] to a list. |  | 
| 9587    */ |  | 
| 9588   List<Source> _toArray(HashSet<Source> sources) { |  | 
| 9589     int size = sources.length; |  | 
| 9590     if (size == 0) { |  | 
| 9591       return Source.EMPTY_LIST; |  | 
| 9592     } |  | 
| 9593     return new List.from(sources); |  | 
| 9594   } |  | 
| 9595 |  | 
| 9596   /** |  | 
| 9597    * Return the result of resolving the URI of the given URI-based directive aga
       inst the URI of the |  | 
| 9598    * given library, or `null` if the URI is not valid. |  | 
| 9599    * |  | 
| 9600    * @param context the context in which the resolution is to be performed |  | 
| 9601    * @param librarySource the source representing the library containing the dir
       ective |  | 
| 9602    * @param directive the directive which URI should be resolved |  | 
| 9603    * @param errorListener the error listener to which errors should be reported |  | 
| 9604    * @return the result of resolving the URI against the URI of the library |  | 
| 9605    */ |  | 
| 9606   static Source resolveDirective(AnalysisContext context, Source librarySource, |  | 
| 9607       UriBasedDirective directive, AnalysisErrorListener errorListener) { |  | 
| 9608     StringLiteral uriLiteral = directive.uri; |  | 
| 9609     String uriContent = uriLiteral.stringValue; |  | 
| 9610     if (uriContent != null) { |  | 
| 9611       uriContent = uriContent.trim(); |  | 
| 9612       directive.uriContent = uriContent; |  | 
| 9613     } |  | 
| 9614     UriValidationCode code = directive.validate(); |  | 
| 9615     if (code == null) { |  | 
| 9616       String encodedUriContent = Uri.encodeFull(uriContent); |  | 
| 9617       try { |  | 
| 9618         Source source = |  | 
| 9619             context.sourceFactory.resolveUri(librarySource, encodedUriContent); |  | 
| 9620         directive.source = source; |  | 
| 9621         return source; |  | 
| 9622       } on JavaIOException { |  | 
| 9623         code = UriValidationCode.INVALID_URI; |  | 
| 9624       } |  | 
| 9625     } |  | 
| 9626     if (code == UriValidationCode.URI_WITH_DART_EXT_SCHEME) { |  | 
| 9627       return null; |  | 
| 9628     } |  | 
| 9629     if (code == UriValidationCode.URI_WITH_INTERPOLATION) { |  | 
| 9630       errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset, |  | 
| 9631           uriLiteral.length, CompileTimeErrorCode.URI_WITH_INTERPOLATION)); |  | 
| 9632       return null; |  | 
| 9633     } |  | 
| 9634     if (code == UriValidationCode.INVALID_URI) { |  | 
| 9635       errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset, |  | 
| 9636           uriLiteral.length, CompileTimeErrorCode.INVALID_URI, [uriContent])); |  | 
| 9637       return null; |  | 
| 9638     } |  | 
| 9639     throw new RuntimeException( |  | 
| 9640         message: "Failed to handle validation code: $code"); |  | 
| 9641   } |  | 
| 9642 } |  | 
| 9643 |  | 
| 9644 /** |  | 
| 9645  * Instances of the class `ParseHtmlTask` parse a specific source as an HTML fil
       e. |  | 
| 9646  */ |  | 
| 9647 class ParseHtmlTask extends AnalysisTask { |  | 
| 9648   /** |  | 
| 9649    * The name of the 'src' attribute in a HTML tag. |  | 
| 9650    */ |  | 
| 9651   static String _ATTRIBUTE_SRC = "src"; |  | 
| 9652 |  | 
| 9653   /** |  | 
| 9654    * The name of the 'script' tag in an HTML file. |  | 
| 9655    */ |  | 
| 9656   static String _TAG_SCRIPT = "script"; |  | 
| 9657 |  | 
| 9658   /** |  | 
| 9659    * The source to be parsed. |  | 
| 9660    */ |  | 
| 9661   final Source source; |  | 
| 9662 |  | 
| 9663   /** |  | 
| 9664    * The contents of the source. |  | 
| 9665    */ |  | 
| 9666   final String _content; |  | 
| 9667 |  | 
| 9668   /** |  | 
| 9669    * The line information that was produced. |  | 
| 9670    */ |  | 
| 9671   LineInfo _lineInfo; |  | 
| 9672 |  | 
| 9673   /** |  | 
| 9674    * The HTML unit that was produced by parsing the source. |  | 
| 9675    */ |  | 
| 9676   ht.HtmlUnit _unit; |  | 
| 9677 |  | 
| 9678   /** |  | 
| 9679    * The errors that were produced by scanning and parsing the source. |  | 
| 9680    */ |  | 
| 9681   List<AnalysisError> _errors = AnalysisError.NO_ERRORS; |  | 
| 9682 |  | 
| 9683   /** |  | 
| 9684    * A list containing the sources of the libraries that are referenced within t
       he HTML. |  | 
| 9685    */ |  | 
| 9686   List<Source> _referencedLibraries = Source.EMPTY_LIST; |  | 
| 9687 |  | 
| 9688   /** |  | 
| 9689    * Initialize a newly created task to perform analysis within the given contex
       t. |  | 
| 9690    * |  | 
| 9691    * @param context the context in which the task is to be performed |  | 
| 9692    * @param source the source to be parsed |  | 
| 9693    * @param content the contents of the source |  | 
| 9694    */ |  | 
| 9695   ParseHtmlTask(InternalAnalysisContext context, this.source, this._content) |  | 
| 9696       : super(context); |  | 
| 9697 |  | 
| 9698   /** |  | 
| 9699    * Return the errors that were produced by scanning and parsing the source, or
        `null` if the |  | 
| 9700    * task has not yet been performed or if an exception occurred. |  | 
| 9701    * |  | 
| 9702    * @return the errors that were produced by scanning and parsing the source |  | 
| 9703    */ |  | 
| 9704   List<AnalysisError> get errors => _errors; |  | 
| 9705 |  | 
| 9706   /** |  | 
| 9707    * Return the HTML unit that was produced by parsing the source. |  | 
| 9708    * |  | 
| 9709    * @return the HTML unit that was produced by parsing the source |  | 
| 9710    */ |  | 
| 9711   ht.HtmlUnit get htmlUnit => _unit; |  | 
| 9712 |  | 
| 9713   /** |  | 
| 9714    * Return the sources of libraries that are referenced in the specified HTML f
       ile. |  | 
| 9715    * |  | 
| 9716    * @return the sources of libraries that are referenced in the HTML file |  | 
| 9717    */ |  | 
| 9718   List<Source> get librarySources { |  | 
| 9719     List<Source> libraries = new List<Source>(); |  | 
| 9720     _unit.accept(new ParseHtmlTask_getLibrarySources(this, libraries)); |  | 
| 9721     if (libraries.isEmpty) { |  | 
| 9722       return Source.EMPTY_LIST; |  | 
| 9723     } |  | 
| 9724     return libraries; |  | 
| 9725   } |  | 
| 9726 |  | 
| 9727   /** |  | 
| 9728    * Return the line information that was produced, or `null` if the task has no
       t yet been |  | 
| 9729    * performed or if an exception occurred. |  | 
| 9730    * |  | 
| 9731    * @return the line information that was produced |  | 
| 9732    */ |  | 
| 9733   LineInfo get lineInfo => _lineInfo; |  | 
| 9734 |  | 
| 9735   /** |  | 
| 9736    * Return a list containing the sources of the libraries that are referenced w
       ithin the HTML. |  | 
| 9737    * |  | 
| 9738    * @return the sources of the libraries that are referenced within the HTML |  | 
| 9739    */ |  | 
| 9740   List<Source> get referencedLibraries => _referencedLibraries; |  | 
| 9741 |  | 
| 9742   @override |  | 
| 9743   String get taskDescription { |  | 
| 9744     if (source == null) { |  | 
| 9745       return "parse as html null source"; |  | 
| 9746     } |  | 
| 9747     return "parse as html ${source.fullName}"; |  | 
| 9748   } |  | 
| 9749 |  | 
| 9750   @override |  | 
| 9751   accept(AnalysisTaskVisitor visitor) => visitor.visitParseHtmlTask(this); |  | 
| 9752 |  | 
| 9753   @override |  | 
| 9754   void internalPerform() { |  | 
| 9755     try { |  | 
| 9756       ht.AbstractScanner scanner = new ht.StringScanner(source, _content); |  | 
| 9757       scanner.passThroughElements = <String>[_TAG_SCRIPT]; |  | 
| 9758       ht.Token token = scanner.tokenize(); |  | 
| 9759       _lineInfo = new LineInfo(scanner.lineStarts); |  | 
| 9760       RecordingErrorListener errorListener = new RecordingErrorListener(); |  | 
| 9761       _unit = new ht.HtmlParser(source, errorListener, context.analysisOptions) |  | 
| 9762           .parse(token, _lineInfo); |  | 
| 9763       _unit.accept(new RecursiveXmlVisitor_ParseHtmlTask_internalPerform( |  | 
| 9764           this, errorListener)); |  | 
| 9765       _errors = errorListener.getErrorsForSource(source); |  | 
| 9766       _referencedLibraries = librarySources; |  | 
| 9767     } catch (exception, stackTrace) { |  | 
| 9768       throw new AnalysisException( |  | 
| 9769           "Exception", new CaughtException(exception, stackTrace)); |  | 
| 9770     } |  | 
| 9771   } |  | 
| 9772 |  | 
| 9773   /** |  | 
| 9774    * Resolves directives in the given [CompilationUnit]. |  | 
| 9775    */ |  | 
| 9776   void _resolveScriptDirectives( |  | 
| 9777       CompilationUnit script, AnalysisErrorListener errorListener) { |  | 
| 9778     if (script == null) { |  | 
| 9779       return; |  | 
| 9780     } |  | 
| 9781     AnalysisContext analysisContext = context; |  | 
| 9782     for (Directive directive in script.directives) { |  | 
| 9783       if (directive is UriBasedDirective) { |  | 
| 9784         ParseDartTask.resolveDirective( |  | 
| 9785             analysisContext, source, directive, errorListener); |  | 
| 9786       } |  | 
| 9787     } |  | 
| 9788   } |  | 
| 9789 } |  | 
| 9790 |  | 
| 9791 class ParseHtmlTask_getLibrarySources extends ht.RecursiveXmlVisitor<Object> { |  | 
| 9792   final ParseHtmlTask _task; |  | 
| 9793 |  | 
| 9794   List<Source> libraries; |  | 
| 9795 |  | 
| 9796   ParseHtmlTask_getLibrarySources(this._task, this.libraries) : super(); |  | 
| 9797 |  | 
| 9798   @override |  | 
| 9799   Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) { |  | 
| 9800     ht.XmlAttributeNode scriptAttribute = null; |  | 
| 9801     for (ht.XmlAttributeNode attribute in node.attributes) { |  | 
| 9802       if (javaStringEqualsIgnoreCase( |  | 
| 9803           attribute.name, ParseHtmlTask._ATTRIBUTE_SRC)) { |  | 
| 9804         scriptAttribute = attribute; |  | 
| 9805       } |  | 
| 9806     } |  | 
| 9807     if (scriptAttribute != null) { |  | 
| 9808       try { |  | 
| 9809         Uri uri = Uri.parse(scriptAttribute.text); |  | 
| 9810         String fileName = uri.path; |  | 
| 9811         Source librarySource = |  | 
| 9812             _task.context.sourceFactory.resolveUri(_task.source, fileName); |  | 
| 9813         if (_task.context.exists(librarySource)) { |  | 
| 9814           libraries.add(librarySource); |  | 
| 9815         } |  | 
| 9816       } on FormatException { |  | 
| 9817         // ignored - invalid URI reported during resolution phase |  | 
| 9818       } |  | 
| 9819     } |  | 
| 9820     return super.visitHtmlScriptTagNode(node); |  | 
| 9821   } |  | 
| 9822 } |  | 
| 9823 |  | 
| 9824 /** |  | 
| 9825  * An object that manages the partitions that can be shared between analysis |  | 
| 9826  * contexts. |  | 
| 9827  */ |  | 
| 9828 class PartitionManager { |  | 
| 9829   /** |  | 
| 9830    * The default cache size for a Dart SDK partition. |  | 
| 9831    */ |  | 
| 9832   static int _DEFAULT_SDK_CACHE_SIZE = 256; |  | 
| 9833 |  | 
| 9834   /** |  | 
| 9835    * A table mapping SDK's to the partitions used for those SDK's. |  | 
| 9836    */ |  | 
| 9837   HashMap<DartSdk, SdkCachePartition> _sdkPartitions = |  | 
| 9838       new HashMap<DartSdk, SdkCachePartition>(); |  | 
| 9839 |  | 
| 9840   /** |  | 
| 9841    * Clear any cached data being maintained by this manager. |  | 
| 9842    */ |  | 
| 9843   void clearCache() { |  | 
| 9844     _sdkPartitions.clear(); |  | 
| 9845   } |  | 
| 9846 |  | 
| 9847   /** |  | 
| 9848    * Return the partition being used for the given [sdk], creating the partition |  | 
| 9849    * if necessary. |  | 
| 9850    */ |  | 
| 9851   SdkCachePartition forSdk(DartSdk sdk) { |  | 
| 9852     // Call sdk.context now, because when it creates a new |  | 
| 9853     // InternalAnalysisContext instance, it calls forSdk() again, so creates an |  | 
| 9854     // SdkCachePartition instance. |  | 
| 9855     // So, if we initialize context after "partition == null", we end up |  | 
| 9856     // with two SdkCachePartition instances. |  | 
| 9857     InternalAnalysisContext sdkContext = sdk.context; |  | 
| 9858     // Check cache for an existing partition. |  | 
| 9859     SdkCachePartition partition = _sdkPartitions[sdk]; |  | 
| 9860     if (partition == null) { |  | 
| 9861       partition = new SdkCachePartition(sdkContext, _DEFAULT_SDK_CACHE_SIZE); |  | 
| 9862       _sdkPartitions[sdk] = partition; |  | 
| 9863     } |  | 
| 9864     return partition; |  | 
| 9865   } |  | 
| 9866 } |  | 
| 9867 |  | 
| 9868 /** |  | 
| 9869  * Representation of a pending computation which is based on the results of |  | 
| 9870  * analysis that may or may not have been completed. |  | 
| 9871  */ |  | 
| 9872 class PendingFuture<T> { |  | 
| 9873   /** |  | 
| 9874    * The context in which this computation runs. |  | 
| 9875    */ |  | 
| 9876   final AnalysisContextImpl _context; |  | 
| 9877 |  | 
| 9878   /** |  | 
| 9879    * The source used by this computation to compute its value. |  | 
| 9880    */ |  | 
| 9881   final Source source; |  | 
| 9882 |  | 
| 9883   /** |  | 
| 9884    * The function which implements the computation. |  | 
| 9885    */ |  | 
| 9886   final PendingFutureComputer<T> _computeValue; |  | 
| 9887 |  | 
| 9888   /** |  | 
| 9889    * The completer that should be completed once the computation has succeeded. |  | 
| 9890    */ |  | 
| 9891   CancelableCompleter<T> _completer; |  | 
| 9892 |  | 
| 9893   PendingFuture(this._context, this.source, this._computeValue) { |  | 
| 9894     _completer = new CancelableCompleter<T>(_onCancel); |  | 
| 9895   } |  | 
| 9896 |  | 
| 9897   /** |  | 
| 9898    * Retrieve the future which will be completed when this object is |  | 
| 9899    * successfully evaluated. |  | 
| 9900    */ |  | 
| 9901   CancelableFuture<T> get future => _completer.future; |  | 
| 9902 |  | 
| 9903   /** |  | 
| 9904    * Execute [_computeValue], passing it the given [sourceEntry], and complete |  | 
| 9905    * the pending future if it's appropriate to do so.  If the pending future is |  | 
| 9906    * completed by this call, true is returned; otherwise false is returned. |  | 
| 9907    * |  | 
| 9908    * Once this function has returned true, it should not be called again. |  | 
| 9909    * |  | 
| 9910    * Other than completing the future, this method is free of side effects. |  | 
| 9911    * Note that any code the client has attached to the future will be executed |  | 
| 9912    * in a microtask, so there is no danger of side effects occurring due to |  | 
| 9913    * client callbacks. |  | 
| 9914    */ |  | 
| 9915   bool evaluate(SourceEntry sourceEntry) { |  | 
| 9916     assert(!_completer.isCompleted); |  | 
| 9917     try { |  | 
| 9918       T result = _computeValue(sourceEntry); |  | 
| 9919       if (result == null) { |  | 
| 9920         return false; |  | 
| 9921       } else { |  | 
| 9922         _completer.complete(result); |  | 
| 9923         return true; |  | 
| 9924       } |  | 
| 9925     } catch (exception, stackTrace) { |  | 
| 9926       _completer.completeError(exception, stackTrace); |  | 
| 9927       return true; |  | 
| 9928     } |  | 
| 9929   } |  | 
| 9930 |  | 
| 9931   /** |  | 
| 9932    * No further analysis updates are expected which affect this future, so |  | 
| 9933    * complete it with an AnalysisNotScheduledError in order to avoid |  | 
| 9934    * deadlocking the client. |  | 
| 9935    */ |  | 
| 9936   void forciblyComplete() { |  | 
| 9937     try { |  | 
| 9938       throw new AnalysisNotScheduledError(); |  | 
| 9939     } catch (exception, stackTrace) { |  | 
| 9940       _completer.completeError(exception, stackTrace); |  | 
| 9941     } |  | 
| 9942   } |  | 
| 9943 |  | 
| 9944   void _onCancel() { |  | 
| 9945     _context._cancelFuture(this); |  | 
| 9946   } |  | 
| 9947 } |  | 
| 9948 |  | 
| 9949 /** |  | 
| 9950  * Container with global [AnalysisContext] performance statistics. |  | 
| 9951  */ |  | 
| 9952 class PerformanceStatistics { |  | 
| 9953   /** |  | 
| 9954    * The [PerformanceTag] for time spent in reading files. |  | 
| 9955    */ |  | 
| 9956   static PerformanceTag io = new PerformanceTag('io'); |  | 
| 9957 |  | 
| 9958   /** |  | 
| 9959    * The [PerformanceTag] for time spent in scanning. |  | 
| 9960    */ |  | 
| 9961   static PerformanceTag scan = new PerformanceTag('scan'); |  | 
| 9962 |  | 
| 9963   /** |  | 
| 9964    * The [PerformanceTag] for time spent in parsing. |  | 
| 9965    */ |  | 
| 9966   static PerformanceTag parse = new PerformanceTag('parse'); |  | 
| 9967 |  | 
| 9968   /** |  | 
| 9969    * The [PerformanceTag] for time spent in resolving. |  | 
| 9970    */ |  | 
| 9971   static PerformanceTag resolve = new PerformanceTag('resolve'); |  | 
| 9972 |  | 
| 9973   /** |  | 
| 9974    * The [PerformanceTag] for time spent in error verifier. |  | 
| 9975    */ |  | 
| 9976   static PerformanceTag errors = new PerformanceTag('errors'); |  | 
| 9977 |  | 
| 9978   /** |  | 
| 9979    * The [PerformanceTag] for time spent in hints generator. |  | 
| 9980    */ |  | 
| 9981   static PerformanceTag hints = new PerformanceTag('hints'); |  | 
| 9982 |  | 
| 9983   /** |  | 
| 9984    * The [PerformanceTag] for time spent in linting. |  | 
| 9985    */ |  | 
| 9986   static PerformanceTag lint = new PerformanceTag('lint'); |  | 
| 9987 |  | 
| 9988   /** |  | 
| 9989    * The [PerformanceTag] for time spent computing cycles. |  | 
| 9990    */ |  | 
| 9991   static PerformanceTag cycles = new PerformanceTag('cycles'); |  | 
| 9992 |  | 
| 9993   /** |  | 
| 9994    * The [PerformanceTag] for time spent in other phases of analysis. |  | 
| 9995    */ |  | 
| 9996   static PerformanceTag performAnaysis = new PerformanceTag('performAnaysis'); |  | 
| 9997 |  | 
| 9998   /** |  | 
| 9999    * The [PerformanceTag] for time spent in the analysis task visitor after |  | 
| 10000    * tasks are complete. |  | 
| 10001    */ |  | 
| 10002   static PerformanceTag analysisTaskVisitor = |  | 
| 10003       new PerformanceTag('analysisTaskVisitor'); |  | 
| 10004 |  | 
| 10005   /** |  | 
| 10006    * The [PerformanceTag] for time spent in the getter |  | 
| 10007    * AnalysisContextImpl.nextAnalysisTask. |  | 
| 10008    */ |  | 
| 10009   static var nextTask = new PerformanceTag('nextAnalysisTask'); |  | 
| 10010 |  | 
| 10011   /** |  | 
| 10012    * The [PerformanceTag] for time spent during otherwise not accounted parts |  | 
| 10013    * incremental of analysis. |  | 
| 10014    */ |  | 
| 10015   static PerformanceTag incrementalAnalysis = |  | 
| 10016       new PerformanceTag('incrementalAnalysis'); |  | 
| 10017 } |  | 
| 10018 |  | 
| 10019 /** |  | 
| 10020  * An error listener that will record the errors that are reported to it in a |  | 
| 10021  * way that is appropriate for caching those errors within an analysis context. |  | 
| 10022  */ |  | 
| 10023 class RecordingErrorListener implements AnalysisErrorListener { |  | 
| 10024   /** |  | 
| 10025    * A map of sets containing the errors that were collected, keyed by each |  | 
| 10026    * source. |  | 
| 10027    */ |  | 
| 10028   Map<Source, HashSet<AnalysisError>> _errors = |  | 
| 10029       new HashMap<Source, HashSet<AnalysisError>>(); |  | 
| 10030 |  | 
| 10031   /** |  | 
| 10032    * Return the errors collected by the listener. |  | 
| 10033    */ |  | 
| 10034   List<AnalysisError> get errors { |  | 
| 10035     int numEntries = _errors.length; |  | 
| 10036     if (numEntries == 0) { |  | 
| 10037       return AnalysisError.NO_ERRORS; |  | 
| 10038     } |  | 
| 10039     List<AnalysisError> resultList = new List<AnalysisError>(); |  | 
| 10040     for (HashSet<AnalysisError> errors in _errors.values) { |  | 
| 10041       resultList.addAll(errors); |  | 
| 10042     } |  | 
| 10043     return resultList; |  | 
| 10044   } |  | 
| 10045 |  | 
| 10046   /** |  | 
| 10047    * Add all of the errors recorded by the given [listener] to this listener. |  | 
| 10048    */ |  | 
| 10049   void addAll(RecordingErrorListener listener) { |  | 
| 10050     for (AnalysisError error in listener.errors) { |  | 
| 10051       onError(error); |  | 
| 10052     } |  | 
| 10053   } |  | 
| 10054 |  | 
| 10055   /** |  | 
| 10056    * Return the errors collected by the listener for the given [source]. |  | 
| 10057    */ |  | 
| 10058   List<AnalysisError> getErrorsForSource(Source source) { |  | 
| 10059     HashSet<AnalysisError> errorsForSource = _errors[source]; |  | 
| 10060     if (errorsForSource == null) { |  | 
| 10061       return AnalysisError.NO_ERRORS; |  | 
| 10062     } else { |  | 
| 10063       return new List.from(errorsForSource); |  | 
| 10064     } |  | 
| 10065   } |  | 
| 10066 |  | 
| 10067   @override |  | 
| 10068   void onError(AnalysisError error) { |  | 
| 10069     Source source = error.source; |  | 
| 10070     HashSet<AnalysisError> errorsForSource = _errors[source]; |  | 
| 10071     if (_errors[source] == null) { |  | 
| 10072       errorsForSource = new HashSet<AnalysisError>(); |  | 
| 10073       _errors[source] = errorsForSource; |  | 
| 10074     } |  | 
| 10075     errorsForSource.add(error); |  | 
| 10076   } |  | 
| 10077 } |  | 
| 10078 |  | 
| 10079 class RecursiveXmlVisitor_ParseHtmlTask_internalPerform |  | 
| 10080     extends ht.RecursiveXmlVisitor<Object> { |  | 
| 10081   final ParseHtmlTask ParseHtmlTask_this; |  | 
| 10082 |  | 
| 10083   RecordingErrorListener errorListener; |  | 
| 10084 |  | 
| 10085   RecursiveXmlVisitor_ParseHtmlTask_internalPerform( |  | 
| 10086       this.ParseHtmlTask_this, this.errorListener) |  | 
| 10087       : super(); |  | 
| 10088 |  | 
| 10089   @override |  | 
| 10090   Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) { |  | 
| 10091     ParseHtmlTask_this._resolveScriptDirectives(node.script, errorListener); |  | 
| 10092     return null; |  | 
| 10093   } |  | 
| 10094 } |  | 
| 10095 |  | 
| 10096 class RecursiveXmlVisitor_ResolveHtmlTask_internalPerform |  | 
| 10097     extends ht.RecursiveXmlVisitor<Object> { |  | 
| 10098   final ResolveHtmlTask ResolveHtmlTask_this; |  | 
| 10099 |  | 
| 10100   RecordingErrorListener errorListener; |  | 
| 10101 |  | 
| 10102   RecursiveXmlVisitor_ResolveHtmlTask_internalPerform( |  | 
| 10103       this.ResolveHtmlTask_this, this.errorListener) |  | 
| 10104       : super(); |  | 
| 10105 |  | 
| 10106   @override |  | 
| 10107   Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) { |  | 
| 10108     CompilationUnit script = node.script; |  | 
| 10109     if (script != null) { |  | 
| 10110       GenerateDartErrorsTask.validateDirectives(ResolveHtmlTask_this.context, |  | 
| 10111           ResolveHtmlTask_this.source, script, errorListener); |  | 
| 10112     } |  | 
| 10113     return null; |  | 
| 10114   } |  | 
| 10115 } |  | 
| 10116 |  | 
| 10117 /** |  | 
| 10118  * An visitor that removes any resolution information from an AST structure when |  | 
| 10119  * used to visit that structure. |  | 
| 10120  */ |  | 
| 10121 class ResolutionEraser extends GeneralizingAstVisitor<Object> { |  | 
| 10122   @override |  | 
| 10123   Object visitAssignmentExpression(AssignmentExpression node) { |  | 
| 10124     node.staticElement = null; |  | 
| 10125     node.propagatedElement = null; |  | 
| 10126     return super.visitAssignmentExpression(node); |  | 
| 10127   } |  | 
| 10128 |  | 
| 10129   @override |  | 
| 10130   Object visitBinaryExpression(BinaryExpression node) { |  | 
| 10131     node.staticElement = null; |  | 
| 10132     node.propagatedElement = null; |  | 
| 10133     return super.visitBinaryExpression(node); |  | 
| 10134   } |  | 
| 10135 |  | 
| 10136   @override |  | 
| 10137   Object visitBreakStatement(BreakStatement node) { |  | 
| 10138     node.target = null; |  | 
| 10139     return super.visitBreakStatement(node); |  | 
| 10140   } |  | 
| 10141 |  | 
| 10142   @override |  | 
| 10143   Object visitCompilationUnit(CompilationUnit node) { |  | 
| 10144     node.element = null; |  | 
| 10145     return super.visitCompilationUnit(node); |  | 
| 10146   } |  | 
| 10147 |  | 
| 10148   @override |  | 
| 10149   Object visitConstructorDeclaration(ConstructorDeclaration node) { |  | 
| 10150     node.element = null; |  | 
| 10151     return super.visitConstructorDeclaration(node); |  | 
| 10152   } |  | 
| 10153 |  | 
| 10154   @override |  | 
| 10155   Object visitConstructorName(ConstructorName node) { |  | 
| 10156     node.staticElement = null; |  | 
| 10157     return super.visitConstructorName(node); |  | 
| 10158   } |  | 
| 10159 |  | 
| 10160   @override |  | 
| 10161   Object visitContinueStatement(ContinueStatement node) { |  | 
| 10162     node.target = null; |  | 
| 10163     return super.visitContinueStatement(node); |  | 
| 10164   } |  | 
| 10165 |  | 
| 10166   @override |  | 
| 10167   Object visitDirective(Directive node) { |  | 
| 10168     node.element = null; |  | 
| 10169     return super.visitDirective(node); |  | 
| 10170   } |  | 
| 10171 |  | 
| 10172   @override |  | 
| 10173   Object visitExpression(Expression node) { |  | 
| 10174     node.staticType = null; |  | 
| 10175     node.propagatedType = null; |  | 
| 10176     return super.visitExpression(node); |  | 
| 10177   } |  | 
| 10178 |  | 
| 10179   @override |  | 
| 10180   Object visitFunctionExpression(FunctionExpression node) { |  | 
| 10181     node.element = null; |  | 
| 10182     return super.visitFunctionExpression(node); |  | 
| 10183   } |  | 
| 10184 |  | 
| 10185   @override |  | 
| 10186   Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |  | 
| 10187     node.staticElement = null; |  | 
| 10188     node.propagatedElement = null; |  | 
| 10189     return super.visitFunctionExpressionInvocation(node); |  | 
| 10190   } |  | 
| 10191 |  | 
| 10192   @override |  | 
| 10193   Object visitIndexExpression(IndexExpression node) { |  | 
| 10194     node.staticElement = null; |  | 
| 10195     node.propagatedElement = null; |  | 
| 10196     return super.visitIndexExpression(node); |  | 
| 10197   } |  | 
| 10198 |  | 
| 10199   @override |  | 
| 10200   Object visitInstanceCreationExpression(InstanceCreationExpression node) { |  | 
| 10201     node.staticElement = null; |  | 
| 10202     return super.visitInstanceCreationExpression(node); |  | 
| 10203   } |  | 
| 10204 |  | 
| 10205   @override |  | 
| 10206   Object visitPostfixExpression(PostfixExpression node) { |  | 
| 10207     node.staticElement = null; |  | 
| 10208     node.propagatedElement = null; |  | 
| 10209     return super.visitPostfixExpression(node); |  | 
| 10210   } |  | 
| 10211 |  | 
| 10212   @override |  | 
| 10213   Object visitPrefixExpression(PrefixExpression node) { |  | 
| 10214     node.staticElement = null; |  | 
| 10215     node.propagatedElement = null; |  | 
| 10216     return super.visitPrefixExpression(node); |  | 
| 10217   } |  | 
| 10218 |  | 
| 10219   @override |  | 
| 10220   Object visitRedirectingConstructorInvocation( |  | 
| 10221       RedirectingConstructorInvocation node) { |  | 
| 10222     node.staticElement = null; |  | 
| 10223     return super.visitRedirectingConstructorInvocation(node); |  | 
| 10224   } |  | 
| 10225 |  | 
| 10226   @override |  | 
| 10227   Object visitSimpleIdentifier(SimpleIdentifier node) { |  | 
| 10228     node.staticElement = null; |  | 
| 10229     node.propagatedElement = null; |  | 
| 10230     return super.visitSimpleIdentifier(node); |  | 
| 10231   } |  | 
| 10232 |  | 
| 10233   @override |  | 
| 10234   Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { |  | 
| 10235     node.staticElement = null; |  | 
| 10236     return super.visitSuperConstructorInvocation(node); |  | 
| 10237   } |  | 
| 10238 |  | 
| 10239   /** |  | 
| 10240    * Remove any resolution information from the given AST structure. |  | 
| 10241    */ |  | 
| 10242   static void erase(AstNode node) { |  | 
| 10243     node.accept(new ResolutionEraser()); |  | 
| 10244   } |  | 
| 10245 } |  | 
| 10246 |  | 
| 10247 /** |  | 
| 10248  * The information produced by resolving a compilation unit as part of a |  | 
| 10249  * specific library. |  | 
| 10250  */ |  | 
| 10251 class ResolutionState { |  | 
| 10252   /** |  | 
| 10253    * The next resolution state or `null` if none. |  | 
| 10254    */ |  | 
| 10255   ResolutionState _nextState; |  | 
| 10256 |  | 
| 10257   /** |  | 
| 10258    * The source for the defining compilation unit of the library that contains |  | 
| 10259    * this unit. If this unit is the defining compilation unit for it's library, |  | 
| 10260    * then this will be the source for this unit. |  | 
| 10261    */ |  | 
| 10262   Source _librarySource; |  | 
| 10263 |  | 
| 10264   /** |  | 
| 10265    * A table mapping descriptors to the cached results for those descriptors. |  | 
| 10266    * If there is no entry for a given descriptor then the state is implicitly |  | 
| 10267    * [CacheState.INVALID] and the value is implicitly the default value. |  | 
| 10268    */ |  | 
| 10269   Map<DataDescriptor, CachedResult> resultMap = |  | 
| 10270       new HashMap<DataDescriptor, CachedResult>(); |  | 
| 10271 |  | 
| 10272   /** |  | 
| 10273    * Flush any AST structures being maintained by this state. |  | 
| 10274    */ |  | 
| 10275   void flushAstStructures() { |  | 
| 10276     _flush(DartEntry.BUILT_UNIT); |  | 
| 10277     _flush(DartEntry.RESOLVED_UNIT); |  | 
| 10278     if (_nextState != null) { |  | 
| 10279       _nextState.flushAstStructures(); |  | 
| 10280     } |  | 
| 10281   } |  | 
| 10282 |  | 
| 10283   /** |  | 
| 10284    * Return the state of the data represented by the given [descriptor]. |  | 
| 10285    */ |  | 
| 10286   CacheState getState(DataDescriptor descriptor) { |  | 
| 10287     CachedResult result = resultMap[descriptor]; |  | 
| 10288     if (result == null) { |  | 
| 10289       return CacheState.INVALID; |  | 
| 10290     } |  | 
| 10291     return result.state; |  | 
| 10292   } |  | 
| 10293 |  | 
| 10294   /** |  | 
| 10295    * Return the value of the data represented by the given [descriptor], or |  | 
| 10296    * `null` if the data represented by the descriptor is not valid. |  | 
| 10297    */ |  | 
| 10298   /*<V>*/ dynamic /*V*/ getValue(DataDescriptor /*<V>*/ descriptor) { |  | 
| 10299     CachedResult result = resultMap[descriptor]; |  | 
| 10300     if (result == null) { |  | 
| 10301       return descriptor.defaultValue; |  | 
| 10302     } |  | 
| 10303     return result.value; |  | 
| 10304   } |  | 
| 10305 |  | 
| 10306   /** |  | 
| 10307    * Return `true` if the state of any data value is [CacheState.ERROR]. |  | 
| 10308    */ |  | 
| 10309   bool hasErrorState() { |  | 
| 10310     for (CachedResult result in resultMap.values) { |  | 
| 10311       if (result.state == CacheState.ERROR) { |  | 
| 10312         return true; |  | 
| 10313       } |  | 
| 10314     } |  | 
| 10315     return false; |  | 
| 10316   } |  | 
| 10317 |  | 
| 10318   /** |  | 
| 10319    * Invalidate all of the resolution information associated with the compilatio
       n unit. |  | 
| 10320    */ |  | 
| 10321   void invalidateAllResolutionInformation() { |  | 
| 10322     _nextState = null; |  | 
| 10323     _librarySource = null; |  | 
| 10324     setState(DartEntry.BUILT_UNIT, CacheState.INVALID); |  | 
| 10325     setState(DartEntry.BUILT_ELEMENT, CacheState.INVALID); |  | 
| 10326     setState(DartEntry.HINTS, CacheState.INVALID); |  | 
| 10327     setState(DartEntry.LINTS, CacheState.INVALID); |  | 
| 10328     setState(DartEntry.RESOLVED_UNIT, CacheState.INVALID); |  | 
| 10329     setState(DartEntry.RESOLUTION_ERRORS, CacheState.INVALID); |  | 
| 10330     setState(DartEntry.VERIFICATION_ERRORS, CacheState.INVALID); |  | 
| 10331   } |  | 
| 10332 |  | 
| 10333   /** |  | 
| 10334    * Record that an exception occurred while attempting to build the element |  | 
| 10335    * model for the source associated with this state. |  | 
| 10336    */ |  | 
| 10337   void recordBuildElementError() { |  | 
| 10338     setState(DartEntry.BUILT_UNIT, CacheState.ERROR); |  | 
| 10339     setState(DartEntry.BUILT_ELEMENT, CacheState.ERROR); |  | 
| 10340     recordResolutionError(); |  | 
| 10341   } |  | 
| 10342 |  | 
| 10343   /** |  | 
| 10344    * Record that an exception occurred while attempting to generate hints for |  | 
| 10345    * the source associated with this entry. This will set the state of all |  | 
| 10346    * verification information as being in error. |  | 
| 10347    */ |  | 
| 10348   void recordHintError() { |  | 
| 10349     setState(DartEntry.HINTS, CacheState.ERROR); |  | 
| 10350   } |  | 
| 10351 |  | 
| 10352   /** |  | 
| 10353    * Record that an exception occurred while attempting to generate lints for |  | 
| 10354    * the source associated with this entry. This will set the state of all |  | 
| 10355    * verification information as being in error. |  | 
| 10356    */ |  | 
| 10357   void recordLintError() { |  | 
| 10358     setState(DartEntry.LINTS, CacheState.ERROR); |  | 
| 10359   } |  | 
| 10360 |  | 
| 10361   /** |  | 
| 10362    * Record that an exception occurred while attempting to resolve the source |  | 
| 10363    * associated with this state. |  | 
| 10364    */ |  | 
| 10365   void recordResolutionError() { |  | 
| 10366     setState(DartEntry.RESOLVED_UNIT, CacheState.ERROR); |  | 
| 10367     setState(DartEntry.RESOLUTION_ERRORS, CacheState.ERROR); |  | 
| 10368     recordVerificationError(); |  | 
| 10369   } |  | 
| 10370 |  | 
| 10371   /** |  | 
| 10372    * Record that an exception occurred while attempting to scan or parse the |  | 
| 10373    * source associated with this entry. This will set the state of all |  | 
| 10374    * resolution-based information as being in error. |  | 
| 10375    */ |  | 
| 10376   void recordResolutionErrorsInAllLibraries() { |  | 
| 10377     recordBuildElementError(); |  | 
| 10378     if (_nextState != null) { |  | 
| 10379       _nextState.recordResolutionErrorsInAllLibraries(); |  | 
| 10380     } |  | 
| 10381   } |  | 
| 10382 |  | 
| 10383   /** |  | 
| 10384    * Record that an exception occurred while attempting to generate errors and |  | 
| 10385    * warnings for the source associated with this entry. This will set the state |  | 
| 10386    * of all verification information as being in error. |  | 
| 10387    */ |  | 
| 10388   void recordVerificationError() { |  | 
| 10389     setState(DartEntry.VERIFICATION_ERRORS, CacheState.ERROR); |  | 
| 10390     recordHintError(); |  | 
| 10391   } |  | 
| 10392 |  | 
| 10393   /** |  | 
| 10394    * Set the state of the data represented by the given [descriptor] to the |  | 
| 10395    * given [state]. |  | 
| 10396    */ |  | 
| 10397   void setState(DataDescriptor descriptor, CacheState state) { |  | 
| 10398     if (state == CacheState.VALID) { |  | 
| 10399       throw new ArgumentError("use setValue() to set the state to VALID"); |  | 
| 10400     } |  | 
| 10401     if (state == CacheState.INVALID) { |  | 
| 10402       resultMap.remove(descriptor); |  | 
| 10403     } else { |  | 
| 10404       CachedResult result = |  | 
| 10405           resultMap.putIfAbsent(descriptor, () => new CachedResult(descriptor)); |  | 
| 10406       result.state = state; |  | 
| 10407       if (state != CacheState.IN_PROCESS) { |  | 
| 10408         // |  | 
| 10409         // If the state is in-process, we can leave the current value in the |  | 
| 10410         // cache for any 'get' methods to access. |  | 
| 10411         // |  | 
| 10412         result.value = descriptor.defaultValue; |  | 
| 10413       } |  | 
| 10414     } |  | 
| 10415   } |  | 
| 10416 |  | 
| 10417   /** |  | 
| 10418    * Set the value of the data represented by the given [descriptor] to the |  | 
| 10419    * given [value]. |  | 
| 10420    */ |  | 
| 10421   void setValue(DataDescriptor /*<V>*/ descriptor, dynamic /*V*/ value) { |  | 
| 10422     CachedResult result = |  | 
| 10423         resultMap.putIfAbsent(descriptor, () => new CachedResult(descriptor)); |  | 
| 10424     SourceEntry.countTransition(descriptor, result); |  | 
| 10425     result.state = CacheState.VALID; |  | 
| 10426     result.value = value == null ? descriptor.defaultValue : value; |  | 
| 10427   } |  | 
| 10428 |  | 
| 10429   /** |  | 
| 10430    * Flush the value of the data described by the [descriptor]. |  | 
| 10431    */ |  | 
| 10432   void _flush(DataDescriptor descriptor) { |  | 
| 10433     CachedResult result = resultMap[descriptor]; |  | 
| 10434     if (result != null && result.state == CacheState.VALID) { |  | 
| 10435       result.state = CacheState.FLUSHED; |  | 
| 10436       result.value = descriptor.defaultValue; |  | 
| 10437     } |  | 
| 10438   } |  | 
| 10439 |  | 
| 10440   /** |  | 
| 10441    * Write a textual representation of the difference between the old entry and |  | 
| 10442    * this entry to the given string [buffer]. A separator will be written before |  | 
| 10443    * the first difference if [needsSeparator] is `true`. The [oldEntry] is the |  | 
| 10444    * entry that was replaced by this entry. Return `true` is a separator is |  | 
| 10445    * needed before writing any subsequent differences. |  | 
| 10446    */ |  | 
| 10447   bool _writeDiffOn( |  | 
| 10448       StringBuffer buffer, bool needsSeparator, DartEntry oldEntry) { |  | 
| 10449     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, "resolvedUnit", |  | 
| 10450         DartEntry.RESOLVED_UNIT, oldEntry); |  | 
| 10451     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, |  | 
| 10452         "resolutionErrors", DartEntry.RESOLUTION_ERRORS, oldEntry); |  | 
| 10453     needsSeparator = _writeStateDiffOn(buffer, needsSeparator, |  | 
| 10454         "verificationErrors", DartEntry.VERIFICATION_ERRORS, oldEntry); |  | 
| 10455     needsSeparator = _writeStateDiffOn( |  | 
| 10456         buffer, needsSeparator, "hints", DartEntry.HINTS, oldEntry); |  | 
| 10457     needsSeparator = _writeStateDiffOn( |  | 
| 10458         buffer, needsSeparator, "lints", DartEntry.LINTS, oldEntry); |  | 
| 10459     return needsSeparator; |  | 
| 10460   } |  | 
| 10461 |  | 
| 10462   /** |  | 
| 10463    * Write a textual representation of this state to the given [buffer]. The |  | 
| 10464    * result will only be used for debugging purposes. |  | 
| 10465    */ |  | 
| 10466   void _writeOn(StringBuffer buffer) { |  | 
| 10467     if (_librarySource != null) { |  | 
| 10468       _writeStateOn(buffer, "builtElement", DartEntry.BUILT_ELEMENT); |  | 
| 10469       _writeStateOn(buffer, "builtUnit", DartEntry.BUILT_UNIT); |  | 
| 10470       _writeStateOn(buffer, "resolvedUnit", DartEntry.RESOLVED_UNIT); |  | 
| 10471       _writeStateOn(buffer, "resolutionErrors", DartEntry.RESOLUTION_ERRORS); |  | 
| 10472       _writeStateOn( |  | 
| 10473           buffer, "verificationErrors", DartEntry.VERIFICATION_ERRORS); |  | 
| 10474       _writeStateOn(buffer, "hints", DartEntry.HINTS); |  | 
| 10475       _writeStateOn(buffer, "lints", DartEntry.LINTS); |  | 
| 10476       if (_nextState != null) { |  | 
| 10477         _nextState._writeOn(buffer); |  | 
| 10478       } |  | 
| 10479     } |  | 
| 10480   } |  | 
| 10481 |  | 
| 10482   /** |  | 
| 10483    * Write a textual representation of the difference between the state of the |  | 
| 10484    * value described by the given [descriptor] between the [oldEntry] and this |  | 
| 10485    * entry to the given [buffer]. Return `true` if some difference was written. |  | 
| 10486    */ |  | 
| 10487   bool _writeStateDiffOn(StringBuffer buffer, bool needsSeparator, String label, |  | 
| 10488       DataDescriptor descriptor, SourceEntry oldEntry) { |  | 
| 10489     CacheState oldState = oldEntry.getState(descriptor); |  | 
| 10490     CacheState newState = getState(descriptor); |  | 
| 10491     if (oldState != newState) { |  | 
| 10492       if (needsSeparator) { |  | 
| 10493         buffer.write("; "); |  | 
| 10494       } |  | 
| 10495       buffer.write(label); |  | 
| 10496       buffer.write(" = "); |  | 
| 10497       buffer.write(oldState); |  | 
| 10498       buffer.write(" -> "); |  | 
| 10499       buffer.write(newState); |  | 
| 10500       return true; |  | 
| 10501     } |  | 
| 10502     return needsSeparator; |  | 
| 10503   } |  | 
| 10504 |  | 
| 10505   /** |  | 
| 10506    * Write a textual representation of the state of the value described by the |  | 
| 10507    * given [descriptor] to the given bugger, prefixed by the given [label] to |  | 
| 10508    * the given [buffer]. |  | 
| 10509    */ |  | 
| 10510   void _writeStateOn( |  | 
| 10511       StringBuffer buffer, String label, DataDescriptor descriptor) { |  | 
| 10512     CachedResult result = resultMap[descriptor]; |  | 
| 10513     buffer.write("; "); |  | 
| 10514     buffer.write(label); |  | 
| 10515     buffer.write(" = "); |  | 
| 10516     buffer.write(result == null ? CacheState.INVALID : result.state); |  | 
| 10517   } |  | 
| 10518 } |  | 
| 10519 |  | 
| 10520 /** |  | 
| 10521  * A compilation unit that is not referenced by any other objects. It is used by |  | 
| 10522  * the [LibraryResolver] to resolve a library. |  | 
| 10523  */ |  | 
| 10524 class ResolvableCompilationUnit { |  | 
| 10525   /** |  | 
| 10526    * The source of the compilation unit. |  | 
| 10527    */ |  | 
| 10528   final Source source; |  | 
| 10529 |  | 
| 10530   /** |  | 
| 10531    * The compilation unit. |  | 
| 10532    */ |  | 
| 10533   final CompilationUnit compilationUnit; |  | 
| 10534 |  | 
| 10535   /** |  | 
| 10536    * Initialize a newly created holder to hold the given [source] and |  | 
| 10537    * [compilationUnit]. |  | 
| 10538    */ |  | 
| 10539   ResolvableCompilationUnit(this.source, this.compilationUnit); |  | 
| 10540 } |  | 
| 10541 |  | 
| 10542 /** |  | 
| 10543  * Instances of the class `ResolveDartLibraryTask` resolve a specific Dart libra
       ry. |  | 
| 10544  */ |  | 
| 10545 class ResolveDartLibraryCycleTask extends AnalysisTask { |  | 
| 10546   /** |  | 
| 10547    * The source representing the file whose compilation unit is to be returned. 
       TODO(brianwilkerson) |  | 
| 10548    * This should probably be removed, but is being left in for now to ease the t
       ransition. |  | 
| 10549    */ |  | 
| 10550   final Source unitSource; |  | 
| 10551 |  | 
| 10552   /** |  | 
| 10553    * The source representing the library to be resolved. |  | 
| 10554    */ |  | 
| 10555   final Source librarySource; |  | 
| 10556 |  | 
| 10557   /** |  | 
| 10558    * The libraries that are part of the cycle containing the library to be resol
       ved. |  | 
| 10559    */ |  | 
| 10560   final List<ResolvableLibrary> _librariesInCycle; |  | 
| 10561 |  | 
| 10562   /** |  | 
| 10563    * The library resolver holding information about the libraries that were reso
       lved. |  | 
| 10564    */ |  | 
| 10565   LibraryResolver2 _resolver; |  | 
| 10566 |  | 
| 10567   /** |  | 
| 10568    * Initialize a newly created task to perform analysis within the given contex
       t. |  | 
| 10569    * |  | 
| 10570    * @param context the context in which the task is to be performed |  | 
| 10571    * @param unitSource the source representing the file whose compilation unit i
       s to be returned |  | 
| 10572    * @param librarySource the source representing the library to be resolved |  | 
| 10573    * @param librariesInCycle the libraries that are part of the cycle containing
        the library to be |  | 
| 10574    *          resolved |  | 
| 10575    */ |  | 
| 10576   ResolveDartLibraryCycleTask(InternalAnalysisContext context, this.unitSource, |  | 
| 10577       this.librarySource, this._librariesInCycle) |  | 
| 10578       : super(context); |  | 
| 10579 |  | 
| 10580   /** |  | 
| 10581    * Return the library resolver holding information about the libraries that we
       re resolved. |  | 
| 10582    * |  | 
| 10583    * @return the library resolver holding information about the libraries that w
       ere resolved |  | 
| 10584    */ |  | 
| 10585   LibraryResolver2 get libraryResolver => _resolver; |  | 
| 10586 |  | 
| 10587   @override |  | 
| 10588   String get taskDescription { |  | 
| 10589     if (librarySource == null) { |  | 
| 10590       return "resolve library null source"; |  | 
| 10591     } |  | 
| 10592     return "resolve library ${librarySource.fullName}"; |  | 
| 10593   } |  | 
| 10594 |  | 
| 10595   @override |  | 
| 10596   accept(AnalysisTaskVisitor visitor) => |  | 
| 10597       visitor.visitResolveDartLibraryCycleTask(this); |  | 
| 10598 |  | 
| 10599   @override |  | 
| 10600   void internalPerform() { |  | 
| 10601     _resolver = new LibraryResolver2(context); |  | 
| 10602     _resolver.resolveLibrary(librarySource, _librariesInCycle); |  | 
| 10603   } |  | 
| 10604 } |  | 
| 10605 |  | 
| 10606 /** |  | 
| 10607  * Instances of the class `ResolveDartLibraryTask` resolve a specific Dart libra
       ry. |  | 
| 10608  */ |  | 
| 10609 class ResolveDartLibraryTask extends AnalysisTask { |  | 
| 10610   /** |  | 
| 10611    * The source representing the file whose compilation unit is to be returned. |  | 
| 10612    */ |  | 
| 10613   final Source unitSource; |  | 
| 10614 |  | 
| 10615   /** |  | 
| 10616    * The source representing the library to be resolved. |  | 
| 10617    */ |  | 
| 10618   final Source librarySource; |  | 
| 10619 |  | 
| 10620   /** |  | 
| 10621    * The library resolver holding information about the libraries that were reso
       lved. |  | 
| 10622    */ |  | 
| 10623   LibraryResolver _resolver; |  | 
| 10624 |  | 
| 10625   /** |  | 
| 10626    * Initialize a newly created task to perform analysis within the given contex
       t. |  | 
| 10627    * |  | 
| 10628    * @param context the context in which the task is to be performed |  | 
| 10629    * @param unitSource the source representing the file whose compilation unit i
       s to be returned |  | 
| 10630    * @param librarySource the source representing the library to be resolved |  | 
| 10631    */ |  | 
| 10632   ResolveDartLibraryTask( |  | 
| 10633       InternalAnalysisContext context, this.unitSource, this.librarySource) |  | 
| 10634       : super(context); |  | 
| 10635 |  | 
| 10636   /** |  | 
| 10637    * Return the library resolver holding information about the libraries that we
       re resolved. |  | 
| 10638    * |  | 
| 10639    * @return the library resolver holding information about the libraries that w
       ere resolved |  | 
| 10640    */ |  | 
| 10641   LibraryResolver get libraryResolver => _resolver; |  | 
| 10642 |  | 
| 10643   @override |  | 
| 10644   String get taskDescription { |  | 
| 10645     if (librarySource == null) { |  | 
| 10646       return "resolve library null source"; |  | 
| 10647     } |  | 
| 10648     return "resolve library ${librarySource.fullName}"; |  | 
| 10649   } |  | 
| 10650 |  | 
| 10651   @override |  | 
| 10652   accept(AnalysisTaskVisitor visitor) => |  | 
| 10653       visitor.visitResolveDartLibraryTask(this); |  | 
| 10654 |  | 
| 10655   @override |  | 
| 10656   void internalPerform() { |  | 
| 10657     LibraryResolverFactory resolverFactory = context.libraryResolverFactory; |  | 
| 10658     _resolver = resolverFactory == null |  | 
| 10659         ? new LibraryResolver(context) |  | 
| 10660         : resolverFactory(context); |  | 
| 10661     _resolver.resolveLibrary(librarySource, true); |  | 
| 10662   } |  | 
| 10663 } |  | 
| 10664 |  | 
| 10665 /** |  | 
| 10666  * Instances of the class `ResolveDartUnitTask` resolve a single Dart file based
        on a existing |  | 
| 10667  * element model. |  | 
| 10668  */ |  | 
| 10669 class ResolveDartUnitTask extends AnalysisTask { |  | 
| 10670   /** |  | 
| 10671    * The source that is to be resolved. |  | 
| 10672    */ |  | 
| 10673   final Source source; |  | 
| 10674 |  | 
| 10675   /** |  | 
| 10676    * The element model for the library containing the source. |  | 
| 10677    */ |  | 
| 10678   final LibraryElement _libraryElement; |  | 
| 10679 |  | 
| 10680   /** |  | 
| 10681    * The compilation unit that was resolved by this task. |  | 
| 10682    */ |  | 
| 10683   CompilationUnit _resolvedUnit; |  | 
| 10684 |  | 
| 10685   /** |  | 
| 10686    * Initialize a newly created task to perform analysis within the given contex
       t. |  | 
| 10687    * |  | 
| 10688    * @param context the context in which the task is to be performed |  | 
| 10689    * @param source the source to be parsed |  | 
| 10690    * @param libraryElement the element model for the library containing the sour
       ce |  | 
| 10691    */ |  | 
| 10692   ResolveDartUnitTask( |  | 
| 10693       InternalAnalysisContext context, this.source, this._libraryElement) |  | 
| 10694       : super(context); |  | 
| 10695 |  | 
| 10696   /** |  | 
| 10697    * Return the source for the library containing the source that is to be resol
       ved. |  | 
| 10698    * |  | 
| 10699    * @return the source for the library containing the source that is to be reso
       lved |  | 
| 10700    */ |  | 
| 10701   Source get librarySource => _libraryElement.source; |  | 
| 10702 |  | 
| 10703   /** |  | 
| 10704    * Return the compilation unit that was resolved by this task. |  | 
| 10705    * |  | 
| 10706    * @return the compilation unit that was resolved by this task |  | 
| 10707    */ |  | 
| 10708   CompilationUnit get resolvedUnit => _resolvedUnit; |  | 
| 10709 |  | 
| 10710   @override |  | 
| 10711   String get taskDescription { |  | 
| 10712     Source librarySource = _libraryElement.source; |  | 
| 10713     if (librarySource == null) { |  | 
| 10714       return "resolve unit null source"; |  | 
| 10715     } |  | 
| 10716     return "resolve unit ${librarySource.fullName}"; |  | 
| 10717   } |  | 
| 10718 |  | 
| 10719   @override |  | 
| 10720   accept(AnalysisTaskVisitor visitor) => visitor.visitResolveDartUnitTask(this); |  | 
| 10721 |  | 
| 10722   @override |  | 
| 10723   void internalPerform() { |  | 
| 10724     TypeProvider typeProvider = _libraryElement.context.typeProvider; |  | 
| 10725     CompilationUnit unit = context.computeResolvableCompilationUnit(source); |  | 
| 10726     if (unit == null) { |  | 
| 10727       throw new AnalysisException( |  | 
| 10728           "Internal error: computeResolvableCompilationUnit returned a value wit
       hout a parsed Dart unit"); |  | 
| 10729     } |  | 
| 10730     // |  | 
| 10731     // Resolve names in declarations. |  | 
| 10732     // |  | 
| 10733     new DeclarationResolver().resolve(unit, _find(_libraryElement, source)); |  | 
| 10734     // |  | 
| 10735     // Resolve the type names. |  | 
| 10736     // |  | 
| 10737     RecordingErrorListener errorListener = new RecordingErrorListener(); |  | 
| 10738     TypeResolverVisitor typeResolverVisitor = new TypeResolverVisitor( |  | 
| 10739         _libraryElement, source, typeProvider, errorListener); |  | 
| 10740     unit.accept(typeResolverVisitor); |  | 
| 10741     // |  | 
| 10742     // Resolve the rest of the structure |  | 
| 10743     // |  | 
| 10744     InheritanceManager inheritanceManager = |  | 
| 10745         new InheritanceManager(_libraryElement); |  | 
| 10746     ResolverVisitor resolverVisitor = new ResolverVisitor( |  | 
| 10747         _libraryElement, source, typeProvider, errorListener, |  | 
| 10748         inheritanceManager: inheritanceManager); |  | 
| 10749     unit.accept(resolverVisitor); |  | 
| 10750     // |  | 
| 10751     // Perform additional error checking. |  | 
| 10752     // |  | 
| 10753     PerformanceStatistics.errors.makeCurrentWhile(() { |  | 
| 10754       ErrorReporter errorReporter = new ErrorReporter(errorListener, source); |  | 
| 10755       ErrorVerifier errorVerifier = new ErrorVerifier( |  | 
| 10756           errorReporter, _libraryElement, typeProvider, inheritanceManager); |  | 
| 10757       unit.accept(errorVerifier); |  | 
| 10758       // TODO(paulberry): as a temporary workaround for issue 21572, |  | 
| 10759       // ConstantVerifier is being run right after ConstantValueComputer, so we |  | 
| 10760       // don't need to run it here.  Once issue 21572 is fixed, re-enable the |  | 
| 10761       // call to ConstantVerifier. |  | 
| 10762 //       ConstantVerifier constantVerifier = new ConstantVerifier(errorReporter,
        _libraryElement, typeProvider); |  | 
| 10763 //       unit.accept(constantVerifier); |  | 
| 10764     }); |  | 
| 10765     // |  | 
| 10766     // Capture the results. |  | 
| 10767     // |  | 
| 10768     _resolvedUnit = unit; |  | 
| 10769   } |  | 
| 10770 |  | 
| 10771   /** |  | 
| 10772    * Search the compilation units that are part of the given library and return 
       the element |  | 
| 10773    * representing the compilation unit with the given source. Return `null` if t
       here is no |  | 
| 10774    * such compilation unit. |  | 
| 10775    * |  | 
| 10776    * @param libraryElement the element representing the library being searched t
       hrough |  | 
| 10777    * @param unitSource the source for the compilation unit whose element is to b
       e returned |  | 
| 10778    * @return the element representing the compilation unit |  | 
| 10779    */ |  | 
| 10780   CompilationUnitElement _find( |  | 
| 10781       LibraryElement libraryElement, Source unitSource) { |  | 
| 10782     CompilationUnitElement element = libraryElement.definingCompilationUnit; |  | 
| 10783     if (element.source == unitSource) { |  | 
| 10784       return element; |  | 
| 10785     } |  | 
| 10786     for (CompilationUnitElement partElement in libraryElement.parts) { |  | 
| 10787       if (partElement.source == unitSource) { |  | 
| 10788         return partElement; |  | 
| 10789       } |  | 
| 10790     } |  | 
| 10791     return null; |  | 
| 10792   } |  | 
| 10793 } |  | 
| 10794 |  | 
| 10795 /** |  | 
| 10796  * Instances of the class `ResolveHtmlTask` resolve a specific source as an HTML
        file. |  | 
| 10797  */ |  | 
| 10798 class ResolveHtmlTask extends AnalysisTask { |  | 
| 10799   /** |  | 
| 10800    * The source to be resolved. |  | 
| 10801    */ |  | 
| 10802   final Source source; |  | 
| 10803 |  | 
| 10804   /** |  | 
| 10805    * The time at which the contents of the source were last modified. |  | 
| 10806    */ |  | 
| 10807   final int modificationTime; |  | 
| 10808 |  | 
| 10809   /** |  | 
| 10810    * The HTML unit to be resolved. |  | 
| 10811    */ |  | 
| 10812   final ht.HtmlUnit _unit; |  | 
| 10813 |  | 
| 10814   /** |  | 
| 10815    * The [HtmlUnit] that was resolved by this task. |  | 
| 10816    */ |  | 
| 10817   ht.HtmlUnit _resolvedUnit; |  | 
| 10818 |  | 
| 10819   /** |  | 
| 10820    * The element produced by resolving the source. |  | 
| 10821    */ |  | 
| 10822   HtmlElement _element = null; |  | 
| 10823 |  | 
| 10824   /** |  | 
| 10825    * The resolution errors that were discovered while resolving the source. |  | 
| 10826    */ |  | 
| 10827   List<AnalysisError> _resolutionErrors = AnalysisError.NO_ERRORS; |  | 
| 10828 |  | 
| 10829   /** |  | 
| 10830    * Initialize a newly created task to perform analysis within the given contex
       t. |  | 
| 10831    * |  | 
| 10832    * @param context the context in which the task is to be performed |  | 
| 10833    * @param source the source to be resolved |  | 
| 10834    * @param modificationTime the time at which the contents of the source were l
       ast modified |  | 
| 10835    * @param unit the HTML unit to be resolved |  | 
| 10836    */ |  | 
| 10837   ResolveHtmlTask(InternalAnalysisContext context, this.source, |  | 
| 10838       this.modificationTime, this._unit) |  | 
| 10839       : super(context); |  | 
| 10840 |  | 
| 10841   HtmlElement get element => _element; |  | 
| 10842 |  | 
| 10843   List<AnalysisError> get resolutionErrors => _resolutionErrors; |  | 
| 10844 |  | 
| 10845   /** |  | 
| 10846    * Return the [HtmlUnit] that was resolved by this task. |  | 
| 10847    * |  | 
| 10848    * @return the [HtmlUnit] that was resolved by this task |  | 
| 10849    */ |  | 
| 10850   ht.HtmlUnit get resolvedUnit => _resolvedUnit; |  | 
| 10851 |  | 
| 10852   @override |  | 
| 10853   String get taskDescription { |  | 
| 10854     if (source == null) { |  | 
| 10855       return "resolve as html null source"; |  | 
| 10856     } |  | 
| 10857     return "resolve as html ${source.fullName}"; |  | 
| 10858   } |  | 
| 10859 |  | 
| 10860   @override |  | 
| 10861   accept(AnalysisTaskVisitor visitor) => visitor.visitResolveHtmlTask(this); |  | 
| 10862 |  | 
| 10863   @override |  | 
| 10864   void internalPerform() { |  | 
| 10865     // |  | 
| 10866     // Build the standard HTML element. |  | 
| 10867     // |  | 
| 10868     HtmlUnitBuilder builder = new HtmlUnitBuilder(context); |  | 
| 10869     _element = builder.buildHtmlElement(source, _unit); |  | 
| 10870     RecordingErrorListener errorListener = builder.errorListener; |  | 
| 10871     // |  | 
| 10872     // Validate the directives |  | 
| 10873     // |  | 
| 10874     _unit.accept(new RecursiveXmlVisitor_ResolveHtmlTask_internalPerform( |  | 
| 10875         this, errorListener)); |  | 
| 10876     // |  | 
| 10877     // Record all resolution errors. |  | 
| 10878     // |  | 
| 10879     _resolutionErrors = errorListener.getErrorsForSource(source); |  | 
| 10880     // |  | 
| 10881     // Remember the resolved unit. |  | 
| 10882     // |  | 
| 10883     _resolvedUnit = _unit; |  | 
| 10884   } |  | 
| 10885 } |  | 
| 10886 |  | 
| 10887 /** |  | 
| 10888  * The priority of data in the cache in terms of the desirability of retaining |  | 
| 10889  * some specified data about a specified source. |  | 
| 10890  */ |  | 
| 10891 class RetentionPriority extends Enum<RetentionPriority> { |  | 
| 10892   /** |  | 
| 10893    * A priority indicating that a given piece of data can be removed from the |  | 
| 10894    * cache without reservation. |  | 
| 10895    */ |  | 
| 10896   static const RetentionPriority LOW = const RetentionPriority('LOW', 0); |  | 
| 10897 |  | 
| 10898   /** |  | 
| 10899    * A priority indicating that a given piece of data should not be removed from |  | 
| 10900    * the cache unless there are no sources for which the corresponding data has |  | 
| 10901    * a lower priority. Currently used for data that is needed in order to finish |  | 
| 10902    * some outstanding analysis task. |  | 
| 10903    */ |  | 
| 10904   static const RetentionPriority MEDIUM = const RetentionPriority('MEDIUM', 1); |  | 
| 10905 |  | 
| 10906   /** |  | 
| 10907    * A priority indicating that a given piece of data should not be removed from |  | 
| 10908    * the cache. Currently used for data related to a priority source. |  | 
| 10909    */ |  | 
| 10910   static const RetentionPriority HIGH = const RetentionPriority('HIGH', 2); |  | 
| 10911 |  | 
| 10912   static const List<RetentionPriority> values = const [LOW, MEDIUM, HIGH]; |  | 
| 10913 |  | 
| 10914   const RetentionPriority(String name, int ordinal) : super(name, ordinal); |  | 
| 10915 } |  | 
| 10916 |  | 
| 10917 /** |  | 
| 10918  * Instances of the class `ScanDartTask` scan a specific source as a Dart file. |  | 
| 10919  */ |  | 
| 10920 class ScanDartTask extends AnalysisTask { |  | 
| 10921   /** |  | 
| 10922    * The source to be scanned. |  | 
| 10923    */ |  | 
| 10924   final Source source; |  | 
| 10925 |  | 
| 10926   /** |  | 
| 10927    * The contents of the source. |  | 
| 10928    */ |  | 
| 10929   final String _content; |  | 
| 10930 |  | 
| 10931   /** |  | 
| 10932    * The token stream that was produced by scanning the source. |  | 
| 10933    */ |  | 
| 10934   Token _tokenStream; |  | 
| 10935 |  | 
| 10936   /** |  | 
| 10937    * The line information that was produced. |  | 
| 10938    */ |  | 
| 10939   LineInfo _lineInfo; |  | 
| 10940 |  | 
| 10941   /** |  | 
| 10942    * The errors that were produced by scanning the source. |  | 
| 10943    */ |  | 
| 10944   List<AnalysisError> _errors = AnalysisError.NO_ERRORS; |  | 
| 10945 |  | 
| 10946   /** |  | 
| 10947    * Initialize a newly created task to perform analysis within the given contex
       t. |  | 
| 10948    * |  | 
| 10949    * @param context the context in which the task is to be performed |  | 
| 10950    * @param source the source to be parsed |  | 
| 10951    * @param content the contents of the source |  | 
| 10952    */ |  | 
| 10953   ScanDartTask(InternalAnalysisContext context, this.source, this._content) |  | 
| 10954       : super(context); |  | 
| 10955 |  | 
| 10956   /** |  | 
| 10957    * Return the errors that were produced by scanning the source, or `null` if t
       he task has |  | 
| 10958    * not yet been performed or if an exception occurred. |  | 
| 10959    * |  | 
| 10960    * @return the errors that were produced by scanning the source |  | 
| 10961    */ |  | 
| 10962   List<AnalysisError> get errors => _errors; |  | 
| 10963 |  | 
| 10964   /** |  | 
| 10965    * Return the line information that was produced, or `null` if the task has no
       t yet been |  | 
| 10966    * performed or if an exception occurred. |  | 
| 10967    * |  | 
| 10968    * @return the line information that was produced |  | 
| 10969    */ |  | 
| 10970   LineInfo get lineInfo => _lineInfo; |  | 
| 10971 |  | 
| 10972   @override |  | 
| 10973   String get taskDescription { |  | 
| 10974     if (source == null) { |  | 
| 10975       return "scan as dart null source"; |  | 
| 10976     } |  | 
| 10977     return "scan as dart ${source.fullName}"; |  | 
| 10978   } |  | 
| 10979 |  | 
| 10980   /** |  | 
| 10981    * Return the token stream that was produced by scanning the source, or `null`
        if the task |  | 
| 10982    * has not yet been performed or if an exception occurred. |  | 
| 10983    * |  | 
| 10984    * @return the token stream that was produced by scanning the source |  | 
| 10985    */ |  | 
| 10986   Token get tokenStream => _tokenStream; |  | 
| 10987 |  | 
| 10988   @override |  | 
| 10989   accept(AnalysisTaskVisitor visitor) => visitor.visitScanDartTask(this); |  | 
| 10990 |  | 
| 10991   @override |  | 
| 10992   void internalPerform() { |  | 
| 10993     PerformanceStatistics.scan.makeCurrentWhile(() { |  | 
| 10994       RecordingErrorListener errorListener = new RecordingErrorListener(); |  | 
| 10995       try { |  | 
| 10996         Scanner scanner = new Scanner( |  | 
| 10997             source, new CharSequenceReader(_content), errorListener); |  | 
| 10998         scanner.preserveComments = context.analysisOptions.preserveComments; |  | 
| 10999         _tokenStream = scanner.tokenize(); |  | 
| 11000         _lineInfo = new LineInfo(scanner.lineStarts); |  | 
| 11001         _errors = errorListener.getErrorsForSource(source); |  | 
| 11002       } catch (exception, stackTrace) { |  | 
| 11003         throw new AnalysisException( |  | 
| 11004             "Exception", new CaughtException(exception, stackTrace)); |  | 
| 11005       } |  | 
| 11006     }); |  | 
| 11007   } |  | 
| 11008 } |  | 
| 11009 |  | 
| 11010 /** |  | 
| 11011  * An [AnalysisContext] that only contains sources for a Dart SDK. |  | 
| 11012  */ |  | 
| 11013 class SdkAnalysisContext extends AnalysisContextImpl { |  | 
| 11014   @override |  | 
| 11015   AnalysisCache createCacheFromSourceFactory(SourceFactory factory) { |  | 
| 11016     if (factory == null) { |  | 
| 11017       return super.createCacheFromSourceFactory(factory); |  | 
| 11018     } |  | 
| 11019     DartSdk sdk = factory.dartSdk; |  | 
| 11020     if (sdk == null) { |  | 
| 11021       throw new IllegalArgumentException( |  | 
| 11022           "The source factory for an SDK analysis context must have a DartUriRes
       olver"); |  | 
| 11023     } |  | 
| 11024     return new AnalysisCache( |  | 
| 11025         <CachePartition>[AnalysisEngine.instance.partitionManager.forSdk(sdk)]); |  | 
| 11026   } |  | 
| 11027 } |  | 
| 11028 |  | 
| 11029 /** |  | 
| 11030  * A cache partition that contains all of the sources in the SDK. |  | 
| 11031  */ |  | 
| 11032 class SdkCachePartition extends CachePartition { |  | 
| 11033   /** |  | 
| 11034    * Initialize a newly created partition. The [context] is the context that |  | 
| 11035    * owns this partition. The [maxCacheSize] is the maximum number of sources |  | 
| 11036    * for which AST structures should be kept in the cache. |  | 
| 11037    */ |  | 
| 11038   SdkCachePartition(InternalAnalysisContext context, int maxCacheSize) |  | 
| 11039       : super(context, maxCacheSize, DefaultRetentionPolicy.POLICY); |  | 
| 11040 |  | 
| 11041   @override |  | 
| 11042   bool contains(Source source) => source.isInSystemLibrary; |  | 
| 11043 } |  | 
| 11044 |  | 
| 11045 /** |  | 
| 11046  * The information cached by an analysis context about an individual source, no |  | 
| 11047  * matter what kind of source it is. |  | 
| 11048  */ |  | 
| 11049 abstract class SourceEntry { |  | 
| 11050   /** |  | 
| 11051    * The data descriptor representing the contents of the source. |  | 
| 11052    */ |  | 
| 11053   static final DataDescriptor<String> CONTENT = |  | 
| 11054       new DataDescriptor<String>("SourceEntry.CONTENT"); |  | 
| 11055 |  | 
| 11056   /** |  | 
| 11057    * The data descriptor representing the errors resulting from reading the |  | 
| 11058    * source content. |  | 
| 11059    */ |  | 
| 11060   static final DataDescriptor<List<AnalysisError>> CONTENT_ERRORS = |  | 
| 11061       new DataDescriptor<List<AnalysisError>>( |  | 
| 11062           "SourceEntry.CONTENT_ERRORS", AnalysisError.NO_ERRORS); |  | 
| 11063 |  | 
| 11064   /** |  | 
| 11065    * The data descriptor representing the line information. |  | 
| 11066    */ |  | 
| 11067   static final DataDescriptor<LineInfo> LINE_INFO = |  | 
| 11068       new DataDescriptor<LineInfo>("SourceEntry.LINE_INFO"); |  | 
| 11069 |  | 
| 11070   /** |  | 
| 11071    * The index of the flag indicating whether the source was explicitly added to |  | 
| 11072    * the context or whether the source was implicitly added because it was |  | 
| 11073    * referenced by another source. |  | 
| 11074    */ |  | 
| 11075   static int _EXPLICITLY_ADDED_FLAG = 0; |  | 
| 11076 |  | 
| 11077   /** |  | 
| 11078    * A table mapping data descriptors to a count of the number of times a value |  | 
| 11079    * was set when in a given state. |  | 
| 11080    */ |  | 
| 11081   static final Map<DataDescriptor, Map<CacheState, int>> transitionMap = |  | 
| 11082       new HashMap<DataDescriptor, Map<CacheState, int>>(); |  | 
| 11083 |  | 
| 11084   /** |  | 
| 11085    * The most recent time at which the state of the source matched the state |  | 
| 11086    * represented by this entry. |  | 
| 11087    */ |  | 
| 11088   int modificationTime = 0; |  | 
| 11089 |  | 
| 11090   /** |  | 
| 11091    * The exception that caused one or more values to have a state of |  | 
| 11092    * [CacheState.ERROR]. |  | 
| 11093    */ |  | 
| 11094   CaughtException exception; |  | 
| 11095 |  | 
| 11096   /** |  | 
| 11097    * A bit-encoding of boolean flags associated with this element. |  | 
| 11098    */ |  | 
| 11099   int _flags = 0; |  | 
| 11100 |  | 
| 11101   /** |  | 
| 11102    * A table mapping data descriptors to the cached results for those |  | 
| 11103    * descriptors. |  | 
| 11104    */ |  | 
| 11105   Map<DataDescriptor, CachedResult> resultMap = |  | 
| 11106       new HashMap<DataDescriptor, CachedResult>(); |  | 
| 11107 |  | 
| 11108   /** |  | 
| 11109    * Return all of the errors associated with this entry. |  | 
| 11110    */ |  | 
| 11111   List<AnalysisError> get allErrors { |  | 
| 11112     return getValue(CONTENT_ERRORS); |  | 
| 11113   } |  | 
| 11114 |  | 
| 11115   /** |  | 
| 11116    * Get a list of all the library-independent descriptors for which values may |  | 
| 11117    * be stored in this SourceEntry. |  | 
| 11118    */ |  | 
| 11119   List<DataDescriptor> get descriptors { |  | 
| 11120     return <DataDescriptor>[CONTENT, CONTENT_ERRORS, LINE_INFO]; |  | 
| 11121   } |  | 
| 11122 |  | 
| 11123   /** |  | 
| 11124    * Return `true` if the source was explicitly added to the context or `false` |  | 
| 11125    * if the source was implicitly added because it was referenced by another |  | 
| 11126    * source. |  | 
| 11127    */ |  | 
| 11128   bool get explicitlyAdded => _getFlag(_EXPLICITLY_ADDED_FLAG); |  | 
| 11129 |  | 
| 11130   /** |  | 
| 11131    * Set whether the source was explicitly added to the context to match the |  | 
| 11132    * [explicitlyAdded] flag. |  | 
| 11133    */ |  | 
| 11134   void set explicitlyAdded(bool explicitlyAdded) { |  | 
| 11135     _setFlag(_EXPLICITLY_ADDED_FLAG, explicitlyAdded); |  | 
| 11136   } |  | 
| 11137 |  | 
| 11138   /** |  | 
| 11139    * Return the kind of the source, or `null` if the kind is not currently |  | 
| 11140    * cached. |  | 
| 11141    */ |  | 
| 11142   SourceKind get kind; |  | 
| 11143 |  | 
| 11144   /** |  | 
| 11145    * Fix the state of the [exception] to match the current state of the entry. |  | 
| 11146    */ |  | 
| 11147   void fixExceptionState() { |  | 
| 11148     if (hasErrorState()) { |  | 
| 11149       if (exception == null) { |  | 
| 11150         // |  | 
| 11151         // This code should never be reached, but is a fail-safe in case an |  | 
| 11152         // exception is not recorded when it should be. |  | 
| 11153         // |  | 
| 11154         String message = "State set to ERROR without setting an exception"; |  | 
| 11155         exception = new CaughtException(new AnalysisException(message), null); |  | 
| 11156       } |  | 
| 11157     } else { |  | 
| 11158       exception = null; |  | 
| 11159     } |  | 
| 11160   } |  | 
| 11161 |  | 
| 11162   /** |  | 
| 11163    * Return a textual representation of the difference between the [oldEntry] |  | 
| 11164    * and this entry. The difference is represented as a sequence of fields whose |  | 
| 11165    * value would change if the old entry were converted into the new entry. |  | 
| 11166    */ |  | 
| 11167   String getDiff(SourceEntry oldEntry) { |  | 
| 11168     StringBuffer buffer = new StringBuffer(); |  | 
| 11169     _writeDiffOn(buffer, oldEntry); |  | 
| 11170     return buffer.toString(); |  | 
| 11171   } |  | 
| 11172 |  | 
| 11173   /** |  | 
| 11174    * Return the state of the data represented by the given [descriptor]. |  | 
| 11175    */ |  | 
| 11176   CacheState getState(DataDescriptor descriptor) { |  | 
| 11177     if (!_isValidDescriptor(descriptor)) { |  | 
| 11178       throw new ArgumentError("Invalid descriptor: $descriptor"); |  | 
| 11179     } |  | 
| 11180     CachedResult result = resultMap[descriptor]; |  | 
| 11181     if (result == null) { |  | 
| 11182       return CacheState.INVALID; |  | 
| 11183     } |  | 
| 11184     return result.state; |  | 
| 11185   } |  | 
| 11186 |  | 
| 11187   /** |  | 
| 11188    * Return the value of the data represented by the given [descriptor], or |  | 
| 11189    * `null` if the data represented by the descriptor is not valid. |  | 
| 11190    */ |  | 
| 11191   /*<V>*/ dynamic /*V*/ getValue(DataDescriptor /*<V>*/ descriptor) { |  | 
| 11192     if (!_isValidDescriptor(descriptor)) { |  | 
| 11193       throw new ArgumentError("Invalid descriptor: $descriptor"); |  | 
| 11194     } |  | 
| 11195     CachedResult result = resultMap[descriptor]; |  | 
| 11196     if (result == null) { |  | 
| 11197       return descriptor.defaultValue; |  | 
| 11198     } |  | 
| 11199     return result.value; |  | 
| 11200   } |  | 
| 11201 |  | 
| 11202   /** |  | 
| 11203    * Return `true` if the state of any data value is [CacheState.ERROR]. |  | 
| 11204    */ |  | 
| 11205   bool hasErrorState() { |  | 
| 11206     for (CachedResult result in resultMap.values) { |  | 
| 11207       if (result.state == CacheState.ERROR) { |  | 
| 11208         return true; |  | 
| 11209       } |  | 
| 11210     } |  | 
| 11211     return false; |  | 
| 11212   } |  | 
| 11213 |  | 
| 11214   /** |  | 
| 11215    * Invalidate all of the information associated with this source. |  | 
| 11216    */ |  | 
| 11217   void invalidateAllInformation() { |  | 
| 11218     setState(CONTENT, CacheState.INVALID); |  | 
| 11219     setState(CONTENT_ERRORS, CacheState.INVALID); |  | 
| 11220     setState(LINE_INFO, CacheState.INVALID); |  | 
| 11221   } |  | 
| 11222 |  | 
| 11223   /** |  | 
| 11224    * Record that an [exception] occurred while attempting to get the contents of |  | 
| 11225    * the source represented by this entry. This will set the state of all |  | 
| 11226    * information, including any resolution-based information, as being in error. |  | 
| 11227    */ |  | 
| 11228   void recordContentError(CaughtException exception) { |  | 
| 11229     setState(CONTENT, CacheState.ERROR); |  | 
| 11230     recordScanError(exception); |  | 
| 11231   } |  | 
| 11232 |  | 
| 11233   /** |  | 
| 11234    * Record that an [exception] occurred while attempting to scan or parse the |  | 
| 11235    * entry represented by this entry. This will set the state of all |  | 
| 11236    * information, including any resolution-based information, as being in error. |  | 
| 11237    */ |  | 
| 11238   void recordScanError(CaughtException exception) { |  | 
| 11239     this.exception = exception; |  | 
| 11240     setState(LINE_INFO, CacheState.ERROR); |  | 
| 11241   } |  | 
| 11242 |  | 
| 11243   /** |  | 
| 11244    * Set the state of the data represented by the given [descriptor] to the |  | 
| 11245    * given [state]. |  | 
| 11246    */ |  | 
| 11247   void setState(DataDescriptor descriptor, CacheState state) { |  | 
| 11248     if (!_isValidDescriptor(descriptor)) { |  | 
| 11249       throw new ArgumentError("Invalid descriptor: $descriptor"); |  | 
| 11250     } |  | 
| 11251     if (state == CacheState.VALID) { |  | 
| 11252       throw new ArgumentError("use setValue() to set the state to VALID"); |  | 
| 11253     } |  | 
| 11254     _validateStateChange(descriptor, state); |  | 
| 11255     if (state == CacheState.INVALID) { |  | 
| 11256       resultMap.remove(descriptor); |  | 
| 11257     } else { |  | 
| 11258       CachedResult result = |  | 
| 11259           resultMap.putIfAbsent(descriptor, () => new CachedResult(descriptor)); |  | 
| 11260       result.state = state; |  | 
| 11261       if (state != CacheState.IN_PROCESS) { |  | 
| 11262         // |  | 
| 11263         // If the state is in-process, we can leave the current value in the |  | 
| 11264         // cache for any 'get' methods to access. |  | 
| 11265         // |  | 
| 11266         result.value = descriptor.defaultValue; |  | 
| 11267       } |  | 
| 11268     } |  | 
| 11269   } |  | 
| 11270 |  | 
| 11271   /** |  | 
| 11272    * Set the value of the data represented by the given [descriptor] to the |  | 
| 11273    * given [value]. |  | 
| 11274    */ |  | 
| 11275   void setValue(DataDescriptor /*<V>*/ descriptor, dynamic /*V*/ value) { |  | 
| 11276     if (!_isValidDescriptor(descriptor)) { |  | 
| 11277       throw new ArgumentError("Invalid descriptor: $descriptor"); |  | 
| 11278     } |  | 
| 11279     _validateStateChange(descriptor, CacheState.VALID); |  | 
| 11280     CachedResult result = |  | 
| 11281         resultMap.putIfAbsent(descriptor, () => new CachedResult(descriptor)); |  | 
| 11282     countTransition(descriptor, result); |  | 
| 11283     result.state = CacheState.VALID; |  | 
| 11284     result.value = value == null ? descriptor.defaultValue : value; |  | 
| 11285   } |  | 
| 11286 |  | 
| 11287   @override |  | 
| 11288   String toString() { |  | 
| 11289     StringBuffer buffer = new StringBuffer(); |  | 
| 11290     _writeOn(buffer); |  | 
| 11291     return buffer.toString(); |  | 
| 11292   } |  | 
| 11293 |  | 
| 11294   /** |  | 
| 11295    * Flush the value of the data described by the [descriptor]. |  | 
| 11296    */ |  | 
| 11297   void _flush(DataDescriptor descriptor) { |  | 
| 11298     CachedResult result = resultMap[descriptor]; |  | 
| 11299     if (result != null && result.state == CacheState.VALID) { |  | 
| 11300       _validateStateChange(descriptor, CacheState.FLUSHED); |  | 
| 11301       result.state = CacheState.FLUSHED; |  | 
| 11302       result.value = descriptor.defaultValue; |  | 
| 11303     } |  | 
| 11304   } |  | 
| 11305 |  | 
| 11306   /** |  | 
| 11307    * Return the value of the flag with the given [index]. |  | 
| 11308    */ |  | 
| 11309   bool _getFlag(int index) => BooleanArray.get(_flags, index); |  | 
| 11310 |  | 
| 11311   /** |  | 
| 11312    * Return `true` if the [descriptor] is valid for this entry. |  | 
| 11313    */ |  | 
| 11314   bool _isValidDescriptor(DataDescriptor descriptor) { |  | 
| 11315     return descriptor == CONTENT || |  | 
| 11316         descriptor == CONTENT_ERRORS || |  | 
| 11317         descriptor == LINE_INFO; |  | 
| 11318   } |  | 
| 11319 |  | 
| 11320   /** |  | 
| 11321    * Set the value of the flag with the given [index] to the given [value]. |  | 
| 11322    */ |  | 
| 11323   void _setFlag(int index, bool value) { |  | 
| 11324     _flags = BooleanArray.set(_flags, index, value); |  | 
| 11325   } |  | 
| 11326 |  | 
| 11327   /** |  | 
| 11328    * If the state of the value described by the given [descriptor] is changing |  | 
| 11329    * from ERROR to anything else, capture the information. This is an attempt to |  | 
| 11330    * discover the underlying cause of a long-standing bug. |  | 
| 11331    */ |  | 
| 11332   void _validateStateChange(DataDescriptor descriptor, CacheState newState) { |  | 
| 11333     // TODO(brianwilkerson) Decide whether we still want to capture this data. |  | 
| 11334 //    if (descriptor != CONTENT) { |  | 
| 11335 //      return; |  | 
| 11336 //    } |  | 
| 11337 //    CachedResult result = resultMap[CONTENT]; |  | 
| 11338 //    if (result != null && result.state == CacheState.ERROR) { |  | 
| 11339 //      String message = |  | 
| 11340 //          "contentState changing from ${result.state} to $newState"; |  | 
| 11341 //      InstrumentationBuilder builder = |  | 
| 11342 //          Instrumentation.builder2("SourceEntry-validateStateChange"); |  | 
| 11343 //      builder.data3("message", message); |  | 
| 11344 //      //builder.data("source", source.getFullName()); |  | 
| 11345 //      builder.record(new CaughtException(new AnalysisException(message), null)
       ); |  | 
| 11346 //      builder.log(); |  | 
| 11347 //    } |  | 
| 11348   } |  | 
| 11349 |  | 
| 11350   /** |  | 
| 11351    * Write a textual representation of the difference between the [oldEntry] and |  | 
| 11352    * this entry to the given string [buffer]. Return `true` if some difference |  | 
| 11353    * was written. |  | 
| 11354    */ |  | 
| 11355   bool _writeDiffOn(StringBuffer buffer, SourceEntry oldEntry) { |  | 
| 11356     bool needsSeparator = false; |  | 
| 11357     CaughtException oldException = oldEntry.exception; |  | 
| 11358     if (!identical(oldException, exception)) { |  | 
| 11359       buffer.write("exception = "); |  | 
| 11360       buffer.write(oldException.runtimeType); |  | 
| 11361       buffer.write(" -> "); |  | 
| 11362       buffer.write(exception.runtimeType); |  | 
| 11363       needsSeparator = true; |  | 
| 11364     } |  | 
| 11365     int oldModificationTime = oldEntry.modificationTime; |  | 
| 11366     if (oldModificationTime != modificationTime) { |  | 
| 11367       if (needsSeparator) { |  | 
| 11368         buffer.write("; "); |  | 
| 11369       } |  | 
| 11370       buffer.write("time = "); |  | 
| 11371       buffer.write(oldModificationTime); |  | 
| 11372       buffer.write(" -> "); |  | 
| 11373       buffer.write(modificationTime); |  | 
| 11374       needsSeparator = true; |  | 
| 11375     } |  | 
| 11376     needsSeparator = |  | 
| 11377         _writeStateDiffOn(buffer, needsSeparator, "content", CONTENT, oldEntry); |  | 
| 11378     needsSeparator = _writeStateDiffOn( |  | 
| 11379         buffer, needsSeparator, "contentErrors", CONTENT_ERRORS, oldEntry); |  | 
| 11380     needsSeparator = _writeStateDiffOn( |  | 
| 11381         buffer, needsSeparator, "lineInfo", LINE_INFO, oldEntry); |  | 
| 11382     return needsSeparator; |  | 
| 11383   } |  | 
| 11384 |  | 
| 11385   /** |  | 
| 11386    * Write a textual representation of this entry to the given [buffer]. The |  | 
| 11387    * result should only be used for debugging purposes. |  | 
| 11388    */ |  | 
| 11389   void _writeOn(StringBuffer buffer) { |  | 
| 11390     buffer.write("time = "); |  | 
| 11391     buffer.write(modificationTime); |  | 
| 11392     _writeStateOn(buffer, "content", CONTENT); |  | 
| 11393     _writeStateOn(buffer, "contentErrors", CONTENT_ERRORS); |  | 
| 11394     _writeStateOn(buffer, "lineInfo", LINE_INFO); |  | 
| 11395   } |  | 
| 11396 |  | 
| 11397   /** |  | 
| 11398    * Write a textual representation of the difference between the state of the |  | 
| 11399    * value described by the given [descriptor] between the [oldEntry] and this |  | 
| 11400    * entry to the given [buffer]. Return `true` if some difference was written. |  | 
| 11401    */ |  | 
| 11402   bool _writeStateDiffOn(StringBuffer buffer, bool needsSeparator, String label, |  | 
| 11403       DataDescriptor descriptor, SourceEntry oldEntry) { |  | 
| 11404     CacheState oldState = oldEntry.getState(descriptor); |  | 
| 11405     CacheState newState = getState(descriptor); |  | 
| 11406     if (oldState != newState) { |  | 
| 11407       if (needsSeparator) { |  | 
| 11408         buffer.write("; "); |  | 
| 11409       } |  | 
| 11410       buffer.write(label); |  | 
| 11411       buffer.write(" = "); |  | 
| 11412       buffer.write(oldState); |  | 
| 11413       buffer.write(" -> "); |  | 
| 11414       buffer.write(newState); |  | 
| 11415       return true; |  | 
| 11416     } |  | 
| 11417     return needsSeparator; |  | 
| 11418   } |  | 
| 11419 |  | 
| 11420   /** |  | 
| 11421    * Write a textual representation of the state of the value described by the |  | 
| 11422    * given [descriptor] to the given bugger, prefixed by the given [label] to |  | 
| 11423    * the given [buffer]. |  | 
| 11424    */ |  | 
| 11425   void _writeStateOn( |  | 
| 11426       StringBuffer buffer, String label, DataDescriptor descriptor) { |  | 
| 11427     CachedResult result = resultMap[descriptor]; |  | 
| 11428     buffer.write("; "); |  | 
| 11429     buffer.write(label); |  | 
| 11430     buffer.write(" = "); |  | 
| 11431     buffer.write(result == null ? CacheState.INVALID : result.state); |  | 
| 11432   } |  | 
| 11433 |  | 
| 11434   /** |  | 
| 11435    * Increment the count of the number of times that data represented by the |  | 
| 11436    * given [descriptor] was transitioned from the current state (as found in the |  | 
| 11437    * given [result] to a valid state. |  | 
| 11438    */ |  | 
| 11439   static void countTransition(DataDescriptor descriptor, CachedResult result) { |  | 
| 11440     Map<CacheState, int> countMap = transitionMap.putIfAbsent( |  | 
| 11441         descriptor, () => new HashMap<CacheState, int>()); |  | 
| 11442     int count = countMap[result.state]; |  | 
| 11443     countMap[result.state] = count == null ? 1 : count + 1; |  | 
| 11444   } |  | 
| 11445 } |  | 
| 11446 |  | 
| 11447 /** |  | 
| 11448  * The priority levels used to return sources in an optimal order. A smaller |  | 
| 11449  * ordinal value equates to a higher priority. |  | 
| 11450  */ |  | 
| 11451 class SourcePriority extends Enum<SourcePriority> { |  | 
| 11452   /** |  | 
| 11453    * Used for a Dart source that is known to be a part contained in a library |  | 
| 11454    * that was recently resolved. These parts are given a higher priority because |  | 
| 11455    * there is a high probability that their AST structure is still in the cache |  | 
| 11456    * and therefore would not need to be re-created. |  | 
| 11457    */ |  | 
| 11458   static const SourcePriority PRIORITY_PART = |  | 
| 11459       const SourcePriority('PRIORITY_PART', 0); |  | 
| 11460 |  | 
| 11461   /** |  | 
| 11462    * Used for a Dart source that is known to be a library. |  | 
| 11463    */ |  | 
| 11464   static const SourcePriority LIBRARY = const SourcePriority('LIBRARY', 1); |  | 
| 11465 |  | 
| 11466   /** |  | 
| 11467    * Used for a Dart source whose kind is unknown. |  | 
| 11468    */ |  | 
| 11469   static const SourcePriority UNKNOWN = const SourcePriority('UNKNOWN', 2); |  | 
| 11470 |  | 
| 11471   /** |  | 
| 11472    * Used for a Dart source that is known to be a part but whose library has not |  | 
| 11473    * yet been resolved. |  | 
| 11474    */ |  | 
| 11475   static const SourcePriority NORMAL_PART = |  | 
| 11476       const SourcePriority('NORMAL_PART', 3); |  | 
| 11477 |  | 
| 11478   /** |  | 
| 11479    * Used for an HTML source. |  | 
| 11480    */ |  | 
| 11481   static const SourcePriority HTML = const SourcePriority('HTML', 4); |  | 
| 11482 |  | 
| 11483   static const List<SourcePriority> values = const [ |  | 
| 11484     PRIORITY_PART, |  | 
| 11485     LIBRARY, |  | 
| 11486     UNKNOWN, |  | 
| 11487     NORMAL_PART, |  | 
| 11488     HTML |  | 
| 11489   ]; |  | 
| 11490 |  | 
| 11491   const SourcePriority(String name, int ordinal) : super(name, ordinal); |  | 
| 11492 } |  | 
| 11493 |  | 
| 11494 /** |  | 
| 11495  * [SourcesChangedEvent] indicates which sources have been added, removed, |  | 
| 11496  * or whose contents have changed. |  | 
| 11497  */ |  | 
| 11498 class SourcesChangedEvent { |  | 
| 11499   /** |  | 
| 11500    * The internal representation of what has changed. Clients should not access |  | 
| 11501    * this field directly. |  | 
| 11502    */ |  | 
| 11503   final ChangeSet _changeSet; |  | 
| 11504 |  | 
| 11505   /** |  | 
| 11506    * Construct an instance representing the given changes. |  | 
| 11507    */ |  | 
| 11508   SourcesChangedEvent(ChangeSet changeSet) : _changeSet = changeSet; |  | 
| 11509 |  | 
| 11510   /** |  | 
| 11511    * Construct an instance representing a source content change. |  | 
| 11512    */ |  | 
| 11513   factory SourcesChangedEvent.changedContent(Source source, String contents) { |  | 
| 11514     ChangeSet changeSet = new ChangeSet(); |  | 
| 11515     changeSet.changedContent(source, contents); |  | 
| 11516     return new SourcesChangedEvent(changeSet); |  | 
| 11517   } |  | 
| 11518 |  | 
| 11519   /** |  | 
| 11520    * Construct an instance representing a source content change. |  | 
| 11521    */ |  | 
| 11522   factory SourcesChangedEvent.changedRange(Source source, String contents, |  | 
| 11523       int offset, int oldLength, int newLength) { |  | 
| 11524     ChangeSet changeSet = new ChangeSet(); |  | 
| 11525     changeSet.changedRange(source, contents, offset, oldLength, newLength); |  | 
| 11526     return new SourcesChangedEvent(changeSet); |  | 
| 11527   } |  | 
| 11528 |  | 
| 11529   /** |  | 
| 11530    * Return the collection of sources for which content has changed. |  | 
| 11531    */ |  | 
| 11532   Iterable<Source> get changedSources { |  | 
| 11533     List<Source> changedSources = new List.from(_changeSet.changedSources); |  | 
| 11534     changedSources.addAll(_changeSet.changedContents.keys); |  | 
| 11535     changedSources.addAll(_changeSet.changedRanges.keys); |  | 
| 11536     return changedSources; |  | 
| 11537   } |  | 
| 11538 |  | 
| 11539   /** |  | 
| 11540    * Return `true` if any sources were added. |  | 
| 11541    */ |  | 
| 11542   bool get wereSourcesAdded => _changeSet.addedSources.length > 0; |  | 
| 11543 |  | 
| 11544   /** |  | 
| 11545    * Return `true` if any sources were removed or deleted. |  | 
| 11546    */ |  | 
| 11547   bool get wereSourcesRemovedOrDeleted => |  | 
| 11548       _changeSet.removedSources.length > 0 || |  | 
| 11549           _changeSet.removedContainers.length > 0 || |  | 
| 11550           _changeSet.deletedSources.length > 0; |  | 
| 11551 } |  | 
| 11552 |  | 
| 11553 /** |  | 
| 11554  * Analysis data for which we have a modification time. |  | 
| 11555  */ |  | 
| 11556 class TimestampedData<E> { |  | 
| 11557   /** |  | 
| 11558    * The modification time of the source from which the data was created. |  | 
| 11559    */ |  | 
| 11560   final int modificationTime; |  | 
| 11561 |  | 
| 11562   /** |  | 
| 11563    * The data that was created from the source. |  | 
| 11564    */ |  | 
| 11565   final E data; |  | 
| 11566 |  | 
| 11567   /** |  | 
| 11568    * Initialize a newly created holder to associate the given [data] with the |  | 
| 11569    * given [modificationTime]. |  | 
| 11570    */ |  | 
| 11571   TimestampedData(this.modificationTime, this.data); |  | 
| 11572 } |  | 
| 11573 |  | 
| 11574 /** |  | 
| 11575  * A cache partition that contains all sources not contained in other |  | 
| 11576  * partitions. |  | 
| 11577  */ |  | 
| 11578 class UniversalCachePartition extends CachePartition { |  | 
| 11579   /** |  | 
| 11580    * Initialize a newly created partition. The [context] is the context that |  | 
| 11581    * owns this partition. The [maxCacheSize] is the maximum number of sources |  | 
| 11582    * for which AST structures should be kept in the cache. The [retentionPolicy] |  | 
| 11583    * is the policy used to determine which pieces of data to remove from the |  | 
| 11584    * cache. |  | 
| 11585    */ |  | 
| 11586   UniversalCachePartition(InternalAnalysisContext context, int maxCacheSize, |  | 
| 11587       CacheRetentionPolicy retentionPolicy) |  | 
| 11588       : super(context, maxCacheSize, retentionPolicy); |  | 
| 11589 |  | 
| 11590   @override |  | 
| 11591   bool contains(Source source) => true; |  | 
| 11592 } |  | 
| 11593 |  | 
| 11594 /** |  | 
| 11595  * The unique instances of the class `WaitForAsyncTask` represents a state in wh
       ich there is |  | 
| 11596  * no analysis work that can be done until some asynchronous task (such as IO) h
       as completed, but |  | 
| 11597  * where analysis is not yet complete. |  | 
| 11598  */ |  | 
| 11599 class WaitForAsyncTask extends AnalysisTask { |  | 
| 11600   /** |  | 
| 11601    * The unique instance of this class. |  | 
| 11602    */ |  | 
| 11603   static WaitForAsyncTask _UniqueInstance = new WaitForAsyncTask(); |  | 
| 11604 |  | 
| 11605   /** |  | 
| 11606    * Return the unique instance of this class. |  | 
| 11607    * |  | 
| 11608    * @return the unique instance of this class |  | 
| 11609    */ |  | 
| 11610   static WaitForAsyncTask get instance => _UniqueInstance; |  | 
| 11611 |  | 
| 11612   /** |  | 
| 11613    * Prevent the creation of instances of this class. |  | 
| 11614    */ |  | 
| 11615   WaitForAsyncTask() : super(null); |  | 
| 11616 |  | 
| 11617   @override |  | 
| 11618   String get taskDescription => "Waiting for async analysis"; |  | 
| 11619 |  | 
| 11620   @override |  | 
| 11621   accept(AnalysisTaskVisitor visitor) => null; |  | 
| 11622 |  | 
| 11623   @override |  | 
| 11624   void internalPerform() { |  | 
| 11625     // There is no work to be done. |  | 
| 11626   } |  | 
| 11627 } |  | 
| 11628 |  | 
| 11629 /** |  | 
| 11630  * An object that manages a list of sources that need to have analysis work |  | 
| 11631  * performed on them. |  | 
| 11632  */ |  | 
| 11633 class WorkManager { |  | 
| 11634   /** |  | 
| 11635    * A list containing the various queues is priority order. |  | 
| 11636    */ |  | 
| 11637   List<List<Source>> _workQueues; |  | 
| 11638 |  | 
| 11639   /** |  | 
| 11640    * Initialize a newly created manager to have no work queued up. |  | 
| 11641    */ |  | 
| 11642   WorkManager() { |  | 
| 11643     int queueCount = SourcePriority.values.length; |  | 
| 11644     _workQueues = new List<List<Source>>(queueCount); |  | 
| 11645     for (int i = 0; i < queueCount; i++) { |  | 
| 11646       _workQueues[i] = new List<Source>(); |  | 
| 11647     } |  | 
| 11648   } |  | 
| 11649 |  | 
| 11650   /** |  | 
| 11651    * Record that the given [source] needs to be analyzed. The [priority] level |  | 
| 11652    * is used to control when the source will be analyzed with respect to other |  | 
| 11653    * sources. If the source was previously added then it's priority is updated. |  | 
| 11654    * If it was previously added with the same priority then it's position in the |  | 
| 11655    * queue is unchanged. |  | 
| 11656    */ |  | 
| 11657   void add(Source source, SourcePriority priority) { |  | 
| 11658     int queueCount = _workQueues.length; |  | 
| 11659     int ordinal = priority.ordinal; |  | 
| 11660     for (int i = 0; i < queueCount; i++) { |  | 
| 11661       List<Source> queue = _workQueues[i]; |  | 
| 11662       if (i == ordinal) { |  | 
| 11663         if (!queue.contains(source)) { |  | 
| 11664           queue.add(source); |  | 
| 11665         } |  | 
| 11666       } else { |  | 
| 11667         queue.remove(source); |  | 
| 11668       } |  | 
| 11669     } |  | 
| 11670   } |  | 
| 11671 |  | 
| 11672   /** |  | 
| 11673    * Record that the given [source] needs to be analyzed. The [priority] level |  | 
| 11674    * is used to control when the source will be analyzed with respect to other |  | 
| 11675    * sources. If the source was previously added then it's priority is updated. |  | 
| 11676    * In either case, it will be analyzed before other sources of the same |  | 
| 11677    * priority. |  | 
| 11678    */ |  | 
| 11679   void addFirst(Source source, SourcePriority priority) { |  | 
| 11680     int queueCount = _workQueues.length; |  | 
| 11681     int ordinal = priority.ordinal; |  | 
| 11682     for (int i = 0; i < queueCount; i++) { |  | 
| 11683       List<Source> queue = _workQueues[i]; |  | 
| 11684       if (i == ordinal) { |  | 
| 11685         queue.remove(source); |  | 
| 11686         queue.insert(0, source); |  | 
| 11687       } else { |  | 
| 11688         queue.remove(source); |  | 
| 11689       } |  | 
| 11690     } |  | 
| 11691   } |  | 
| 11692 |  | 
| 11693   /** |  | 
| 11694    * Return an iterator that can be used to access the sources to be analyzed in |  | 
| 11695    * the order in which they should be analyzed. |  | 
| 11696    * |  | 
| 11697    * <b>Note:</b> As with other iterators, no sources can be added or removed |  | 
| 11698    * from this work manager while the iterator is being used. Unlike some |  | 
| 11699    * implementations, however, the iterator will not detect when this |  | 
| 11700    * requirement has been violated; it might work correctly, it might return the |  | 
| 11701    * wrong source, or it might throw an exception. |  | 
| 11702    */ |  | 
| 11703   WorkManager_WorkIterator iterator() => new WorkManager_WorkIterator(this); |  | 
| 11704 |  | 
| 11705   /** |  | 
| 11706    * Record that the given source is fully analyzed. |  | 
| 11707    */ |  | 
| 11708   void remove(Source source) { |  | 
| 11709     int queueCount = _workQueues.length; |  | 
| 11710     for (int i = 0; i < queueCount; i++) { |  | 
| 11711       _workQueues[i].remove(source); |  | 
| 11712     } |  | 
| 11713   } |  | 
| 11714 |  | 
| 11715   @override |  | 
| 11716   String toString() { |  | 
| 11717     StringBuffer buffer = new StringBuffer(); |  | 
| 11718     List<SourcePriority> priorities = SourcePriority.values; |  | 
| 11719     bool needsSeparator = false; |  | 
| 11720     int queueCount = _workQueues.length; |  | 
| 11721     for (int i = 0; i < queueCount; i++) { |  | 
| 11722       List<Source> queue = _workQueues[i]; |  | 
| 11723       if (!queue.isEmpty) { |  | 
| 11724         if (needsSeparator) { |  | 
| 11725           buffer.write("; "); |  | 
| 11726         } |  | 
| 11727         buffer.write(priorities[i]); |  | 
| 11728         buffer.write(": "); |  | 
| 11729         int queueSize = queue.length; |  | 
| 11730         for (int j = 0; j < queueSize; j++) { |  | 
| 11731           if (j > 0) { |  | 
| 11732             buffer.write(", "); |  | 
| 11733           } |  | 
| 11734           buffer.write(queue[j].fullName); |  | 
| 11735         } |  | 
| 11736         needsSeparator = true; |  | 
| 11737       } |  | 
| 11738     } |  | 
| 11739     return buffer.toString(); |  | 
| 11740   } |  | 
| 11741 } |  | 
| 11742 |  | 
| 11743 /** |  | 
| 11744  * An iterator that returns the sources in a work manager in the order in which |  | 
| 11745  * they are to be analyzed. |  | 
| 11746  */ |  | 
| 11747 class WorkManager_WorkIterator { |  | 
| 11748   final WorkManager _manager; |  | 
| 11749 |  | 
| 11750   /** |  | 
| 11751    * The index of the work queue through which we are currently iterating. |  | 
| 11752    */ |  | 
| 11753   int _queueIndex = 0; |  | 
| 11754 |  | 
| 11755   /** |  | 
| 11756    * The index of the next element of the work queue to be returned. |  | 
| 11757    */ |  | 
| 11758   int _index = -1; |  | 
| 11759 |  | 
| 11760   /** |  | 
| 11761    * Initialize a newly created iterator to be ready to return the first element |  | 
| 11762    * in the iteration. |  | 
| 11763    */ |  | 
| 11764   WorkManager_WorkIterator(this._manager) { |  | 
| 11765     _advance(); |  | 
| 11766   } |  | 
| 11767 |  | 
| 11768   /** |  | 
| 11769    * Return `true` if there is another [Source] available for processing. |  | 
| 11770    */ |  | 
| 11771   bool get hasNext => _queueIndex < _manager._workQueues.length; |  | 
| 11772 |  | 
| 11773   /** |  | 
| 11774    * Return the next [Source] available for processing and advance so that the |  | 
| 11775    * returned source will not be returned again. |  | 
| 11776    */ |  | 
| 11777   Source next() { |  | 
| 11778     if (!hasNext) { |  | 
| 11779       throw new NoSuchElementException(); |  | 
| 11780     } |  | 
| 11781     Source source = _manager._workQueues[_queueIndex][_index]; |  | 
| 11782     _advance(); |  | 
| 11783     return source; |  | 
| 11784   } |  | 
| 11785 |  | 
| 11786   /** |  | 
| 11787    * Increment the [index] and [queueIndex] so that they are either indicating |  | 
| 11788    * the next source to be returned or are indicating that there are no more |  | 
| 11789    * sources to be returned. |  | 
| 11790    */ |  | 
| 11791   void _advance() { |  | 
| 11792     _index++; |  | 
| 11793     if (_index >= _manager._workQueues[_queueIndex].length) { |  | 
| 11794       _index = 0; |  | 
| 11795       _queueIndex++; |  | 
| 11796       while (_queueIndex < _manager._workQueues.length && |  | 
| 11797           _manager._workQueues[_queueIndex].isEmpty) { |  | 
| 11798         _queueIndex++; |  | 
| 11799       } |  | 
| 11800     } |  | 
| 11801   } |  | 
| 11802 } |  | 
| 11803 |  | 
| 11804 /** |  | 
| 11805  * A helper class used to create futures for AnalysisContextImpl. Using a helper |  | 
| 11806  * class allows us to preserve the generic parameter T. |  | 
| 11807  */ |  | 
| 11808 class _AnalysisFutureHelper<T> { |  | 
| 11809   final AnalysisContextImpl _context; |  | 
| 11810 |  | 
| 11811   _AnalysisFutureHelper(this._context); |  | 
| 11812 |  | 
| 11813   /** |  | 
| 11814    * Return a future that will be completed with the result of calling |  | 
| 11815    * [computeValue].  If [computeValue] returns non-null, the future will be |  | 
| 11816    * completed immediately with the resulting value.  If it returns null, then |  | 
| 11817    * it will be re-executed in the future, after the next time the cached |  | 
| 11818    * information for [source] has changed.  If [computeValue] throws an |  | 
| 11819    * exception, the future will fail with that exception. |  | 
| 11820    * |  | 
| 11821    * If the [computeValue] still returns null after there is no further |  | 
| 11822    * analysis to be done for [source], then the future will be completed with |  | 
| 11823    * the error AnalysisNotScheduledError. |  | 
| 11824    * |  | 
| 11825    * Since [computeValue] will be called while the state of analysis is being |  | 
| 11826    * updated, it should be free of side effects so that it doesn't cause |  | 
| 11827    * reentrant changes to the analysis state. |  | 
| 11828    */ |  | 
| 11829   CancelableFuture<T> computeAsync( |  | 
| 11830       Source source, T computeValue(SourceEntry sourceEntry)) { |  | 
| 11831     if (_context.isDisposed) { |  | 
| 11832       // No further analysis is expected, so return a future that completes |  | 
| 11833       // immediately with AnalysisNotScheduledError. |  | 
| 11834       return new CancelableFuture.error(new AnalysisNotScheduledError()); |  | 
| 11835     } |  | 
| 11836     SourceEntry sourceEntry = _context.getReadableSourceEntryOrNull(source); |  | 
| 11837     if (sourceEntry == null) { |  | 
| 11838       return new CancelableFuture.error(new AnalysisNotScheduledError()); |  | 
| 11839     } |  | 
| 11840     PendingFuture pendingFuture = |  | 
| 11841         new PendingFuture<T>(_context, source, computeValue); |  | 
| 11842     if (!pendingFuture.evaluate(sourceEntry)) { |  | 
| 11843       _context._pendingFutureSources |  | 
| 11844           .putIfAbsent(source, () => <PendingFuture>[]) |  | 
| 11845           .add(pendingFuture); |  | 
| 11846     } |  | 
| 11847     return pendingFuture.future; |  | 
| 11848   } |  | 
| 11849 } |  | 
| OLD | NEW | 
|---|