mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:00:09 +00:00
Fix for adding new elements into library cycles.
R=brianwilkerson@google.com BUG= Review URL: https://codereview.chromium.org/2212093002 .
This commit is contained in:
parent
99baa3de32
commit
bc8b32145b
|
@ -5872,17 +5872,6 @@ class LibraryElementImpl extends ElementImpl implements LibraryElement {
|
|||
* cached library cycles in the element model which may have been invalidated.
|
||||
*/
|
||||
void invalidateLibraryCycles() {
|
||||
if (_libraryCycle == null) {
|
||||
// We have already invalidated this node, or we have never computed
|
||||
// library cycle information for it. In the former case, we're done. In
|
||||
// the latter case, this node cannot be reachable from any node for which
|
||||
// we have computed library cycle information. Therefore, any edges added
|
||||
// or deleted in the update causing this invalidation can only be edges to
|
||||
// nodes which either have no library cycle information (and hence do not
|
||||
// need invalidation), or which do not reach this node by any path.
|
||||
// In either case, no further invalidation is needed.
|
||||
return;
|
||||
}
|
||||
// If we have pre-computed library cycle information, then we must
|
||||
// invalidate the information both on this element, and on certain
|
||||
// other elements. Edges originating at this node may have been
|
||||
|
|
|
@ -487,6 +487,43 @@ class B {}
|
|||
expect(context.getErrors(a).errors, hasLength(0));
|
||||
}
|
||||
|
||||
void test_applyChanges_addNewImport_invalidateLibraryCycle() {
|
||||
context.analysisOptions =
|
||||
new AnalysisOptionsImpl.from(context.analysisOptions)
|
||||
..strongMode = true;
|
||||
Source embedder = addSource(
|
||||
'/a.dart',
|
||||
r'''
|
||||
library a;
|
||||
import 'b.dart';
|
||||
//import 'c.dart';
|
||||
''');
|
||||
addSource(
|
||||
'/b.dart',
|
||||
r'''
|
||||
library b;
|
||||
import 'a.dart';
|
||||
''');
|
||||
addSource(
|
||||
'/c.dart',
|
||||
r'''
|
||||
library c;
|
||||
import 'b.dart';
|
||||
''');
|
||||
_performPendingAnalysisTasks();
|
||||
// Add a new import into a.dart, this should invalidate its library cycle.
|
||||
// If it doesn't, we will get a task cycle exception.
|
||||
context.setContents(
|
||||
embedder,
|
||||
r'''
|
||||
library a;
|
||||
import 'b.dart';
|
||||
import 'c.dart';
|
||||
''');
|
||||
_performPendingAnalysisTasks();
|
||||
expect(context.getCacheEntry(embedder).exception, isNull);
|
||||
}
|
||||
|
||||
void test_cacheConsistencyValidator_computed_deleted() {
|
||||
CacheConsistencyValidator validator = context.cacheConsistencyValidator;
|
||||
var stat = PerformanceStatistics.cacheConsistencyValidationStatistics;
|
||||
|
|
|
@ -1556,113 +1556,143 @@ class ComputeLibraryCycleTaskTest extends _AbstractDartTaskTest {
|
|||
|
||||
void test_library_cycle_incremental() {
|
||||
enableStrongMode();
|
||||
Source lib1Source = newSource(
|
||||
'/my_lib1.dart',
|
||||
Source a = newSource(
|
||||
'/a.dart',
|
||||
'''
|
||||
library my_lib1;
|
||||
library a;
|
||||
''');
|
||||
Source lib2Source = newSource(
|
||||
'/my_lib2.dart',
|
||||
Source b = newSource(
|
||||
'/b.dart',
|
||||
'''
|
||||
library my_lib2;
|
||||
import 'my_lib1.dart';
|
||||
library b;
|
||||
import 'a.dart';
|
||||
''');
|
||||
Source lib3Source = newSource(
|
||||
'/my_lib3.dart',
|
||||
Source c = newSource(
|
||||
'/c.dart',
|
||||
'''
|
||||
library my_lib3;
|
||||
import 'my_lib2.dart';
|
||||
library c;
|
||||
import 'b.dart';
|
||||
''');
|
||||
|
||||
computeResult(lib1Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(1));
|
||||
computeResult(lib2Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(1));
|
||||
computeResult(lib3Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(1));
|
||||
_assertLibraryCycle(a, [a]);
|
||||
_assertLibraryCycle(b, [b]);
|
||||
_assertLibraryCycle(c, [c]);
|
||||
|
||||
// create a cycle
|
||||
// Create a cycle.
|
||||
context.setContents(
|
||||
lib1Source,
|
||||
a,
|
||||
'''
|
||||
library my_lib1;
|
||||
import 'my_lib3.dart';
|
||||
library a;
|
||||
import 'c.dart';
|
||||
''');
|
||||
_expectInvalid(lib1Source);
|
||||
_expectInvalid(lib2Source);
|
||||
_expectInvalid(lib3Source);
|
||||
_expectInvalid(a);
|
||||
_expectInvalid(b);
|
||||
_expectInvalid(c);
|
||||
|
||||
computeResult(lib1Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(3));
|
||||
computeResult(lib2Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(3));
|
||||
computeResult(lib3Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(3));
|
||||
_assertLibraryCycle(a, [a, b, c]);
|
||||
_assertLibraryCycle(b, [a, b, c]);
|
||||
_assertLibraryCycle(c, [a, b, c]);
|
||||
|
||||
// break the cycle again
|
||||
// Break the cycle again.
|
||||
context.setContents(
|
||||
lib1Source,
|
||||
a,
|
||||
'''
|
||||
library my_lib1;
|
||||
library a;
|
||||
''');
|
||||
_expectInvalid(lib1Source);
|
||||
_expectInvalid(lib2Source);
|
||||
_expectInvalid(lib3Source);
|
||||
_expectInvalid(a);
|
||||
_expectInvalid(b);
|
||||
_expectInvalid(c);
|
||||
|
||||
computeResult(lib1Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(1));
|
||||
computeResult(lib2Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(1));
|
||||
computeResult(lib3Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(1));
|
||||
_assertLibraryCycle(a, [a]);
|
||||
_assertLibraryCycle(b, [b]);
|
||||
_assertLibraryCycle(c, [c]);
|
||||
}
|
||||
|
||||
void test_library_cycle_incremental_partial() {
|
||||
enableStrongMode();
|
||||
Source lib1Source = newSource(
|
||||
'/my_lib1.dart',
|
||||
'''
|
||||
library my_lib1;
|
||||
Source a = newSource(
|
||||
'/a.dart',
|
||||
r'''
|
||||
library a;
|
||||
''');
|
||||
Source lib2Source = newSource(
|
||||
'/my_lib2.dart',
|
||||
'''
|
||||
library my_lib2;
|
||||
import 'my_lib1.dart';
|
||||
Source b = newSource(
|
||||
'/b.dart',
|
||||
r'''
|
||||
library b;
|
||||
import 'a.dart';
|
||||
''');
|
||||
Source lib3Source = newSource(
|
||||
'/my_lib3.dart',
|
||||
'''
|
||||
library my_lib3;
|
||||
import 'my_lib2.dart';
|
||||
Source c = newSource(
|
||||
'/c.dart',
|
||||
r'''
|
||||
library c;
|
||||
import 'b.dart';
|
||||
''');
|
||||
|
||||
computeResult(lib1Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(1));
|
||||
computeResult(lib2Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(1));
|
||||
// lib3 is not reachable, so we have not yet computed its library
|
||||
// cycles
|
||||
_assertLibraryCycle(a, [a]);
|
||||
_assertLibraryCycle(b, [b]);
|
||||
// 'c' is not reachable, so we have not yet computed its library cycles.
|
||||
|
||||
// complete the cycle, via lib3
|
||||
// Complete the cycle, via 'c'.
|
||||
context.setContents(
|
||||
lib1Source,
|
||||
'''
|
||||
library my_lib1;
|
||||
import 'my_lib3.dart';
|
||||
a,
|
||||
r'''
|
||||
library a;
|
||||
import 'c.dart';
|
||||
''');
|
||||
_expectInvalid(lib1Source);
|
||||
_expectInvalid(lib2Source);
|
||||
_expectInvalid(lib3Source);
|
||||
_expectInvalid(a);
|
||||
_expectInvalid(b);
|
||||
_expectInvalid(c);
|
||||
|
||||
// Ensure that invalidation correctly invalidated everything reachable
|
||||
// through lib3
|
||||
computeResult(lib1Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(3));
|
||||
computeResult(lib2Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(3));
|
||||
computeResult(lib3Source, LIBRARY_CYCLE);
|
||||
expect(outputs[LIBRARY_CYCLE], hasLength(3));
|
||||
// Ensure that everything reachable through 'c' was invalidated,
|
||||
// and recomputed to include all three sources.
|
||||
_assertLibraryCycle(a, [a, b, c]);
|
||||
_assertLibraryCycle(b, [a, b, c]);
|
||||
_assertLibraryCycle(c, [a, b, c]);
|
||||
}
|
||||
|
||||
void test_library_cycle_incremental_partial2() {
|
||||
enableStrongMode();
|
||||
Source a = newSource(
|
||||
'/a.dart',
|
||||
r'''
|
||||
library a;
|
||||
import 'b.dart';
|
||||
''');
|
||||
Source b = newSource(
|
||||
'/b.dart',
|
||||
r'''
|
||||
library b;
|
||||
import 'a.dart';
|
||||
''');
|
||||
Source c = newSource(
|
||||
'/c.dart',
|
||||
r'''
|
||||
library c;
|
||||
import 'b.dart';
|
||||
''');
|
||||
|
||||
_assertLibraryCycle(a, [a, b]);
|
||||
_assertLibraryCycle(b, [a, b]);
|
||||
_assertLibraryCycle(c, [c]);
|
||||
|
||||
// Include 'c' into the cycle.
|
||||
context.setContents(
|
||||
a,
|
||||
r'''
|
||||
library a;
|
||||
import 'b.dart';
|
||||
import 'c.dart';
|
||||
''');
|
||||
_expectInvalid(a);
|
||||
_expectInvalid(b);
|
||||
_expectInvalid(c);
|
||||
|
||||
// Start processing with 'b', so that when we resolve 'b' directives,
|
||||
// and invalidate library cycles, the 'a' directives are not resolved yet,
|
||||
// so we don't know that the cycle must include 'c'.
|
||||
_assertLibraryCycle(b, [a, b, c]);
|
||||
_assertLibraryCycle(a, [a, b, c]);
|
||||
_assertLibraryCycle(c, [a, b, c]);
|
||||
}
|
||||
|
||||
void test_library_cycle_linear() {
|
||||
|
@ -1974,6 +2004,12 @@ import 'dart:core';
|
|||
expect(dep5, hasLength(5)); // dart:core, a.dart, aa.dart, ab.dart, b.dart
|
||||
}
|
||||
|
||||
void _assertLibraryCycle(Source source, List<Source> expected) {
|
||||
computeResult(source, LIBRARY_CYCLE);
|
||||
List<LibraryElement> cycle = outputs[LIBRARY_CYCLE] as List<LibraryElement>;
|
||||
expect(cycle.map((e) => e.source), unorderedEquals(expected));
|
||||
}
|
||||
|
||||
void _expectInvalid(Source librarySource) {
|
||||
CacheEntry entry = context.getCacheEntry(librarySource);
|
||||
expect(entry.getState(LIBRARY_CYCLE), CacheState.INVALID);
|
||||
|
|
Loading…
Reference in a new issue