Issue 24812. Fix for detached CompilationUnitElement(s) after package version switch.
R=brianwilkerson@google.com
BUG= https://github.com/dart-lang/sdk/issues/24812
Review URL: https://codereview.chromium.org/1441013003 .
diff --git a/pkg/analyzer/lib/src/task/dart_work_manager.dart b/pkg/analyzer/lib/src/task/dart_work_manager.dart
index 62a25ea..793d9ce 100644
--- a/pkg/analyzer/lib/src/task/dart_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/dart_work_manager.dart
@@ -88,7 +88,8 @@
analysisCache.onResultInvalidated.listen((InvalidatedResult event) {
if (event.descriptor == LIBRARY_ERRORS_READY) {
CacheEntry entry = event.entry;
- if (entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY) {
+ if (entry.explicitlyAdded &&
+ entry.getValue(SOURCE_KIND) == SourceKind.LIBRARY) {
librarySourceQueue.add(entry.target);
}
}
@@ -392,7 +393,10 @@
unitTargets.add(target);
Source library = target.library;
if (context.exists(library)) {
- librarySourceQueue.add(library);
+ CacheEntry entry = iterator.value;
+ if (entry.explicitlyAdded) {
+ librarySourceQueue.add(library);
+ }
}
}
}
@@ -408,6 +412,8 @@
entry.setState(EXPLICITLY_IMPORTED_LIBRARIES, CacheState.INVALID);
entry.setState(EXPORTED_LIBRARIES, CacheState.INVALID);
entry.setState(INCLUDED_PARTS, CacheState.INVALID);
+ entry.setState(LIBRARY_SPECIFIC_UNITS, CacheState.INVALID);
+ entry.setState(UNITS, CacheState.INVALID);
}
}
}
diff --git a/pkg/analyzer/test/src/context/abstract_context.dart b/pkg/analyzer/test/src/context/abstract_context.dart
index 09c30b2..135fd42 100644
--- a/pkg/analyzer/test/src/context/abstract_context.dart
+++ b/pkg/analyzer/test/src/context/abstract_context.dart
@@ -28,6 +28,9 @@
AnalysisCache analysisCache;
AnalysisDriver analysisDriver;
+ UriResolver sdkResolver;
+ UriResolver resourceResolver;
+
AnalysisTask task;
Map<ResultDescriptor<dynamic>, dynamic> oldOutputs;
Map<ResultDescriptor<dynamic>, dynamic> outputs;
@@ -107,10 +110,10 @@
}
void prepareAnalysisContext([AnalysisOptions options]) {
- sourceFactory = new SourceFactory(<UriResolver>[
- new DartUriResolver(sdk),
- new ResourceUriResolver(resourceProvider)
- ]);
+ sdkResolver = new DartUriResolver(sdk);
+ resourceResolver = new ResourceUriResolver(resourceProvider);
+ sourceFactory =
+ new SourceFactory(<UriResolver>[sdkResolver, resourceResolver]);
context = createAnalysisContext();
if (options != null) {
context.analysisOptions = options;
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index f0d2110..4d68fd3 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -7,6 +7,7 @@
import 'dart:async';
import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/src/cancelable_future.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/context/context.dart';
@@ -34,6 +35,7 @@
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/task/dart.dart';
import 'package:analyzer/src/task/html.dart';
import 'package:analyzer/task/dart.dart';
@@ -1954,6 +1956,60 @@
expect(resolvedUnitUris, contains('file:///test.dart'));
}
+ void test_performAnalysisTask_switchPackageVersion() {
+ // version 1
+ resourceProvider.newFile(
+ '/pkgs/crypto-1/lib/crypto.dart',
+ r'''
+library crypto;
+part 'src/hash_utils.dart';
+''');
+ resourceProvider.newFile(
+ '/pkgs/crypto-1/lib/src/hash_utils.dart',
+ r'''
+part of crypto;
+const _MASK_8 = 0xff;
+''');
+ // version 2
+ resourceProvider.newFile(
+ '/pkgs/crypto-2/lib/crypto.dart',
+ r'''
+library crypto;
+part 'src/hash_utils.dart';
+''');
+ resourceProvider.newFile(
+ '/pkgs/crypto-2/lib/src/hash_utils.dart',
+ r'''
+part of crypto;
+const _MASK_8 = 0xff;
+''');
+ // use version 1
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'crypto': [resourceProvider.getFolder('/pkgs/crypto-1/lib')]
+ })
+ ]);
+ // analyze
+ addSource(
+ "/test.dart",
+ r'''
+import 'package:crypto/crypto.dart';
+''');
+ _analyzeAll_assertFinished();
+ // use version 2
+ context.sourceFactory = new SourceFactory(<UriResolver>[
+ sdkResolver,
+ resourceResolver,
+ new PackageMapUriResolver(resourceProvider, {
+ 'crypto': [resourceProvider.getFolder('/pkgs/crypto-2/lib')]
+ })
+ ]);
+ _analyzeAll_assertFinished();
+ _assertNoExceptions();
+ }
+
void test_resolveCompilationUnit_import_relative() {
Source sourceA =
addSource("/libA.dart", "library libA; import 'libB.dart'; class A{}");
@@ -1993,6 +2049,13 @@
expect(compilationUnit.element, isNotNull);
}
+ void test_resolveCompilationUnit_source() {
+ Source source = addSource("/lib.dart", "library lib;");
+ CompilationUnit compilationUnit =
+ context.resolveCompilationUnit2(source, source);
+ expect(compilationUnit, isNotNull);
+ }
+
// void test_resolveCompilationUnit_sourceChangeDuringResolution() {
// _context = new _AnalysisContext_sourceChangeDuringResolution();
// AnalysisContextFactory.initContextWithCore(_context);
@@ -2004,13 +2067,6 @@
// expect(_context.getLineInfo(source), isNotNull);
// }
- void test_resolveCompilationUnit_source() {
- Source source = addSource("/lib.dart", "library lib;");
- CompilationUnit compilationUnit =
- context.resolveCompilationUnit2(source, source);
- expect(compilationUnit, isNotNull);
- }
-
void test_setAnalysisOptions() {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.cacheSize = 42;
@@ -2263,6 +2319,24 @@
fail("performAnalysisTask failed to terminate after analyzing all sources");
}
+ void _assertNoExceptions() {
+ MapIterator<AnalysisTarget, CacheEntry> iterator = analysisCache.iterator();
+ String exceptionsStr = '';
+ while (iterator.moveNext()) {
+ CaughtException exception = iterator.value.exception;
+ if (exception != null) {
+ AnalysisTarget target = iterator.key;
+ exceptionsStr +=
+ '============= key: $target source: ${target.source}\n';
+ exceptionsStr += exception.toString();
+ exceptionsStr += '\n';
+ }
+ }
+ if (exceptionsStr.isNotEmpty) {
+ fail(exceptionsStr);
+ }
+ }
+
void _changeSource(TestSource source, String contents) {
source.setContents(contents);
ChangeSet changeSet = new ChangeSet();
diff --git a/pkg/analyzer/test/src/task/dart_work_manager_test.dart b/pkg/analyzer/test/src/task/dart_work_manager_test.dart
index 8dd7dbc..a10cfef 100644
--- a/pkg/analyzer/test/src/task/dart_work_manager_test.dart
+++ b/pkg/analyzer/test/src/task/dart_work_manager_test.dart
@@ -64,10 +64,10 @@
void setUp() {
cache = context.analysisCache;
manager = new DartWorkManager(context);
- entry1 = context.getCacheEntry(source1);
- entry2 = context.getCacheEntry(source2);
- entry3 = context.getCacheEntry(source3);
- entry4 = context.getCacheEntry(source4);
+ entry1 = _getOrCreateEntry(source1);
+ entry2 = _getOrCreateEntry(source2);
+ entry3 = _getOrCreateEntry(source3);
+ entry4 = _getOrCreateEntry(source4);
}
void test_applyChange_add() {
@@ -509,6 +509,8 @@
}
void test_onResultInvalidated_scheduleInvalidatedLibraries() {
+ // make source3 implicit
+ entry3.explicitlyAdded = false;
// set SOURCE_KIND
entry1.setValue(SOURCE_KIND, SourceKind.LIBRARY, []);
entry2.setValue(SOURCE_KIND, SourceKind.PART, []);
@@ -519,9 +521,9 @@
// invalidate LIBRARY_ERRORS_READY for source1, schedule it
entry1.setState(LIBRARY_ERRORS_READY, CacheState.INVALID);
expect_librarySourceQueue([source1]);
- // invalidate LIBRARY_ERRORS_READY for source3, schedule it
+ // invalidate LIBRARY_ERRORS_READY for source3, implicit, not scheduled
entry3.setState(LIBRARY_ERRORS_READY, CacheState.INVALID);
- expect_librarySourceQueue([source1, source3]);
+ expect_librarySourceQueue([source1]);
}
void test_onSourceFactoryChanged() {
@@ -532,6 +534,8 @@
entry1.setValue(EXPLICITLY_IMPORTED_LIBRARIES, <Source>[], []);
entry1.setValue(EXPORTED_LIBRARIES, <Source>[], []);
entry1.setValue(INCLUDED_PARTS, <Source>[], []);
+ entry1.setValue(LIBRARY_SPECIFIC_UNITS, <LibrarySpecificUnit>[], []);
+ entry1.setValue(UNITS, <Source>[], []);
// configure LibrarySpecificUnit
LibrarySpecificUnit unitTarget = new LibrarySpecificUnit(source2, source3);
CacheEntry unitEntry = new CacheEntry(unitTarget);
@@ -548,6 +552,8 @@
expect(entry1.getState(EXPLICITLY_IMPORTED_LIBRARIES), CacheState.INVALID);
expect(entry1.getState(EXPORTED_LIBRARIES), CacheState.INVALID);
expect(entry1.getState(INCLUDED_PARTS), CacheState.INVALID);
+ expect(entry1.getState(LIBRARY_SPECIFIC_UNITS), CacheState.INVALID);
+ expect(entry1.getState(UNITS), CacheState.INVALID);
}
void test_resultsComputed_errors_forLibrarySpecificUnit() {
@@ -745,10 +751,11 @@
expect(manager.libraryPartsMap, isEmpty);
}
- CacheEntry _getOrCreateEntry(Source source) {
+ CacheEntry _getOrCreateEntry(Source source, [bool explicit = true]) {
CacheEntry entry = cache.get(source);
if (entry == null) {
entry = new CacheEntry(source);
+ entry.explicitlyAdded = explicit;
cache.put(entry);
}
return entry;