Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library analyzer.src.context.context; | |
| 6 | |
| 7 import 'dart:async'; | |
| 8 import 'dart:collection'; | |
| 9 | |
| 10 import 'package:analyzer/src/cancelable_future.dart'; | |
| 11 import 'package:analyzer/src/context/cache.dart' as cache; | |
| 12 import 'package:analyzer/src/generated/ast.dart'; | |
| 13 import 'package:analyzer/src/generated/constant.dart'; | |
| 14 import 'package:analyzer/src/generated/element.dart'; | |
| 15 import 'package:analyzer/src/generated/engine.dart'; | |
| 16 import 'package:analyzer/src/generated/error.dart'; | |
| 17 import 'package:analyzer/src/generated/html.dart' as ht; | |
| 18 import 'package:analyzer/src/generated/java_core.dart'; | |
| 19 import 'package:analyzer/src/generated/java_engine.dart'; | |
| 20 import 'package:analyzer/src/generated/resolver.dart'; | |
| 21 import 'package:analyzer/src/generated/scanner.dart'; | |
| 22 import 'package:analyzer/src/generated/sdk.dart' show DartSdk; | |
| 23 import 'package:analyzer/src/generated/source.dart'; | |
| 24 import 'package:analyzer/src/generated/utilities_collection.dart'; | |
| 25 import 'package:analyzer/src/task/dart.dart'; | |
| 26 import 'package:analyzer/src/task/driver.dart'; | |
| 27 import 'package:analyzer/src/task/manager.dart'; | |
| 28 import 'package:analyzer/task/dart.dart'; | |
| 29 import 'package:analyzer/task/general.dart'; | |
| 30 import 'package:analyzer/task/model.dart'; | |
| 31 | |
| 32 /** | |
| 33 * An [AnalysisContext] in which analysis can be performed. | |
| 34 */ | |
| 35 class AnalysisContextImpl implements InternalAnalysisContext { | |
| 36 /** | |
| 37 * A client-provided name used to identify this context, or `null` if the | |
| 38 * client has not provided a name. | |
| 39 */ | |
| 40 String name; | |
| 41 | |
| 42 /** | |
| 43 * The set of analysis options controlling the behavior of this context. | |
| 44 */ | |
| 45 AnalysisOptionsImpl _options = new AnalysisOptionsImpl(); | |
| 46 | |
| 47 /** | |
| 48 * A flag indicating whether this context is disposed. | |
| 49 */ | |
| 50 bool _disposed = false; | |
| 51 | |
| 52 /** | |
| 53 * A cache of content used to override the default content of a source. | |
| 54 */ | |
| 55 ContentCache _contentCache = new ContentCache(); | |
| 56 | |
| 57 /** | |
| 58 * The source factory used to create the sources that can be analyzed in this | |
| 59 * context. | |
| 60 */ | |
| 61 SourceFactory _sourceFactory; | |
| 62 | |
| 63 /** | |
| 64 * The set of declared variables used when computing constant values. | |
| 65 */ | |
| 66 DeclaredVariables _declaredVariables = new DeclaredVariables(); | |
| 67 | |
| 68 /** | |
| 69 * The partition that contains analysis results that are not shared with other | |
| 70 * contexts. | |
| 71 */ | |
| 72 cache.CachePartition _privatePartition; | |
| 73 | |
| 74 /** | |
| 75 * The cache in which information about the results associated with targets | |
| 76 * are stored. | |
| 77 */ | |
| 78 cache.AnalysisCache _cache; | |
| 79 | |
| 80 /** | |
| 81 * The task manager used to manage the tasks used to analyze code. | |
| 82 */ | |
| 83 TaskManager _taskManager; | |
| 84 | |
| 85 /** | |
| 86 * The analysis driver used to perform analysis. | |
| 87 */ | |
| 88 AnalysisDriver _driver; | |
| 89 | |
| 90 /** | |
| 91 * A list containing sources for which data should not be flushed. | |
| 92 */ | |
| 93 List<Source> _priorityOrder = Source.EMPTY_ARRAY; | |
| 94 | |
| 95 /** | |
| 96 * A map from all sources for which there are futures pending to a list of | |
| 97 * the corresponding PendingFuture objects. These sources will be analyzed | |
| 98 * in the same way as priority sources, except with higher priority. | |
| 99 */ | |
| 100 HashMap<Source, List<PendingFuture>> _pendingFutureSources = | |
| 101 new HashMap<Source, List<PendingFuture>>(); | |
| 102 | |
| 103 /** | |
| 104 * A table mapping sources to the change notices that are waiting to be | |
| 105 * returned related to that source. | |
| 106 */ | |
| 107 HashMap<Source, ChangeNoticeImpl> _pendingNotices = | |
| 108 new HashMap<Source, ChangeNoticeImpl>(); | |
| 109 | |
| 110 /** | |
| 111 * Cached information used in incremental analysis or `null` if none. | |
| 112 */ | |
| 113 IncrementalAnalysisCache _incrementalAnalysisCache; | |
| 114 | |
| 115 /** | |
| 116 * The [TypeProvider] for this context, `null` if not yet created. | |
| 117 */ | |
| 118 TypeProvider _typeProvider; | |
| 119 | |
| 120 /** | |
| 121 * The controller for sending [SourcesChangedEvent]s. | |
| 122 */ | |
| 123 StreamController<SourcesChangedEvent> _onSourcesChangedController; | |
| 124 | |
| 125 /** | |
| 126 * The listeners that are to be notified when various analysis results are | |
| 127 * produced in this context. | |
| 128 */ | |
| 129 List<AnalysisListener> _listeners = new List<AnalysisListener>(); | |
| 130 | |
| 131 /** | |
| 132 * The most recently incrementally resolved source, or `null` when it was | |
| 133 * already validated, or the most recent change was not incrementally resolved . | |
| 134 */ | |
| 135 Source incrementalResolutionValidation_lastUnitSource; | |
| 136 | |
| 137 /** | |
| 138 * The most recently incrementally resolved library source, or `null` when it | |
| 139 * was already validated, or the most recent change was not incrementally | |
| 140 * resolved. | |
| 141 */ | |
| 142 Source incrementalResolutionValidation_lastLibrarySource; | |
| 143 | |
| 144 /** | |
| 145 * The result of incremental resolution result of | |
| 146 * [incrementalResolutionValidation_lastSource]. | |
| 147 */ | |
| 148 CompilationUnit incrementalResolutionValidation_lastUnit; | |
| 149 | |
| 150 /** | |
| 151 * A factory to override how the [ResolverVisitor] is created. | |
| 152 */ | |
| 153 ResolverVisitorFactory resolverVisitorFactory; | |
| 154 | |
| 155 /** | |
| 156 * A factory to override how the [TypeResolverVisitor] is created. | |
| 157 */ | |
| 158 TypeResolverVisitorFactory typeResolverVisitorFactory; | |
| 159 | |
| 160 /** | |
| 161 * A factory to override how [LibraryResolver] is created. | |
| 162 */ | |
| 163 LibraryResolverFactory libraryResolverFactory; | |
| 164 | |
| 165 /** | |
| 166 * Initialize a newly created analysis context. | |
| 167 */ | |
| 168 AnalysisContextImpl() { | |
| 169 _privatePartition = new cache.UniversalCachePartition(this, | |
| 170 AnalysisOptionsImpl.DEFAULT_CACHE_SIZE, | |
| 171 new ContextRetentionPolicy(this)); | |
| 172 _cache = createCacheFromSourceFactory(null); | |
| 173 _taskManager = AnalysisEngine.instance.taskManager; | |
| 174 _driver = new AnalysisDriver(_taskManager, this); | |
| 175 _onSourcesChangedController = | |
| 176 new StreamController<SourcesChangedEvent>.broadcast(); | |
| 177 } | |
| 178 | |
| 179 @override | |
| 180 AnalysisOptions get analysisOptions => _options; | |
| 181 | |
| 182 @override | |
| 183 void set analysisOptions(AnalysisOptions options) { | |
| 184 bool needsRecompute = this._options.analyzeFunctionBodiesPredicate != | |
| 185 options.analyzeFunctionBodiesPredicate || | |
| 186 this._options.generateImplicitErrors != | |
| 187 options.generateImplicitErrors || | |
| 188 this._options.generateSdkErrors != options.generateSdkErrors || | |
| 189 this._options.dart2jsHint != options.dart2jsHint || | |
| 190 (this._options.hint && !options.hint) || | |
| 191 this._options.preserveComments != options.preserveComments || | |
| 192 this._options.enableNullAwareOperators != | |
| 193 options.enableNullAwareOperators || | |
| 194 this._options.enableStrictCallChecks != options.enableStrictCallChecks; | |
| 195 int cacheSize = options.cacheSize; | |
| 196 if (this._options.cacheSize != cacheSize) { | |
| 197 this._options.cacheSize = cacheSize; | |
| 198 _privatePartition.maxCacheSize = cacheSize; | |
| 199 } | |
| 200 this._options.analyzeFunctionBodiesPredicate = | |
| 201 options.analyzeFunctionBodiesPredicate; | |
| 202 this._options.generateImplicitErrors = options.generateImplicitErrors; | |
| 203 this._options.generateSdkErrors = options.generateSdkErrors; | |
| 204 this._options.dart2jsHint = options.dart2jsHint; | |
| 205 this._options.enableNullAwareOperators = options.enableNullAwareOperators; | |
| 206 this._options.enableStrictCallChecks = options.enableStrictCallChecks; | |
| 207 this._options.hint = options.hint; | |
| 208 this._options.incremental = options.incremental; | |
| 209 this._options.incrementalApi = options.incrementalApi; | |
| 210 this._options.incrementalValidation = options.incrementalValidation; | |
| 211 this._options.lint = options.lint; | |
| 212 this._options.preserveComments = options.preserveComments; | |
| 213 if (needsRecompute) { | |
| 214 _invalidateAllLocalResolutionInformation(false); | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 @override | |
| 219 void set analysisPriorityOrder(List<Source> sources) { | |
| 220 if (sources == null || sources.isEmpty) { | |
| 221 _priorityOrder = Source.EMPTY_ARRAY; | |
| 222 } else { | |
| 223 while (sources.remove(null)) { | |
| 224 // Nothing else to do. | |
| 225 } | |
| 226 if (sources.isEmpty) { | |
| 227 _priorityOrder = Source.EMPTY_ARRAY; | |
| 228 } else { | |
| 229 _priorityOrder = sources; | |
| 230 } | |
| 231 } | |
| 232 } | |
| 233 | |
| 234 @override | |
| 235 set contentCache(ContentCache value) { | |
| 236 _contentCache = value; | |
| 237 } | |
| 238 | |
| 239 @override | |
| 240 DeclaredVariables get declaredVariables => _declaredVariables; | |
| 241 | |
| 242 @override | |
| 243 List<AnalysisTarget> get explicitTargets { | |
| 244 List<AnalysisTarget> targets = <AnalysisTarget>[]; | |
| 245 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator(); | |
| 246 while (iterator.moveNext()) { | |
| 247 if (iterator.value.explicitlyAdded) { | |
| 248 targets.add(iterator.key); | |
| 249 } | |
| 250 } | |
| 251 return targets; | |
| 252 } | |
| 253 | |
| 254 @override | |
| 255 List<Source> get htmlSources => _getSources(SourceKind.HTML); | |
| 256 | |
| 257 @override | |
| 258 bool get isDisposed => _disposed; | |
| 259 | |
| 260 @override | |
| 261 List<Source> get launchableClientLibrarySources { | |
| 262 // TODO(brianwilkerson) This needs to filter out libraries that do not | |
| 263 // reference dart:html, either directly or indirectly. | |
| 264 List<Source> sources = new List<Source>(); | |
| 265 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator(); | |
| 266 while (iterator.moveNext()) { | |
| 267 AnalysisTarget target = iterator.key; | |
| 268 cache.CacheEntry entry = iterator.value; | |
| 269 if (target is Source && | |
| 270 entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY && | |
| 271 !target.isInSystemLibrary) { | |
| 272 // DartEntry dartEntry = (DartEntry) sourceEntry; | |
| 273 // if (dartEntry.getValue(DartEntry.IS_LAUNCHABLE) && !dartEntry.getVal ue(DartEntry.IS_CLIENT)) { | |
| 274 sources.add(target); | |
| 275 // } | |
| 276 } | |
| 277 } | |
| 278 return sources; | |
| 279 } | |
| 280 | |
| 281 @override | |
| 282 List<Source> get launchableServerLibrarySources { | |
| 283 // TODO(brianwilkerson) This needs to filter out libraries that reference | |
| 284 // dart:html, either directly or indirectly. | |
| 285 List<Source> sources = new List<Source>(); | |
| 286 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator(); | |
| 287 while (iterator.moveNext()) { | |
| 288 AnalysisTarget target = iterator.key; | |
| 289 cache.CacheEntry entry = iterator.value; | |
| 290 if (target is Source && | |
| 291 entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY && | |
| 292 !target.isInSystemLibrary) { | |
| 293 // DartEntry dartEntry = (DartEntry) sourceEntry; | |
| 294 // if (dartEntry.getValue(DartEntry.IS_LAUNCHABLE) && !dartEntry.getVal ue(DartEntry.IS_CLIENT)) { | |
| 295 sources.add(target); | |
| 296 // } | |
| 297 } | |
| 298 } | |
| 299 return sources; | |
| 300 } | |
| 301 | |
| 302 @override | |
| 303 List<Source> get librarySources => _getSources(SourceKind.LIBRARY); | |
| 304 | |
| 305 @override | |
| 306 Stream<SourcesChangedEvent> get onSourcesChanged => | |
| 307 _onSourcesChangedController.stream; | |
| 308 | |
| 309 /** | |
| 310 * Make _pendingFutureSources available to unit tests. | |
| 311 */ | |
| 312 HashMap<Source, List<PendingFuture>> get pendingFutureSources_forTesting => | |
| 313 _pendingFutureSources; | |
| 314 | |
| 315 @override | |
| 316 List<Source> get prioritySources => _priorityOrder; | |
| 317 | |
| 318 @override | |
| 319 List<AnalysisTarget> get priorityTargets => prioritySources; | |
| 320 | |
| 321 @override | |
| 322 List<Source> get refactoringUnsafeSources { | |
| 323 // TODO(brianwilkerson) Implement this. | |
| 324 List<Source> sources = new List<Source>(); | |
| 325 // MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator() ; | |
| 326 // while (iterator.moveNext()) { | |
| 327 // cache.CacheEntry entry = iterator.value; | |
| 328 // AnalysisTarget target = iterator.key; | |
| 329 // if (target is Source && | |
| 330 // !target.isInSystemLibrary && | |
| 331 // !entry.isRefactoringSafe) { | |
| 332 // sources.add(target); | |
| 333 // } | |
| 334 // } | |
| 335 return sources; | |
| 336 } | |
| 337 | |
| 338 @override | |
| 339 SourceFactory get sourceFactory => _sourceFactory; | |
| 340 | |
| 341 @override | |
| 342 void set sourceFactory(SourceFactory factory) { | |
| 343 if (identical(_sourceFactory, factory)) { | |
| 344 return; | |
| 345 } else if (factory.context != null) { | |
| 346 throw new IllegalStateException( | |
| 347 "Source factories cannot be shared between contexts"); | |
| 348 } | |
| 349 if (_sourceFactory != null) { | |
| 350 _sourceFactory.context = null; | |
| 351 } | |
| 352 factory.context = this; | |
| 353 _sourceFactory = factory; | |
| 354 _cache = createCacheFromSourceFactory(factory); | |
| 355 _invalidateAllLocalResolutionInformation(true); | |
| 356 } | |
| 357 | |
| 358 @override | |
| 359 List<Source> get sources { | |
| 360 List<Source> sources = new List<Source>(); | |
| 361 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator(); | |
| 362 while (iterator.moveNext()) { | |
| 363 AnalysisTarget target = iterator.key; | |
| 364 if (target is Source) { | |
| 365 sources.add(target); | |
| 366 } | |
| 367 } | |
| 368 return sources; | |
| 369 } | |
| 370 | |
| 371 /** | |
| 372 * Return a list of the sources that would be processed by | |
| 373 * [performAnalysisTask]. This method duplicates, and must therefore be kept | |
| 374 * in sync with, [getNextAnalysisTask]. This method is intended to be used for | |
| 375 * testing purposes only. | |
| 376 */ | |
| 377 List<Source> get sourcesNeedingProcessing { | |
| 378 HashSet<Source> sources = new HashSet<Source>(); | |
| 379 bool hintsEnabled = _options.hint; | |
| 380 bool lintsEnabled = _options.lint; | |
| 381 | |
| 382 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator(); | |
| 383 while (iterator.moveNext()) { | |
| 384 AnalysisTarget target = iterator.key; | |
| 385 if (target is Source) { | |
| 386 _getSourcesNeedingProcessing( | |
| 387 target, iterator.value, false, hintsEnabled, lintsEnabled, sources); | |
| 388 } | |
| 389 } | |
| 390 return new List<Source>.from(sources); | |
| 391 } | |
| 392 | |
| 393 @override | |
| 394 AnalysisContextStatistics get statistics { | |
| 395 AnalysisContextStatisticsImpl statistics = | |
| 396 new AnalysisContextStatisticsImpl(); | |
| 397 // TODO(brianwilkerson) Implement this. | |
| 398 // visitCacheItems(statistics._internalPutCacheItem); | |
| 399 // statistics.partitionData = _cache.partitionData; | |
| 400 return statistics; | |
| 401 } | |
| 402 | |
| 403 IncrementalAnalysisCache get test_incrementalAnalysisCache { | |
| 404 return _incrementalAnalysisCache; | |
| 405 } | |
| 406 | |
| 407 set test_incrementalAnalysisCache(IncrementalAnalysisCache value) { | |
| 408 _incrementalAnalysisCache = value; | |
| 409 } | |
| 410 | |
| 411 List<Source> get test_priorityOrder => _priorityOrder; | |
| 412 | |
| 413 @override | |
| 414 TypeProvider get typeProvider { | |
| 415 if (_typeProvider != null) { | |
| 416 return _typeProvider; | |
| 417 } | |
| 418 Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE); | |
| 419 if (coreSource == null) { | |
| 420 throw new AnalysisException("Could not create a source for dart:core"); | |
| 421 } | |
| 422 LibraryElement coreElement = computeLibraryElement(coreSource); | |
| 423 if (coreElement == null) { | |
| 424 throw new AnalysisException("Could not create an element for dart:core"); | |
| 425 } | |
| 426 Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC); | |
| 427 if (asyncSource == null) { | |
| 428 throw new AnalysisException("Could not create a source for dart:async"); | |
| 429 } | |
| 430 LibraryElement asyncElement = computeLibraryElement(asyncSource); | |
| 431 if (asyncElement == null) { | |
| 432 throw new AnalysisException("Could not create an element for dart:async"); | |
| 433 } | |
| 434 _typeProvider = new TypeProviderImpl(coreElement, asyncElement); | |
| 435 return _typeProvider; | |
| 436 } | |
| 437 | |
| 438 /** | |
| 439 * Sets the [TypeProvider] for this context. | |
| 440 */ | |
| 441 void set typeProvider(TypeProvider typeProvider) { | |
| 442 _typeProvider = typeProvider; | |
| 443 } | |
| 444 | |
| 445 /** | |
| 446 * Return `true` if the (new) task model should be used to perform analysis. | |
| 447 */ | |
| 448 bool get useTaskModel => AnalysisEngine.instance.useTaskModel; | |
| 449 | |
| 450 @override | |
| 451 void addListener(AnalysisListener listener) { | |
| 452 if (!_listeners.contains(listener)) { | |
| 453 _listeners.add(listener); | |
| 454 } | |
| 455 } | |
| 456 | |
| 457 @override | |
| 458 void addSourceInfo(Source source, SourceEntry info) { | |
| 459 // TODO(brianwilkerson) This method needs to be replaced by something that | |
| 460 // will copy CacheEntry's. | |
| 461 // _cache.put(source, info); | |
| 462 } | |
| 463 | |
| 464 @override | |
| 465 void applyAnalysisDelta(AnalysisDelta delta) { | |
| 466 ChangeSet changeSet = new ChangeSet(); | |
| 467 delta.analysisLevels.forEach((Source source, AnalysisLevel level) { | |
| 468 if (level == AnalysisLevel.NONE) { | |
| 469 changeSet.removedSource(source); | |
| 470 } else { | |
| 471 changeSet.addedSource(source); | |
| 472 } | |
| 473 }); | |
| 474 applyChanges(changeSet); | |
| 475 } | |
| 476 | |
| 477 @override | |
| 478 void applyChanges(ChangeSet changeSet) { | |
| 479 if (changeSet.isEmpty) { | |
| 480 return; | |
| 481 } | |
| 482 // | |
| 483 // First, compute the list of sources that have been removed. | |
| 484 // | |
| 485 List<Source> removedSources = | |
| 486 new List<Source>.from(changeSet.removedSources); | |
| 487 for (SourceContainer container in changeSet.removedContainers) { | |
| 488 _addSourcesInContainer(removedSources, container); | |
| 489 } | |
| 490 // | |
| 491 // Then determine which cached results are no longer valid. | |
| 492 // | |
| 493 for (Source source in changeSet.addedSources) { | |
| 494 _sourceAvailable(source); | |
| 495 } | |
| 496 for (Source source in changeSet.changedSources) { | |
| 497 if (_contentCache.getContents(source) != null) { | |
| 498 // This source is overridden in the content cache, so the change will | |
| 499 // have no effect. Just ignore it to avoid wasting time doing | |
| 500 // re-analysis. | |
| 501 continue; | |
| 502 } | |
| 503 _sourceChanged(source); | |
| 504 } | |
| 505 changeSet.changedContents.forEach((Source key, String value) { | |
| 506 _contentsChanged(key, value, false); | |
| 507 }); | |
| 508 changeSet.changedRanges | |
| 509 .forEach((Source source, ChangeSet_ContentChange change) { | |
| 510 _contentRangeChanged(source, change.contents, change.offset, | |
| 511 change.oldLength, change.newLength); | |
| 512 }); | |
| 513 for (Source source in changeSet.deletedSources) { | |
| 514 _sourceDeleted(source); | |
| 515 } | |
| 516 for (Source source in removedSources) { | |
| 517 _sourceRemoved(source); | |
| 518 } | |
| 519 _onSourcesChangedController.add(new SourcesChangedEvent(changeSet)); | |
| 520 } | |
| 521 | |
| 522 @override | |
| 523 String computeDocumentationComment(Element element) { | |
| 524 if (element == null) { | |
| 525 return null; | |
| 526 } | |
| 527 Source source = element.source; | |
| 528 if (source == null) { | |
| 529 return null; | |
| 530 } | |
| 531 CompilationUnit unit = parseCompilationUnit(source); | |
| 532 if (unit == null) { | |
| 533 return null; | |
| 534 } | |
| 535 NodeLocator locator = new NodeLocator.con1(element.nameOffset); | |
| 536 AstNode nameNode = locator.searchWithin(unit); | |
| 537 while (nameNode != null) { | |
| 538 if (nameNode is AnnotatedNode) { | |
| 539 Comment comment = nameNode.documentationComment; | |
| 540 if (comment == null) { | |
| 541 return null; | |
| 542 } | |
| 543 StringBuffer buffer = new StringBuffer(); | |
| 544 List<Token> tokens = comment.tokens; | |
| 545 for (int i = 0; i < tokens.length; i++) { | |
| 546 if (i > 0) { | |
| 547 buffer.write("\n"); | |
| 548 } | |
| 549 buffer.write(tokens[i].lexeme); | |
| 550 } | |
| 551 return buffer.toString(); | |
| 552 } | |
| 553 nameNode = nameNode.parent; | |
| 554 } | |
| 555 return null; | |
| 556 } | |
| 557 | |
| 558 @override | |
| 559 List<AnalysisError> computeErrors(Source source) => | |
| 560 _computeResult(source, DART_ERRORS); | |
| 561 | |
| 562 @override | |
| 563 List<Source> computeExportedLibraries(Source source) => | |
| 564 _computeResult(source, EXPORTED_LIBRARIES); | |
| 565 | |
| 566 @override | |
| 567 // TODO(brianwilkerson) Implement this. | |
| 568 HtmlElement computeHtmlElement(Source source) => null; | |
| 569 | |
| 570 @override | |
| 571 List<Source> computeImportedLibraries(Source source) => _computeResult( | |
| 572 source, IMPORTED_LIBRARIES); | |
| 573 | |
| 574 @override | |
| 575 SourceKind computeKindOf(Source source) => | |
| 576 _computeResult(source, SOURCE_KIND); | |
| 577 | |
| 578 @override | |
| 579 LibraryElement computeLibraryElement(Source source) => | |
| 580 _computeResult(source, LIBRARY_ELEMENT); //_computeResult(source, HtmlEntr y.ELEMENT); | |
| 581 | |
| 582 @override | |
| 583 LineInfo computeLineInfo(Source source) => _computeResult(source, LINE_INFO); | |
| 584 | |
| 585 @override | |
| 586 @deprecated | |
| 587 CompilationUnit computeResolvableCompilationUnit(Source source) { | |
| 588 return null; | |
| 589 } | |
| 590 | |
| 591 @override | |
| 592 CancelableFuture<CompilationUnit> computeResolvedCompilationUnitAsync( | |
| 593 Source unitSource, Source librarySource) { | |
| 594 // TODO(brianwilkerson) Implement this. | |
| 595 return new CancelableFuture<CompilationUnit>(() => null); | |
| 596 // return new _AnalysisFutureHelper<CompilationUnit>(this).computeAsync( | |
| 597 // unitSource, (SourceEntry sourceEntry) { | |
| 598 // if (sourceEntry is DartEntry) { | |
| 599 // if (sourceEntry.getStateInLibrary( | |
| 600 // DartEntry.RESOLVED_UNIT, librarySource) == | |
| 601 // CacheState.ERROR) { | |
| 602 // throw sourceEntry.exception; | |
| 603 // } | |
| 604 // return sourceEntry.getValueInLibrary( | |
| 605 // DartEntry.RESOLVED_UNIT, librarySource); | |
| 606 // } | |
| 607 // throw new AnalysisNotScheduledError(); | |
| 608 // }); | |
| 609 } | |
| 610 | |
| 611 /** | |
| 612 * Create an analysis cache based on the given source [factory]. | |
| 613 */ | |
| 614 cache.AnalysisCache createCacheFromSourceFactory(SourceFactory factory) { | |
| 615 if (factory == null) { | |
| 616 return new cache.AnalysisCache(<cache.CachePartition>[_privatePartition]); | |
| 617 } | |
| 618 DartSdk sdk = factory.dartSdk; | |
| 619 if (sdk == null) { | |
| 620 return new cache.AnalysisCache(<cache.CachePartition>[_privatePartition]); | |
| 621 } | |
| 622 return new cache.AnalysisCache(<cache.CachePartition>[ | |
| 623 AnalysisEngine.instance.partitionManager_new.forSdk(sdk), | |
| 624 _privatePartition | |
| 625 ]); | |
| 626 } | |
| 627 | |
| 628 @override | |
| 629 void dispose() { | |
| 630 _disposed = true; | |
| 631 for (List<PendingFuture> pendingFutures in _pendingFutureSources.values) { | |
| 632 for (PendingFuture pendingFuture in pendingFutures) { | |
| 633 pendingFuture.forciblyComplete(); | |
| 634 } | |
| 635 } | |
| 636 _pendingFutureSources.clear(); | |
| 637 } | |
| 638 | |
| 639 @override | |
| 640 List<CompilationUnit> ensureResolvedDartUnits(Source unitSource) { | |
| 641 // TODO(brianwilkerson) Implement this. | |
| 642 return null; | |
| 643 // cache.CacheEntry entry = _cache.get(unitSource); | |
| 644 // // Check every library. | |
| 645 // List<CompilationUnit> units = <CompilationUnit>[]; | |
| 646 // List<Source> containingLibraries = entry.containingLibraries; | |
| 647 // for (Source librarySource in containingLibraries) { | |
| 648 // CompilationUnit unit = | |
| 649 // entry.getValueInLibrary(DartEntry.RESOLVED_UNIT, librarySource); | |
| 650 // if (unit == null) { | |
| 651 // units = null; | |
| 652 // break; | |
| 653 // } | |
| 654 // units.add(unit); | |
| 655 // } | |
| 656 // // Invalidate the flushed RESOLVED_UNIT to force it eventually. | |
| 657 // if (units == null) { | |
| 658 // bool shouldBeScheduled = false; | |
| 659 // for (Source librarySource in containingLibraries) { | |
| 660 // if (entry.getStateInLibrary(DartEntry.RESOLVED_UNIT, librarySource) == | |
| 661 // CacheState.FLUSHED) { | |
| 662 // entry.setStateInLibrary( | |
| 663 // DartEntry.RESOLVED_UNIT, librarySource, CacheState.INVALID); | |
| 664 // shouldBeScheduled = true; | |
| 665 // } | |
| 666 // } | |
| 667 // if (shouldBeScheduled) { | |
| 668 // _workManager.add(unitSource, SourcePriority.UNKNOWN); | |
| 669 // } | |
| 670 // // We cannot provide resolved units right now, | |
| 671 // // but the future analysis will. | |
| 672 // return null; | |
| 673 // } | |
| 674 // // done | |
| 675 // return units; | |
| 676 } | |
| 677 | |
| 678 @override | |
| 679 bool exists(Source source) { | |
| 680 if (source == null) { | |
| 681 return false; | |
| 682 } | |
| 683 if (_contentCache.getContents(source) != null) { | |
| 684 return true; | |
| 685 } | |
| 686 return source.exists(); | |
| 687 } | |
| 688 | |
| 689 Element findElementById(int id) { | |
| 690 // TODO(brianwilkerson) Implement this. | |
| 691 return null; | |
| 692 // _ElementByIdFinder finder = new _ElementByIdFinder(id); | |
| 693 // try { | |
| 694 // MapIterator<AnalysisTarget, cache.CacheEntry> iterator = | |
| 695 // _cache.iterator(); | |
| 696 // while (iterator.moveNext()) { | |
| 697 // cache.CacheEntry entry = iterator.value; | |
| 698 // if (entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY) { | |
| 699 // DartEntry dartEntry = entry; | |
| 700 // LibraryElement library = dartEntry.getValue(DartEntry.ELEMENT); | |
| 701 // if (library != null) { | |
| 702 // library.accept(finder); | |
| 703 // } | |
| 704 // } | |
| 705 // } | |
| 706 // } on _ElementByIdFinderException { | |
| 707 // return finder.result; | |
| 708 // } | |
| 709 // return null; | |
| 710 } | |
| 711 | |
| 712 @override | |
| 713 cache.CacheEntry getCacheEntry(AnalysisTarget target) { | |
| 714 cache.CacheEntry entry = _cache.get(target); | |
| 715 if (entry == null) { | |
| 716 entry = new cache.CacheEntry(); | |
| 717 _cache.put(target, entry); | |
| 718 } | |
| 719 return entry; | |
| 720 } | |
| 721 | |
| 722 @override | |
| 723 CompilationUnitElement getCompilationUnitElement( | |
| 724 Source unitSource, Source librarySource) { | |
| 725 AnalysisTarget target = new LibrarySpecificUnit(librarySource, unitSource); | |
| 726 return _getResult(target, COMPILATION_UNIT_ELEMENT); | |
| 727 } | |
| 728 | |
| 729 @override | |
| 730 TimestampedData<String> getContents(Source source) { | |
| 731 String contents = _contentCache.getContents(source); | |
| 732 if (contents != null) { | |
| 733 return new TimestampedData<String>( | |
| 734 _contentCache.getModificationStamp(source), contents); | |
| 735 } | |
| 736 return source.contents; | |
| 737 } | |
| 738 | |
| 739 @override | |
| 740 InternalAnalysisContext getContextFor(Source source) { | |
| 741 InternalAnalysisContext context = _cache.getContextFor(source); | |
| 742 return context == null ? this : context; | |
| 743 } | |
| 744 | |
| 745 @override | |
| 746 Element getElement(ElementLocation location) { | |
| 747 // TODO(brianwilkerson) This should not be a "get" method. | |
| 748 try { | |
| 749 List<String> components = location.components; | |
| 750 Source source = _computeSourceFromEncoding(components[0]); | |
| 751 String sourceName = source.shortName; | |
| 752 if (AnalysisEngine.isDartFileName(sourceName)) { | |
| 753 ElementImpl element = computeLibraryElement(source) as ElementImpl; | |
| 754 for (int i = 1; i < components.length; i++) { | |
| 755 if (element == null) { | |
| 756 return null; | |
| 757 } | |
| 758 element = element.getChild(components[i]); | |
| 759 } | |
| 760 return element; | |
| 761 } | |
| 762 if (AnalysisEngine.isHtmlFileName(sourceName)) { | |
| 763 return computeHtmlElement(source); | |
| 764 } | |
| 765 } catch (exception) { | |
| 766 // If the location cannot be decoded for some reason then the underlying | |
| 767 // cause should have been logged already and we can fall though to return | |
| 768 // null. | |
| 769 } | |
| 770 return null; | |
| 771 } | |
| 772 | |
| 773 @override | |
| 774 AnalysisErrorInfo getErrors(Source source) => _getResult(source, DART_ERRORS); | |
| 775 | |
| 776 @override | |
| 777 HtmlElement getHtmlElement(Source source) { | |
| 778 // TODO(brianwilkerson) Implement this. | |
| 779 // SourceEntry sourceEntry = getReadableSourceEntryOrNull(source); | |
| 780 // if (sourceEntry is HtmlEntry) { | |
| 781 // return sourceEntry.getValue(HtmlEntry.ELEMENT); | |
| 782 // } | |
| 783 return null; | |
| 784 } | |
| 785 | |
| 786 @override | |
| 787 List<Source> getHtmlFilesReferencing(Source source) { | |
| 788 SourceKind sourceKind = getKindOf(source); | |
| 789 if (sourceKind == null) { | |
| 790 return Source.EMPTY_ARRAY; | |
| 791 } | |
| 792 List<Source> htmlSources = new List<Source>(); | |
| 793 while (true) { | |
| 794 if (sourceKind == SourceKind.PART) { | |
| 795 List<Source> librarySources = getLibrariesContaining(source); | |
| 796 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = | |
| 797 _cache.iterator(); | |
| 798 while (iterator.moveNext()) { | |
| 799 cache.CacheEntry entry = iterator.value; | |
| 800 if (entry.getValue(SOURCE_KIND) == SourceKind.HTML) { | |
| 801 List<Source> referencedLibraries = | |
| 802 (entry as HtmlEntry).getValue(HtmlEntry.REFERENCED_LIBRARIES); | |
| 803 if (_containsAny(referencedLibraries, librarySources)) { | |
| 804 htmlSources.add(iterator.key); | |
| 805 } | |
| 806 } | |
| 807 } | |
| 808 } else { | |
| 809 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = | |
| 810 _cache.iterator(); | |
| 811 while (iterator.moveNext()) { | |
| 812 cache.CacheEntry entry = iterator.value; | |
| 813 if (entry.getValue(SOURCE_KIND) == SourceKind.HTML) { | |
| 814 List<Source> referencedLibraries = | |
| 815 (entry as HtmlEntry).getValue(HtmlEntry.REFERENCED_LIBRARIES); | |
| 816 if (_contains(referencedLibraries, source)) { | |
| 817 htmlSources.add(iterator.key); | |
| 818 } | |
| 819 } | |
| 820 } | |
| 821 } | |
| 822 break; | |
| 823 } | |
| 824 if (htmlSources.isEmpty) { | |
| 825 return Source.EMPTY_ARRAY; | |
| 826 } | |
| 827 return htmlSources; | |
| 828 } | |
| 829 | |
| 830 @override | |
| 831 SourceKind getKindOf(Source source) => _getResult(source, SOURCE_KIND); | |
| 832 | |
| 833 @override | |
| 834 List<Source> getLibrariesContaining(Source source) { | |
| 835 // TODO(brianwilkerson) Implement this. | |
| 836 // cache.CacheEntry sourceEntry = _cache.get(source); | |
| 837 // if (sourceEntry is DartEntry) { | |
| 838 // return sourceEntry.containingLibraries; | |
| 839 // } | |
| 840 return Source.EMPTY_ARRAY; | |
| 841 } | |
| 842 | |
| 843 @override | |
| 844 List<Source> getLibrariesDependingOn(Source librarySource) { | |
| 845 List<Source> dependentLibraries = new List<Source>(); | |
| 846 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator(); | |
| 847 while (iterator.moveNext()) { | |
| 848 cache.CacheEntry entry = iterator.value; | |
| 849 if (entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY) { | |
| 850 if (_contains(entry.getValue(EXPORTED_LIBRARIES), librarySource)) { | |
| 851 dependentLibraries.add(iterator.key); | |
| 852 } | |
| 853 if (_contains(entry.getValue(IMPORTED_LIBRARIES), librarySource)) { | |
| 854 dependentLibraries.add(iterator.key); | |
| 855 } | |
| 856 } | |
| 857 } | |
| 858 if (dependentLibraries.isEmpty) { | |
| 859 return Source.EMPTY_ARRAY; | |
| 860 } | |
| 861 return dependentLibraries; | |
| 862 } | |
| 863 | |
| 864 @override | |
| 865 List<Source> getLibrariesReferencedFromHtml(Source htmlSource) { | |
| 866 // TODO(brianwilkerson) Implement this. | |
| 867 // cache.CacheEntry entry = getReadableSourceEntryOrNull(htmlSource); | |
| 868 // if (entry is HtmlEntry) { | |
| 869 // HtmlEntry htmlEntry = entry; | |
| 870 // return htmlEntry.getValue(HtmlEntry.REFERENCED_LIBRARIES); | |
| 871 // } | |
| 872 return Source.EMPTY_ARRAY; | |
| 873 } | |
| 874 | |
| 875 @override | |
| 876 LibraryElement getLibraryElement(Source source) => | |
| 877 _getResult(source, LIBRARY_ELEMENT); | |
| 878 | |
| 879 @override | |
| 880 LineInfo getLineInfo(Source source) => _getResult(source, LINE_INFO); | |
| 881 | |
| 882 @override | |
| 883 int getModificationStamp(Source source) { | |
| 884 int stamp = _contentCache.getModificationStamp(source); | |
| 885 if (stamp != null) { | |
| 886 return stamp; | |
| 887 } | |
| 888 return source.modificationStamp; | |
| 889 } | |
| 890 | |
| 891 @override | |
| 892 Namespace getPublicNamespace(LibraryElement library) { | |
| 893 // TODO(brianwilkerson) Rename this to not start with 'get'. | |
| 894 // Note that this is not part of the API of the interface. | |
| 895 // TODO(brianwilkerson) The public namespace used to be cached, but no is. | |
|
scheglov
2015/04/20 03:44:50
The only client of this method is NamespaceBuilder
Brian Wilkerson
2015/04/20 15:00:36
Clean-up (by someone) in a later CL.
| |
| 896 NamespaceBuilder builder = new NamespaceBuilder(); | |
| 897 return builder.createPublicNamespaceForLibrary(library); | |
| 898 } | |
| 899 | |
| 900 /** | |
| 901 * Return the cache entry associated with the given [source], or `null` if | |
| 902 * there is no entry associated with the source. | |
| 903 */ | |
| 904 cache.CacheEntry getReadableSourceEntryOrNull(Source source) => | |
| 905 _cache.get(source); | |
| 906 | |
| 907 @override | |
| 908 CompilationUnit getResolvedCompilationUnit( | |
| 909 Source unitSource, LibraryElement library) { | |
| 910 if (library == null) { | |
| 911 return null; | |
| 912 } | |
| 913 return getResolvedCompilationUnit2(unitSource, library.source); | |
| 914 } | |
| 915 | |
| 916 @override | |
| 917 CompilationUnit getResolvedCompilationUnit2( | |
| 918 Source unitSource, Source librarySource) => _getResult( | |
| 919 new LibrarySpecificUnit(librarySource, unitSource), RESOLVED_UNIT); | |
| 920 | |
| 921 @override | |
| 922 ht.HtmlUnit getResolvedHtmlUnit(Source htmlSource) { | |
| 923 // TODO(brianwilkerson) Implement this. | |
| 924 // SourceEntry sourceEntry = getReadableSourceEntryOrNull(htmlSource); | |
| 925 // if (sourceEntry is HtmlEntry) { | |
| 926 // HtmlEntry htmlEntry = sourceEntry; | |
| 927 // return htmlEntry.getValue(HtmlEntry.RESOLVED_UNIT); | |
| 928 // } | |
| 929 return null; | |
| 930 } | |
| 931 | |
| 932 @override | |
| 933 List<Source> getSourcesWithFullName(String path) { | |
| 934 List<Source> sources = <Source>[]; | |
| 935 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator(); | |
| 936 while (iterator.moveNext()) { | |
| 937 AnalysisTarget target = iterator.key; | |
| 938 if (target is Source && target.fullName == path) { | |
| 939 sources.add(target); | |
| 940 } | |
| 941 } | |
| 942 return sources; | |
| 943 } | |
| 944 | |
| 945 @override | |
| 946 bool handleContentsChanged( | |
| 947 Source source, String originalContents, String newContents, bool notify) { | |
| 948 cache.CacheEntry entry = _cache.get(source); | |
| 949 if (entry == null) { | |
| 950 return false; | |
| 951 } | |
| 952 bool changed = newContents != originalContents; | |
| 953 if (newContents != null) { | |
| 954 if (newContents != originalContents) { | |
| 955 _incrementalAnalysisCache = | |
| 956 IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source); | |
| 957 if (!analysisOptions.incremental || | |
| 958 !_tryPoorMansIncrementalResolution(source, newContents)) { | |
| 959 _sourceChanged(source); | |
| 960 } | |
| 961 entry.modificationTime = _contentCache.getModificationStamp(source); | |
| 962 entry.setValue(CONTENT, newContents); | |
| 963 } else { | |
| 964 entry.modificationTime = _contentCache.getModificationStamp(source); | |
| 965 } | |
| 966 } else if (originalContents != null) { | |
| 967 _incrementalAnalysisCache = | |
| 968 IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source); | |
| 969 changed = newContents != originalContents; | |
| 970 // We are removing the overlay for the file, check if the file's | |
| 971 // contents is the same as it was in the overlay. | |
| 972 try { | |
| 973 TimestampedData<String> fileContents = getContents(source); | |
| 974 String fileContentsData = fileContents.data; | |
| 975 if (fileContentsData == originalContents) { | |
| 976 entry.setValue(CONTENT, fileContentsData); | |
| 977 entry.modificationTime = fileContents.modificationTime; | |
| 978 changed = false; | |
| 979 } | |
| 980 } catch (e) {} | |
| 981 // If not the same content (e.g. the file is being closed without save), | |
| 982 // then force analysis. | |
| 983 if (changed) { | |
| 984 _sourceChanged(source); | |
| 985 } | |
| 986 } | |
| 987 if (notify && changed) { | |
| 988 _onSourcesChangedController | |
| 989 .add(new SourcesChangedEvent.changedContent(source, newContents)); | |
| 990 } | |
| 991 return changed; | |
| 992 } | |
| 993 | |
| 994 /** | |
| 995 * Invalidates hints in the given [librarySource] and included parts. | |
| 996 */ | |
| 997 void invalidateLibraryHints(Source librarySource) { | |
| 998 cache.CacheEntry entry = _cache.get(librarySource); | |
| 999 // Prepare sources to invalidate hints in. | |
| 1000 List<Source> sources = <Source>[librarySource]; | |
| 1001 sources.addAll(entry.getValue(INCLUDED_PARTS)); | |
| 1002 // Invalidate hints. | |
| 1003 for (Source source in sources) { | |
| 1004 LibrarySpecificUnit unitTarget = | |
| 1005 new LibrarySpecificUnit(librarySource, source); | |
| 1006 cache.CacheEntry unitEntry = _cache.get(unitTarget); | |
| 1007 if (unitEntry.getState(HINTS) == CacheState.VALID) { | |
| 1008 unitEntry.setState(HINTS, CacheState.INVALID); | |
| 1009 } | |
| 1010 } | |
| 1011 } | |
| 1012 | |
| 1013 @override | |
| 1014 bool isClientLibrary(Source librarySource) { | |
| 1015 cache.CacheEntry entry = _cache.get(librarySource); | |
| 1016 return entry.getValue(IS_CLIENT) && entry.getValue(IS_LAUNCHABLE); | |
| 1017 } | |
| 1018 | |
| 1019 @override | |
| 1020 bool isServerLibrary(Source librarySource) { | |
| 1021 cache.CacheEntry entry = _cache.get(librarySource); | |
| 1022 return !entry.getValue(IS_CLIENT) && entry.getValue(IS_LAUNCHABLE); | |
| 1023 } | |
| 1024 | |
| 1025 @override | |
| 1026 CompilationUnit parseCompilationUnit(Source source) { | |
| 1027 if (!AnalysisEngine.isDartFileName(source.shortName)) { | |
| 1028 return null; | |
| 1029 } | |
| 1030 return _computeResult(source, PARSED_UNIT); | |
| 1031 } | |
| 1032 | |
| 1033 @override | |
| 1034 ht.HtmlUnit parseHtmlUnit(Source source) { | |
| 1035 if (!AnalysisEngine.isHtmlFileName(source.shortName)) { | |
| 1036 return null; | |
| 1037 } | |
| 1038 // TODO(brianwilkerson) Implement HTML analysis. | |
| 1039 return null; //_computeResult(source, null); | |
| 1040 } | |
| 1041 | |
| 1042 @override | |
| 1043 AnalysisResult performAnalysisTask() { | |
| 1044 return PerformanceStatistics.performAnaysis.makeCurrentWhile(() { | |
| 1045 bool done = !_driver.performAnalysisTask(); | |
| 1046 if (done) { | |
| 1047 done = !_validateCacheConsistency(); | |
| 1048 } | |
| 1049 List<ChangeNotice> notices = _getChangeNotices(done); | |
| 1050 if (notices != null) { | |
| 1051 int noticeCount = notices.length; | |
| 1052 for (int i = 0; i < noticeCount; i++) { | |
| 1053 ChangeNotice notice = notices[i]; | |
| 1054 _notifyErrors(notice.source, notice.errors, notice.lineInfo); | |
| 1055 } | |
| 1056 } | |
| 1057 return new AnalysisResult(notices, -1, '', -1); | |
| 1058 }); | |
| 1059 } | |
| 1060 | |
| 1061 @override | |
| 1062 void recordLibraryElements(Map<Source, LibraryElement> elementMap) { | |
| 1063 elementMap.forEach((Source librarySource, LibraryElement library) { | |
| 1064 // | |
| 1065 // Cache the element in the library's info. | |
| 1066 // | |
| 1067 cache.CacheEntry entry = getCacheEntry(librarySource); | |
| 1068 entry.setValue(BUILD_DIRECTIVES_ERRORS, AnalysisError.NO_ERRORS); | |
| 1069 entry.setValue( | |
| 1070 BUILD_FUNCTION_TYPE_ALIASES_ERRORS, AnalysisError.NO_ERRORS); | |
| 1071 entry.setValue(BUILD_LIBRARY_ERRORS, AnalysisError.NO_ERRORS); | |
| 1072 // CLASS_ELEMENTS | |
| 1073 entry.setValue(COMPILATION_UNIT_ELEMENT, library.definingCompilationUnit); | |
| 1074 // CONSTRUCTORS | |
| 1075 // CONSTRUCTORS_ERRORS | |
| 1076 entry.setState(CONTENT, CacheState.FLUSHED); | |
| 1077 entry.setValue(EXPORTED_LIBRARIES, Source.EMPTY_ARRAY); | |
| 1078 // EXPORT_SOURCE_CLOSURE | |
| 1079 entry.setValue(IMPORTED_LIBRARIES, Source.EMPTY_ARRAY); | |
| 1080 // IMPORT_SOURCE_CLOSURE | |
| 1081 entry.setValue(INCLUDED_PARTS, Source.EMPTY_ARRAY); | |
| 1082 entry.setValue(IS_CLIENT, true); | |
| 1083 entry.setValue(IS_LAUNCHABLE, false); | |
| 1084 entry.setValue(LIBRARY_ELEMENT, library); | |
| 1085 entry.setValue(LIBRARY_ELEMENT1, library); | |
| 1086 entry.setValue(LIBRARY_ELEMENT2, library); | |
| 1087 entry.setValue(LIBRARY_ELEMENT3, library); | |
| 1088 entry.setValue(LIBRARY_ELEMENT4, library); | |
| 1089 entry.setValue(LIBRARY_ELEMENT5, library); | |
| 1090 entry.setValue(LINE_INFO, new LineInfo(<int>[0])); | |
| 1091 entry.setValue(PARSE_ERRORS, AnalysisError.NO_ERRORS); | |
| 1092 entry.setState(PARSED_UNIT, CacheState.FLUSHED); | |
| 1093 entry.setState(RESOLVE_TYPE_NAMES_ERRORS, CacheState.FLUSHED); | |
| 1094 entry.setValue(SCAN_ERRORS, AnalysisError.NO_ERRORS); | |
| 1095 entry.setValue(SOURCE_KIND, SourceKind.LIBRARY); | |
| 1096 entry.setState(TOKEN_STREAM, CacheState.FLUSHED); | |
| 1097 entry.setValue(UNITS, <Source>[librarySource]); | |
| 1098 | |
| 1099 LibrarySpecificUnit unit = | |
| 1100 new LibrarySpecificUnit(librarySource, librarySource); | |
| 1101 entry = getCacheEntry(unit); | |
| 1102 entry.setValue(HINTS, AnalysisError.NO_ERRORS); | |
| 1103 // dartEntry.setValue(LINTS, AnalysisError.NO_ERRORS); | |
| 1104 entry.setState(RESOLVE_REFERENCES_ERRORS, CacheState.FLUSHED); | |
| 1105 entry.setState(RESOLVED_UNIT, CacheState.FLUSHED); | |
| 1106 entry.setState(RESOLVED_UNIT1, CacheState.FLUSHED); | |
| 1107 entry.setState(RESOLVED_UNIT2, CacheState.FLUSHED); | |
| 1108 entry.setState(RESOLVED_UNIT3, CacheState.FLUSHED); | |
| 1109 entry.setState(RESOLVED_UNIT4, CacheState.FLUSHED); | |
| 1110 entry.setState(RESOLVED_UNIT5, CacheState.FLUSHED); | |
| 1111 // USED_IMPORTED_ELEMENTS | |
| 1112 // USED_LOCAL_ELEMENTS | |
| 1113 entry.setValue(VERIFY_ERRORS, AnalysisError.NO_ERRORS); | |
| 1114 }); | |
| 1115 | |
| 1116 cache.CacheEntry entry = getCacheEntry(AnalysisContextTarget.request); | |
| 1117 entry.setValue(TYPE_PROVIDER, typeProvider); | |
| 1118 } | |
| 1119 | |
| 1120 @override | |
| 1121 void removeListener(AnalysisListener listener) { | |
| 1122 _listeners.remove(listener); | |
| 1123 } | |
| 1124 | |
| 1125 @override | |
| 1126 CompilationUnit resolveCompilationUnit( | |
| 1127 Source unitSource, LibraryElement library) { | |
| 1128 if (library == null) { | |
| 1129 return null; | |
| 1130 } | |
| 1131 return resolveCompilationUnit2(unitSource, library.source); | |
| 1132 } | |
| 1133 | |
| 1134 @override | |
| 1135 CompilationUnit resolveCompilationUnit2( | |
| 1136 Source unitSource, Source librarySource) => _computeResult( | |
| 1137 new LibrarySpecificUnit(librarySource, unitSource), RESOLVED_UNIT); | |
| 1138 | |
| 1139 @override | |
| 1140 ht.HtmlUnit resolveHtmlUnit(Source htmlSource) { | |
| 1141 computeHtmlElement(htmlSource); | |
| 1142 return parseHtmlUnit(htmlSource); | |
| 1143 } | |
| 1144 | |
| 1145 @override | |
| 1146 void setChangedContents(Source source, String contents, int offset, | |
| 1147 int oldLength, int newLength) { | |
| 1148 if (_contentRangeChanged(source, contents, offset, oldLength, newLength)) { | |
| 1149 _onSourcesChangedController.add(new SourcesChangedEvent.changedRange( | |
| 1150 source, contents, offset, oldLength, newLength)); | |
| 1151 } | |
| 1152 } | |
| 1153 | |
| 1154 @override | |
| 1155 void setContents(Source source, String contents) { | |
| 1156 _contentsChanged(source, contents, true); | |
| 1157 } | |
| 1158 | |
| 1159 @override | |
| 1160 void visitCacheItems(void callback(Source source, SourceEntry dartEntry, | |
| 1161 DataDescriptor rowDesc, CacheState state)) { | |
| 1162 // TODO(brianwilkerson) Figure out where this is used and adjust the call | |
| 1163 // sites to use CacheEntry's. | |
| 1164 // bool hintsEnabled = _options.hint; | |
| 1165 // bool lintsEnabled = _options.lint; | |
| 1166 // MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator() ; | |
| 1167 // while (iterator.moveNext()) { | |
| 1168 // Source source = iterator.key; | |
| 1169 // cache.CacheEntry sourceEntry = iterator.value; | |
| 1170 // for (DataDescriptor descriptor in sourceEntry.descriptors) { | |
| 1171 // if (descriptor == DartEntry.SOURCE_KIND) { | |
| 1172 // // The source kind is always valid, so the state isn't interesting. | |
| 1173 // continue; | |
| 1174 // } else if (descriptor == DartEntry.CONTAINING_LIBRARIES) { | |
| 1175 // // The list of containing libraries is always valid, so the state | |
| 1176 // // isn't interesting. | |
| 1177 // continue; | |
| 1178 // } else if (descriptor == DartEntry.PUBLIC_NAMESPACE) { | |
| 1179 // // The public namespace isn't computed by performAnalysisTask() | |
| 1180 // // and therefore isn't interesting. | |
| 1181 // continue; | |
| 1182 // } else if (descriptor == HtmlEntry.HINTS) { | |
| 1183 // // We are not currently recording any hints related to HTML. | |
| 1184 // continue; | |
| 1185 // } | |
| 1186 // callback( | |
| 1187 // source, sourceEntry, descriptor, sourceEntry.getState(descriptor)) ; | |
| 1188 // } | |
| 1189 // if (sourceEntry is DartEntry) { | |
| 1190 // // get library-specific values | |
| 1191 // List<Source> librarySources = getLibrariesContaining(source); | |
| 1192 // for (Source librarySource in librarySources) { | |
| 1193 // for (DataDescriptor descriptor in sourceEntry.libraryDescriptors) { | |
| 1194 // if (descriptor == DartEntry.BUILT_ELEMENT || | |
| 1195 // descriptor == DartEntry.BUILT_UNIT) { | |
| 1196 // // These values are not currently being computed, so their state | |
| 1197 // // is not interesting. | |
| 1198 // continue; | |
| 1199 // } else if (!sourceEntry.explicitlyAdded && | |
| 1200 // !_generateImplicitErrors && | |
| 1201 // (descriptor == DartEntry.VERIFICATION_ERRORS || | |
| 1202 // descriptor == DartEntry.HINTS || | |
| 1203 // descriptor == DartEntry.LINTS)) { | |
| 1204 // continue; | |
| 1205 // } else if (source.isInSystemLibrary && | |
| 1206 // !_generateSdkErrors && | |
| 1207 // (descriptor == DartEntry.VERIFICATION_ERRORS || | |
| 1208 // descriptor == DartEntry.HINTS || | |
| 1209 // descriptor == DartEntry.LINTS)) { | |
| 1210 // continue; | |
| 1211 // } else if (!hintsEnabled && descriptor == DartEntry.HINTS) { | |
| 1212 // continue; | |
| 1213 // } else if (!lintsEnabled && descriptor == DartEntry.LINTS) { | |
| 1214 // continue; | |
| 1215 // } | |
| 1216 // callback(librarySource, sourceEntry, descriptor, | |
| 1217 // sourceEntry.getStateInLibrary(descriptor, librarySource)); | |
| 1218 // } | |
| 1219 // } | |
| 1220 // } | |
| 1221 // } | |
| 1222 } | |
| 1223 | |
| 1224 /** | |
| 1225 * Visit all entries of the content cache. | |
| 1226 */ | |
| 1227 void visitContentCache(ContentCacheVisitor visitor) { | |
| 1228 _contentCache.accept(visitor); | |
| 1229 } | |
| 1230 | |
| 1231 /** | |
| 1232 * Add all of the sources contained in the given source [container] to the | |
| 1233 * given list of [sources]. | |
| 1234 */ | |
| 1235 void _addSourcesInContainer(List<Source> sources, SourceContainer container) { | |
| 1236 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator(); | |
| 1237 while (iterator.moveNext()) { | |
| 1238 Source source = iterator.key; | |
| 1239 if (container.contains(source)) { | |
| 1240 sources.add(source); | |
| 1241 } | |
| 1242 } | |
| 1243 } | |
| 1244 | |
| 1245 /** | |
| 1246 * Return the priority that should be used when the source associated with | |
| 1247 * the given [entry] is added to the work manager. | |
| 1248 */ | |
| 1249 SourcePriority _computePriority(cache.CacheEntry entry) { | |
| 1250 // Used in commented out code. | |
| 1251 SourceKind kind = entry.getValue(SOURCE_KIND); | |
| 1252 if (kind == SourceKind.LIBRARY) { | |
| 1253 return SourcePriority.LIBRARY; | |
| 1254 } else if (kind == SourceKind.PART) { | |
| 1255 return SourcePriority.NORMAL_PART; | |
| 1256 } | |
| 1257 return SourcePriority.UNKNOWN; | |
| 1258 } | |
| 1259 | |
| 1260 Object /*V*/ _computeResult( | |
| 1261 AnalysisTarget target, ResultDescriptor /*<V>*/ descriptor) { | |
| 1262 cache.CacheEntry entry = _cache.get(target); | |
| 1263 if (entry == null) { | |
| 1264 return descriptor.defaultValue; | |
| 1265 } | |
| 1266 if (descriptor is CompositeResultDescriptor) { | |
| 1267 List compositeResults = []; | |
| 1268 for (ResultDescriptor descriptor in descriptor.contributors) { | |
| 1269 List value = _computeResult(target, descriptor); | |
| 1270 compositeResults.addAll(value); | |
| 1271 } | |
| 1272 return compositeResults; | |
| 1273 } | |
| 1274 CacheState state = entry.getState(descriptor); | |
| 1275 if (state == CacheState.FLUSHED || state == CacheState.INVALID) { | |
| 1276 _driver.computeResult(target, descriptor); | |
| 1277 } | |
| 1278 return entry.getValue(descriptor); | |
| 1279 } | |
| 1280 | |
| 1281 /** | |
| 1282 * Given the encoded form of a source ([encoding]), use the source factory to | |
| 1283 * reconstitute the original source. | |
| 1284 */ | |
| 1285 Source _computeSourceFromEncoding(String encoding) => | |
| 1286 _sourceFactory.fromEncoding(encoding); | |
| 1287 | |
| 1288 /** | |
| 1289 * Return `true` if the given list of [sources] contains the given | |
| 1290 * [targetSource]. | |
| 1291 */ | |
| 1292 bool _contains(List<Source> sources, Source targetSource) { | |
| 1293 for (Source source in sources) { | |
| 1294 if (source == targetSource) { | |
| 1295 return true; | |
| 1296 } | |
| 1297 } | |
| 1298 return false; | |
| 1299 } | |
| 1300 | |
| 1301 /** | |
| 1302 * Return `true` if the given list of [sources] contains any of the given | |
| 1303 * [targetSources]. | |
| 1304 */ | |
| 1305 bool _containsAny(List<Source> sources, List<Source> targetSources) { | |
| 1306 for (Source targetSource in targetSources) { | |
| 1307 if (_contains(sources, targetSource)) { | |
| 1308 return true; | |
| 1309 } | |
| 1310 } | |
| 1311 return false; | |
| 1312 } | |
| 1313 | |
| 1314 /** | |
| 1315 * Set the contents of the given [source] to the given [contents] and mark the | |
| 1316 * source as having changed. The additional [offset], [oldLength] and | |
| 1317 * [newLength] information is used by the context to determine what reanalysis | |
| 1318 * is necessary. The method [setChangedContents] triggers a source changed | |
| 1319 * event where as this method does not. | |
| 1320 */ | |
| 1321 bool _contentRangeChanged(Source source, String contents, int offset, | |
| 1322 int oldLength, int newLength) { | |
| 1323 bool changed = false; | |
| 1324 String originalContents = _contentCache.setContents(source, contents); | |
| 1325 if (contents != null) { | |
| 1326 if (contents != originalContents) { | |
| 1327 // TODO(brianwilkerson) Find a better way to do incremental analysis. | |
| 1328 // if (_options.incremental) { | |
| 1329 // _incrementalAnalysisCache = IncrementalAnalysisCache.update( | |
| 1330 // _incrementalAnalysisCache, source, originalContents, contents, | |
| 1331 // offset, oldLength, newLength, _cache.get(source)); | |
| 1332 // } | |
| 1333 _sourceChanged(source); | |
| 1334 changed = true; | |
| 1335 cache.CacheEntry entry = _cache.get(source); | |
| 1336 if (entry != null) { | |
| 1337 entry.modificationTime = _contentCache.getModificationStamp(source); | |
| 1338 entry.setValue(CONTENT, contents); | |
| 1339 } | |
| 1340 } | |
| 1341 } else if (originalContents != null) { | |
| 1342 _incrementalAnalysisCache = | |
| 1343 IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source); | |
| 1344 _sourceChanged(source); | |
| 1345 changed = true; | |
| 1346 } | |
| 1347 return changed; | |
| 1348 } | |
| 1349 | |
| 1350 /** | |
| 1351 * Set the contents of the given [source] to the given [contents] and mark the | |
| 1352 * source as having changed. This has the effect of overriding the default | |
| 1353 * contents of the source. If the contents are `null` the override is removed | |
| 1354 * so that the default contents will be returned. If [notify] is true, a | |
| 1355 * source changed event is triggered. | |
| 1356 */ | |
| 1357 void _contentsChanged(Source source, String contents, bool notify) { | |
| 1358 String originalContents = _contentCache.setContents(source, contents); | |
| 1359 handleContentsChanged(source, originalContents, contents, notify); | |
| 1360 } | |
| 1361 | |
| 1362 /** | |
| 1363 * Create a cache entry for the given [source]. The source was explicitly | |
| 1364 * added to this context if [explicitlyAdded] is `true`. Return the cache | |
| 1365 * entry that was created. | |
| 1366 */ | |
| 1367 cache.CacheEntry _createCacheEntry(Source source, bool explicitlyAdded) { | |
| 1368 cache.CacheEntry entry = new cache.CacheEntry(); | |
| 1369 entry.modificationTime = getModificationStamp(source); | |
| 1370 entry.explicitlyAdded = explicitlyAdded; | |
| 1371 _cache.put(source, entry); | |
| 1372 return entry; | |
| 1373 } | |
| 1374 | |
| 1375 /** | |
| 1376 * Return a list containing all of the change notices that are waiting to be | |
| 1377 * returned. If there are no notices, then return either `null` or an empty | |
| 1378 * list, depending on the value of [nullIfEmpty]. | |
| 1379 */ | |
| 1380 List<ChangeNotice> _getChangeNotices(bool nullIfEmpty) { | |
| 1381 if (_pendingNotices.isEmpty) { | |
| 1382 if (nullIfEmpty) { | |
| 1383 return null; | |
| 1384 } | |
| 1385 return ChangeNoticeImpl.EMPTY_ARRAY; | |
| 1386 } | |
| 1387 List<ChangeNotice> notices = new List.from(_pendingNotices.values); | |
| 1388 _pendingNotices.clear(); | |
| 1389 return notices; | |
| 1390 } | |
| 1391 | |
| 1392 /** | |
| 1393 * Return a change notice for the given [source], creating one if one does not | |
| 1394 * already exist. | |
| 1395 */ | |
| 1396 ChangeNoticeImpl _getNotice(Source source) { | |
| 1397 // Used in commented out code. | |
| 1398 ChangeNoticeImpl notice = _pendingNotices[source]; | |
| 1399 if (notice == null) { | |
| 1400 notice = new ChangeNoticeImpl(source); | |
| 1401 _pendingNotices[source] = notice; | |
| 1402 } | |
| 1403 return notice; | |
| 1404 } | |
| 1405 | |
| 1406 Object _getResult(AnalysisTarget target, ResultDescriptor descriptor) { | |
| 1407 cache.CacheEntry entry = _cache.get(target); | |
| 1408 if (entry != null && entry.isValid(descriptor)) { | |
| 1409 return entry.getValue(descriptor); | |
| 1410 } | |
| 1411 return descriptor.defaultValue; | |
| 1412 } | |
| 1413 | |
| 1414 /** | |
| 1415 * Return a list containing all of the sources known to this context that have | |
| 1416 * the given [kind]. | |
| 1417 */ | |
| 1418 List<Source> _getSources(SourceKind kind) { | |
| 1419 List<Source> sources = new List<Source>(); | |
| 1420 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator(); | |
| 1421 while (iterator.moveNext()) { | |
| 1422 if (iterator.value.getValue(SOURCE_KIND) == kind && | |
| 1423 iterator.key is Source) { | |
| 1424 sources.add(iterator.key); | |
| 1425 } | |
| 1426 } | |
| 1427 return sources; | |
| 1428 } | |
| 1429 | |
| 1430 /** | |
| 1431 * Look at the given [source] to see whether a task needs to be performed | |
| 1432 * related to it. If so, add the source to the set of sources that need to be | |
| 1433 * processed. This method is intended to be used for testing purposes only. | |
| 1434 */ | |
| 1435 void _getSourcesNeedingProcessing(Source source, cache.CacheEntry sourceEntry, | |
| 1436 bool isPriority, bool hintsEnabled, bool lintsEnabled, | |
| 1437 HashSet<Source> sources) { | |
| 1438 CacheState state = sourceEntry.getState(CONTENT); | |
| 1439 if (state == CacheState.INVALID || | |
| 1440 (isPriority && state == CacheState.FLUSHED)) { | |
| 1441 sources.add(source); | |
| 1442 return; | |
| 1443 } else if (state == CacheState.ERROR) { | |
| 1444 return; | |
| 1445 } | |
| 1446 state = sourceEntry.getState(SOURCE_KIND); | |
| 1447 if (state == CacheState.INVALID || | |
| 1448 (isPriority && state == CacheState.FLUSHED)) { | |
| 1449 sources.add(source); | |
| 1450 return; | |
| 1451 } else if (state == CacheState.ERROR) { | |
| 1452 return; | |
| 1453 } | |
| 1454 SourceKind kind = sourceEntry.getValue(SOURCE_KIND); | |
| 1455 if (kind == SourceKind.LIBRARY || kind == SourceKind.PART) { | |
| 1456 state = sourceEntry.getState(SCAN_ERRORS); | |
| 1457 if (state == CacheState.INVALID || | |
| 1458 (isPriority && state == CacheState.FLUSHED)) { | |
| 1459 sources.add(source); | |
| 1460 return; | |
| 1461 } else if (state == CacheState.ERROR) { | |
| 1462 return; | |
| 1463 } | |
| 1464 state = sourceEntry.getState(PARSE_ERRORS); | |
| 1465 if (state == CacheState.INVALID || | |
| 1466 (isPriority && state == CacheState.FLUSHED)) { | |
| 1467 sources.add(source); | |
| 1468 return; | |
| 1469 } else if (state == CacheState.ERROR) { | |
| 1470 return; | |
| 1471 } | |
| 1472 // if (isPriority) { | |
| 1473 // if (!sourceEntry.hasResolvableCompilationUnit) { | |
| 1474 // sources.add(source); | |
| 1475 // return; | |
| 1476 // } | |
| 1477 // } | |
| 1478 for (Source librarySource in getLibrariesContaining(source)) { | |
| 1479 cache.CacheEntry libraryEntry = _cache.get(librarySource); | |
| 1480 state = libraryEntry.getState(LIBRARY_ELEMENT); | |
| 1481 if (state == CacheState.INVALID || | |
| 1482 (isPriority && state == CacheState.FLUSHED)) { | |
| 1483 sources.add(source); | |
| 1484 return; | |
| 1485 } else if (state == CacheState.ERROR) { | |
| 1486 return; | |
| 1487 } | |
| 1488 cache.CacheEntry unitEntry = | |
| 1489 _cache.get(new LibrarySpecificUnit(librarySource, source)); | |
| 1490 state = unitEntry.getState(RESOLVED_UNIT); | |
| 1491 if (state == CacheState.INVALID || | |
| 1492 (isPriority && state == CacheState.FLUSHED)) { | |
| 1493 sources.add(source); | |
| 1494 return; | |
| 1495 } else if (state == CacheState.ERROR) { | |
| 1496 return; | |
| 1497 } | |
| 1498 if (_shouldErrorsBeAnalyzed(source, unitEntry)) { | |
| 1499 state = unitEntry.getState(VERIFY_ERRORS); | |
| 1500 if (state == CacheState.INVALID || | |
| 1501 (isPriority && state == CacheState.FLUSHED)) { | |
| 1502 sources.add(source); | |
| 1503 return; | |
| 1504 } else if (state == CacheState.ERROR) { | |
| 1505 return; | |
| 1506 } | |
| 1507 if (hintsEnabled) { | |
| 1508 state = unitEntry.getState(HINTS); | |
| 1509 if (state == CacheState.INVALID || | |
| 1510 (isPriority && state == CacheState.FLUSHED)) { | |
| 1511 sources.add(source); | |
| 1512 return; | |
| 1513 } else if (state == CacheState.ERROR) { | |
| 1514 return; | |
| 1515 } | |
| 1516 } | |
| 1517 // if (lintsEnabled) { | |
| 1518 // state = unitEntry.getState(LINTS); | |
| 1519 // if (state == CacheState.INVALID || | |
| 1520 // (isPriority && state == CacheState.FLUSHED)) { | |
| 1521 // sources.add(source); | |
| 1522 // return; | |
| 1523 // } else if (state == CacheState.ERROR) { | |
| 1524 // return; | |
| 1525 // } | |
| 1526 // } | |
| 1527 } | |
| 1528 } | |
| 1529 // } else if (kind == SourceKind.HTML) { | |
| 1530 // CacheState parsedUnitState = sourceEntry.getState(HtmlEntry.PARSED_UNIT) ; | |
| 1531 // if (parsedUnitState == CacheState.INVALID || | |
| 1532 // (isPriority && parsedUnitState == CacheState.FLUSHED)) { | |
| 1533 // sources.add(source); | |
| 1534 // return; | |
| 1535 // } | |
| 1536 // CacheState resolvedUnitState = | |
| 1537 // sourceEntry.getState(HtmlEntry.RESOLVED_UNIT); | |
| 1538 // if (resolvedUnitState == CacheState.INVALID || | |
| 1539 // (isPriority && resolvedUnitState == CacheState.FLUSHED)) { | |
| 1540 // sources.add(source); | |
| 1541 // return; | |
| 1542 // } | |
| 1543 } | |
| 1544 } | |
| 1545 | |
| 1546 /** | |
| 1547 * Invalidate all of the resolution results computed by this context. The flag | |
| 1548 * [invalidateUris] should be `true` if the cached results of converting URIs | |
| 1549 * to source files should also be invalidated. | |
| 1550 */ | |
| 1551 void _invalidateAllLocalResolutionInformation(bool invalidateUris) { | |
| 1552 HashMap<Source, List<Source>> oldPartMap = | |
| 1553 new HashMap<Source, List<Source>>(); | |
| 1554 // TODO(brianwilkerson) Implement this | |
| 1555 // MapIterator<AnalysisTarget, cache.CacheEntry> iterator = | |
| 1556 // _privatePartition.iterator(); | |
| 1557 // while (iterator.moveNext()) { | |
| 1558 // AnalysisTarget target = iterator.key; | |
| 1559 // cache.CacheEntry entry = iterator.value; | |
| 1560 // if (entry is HtmlEntry) { | |
| 1561 // HtmlEntry htmlEntry = entry; | |
| 1562 // htmlEntry.invalidateAllResolutionInformation(invalidateUris); | |
| 1563 // iterator.value = htmlEntry; | |
| 1564 // _workManager.add(target, SourcePriority.HTML); | |
| 1565 // } else if (entry is DartEntry) { | |
| 1566 // DartEntry dartEntry = entry; | |
| 1567 // oldPartMap[target] = dartEntry.getValue(DartEntry.INCLUDED_PARTS); | |
| 1568 // dartEntry.invalidateAllResolutionInformation(invalidateUris); | |
| 1569 // iterator.value = dartEntry; | |
| 1570 // _workManager.add(target, _computePriority(dartEntry)); | |
| 1571 // } | |
| 1572 // } | |
| 1573 _removeFromPartsUsingMap(oldPartMap); | |
| 1574 } | |
| 1575 | |
| 1576 /** | |
| 1577 * In response to a change to at least one of the compilation units in the | |
| 1578 * library defined by the given [librarySource], invalidate any results that | |
| 1579 * are dependent on the result of resolving that library. | |
| 1580 * | |
| 1581 * <b>Note:</b> Any cache entries that were accessed before this method was | |
| 1582 * invoked must be re-accessed after this method returns. | |
| 1583 */ | |
| 1584 void _invalidateLibraryResolution(Source librarySource) { | |
| 1585 // TODO(brianwilkerson) Figure out whether we still need this. | |
| 1586 // TODO(brianwilkerson) This could be optimized. There's no need to flush | |
| 1587 // all of these entries if the public namespace hasn't changed, which will | |
| 1588 // be a fairly common case. The question is whether we can afford the time | |
| 1589 // to compute the namespace to look for differences. | |
| 1590 // DartEntry libraryEntry = _getReadableDartEntry(librarySource); | |
| 1591 // if (libraryEntry != null) { | |
| 1592 // List<Source> includedParts = | |
| 1593 // libraryEntry.getValue(DartEntry.INCLUDED_PARTS); | |
| 1594 // libraryEntry.invalidateAllResolutionInformation(false); | |
| 1595 // _workManager.add(librarySource, SourcePriority.LIBRARY); | |
| 1596 // for (Source partSource in includedParts) { | |
| 1597 // SourceEntry partEntry = _cache.get(partSource); | |
| 1598 // if (partEntry is DartEntry) { | |
| 1599 // partEntry.invalidateAllResolutionInformation(false); | |
| 1600 // } | |
| 1601 // } | |
| 1602 // } | |
| 1603 } | |
| 1604 | |
| 1605 /** | |
| 1606 * Log the given debugging [message]. | |
| 1607 */ | |
| 1608 void _logInformation(String message) { | |
| 1609 AnalysisEngine.instance.logger.logInformation(message); | |
| 1610 } | |
| 1611 | |
| 1612 /** | |
| 1613 * Notify all of the analysis listeners that the errors associated with the | |
| 1614 * given [source] has been updated to the given [errors]. | |
| 1615 */ | |
| 1616 void _notifyErrors( | |
| 1617 Source source, List<AnalysisError> errors, LineInfo lineInfo) { | |
| 1618 int count = _listeners.length; | |
| 1619 for (int i = 0; i < count; i++) { | |
| 1620 _listeners[i].computedErrors(this, source, errors, lineInfo); | |
| 1621 } | |
| 1622 } | |
| 1623 | |
| 1624 /** | |
| 1625 * Remove the given libraries that are keys in the given map from the list of | |
| 1626 * containing libraries for each of the parts in the corresponding value. | |
| 1627 */ | |
| 1628 void _removeFromPartsUsingMap(HashMap<Source, List<Source>> oldPartMap) { | |
| 1629 // TODO(brianwilkerson) Figure out whether we still need this. | |
| 1630 // oldPartMap.forEach((Source librarySource, List<Source> oldParts) { | |
| 1631 // for (int i = 0; i < oldParts.length; i++) { | |
| 1632 // Source partSource = oldParts[i]; | |
| 1633 // if (partSource != librarySource) { | |
| 1634 // DartEntry partEntry = _getReadableDartEntry(partSource); | |
| 1635 // if (partEntry != null) { | |
| 1636 // partEntry.removeContainingLibrary(librarySource); | |
| 1637 // if (partEntry.containingLibraries.length == 0 && | |
| 1638 // !exists(partSource)) { | |
| 1639 // _cache.remove(partSource); | |
| 1640 // } | |
| 1641 // } | |
| 1642 // } | |
| 1643 // } | |
| 1644 // }); | |
| 1645 } | |
| 1646 | |
| 1647 /** | |
| 1648 * Remove the given [source] from the priority order if it is in the list. | |
| 1649 */ | |
| 1650 void _removeFromPriorityOrder(Source source) { | |
| 1651 int count = _priorityOrder.length; | |
| 1652 List<Source> newOrder = new List<Source>(); | |
| 1653 for (int i = 0; i < count; i++) { | |
| 1654 if (_priorityOrder[i] != source) { | |
| 1655 newOrder.add(_priorityOrder[i]); | |
| 1656 } | |
| 1657 } | |
| 1658 if (newOrder.length < count) { | |
| 1659 analysisPriorityOrder = newOrder; | |
| 1660 } | |
| 1661 } | |
| 1662 | |
| 1663 /** | |
| 1664 * Return `true` if errors should be produced for the given [source]. The | |
| 1665 * [entry] associated with the source is passed in for efficiency. | |
| 1666 */ | |
| 1667 bool _shouldErrorsBeAnalyzed(Source source, cache.CacheEntry entry) { | |
| 1668 if (source.isInSystemLibrary) { | |
| 1669 return _options.generateSdkErrors; | |
| 1670 } else if (!entry.explicitlyAdded) { | |
| 1671 return _options.generateImplicitErrors; | |
| 1672 } else { | |
| 1673 return true; | |
| 1674 } | |
| 1675 } | |
| 1676 | |
| 1677 /** | |
| 1678 * Create an entry for the newly added [source] and invalidate any sources | |
| 1679 * that referenced the source before it existed. | |
| 1680 */ | |
| 1681 void _sourceAvailable(Source source) { | |
| 1682 cache.CacheEntry entry = _cache.get(source); | |
| 1683 if (entry == null) { | |
| 1684 _createCacheEntry(source, true); | |
| 1685 } else { | |
| 1686 // TODO(brianwilkerson) Implement this. | |
| 1687 // _propagateInvalidation(source, entry); | |
| 1688 } | |
| 1689 } | |
| 1690 | |
| 1691 /** | |
| 1692 * Invalidate the [source] that was changed and any sources that referenced | |
| 1693 * the source before it existed. | |
| 1694 */ | |
| 1695 void _sourceChanged(Source source) { | |
| 1696 cache.CacheEntry entry = _cache.get(source); | |
| 1697 // If the source is removed, we don't care about it. | |
| 1698 if (entry == null) { | |
| 1699 return; | |
| 1700 } | |
| 1701 // Check whether the content of the source is the same as it was the last | |
| 1702 // time. | |
| 1703 String sourceContent = entry.getValue(CONTENT); | |
| 1704 if (sourceContent != null) { | |
| 1705 entry.setState(CONTENT, CacheState.FLUSHED); | |
| 1706 try { | |
| 1707 TimestampedData<String> fileContents = getContents(source); | |
| 1708 if (fileContents.data == sourceContent) { | |
| 1709 return; | |
| 1710 } | |
| 1711 } catch (e) {} | |
| 1712 } | |
| 1713 // We need to invalidate the cache. | |
| 1714 // TODO(brianwilkerson) Implement this. | |
| 1715 // _propagateInvalidation(source, entry); | |
| 1716 } | |
| 1717 | |
| 1718 /** | |
| 1719 * Record that the give [source] has been deleted. | |
| 1720 */ | |
| 1721 void _sourceDeleted(Source source) { | |
| 1722 // TODO(brianwilkerson) Implement this. | |
| 1723 // SourceEntry sourceEntry = _cache.get(source); | |
| 1724 // if (sourceEntry is HtmlEntry) { | |
| 1725 // HtmlEntry htmlEntry = sourceEntry; | |
| 1726 // htmlEntry.recordContentError(new CaughtException( | |
| 1727 // new AnalysisException("This source was marked as being deleted"), | |
| 1728 // null)); | |
| 1729 // } else if (sourceEntry is DartEntry) { | |
| 1730 // DartEntry dartEntry = sourceEntry; | |
| 1731 // HashSet<Source> libraries = new HashSet<Source>(); | |
| 1732 // for (Source librarySource in getLibrariesContaining(source)) { | |
| 1733 // libraries.add(librarySource); | |
| 1734 // for (Source dependentLibrary | |
| 1735 // in getLibrariesDependingOn(librarySource)) { | |
| 1736 // libraries.add(dependentLibrary); | |
| 1737 // } | |
| 1738 // } | |
| 1739 // for (Source librarySource in libraries) { | |
| 1740 // _invalidateLibraryResolution(librarySource); | |
| 1741 // } | |
| 1742 // dartEntry.recordContentError(new CaughtException( | |
| 1743 // new AnalysisException("This source was marked as being deleted"), | |
| 1744 // null)); | |
| 1745 // } | |
| 1746 _removeFromPriorityOrder(source); | |
| 1747 } | |
| 1748 | |
| 1749 /** | |
| 1750 * Record that the given [source] has been removed. | |
| 1751 */ | |
| 1752 void _sourceRemoved(Source source) { | |
| 1753 List<Source> containingLibraries = getLibrariesContaining(source); | |
| 1754 if (containingLibraries != null && containingLibraries.isNotEmpty) { | |
| 1755 HashSet<Source> libraries = new HashSet<Source>(); | |
| 1756 for (Source librarySource in containingLibraries) { | |
| 1757 libraries.add(librarySource); | |
| 1758 for (Source dependentLibrary | |
| 1759 in getLibrariesDependingOn(librarySource)) { | |
| 1760 libraries.add(dependentLibrary); | |
| 1761 } | |
| 1762 } | |
| 1763 for (Source librarySource in libraries) { | |
| 1764 _invalidateLibraryResolution(librarySource); | |
| 1765 } | |
| 1766 } | |
| 1767 _cache.remove(source); | |
| 1768 _removeFromPriorityOrder(source); | |
| 1769 } | |
| 1770 | |
| 1771 /** | |
| 1772 * TODO(scheglov) A hackish, limited incremental resolution implementation. | |
| 1773 */ | |
| 1774 bool _tryPoorMansIncrementalResolution(Source unitSource, String newCode) { | |
| 1775 // TODO(brianwilkerson) Implement this. | |
| 1776 return false; | |
| 1777 // return PerformanceStatistics.incrementalAnalysis.makeCurrentWhile(() { | |
| 1778 // incrementalResolutionValidation_lastUnitSource = null; | |
| 1779 // incrementalResolutionValidation_lastLibrarySource = null; | |
| 1780 // incrementalResolutionValidation_lastUnit = null; | |
| 1781 // // prepare the entry | |
| 1782 // cache.CacheEntry entry = _cache.get(unitSource); | |
| 1783 // if (entry == null) { | |
| 1784 // return false; | |
| 1785 // } | |
| 1786 // // prepare the (only) library source | |
| 1787 // List<Source> librarySources = getLibrariesContaining(unitSource); | |
| 1788 // if (librarySources.length != 1) { | |
| 1789 // return false; | |
| 1790 // } | |
| 1791 // Source librarySource = librarySources[0]; | |
| 1792 // // prepare the library element | |
| 1793 // LibraryElement libraryElement = getLibraryElement(librarySource); | |
| 1794 // if (libraryElement == null) { | |
| 1795 // return false; | |
| 1796 // } | |
| 1797 // // prepare the existing unit | |
| 1798 // CompilationUnit oldUnit = | |
| 1799 // getResolvedCompilationUnit2(unitSource, librarySource); | |
| 1800 // if (oldUnit == null) { | |
| 1801 // return false; | |
| 1802 // } | |
| 1803 // // do resolution | |
| 1804 // Stopwatch perfCounter = new Stopwatch()..start(); | |
| 1805 // PoorMansIncrementalResolver resolver = new PoorMansIncrementalResolver( | |
| 1806 // typeProvider, unitSource, entry, oldUnit, | |
| 1807 // analysisOptions.incrementalApi, analysisOptions); | |
| 1808 // bool success = resolver.resolve(newCode); | |
| 1809 // AnalysisEngine.instance.instrumentationService.logPerformance( | |
| 1810 // AnalysisPerformanceKind.INCREMENTAL, perfCounter, | |
| 1811 // 'success=$success,context_id=$_id,code_length=${newCode.length}'); | |
| 1812 // if (!success) { | |
| 1813 // return false; | |
| 1814 // } | |
| 1815 // // if validation, remember the result, but throw it away | |
| 1816 // if (analysisOptions.incrementalValidation) { | |
| 1817 // incrementalResolutionValidation_lastUnitSource = oldUnit.element.sourc e; | |
| 1818 // incrementalResolutionValidation_lastLibrarySource = | |
| 1819 // oldUnit.element.library.source; | |
| 1820 // incrementalResolutionValidation_lastUnit = oldUnit; | |
| 1821 // return false; | |
| 1822 // } | |
| 1823 // // prepare notice | |
| 1824 // { | |
| 1825 // LineInfo lineInfo = getLineInfo(unitSource); | |
| 1826 // ChangeNoticeImpl notice = _getNotice(unitSource); | |
| 1827 // notice.resolvedDartUnit = oldUnit; | |
| 1828 // notice.setErrors(entry.allErrors, lineInfo); | |
| 1829 // } | |
| 1830 // // OK | |
| 1831 // return true; | |
| 1832 // }); | |
| 1833 } | |
| 1834 | |
| 1835 /** | |
| 1836 * Check the cache for any invalid entries (entries whose modification time | |
| 1837 * does not match the modification time of the source associated with the | |
| 1838 * entry). Invalid entries will be marked as invalid so that the source will | |
| 1839 * be re-analyzed. Return `true` if at least one entry was invalid. | |
| 1840 */ | |
| 1841 bool _validateCacheConsistency() { | |
| 1842 int consistencyCheckStart = JavaSystem.nanoTime(); | |
| 1843 List<AnalysisTarget> changedTargets = new List<AnalysisTarget>(); | |
| 1844 List<AnalysisTarget> missingTargets = new List<AnalysisTarget>(); | |
| 1845 MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator(); | |
| 1846 while (iterator.moveNext()) { | |
| 1847 AnalysisTarget target = iterator.key; | |
| 1848 cache.CacheEntry entry = iterator.value; | |
| 1849 if (target is Source) { | |
| 1850 int sourceTime = getModificationStamp(target); | |
| 1851 if (sourceTime != entry.modificationTime) { | |
| 1852 changedTargets.add(target); | |
| 1853 } | |
| 1854 } | |
| 1855 if (entry.exception != null) { | |
| 1856 if (!exists(target)) { | |
| 1857 missingTargets.add(target); | |
| 1858 } | |
| 1859 } | |
| 1860 } | |
| 1861 int count = changedTargets.length; | |
| 1862 for (int i = 0; i < count; i++) { | |
| 1863 _sourceChanged(changedTargets[i]); | |
| 1864 } | |
| 1865 int removalCount = 0; | |
| 1866 for (AnalysisTarget target in missingTargets) { | |
| 1867 if (target is Source && | |
| 1868 getLibrariesContaining(target).isEmpty && | |
| 1869 getLibrariesDependingOn(target).isEmpty) { | |
| 1870 _cache.remove(target); | |
| 1871 removalCount++; | |
| 1872 } | |
| 1873 } | |
| 1874 int consistencyCheckEnd = JavaSystem.nanoTime(); | |
| 1875 if (changedTargets.length > 0 || missingTargets.length > 0) { | |
| 1876 StringBuffer buffer = new StringBuffer(); | |
| 1877 buffer.write("Consistency check took "); | |
| 1878 buffer.write((consistencyCheckEnd - consistencyCheckStart) / 1000000.0); | |
| 1879 buffer.writeln(" ms and found"); | |
| 1880 buffer.write(" "); | |
| 1881 buffer.write(changedTargets.length); | |
| 1882 buffer.writeln(" inconsistent entries"); | |
| 1883 buffer.write(" "); | |
| 1884 buffer.write(missingTargets.length); | |
| 1885 buffer.write(" missing sources ("); | |
| 1886 buffer.write(removalCount); | |
| 1887 buffer.writeln(" removed"); | |
| 1888 for (Source source in missingTargets) { | |
| 1889 buffer.write(" "); | |
| 1890 buffer.writeln(source.fullName); | |
| 1891 } | |
| 1892 _logInformation(buffer.toString()); | |
| 1893 } | |
| 1894 return changedTargets.length > 0; | |
| 1895 } | |
| 1896 } | |
| 1897 | |
| 1898 /** | |
| 1899 * A retention policy used by an analysis context. | |
| 1900 */ | |
| 1901 class ContextRetentionPolicy implements cache.CacheRetentionPolicy { | |
| 1902 /** | |
| 1903 * The context associated with this policy. | |
| 1904 */ | |
| 1905 final AnalysisContextImpl context; | |
| 1906 | |
| 1907 /** | |
| 1908 * Initialize a newly created policy to be associated with the given | |
| 1909 * [context]. | |
| 1910 */ | |
| 1911 ContextRetentionPolicy(this.context); | |
| 1912 | |
| 1913 @override | |
| 1914 RetentionPriority getAstPriority( | |
| 1915 AnalysisTarget target, cache.CacheEntry entry) { | |
| 1916 int priorityCount = context._priorityOrder.length; | |
| 1917 for (int i = 0; i < priorityCount; i++) { | |
| 1918 if (target == context._priorityOrder[i]) { | |
| 1919 return RetentionPriority.HIGH; | |
| 1920 } | |
| 1921 } | |
| 1922 if (_astIsNeeded(entry)) { | |
| 1923 return RetentionPriority.MEDIUM; | |
| 1924 } | |
| 1925 return RetentionPriority.LOW; | |
| 1926 } | |
| 1927 | |
| 1928 bool _astIsNeeded(cache.CacheEntry entry) => | |
| 1929 entry.isInvalid(BUILD_FUNCTION_TYPE_ALIASES_ERRORS) || | |
| 1930 entry.isInvalid(BUILD_LIBRARY_ERRORS) || | |
| 1931 entry.isInvalid(CONSTRUCTORS_ERRORS) || | |
| 1932 entry.isInvalid(HINTS) || | |
| 1933 //entry.isInvalid(LINTS) || | |
| 1934 entry.isInvalid(RESOLVE_REFERENCES_ERRORS) || | |
| 1935 entry.isInvalid(RESOLVE_TYPE_NAMES_ERRORS) || | |
| 1936 entry.isInvalid(VERIFY_ERRORS); | |
| 1937 } | |
| 1938 | |
| 1939 /** | |
| 1940 * An object that manages the partitions that can be shared between analysis | |
| 1941 * contexts. | |
| 1942 */ | |
| 1943 class PartitionManager { | |
| 1944 /** | |
| 1945 * The default cache size for a Dart SDK partition. | |
| 1946 */ | |
| 1947 static int _DEFAULT_SDK_CACHE_SIZE = 256; | |
| 1948 | |
| 1949 /** | |
| 1950 * A table mapping SDK's to the partitions used for those SDK's. | |
| 1951 */ | |
| 1952 HashMap<DartSdk, cache.SdkCachePartition> _sdkPartitions = | |
| 1953 new HashMap<DartSdk, cache.SdkCachePartition>(); | |
| 1954 | |
| 1955 /** | |
| 1956 * Clear any cached data being maintained by this manager. | |
| 1957 */ | |
| 1958 void clearCache() { | |
| 1959 _sdkPartitions.clear(); | |
| 1960 } | |
| 1961 | |
| 1962 /** | |
| 1963 * Return the partition being used for the given [sdk], creating the partition | |
| 1964 * if necessary. | |
| 1965 */ | |
| 1966 cache.SdkCachePartition forSdk(DartSdk sdk) { | |
| 1967 // Call sdk.context now, because when it creates a new | |
| 1968 // InternalAnalysisContext instance, it calls forSdk() again, so creates an | |
| 1969 // SdkCachePartition instance. | |
| 1970 // So, if we initialize context after "partition == null", we end up | |
| 1971 // with two SdkCachePartition instances. | |
| 1972 InternalAnalysisContext sdkContext = sdk.context; | |
| 1973 // Check cache for an existing partition. | |
| 1974 cache.SdkCachePartition partition = _sdkPartitions[sdk]; | |
| 1975 if (partition == null) { | |
| 1976 partition = | |
| 1977 new cache.SdkCachePartition(sdkContext, _DEFAULT_SDK_CACHE_SIZE); | |
| 1978 _sdkPartitions[sdk] = partition; | |
| 1979 } | |
| 1980 return partition; | |
| 1981 } | |
| 1982 } | |
| OLD | NEW |