OLD | NEW |
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 AstNode, | 13 AstNode, |
14 CompilationUnit, | 14 CompilationUnit, |
15 ExportDirective, | 15 ExportDirective, |
16 Identifier, | 16 Identifier, |
17 ImportDirective, | 17 ImportDirective, |
18 LibraryDirective, | 18 LibraryDirective, |
19 PartDirective, | 19 PartDirective, |
20 PartOfDirective; | 20 PartOfDirective; |
21 import 'package:analyzer/src/generated/engine.dart' | 21 import 'package:analyzer/src/generated/engine.dart' |
22 show ParseDartTask, AnalysisContext; | 22 show ParseDartTask, AnalysisContext; |
23 import 'package:analyzer/src/generated/source.dart' show Source, SourceKind; | 23 import 'package:analyzer/src/generated/source.dart' show Source, SourceKind; |
24 import 'package:html/dom.dart' show Document, Node; | 24 import 'package:html/dom.dart' show Document, Node; |
25 import 'package:html/parser.dart' as html; | 25 import 'package:html/parser.dart' as html; |
26 import 'package:logging/logging.dart' show Logger, Level; | 26 import 'package:logging/logging.dart' show Logger, Level; |
27 import 'package:path/path.dart' as path; | 27 import 'package:path/path.dart' as path; |
28 import 'package:source_span/source_span.dart' show SourceSpan; | |
29 | 28 |
30 import 'info.dart'; | 29 import 'info.dart'; |
31 import 'options.dart'; | 30 import 'options.dart'; |
32 import 'report.dart'; | 31 import 'report.dart'; |
33 import 'utils.dart'; | |
34 | 32 |
35 /// Holds references to all source nodes in the import graph. This is mainly | 33 /// Holds references to all source nodes in the import graph. This is mainly |
36 /// used as a level of indirection to ensure that each source has a canonical | 34 /// used as a level of indirection to ensure that each source has a canonical |
37 /// representation. | 35 /// representation. |
38 class SourceGraph { | 36 class SourceGraph { |
39 /// All nodes in the source graph. Used to get a canonical representation for | 37 /// All nodes in the source graph. Used to get a canonical representation for |
40 /// any node. | 38 /// any node. |
41 final Map<Uri, SourceNode> nodes = {}; | 39 final Map<Uri, SourceNode> nodes = {}; |
42 | 40 |
43 /// Resources included by default on any application. | 41 /// Resources included by default on any application. |
(...skipping 19 matching lines...) Expand all Loading... |
63 } | 61 } |
64 } | 62 } |
65 | 63 |
66 /// Node associated with a resolved [uri]. | 64 /// Node associated with a resolved [uri]. |
67 SourceNode nodeFromUri(Uri uri) { | 65 SourceNode nodeFromUri(Uri uri) { |
68 var uriString = Uri.encodeFull('$uri'); | 66 var uriString = Uri.encodeFull('$uri'); |
69 return nodes.putIfAbsent(uri, () { | 67 return nodes.putIfAbsent(uri, () { |
70 var source = _context.sourceFactory.forUri(uriString); | 68 var source = _context.sourceFactory.forUri(uriString); |
71 var extension = path.extension(uriString); | 69 var extension = path.extension(uriString); |
72 if (extension == '.html') { | 70 if (extension == '.html') { |
73 return new HtmlSourceNode(uri, source, this); | 71 return new HtmlSourceNode(this, uri, source); |
74 } else if (extension == '.dart' || uriString.startsWith('dart:')) { | 72 } else if (extension == '.dart' || uriString.startsWith('dart:')) { |
75 return new DartSourceNode(uri, source); | 73 return new DartSourceNode(this, uri, source); |
76 } else { | 74 } else { |
77 return new ResourceSourceNode(uri, source); | 75 return new ResourceSourceNode(this, uri, source); |
78 } | 76 } |
79 }); | 77 }); |
80 } | 78 } |
81 } | 79 } |
82 | 80 |
83 /// A node in the import graph representing a source file. | 81 /// A node in the import graph representing a source file. |
84 abstract class SourceNode { | 82 abstract class SourceNode { |
| 83 final SourceGraph graph; |
| 84 |
85 /// Resolved URI for this node. | 85 /// Resolved URI for this node. |
86 final Uri uri; | 86 final Uri uri; |
87 | 87 |
88 /// Resolved source from the analyzer. We let the analyzer internally track | 88 /// Resolved source from the analyzer. We let the analyzer internally track |
89 /// for modifications to the source files. | 89 /// for modifications to the source files. |
90 Source _source; | 90 Source _source; |
91 Source get source => _source; | 91 Source get source => _source; |
92 | 92 |
| 93 String get contents => graph._context.getContents(source).data; |
| 94 |
93 /// Last stamp read from `source.modificationStamp`. | 95 /// Last stamp read from `source.modificationStamp`. |
94 int _lastStamp = 0; | 96 int _lastStamp = 0; |
95 | 97 |
96 /// A hash used to help browsers cache the output that would be produced from | 98 /// A hash used to help browsers cache the output that would be produced from |
97 /// building this node. | 99 /// building this node. |
98 String cachingHash; | 100 String cachingHash; |
99 | 101 |
100 /// Whether we need to rebuild this source file. | 102 /// Whether we need to rebuild this source file. |
101 bool needsRebuild = false; | 103 bool needsRebuild = false; |
102 | 104 |
103 /// Whether the structure of dependencies from this node (scripts, imports, | 105 /// Whether the structure of dependencies from this node (scripts, imports, |
104 /// exports, or parts) changed after we reparsed its contents. | 106 /// exports, or parts) changed after we reparsed its contents. |
105 bool structureChanged = false; | 107 bool structureChanged = false; |
106 | 108 |
107 /// Direct dependencies in the [SourceGraph]. These include script tags for | 109 /// Direct dependencies in the [SourceGraph]. These include script tags for |
108 /// [HtmlSourceNode]s; and imports, exports and parts for [DartSourceNode]s. | 110 /// [HtmlSourceNode]s; and imports, exports and parts for [DartSourceNode]s. |
109 Iterable<SourceNode> get allDeps => const []; | 111 Iterable<SourceNode> get allDeps => const []; |
110 | 112 |
111 /// Like [allDeps] but excludes parts for [DartSourceNode]s. For many | 113 /// Like [allDeps] but excludes parts for [DartSourceNode]s. For many |
112 /// operations we mainly care about dependencies at the library level, so | 114 /// operations we mainly care about dependencies at the library level, so |
113 /// parts are excluded from this list. | 115 /// parts are excluded from this list. |
114 Iterable<SourceNode> get depsWithoutParts => const []; | 116 Iterable<SourceNode> get depsWithoutParts => const []; |
115 | 117 |
116 SourceNode(this.uri, this._source); | 118 SourceNode(this.graph, this.uri, this._source); |
117 | 119 |
118 /// Check for whether the file has changed and, if so, mark [needsRebuild] and | 120 /// Check for whether the file has changed and, if so, mark [needsRebuild] and |
119 /// [structureChanged] as necessary. | 121 /// [structureChanged] as necessary. |
120 void update(SourceGraph graph) { | 122 void update() { |
121 if (_source == null) { | 123 if (_source == null) { |
122 _source = graph._context.sourceFactory.forUri(Uri.encodeFull('$uri')); | 124 _source = graph._context.sourceFactory.forUri(Uri.encodeFull('$uri')); |
123 if (_source == null) return; | 125 if (_source == null) return; |
124 } | 126 } |
125 int newStamp = _source.modificationStamp; | 127 int newStamp = _source.modificationStamp; |
126 if (newStamp > _lastStamp) { | 128 if (newStamp > _lastStamp) { |
| 129 // If the timestamp changed, read the file from disk and cache it. |
| 130 // We don't want the source text to change during compilation. |
| 131 saveUpdatedContents(); |
127 _lastStamp = newStamp; | 132 _lastStamp = newStamp; |
128 needsRebuild = true; | 133 needsRebuild = true; |
129 } | 134 } |
130 } | 135 } |
131 | 136 |
| 137 void saveUpdatedContents() {} |
| 138 |
132 String toString() { | 139 String toString() { |
133 var simpleUri = uri.scheme == 'file' ? path.relative(uri.path) : "$uri"; | 140 var simpleUri = uri.scheme == 'file' ? path.relative(uri.path) : "$uri"; |
134 return '[$runtimeType: $simpleUri]'; | 141 return '[$runtimeType: $simpleUri]'; |
135 } | 142 } |
136 } | 143 } |
137 | 144 |
138 /// A node representing an entry HTML source file. | 145 /// A node representing an entry HTML source file. |
139 class HtmlSourceNode extends SourceNode { | 146 class HtmlSourceNode extends SourceNode { |
140 /// Resources included by default on any application. | 147 /// Resources included by default on any application. |
141 final runtimeDeps; | 148 final runtimeDeps; |
142 | 149 |
143 /// Libraries referred to via script tags. | 150 /// Libraries referred to via script tags. |
144 Set<DartSourceNode> scripts = new Set<DartSourceNode>(); | 151 Set<DartSourceNode> scripts = new Set<DartSourceNode>(); |
145 | 152 |
146 /// Link-rel stylesheets and images. | 153 /// Link-rel stylesheets and images. |
147 Set<ResourceSourceNode> resources = new Set<ResourceSourceNode>(); | 154 Set<ResourceSourceNode> resources = new Set<ResourceSourceNode>(); |
148 | 155 |
149 @override | 156 @override |
150 Iterable<SourceNode> get allDeps => | 157 Iterable<SourceNode> get allDeps => |
151 [scripts, resources, runtimeDeps].expand((e) => e); | 158 [scripts, resources, runtimeDeps].expand((e) => e); |
152 | 159 |
153 @override | 160 @override |
154 Iterable<SourceNode> get depsWithoutParts => allDeps; | 161 Iterable<SourceNode> get depsWithoutParts => allDeps; |
155 | 162 |
156 /// Parsed document, updated whenever [update] is invoked. | 163 /// Parsed document, updated whenever [update] is invoked. |
157 Document document; | 164 Document document; |
158 | 165 |
159 HtmlSourceNode(Uri uri, Source source, SourceGraph graph) | 166 HtmlSourceNode(SourceGraph graph, Uri uri, Source source) |
160 : runtimeDeps = graph.runtimeDeps, | 167 : runtimeDeps = graph.runtimeDeps, |
161 super(uri, source); | 168 super(graph, uri, source); |
162 | 169 |
163 void update(SourceGraph graph) { | 170 @override |
164 super.update(graph); | 171 void update() { |
| 172 super.update(); |
165 if (needsRebuild) { | 173 if (needsRebuild) { |
166 graph._reporter.clearHtml(uri); | 174 graph._reporter.clearHtml(uri); |
167 document = html.parse(source.contents.data, generateSpans: true); | 175 document = html.parse(contents, generateSpans: true); |
168 var newScripts = new Set<DartSourceNode>(); | 176 var newScripts = new Set<DartSourceNode>(); |
169 var tags = document.querySelectorAll('script[type="application/dart"]'); | 177 var tags = document.querySelectorAll('script[type="application/dart"]'); |
170 for (var script in tags) { | 178 for (var script in tags) { |
171 var src = script.attributes['src']; | 179 var src = script.attributes['src']; |
172 if (src == null) { | 180 if (src == null) { |
173 _reportError(graph, 'inlined script tags not supported at this time ' | 181 _reportError(graph, 'inlined script tags not supported at this time ' |
174 '(see https://github.com/dart-lang/dart-dev-compiler/issues/54).', | 182 '(see https://github.com/dart-lang/dart-dev-compiler/issues/54).', |
175 script); | 183 script); |
176 continue; | 184 continue; |
177 } | 185 } |
(...skipping 19 matching lines...) Expand all Loading... |
197 } | 205 } |
198 if (!_same(newResources, resources)) { | 206 if (!_same(newResources, resources)) { |
199 structureChanged = true; | 207 structureChanged = true; |
200 resources = newResources; | 208 resources = newResources; |
201 } | 209 } |
202 } | 210 } |
203 } | 211 } |
204 | 212 |
205 void _reportError(SourceGraph graph, String message, Node node) { | 213 void _reportError(SourceGraph graph, String message, Node node) { |
206 graph._reporter.enterHtml(source.uri); | 214 graph._reporter.enterHtml(source.uri); |
207 graph._reporter.log(new DependencyGraphError(message, node.sourceSpan)); | 215 var span = node.sourceSpan; |
| 216 graph._reporter.log( |
| 217 new Message(message, Level.SEVERE, span.start.offset, span.end.offset)); |
208 graph._reporter.leaveHtml(); | 218 graph._reporter.leaveHtml(); |
209 } | 219 } |
210 } | 220 } |
211 | 221 |
212 /// A node representing a Dart library or part. | 222 /// A node representing a Dart library or part. |
213 class DartSourceNode extends SourceNode { | 223 class DartSourceNode extends SourceNode { |
214 /// Set of imported libraries (empty for part files). | 224 /// Set of imported libraries (empty for part files). |
215 Set<DartSourceNode> imports = new Set<DartSourceNode>(); | 225 Set<DartSourceNode> imports = new Set<DartSourceNode>(); |
216 | 226 |
217 /// Set of exported libraries (empty for part files). | 227 /// Set of exported libraries (empty for part files). |
218 Set<DartSourceNode> exports = new Set<DartSourceNode>(); | 228 Set<DartSourceNode> exports = new Set<DartSourceNode>(); |
219 | 229 |
220 /// Parts of this library (empty for part files). | 230 /// Parts of this library (empty for part files). |
221 Set<DartSourceNode> parts = new Set<DartSourceNode>(); | 231 Set<DartSourceNode> parts = new Set<DartSourceNode>(); |
222 | 232 |
223 /// How many times this file is included as a part. | 233 /// How many times this file is included as a part. |
224 int includedAsPart = 0; | 234 int includedAsPart = 0; |
225 | 235 |
226 DartSourceNode(uri, source) : super(uri, source); | 236 DartSourceNode(graph, uri, source) : super(graph, uri, source); |
227 | 237 |
228 @override | 238 @override |
229 Iterable<SourceNode> get allDeps => | 239 Iterable<SourceNode> get allDeps => |
230 [imports, exports, parts].expand((e) => e); | 240 [imports, exports, parts].expand((e) => e); |
231 | 241 |
232 @override | 242 @override |
233 Iterable<SourceNode> get depsWithoutParts => | 243 Iterable<SourceNode> get depsWithoutParts => |
234 [imports, exports].expand((e) => e); | 244 [imports, exports].expand((e) => e); |
235 | 245 |
236 LibraryInfo info; | 246 LibraryInfo info; |
237 | 247 |
238 void update(SourceGraph graph) { | 248 // TODO(jmesserly): it would be nice to not keep all sources in memory at |
239 super.update(graph); | 249 // once, but how else can we ensure a consistent view across a given |
| 250 // compile? One different from dev_compiler vs analyzer is that our |
| 251 // messages later in the compiler need the original source text to print |
| 252 // spans. We also read source text ourselves to parse directives. |
| 253 // But we could discard it after that point. |
| 254 void saveUpdatedContents() { |
| 255 graph._context.setContents(source, source.contents.data); |
| 256 } |
240 | 257 |
241 if (needsRebuild && source.contents.data != null) { | 258 @override |
| 259 void update() { |
| 260 super.update(); |
| 261 |
| 262 if (needsRebuild && contents != null) { |
242 graph._reporter.clearLibrary(uri); | 263 graph._reporter.clearLibrary(uri); |
243 // If the defining compilation-unit changed, the structure might have | 264 // If the defining compilation-unit changed, the structure might have |
244 // changed. | 265 // changed. |
245 var unit = parseDirectives(source.contents.data, name: source.fullName); | 266 var unit = parseDirectives(contents, name: source.fullName); |
246 var newImports = new Set<DartSourceNode>(); | 267 var newImports = new Set<DartSourceNode>(); |
247 var newExports = new Set<DartSourceNode>(); | 268 var newExports = new Set<DartSourceNode>(); |
248 var newParts = new Set<DartSourceNode>(); | 269 var newParts = new Set<DartSourceNode>(); |
249 for (var d in unit.directives) { | 270 for (var d in unit.directives) { |
250 // Nothing to do for parts. | 271 // Nothing to do for parts. |
251 if (d is PartOfDirective) return; | 272 if (d is PartOfDirective) return; |
252 if (d is LibraryDirective) continue; | 273 if (d is LibraryDirective) continue; |
253 | 274 |
254 // `dart:core` and other similar URLs only contain a name, but it is | 275 // `dart:core` and other similar URLs only contain a name, but it is |
255 // meant to be a folder when resolving relative paths from it. | 276 // meant to be a folder when resolving relative paths from it. |
256 var targetUri = uri.scheme == 'dart' && uri.pathSegments.length == 1 | 277 var targetUri = uri.scheme == 'dart' && uri.pathSegments.length == 1 |
257 ? Uri.parse('$uri/').resolve(d.uri.stringValue) | 278 ? Uri.parse('$uri/').resolve(d.uri.stringValue) |
258 : uri.resolve(d.uri.stringValue); | 279 : uri.resolve(d.uri.stringValue); |
259 var target = | 280 var target = |
260 ParseDartTask.resolveDirective(graph._context, source, d, null); | 281 ParseDartTask.resolveDirective(graph._context, source, d, null); |
261 if (target != null) { | 282 if (target != null) { |
262 if (targetUri != target.uri) print(">> ${target.uri} $targetUri"); | 283 if (targetUri != target.uri) print(">> ${target.uri} $targetUri"); |
263 } | 284 } |
264 var node = graph.nodes.putIfAbsent( | 285 var node = graph.nodes.putIfAbsent( |
265 targetUri, () => new DartSourceNode(targetUri, target)); | 286 targetUri, () => new DartSourceNode(graph, targetUri, target)); |
266 //var node = graph.nodeFromUri(targetUri); | 287 //var node = graph.nodeFromUri(targetUri); |
267 if (node.source == null || !node.source.exists()) { | 288 if (node.source == null || !node.source.exists()) { |
268 _reportError(graph, 'File $targetUri not found', unit, d); | 289 _reportError(graph, 'File $targetUri not found', unit, d); |
269 } | 290 } |
270 | 291 |
271 if (d is ImportDirective) { | 292 if (d is ImportDirective) { |
272 newImports.add(node); | 293 newImports.add(node); |
273 } else if (d is ExportDirective) { | 294 } else if (d is ExportDirective) { |
274 newExports.add(node); | 295 newExports.add(node); |
275 } else if (d is PartDirective) { | 296 } else if (d is PartDirective) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 } | 328 } |
308 } | 329 } |
309 | 330 |
310 // The library should be marked as needing rebuild if a part changed | 331 // The library should be marked as needing rebuild if a part changed |
311 // internally: | 332 // internally: |
312 for (var p in parts) { | 333 for (var p in parts) { |
313 // Technically for parts we don't need to look at the contents. If they | 334 // Technically for parts we don't need to look at the contents. If they |
314 // contain imports, exports, or parts, we'll ignore them in our crawling. | 335 // contain imports, exports, or parts, we'll ignore them in our crawling. |
315 // However we do a full update to make it easier to adjust when users | 336 // However we do a full update to make it easier to adjust when users |
316 // switch a file from a part to a library. | 337 // switch a file from a part to a library. |
317 p.update(graph); | 338 p.update(); |
318 if (p.needsRebuild) needsRebuild = true; | 339 if (p.needsRebuild) needsRebuild = true; |
319 } | 340 } |
320 } | 341 } |
321 | 342 |
322 void _reportError( | 343 void _reportError( |
323 SourceGraph graph, String message, CompilationUnit unit, AstNode node) { | 344 SourceGraph graph, String message, CompilationUnit unit, AstNode node) { |
324 graph._reporter.enterLibrary(source.uri); | 345 graph._reporter |
325 graph._reporter.log( | 346 ..enterLibrary(source.uri) |
326 new DependencyGraphError(message, spanForNode(unit, source, node))); | 347 ..enterCompilationUnit(unit, source) |
327 graph._reporter.leaveLibrary(); | 348 ..log(new Message(message, Level.SEVERE, node.offset, node.end)) |
| 349 ..leaveCompilationUnit() |
| 350 ..leaveLibrary(); |
328 } | 351 } |
329 } | 352 } |
330 | 353 |
331 /// Represents a runtime resource from our compiler that is needed to run an | 354 /// Represents a runtime resource from our compiler that is needed to run an |
332 /// application. | 355 /// application. |
333 class ResourceSourceNode extends SourceNode { | 356 class ResourceSourceNode extends SourceNode { |
334 ResourceSourceNode(uri, source) : super(uri, source); | 357 ResourceSourceNode(graph, uri, source) : super(graph, uri, source); |
335 } | 358 } |
336 | 359 |
337 /// Updates the structure and `needsRebuild` marks in nodes of [graph] reachable | 360 /// Updates the structure and `needsRebuild` marks in nodes of [graph] reachable |
338 /// from [start]. | 361 /// from [start]. |
339 /// | 362 /// |
340 /// That is, staring from [start], we update the graph by detecting file changes | 363 /// That is, staring from [start], we update the graph by detecting file changes |
341 /// and rebuilding the structure of the graph wherever it changed (an import was | 364 /// and rebuilding the structure of the graph wherever it changed (an import was |
342 /// added or removed, etc). | 365 /// added or removed, etc). |
343 /// | 366 /// |
344 /// After calling this function a node is marked with `needsRebuild` only if it | 367 /// After calling this function a node is marked with `needsRebuild` only if it |
345 /// contained local changes. Rebuild decisions that derive from transitive | 368 /// contained local changes. Rebuild decisions that derive from transitive |
346 /// changes (e.g. when the API of a dependency changed) are handled later in | 369 /// changes (e.g. when the API of a dependency changed) are handled later in |
347 /// [rebuild]. | 370 /// [rebuild]. |
348 void refreshStructureAndMarks(SourceNode start, SourceGraph graph) { | 371 void refreshStructureAndMarks(SourceNode start) { |
349 visitInPreOrder(start, (n) => n.update(graph), includeParts: false); | 372 visitInPreOrder(start, (n) => n.update(), includeParts: false); |
350 } | 373 } |
351 | 374 |
352 /// Clears all the `needsRebuild` and `structureChanged` marks in nodes | 375 /// Clears all the `needsRebuild` and `structureChanged` marks in nodes |
353 /// reachable from [start]. | 376 /// reachable from [start]. |
354 void clearMarks(SourceNode start) { | 377 void clearMarks(SourceNode start) { |
355 visitInPreOrder(start, (n) => n.needsRebuild = n.structureChanged = false, | 378 visitInPreOrder(start, (n) => n.needsRebuild = n.structureChanged = false, |
356 includeParts: true); | 379 includeParts: true); |
357 } | 380 } |
358 | 381 |
359 /// Traverses from [start] with the purpose of building any source that needs to | 382 /// Traverses from [start] with the purpose of building any source that needs to |
(...skipping 15 matching lines...) Expand all Loading... |
375 /// | 398 /// |
376 /// * Rebuild [HtmlSourceNode]s if there were structural changes somewhere | 399 /// * Rebuild [HtmlSourceNode]s if there were structural changes somewhere |
377 /// down its reachable subgraph. This is done because HTML files embed the | 400 /// down its reachable subgraph. This is done because HTML files embed the |
378 /// transitive closure of the import graph in their output. | 401 /// transitive closure of the import graph in their output. |
379 /// | 402 /// |
380 /// * Rebuild [DartSourceNode]s that depend on other [DartSourceNode]s | 403 /// * Rebuild [DartSourceNode]s that depend on other [DartSourceNode]s |
381 /// whose API may have changed. The result of [build] is used to determine | 404 /// whose API may have changed. The result of [build] is used to determine |
382 /// whether other nodes need to be rebuilt. The function [build] is expected | 405 /// whether other nodes need to be rebuilt. The function [build] is expected |
383 /// to return `true` on a node `n` if it detemines other nodes that import | 406 /// to return `true` on a node `n` if it detemines other nodes that import |
384 /// `n` may need to be rebuilt as well. | 407 /// `n` may need to be rebuilt as well. |
385 rebuild(SourceNode start, SourceGraph graph, bool build(SourceNode node)) { | 408 rebuild(SourceNode start, bool build(SourceNode node)) { |
386 refreshStructureAndMarks(start, graph); | 409 refreshStructureAndMarks(start); |
387 // Hold which source nodes may have changed their public API, this includes | 410 // Hold which source nodes may have changed their public API, this includes |
388 // libraries that were modified or libraries that export other modified APIs. | 411 // libraries that were modified or libraries that export other modified APIs. |
389 // TODO(sigmund): consider removing this special support for exports? Many | 412 // TODO(sigmund): consider removing this special support for exports? Many |
390 // cases anways require using summaries to understand what parts of the public | 413 // cases anways require using summaries to understand what parts of the public |
391 // API may be affected by transitive changes. The re-export case is just one | 414 // API may be affected by transitive changes. The re-export case is just one |
392 // of those transitive cases, but is not sufficient. See | 415 // of those transitive cases, but is not sufficient. See |
393 // https://github.com/dart-lang/dev_compiler/issues/76 | 416 // https://github.com/dart-lang/dev_compiler/issues/76 |
394 var apiChangeDetected = new HashSet<SourceNode>(); | 417 var apiChangeDetected = new HashSet<SourceNode>(); |
395 bool htmlNeedsRebuild = false; | 418 bool htmlNeedsRebuild = false; |
396 | 419 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 if (!seen.add(node)) return; | 470 if (!seen.add(node)) return; |
448 var deps = includeParts ? node.allDeps : node.depsWithoutParts; | 471 var deps = includeParts ? node.allDeps : node.depsWithoutParts; |
449 deps.forEach(helper); | 472 deps.forEach(helper); |
450 action(node); | 473 action(node); |
451 } | 474 } |
452 helper(start); | 475 helper(start); |
453 } | 476 } |
454 | 477 |
455 bool _same(Set a, Set b) => a.length == b.length && a.containsAll(b); | 478 bool _same(Set a, Set b) => a.length == b.length && a.containsAll(b); |
456 | 479 |
457 /// An error message discovered while parsing the dependencies between files. | |
458 class DependencyGraphError extends MessageWithSpan { | |
459 const DependencyGraphError(String message, SourceSpan span) | |
460 : super(message, Level.SEVERE, span); | |
461 } | |
462 | |
463 /// Runtime files added to all applications when running the compiler in the | 480 /// Runtime files added to all applications when running the compiler in the |
464 /// command line. | 481 /// command line. |
465 final defaultRuntimeFiles = () { | 482 final defaultRuntimeFiles = () { |
466 var files = ['harmony_feature_check.js', 'dart_runtime.js',]; | 483 var files = ['harmony_feature_check.js', 'dart_runtime.js',]; |
467 files.addAll(corelibOrder.map((l) => l.replaceAll('.', '/') + '.js')); | 484 files.addAll(corelibOrder.map((l) => l.replaceAll('.', '/') + '.js')); |
468 return files; | 485 return files; |
469 }(); | 486 }(); |
470 | 487 |
471 /// Curated order to minimize lazy classes needed by dart:core and its | 488 /// Curated order to minimize lazy classes needed by dart:core and its |
472 /// transitive SDK imports. | 489 /// transitive SDK imports. |
(...skipping 19 matching lines...) Expand all Loading... |
492 'dart._interceptors', | 509 'dart._interceptors', |
493 'dart._native_typed_data', | 510 'dart._native_typed_data', |
494 */ | 511 */ |
495 ]; | 512 ]; |
496 | 513 |
497 /// Runtime files added to applications when running in server mode. | 514 /// Runtime files added to applications when running in server mode. |
498 final runtimeFilesForServerMode = new List<String>.from(defaultRuntimeFiles) | 515 final runtimeFilesForServerMode = new List<String>.from(defaultRuntimeFiles) |
499 ..addAll(const ['messages_widget.js', 'messages.css']); | 516 ..addAll(const ['messages_widget.js', 'messages.css']); |
500 | 517 |
501 final _log = new Logger('dev_compiler.dependency_graph'); | 518 final _log = new Logger('dev_compiler.dependency_graph'); |
OLD | NEW |