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, HashMap; | 8 import 'dart:collection' show HashSet, HashMap; |
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 UriBasedDirective; | 21 UriBasedDirective; |
22 import 'package:analyzer/src/generated/engine.dart' | 22 import 'package:analyzer/src/generated/engine.dart' |
23 show ParseDartTask, AnalysisContext; | 23 show ParseDartTask, AnalysisContext; |
24 import 'package:analyzer/src/generated/error.dart'; | |
24 import 'package:analyzer/src/generated/source.dart' show Source, SourceKind; | 25 import 'package:analyzer/src/generated/source.dart' show Source, SourceKind; |
25 import 'package:html/dom.dart' show Document, Node, Element; | 26 import 'package:html/dom.dart' show Document, Node, Element; |
26 import 'package:html/parser.dart' as html; | 27 import 'package:html/parser.dart' as html; |
27 import 'package:logging/logging.dart' show Logger, Level; | 28 import 'package:logging/logging.dart' show Logger, Level; |
28 import 'package:path/path.dart' as path; | 29 import 'package:path/path.dart' as path; |
29 | 30 |
30 import 'info.dart'; | 31 import 'info.dart'; |
31 import 'options.dart'; | 32 import 'options.dart'; |
32 import 'report.dart'; | 33 import 'report.dart'; |
33 | 34 |
34 /// Holds references to all source nodes in the import graph. This is mainly | 35 /// Holds references to all source nodes in the import graph. This is mainly |
35 /// used as a level of indirection to ensure that each source has a canonical | 36 /// used as a level of indirection to ensure that each source has a canonical |
36 /// representation. | 37 /// representation. |
37 class SourceGraph { | 38 class SourceGraph { |
38 /// All nodes in the source graph. Used to get a canonical representation for | 39 /// All nodes in the source graph. Used to get a canonical representation for |
39 /// any node. | 40 /// any node. |
40 final Map<Uri, SourceNode> nodes = {}; | 41 final Map<Uri, SourceNode> nodes = {}; |
41 | 42 |
42 /// Resources included by default on any application. | 43 /// Resources included by default on any application. |
43 final runtimeDeps = new Set<ResourceSourceNode>(); | 44 final runtimeDeps = new Set<ResourceSourceNode>(); |
44 | 45 |
45 /// Analyzer used to resolve source files. | 46 /// Analyzer used to resolve source files. |
46 final AnalysisContext _context; | 47 final AnalysisContext _context; |
47 final CompilerReporter _reporter; | 48 final AnalysisErrorListener _reporter; |
48 final CompilerOptions _options; | 49 final CompilerOptions _options; |
49 | 50 |
50 SourceGraph(this._context, this._reporter, this._options) { | 51 SourceGraph(this._context, this._reporter, this._options) { |
51 var dir = _options.runtimeDir; | 52 var dir = _options.runtimeDir; |
52 if (dir == null) { | 53 if (dir == null) { |
53 _log.severe('Runtime dir could not be determined automatically, ' | 54 _log.severe('Runtime dir could not be determined automatically, ' |
54 'please specify the --runtime-dir flag on the command line.'); | 55 'please specify the --runtime-dir flag on the command line.'); |
55 return; | 56 return; |
56 } | 57 } |
57 var prefix = path.absolute(dir); | 58 var prefix = path.absolute(dir); |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 final htmlResourceNodes = new HashMap<Element, ResourceSourceNode>(); | 175 final htmlResourceNodes = new HashMap<Element, ResourceSourceNode>(); |
175 | 176 |
176 HtmlSourceNode(SourceGraph graph, Uri uri, Source source) | 177 HtmlSourceNode(SourceGraph graph, Uri uri, Source source) |
177 : runtimeDeps = graph.runtimeDeps, | 178 : runtimeDeps = graph.runtimeDeps, |
178 super(graph, uri, source); | 179 super(graph, uri, source); |
179 | 180 |
180 @override | 181 @override |
181 void update() { | 182 void update() { |
182 super.update(); | 183 super.update(); |
183 if (needsRebuild) { | 184 if (needsRebuild) { |
184 graph._reporter.clearHtml(uri); | 185 var reporter = graph._reporter; |
186 if (reporter is SummaryReporter) { | |
187 reporter.clearHtml(uri); | |
188 } | |
185 document = html.parse(contents, generateSpans: true); | 189 document = html.parse(contents, generateSpans: true); |
186 var newScripts = new Set<DartSourceNode>(); | 190 var newScripts = new Set<DartSourceNode>(); |
187 var tags = document.querySelectorAll('script[type="application/dart"]'); | 191 var tags = document.querySelectorAll('script[type="application/dart"]'); |
188 for (var script in tags) { | 192 for (var script in tags) { |
189 var src = script.attributes['src']; | 193 var src = script.attributes['src']; |
190 if (src == null) { | 194 if (src == null) { |
191 _reportError(graph, 'inlined script tags not supported at this time ' | 195 _reportError(graph, 'inlined script tags not supported at this time ' |
192 '(see https://github.com/dart-lang/dart-dev-compiler/issues/54).', | 196 '(see https://github.com/dart-lang/dart-dev-compiler/issues/54).', |
193 script); | 197 script); |
194 continue; | 198 continue; |
(...skipping 30 matching lines...) Expand all Loading... | |
225 newResources.add(res); | 229 newResources.add(res); |
226 } | 230 } |
227 if (!_same(newResources, resources)) { | 231 if (!_same(newResources, resources)) { |
228 structureChanged = true; | 232 structureChanged = true; |
229 resources = newResources; | 233 resources = newResources; |
230 } | 234 } |
231 } | 235 } |
232 } | 236 } |
233 | 237 |
234 void _reportError(SourceGraph graph, String message, Node node) { | 238 void _reportError(SourceGraph graph, String message, Node node) { |
235 graph._reporter.enterHtml(_source.uri); | |
236 var span = node.sourceSpan; | 239 var span = node.sourceSpan; |
237 graph._reporter.log( | 240 |
238 new Message(message, Level.SEVERE, span.start.offset, span.end.offset)); | 241 // TODO(jmesserly): should these be errors or warnings? |
vsm
2015/07/09 23:54:07
Mostly look like real errors (e.g., inline scripts
Jennifer Messerly
2015/07/10 16:12:05
yeah, maybe ... on the other hand, HTML doesn't re
| |
239 graph._reporter.leaveHtml(); | 242 var errorCode = new HtmlWarningCode('dev_compiler.$runtimeType', message); |
243 graph._reporter.onError(new AnalysisError( | |
244 _source, span.start.offset, span.length, errorCode)); | |
240 } | 245 } |
241 } | 246 } |
242 | 247 |
243 /// A node representing a Dart library or part. | 248 /// A node representing a Dart library or part. |
244 class DartSourceNode extends SourceNode { | 249 class DartSourceNode extends SourceNode { |
245 /// Set of imported libraries (empty for part files). | 250 /// Set of imported libraries (empty for part files). |
246 Set<DartSourceNode> imports = new Set<DartSourceNode>(); | 251 Set<DartSourceNode> imports = new Set<DartSourceNode>(); |
247 | 252 |
248 /// Set of exported libraries (empty for part files). | 253 /// Set of exported libraries (empty for part files). |
249 Set<DartSourceNode> exports = new Set<DartSourceNode>(); | 254 Set<DartSourceNode> exports = new Set<DartSourceNode>(); |
(...skipping 24 matching lines...) Expand all Loading... | |
274 // But we could discard it after that point. | 279 // But we could discard it after that point. |
275 void saveUpdatedContents() { | 280 void saveUpdatedContents() { |
276 graph._context.setContents(_source, _source.contents.data); | 281 graph._context.setContents(_source, _source.contents.data); |
277 } | 282 } |
278 | 283 |
279 @override | 284 @override |
280 void update() { | 285 void update() { |
281 super.update(); | 286 super.update(); |
282 | 287 |
283 if (needsRebuild) { | 288 if (needsRebuild) { |
284 graph._reporter.clearLibrary(uri); | 289 var reporter = graph._reporter; |
290 if (reporter is SummaryReporter) { | |
291 reporter.clearLibrary(uri); | |
292 } | |
293 | |
285 // If the defining compilation-unit changed, the structure might have | 294 // If the defining compilation-unit changed, the structure might have |
286 // changed. | 295 // changed. |
287 var unit = parseDirectives(contents, name: _source.fullName); | 296 var unit = parseDirectives(contents, name: _source.fullName); |
288 var newImports = new Set<DartSourceNode>(); | 297 var newImports = new Set<DartSourceNode>(); |
289 var newExports = new Set<DartSourceNode>(); | 298 var newExports = new Set<DartSourceNode>(); |
290 var newParts = new Set<DartSourceNode>(); | 299 var newParts = new Set<DartSourceNode>(); |
291 for (var d in unit.directives) { | 300 for (var d in unit.directives) { |
292 // Nothing to do for parts. | 301 // Nothing to do for parts. |
293 if (d is PartOfDirective) return; | 302 if (d is PartOfDirective) return; |
294 if (d is LibraryDirective) continue; | 303 if (d is LibraryDirective) continue; |
295 | 304 |
296 var directiveUri = (d as UriBasedDirective).uri; | 305 var directiveUri = (d as UriBasedDirective).uri; |
297 | 306 |
298 // `dart:core` and other similar URLs only contain a name, but it is | 307 // `dart:core` and other similar URLs only contain a name, but it is |
299 // meant to be a folder when resolving relative paths from it. | 308 // meant to be a folder when resolving relative paths from it. |
300 var targetUri = uri.scheme == 'dart' && uri.pathSegments.length == 1 | 309 var targetUri = uri.scheme == 'dart' && uri.pathSegments.length == 1 |
301 ? Uri.parse('$uri/').resolve(directiveUri.stringValue) | 310 ? Uri.parse('$uri/').resolve(directiveUri.stringValue) |
302 : uri.resolve(directiveUri.stringValue); | 311 : uri.resolve(directiveUri.stringValue); |
303 var target = | 312 var target = |
304 ParseDartTask.resolveDirective(graph._context, _source, d, null); | 313 ParseDartTask.resolveDirective(graph._context, _source, d, null); |
305 var node = graph.nodes.putIfAbsent( | 314 var node = graph.nodes.putIfAbsent( |
306 targetUri, () => new DartSourceNode(graph, targetUri, target)); | 315 targetUri, () => new DartSourceNode(graph, targetUri, target)); |
307 //var node = graph.nodeFromUri(targetUri); | 316 //var node = graph.nodeFromUri(targetUri); |
308 if (node._source == null || !node._source.exists()) { | 317 if (node._source == null || !node._source.exists()) { |
309 _reportError(graph, 'File $targetUri not found', unit, d); | 318 _reportError(graph, 'File $targetUri not found', d); |
310 } | 319 } |
311 | 320 |
312 if (d is ImportDirective) { | 321 if (d is ImportDirective) { |
313 newImports.add(node); | 322 newImports.add(node); |
314 } else if (d is ExportDirective) { | 323 } else if (d is ExportDirective) { |
315 newExports.add(node); | 324 newExports.add(node); |
316 } else if (d is PartDirective) { | 325 } else if (d is PartDirective) { |
317 newParts.add(node); | 326 newParts.add(node); |
318 } | 327 } |
319 } | 328 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
353 for (var p in parts) { | 362 for (var p in parts) { |
354 // Technically for parts we don't need to look at the contents. If they | 363 // Technically for parts we don't need to look at the contents. If they |
355 // contain imports, exports, or parts, we'll ignore them in our crawling. | 364 // contain imports, exports, or parts, we'll ignore them in our crawling. |
356 // However we do a full update to make it easier to adjust when users | 365 // However we do a full update to make it easier to adjust when users |
357 // switch a file from a part to a library. | 366 // switch a file from a part to a library. |
358 p.update(); | 367 p.update(); |
359 if (p.needsRebuild) needsRebuild = true; | 368 if (p.needsRebuild) needsRebuild = true; |
360 } | 369 } |
361 } | 370 } |
362 | 371 |
363 void _reportError( | 372 void _reportError(SourceGraph graph, String message, AstNode node) { |
364 SourceGraph graph, String message, CompilationUnit unit, AstNode node) { | 373 graph._reporter.onError(new AnalysisError(_source, node.offset, |
365 graph._reporter | 374 node.length, new CompileTimeErrorCode('dev_compiler.$runtimeType', messa ge))); |
366 ..enterLibrary(_source.uri) | |
367 ..enterCompilationUnit(unit, _source) | |
368 ..log(new Message(message, Level.SEVERE, node.offset, node.end)) | |
369 ..leaveCompilationUnit() | |
370 ..leaveLibrary(); | |
371 } | 375 } |
372 } | 376 } |
373 | 377 |
374 /// Represents a runtime resource from our compiler that is needed to run an | 378 /// Represents a runtime resource from our compiler that is needed to run an |
375 /// application. | 379 /// application. |
376 class ResourceSourceNode extends SourceNode { | 380 class ResourceSourceNode extends SourceNode { |
377 ResourceSourceNode(graph, uri, source) : super(graph, uri, source); | 381 ResourceSourceNode(graph, uri, source) : super(graph, uri, source); |
378 } | 382 } |
379 | 383 |
380 /// Updates the structure and `needsRebuild` marks in nodes of [graph] reachable | 384 /// Updates the structure and `needsRebuild` marks in nodes of [graph] reachable |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
539 // _foreign_helper is not included, as it only defines the JS builtin that | 543 // _foreign_helper is not included, as it only defines the JS builtin that |
540 // the compiler handles at compile time. | 544 // the compiler handles at compile time. |
541 ]; | 545 ]; |
542 | 546 |
543 /// Runtime files added to applications when running in server mode. | 547 /// Runtime files added to applications when running in server mode. |
544 List<String> runtimeFilesForServerMode([bool includeWidget = true]) => | 548 List<String> runtimeFilesForServerMode([bool includeWidget = true]) => |
545 new List<String>.from(defaultRuntimeFiles) | 549 new List<String>.from(defaultRuntimeFiles) |
546 ..addAll(includeWidget ? const ['messages_widget.js', 'messages.css'] : []); | 550 ..addAll(includeWidget ? const ['messages_widget.js', 'messages.css'] : []); |
547 | 551 |
548 final _log = new Logger('dev_compiler.dependency_graph'); | 552 final _log = new Logger('dev_compiler.dependency_graph'); |
OLD | NEW |