Skip to content

Commit 85a7aff

Browse files
committed
Record information about parts of dependent libraries in summaries.
This information will be necessary in order to determine whether a summary needs to be re-linked, since a change to a part of library A may affect any other library that depends on library A, even if the defining compilation unit of library A is unaffected. [email protected] Review URL: https://codereview.chromium.org/1574113002 .
1 parent a5ba7a7 commit 85a7aff

File tree

5 files changed

+116
-17
lines changed

5 files changed

+116
-17
lines changed

pkg/analyzer/lib/src/summary/format.dart

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,35 +45,57 @@ class PrelinkedDependencyBuilder {
4545
bool _finished = false;
4646

4747
String _uri;
48+
List<String> _parts;
4849

4950
PrelinkedDependencyBuilder();
5051

5152
/**
52-
* The relative URI used to import one library from the other.
53+
* The relative URI of the dependent library. This URI is relative to the
54+
* importing library, even if there are intervening `export` declarations.
55+
* So, for example, if `a.dart` imports `b/c.dart` and `b/c.dart` exports
56+
* `d/e.dart`, the URI listed for `a.dart`'s dependency on `e.dart` will be
57+
* `b/d/e.dart`.
5358
*/
5459
void set uri(String _value) {
5560
assert(!_finished);
5661
_uri = _value;
5762
}
5863

64+
/**
65+
* URI for the compilation units listed in the library's `part` declarations.
66+
* These URIs are relative to the importing library.
67+
*/
68+
void set parts(List<String> _value) {
69+
assert(!_finished);
70+
_parts = _value;
71+
}
72+
5973
fb.Offset finish(fb.Builder fbBuilder) {
6074
assert(!_finished);
6175
_finished = true;
6276
fb.Offset offset_uri;
77+
fb.Offset offset_parts;
6378
if (_uri != null) {
6479
offset_uri = fbBuilder.writeString(_uri);
6580
}
81+
if (!(_parts == null || _parts.isEmpty)) {
82+
offset_parts = fbBuilder.writeList(_parts.map((b) => fbBuilder.writeString(b)).toList());
83+
}
6684
fbBuilder.startTable();
6785
if (offset_uri != null) {
6886
fbBuilder.addOffset(0, offset_uri);
6987
}
88+
if (offset_parts != null) {
89+
fbBuilder.addOffset(1, offset_parts);
90+
}
7091
return fbBuilder.endTable();
7192
}
7293
}
7394

74-
PrelinkedDependencyBuilder encodePrelinkedDependency({String uri}) {
95+
PrelinkedDependencyBuilder encodePrelinkedDependency({String uri, List<String> parts}) {
7596
PrelinkedDependencyBuilder builder = new PrelinkedDependencyBuilder();
7697
builder.uri = uri;
98+
builder.parts = parts;
7799
return builder;
78100
}
79101

@@ -84,9 +106,19 @@ PrelinkedDependencyBuilder encodePrelinkedDependency({String uri}) {
84106
abstract class PrelinkedDependency extends base.SummaryClass {
85107

86108
/**
87-
* The relative URI used to import one library from the other.
109+
* The relative URI of the dependent library. This URI is relative to the
110+
* importing library, even if there are intervening `export` declarations.
111+
* So, for example, if `a.dart` imports `b/c.dart` and `b/c.dart` exports
112+
* `d/e.dart`, the URI listed for `a.dart`'s dependency on `e.dart` will be
113+
* `b/d/e.dart`.
88114
*/
89115
String get uri;
116+
117+
/**
118+
* URI for the compilation units listed in the library's `part` declarations.
119+
* These URIs are relative to the importing library.
120+
*/
121+
List<String> get parts;
90122
}
91123

92124
class _PrelinkedDependencyReader extends fb.TableReader<_PrelinkedDependencyImpl> {
@@ -102,17 +134,25 @@ class _PrelinkedDependencyImpl implements PrelinkedDependency {
102134
_PrelinkedDependencyImpl(this._bp);
103135

104136
String _uri;
137+
List<String> _parts;
105138

106139
@override
107140
Map<String, Object> toMap() => {
108141
"uri": uri,
142+
"parts": parts,
109143
};
110144

111145
@override
112146
String get uri {
113147
_uri ??= const fb.StringReader().vTableGet(_bp, 0, '');
114148
return _uri;
115149
}
150+
151+
@override
152+
List<String> get parts {
153+
_parts ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 1, const <String>[]);
154+
return _parts;
155+
}
116156
}
117157

118158
class PrelinkedLibraryBuilder {

pkg/analyzer/lib/src/summary/prelink.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,13 @@ class _Prelinker {
156156
assert(dependencies.length == dependencyToPublicNamespace.length);
157157
int dependency = dependencies.length;
158158
uriToDependency[relativeUri] = dependency;
159-
dependencies.add(encodePrelinkedDependency(uri: relativeUri));
159+
List<String> unitUris = getUnitUris(relativeUri);
160+
PrelinkedDependencyBuilder prelinkedDependency =
161+
encodePrelinkedDependency(uri: relativeUri, parts: unitUris.sublist(1));
162+
dependencies.add(prelinkedDependency);
160163

161164
Map<String, _Meaning> aggregated = <String, _Meaning>{};
162165

163-
List<String> unitUris = getUnitUris(relativeUri);
164166
for (int unitNum = 0; unitNum < unitUris.length; unitNum++) {
165167
String unitUri = unitUris[unitNum];
166168
UnlinkedPublicNamespace importedNamespace = getImportCached(unitUri);

pkg/analyzer/lib/src/summary/summarize_elements.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,11 @@ class _LibrarySerializer {
390390
int serializeDependency(LibraryElement dependentLibrary) {
391391
return dependencyMap.putIfAbsent(dependentLibrary, () {
392392
int index = dependencies.length;
393+
List<String> parts = dependentLibrary.parts
394+
.map((CompilationUnitElement e) => e.source.uri.toString())
395+
.toList();
393396
dependencies.add(encodePrelinkedDependency(
394-
uri: dependentLibrary.source.uri.toString()));
397+
uri: dependentLibrary.source.uri.toString(), parts: parts));
395398
return index;
396399
});
397400
}

pkg/analyzer/test/src/summary/summary_test.dart

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,9 @@ class PrelinkerTest extends SummarizeElementsTest {
112112
summarize_elements.serializeLibrary(
113113
library, analysisContext.typeProvider);
114114
for (int i = 0; i < serializedLibrary.unlinkedUnits.length; i++) {
115-
uriToNamespace[serializedLibrary.unitUris[i]] =
116-
new UnlinkedUnit.fromBuffer(
117-
serializedLibrary.unlinkedUnits[i].toBuffer())
118-
.publicNamespace;
115+
uriToNamespace[
116+
serializedLibrary.unitUris[i]] = new UnlinkedUnit.fromBuffer(
117+
serializedLibrary.unlinkedUnits[i].toBuffer()).publicNamespace;
119118
}
120119
}
121120
return uriToNamespace;
@@ -370,6 +369,21 @@ abstract class SummaryTest {
370369
expect(prelinked.dependencies[dependency].uri, relativeUri);
371370
}
372371

372+
/**
373+
* Verify that the given [dependency] lists the given [absoluteUris] or
374+
* [relativeUris] as its parts.
375+
*/
376+
void checkDependencyParts(PrelinkedDependency dependency,
377+
List<String> absoluteUris, List<String> relativeUris) {
378+
if (expectAbsoluteUrisInDependencies) {
379+
// The element model doesn't (yet) store enough information to recover
380+
// relative URIs, so we have to use the absolute URI.
381+
// TODO(paulberry): fix this.
382+
relativeUris = absoluteUris;
383+
}
384+
expect(dependency.parts, relativeUris);
385+
}
386+
373387
/**
374388
* Check that the given [documentationComment] matches the first
375389
* Javadoc-style comment found in [text].
@@ -403,8 +417,11 @@ abstract class SummaryTest {
403417
/**
404418
* Verify that the dependency table contains an entry for a file reachable
405419
* via the given [absoluteUri] and [relativeUri].
420+
*
421+
* The [PrelinkedDependency] is returned.
406422
*/
407-
void checkHasDependency(String absoluteUri, String relativeUri) {
423+
PrelinkedDependency checkHasDependency(
424+
String absoluteUri, String relativeUri) {
408425
if (expectAbsoluteUrisInDependencies) {
409426
// The element model doesn't (yet) store enough information to recover
410427
// relative URIs, so we have to use the absolute URI.
@@ -414,11 +431,12 @@ abstract class SummaryTest {
414431
List<String> found = <String>[];
415432
for (PrelinkedDependency dep in prelinked.dependencies) {
416433
if (dep.uri == relativeUri) {
417-
return;
434+
return dep;
418435
}
419436
found.add(dep.uri);
420437
}
421438
fail('Did not find dependency $relativeUri. Found: $found');
439+
return null;
422440
}
423441

424442
/**
@@ -786,8 +804,7 @@ b.C c4;''');
786804
UnlinkedTypeRef serializeTypeText(String text,
787805
{String otherDeclarations: '', bool allowErrors: false}) {
788806
return serializeVariableText('$otherDeclarations\n$text v;',
789-
allowErrors: allowErrors)
790-
.type;
807+
allowErrors: allowErrors).type;
791808
}
792809

793810
/**
@@ -1441,6 +1458,8 @@ class C {
14411458
test_dependencies_export_none() {
14421459
// Exports are not listed as dependencies since no change to the exported
14431460
// file can change the summary of the exporting file.
1461+
// TODO(paulberry): this needs to change since the element model for a
1462+
// library includes its export namespace.
14441463
addNamedSource('/a.dart', 'library a; export "b.dart";');
14451464
addNamedSource('/b.dart', 'library b;');
14461465
serializeLibraryText('export "a.dart";');
@@ -1521,6 +1540,32 @@ class C {
15211540
checkLacksDependency(absUri('/b.dart'), 'b.dart');
15221541
}
15231542

1543+
test_dependencies_parts() {
1544+
addNamedSource(
1545+
'/a.dart', 'library a; part "b.dart"; part "c.dart"; class A {}');
1546+
addNamedSource('/b.dart', 'part of a;');
1547+
addNamedSource('/c.dart', 'part of a;');
1548+
serializeLibraryText('import "a.dart"; A a;');
1549+
PrelinkedDependency dep = checkHasDependency(absUri('/a.dart'), 'a.dart');
1550+
checkDependencyParts(
1551+
dep, [absUri('/b.dart'), absUri('/c.dart')], ['b.dart', 'c.dart']);
1552+
}
1553+
1554+
test_dependencies_parts_relative_to_importing_library() {
1555+
addNamedSource('/a/b.dart', 'export "c/d.dart";');
1556+
addNamedSource('/a/c/d.dart',
1557+
'library d; part "e/f.dart"; part "g/h.dart"; class D {}');
1558+
addNamedSource('/a/c/e/f.dart', 'part of d;');
1559+
addNamedSource('/a/c/g/h.dart', 'part of d;');
1560+
serializeLibraryText('import "a/b.dart"; D d;');
1561+
PrelinkedDependency dep =
1562+
checkHasDependency(absUri('/a/c/d.dart'), 'a/c/d.dart');
1563+
checkDependencyParts(
1564+
dep,
1565+
[absUri('/a/c/e/f.dart'), absUri('/a/c/g/h.dart')],
1566+
['a/c/e/f.dart', 'a/c/g/h.dart']);
1567+
}
1568+
15241569
test_elements_in_part() {
15251570
addNamedSource(
15261571
'/part1.dart',
@@ -1812,8 +1857,7 @@ enum E { v }''';
18121857

18131858
test_executable_operator_index_set() {
18141859
UnlinkedExecutable executable = serializeClassText(
1815-
'class C { void operator[]=(int i, bool v) => null; }')
1816-
.executables[0];
1860+
'class C { void operator[]=(int i, bool v) => null; }').executables[0];
18171861
expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
18181862
expect(executable.name, '[]=');
18191863
expect(executable.hasImplicitReturnType, false);

pkg/analyzer/tool/summary/idl.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,19 @@ const topLevel = null;
6868
*/
6969
class PrelinkedDependency {
7070
/**
71-
* The relative URI used to import one library from the other.
71+
* The relative URI of the dependent library. This URI is relative to the
72+
* importing library, even if there are intervening `export` declarations.
73+
* So, for example, if `a.dart` imports `b/c.dart` and `b/c.dart` exports
74+
* `d/e.dart`, the URI listed for `a.dart`'s dependency on `e.dart` will be
75+
* `b/d/e.dart`.
7276
*/
7377
String uri;
78+
79+
/**
80+
* URI for the compilation units listed in the library's `part` declarations.
81+
* These URIs are relative to the importing library.
82+
*/
83+
List<String> parts;
7484
}
7585

7686
/**

0 commit comments

Comments
 (0)