Skip to content

Commit 89a45a9

Browse files
committed
AnalysisDriverModel: update the directive graph on newly-discovered inputs.
1 parent 5b59745 commit 89a45a9

File tree

2 files changed

+69
-31
lines changed

2 files changed

+69
-31
lines changed

build_resolvers/lib/src/analysis_driver_model.dart

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -112,21 +112,10 @@ class AnalysisDriverModel {
112112

113113
// If requested, find transitive imports.
114114
if (transitive) {
115-
await _graph.load(buildStep, entryPoints);
115+
final previouslyMissingFiles = await _graph.load(buildStep, entryPoints);
116+
_syncedOntoResourceProvider.removeAll(previouslyMissingFiles);
116117
idsToSyncOntoResourceProvider = _graph.nodes.keys.toList();
117118
inputIds = _graph.inputsFor(entryPoints);
118-
119-
// Check for inputs that were missing when the directive graph was read
120-
// but have since been written by another build action.
121-
for (final id in inputIds
122-
.where((id) => !id.path.endsWith(_transitiveDigestExtension))) {
123-
if (_graph.nodes[id]!.isMissing) {
124-
if (await buildStep.canRead(id)) {
125-
idsToSyncOntoResourceProvider.add(id);
126-
_syncedOntoResourceProvider.remove(id);
127-
}
128-
}
129-
}
130119
}
131120

132121
// Notify [buildStep] of its inputs.
@@ -203,33 +192,50 @@ class _Graph {
203192
final Map<AssetId, _Node> nodes = {};
204193

205194
/// Walks the import graph from [ids] loading into [nodes].
206-
Future<void> load(AssetReader reader, Iterable<AssetId> ids) async {
195+
///
196+
/// Checks files that are in the graph as missing to determine whether they
197+
/// are now available.
198+
///
199+
/// Returns the set of files that were in the graph as missing and have now
200+
/// been loaded.
201+
Future<Set<AssetId>> load(AssetReader reader, Iterable<AssetId> ids) async {
207202
// TODO(davidmorgan): check if List is faster.
208203
final nextIds = Queue.of(ids);
204+
final processed = <AssetId>{};
205+
final previouslyMissingFiles = <AssetId>{};
209206
while (nextIds.isNotEmpty) {
210207
final nextId = nextIds.removeFirst();
211208

212-
// Skip if already seen.
213-
if (nodes.containsKey(nextId)) continue;
209+
if (!processed.add(nextId)) continue;
214210

215-
final hasTransitiveDigestAsset =
216-
await reader.canRead(nextId.addExtension(_transitiveDigestExtension));
217-
218-
// Skip if not readable.
219-
if (!await reader.canRead(nextId)) {
220-
nodes[nextId] = _Node.missing(
221-
id: nextId, hasTransitiveDigestAsset: hasTransitiveDigestAsset);
222-
continue;
211+
// Read nodes not yet loaded or that were missing when loaded.
212+
var node = nodes[nextId];
213+
if (node == null || node.isMissing) {
214+
if (await reader.canRead(nextId)) {
215+
// If it was missing when loaded, record that.
216+
if (node != null && node.isMissing) {
217+
previouslyMissingFiles.add(nextId);
218+
}
219+
// Load the node.
220+
final hasTransitiveDigestAsset = await reader
221+
.canRead(nextId.addExtension(_transitiveDigestExtension));
222+
final content = await reader.readAsString(nextId);
223+
final deps = _parseDependencies(content, nextId);
224+
node = _Node(
225+
id: nextId,
226+
deps: deps,
227+
hasTransitiveDigestAsset: hasTransitiveDigestAsset);
228+
} else {
229+
node ??= _Node.missing(id: nextId, hasTransitiveDigestAsset: false);
230+
}
231+
nodes[nextId] = node;
223232
}
224233

225-
final content = await reader.readAsString(nextId);
226-
final deps = _parseDependencies(content, nextId);
227-
nodes[nextId] = _Node(
228-
id: nextId,
229-
deps: deps,
230-
hasTransitiveDigestAsset: hasTransitiveDigestAsset);
231-
nextIds.addAll(deps.where((id) => !nodes.containsKey(id)));
234+
// Continue to deps even for already-loaded nodes, to check missing files.
235+
nextIds.addAll(node.deps.where((id) => !processed.contains(id)));
232236
}
237+
238+
return previouslyMissingFiles;
233239
}
234240

235241
void clear() {

build_resolvers/test/resolver_test.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,38 @@ void runTests(ResolversFactory resolversFactory) {
236236
}, resolvers: resolvers);
237237
});
238238

239+
test('updates graph when a missing file appears during build', () async {
240+
var resolvers = createResolvers();
241+
var sources = {
242+
'a|web/main.dart': '''
243+
import 'b.dart';
244+
245+
class A implements C {}
246+
''',
247+
'a|web/b.dart': '''
248+
export 'c.dart';
249+
''',
250+
'a|web/c.dart': '''
251+
class C {}
252+
''',
253+
};
254+
var sourcesWithoutB = Map.of(sources)..remove('a|web/b.dart');
255+
await resolveSources(sourcesWithoutB, (resolver) async {
256+
var lib = await resolver.libraryFor(entryPoint);
257+
var clazz = lib.getClass('A');
258+
expect(clazz, isNotNull);
259+
expect(clazz!.interfaces, isEmpty);
260+
}, resolvers: resolvers);
261+
262+
await resolveSources(sources, (resolver) async {
263+
var lib = await resolver.libraryFor(entryPoint);
264+
var clazz = lib.getClass('A');
265+
expect(clazz, isNotNull);
266+
expect(clazz!.interfaces, hasLength(1));
267+
expect(clazz.interfaces.first.getDisplayString(), 'C');
268+
}, resolvers: resolvers);
269+
});
270+
239271
test('should still crawl transitively after a call to isLibrary', () {
240272
return resolveSources({
241273
'a|web/main.dart': '''

0 commit comments

Comments
 (0)