Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(698)

Side by Side Diff: lib/src/dependency_graph.dart

Issue 983553002: Allow changing a file from a part to a library. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/src/codegen/html_codegen.dart ('k') | test/dependency_graph_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /// Tracks the shape of the import/export graph and dependencies between files. 5 /// Tracks the shape of the import/export graph and dependencies between files.
6 library dev_compiler.src.dependency_graph; 6 library dev_compiler.src.dependency_graph;
7 7
8 import 'dart:collection' show HashSet; 8 import 'dart:collection' show HashSet;
9 9
10 import 'package:analyzer/analyzer.dart' show parseDirectives; 10 import 'package:analyzer/analyzer.dart' show parseDirectives;
11 import 'package:analyzer/src/generated/ast.dart' 11 import 'package:analyzer/src/generated/ast.dart'
12 show 12 show
13 LibraryDirective, 13 LibraryDirective,
14 ImportDirective, 14 ImportDirective,
15 ExportDirective, 15 ExportDirective,
16 PartDirective, 16 PartDirective,
17 PartOfDirective,
17 CompilationUnit, 18 CompilationUnit,
18 Identifier; 19 Identifier;
19 import 'package:analyzer/src/generated/engine.dart' 20 import 'package:analyzer/src/generated/engine.dart'
20 show ParseDartTask, AnalysisContext; 21 show ParseDartTask, AnalysisContext;
21 import 'package:analyzer/src/generated/source.dart' show Source, SourceKind; 22 import 'package:analyzer/src/generated/source.dart' show Source, SourceKind;
22 import 'package:html5lib/dom.dart' show Document; 23 import 'package:html5lib/dom.dart' show Document;
23 import 'package:html5lib/parser.dart' as html; 24 import 'package:html5lib/parser.dart' as html;
24 import 'package:logging/logging.dart' show Logger; 25 import 'package:logging/logging.dart' show Logger;
25 import 'package:path/path.dart' as path; 26 import 'package:path/path.dart' as path;
26 27
27 import 'info.dart'; 28 import 'info.dart';
28 import 'options.dart'; 29 import 'options.dart';
29 import 'utils.dart'; 30 import 'utils.dart';
30 31
31 /// Holds references to all source nodes in the import graph. This is mainly 32 /// Holds references to all source nodes in the import graph. This is mainly
32 /// used as a level of indirection to ensure that each source has a canonical 33 /// used as a level of indirection to ensure that each source has a canonical
33 /// representation. 34 /// representation.
34 class SourceGraph { 35 class SourceGraph {
35 /// All nodes in the source graph. Used to get a canonical representation for 36 /// All nodes in the source graph. Used to get a canonical representation for
36 /// any node. 37 /// any node.
37 final Map<Uri, SourceNode> nodes = {}; 38 final Map<Uri, SourceNode> nodes = {};
38 39
39 /// Analyzer used to resolve source files. 40 /// Analyzer used to resolve source files.
40 final AnalysisContext _context; 41 final AnalysisContext _context;
41 final CompilerOptions _options; 42 final CompilerOptions _options;
42 43
43 SourceGraph(this._context, this._options); 44 SourceGraph(this._context, this._options);
44 45
45 /// Node associated with a resolved [uri]. 46 /// Node associated with a resolved [uri].
46 SourceNode nodeFromUri(Uri uri, [bool isPart = false]) { 47 SourceNode nodeFromUri(Uri uri) {
47 var uriString = Uri.encodeFull('$uri'); 48 var uriString = Uri.encodeFull('$uri');
48 var kind = uriString.endsWith('.html')
49 ? SourceKind.HTML
50 : isPart ? SourceKind.PART : SourceKind.LIBRARY;
51 return nodeFor(uri, _context.sourceFactory.forUri(uriString), kind);
52 }
53
54 /// Construct the node of the given [kind] with the given [uri] and [source].
55 SourceNode nodeFor(Uri uri, Source source, SourceKind kind) {
56 // TODO(sigmund): validate canonicalization?
57 // TODO(sigmund): add support for changing a file from one kind to another
58 // (e.g. converting a file from a part to a library).
59 return nodes.putIfAbsent(uri, () { 49 return nodes.putIfAbsent(uri, () {
60 if (kind == SourceKind.HTML) { 50 var source = _context.sourceFactory.forUri(uriString);
51 var extension = path.extension(uriString);
52 if (extension == '.html') {
61 return new HtmlSourceNode(uri, source); 53 return new HtmlSourceNode(uri, source);
62 } else if (kind == SourceKind.LIBRARY) { 54 } else if (extension == '.dart' || uriString.startsWith('dart:')) {
63 return new LibrarySourceNode(uri, source); 55 return new DartSourceNode(uri, source);
64 } else if (kind == SourceKind.PART) {
65 return new PartSourceNode(uri, source);
66 } else { 56 } else {
67 assert(false); // unreachable 57 assert(false); // unreachable
68 } 58 }
69 }); 59 });
70 } 60 }
71 } 61 }
72 62
73 /// A node in the import graph representing a source file. 63 /// A node in the import graph representing a source file.
74 abstract class SourceNode { 64 abstract class SourceNode {
75 /// Resolved URI for this node. 65 /// Resolved URI for this node.
76 final Uri uri; 66 final Uri uri;
77 67
78 /// Resolved source from the analyzer. We let the analyzer internally track 68 /// Resolved source from the analyzer. We let the analyzer internally track
79 /// for modifications to the source files. 69 /// for modifications to the source files.
80 final Source source; 70 final Source source;
81 71
82 /// Last stamp read from `source.modificationStamp`. 72 /// Last stamp read from `source.modificationStamp`.
83 int _lastStamp = 0; 73 int _lastStamp = 0;
84 74
85 /// Whether we need to rebuild this source file. 75 /// Whether we need to rebuild this source file.
86 bool needsRebuild = false; 76 bool needsRebuild = false;
87 77
88 /// Whether the structure of dependencies from this node (scripts, imports, 78 /// Whether the structure of dependencies from this node (scripts, imports,
89 /// exports, or parts) changed after we reparsed its contents. 79 /// exports, or parts) changed after we reparsed its contents.
90 bool structureChanged = false; 80 bool structureChanged = false;
91 81
92 /// Direct dependencies (script tags for HtmlSourceNodes; imports, exports and 82 /// Direct dependencies in the [SourceGraph]. These include script tags for
93 /// parts for LibrarySourceNodes). 83 /// [HtmlSourceNode]s; and imports, exports and parts for [DartSourceNode]s.
94 Iterable<SourceNode> get directDeps; 84 Iterable<SourceNode> get allDeps;
85
86 /// Like [allDeps] but excludes parts for [DartSourceNode]s. For many
87 /// operations we mainly care about dependencies at the library level, so
88 /// parts are excluded from this list.
89 Iterable<SourceNode> get depsWithoutParts;
95 90
96 SourceNode(this.uri, this.source); 91 SourceNode(this.uri, this.source);
97 92
98 /// Check for whether the file has changed and, if so, mark [needsRebuild] and 93 /// Check for whether the file has changed and, if so, mark [needsRebuild] and
99 /// [structureChanged] as necessary. 94 /// [structureChanged] as necessary.
100 void update(SourceGraph graph) { 95 void update(SourceGraph graph) {
101 int newStamp = source.modificationStamp; 96 int newStamp = source.modificationStamp;
102 if (newStamp > _lastStamp) { 97 if (newStamp > _lastStamp) {
103 _lastStamp = newStamp; 98 _lastStamp = newStamp;
104 needsRebuild = true; 99 needsRebuild = true;
105 } 100 }
106 } 101 }
107 102
108 String toString() { 103 String toString() {
109 var simpleUri = uri.scheme == 'file' ? path.relative(uri.path) : "$uri"; 104 var simpleUri = uri.scheme == 'file' ? path.relative(uri.path) : "$uri";
110 return '[$runtimeType: $simpleUri]'; 105 return '[$runtimeType: $simpleUri]';
111 } 106 }
112 } 107 }
113 108
114 /// A node representing an entry HTML source file. 109 /// A node representing an entry HTML source file.
115 class HtmlSourceNode extends SourceNode { 110 class HtmlSourceNode extends SourceNode {
116 /// Libraries referred to via script tags. 111 /// Libraries referred to via script tags.
117 Set<LibrarySourceNode> scripts = new Set<LibrarySourceNode>(); 112 Set<DartSourceNode> scripts = new Set<DartSourceNode>();
118 113
119 @override 114 @override
120 Iterable<SourceNode> get directDeps => scripts; 115 Iterable<SourceNode> get allDeps => scripts;
116
117 @override
118 Iterable<SourceNode> get depsWithoutParts => scripts;
121 119
122 /// Parsed document, updated whenever [update] is invoked. 120 /// Parsed document, updated whenever [update] is invoked.
123 Document document; 121 Document document;
124 122
125 HtmlSourceNode(uri, source) : super(uri, source); 123 HtmlSourceNode(uri, source) : super(uri, source);
126 124
127 void update(SourceGraph graph) { 125 void update(SourceGraph graph) {
128 super.update(graph); 126 super.update(graph);
129 if (needsRebuild) { 127 if (needsRebuild) {
130 document = html.parse(source.contents.data, generateSpans: true); 128 document = html.parse(source.contents.data, generateSpans: true);
131 var newScripts = new Set<LibrarySourceNode>(); 129 var newScripts = new Set<DartSourceNode>();
132 var tags = document.querySelectorAll('script[type="application/dart"]'); 130 var tags = document.querySelectorAll('script[type="application/dart"]');
133 for (var script in tags) { 131 for (var script in tags) {
134 var src = script.attributes['src']; 132 var src = script.attributes['src'];
135 if (src == null) { 133 if (src == null) {
136 // TODO(sigmund): expose these as compile-time failures 134 // TODO(sigmund): expose these as compile-time failures
137 _log.severe(script.sourceSpan.message( 135 _log.severe(script.sourceSpan.message(
138 'inlined script tags not supported at this time ' 136 'inlined script tags not supported at this time '
139 '(see https://github.com/dart-lang/dart-dev-compiler/issues/54).', 137 '(see https://github.com/dart-lang/dart-dev-compiler/issues/54).',
140 color: graph._options.useColors ? colorOf('error') : false)); 138 color: graph._options.useColors ? colorOf('error') : false));
141 continue; 139 continue;
142 } 140 }
143 var node = graph.nodeFromUri(uri.resolve(src)); 141 var node = graph.nodeFromUri(uri.resolve(src));
144 if (!node.source.exists()) { 142 if (!node.source.exists()) {
145 _log.severe(script.sourceSpan.message('Script file $src not found', 143 _log.severe(script.sourceSpan.message('Script file $src not found',
146 color: graph._options.useColors ? colorOf('error') : false)); 144 color: graph._options.useColors ? colorOf('error') : false));
147 } 145 }
148 newScripts.add(node); 146 newScripts.add(node);
149 } 147 }
150 148
151 if (!_same(newScripts, scripts)) { 149 if (!_same(newScripts, scripts)) {
152 structureChanged = true; 150 structureChanged = true;
153 scripts = newScripts; 151 scripts = newScripts;
154 } 152 }
155 } 153 }
156 } 154 }
157 } 155 }
158 156
159 /// A node representing a Dart part. 157 /// A node representing a Dart library or part.
160 class PartSourceNode extends SourceNode { 158 class DartSourceNode extends SourceNode {
161 final Iterable<SourceNode> directDeps = const []; 159 /// Set of imported libraries (empty for part files).
162 PartSourceNode(uri, source) : super(uri, source); 160 Set<DartSourceNode> imports = new Set<DartSourceNode>();
163 }
164 161
165 /// A node representing a Dart library. 162 /// Set of exported libraries (empty for part files).
166 class LibrarySourceNode extends SourceNode { 163 Set<DartSourceNode> exports = new Set<DartSourceNode>();
167 LibrarySourceNode(uri, source) : super(uri, source);
168 164
169 Set<LibrarySourceNode> imports = new Set<LibrarySourceNode>(); 165 /// Parts of this library (empty for part files).
170 Set<LibrarySourceNode> exports = new Set<LibrarySourceNode>(); 166 Set<DartSourceNode> parts = new Set<DartSourceNode>();
171 Set<PartSourceNode> parts = new Set<PartSourceNode>();
172 167
173 Iterable<SourceNode> get directDeps => 168 /// How many times this file is included as a part.
169 int includedAsPart = 0;
170
171 DartSourceNode(uri, source) : super(uri, source);
172
173 @override
174 Iterable<SourceNode> get allDeps =>
174 [imports, exports, parts].expand((e) => e); 175 [imports, exports, parts].expand((e) => e);
175 176
177 @override
178 Iterable<SourceNode> get depsWithoutParts =>
179 [imports, exports].expand((e) => e);
180
176 LibraryInfo info; 181 LibraryInfo info;
177 182
178 void update(SourceGraph graph) { 183 void update(SourceGraph graph) {
179 super.update(graph); 184 super.update(graph);
185
180 if (needsRebuild && source.contents.data != null) { 186 if (needsRebuild && source.contents.data != null) {
181 // If the defining compilation-unit changed, the structure might have 187 // If the defining compilation-unit changed, the structure might have
182 // changed. 188 // changed.
183 var unit = parseDirectives(source.contents.data, name: source.fullName); 189 var unit = parseDirectives(source.contents.data, name: source.fullName);
184 var newImports = new Set<LibrarySourceNode>(); 190 var newImports = new Set<DartSourceNode>();
185 var newExports = new Set<LibrarySourceNode>(); 191 var newExports = new Set<DartSourceNode>();
186 var newParts = new Set<PartSourceNode>(); 192 var newParts = new Set<DartSourceNode>();
187 for (var d in unit.directives) { 193 for (var d in unit.directives) {
194 // Nothing to do for parts.
195 if (d is PartOfDirective) return;
188 if (d is LibraryDirective) continue; 196 if (d is LibraryDirective) continue;
189 var target = 197 var target =
190 ParseDartTask.resolveDirective(graph._context, source, d, null); 198 ParseDartTask.resolveDirective(graph._context, source, d, null);
191 var uri = target.uri; 199 var uri = target.uri;
192 var node = graph.nodeFor(uri, target, 200 var node =
193 d is PartDirective ? SourceKind.PART : SourceKind.LIBRARY); 201 graph.nodes.putIfAbsent(uri, () => new DartSourceNode(uri, target));
194 if (!node.source.exists()) { 202 if (!node.source.exists()) {
195 _log.severe(spanForNode(unit, source, d).message( 203 _log.severe(spanForNode(unit, source, d).message(
196 'File $uri not found', 204 'File $uri not found',
197 color: graph._options.useColors ? colorOf('error') : false)); 205 color: graph._options.useColors ? colorOf('error') : false));
198 } 206 }
199 207
200 if (d is ImportDirective) { 208 if (d is ImportDirective) {
201 newImports.add(node); 209 newImports.add(node);
202 } else if (d is ExportDirective) { 210 } else if (d is ExportDirective) {
203 newExports.add(node); 211 newExports.add(node);
204 } else if (d is PartDirective) { 212 } else if (d is PartDirective) {
205 newParts.add(node); 213 newParts.add(node);
206 } 214 }
207 } 215 }
208 216
209 if (!_same(newImports, imports)) { 217 if (!_same(newImports, imports)) {
210 structureChanged = true; 218 structureChanged = true;
211 imports = newImports; 219 imports = newImports;
212 } 220 }
213 221
214 if (!_same(newExports, exports)) { 222 if (!_same(newExports, exports)) {
215 structureChanged = true; 223 structureChanged = true;
216 exports = newExports; 224 exports = newExports;
217 } 225 }
218 226
219 if (!_same(newParts, parts)) { 227 if (!_same(newParts, parts)) {
220 structureChanged = true; 228 structureChanged = true;
229
230 // When parts are removed, it's possible they were updated to be
231 // imported as a library
232 for (var p in parts) {
233 if (newParts.contains(p)) continue;
234 if (--p.includedAsPart == 0) {
235 p.needsRebuild = true;
236 }
237 }
238
239 for (var p in newParts) {
240 if (parts.contains(p)) continue;
241 p.includedAsPart++;
242 }
221 parts = newParts; 243 parts = newParts;
222 } 244 }
223 } 245 }
224 246
225 // The library should be marked as needing rebuild if a part changed 247 // The library should be marked as needing rebuild if a part changed
226 // internally: 248 // internally:
227 for (var p in parts) { 249 for (var p in parts) {
250 // Technically for parts we don't need to look at the contents. If they
251 // contain imports, exports, or parts, we'll ignore them in our crawling.
252 // However we do a full update to make it easier to adjust when users
253 // switch a file from a part to a library.
228 p.update(graph); 254 p.update(graph);
229 if (p.needsRebuild) needsRebuild = true; 255 if (p.needsRebuild) needsRebuild = true;
230 } 256 }
231 } 257 }
232 } 258 }
233 259
234 /// Updates the structure and `needsRebuild` marks in nodes of [graph] reachable 260 /// Updates the structure and `needsRebuild` marks in nodes of [graph] reachable
235 /// from [start]. 261 /// from [start].
236 /// 262 ///
237 /// That is, staring from [start], we update the graph by detecting file changes 263 /// That is, staring from [start], we update the graph by detecting file changes
238 /// and rebuilding the structure of the graph wherever it changed (an import was 264 /// and rebuilding the structure of the graph wherever it changed (an import was
239 /// added or removed, etc). 265 /// added or removed, etc).
240 /// 266 ///
241 /// After calling this function a node is marked with `needsRebuild` only if it 267 /// After calling this function a node is marked with `needsRebuild` only if it
242 /// contained local changes. Rebuild decisions that derive from transitive 268 /// contained local changes. Rebuild decisions that derive from transitive
243 /// changes (e.g. when the API of a dependency changed) are handled later in 269 /// changes (e.g. when the API of a dependency changed) are handled later in
244 /// [rebuild]. 270 /// [rebuild].
245 void refreshStructureAndMarks(SourceNode start, SourceGraph graph) { 271 void refreshStructureAndMarks(SourceNode start, SourceGraph graph) {
246 visitInPreOrder(start, (n) => n.update(graph)); 272 visitInPreOrder(start, (n) => n.update(graph), includeParts: false);
247 } 273 }
248 274
249 /// Clears all the `needsRebuild` and `structureChanged` marks in nodes 275 /// Clears all the `needsRebuild` and `structureChanged` marks in nodes
250 /// reachable from [start]. 276 /// reachable from [start].
251 void clearMarks(SourceNode start) { 277 void clearMarks(SourceNode start) {
252 visitInPreOrder(start, (n) => n.needsRebuild = n.structureChanged = false); 278 visitInPreOrder(start, (n) => n.needsRebuild = n.structureChanged = false,
279 includeParts: true);
253 } 280 }
254 281
255 /// Traverses from [start] with the purpose of building any source that needs to 282 /// Traverses from [start] with the purpose of building any source that needs to
256 /// be rebuilt. 283 /// be rebuilt.
257 /// 284 ///
258 /// This function will call [build] in a post-order fashion, on a subset of the 285 /// This function will call [build] in a post-order fashion, on a subset of the
259 /// reachable nodes. There are four rules used to decide when to rebuild a node 286 /// reachable nodes. There are four rules used to decide when to rebuild a node
260 /// (call [build] on a node): 287 /// (call [build] on a node):
261 /// 288 ///
262 /// * Only rebuild Dart libraries ([LibrarySourceNode]) or HTML files 289 /// * Only rebuild Dart libraries ([DartSourceNode]) or HTML files
263 /// ([HtmlSourceNode]), but never part files ([PartSourceNode]). That is 290 /// ([HtmlSourceNode]), but skip part files. That is because those are
264 /// because those are built as part of some library. 291 /// built as part of some library.
265 /// 292 ///
266 /// * Always rebuild [LibrarySourceNode]s and [HtmlSourceNode]s with local 293 /// * Always rebuild [DartSourceNode]s and [HtmlSourceNode]s with local
267 /// changes or changes in a part of the library. Internally this function 294 /// changes or changes in a part of the library. Internally this function
268 /// calls [refreshStructureAndMarks] to ensure that the graph structure is 295 /// calls [refreshStructureAndMarks] to ensure that the graph structure is
269 /// up-to-date and that these nodes with local changes contain the 296 /// up-to-date and that these nodes with local changes contain the
270 /// `needsRebuild` bit. 297 /// `needsRebuild` bit.
271 /// 298 ///
272 /// * Rebuild [HtmlSourceNode]s if there were structural changes somewhere 299 /// * Rebuild [HtmlSourceNode]s if there were structural changes somewhere
273 /// down its reachable subgraph. This is done because HTML files embed the 300 /// down its reachable subgraph. This is done because HTML files embed the
274 /// transitive closure of the import graph in their output. 301 /// transitive closure of the import graph in their output.
275 /// 302 ///
276 /// * Rebuild [LibrarySourceNode]s that depend on other [LibrarySourceNode]s 303 /// * Rebuild [DartSourceNode]s that depend on other [DartSourceNode]s
277 /// whose API may have changed. The result of [build] is used to determine 304 /// whose API may have changed. The result of [build] is used to determine
278 /// whether other nodes need to be rebuilt. The function [build] is expected 305 /// whether other nodes need to be rebuilt. The function [build] is expected
279 /// to return `true` on a node `n` if it detemines other nodes that import 306 /// to return `true` on a node `n` if it detemines other nodes that import
280 /// `n` may need to be rebuilt as well. 307 /// `n` may need to be rebuilt as well.
281 rebuild(SourceNode start, SourceGraph graph, bool build(SourceNode node)) { 308 rebuild(SourceNode start, SourceGraph graph, bool build(SourceNode node)) {
282 refreshStructureAndMarks(start, graph); 309 refreshStructureAndMarks(start, graph);
283 // Hold which source nodes may have changed their public API, this includes 310 // Hold which source nodes may have changed their public API, this includes
284 // libraries that were modified or libraries that export other modified APIs. 311 // libraries that were modified or libraries that export other modified APIs.
285 // TODO(sigmund): consider removing this special support for exports? Many 312 // TODO(sigmund): consider removing this special support for exports? Many
286 // cases anways require using summaries to understand what parts of the public 313 // cases anways require using summaries to understand what parts of the public
287 // API may be affected by transitive changes. The re-export case is just one 314 // API may be affected by transitive changes. The re-export case is just one
288 // of those transitive cases, but is not sufficient. See 315 // of those transitive cases, but is not sufficient. See
289 // https://github.com/dart-lang/dev_compiler/issues/76 316 // https://github.com/dart-lang/dev_compiler/issues/76
290 var apiChangeDetected = new HashSet<SourceNode>(); 317 var apiChangeDetected = new HashSet<SourceNode>();
291 bool structureHasChanged = false; 318 bool structureHasChanged = false;
292 319
293 bool shouldBuildNode(SourceNode n) { 320 bool shouldBuildNode(SourceNode n) {
294 if (n is PartSourceNode) return false;
295 if (n.needsRebuild) return true; 321 if (n.needsRebuild) return true;
296 if (n is HtmlSourceNode) return structureHasChanged; 322 if (n is HtmlSourceNode) return structureHasChanged;
297 return (n as LibrarySourceNode).imports 323 return (n as DartSourceNode).imports
298 .any((i) => apiChangeDetected.contains(i)); 324 .any((i) => apiChangeDetected.contains(i));
299 } 325 }
300 326
301 visitInPostOrder(start, (n) { 327 visitInPostOrder(start, (n) {
302 if (n.structureChanged) structureHasChanged = true; 328 if (n.structureChanged) structureHasChanged = true;
303 if (shouldBuildNode(n)) { 329 if (shouldBuildNode(n)) {
304 if (build(n)) apiChangeDetected.add(n); 330 if (build(n)) apiChangeDetected.add(n);
305 } else if (n is LibrarySourceNode && 331 } else if (n is DartSourceNode &&
306 n.exports.any((e) => apiChangeDetected.contains(e))) { 332 n.exports.any((e) => apiChangeDetected.contains(e))) {
307 apiChangeDetected.add(n); 333 apiChangeDetected.add(n);
308 } 334 }
309 n.needsRebuild = false; 335 n.needsRebuild = false;
310 n.structureChanged = false; 336 n.structureChanged = false;
311 }); 337 if (n is DartSourceNode) {
338 // Note: clearing out flags in the parts could be a problem if someone
339 // tries to use a file both as a part and a library at the same time.
340 // In that case, we might not correctly propagate changes in the places
341 // where it is used as a library. Technically it's not allowed to have a
342 // file as a part and a library at once, and the analyzer should report an
343 // error in that case.
344 n.parts.forEach((p) => p.needsRebuild = p.structureChanged = false);
345 }
346 }, includeParts: false);
312 } 347 }
313 348
314 /// Helper that runs [action] on nodes reachable from [node] in pre-order. 349 /// Helper that runs [action] on nodes reachable from [start] in pre-order.
315 visitInPreOrder(SourceNode node, void action(SourceNode node), 350 visitInPreOrder(SourceNode start, void action(SourceNode node),
316 {Set<SourceNode> seen}) { 351 {bool includeParts: false}) {
317 if (seen == null) seen = new HashSet<SourceNode>(); 352 var seen = new HashSet<SourceNode>();
318 if (!seen.add(node)) return; 353 helper(SourceNode node) {
319 action(node); 354 if (!seen.add(node)) return;
320 node.directDeps.forEach((d) => visitInPreOrder(d, action, seen: seen)); 355 action(node);
356 var deps = includeParts ? node.allDeps : node.depsWithoutParts;
357 deps.forEach(helper);
358 }
359 helper(start);
321 } 360 }
322 361
323 /// Helper that runs [action] on nodes reachable from [node] in post-order. 362 /// Helper that runs [action] on nodes reachable from [start] in post-order.
324 visitInPostOrder(SourceNode node, void action(SourceNode node), 363 visitInPostOrder(SourceNode start, void action(SourceNode node),
325 {Set<SourceNode> seen}) { 364 {bool includeParts: false}) {
326 if (seen == null) seen = new HashSet<SourceNode>(); 365 var seen = new HashSet<SourceNode>();
327 if (!seen.add(node)) return; 366 helper(SourceNode node) {
328 node.directDeps.forEach((d) => visitInPostOrder(d, action, seen: seen)); 367 if (!seen.add(node)) return;
329 action(node); 368 var deps = includeParts ? node.allDeps : node.depsWithoutParts;
369 deps.forEach(helper);
370 action(node);
371 }
372 helper(start);
330 } 373 }
331 374
332 bool _same(Set a, Set b) => a.length == b.length && a.containsAll(b); 375 bool _same(Set a, Set b) => a.length == b.length && a.containsAll(b);
333 final _log = new Logger('dev_compiler.graph'); 376 final _log = new Logger('dev_compiler.graph');
OLDNEW
« no previous file with comments | « lib/src/codegen/html_codegen.dart ('k') | test/dependency_graph_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698