OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 library dart2js.library_loader; | 5 library dart2js.library_loader; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 | 8 |
9 import 'common.dart'; | 9 import 'common.dart'; |
10 import 'common/names.dart' show | 10 import 'common/names.dart' show Uris; |
11 Uris; | 11 import 'common/tasks.dart' show CompilerTask; |
12 import 'common/tasks.dart' show | 12 import 'compiler.dart' show Compiler; |
13 CompilerTask; | 13 import 'elements/elements.dart' |
14 import 'compiler.dart' show | 14 show |
15 Compiler; | 15 CompilationUnitElement, |
16 import 'elements/elements.dart' show | 16 Element, |
17 CompilationUnitElement, | 17 ImportElement, |
18 Element, | 18 ExportElement, |
19 ImportElement, | 19 LibraryElement, |
20 ExportElement, | 20 PrefixElement; |
21 LibraryElement, | 21 import 'elements/modelx.dart' |
22 PrefixElement; | 22 show |
23 import 'elements/modelx.dart' show | 23 CompilationUnitElementX, |
24 CompilationUnitElementX, | 24 DeferredLoaderGetterElementX, |
25 DeferredLoaderGetterElementX, | 25 ErroneousElementX, |
26 ErroneousElementX, | 26 ExportElementX, |
27 ExportElementX, | 27 ImportElementX, |
28 ImportElementX, | 28 LibraryElementX, |
29 LibraryElementX, | 29 LibraryDependencyElementX, |
30 LibraryDependencyElementX, | 30 PrefixElementX, |
31 PrefixElementX, | 31 SyntheticImportElement; |
32 SyntheticImportElement; | |
33 import 'environment.dart'; | 32 import 'environment.dart'; |
34 import 'script.dart'; | 33 import 'script.dart'; |
35 import 'serialization/serialization.dart' show LibraryDeserializer; | 34 import 'serialization/serialization.dart' show LibraryDeserializer; |
36 import 'tree/tree.dart'; | 35 import 'tree/tree.dart'; |
37 import 'util/util.dart' show | 36 import 'util/util.dart' show Link, LinkBuilder; |
38 Link, | |
39 LinkBuilder; | |
40 | 37 |
41 /** | 38 /** |
42 * [CompilerTask] for loading libraries and setting up the import/export scopes. | 39 * [CompilerTask] for loading libraries and setting up the import/export scopes. |
43 * | 40 * |
44 * The library loader uses four different kinds of URIs in different parts of | 41 * The library loader uses four different kinds of URIs in different parts of |
45 * the loading process. | 42 * the loading process. |
46 * | 43 * |
47 * ## User URI ## | 44 * ## User URI ## |
48 * | 45 * |
49 * A 'user URI' is a URI provided by the user in code and as the main entry URI | 46 * A 'user URI' is a URI provided by the user in code and as the main entry URI |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 * that these imports | 123 * that these imports |
127 * | 124 * |
128 * import 'package:foo.dart' as a; | 125 * import 'package:foo.dart' as a; |
129 * import 'packages/foo.dart' as b; | 126 * import 'packages/foo.dart' as b; |
130 * | 127 * |
131 * do _not_ resolve to the same library when the package root URI happens to | 128 * do _not_ resolve to the same library when the package root URI happens to |
132 * point to the 'packages' folder. | 129 * point to the 'packages' folder. |
133 * | 130 * |
134 */ | 131 */ |
135 abstract class LibraryLoaderTask implements CompilerTask { | 132 abstract class LibraryLoaderTask implements CompilerTask { |
136 factory LibraryLoaderTask(Compiler compiler, | 133 factory LibraryLoaderTask( |
| 134 Compiler compiler, |
137 ResolvedUriTranslator uriTranslator, | 135 ResolvedUriTranslator uriTranslator, |
138 ScriptLoader scriptLoader, | 136 ScriptLoader scriptLoader, |
139 ElementScanner scriptScanner, | 137 ElementScanner scriptScanner, |
140 LibraryDeserializer deserializer, | 138 LibraryDeserializer deserializer, |
141 LibraryLoaderListener listener, | 139 LibraryLoaderListener listener, |
142 Environment environment) = _LibraryLoaderTask; | 140 Environment environment) = _LibraryLoaderTask; |
143 | 141 |
144 /// Returns all libraries that have been loaded. | 142 /// Returns all libraries that have been loaded. |
145 Iterable<LibraryElement> get libraries; | 143 Iterable<LibraryElement> get libraries; |
146 | 144 |
147 /// Looks up the library with the [canonicalUri]. | 145 /// Looks up the library with the [canonicalUri]. |
148 LibraryElement lookupLibrary(Uri canonicalUri); | 146 LibraryElement lookupLibrary(Uri canonicalUri); |
149 | 147 |
150 /// Loads the library specified by the [resolvedUri] and returns its | 148 /// Loads the library specified by the [resolvedUri] and returns its |
151 /// [LibraryElement]. | 149 /// [LibraryElement]. |
152 /// | 150 /// |
153 /// If the library is not already loaded, the method creates the | 151 /// If the library is not already loaded, the method creates the |
154 /// [LibraryElement] for the library and computes the import/export scope, | 152 /// [LibraryElement] for the library and computes the import/export scope, |
155 /// loading and computing the import/export scopes of all required libraries | 153 /// loading and computing the import/export scopes of all required libraries |
156 /// in the process. The method handles cyclic dependency between libraries. | 154 /// in the process. The method handles cyclic dependency between libraries. |
157 /// | 155 /// |
158 /// If [skipFileWithPartOfTag] is `true`, `null` is returned if the | 156 /// If [skipFileWithPartOfTag] is `true`, `null` is returned if the |
159 /// compilation unit for [resolvedUri] contains a `part of` tag. This is only | 157 /// compilation unit for [resolvedUri] contains a `part of` tag. This is only |
160 /// used for analysis through [Compiler.analyzeUri]. | 158 /// used for analysis through [Compiler.analyzeUri]. |
161 Future<LibraryElement> loadLibrary( | 159 Future<LibraryElement> loadLibrary(Uri resolvedUri, |
162 Uri resolvedUri, | |
163 {bool skipFileWithPartOfTag: false}); | 160 {bool skipFileWithPartOfTag: false}); |
164 | 161 |
165 /// Reset the library loader task to prepare for compilation. If provided, | 162 /// Reset the library loader task to prepare for compilation. If provided, |
166 /// libraries matching [reuseLibrary] are reused. | 163 /// libraries matching [reuseLibrary] are reused. |
167 /// | 164 /// |
168 /// This method is used for incremental compilation. | 165 /// This method is used for incremental compilation. |
169 void reset({bool reuseLibrary(LibraryElement library)}); | 166 void reset({bool reuseLibrary(LibraryElement library)}); |
170 | 167 |
171 /// Asynchronous version of [reset]. | 168 /// Asynchronous version of [reset]. |
172 Future resetAsync(Future<bool> reuseLibrary(LibraryElement library)); | 169 Future resetAsync(Future<bool> reuseLibrary(LibraryElement library)); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 final LibraryDeserializer deserializer; | 283 final LibraryDeserializer deserializer; |
287 | 284 |
288 /// Hooks to inform others about progress done by this loader. | 285 /// Hooks to inform others about progress done by this loader. |
289 // TODO(sigmund): move away from this. | 286 // TODO(sigmund): move away from this. |
290 final LibraryLoaderListener listener; | 287 final LibraryLoaderListener listener; |
291 | 288 |
292 /// Definitions provided via the `-D` command line flags. Used to resolve | 289 /// Definitions provided via the `-D` command line flags. Used to resolve |
293 /// conditional imports. | 290 /// conditional imports. |
294 final Environment environment; | 291 final Environment environment; |
295 | 292 |
296 _LibraryLoaderTask( | 293 _LibraryLoaderTask(Compiler compiler, this.uriTranslator, this.scriptLoader, |
297 Compiler compiler, this.uriTranslator, this.scriptLoader, | |
298 this.scanner, this.deserializer, this.listener, this.environment) | 294 this.scanner, this.deserializer, this.listener, this.environment) |
299 // TODO(sigmund): make measurements separate from compiler | 295 // TODO(sigmund): make measurements separate from compiler |
300 : super(compiler); | 296 : super(compiler); |
301 | 297 |
302 String get name => 'LibraryLoader'; | 298 String get name => 'LibraryLoader'; |
303 | 299 |
304 final Map<Uri, LibraryElement> libraryCanonicalUriMap = | 300 final Map<Uri, LibraryElement> libraryCanonicalUriMap = |
305 new Map<Uri, LibraryElement>(); | 301 new Map<Uri, LibraryElement>(); |
306 final Map<Uri, LibraryElement> libraryResourceUriMap = | 302 final Map<Uri, LibraryElement> libraryResourceUriMap = |
307 new Map<Uri, LibraryElement>(); | 303 new Map<Uri, LibraryElement>(); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 Future resetAsync(Future<bool> reuseLibrary(LibraryElement library)) { | 344 Future resetAsync(Future<bool> reuseLibrary(LibraryElement library)) { |
349 return measure(() { | 345 return measure(() { |
350 assert(currentHandler == null); | 346 assert(currentHandler == null); |
351 | 347 |
352 wrapper(lib) => reuseLibrary(lib).then((reuse) => reuse ? lib : null); | 348 wrapper(lib) => reuseLibrary(lib).then((reuse) => reuse ? lib : null); |
353 List<Future<LibraryElement>> reusedLibrariesFuture = | 349 List<Future<LibraryElement>> reusedLibrariesFuture = |
354 // TODO(sigmund): make measurements separate from compiler | 350 // TODO(sigmund): make measurements separate from compiler |
355 compiler.reuseLibraryTask.measure( | 351 compiler.reuseLibraryTask.measure( |
356 () => libraryCanonicalUriMap.values.map(wrapper).toList()); | 352 () => libraryCanonicalUriMap.values.map(wrapper).toList()); |
357 | 353 |
358 return Future.wait(reusedLibrariesFuture).then( | 354 return Future |
359 (List<LibraryElement> reusedLibraries) { | 355 .wait(reusedLibrariesFuture) |
360 resetImplementation(reusedLibraries.where((e) => e != null)); | 356 .then((List<LibraryElement> reusedLibraries) { |
361 }); | 357 resetImplementation(reusedLibraries.where((e) => e != null)); |
| 358 }); |
362 }); | 359 }); |
363 } | 360 } |
364 | 361 |
365 /// Insert [library] in the internal maps. Used for compiler reuse. | 362 /// Insert [library] in the internal maps. Used for compiler reuse. |
366 void mapLibrary(LibraryElement library) { | 363 void mapLibrary(LibraryElement library) { |
367 libraryCanonicalUriMap[library.canonicalUri] = library; | 364 libraryCanonicalUriMap[library.canonicalUri] = library; |
368 | 365 |
369 Uri resourceUri = library.entryCompilationUnit.script.resourceUri; | 366 Uri resourceUri = library.entryCompilationUnit.script.resourceUri; |
370 libraryResourceUriMap[resourceUri] = library; | 367 libraryResourceUriMap[resourceUri] = library; |
371 | 368 |
372 if (library.hasLibraryName) { | 369 if (library.hasLibraryName) { |
373 String name = library.libraryName; | 370 String name = library.libraryName; |
374 libraryNames[name] = library; | 371 libraryNames[name] = library; |
375 } | 372 } |
376 } | 373 } |
377 | 374 |
378 Future<LibraryElement> loadLibrary(Uri resolvedUri, | 375 Future<LibraryElement> loadLibrary(Uri resolvedUri, |
379 {bool skipFileWithPartOfTag: false}) { | 376 {bool skipFileWithPartOfTag: false}) { |
380 return measure(() { | 377 return measure(() { |
381 assert(currentHandler == null); | 378 assert(currentHandler == null); |
382 // TODO(johnniwinther): Ensure that currentHandler correctly encloses the | 379 // TODO(johnniwinther): Ensure that currentHandler correctly encloses the |
383 // loading of a library cluster. | 380 // loading of a library cluster. |
384 currentHandler = new LibraryDependencyHandler(this); | 381 currentHandler = new LibraryDependencyHandler(this); |
385 return createLibrary(currentHandler, null, resolvedUri, | 382 return createLibrary(currentHandler, null, resolvedUri, |
386 skipFileWithPartOfTag: skipFileWithPartOfTag) | 383 skipFileWithPartOfTag: skipFileWithPartOfTag) |
387 .then((LibraryElement library) { | 384 .then((LibraryElement library) { |
388 if (library == null) { | 385 if (library == null) { |
389 currentHandler = null; | 386 currentHandler = null; |
390 return null; | 387 return null; |
391 } | 388 } |
392 return reporter.withCurrentElement(library, () { | 389 return reporter.withCurrentElement(library, () { |
393 return measure(() { | 390 return measure(() { |
394 currentHandler.computeExports(); | 391 currentHandler.computeExports(); |
395 LoadedLibraries loadedLibraries = new _LoadedLibraries( | 392 LoadedLibraries loadedLibraries = new _LoadedLibraries(library, |
396 library, | 393 currentHandler.newLibraries, currentHandler.nodeMap, this); |
397 currentHandler.newLibraries, | |
398 currentHandler.nodeMap, | |
399 this); | |
400 currentHandler = null; | 394 currentHandler = null; |
401 return listener.onLibrariesLoaded(loadedLibraries) | 395 return listener |
| 396 .onLibrariesLoaded(loadedLibraries) |
402 .then((_) => library); | 397 .then((_) => library); |
403 }); | 398 }); |
404 }); | 399 }); |
405 }); | 400 }); |
406 }); | 401 }); |
407 } | 402 } |
408 | 403 |
409 /** | 404 /** |
410 * Processes the library tags in [library]. | 405 * Processes the library tags in [library]. |
411 * | 406 * |
412 * The imported/exported libraries are loaded and processed recursively but | 407 * The imported/exported libraries are loaded and processed recursively but |
413 * the import/export scopes are not set up. | 408 * the import/export scopes are not set up. |
414 */ | 409 */ |
415 Future processLibraryTags(LibraryDependencyHandler handler, | 410 Future processLibraryTags( |
416 LibraryElementX library) { | 411 LibraryDependencyHandler handler, LibraryElementX library) { |
417 TagState tagState = new TagState(); | 412 TagState tagState = new TagState(); |
418 | 413 |
419 bool importsDartCore = false; | 414 bool importsDartCore = false; |
420 LinkBuilder<LibraryDependencyElementX> libraryDependencies = | 415 LinkBuilder<LibraryDependencyElementX> libraryDependencies = |
421 new LinkBuilder<LibraryDependencyElementX>(); | 416 new LinkBuilder<LibraryDependencyElementX>(); |
422 Uri base = library.entryCompilationUnit.script.readableUri; | 417 Uri base = library.entryCompilationUnit.script.readableUri; |
423 | 418 |
424 return Future.forEach(library.tags, (LibraryTag tag) { | 419 return Future.forEach(library.tags, (LibraryTag tag) { |
425 return reporter.withCurrentElement(library, () { | 420 return reporter.withCurrentElement(library, () { |
426 | |
427 Uri computeUri(LibraryDependency node) { | 421 Uri computeUri(LibraryDependency node) { |
428 StringNode uriNode = node.uri; | 422 StringNode uriNode = node.uri; |
429 if (node.conditionalUris != null) { | 423 if (node.conditionalUris != null) { |
430 for (ConditionalUri conditionalUri in node.conditionalUris) { | 424 for (ConditionalUri conditionalUri in node.conditionalUris) { |
431 String key = conditionalUri.key.slowNameString; | 425 String key = conditionalUri.key.slowNameString; |
432 String value = conditionalUri.value == null | 426 String value = conditionalUri.value == null |
433 ? "true" | 427 ? "true" |
434 : conditionalUri.value.dartString.slowToString(); | 428 : conditionalUri.value.dartString.slowToString(); |
435 String actual = environment.valueOf(key); | 429 String actual = environment.valueOf(key); |
436 if (value == actual) { | 430 if (value == actual) { |
437 uriNode = conditionalUri.uri; | 431 uriNode = conditionalUri.uri; |
438 break; | 432 break; |
439 } | 433 } |
440 } | 434 } |
441 } | 435 } |
442 String tagUriString = uriNode.dartString.slowToString(); | 436 String tagUriString = uriNode.dartString.slowToString(); |
443 try { | 437 try { |
444 return Uri.parse(tagUriString); | 438 return Uri.parse(tagUriString); |
445 } on FormatException { | 439 } on FormatException { |
446 reporter.reportErrorMessage( | 440 reporter.reportErrorMessage( |
447 node.uri, | 441 node.uri, MessageKind.INVALID_URI, {'uri': tagUriString}); |
448 MessageKind.INVALID_URI, {'uri': tagUriString}); | |
449 return null; | 442 return null; |
450 } | 443 } |
451 } | 444 } |
452 | 445 |
453 if (tag.isImport) { | 446 if (tag.isImport) { |
454 Uri uri = computeUri(tag); | 447 Uri uri = computeUri(tag); |
455 if (uri == null) { | 448 if (uri == null) { |
456 // Skip this erroneous import. | 449 // Skip this erroneous import. |
457 return new Future.value(); | 450 return new Future.value(); |
458 } | 451 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 }).then((_) { | 490 }).then((_) { |
498 return listener.onLibraryScanned(library, handler); | 491 return listener.onLibraryScanned(library, handler); |
499 }).then((_) { | 492 }).then((_) { |
500 return reporter.withCurrentElement(library, () { | 493 return reporter.withCurrentElement(library, () { |
501 checkDuplicatedLibraryName(library); | 494 checkDuplicatedLibraryName(library); |
502 | 495 |
503 // Import dart:core if not already imported. | 496 // Import dart:core if not already imported. |
504 if (!importsDartCore && library.canonicalUri != Uris.dart_core) { | 497 if (!importsDartCore && library.canonicalUri != Uris.dart_core) { |
505 return createLibrary(handler, null, Uris.dart_core) | 498 return createLibrary(handler, null, Uris.dart_core) |
506 .then((LibraryElement coreLibrary) { | 499 .then((LibraryElement coreLibrary) { |
507 handler.registerDependency(library, | 500 handler.registerDependency( |
| 501 library, |
508 new SyntheticImportElement( | 502 new SyntheticImportElement( |
509 library.entryCompilationUnit, Uris.dart_core), | 503 library.entryCompilationUnit, Uris.dart_core), |
510 coreLibrary); | 504 coreLibrary); |
511 }); | 505 }); |
512 } | 506 } |
513 }); | 507 }); |
514 }).then((_) { | 508 }).then((_) { |
515 return Future.forEach(libraryDependencies.toList(), | 509 return Future.forEach(libraryDependencies.toList(), |
516 (LibraryDependencyElementX libraryDependency) { | 510 (LibraryDependencyElementX libraryDependency) { |
517 return reporter.withCurrentElement(library, () { | 511 return reporter.withCurrentElement(library, () { |
518 return registerLibraryFromImportExport( | 512 return registerLibraryFromImportExport( |
519 handler, library, libraryDependency); | 513 handler, library, libraryDependency); |
520 }); | 514 }); |
521 }); | 515 }); |
522 }); | 516 }); |
523 } | 517 } |
524 | 518 |
525 void checkDuplicatedLibraryName(LibraryElement library) { | 519 void checkDuplicatedLibraryName(LibraryElement library) { |
526 if (library.isInternalLibrary) return; | 520 if (library.isInternalLibrary) return; |
527 Uri resourceUri = library.entryCompilationUnit.script.resourceUri; | 521 Uri resourceUri = library.entryCompilationUnit.script.resourceUri; |
528 LibraryElement existing = | 522 LibraryElement existing = |
529 libraryResourceUriMap.putIfAbsent(resourceUri, () => library); | 523 libraryResourceUriMap.putIfAbsent(resourceUri, () => library); |
530 if (!identical(existing, library)) { | 524 if (!identical(existing, library)) { |
531 if (library.hasLibraryName) { | 525 if (library.hasLibraryName) { |
532 reporter.withCurrentElement(library, () { | 526 reporter.withCurrentElement(library, () { |
533 reporter.reportWarningMessage( | 527 reporter.reportWarningMessage( |
534 library, | 528 library, MessageKind.DUPLICATED_LIBRARY_RESOURCE, { |
535 MessageKind.DUPLICATED_LIBRARY_RESOURCE, | 529 'libraryName': library.libraryName, |
536 {'libraryName': library.libraryName, | 530 'resourceUri': resourceUri, |
537 'resourceUri': resourceUri, | 531 'canonicalUri1': library.canonicalUri, |
538 'canonicalUri1': library.canonicalUri, | 532 'canonicalUri2': existing.canonicalUri |
539 'canonicalUri2': existing.canonicalUri}); | 533 }); |
540 }); | 534 }); |
541 } else { | 535 } else { |
542 reporter.reportHintMessage( | 536 reporter.reportHintMessage(library, MessageKind.DUPLICATED_RESOURCE, { |
543 library, | 537 'resourceUri': resourceUri, |
544 MessageKind.DUPLICATED_RESOURCE, | 538 'canonicalUri1': library.canonicalUri, |
545 {'resourceUri': resourceUri, | 539 'canonicalUri2': existing.canonicalUri |
546 'canonicalUri1': library.canonicalUri, | 540 }); |
547 'canonicalUri2': existing.canonicalUri}); | |
548 } | 541 } |
549 } else if (library.hasLibraryName) { | 542 } else if (library.hasLibraryName) { |
550 String name = library.libraryName; | 543 String name = library.libraryName; |
551 existing = libraryNames.putIfAbsent(name, () => library); | 544 existing = libraryNames.putIfAbsent(name, () => library); |
552 if (!identical(existing, library)) { | 545 if (!identical(existing, library)) { |
553 reporter.withCurrentElement(library, () { | 546 reporter.withCurrentElement(library, () { |
554 reporter.reportWarningMessage( | 547 reporter.reportWarningMessage(library, |
555 library, | 548 MessageKind.DUPLICATED_LIBRARY_NAME, {'libraryName': name}); |
556 MessageKind.DUPLICATED_LIBRARY_NAME, | |
557 {'libraryName': name}); | |
558 }); | 549 }); |
559 reporter.withCurrentElement(existing, () { | 550 reporter.withCurrentElement(existing, () { |
560 reporter.reportWarningMessage( | 551 reporter.reportWarningMessage(existing, |
561 existing, | 552 MessageKind.DUPLICATED_LIBRARY_NAME, {'libraryName': name}); |
562 MessageKind.DUPLICATED_LIBRARY_NAME, | |
563 {'libraryName': name}); | |
564 }); | 553 }); |
565 } | 554 } |
566 } | 555 } |
567 } | 556 } |
568 | 557 |
569 /** | 558 /** |
570 * Handle a part tag in the scope of [library]. The [resolvedUri] given is | 559 * Handle a part tag in the scope of [library]. The [resolvedUri] given is |
571 * used as is, any URI resolution should be done beforehand. | 560 * used as is, any URI resolution should be done beforehand. |
572 */ | 561 */ |
573 Future scanPart(Part part, Uri resolvedUri, LibraryElement library) { | 562 Future scanPart(Part part, Uri resolvedUri, LibraryElement library) { |
574 if (!resolvedUri.isAbsolute) throw new ArgumentError(resolvedUri); | 563 if (!resolvedUri.isAbsolute) throw new ArgumentError(resolvedUri); |
575 Uri readableUri = uriTranslator.translate(library, resolvedUri, part); | 564 Uri readableUri = uriTranslator.translate(library, resolvedUri, part); |
576 if (readableUri == null) return new Future.value(); | 565 if (readableUri == null) return new Future.value(); |
577 return reporter.withCurrentElement(library, () { | 566 return reporter.withCurrentElement(library, () { |
578 return scriptLoader.readScript(readableUri, part).then((Script script) { | 567 return scriptLoader.readScript(readableUri, part).then((Script script) { |
579 if (script == null) return; | 568 if (script == null) return; |
580 createUnitSync(script, library); | 569 createUnitSync(script, library); |
581 }); | 570 }); |
582 }); | 571 }); |
583 } | 572 } |
584 | 573 |
585 /** | 574 /** |
586 * Handle an import/export tag by loading the referenced library and | 575 * Handle an import/export tag by loading the referenced library and |
587 * registering its dependency in [handler] for the computation of the import/ | 576 * registering its dependency in [handler] for the computation of the import/ |
588 * export scope. If the tag does not contain a valid URI, then its dependency | 577 * export scope. If the tag does not contain a valid URI, then its dependency |
589 * is not registered in [handler]. | 578 * is not registered in [handler]. |
590 */ | 579 */ |
591 Future<Null> registerLibraryFromImportExport( | 580 Future<Null> registerLibraryFromImportExport(LibraryDependencyHandler handler, |
592 LibraryDependencyHandler handler, | 581 LibraryElement library, LibraryDependencyElementX libraryDependency) { |
593 LibraryElement library, | |
594 LibraryDependencyElementX libraryDependency) { | |
595 Uri base = library.canonicalUri; | 582 Uri base = library.canonicalUri; |
596 Uri resolvedUri = base.resolveUri(libraryDependency.uri); | 583 Uri resolvedUri = base.resolveUri(libraryDependency.uri); |
597 return createLibrary(handler, library, resolvedUri, node: libraryDependency) | 584 return createLibrary(handler, library, resolvedUri, node: libraryDependency) |
598 .then((LibraryElement loadedLibrary) { | 585 .then((LibraryElement loadedLibrary) { |
599 if (loadedLibrary == null) return; | 586 if (loadedLibrary == null) return; |
600 reporter.withCurrentElement(library, () { | 587 reporter.withCurrentElement(library, () { |
601 libraryDependency.libraryDependency = loadedLibrary; | 588 libraryDependency.libraryDependency = loadedLibrary; |
602 handler.registerDependency( | 589 handler.registerDependency(library, libraryDependency, loadedLibrary); |
603 library, libraryDependency, loadedLibrary); | 590 }); |
604 }); | 591 }); |
605 }); | |
606 } | 592 } |
607 | 593 |
608 /// Loads the deserialized [library] with the [handler]. | 594 /// Loads the deserialized [library] with the [handler]. |
609 /// | 595 /// |
610 /// All libraries imported or exported transitively from [library] will be | 596 /// All libraries imported or exported transitively from [library] will be |
611 /// loaded as well. | 597 /// loaded as well. |
612 Future<LibraryElement> loadDeserializedLibrary( | 598 Future<LibraryElement> loadDeserializedLibrary( |
613 LibraryDependencyHandler handler, | 599 LibraryDependencyHandler handler, LibraryElement library) { |
614 LibraryElement library) { | |
615 libraryCanonicalUriMap[library.canonicalUri] = library; | 600 libraryCanonicalUriMap[library.canonicalUri] = library; |
616 handler.registerNewLibrary(library); | 601 handler.registerNewLibrary(library); |
617 return listener.onLibraryScanned(library, handler).then((_) { | 602 return listener.onLibraryScanned(library, handler).then((_) { |
618 return Future.forEach(library.imports, (ImportElement import) { | 603 return Future.forEach(library.imports, (ImportElement import) { |
619 return createLibrary(handler, library, import.uri); | 604 return createLibrary(handler, library, import.uri); |
620 }).then((_) { | 605 }).then((_) { |
621 return Future.forEach(library.exports, (ExportElement export) { | 606 return Future.forEach(library.exports, (ExportElement export) { |
622 return createLibrary(handler, library, export.uri); | 607 return createLibrary(handler, library, export.uri); |
623 }).then((_) => library); | 608 }).then((_) => library); |
624 }); | 609 }); |
625 }); | 610 }); |
626 } | 611 } |
627 | 612 |
628 Future<Script> _readScript(Spannable spannable, | 613 Future<Script> _readScript( |
629 Uri readableUri, Uri resolvedUri) { | 614 Spannable spannable, Uri readableUri, Uri resolvedUri) { |
630 if (readableUri == null) { | 615 if (readableUri == null) { |
631 return new Future.value(new Script.synthetic(resolvedUri)); | 616 return new Future.value(new Script.synthetic(resolvedUri)); |
632 } else { | 617 } else { |
633 return scriptLoader.readScript(readableUri, spannable); | 618 return scriptLoader.readScript(readableUri, spannable); |
634 } | 619 } |
635 } | 620 } |
636 | 621 |
637 /** | 622 /** |
638 * Create (or reuse) a library element for the library specified by the | 623 * Create (or reuse) a library element for the library specified by the |
639 * [resolvedUri]. | 624 * [resolvedUri]. |
640 * | 625 * |
641 * If a new library is created, the [handler] is notified. | 626 * If a new library is created, the [handler] is notified. |
642 */ | 627 */ |
643 Future<LibraryElement> createLibrary( | 628 Future<LibraryElement> createLibrary(LibraryDependencyHandler handler, |
644 LibraryDependencyHandler handler, | 629 LibraryElement importingLibrary, Uri resolvedUri, |
645 LibraryElement importingLibrary, | 630 {Spannable node, bool skipFileWithPartOfTag: false}) { |
646 Uri resolvedUri, | |
647 {Spannable node, | |
648 bool skipFileWithPartOfTag: false}) { | |
649 Uri readableUri = | 631 Uri readableUri = |
650 uriTranslator.translate(importingLibrary, resolvedUri, node); | 632 uriTranslator.translate(importingLibrary, resolvedUri, node); |
651 LibraryElement library = libraryCanonicalUriMap[resolvedUri]; | 633 LibraryElement library = libraryCanonicalUriMap[resolvedUri]; |
652 if (library != null) { | 634 if (library != null) { |
653 return new Future.value(library); | 635 return new Future.value(library); |
654 } | 636 } |
655 library = deserializer.readLibrary(resolvedUri); | 637 library = deserializer.readLibrary(resolvedUri); |
656 if (library != null) { | 638 if (library != null) { |
657 return loadDeserializedLibrary(handler, library); | 639 return loadDeserializedLibrary(handler, library); |
658 } | 640 } |
(...skipping 17 matching lines...) Expand all Loading... |
676 compilationUnit.partTag, MessageKind.MAIN_HAS_PART_OF)); | 658 compilationUnit.partTag, MessageKind.MAIN_HAS_PART_OF)); |
677 reporter.reportError(error); | 659 reporter.reportError(error); |
678 } else { | 660 } else { |
679 DiagnosticMessage error = reporter.withCurrentElement( | 661 DiagnosticMessage error = reporter.withCurrentElement( |
680 compilationUnit, | 662 compilationUnit, |
681 () => reporter.createMessage( | 663 () => reporter.createMessage( |
682 compilationUnit.partTag, MessageKind.IMPORT_PART_OF)); | 664 compilationUnit.partTag, MessageKind.IMPORT_PART_OF)); |
683 DiagnosticMessage info = reporter.withCurrentElement( | 665 DiagnosticMessage info = reporter.withCurrentElement( |
684 importingLibrary, | 666 importingLibrary, |
685 () => reporter.createMessage( | 667 () => reporter.createMessage( |
686 node, | 668 node, MessageKind.IMPORT_PART_OF_HERE)); |
687 MessageKind.IMPORT_PART_OF_HERE)); | |
688 reporter.reportError(error, [info]); | 669 reporter.reportError(error, [info]); |
689 } | 670 } |
690 } | 671 } |
691 return processLibraryTags(handler, element).then((_) { | 672 return processLibraryTags(handler, element).then((_) { |
692 reporter.withCurrentElement(element, () { | 673 reporter.withCurrentElement(element, () { |
693 handler.registerLibraryExports(element); | 674 handler.registerLibraryExports(element); |
694 }); | 675 }); |
695 return element; | 676 return element; |
696 }); | 677 }); |
697 }); | 678 }); |
698 }); | 679 }); |
699 } | 680 } |
700 | 681 |
701 LibraryElement createLibrarySync(LibraryDependencyHandler handler, | 682 LibraryElement createLibrarySync( |
702 Script script, Uri resolvedUri) { | 683 LibraryDependencyHandler handler, Script script, Uri resolvedUri) { |
703 LibraryElement element = new LibraryElementX(script, resolvedUri); | 684 LibraryElement element = new LibraryElementX(script, resolvedUri); |
704 return reporter.withCurrentElement(element, () { | 685 return reporter.withCurrentElement(element, () { |
705 if (handler != null) { | 686 if (handler != null) { |
706 handler.registerNewLibrary(element); | 687 handler.registerNewLibrary(element); |
707 libraryCanonicalUriMap[resolvedUri] = element; | 688 libraryCanonicalUriMap[resolvedUri] = element; |
708 } | 689 } |
709 scanner.scanLibrary(element); | 690 scanner.scanLibrary(element); |
710 return element; | 691 return element; |
711 }); | 692 }); |
712 } | 693 } |
713 | 694 |
714 CompilationUnitElement createUnitSync(Script script, LibraryElement library) { | 695 CompilationUnitElement createUnitSync(Script script, LibraryElement library) { |
715 CompilationUnitElementX unit = new CompilationUnitElementX(script, library); | 696 CompilationUnitElementX unit = new CompilationUnitElementX(script, library); |
716 reporter.withCurrentElement(unit, () { | 697 reporter.withCurrentElement(unit, () { |
717 scanner.scanUnit(unit); | 698 scanner.scanUnit(unit); |
718 if (unit.partTag == null && !script.isSynthesized) { | 699 if (unit.partTag == null && !script.isSynthesized) { |
719 reporter.reportErrorMessage(unit, MessageKind.MISSING_PART_OF_TAG); | 700 reporter.reportErrorMessage(unit, MessageKind.MISSING_PART_OF_TAG); |
720 } | 701 } |
721 }); | 702 }); |
722 return unit; | 703 return unit; |
723 } | 704 } |
724 } | 705 } |
725 | 706 |
726 | |
727 /// A state machine for checking script tags come in the correct order. | 707 /// A state machine for checking script tags come in the correct order. |
728 class TagState { | 708 class TagState { |
729 /// Initial state. | 709 /// Initial state. |
730 static const int NO_TAG_SEEN = 0; | 710 static const int NO_TAG_SEEN = 0; |
731 | 711 |
732 /// Passed to [checkTag] when a library declaration (the syntax "library | 712 /// Passed to [checkTag] when a library declaration (the syntax "library |
733 /// name;") has been seen. Not an actual state. | 713 /// name;") has been seen. Not an actual state. |
734 static const int LIBRARY = 1; | 714 static const int LIBRARY = 1; |
735 | 715 |
736 /// The state after the first library declaration. | 716 /// The state after the first library declaration. |
737 static const int AFTER_LIBRARY_DECLARATION = 2; | 717 static const int AFTER_LIBRARY_DECLARATION = 2; |
738 | 718 |
739 /// The state after a import or export declaration has been seen, but before | 719 /// The state after a import or export declaration has been seen, but before |
740 /// a part tag has been seen. | 720 /// a part tag has been seen. |
741 static const int IMPORT_OR_EXPORT = 3; | 721 static const int IMPORT_OR_EXPORT = 3; |
742 | 722 |
743 /// The state after a part tag has been seen. | 723 /// The state after a part tag has been seen. |
744 static const int PART = 4; | 724 static const int PART = 4; |
745 | 725 |
746 /// Encodes transition function for state machine. | 726 /// Encodes transition function for state machine. |
747 static const List<int> NEXT = const <int>[ | 727 static const List<int> NEXT = const <int>[ |
748 NO_TAG_SEEN, | 728 NO_TAG_SEEN, |
749 AFTER_LIBRARY_DECLARATION, // Only one library tag is allowed. | 729 AFTER_LIBRARY_DECLARATION, // Only one library tag is allowed. |
750 IMPORT_OR_EXPORT, | 730 IMPORT_OR_EXPORT, |
751 IMPORT_OR_EXPORT, | 731 IMPORT_OR_EXPORT, |
752 PART, | 732 PART, |
753 ]; | 733 ]; |
754 | 734 |
755 int tagState = TagState.NO_TAG_SEEN; | 735 int tagState = TagState.NO_TAG_SEEN; |
756 | 736 |
757 bool hasLibraryDeclaration = false; | 737 bool hasLibraryDeclaration = false; |
758 | 738 |
759 /// If [value] is less than [tagState] complain. Regardless, update | 739 /// If [value] is less than [tagState] complain. Regardless, update |
760 /// [tagState] using transition function for state machine. | 740 /// [tagState] using transition function for state machine. |
761 void checkTag(int value, LibraryTag tag, DiagnosticReporter reporter) { | 741 void checkTag(int value, LibraryTag tag, DiagnosticReporter reporter) { |
762 if (tagState > value) { | 742 if (tagState > value) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
797 */ | 777 */ |
798 class ImportLink { | 778 class ImportLink { |
799 final ImportElementX import; | 779 final ImportElementX import; |
800 final LibraryElement importedLibrary; | 780 final LibraryElement importedLibrary; |
801 | 781 |
802 ImportLink(this.import, this.importedLibrary); | 782 ImportLink(this.import, this.importedLibrary); |
803 | 783 |
804 /** | 784 /** |
805 * Imports the library into the [importingLibrary]. | 785 * Imports the library into the [importingLibrary]. |
806 */ | 786 */ |
807 void importLibrary(DiagnosticReporter reporter, | 787 void importLibrary( |
808 LibraryElementX importingLibrary) { | 788 DiagnosticReporter reporter, LibraryElementX importingLibrary) { |
809 assert(invariant(importingLibrary, | 789 assert(invariant(importingLibrary, importedLibrary.exportsHandled, |
810 importedLibrary.exportsHandled, | 790 message: 'Exports not handled on $importedLibrary')); |
811 message: 'Exports not handled on $importedLibrary')); | |
812 Import tag = import.node; | 791 Import tag = import.node; |
813 CombinatorFilter combinatorFilter = | 792 CombinatorFilter combinatorFilter = new CombinatorFilter.fromTag(tag); |
814 new CombinatorFilter.fromTag(tag); | |
815 if (tag != null && tag.prefix != null) { | 793 if (tag != null && tag.prefix != null) { |
816 String prefix = tag.prefix.source; | 794 String prefix = tag.prefix.source; |
817 Element existingElement = importingLibrary.find(prefix); | 795 Element existingElement = importingLibrary.find(prefix); |
818 PrefixElementX prefixElement; | 796 PrefixElementX prefixElement; |
819 if (existingElement == null || !existingElement.isPrefix) { | 797 if (existingElement == null || !existingElement.isPrefix) { |
820 prefixElement = new PrefixElementX( | 798 prefixElement = new PrefixElementX( |
821 prefix, | 799 prefix, |
822 importingLibrary.entryCompilationUnit, | 800 importingLibrary.entryCompilationUnit, |
823 tag.getBeginToken(), | 801 tag.getBeginToken(), |
824 tag.isDeferred ? import : null); | 802 tag.isDeferred ? import : null); |
825 } else { | 803 } else { |
826 prefixElement = existingElement; | 804 prefixElement = existingElement; |
827 } | 805 } |
828 importingLibrary.addToScope(prefixElement, reporter); | 806 importingLibrary.addToScope(prefixElement, reporter); |
829 importedLibrary.forEachExport((Element element) { | 807 importedLibrary.forEachExport((Element element) { |
830 if (combinatorFilter.exclude(element)) return; | 808 if (combinatorFilter.exclude(element)) return; |
831 prefixElement.addImport(element, import, reporter); | 809 prefixElement.addImport(element, import, reporter); |
832 }); | 810 }); |
833 import.prefix = prefixElement; | 811 import.prefix = prefixElement; |
834 if (prefixElement.isDeferred) { | 812 if (prefixElement.isDeferred) { |
835 prefixElement.addImport( | 813 prefixElement.addImport( |
836 new DeferredLoaderGetterElementX(prefixElement), | 814 new DeferredLoaderGetterElementX(prefixElement), import, reporter); |
837 import, reporter); | |
838 } | 815 } |
839 } else { | 816 } else { |
840 importedLibrary.forEachExport((Element element) { | 817 importedLibrary.forEachExport((Element element) { |
841 reporter.withCurrentElement(importingLibrary, () { | 818 reporter.withCurrentElement(importingLibrary, () { |
842 if (combinatorFilter.exclude(element)) return; | 819 if (combinatorFilter.exclude(element)) return; |
843 importingLibrary.addImport(element, import, reporter); | 820 importingLibrary.addImport(element, import, reporter); |
844 }); | 821 }); |
845 }); | 822 }); |
846 } | 823 } |
847 } | 824 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
880 * exports performed in [LibraryDependencyHandler.computeExports]. | 857 * exports performed in [LibraryDependencyHandler.computeExports]. |
881 */ | 858 */ |
882 class LibraryDependencyNode { | 859 class LibraryDependencyNode { |
883 final LibraryElementX library; | 860 final LibraryElementX library; |
884 | 861 |
885 // TODO(ahe): Remove [hashCodeCounter] and [hashCode] when | 862 // TODO(ahe): Remove [hashCodeCounter] and [hashCode] when |
886 // VM implementation of Object.hashCode is not slow. | 863 // VM implementation of Object.hashCode is not slow. |
887 final int hashCode = ++hashCodeCounter; | 864 final int hashCode = ++hashCodeCounter; |
888 static int hashCodeCounter = 0; | 865 static int hashCodeCounter = 0; |
889 | 866 |
890 | |
891 /** | 867 /** |
892 * A linked list of the import tags that import [library] mapped to the | 868 * A linked list of the import tags that import [library] mapped to the |
893 * corresponding libraries. This is used to propagate exports into imports | 869 * corresponding libraries. This is used to propagate exports into imports |
894 * after the export scopes have been computed. | 870 * after the export scopes have been computed. |
895 */ | 871 */ |
896 Link<ImportLink> imports = const Link<ImportLink>(); | 872 Link<ImportLink> imports = const Link<ImportLink>(); |
897 | 873 |
898 /// A linked list of all libraries directly exported by [library]. | 874 /// A linked list of all libraries directly exported by [library]. |
899 Link<LibraryElement> exports = const Link<LibraryElement>(); | 875 Link<LibraryElement> exports = const Link<LibraryElement>(); |
900 | 876 |
(...skipping 21 matching lines...) Expand all Loading... |
922 */ | 898 */ |
923 Map<Element, Link<ExportElement>> pendingExportMap = | 899 Map<Element, Link<ExportElement>> pendingExportMap = |
924 <Element, Link<ExportElement>>{}; | 900 <Element, Link<ExportElement>>{}; |
925 | 901 |
926 LibraryDependencyNode(this.library); | 902 LibraryDependencyNode(this.library); |
927 | 903 |
928 /** | 904 /** |
929 * Registers that the library of this node imports [importLibrary] through the | 905 * Registers that the library of this node imports [importLibrary] through the |
930 * [import] tag. | 906 * [import] tag. |
931 */ | 907 */ |
932 void registerImportDependency(ImportElementX import, | 908 void registerImportDependency( |
933 LibraryElement importedLibrary) { | 909 ImportElementX import, LibraryElement importedLibrary) { |
934 imports = imports.prepend(new ImportLink(import, importedLibrary)); | 910 imports = imports.prepend(new ImportLink(import, importedLibrary)); |
935 } | 911 } |
936 | 912 |
937 /** | 913 /** |
938 * Registers that the library of this node is exported by | 914 * Registers that the library of this node is exported by |
939 * [exportingLibraryNode] through the [export] tag. | 915 * [exportingLibraryNode] through the [export] tag. |
940 */ | 916 */ |
941 void registerExportDependency(ExportElementX export, | 917 void registerExportDependency( |
942 LibraryDependencyNode exportingLibraryNode) { | 918 ExportElementX export, LibraryDependencyNode exportingLibraryNode) { |
943 // Register the exported library in the exporting library node. | 919 // Register the exported library in the exporting library node. |
944 exportingLibraryNode.exports = | 920 exportingLibraryNode.exports = |
945 exportingLibraryNode.exports.prepend(library); | 921 exportingLibraryNode.exports.prepend(library); |
946 // Register the export in the exported library node. | 922 // Register the export in the exported library node. |
947 dependencies = | 923 dependencies = |
948 dependencies.prepend(new ExportLink(export, exportingLibraryNode)); | 924 dependencies.prepend(new ExportLink(export, exportingLibraryNode)); |
949 } | 925 } |
950 | 926 |
951 /** | 927 /** |
952 * Registers all non-private locally declared members of the library of this | 928 * Registers all non-private locally declared members of the library of this |
953 * node to be exported. This forms the basis for the work-list computation of | 929 * node to be exported. This forms the basis for the work-list computation of |
954 * the export scopes performed in [LibraryDependencyHandler.computeExports]. | 930 * the export scopes performed in [LibraryDependencyHandler.computeExports]. |
955 */ | 931 */ |
956 void registerInitialExports() { | 932 void registerInitialExports() { |
957 for (Element element in library.getNonPrivateElementsInScope()) { | 933 for (Element element in library.getNonPrivateElementsInScope()) { |
958 pendingExportMap[element] = const Link<ExportElement>(); | 934 pendingExportMap[element] = const Link<ExportElement>(); |
959 } | 935 } |
960 } | 936 } |
961 | 937 |
962 /// Register the already computed export scope of [exportedLibraryElement] to | 938 /// Register the already computed export scope of [exportedLibraryElement] to |
963 /// export from the library of this node through the [export] declaration | 939 /// export from the library of this node through the [export] declaration |
964 /// with the given combination [filter]. | 940 /// with the given combination [filter]. |
965 /// | 941 /// |
966 /// Additionally, check that all names in the show/hide combinators are in the | 942 /// Additionally, check that all names in the show/hide combinators are in the |
967 /// export scope of [exportedLibraryElement]. | 943 /// export scope of [exportedLibraryElement]. |
968 void registerHandledExports(DiagnosticReporter reporter, | 944 void registerHandledExports( |
969 LibraryElement exportedLibraryElement, | 945 DiagnosticReporter reporter, |
970 ExportElementX export, | 946 LibraryElement exportedLibraryElement, |
971 CombinatorFilter filter) { | 947 ExportElementX export, |
| 948 CombinatorFilter filter) { |
972 assert(invariant(library, exportedLibraryElement.exportsHandled)); | 949 assert(invariant(library, exportedLibraryElement.exportsHandled)); |
973 exportedLibraryElement.forEachExport((Element exportedElement) { | 950 exportedLibraryElement.forEachExport((Element exportedElement) { |
974 if (!filter.exclude(exportedElement)) { | 951 if (!filter.exclude(exportedElement)) { |
975 Link<ExportElement> exports = | 952 Link<ExportElement> exports = pendingExportMap.putIfAbsent( |
976 pendingExportMap.putIfAbsent(exportedElement, | 953 exportedElement, () => const Link<ExportElement>()); |
977 () => const Link<ExportElement>()); | |
978 pendingExportMap[exportedElement] = exports.prepend(export); | 954 pendingExportMap[exportedElement] = exports.prepend(export); |
979 } | 955 } |
980 }); | 956 }); |
981 if (!reporter.options.suppressHints) { | 957 if (!reporter.options.suppressHints) { |
982 reporter.withCurrentElement(library, () { | 958 reporter.withCurrentElement(library, () { |
983 checkLibraryDependency(reporter, export.node, exportedLibraryElement); | 959 checkLibraryDependency(reporter, export.node, exportedLibraryElement); |
984 }); | 960 }); |
985 } | 961 } |
986 } | 962 } |
987 | 963 |
(...skipping 20 matching lines...) Expand all Loading... |
1008 Map<Element, Link<ExportElement>> pendingExports = | 984 Map<Element, Link<ExportElement>> pendingExports = |
1009 new Map<Element, Link<ExportElement>>.from(pendingExportMap); | 985 new Map<Element, Link<ExportElement>>.from(pendingExportMap); |
1010 pendingExportMap.clear(); | 986 pendingExportMap.clear(); |
1011 return pendingExports; | 987 return pendingExports; |
1012 } | 988 } |
1013 | 989 |
1014 /** | 990 /** |
1015 * Adds [element] to the export scope for this node. If the [element] name | 991 * Adds [element] to the export scope for this node. If the [element] name |
1016 * is a duplicate, an error element is inserted into the export scope. | 992 * is a duplicate, an error element is inserted into the export scope. |
1017 */ | 993 */ |
1018 Element addElementToExportScope( | 994 Element addElementToExportScope(DiagnosticReporter reporter, Element element, |
1019 DiagnosticReporter reporter, | |
1020 Element element, | |
1021 Link<ExportElement> exports) { | 995 Link<ExportElement> exports) { |
1022 String name = element.name; | 996 String name = element.name; |
1023 DiagnosticMessage error; | 997 DiagnosticMessage error; |
1024 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; | 998 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
1025 | 999 |
1026 void createDuplicateExportMessage( | 1000 void createDuplicateExportMessage( |
1027 Element duplicate, | 1001 Element duplicate, Link<ExportElement> duplicateExports) { |
1028 Link<ExportElement> duplicateExports) { | |
1029 assert(invariant(library, !duplicateExports.isEmpty, | 1002 assert(invariant(library, !duplicateExports.isEmpty, |
1030 message: "No export for $duplicate from ${duplicate.library} " | 1003 message: "No export for $duplicate from ${duplicate.library} " |
1031 "in $library.")); | 1004 "in $library.")); |
1032 reporter.withCurrentElement(library, () { | 1005 reporter.withCurrentElement(library, () { |
1033 for (ExportElement export in duplicateExports) { | 1006 for (ExportElement export in duplicateExports) { |
1034 if (error == null) { | 1007 if (error == null) { |
1035 error = reporter.createMessage( | 1008 error = reporter.createMessage( |
1036 export, | 1009 export, MessageKind.DUPLICATE_EXPORT, {'name': name}); |
1037 MessageKind.DUPLICATE_EXPORT, | |
1038 {'name': name}); | |
1039 } else { | 1010 } else { |
1040 infos.add(reporter.createMessage( | 1011 infos.add(reporter.createMessage( |
1041 export, | 1012 export, MessageKind.DUPLICATE_EXPORT_CONT, {'name': name})); |
1042 MessageKind.DUPLICATE_EXPORT_CONT, | |
1043 {'name': name})); | |
1044 } | 1013 } |
1045 } | 1014 } |
1046 }); | 1015 }); |
1047 } | 1016 } |
1048 | 1017 |
1049 void createDuplicateExportDeclMessage( | 1018 void createDuplicateExportDeclMessage( |
1050 Element duplicate, | 1019 Element duplicate, Link<ExportElement> duplicateExports) { |
1051 Link<ExportElement> duplicateExports) { | |
1052 assert(invariant(library, !duplicateExports.isEmpty, | 1020 assert(invariant(library, !duplicateExports.isEmpty, |
1053 message: "No export for $duplicate from ${duplicate.library} " | 1021 message: "No export for $duplicate from ${duplicate.library} " |
1054 "in $library.")); | 1022 "in $library.")); |
1055 infos.add(reporter.createMessage( | 1023 infos.add(reporter.createMessage( |
1056 duplicate, | 1024 duplicate, |
1057 MessageKind.DUPLICATE_EXPORT_DECL, | 1025 MessageKind.DUPLICATE_EXPORT_DECL, |
1058 {'name': name, 'uriString': duplicateExports.head.uri})); | 1026 {'name': name, 'uriString': duplicateExports.head.uri})); |
1059 } | 1027 } |
1060 | 1028 |
1061 Element existingElement = exportScope[name]; | 1029 Element existingElement = exportScope[name]; |
1062 if (existingElement != null && existingElement != element) { | 1030 if (existingElement != null && existingElement != element) { |
1063 if (existingElement.isMalformed) { | 1031 if (existingElement.isMalformed) { |
1064 createDuplicateExportMessage(element, exports); | 1032 createDuplicateExportMessage(element, exports); |
1065 createDuplicateExportDeclMessage(element, exports); | 1033 createDuplicateExportDeclMessage(element, exports); |
1066 element = existingElement; | 1034 element = existingElement; |
1067 } else if (existingElement.library == library) { | 1035 } else if (existingElement.library == library) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1133 }); | 1101 }); |
1134 for (ExportLink exportLink in dependencies) { | 1102 for (ExportLink exportLink in dependencies) { |
1135 reporter.withCurrentElement(exportLink.exportNode.library, () { | 1103 reporter.withCurrentElement(exportLink.exportNode.library, () { |
1136 checkLibraryDependency(reporter, exportLink.export.node, library); | 1104 checkLibraryDependency(reporter, exportLink.export.node, library); |
1137 }); | 1105 }); |
1138 } | 1106 } |
1139 } | 1107 } |
1140 | 1108 |
1141 /// Check that all names in the show/hide combinators of [tag] are in the | 1109 /// Check that all names in the show/hide combinators of [tag] are in the |
1142 /// export scope of [library]. | 1110 /// export scope of [library]. |
1143 void checkLibraryDependency( | 1111 void checkLibraryDependency(DiagnosticReporter reporter, |
1144 DiagnosticReporter reporter, | 1112 LibraryDependency tag, LibraryElement library) { |
1145 LibraryDependency tag, | |
1146 LibraryElement library) { | |
1147 if (tag == null || tag.combinators == null) return; | 1113 if (tag == null || tag.combinators == null) return; |
1148 for (Combinator combinator in tag.combinators) { | 1114 for (Combinator combinator in tag.combinators) { |
1149 for (Identifier identifier in combinator.identifiers) { | 1115 for (Identifier identifier in combinator.identifiers) { |
1150 String name = identifier.source; | 1116 String name = identifier.source; |
1151 Element element = library.findExported(name); | 1117 Element element = library.findExported(name); |
1152 if (element == null) { | 1118 if (element == null) { |
1153 if (combinator.isHide) { | 1119 if (combinator.isHide) { |
1154 if (library.isPackageLibrary && | 1120 if (library.isPackageLibrary && |
1155 reporter.options.hidePackageWarnings) { | 1121 reporter.options.hidePackageWarnings) { |
1156 // Only report hide hint on packages if we show warnings on these: | 1122 // Only report hide hint on packages if we show warnings on these: |
1157 // The hide may be non-empty in some versions of the package, in | 1123 // The hide may be non-empty in some versions of the package, in |
1158 // which case you shouldn't remove the combinator. | 1124 // which case you shouldn't remove the combinator. |
1159 continue; | 1125 continue; |
1160 } | 1126 } |
1161 reporter.reportHintMessage( | 1127 reporter.reportHintMessage(identifier, MessageKind.EMPTY_HIDE, |
1162 identifier, | 1128 {'uri': library.canonicalUri, 'name': name}); |
1163 MessageKind.EMPTY_HIDE, | |
1164 {'uri': library.canonicalUri, | |
1165 'name': name}); | |
1166 } else { | 1129 } else { |
1167 reporter.reportHintMessage( | 1130 reporter.reportHintMessage(identifier, MessageKind.EMPTY_SHOW, |
1168 identifier, | 1131 {'uri': library.canonicalUri, 'name': name}); |
1169 MessageKind.EMPTY_SHOW, | |
1170 {'uri': library.canonicalUri, | |
1171 'name': name}); | |
1172 } | 1132 } |
1173 } | 1133 } |
1174 } | 1134 } |
1175 } | 1135 } |
1176 } | 1136 } |
1177 | |
1178 } | 1137 } |
1179 | 1138 |
1180 /** | 1139 /** |
1181 * Helper class used for computing the possibly cyclic import/export scopes of | 1140 * Helper class used for computing the possibly cyclic import/export scopes of |
1182 * a set of libraries. | 1141 * a set of libraries. |
1183 * | 1142 * |
1184 * This class is used by [ScannerTask.scanLibrary] to collect all newly loaded | 1143 * This class is used by [ScannerTask.scanLibrary] to collect all newly loaded |
1185 * libraries and to compute their import/export scopes through a fixed-point | 1144 * libraries and to compute their import/export scopes through a fixed-point |
1186 * algorithm. | 1145 * algorithm. |
1187 */ | 1146 */ |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1221 // elements. So we must propagate local elements first. We | 1180 // elements. So we must propagate local elements first. We |
1222 // ensure this by pulling the pending exports before | 1181 // ensure this by pulling the pending exports before |
1223 // propagating. This enforces that we handle exports | 1182 // propagating. This enforces that we handle exports |
1224 // breadth-first, with locally defined elements being level 0. | 1183 // breadth-first, with locally defined elements being level 0. |
1225 nodeMap.forEach((_, LibraryDependencyNode node) { | 1184 nodeMap.forEach((_, LibraryDependencyNode node) { |
1226 Map<Element, Link<ExportElement>> pendingExports = | 1185 Map<Element, Link<ExportElement>> pendingExports = |
1227 node.pullPendingExports(); | 1186 node.pullPendingExports(); |
1228 tasks[node] = pendingExports; | 1187 tasks[node] = pendingExports; |
1229 }); | 1188 }); |
1230 tasks.forEach((LibraryDependencyNode node, | 1189 tasks.forEach((LibraryDependencyNode node, |
1231 Map<Element, Link<ExportElement>> pendingExports) { | 1190 Map<Element, Link<ExportElement>> pendingExports) { |
1232 pendingExports.forEach((Element element, Link<ExportElement> exports) { | 1191 pendingExports.forEach((Element element, Link<ExportElement> exports) { |
1233 element = node.addElementToExportScope(reporter, element, exports); | 1192 element = node.addElementToExportScope(reporter, element, exports); |
1234 if (node.propagateElement(element)) { | 1193 if (node.propagateElement(element)) { |
1235 changed = true; | 1194 changed = true; |
1236 } | 1195 } |
1237 }); | 1196 }); |
1238 }); | 1197 }); |
1239 } | 1198 } |
1240 | 1199 |
1241 // Setup export scopes. These have to be set before computing the import | 1200 // Setup export scopes. These have to be set before computing the import |
(...skipping 10 matching lines...) Expand all Loading... |
1252 | 1211 |
1253 if (!reporter.options.suppressHints) { | 1212 if (!reporter.options.suppressHints) { |
1254 nodeMap.forEach((LibraryElement library, LibraryDependencyNode node) { | 1213 nodeMap.forEach((LibraryElement library, LibraryDependencyNode node) { |
1255 node.checkCombinators(reporter); | 1214 node.checkCombinators(reporter); |
1256 }); | 1215 }); |
1257 } | 1216 } |
1258 } | 1217 } |
1259 | 1218 |
1260 /// Registers that [library] depends on [loadedLibrary] through | 1219 /// Registers that [library] depends on [loadedLibrary] through |
1261 /// [libraryDependency]. | 1220 /// [libraryDependency]. |
1262 void registerDependency(LibraryElementX library, | 1221 void registerDependency( |
1263 LibraryDependencyElementX libraryDependency, | 1222 LibraryElementX library, |
1264 LibraryElement loadedLibrary) { | 1223 LibraryDependencyElementX libraryDependency, |
| 1224 LibraryElement loadedLibrary) { |
1265 if (libraryDependency.isExport) { | 1225 if (libraryDependency.isExport) { |
1266 // [loadedLibrary] is exported by [library]. | 1226 // [loadedLibrary] is exported by [library]. |
1267 LibraryDependencyNode exportingNode = nodeMap[library]; | 1227 LibraryDependencyNode exportingNode = nodeMap[library]; |
1268 if (loadedLibrary.exportsHandled) { | 1228 if (loadedLibrary.exportsHandled) { |
1269 // Export scope already computed on [loadedLibrary]. | 1229 // Export scope already computed on [loadedLibrary]. |
1270 CombinatorFilter combinatorFilter = | 1230 CombinatorFilter combinatorFilter = |
1271 new CombinatorFilter.fromTag(libraryDependency.node); | 1231 new CombinatorFilter.fromTag(libraryDependency.node); |
1272 exportingNode.registerHandledExports( | 1232 exportingNode.registerHandledExports( |
1273 reporter, loadedLibrary, libraryDependency, combinatorFilter); | 1233 reporter, loadedLibrary, libraryDependency, combinatorFilter); |
1274 return; | 1234 return; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1329 | 1289 |
1330 /// Applies all imports chains of [uri] in this bulk to [callback]. | 1290 /// Applies all imports chains of [uri] in this bulk to [callback]. |
1331 /// | 1291 /// |
1332 /// The argument [importChainReversed] to [callback] contains the chain of | 1292 /// The argument [importChainReversed] to [callback] contains the chain of |
1333 /// imports uris that lead to importing [uri] starting in [uri] and ending in | 1293 /// imports uris that lead to importing [uri] starting in [uri] and ending in |
1334 /// [rootUri]. | 1294 /// [rootUri]. |
1335 /// | 1295 /// |
1336 /// [callback] is called once for each chain of imports leading to [uri] until | 1296 /// [callback] is called once for each chain of imports leading to [uri] until |
1337 /// [callback] returns `false`. | 1297 /// [callback] returns `false`. |
1338 void forEachImportChain(Uri uri, | 1298 void forEachImportChain(Uri uri, |
1339 {bool callback(Link<Uri> importChainReversed)}); | 1299 {bool callback(Link<Uri> importChainReversed)}); |
1340 } | 1300 } |
1341 | 1301 |
1342 class _LoadedLibraries implements LoadedLibraries { | 1302 class _LoadedLibraries implements LoadedLibraries { |
1343 final _LibraryLoaderTask task; | 1303 final _LibraryLoaderTask task; |
1344 final LibraryElement rootLibrary; | 1304 final LibraryElement rootLibrary; |
1345 final Map<Uri, LibraryElement> loadedLibraries = <Uri, LibraryElement>{}; | 1305 final Map<Uri, LibraryElement> loadedLibraries = <Uri, LibraryElement>{}; |
1346 final Map<LibraryElement, LibraryDependencyNode> nodeMap; | 1306 final Map<LibraryElement, LibraryDependencyNode> nodeMap; |
1347 | 1307 |
1348 _LoadedLibraries( | 1308 _LoadedLibraries(this.rootLibrary, Iterable<LibraryElement> libraries, |
1349 this.rootLibrary, | 1309 this.nodeMap, this.task) { |
1350 Iterable<LibraryElement> libraries, | |
1351 this.nodeMap, | |
1352 this.task) { | |
1353 libraries.forEach((LibraryElement loadedLibrary) { | 1310 libraries.forEach((LibraryElement loadedLibrary) { |
1354 loadedLibraries[loadedLibrary.canonicalUri] = loadedLibrary; | 1311 loadedLibraries[loadedLibrary.canonicalUri] = loadedLibrary; |
1355 }); | 1312 }); |
1356 } | 1313 } |
1357 | 1314 |
1358 Uri get rootUri => rootLibrary.canonicalUri; | 1315 Uri get rootUri => rootLibrary.canonicalUri; |
1359 | 1316 |
1360 bool containsLibrary(Uri uri) => loadedLibraries.containsKey(uri); | 1317 bool containsLibrary(Uri uri) => loadedLibraries.containsKey(uri); |
1361 | 1318 |
1362 LibraryElement getLibrary(Uri uri) => loadedLibraries[uri]; | 1319 LibraryElement getLibrary(Uri uri) => loadedLibraries[uri]; |
1363 | 1320 |
1364 void forEachLibrary(f(LibraryElement library)) => nodeMap.keys.forEach(f); | 1321 void forEachLibrary(f(LibraryElement library)) => nodeMap.keys.forEach(f); |
1365 | 1322 |
1366 void forEachImportChain(Uri targetUri, | 1323 void forEachImportChain(Uri targetUri, |
1367 {bool callback(Link<Uri> importChainReversed)}) { | 1324 {bool callback(Link<Uri> importChainReversed)}) { |
1368 bool aborted = false; | 1325 bool aborted = false; |
1369 | 1326 |
1370 /// Map from libraries to the set of (unreversed) paths to [uri]. | 1327 /// Map from libraries to the set of (unreversed) paths to [uri]. |
1371 Map<LibraryElement, Iterable<Link<Uri>>> suffixChainMap = | 1328 Map<LibraryElement, Iterable<Link<Uri>>> suffixChainMap = |
1372 <LibraryElement, Iterable<Link<Uri>>>{}; | 1329 <LibraryElement, Iterable<Link<Uri>>>{}; |
1373 | 1330 |
1374 /// Computes the set of (unreversed) paths to [targetUri]. | 1331 /// Computes the set of (unreversed) paths to [targetUri]. |
1375 /// | 1332 /// |
1376 /// Finds all paths (suffixes) from the current library to [uri] and stores | 1333 /// Finds all paths (suffixes) from the current library to [uri] and stores |
1377 /// it in [suffixChainMap]. | 1334 /// it in [suffixChainMap]. |
1378 /// | 1335 /// |
1379 /// For every found suffix it prepends the given [prefix] and the canonical | 1336 /// For every found suffix it prepends the given [prefix] and the canonical |
1380 /// uri of [library] and invokes the [callback] with the concatenated chain. | 1337 /// uri of [library] and invokes the [callback] with the concatenated chain. |
1381 void computeSuffixes(LibraryElement library, | 1338 void computeSuffixes(LibraryElement library, Link<Uri> prefix) { |
1382 Link<Uri> prefix) { | |
1383 if (aborted) return; | 1339 if (aborted) return; |
1384 | 1340 |
1385 Uri canonicalUri = library.canonicalUri; | 1341 Uri canonicalUri = library.canonicalUri; |
1386 prefix = prefix.prepend(canonicalUri); | 1342 prefix = prefix.prepend(canonicalUri); |
1387 if (suffixChainMap.containsKey(library)) return; | 1343 if (suffixChainMap.containsKey(library)) return; |
1388 suffixChainMap[library] = const <Link<Uri>>[]; | 1344 suffixChainMap[library] = const <Link<Uri>>[]; |
1389 List<Link<Uri>> suffixes = []; | 1345 List<Link<Uri>> suffixes = []; |
1390 if (targetUri != canonicalUri) { | 1346 if (targetUri != canonicalUri) { |
1391 LibraryDependencyNode node = nodeMap[library]; | 1347 LibraryDependencyNode node = nodeMap[library]; |
1392 | 1348 |
(...skipping 28 matching lines...) Expand all Loading... |
1421 } | 1377 } |
1422 | 1378 |
1423 for (ImportLink import in node.imports.reverse()) { | 1379 for (ImportLink import in node.imports.reverse()) { |
1424 processLibrary(import.importedLibrary); | 1380 processLibrary(import.importedLibrary); |
1425 if (aborted) return; | 1381 if (aborted) return; |
1426 } | 1382 } |
1427 for (LibraryElement exportedLibrary in node.exports.reverse()) { | 1383 for (LibraryElement exportedLibrary in node.exports.reverse()) { |
1428 processLibrary(exportedLibrary); | 1384 processLibrary(exportedLibrary); |
1429 if (aborted) return; | 1385 if (aborted) return; |
1430 } | 1386 } |
1431 } else { // Here `targetUri == canonicalUri`. | 1387 } else { |
| 1388 // Here `targetUri == canonicalUri`. |
1432 if (!callback(prefix)) { | 1389 if (!callback(prefix)) { |
1433 aborted = true; | 1390 aborted = true; |
1434 return; | 1391 return; |
1435 } | 1392 } |
1436 suffixes.add(const Link<Uri>().prepend(canonicalUri)); | 1393 suffixes.add(const Link<Uri>().prepend(canonicalUri)); |
1437 } | 1394 } |
1438 suffixChainMap[library] = suffixes; | 1395 suffixChainMap[library] = suffixes; |
1439 return; | 1396 return; |
1440 } | 1397 } |
1441 | 1398 |
1442 computeSuffixes(rootLibrary, const Link<Uri>()); | 1399 computeSuffixes(rootLibrary, const Link<Uri>()); |
1443 } | 1400 } |
1444 | 1401 |
1445 String toString() => 'root=$rootLibrary,libraries=${loadedLibraries.keys}'; | 1402 String toString() => 'root=$rootLibrary,libraries=${loadedLibraries.keys}'; |
1446 } | 1403 } |
1447 | 1404 |
1448 /// API used by the library loader to translate internal SDK URIs into file | 1405 /// API used by the library loader to translate internal SDK URIs into file |
1449 /// system readable URIs. | 1406 /// system readable URIs. |
1450 abstract class ResolvedUriTranslator { | 1407 abstract class ResolvedUriTranslator { |
1451 // TODO(sigmund): move here the comments from library loader. | 1408 // TODO(sigmund): move here the comments from library loader. |
1452 /// Translate the resolved [uri] in the context of [importingLibrary]. | 1409 /// Translate the resolved [uri] in the context of [importingLibrary]. |
1453 /// | 1410 /// |
1454 /// Use [spannable] for error reporting. | 1411 /// Use [spannable] for error reporting. |
1455 Uri translate( | 1412 Uri translate(LibraryElement importingLibrary, Uri uri, |
1456 LibraryElement importingLibrary, Uri uri, [Spannable spannable]); | 1413 [Spannable spannable]); |
1457 } | 1414 } |
1458 | 1415 |
1459 | |
1460 // TODO(sigmund): remove ScriptLoader & ElementScanner. Such abstraction seems | 1416 // TODO(sigmund): remove ScriptLoader & ElementScanner. Such abstraction seems |
1461 // rather low-level. It might be more practical to split the library-loading | 1417 // rather low-level. It might be more practical to split the library-loading |
1462 // task itself. The task would continue to do the work of recursively loading | 1418 // task itself. The task would continue to do the work of recursively loading |
1463 // dependencies, but it can delegate to a set of subloaders how to do the actual | 1419 // dependencies, but it can delegate to a set of subloaders how to do the actual |
1464 // loading. We would then have a list of subloaders that use different | 1420 // loading. We would then have a list of subloaders that use different |
1465 // implementations: in-memory cache, deserialization, scanning from files. | 1421 // implementations: in-memory cache, deserialization, scanning from files. |
1466 // | 1422 // |
1467 // For example, the API might look like this: | 1423 // For example, the API might look like this: |
1468 // | 1424 // |
1469 // /// APIs to create [LibraryElement] and [CompilationUnitElements] given it's | 1425 // /// APIs to create [LibraryElement] and [CompilationUnitElements] given it's |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1502 Future<Script> readScript(Uri uri, [Spannable spannable]); | 1458 Future<Script> readScript(Uri uri, [Spannable spannable]); |
1503 } | 1459 } |
1504 | 1460 |
1505 /// API used by the library loader to synchronously scan a library or | 1461 /// API used by the library loader to synchronously scan a library or |
1506 /// compilation unit and ensure that their library tags are computed. | 1462 /// compilation unit and ensure that their library tags are computed. |
1507 abstract class ElementScanner { | 1463 abstract class ElementScanner { |
1508 void scanLibrary(LibraryElement library); | 1464 void scanLibrary(LibraryElement library); |
1509 void scanUnit(CompilationUnitElement unit); | 1465 void scanUnit(CompilationUnitElement unit); |
1510 } | 1466 } |
1511 | 1467 |
1512 | |
1513 /// TODO(sigmund): remove this abstraction. Ideally the loader can produce the | 1468 /// TODO(sigmund): remove this abstraction. Ideally the loader can produce the |
1514 /// LoadedLibraries results once, and the compiler and choose what to do with | 1469 /// LoadedLibraries results once, and the compiler and choose what to do with |
1515 /// it instead. | 1470 /// it instead. |
1516 abstract class LibraryLoaderListener { | 1471 abstract class LibraryLoaderListener { |
1517 /// Called after a request to load a library. The [results] will include all | 1472 /// Called after a request to load a library. The [results] will include all |
1518 /// transitive libraries loaded as a result of the initial request. | 1473 /// transitive libraries loaded as a result of the initial request. |
1519 Future onLibrariesLoaded(LoadedLibraries results); | 1474 Future onLibrariesLoaded(LoadedLibraries results); |
1520 | 1475 |
1521 /// Called whenever a library element is created. | 1476 /// Called whenever a library element is created. |
1522 void onLibraryCreated(LibraryElement library); | 1477 void onLibraryCreated(LibraryElement library); |
1523 | 1478 |
1524 /// Called whenever a library is scanned from a script file. | 1479 /// Called whenever a library is scanned from a script file. |
1525 Future onLibraryScanned(LibraryElement library, LibraryLoader loader); | 1480 Future onLibraryScanned(LibraryElement library, LibraryLoader loader); |
1526 } | 1481 } |
OLD | NEW |