From 6f67abeaaa046e18bcb627cde4c37c2da49eff20 Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Tue, 1 Dec 2015 07:55:27 -0800 Subject: [PATCH] Clean source maps during partition dispose. This might fix the following exception: Dart analysis server, SDK version 1.14.0-edge.e3457758ed7e2b24263bcbd9831cd764ce9fd110, server version 1.12.0, FATAL error: Failed to perform operation: Instance of 'PerformAnalysisOperation' The null object does not have a getter 'modificationTime'. NoSuchMethodError: method not found: 'modificationTime' Receiver: null Arguments: [] R=brianwilkerson@google.com BUG= Review URL: https://codereview.chromium.org/1480393004 . --- pkg/analyzer/lib/src/context/cache.dart | 61 ++++++++----------- pkg/analyzer/test/src/context/cache_test.dart | 21 ++++++- 2 files changed, 47 insertions(+), 35 deletions(-) diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart index e23f8f6effd..2b81cdd06c2 100644 --- a/pkg/analyzer/lib/src/context/cache.dart +++ b/pkg/analyzer/lib/src/context/cache.dart @@ -66,7 +66,7 @@ class AnalysisCache { */ Iterable get sources { return _partitions - .map((CachePartition partition) => partition._sources) + .map((CachePartition partition) => partition.sources) .expand((Iterable sources) => sources); } @@ -191,7 +191,7 @@ class AnalysisCache { >[]; for (CachePartition partition in _partitions) { if (context == null || partition.context == context) { - maps.add(partition.map); + maps.add(partition.entryMap); } } return new MultipleMapIterator(maps); @@ -585,7 +585,7 @@ class CacheEntry { _invalidateDependentResults(id, thisData, delta, level + 1); // If empty and not explicitly added, remove the entry altogether. if (_resultMap.isEmpty && !explicitlyAdded) { - _partition._targetMap.remove(target); + _partition.entryMap.remove(target); _partition._removeIfSource(target); } // Notify controller. @@ -858,18 +858,18 @@ abstract class CachePartition { * A table mapping the targets belonging to this partition to the information * known about those targets. */ - HashMap _targetMap = + final HashMap entryMap = new HashMap(); /** * A set of the [Source] targets. */ - final HashSet _sources = new HashSet(); + final HashSet sources = new HashSet(); /** * A table mapping full paths to lists of [Source]s with these full paths. */ - final Map> _pathToSources = >{}; + final Map> pathToSource = >{}; /** * Initialize a newly created cache partition, belonging to the given @@ -877,36 +877,29 @@ abstract class CachePartition { */ CachePartition(this.context); - /** - * Return a table mapping the targets known to the context to the information - * known about the target. - * - * Note: This method is only visible for use by [AnalysisCache] and - * should not be used for any other purpose. - */ - Map get map => _targetMap; - /** * Notifies the partition that the client is going to stop using it. */ void dispose() { - for (CacheEntry entry in _targetMap.values) { + for (CacheEntry entry in entryMap.values) { entry.dispose(); } - _targetMap.clear(); + entryMap.clear(); + sources.clear(); + pathToSource.clear(); } /** * Return the entry associated with the given [target]. */ - CacheEntry get(AnalysisTarget target) => _targetMap[target]; + CacheEntry get(AnalysisTarget target) => entryMap[target]; /** * Return [Source]s whose full path is equal to the given [path]. * Maybe empty, but not `null`. */ List getSourcesWithFullName(String path) { - List sources = _pathToSources[path]; + List sources = pathToSource[path]; return sources != null ? sources : Source.EMPTY_LIST; } @@ -920,7 +913,7 @@ abstract class CachePartition { * cache entries. */ MapIterator iterator() => - new SingleMapIterator(_targetMap); + new SingleMapIterator(entryMap); /** * Puts the given [entry] into the partition. @@ -933,7 +926,7 @@ abstract class CachePartition { } entry._partition = this; entry.fixExceptionState(); - _targetMap[target] = entry; + entryMap[target] = entry; _addIfSource(target); } @@ -946,7 +939,7 @@ abstract class CachePartition { for (CacheFlushManager flushManager in _flushManagerMap.values) { flushManager.targetRemoved(target); } - CacheEntry entry = _targetMap.remove(target); + CacheEntry entry = entryMap.remove(target); if (entry != null) { entry._invalidateAll(); } @@ -985,16 +978,16 @@ abstract class CachePartition { /** * Return the number of targets that are mapped to cache entries. */ - int size() => _targetMap.length; + int size() => entryMap.length; /** - * If the given [target] is a [Source], adds it to [_sources]. + * If the given [target] is a [Source], adds it to [sources]. */ void _addIfSource(AnalysisTarget target) { if (target is Source) { - _sources.add(target); + sources.add(target); String fullName = target.fullName; - _pathToSources.putIfAbsent(fullName, () => []).add(target); + pathToSource.putIfAbsent(fullName, () => []).add(target); } } @@ -1024,17 +1017,17 @@ abstract class CachePartition { } /** - * If the given [target] is a [Source], remove it from the list of [_sources]. + * If the given [target] is a [Source], remove it from the list of [sources]. */ void _removeIfSource(AnalysisTarget target) { if (target is Source) { - _sources.remove(target); - String fullName = target.fullName; - List sources = _pathToSources[fullName]; - if (sources != null) { - sources.remove(target); - if (sources.isEmpty) { - _pathToSources.remove(fullName); + sources.remove(target); + String path = target.fullName; + List pathSources = pathToSource[path]; + if (pathSources != null) { + pathSources.remove(target); + if (pathSources.isEmpty) { + pathToSource.remove(path); } } } diff --git a/pkg/analyzer/test/src/context/cache_test.dart b/pkg/analyzer/test/src/context/cache_test.dart index 75c156a69de..0962474c816 100644 --- a/pkg/analyzer/test/src/context/cache_test.dart +++ b/pkg/analyzer/test/src/context/cache_test.dart @@ -961,12 +961,31 @@ abstract class CachePartitionTest extends EngineTestCase { expect(createPartition(), isNotNull); } + void test_dispose() { + CachePartition partition = createPartition(); + Source source1 = new TestSource('/1.dart'); + Source source2 = new TestSource('/2.dart'); + CacheEntry entry1 = new CacheEntry(source1); + CacheEntry entry2 = new CacheEntry(source2); + // add two sources + partition.put(entry1); + partition.put(entry2); + expect(partition.entryMap, hasLength(2)); + expect(partition.pathToSource, hasLength(2)); + expect(partition.sources, unorderedEquals([source1, source2])); + // dispose, no sources + partition.dispose(); + expect(partition.entryMap, isEmpty); + expect(partition.pathToSource, isEmpty); + expect(partition.sources, isEmpty); + } + void test_entrySet() { CachePartition partition = createPartition(); AnalysisTarget target = new TestSource(); CacheEntry entry = new CacheEntry(target); partition.put(entry); - Map entryMap = partition.map; + Map entryMap = partition.entryMap; expect(entryMap, hasLength(1)); AnalysisTarget entryKey = entryMap.keys.first; expect(entryKey, target);