| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 trydart.poi; | 5 library trydart.poi.scope_information_visitor; |
| 6 | 6 |
| 7 import 'dart:async' show | 7 import 'package:compiler/src/elements/modelx.dart' as modelx; |
| 8 Completer, | |
| 9 Future; | |
| 10 | 8 |
| 11 import 'dart:io' as io; | 9 import 'package:compiler/src/elements/modelx.dart' show |
| 12 | 10 CompilationUnitElementX, |
| 13 import 'dart:convert' show | 11 FieldElementX; |
| 14 UTF8; | |
| 15 | |
| 16 import 'package:dart2js_incremental/dart2js_incremental.dart' show | |
| 17 reuseCompiler; | |
| 18 | |
| 19 import 'package:dart2js_incremental/library_updater.dart' show | |
| 20 LibraryUpdater; | |
| 21 | |
| 22 import 'package:compiler/src/source_file_provider.dart' show | |
| 23 FormattingDiagnosticHandler; | |
| 24 | |
| 25 import 'package:compiler/compiler.dart' as api; | |
| 26 | |
| 27 import 'package:compiler/src/dart2jslib.dart' show | |
| 28 Compiler, | |
| 29 CompilerTask, | |
| 30 Enqueuer, | |
| 31 QueueFilter, | |
| 32 WorkItem; | |
| 33 | 12 |
| 34 import 'package:compiler/src/elements/visitor.dart' show | 13 import 'package:compiler/src/elements/visitor.dart' show |
| 35 ElementVisitor; | 14 ElementVisitor; |
| 36 | 15 |
| 16 import 'package:compiler/src/dart2jslib.dart' show |
| 17 Compiler; |
| 18 |
| 37 import 'package:compiler/src/elements/elements.dart' show | 19 import 'package:compiler/src/elements/elements.dart' show |
| 38 AbstractFieldElement, | 20 AbstractFieldElement, |
| 39 ClassElement, | 21 ClassElement, |
| 40 CompilationUnitElement, | 22 CompilationUnitElement, |
| 41 Element, | 23 Element, |
| 42 ElementCategory, | 24 ElementCategory, |
| 43 FunctionElement, | 25 FunctionElement, |
| 44 LibraryElement, | 26 LibraryElement, |
| 45 ScopeContainerElement; | 27 ScopeContainerElement; |
| 46 | 28 |
| 47 import 'package:compiler/src/elements/modelx.dart' as modelx; | |
| 48 | |
| 49 import 'package:compiler/src/elements/modelx.dart' show | |
| 50 DeclarationSite; | |
| 51 | |
| 52 import 'package:compiler/src/dart_types.dart' show | 29 import 'package:compiler/src/dart_types.dart' show |
| 53 DartType; | 30 DartType; |
| 54 | 31 |
| 55 import 'package:compiler/src/scanner/scannerlib.dart' show | 32 /****************** IGNORE THIS ONLY FOR SMALL DIFF **************************** |
| 56 EOF_TOKEN, | |
| 57 IDENTIFIER_TOKEN, | |
| 58 KEYWORD_TOKEN, | |
| 59 PartialClassElement, | |
| 60 PartialElement, | |
| 61 Token; | |
| 62 | |
| 63 import 'package:compiler/src/js/js.dart' show | |
| 64 js; | |
| 65 | 33 |
| 66 /// Enabled by the option --enable-dart-mind. Controls if this program should | 34 /// Enabled by the option --enable-dart-mind. Controls if this program should |
| 67 /// be querying Dart Mind. | 35 /// be querying Dart Mind. |
| 68 bool isDartMindEnabled = false; | 36 bool isDartMindEnabled = false; |
| 69 | 37 |
| 70 /// Iterator over lines from standard input (or the argument array). | 38 /// Iterator over lines from standard input (or the argument array). |
| 71 Iterator<String> stdin; | 39 Iterator<String> stdin; |
| 72 | 40 |
| 73 /// Enabled by the option --simulate-mutation. When true, this program will | 41 /// Enabled by the option --simulate-mutation. When true, this program will |
| 74 /// only prompt for one file name, and subsequent runs will read | 42 /// only prompt for one file name, and subsequent runs will read |
| (...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 void processWorkItem(void f(WorkItem work), WorkItem work) { | 506 void processWorkItem(void f(WorkItem work), WorkItem work) { |
| 539 if (work.element.library.canonicalUri == script) { | 507 if (work.element.library.canonicalUri == script) { |
| 540 f(work); | 508 f(work); |
| 541 printWallClock('Processed ${work.element}.'); | 509 printWallClock('Processed ${work.element}.'); |
| 542 } else { | 510 } else { |
| 543 printWallClock('Skipped ${work.element}.'); | 511 printWallClock('Skipped ${work.element}.'); |
| 544 } | 512 } |
| 545 } | 513 } |
| 546 } | 514 } |
| 547 | 515 |
| 516 *******************************************************************************/ |
| 517 |
| 548 /** | 518 /** |
| 549 * Serializes scope information about an element. This is accomplished by | 519 * Serializes scope information about an element. This is accomplished by |
| 550 * calling the [serialize] method on each element. Some elements need special | 520 * calling the [serialize] method on each element. Some elements need special |
| 551 * treatment, as their enclosing scope must also be serialized. | 521 * treatment, as their enclosing scope must also be serialized. |
| 552 */ | 522 */ |
| 553 class ScopeInformationVisitor extends ElementVisitor/* <void> */ { | 523 class ScopeInformationVisitor extends ElementVisitor/* <void> */ { |
| 554 // TODO(ahe): Include function parameters and local variables. | 524 // TODO(ahe): Include function parameters and local variables. |
| 555 | 525 |
| 526 final Compiler compiler; |
| 556 final Element currentElement; | 527 final Element currentElement; |
| 557 final int position; | 528 final int position; |
| 558 final StringBuffer buffer = new StringBuffer(); | 529 final StringBuffer buffer = new StringBuffer(); |
| 559 int indentationLevel = 0; | 530 int indentationLevel = 0; |
| 560 ClassElement currentClass; | 531 ClassElement currentClass; |
| 561 | 532 |
| 562 ScopeInformationVisitor(this.currentElement, this.position); | 533 bool sortMembers = false; |
| 534 |
| 535 bool ignoreImports = false; |
| 536 |
| 537 ScopeInformationVisitor(this.compiler, this.currentElement, this.position); |
| 563 | 538 |
| 564 String get indentation => ' ' * indentationLevel; | 539 String get indentation => ' ' * indentationLevel; |
| 565 | 540 |
| 566 StringBuffer get indented => buffer..write(indentation); | 541 StringBuffer get indented => buffer..write(indentation); |
| 567 | 542 |
| 568 void visitElement(Element e) { | 543 void visitElement(Element e) { |
| 569 serialize(e, omitEnclosing: false); | 544 serialize(e, omitEnclosing: false); |
| 570 } | 545 } |
| 571 | 546 |
| 572 void visitLibraryElement(LibraryElement e) { | 547 void visitLibraryElement(LibraryElement e) { |
| 573 bool isFirst = true; | 548 bool isFirst = true; |
| 574 forEach(Element member) { | 549 forEach(Element member) { |
| 575 if (!isFirst) { | 550 if (!isFirst) { |
| 576 buffer.write(','); | 551 buffer.write(','); |
| 577 } | 552 } |
| 578 buffer.write('\n'); | 553 buffer.write('\n'); |
| 579 indented; | 554 indented; |
| 580 serialize(member); | 555 serialize(member); |
| 581 isFirst = false; | 556 isFirst = false; |
| 582 } | 557 } |
| 583 serialize( | 558 serialize( |
| 584 e, | 559 e, |
| 585 // TODO(ahe): We omit the import scope if there is no current | 560 // TODO(ahe): We omit the import scope if there is no current |
| 586 // class. That's wrong. | 561 // class. That's wrong. |
| 587 omitEnclosing: currentClass == null, | 562 omitEnclosing: ignoreImports || currentClass == null, |
| 588 name: e.getLibraryName(), | 563 name: e.getLibraryName(), |
| 589 serializeEnclosing: () { | 564 serializeEnclosing: () { |
| 590 // The enclosing scope of a library is a scope which contains all the | 565 // The enclosing scope of a library is a scope which contains all the |
| 591 // imported names. | 566 // imported names. |
| 592 isFirst = true; | 567 isFirst = true; |
| 593 buffer.write('{\n'); | 568 buffer.write('{\n'); |
| 594 indentationLevel++; | 569 indentationLevel++; |
| 595 indented.write('"kind": "imports",\n'); | 570 indented.write('"kind": "imports",\n'); |
| 596 indented.write('"members": ['); | 571 indented.write('"members": ['); |
| 597 indentationLevel++; | 572 indentationLevel++; |
| 598 importScope(e).importScope.values.forEach(forEach); | 573 sortElements(importScope(e).importScope.values).forEach(forEach); |
| 599 indentationLevel--; | 574 indentationLevel--; |
| 600 buffer.write('\n'); | 575 buffer.write('\n'); |
| 601 indented.write('],\n'); | 576 indented.write('],\n'); |
| 602 // The enclosing scope of the imported names scope is the superclass | 577 // The enclosing scope of the imported names scope is the superclass |
| 603 // scope of the current class. | 578 // scope of the current class. |
| 604 indented.write('"enclosing": '); | 579 indented.write('"enclosing": '); |
| 605 serializeClassSide( | 580 serializeClassSide( |
| 606 currentClass.superclass, isStatic: false, includeSuper: true); | 581 currentClass.superclass, isStatic: false, includeSuper: true); |
| 607 buffer.write('\n'); | 582 buffer.write('\n'); |
| 608 indentationLevel--; | 583 indentationLevel--; |
| 609 indented.write('}'); | 584 indented.write('}'); |
| 610 }, | 585 }, |
| 611 serializeMembers: () { | 586 serializeMembers: () { |
| 612 isFirst = true; | 587 isFirst = true; |
| 613 localScope(e).values.forEach(forEach); | 588 sortElements(localScope(e).values).forEach(forEach); |
| 614 }); | 589 }); |
| 615 } | 590 } |
| 616 | 591 |
| 617 void visitClassElement(ClassElement e) { | 592 void visitClassElement(ClassElement e) { |
| 618 currentClass = e; | 593 currentClass = e; |
| 619 serializeClassSide(e, isStatic: true); | 594 serializeClassSide(e, isStatic: true); |
| 620 } | 595 } |
| 621 | 596 |
| 622 /// Serializes one of the "sides" a class. The sides of a class are "instance | 597 /// Serializes one of the "sides" a class. The sides of a class are "instance |
| 623 /// side" and "class side". These terms are from Smalltalk. The instance side | 598 /// side" and "class side". These terms are from Smalltalk. The instance side |
| 624 /// is all the local instance members of the class (the members of the | 599 /// is all the local instance members of the class (the members of the |
| 625 /// mixin), and the class side is the equivalent for static members and | 600 /// mixin), and the class side is the equivalent for static members and |
| 626 /// constructors. | 601 /// constructors. |
| 627 /// The scope chain is ordered so that the "class side" is searched before | 602 /// The scope chain is ordered so that the "class side" is searched before |
| 628 /// the "instance side". | 603 /// the "instance side". |
| 629 void serializeClassSide( | 604 void serializeClassSide( |
| 630 ClassElement e, | 605 ClassElement e, |
| 631 {bool isStatic: false, | 606 {bool isStatic: false, |
| 632 bool omitEnclosing: false, | 607 bool omitEnclosing: false, |
| 633 bool includeSuper: false}) { | 608 bool includeSuper: false}) { |
| 609 e.ensureResolved(compiler); |
| 634 bool isFirst = true; | 610 bool isFirst = true; |
| 635 var serializeEnclosing; | 611 var serializeEnclosing; |
| 636 String kind; | 612 String kind; |
| 637 if (isStatic) { | 613 if (isStatic) { |
| 638 kind = 'class side'; | 614 kind = 'class side'; |
| 639 serializeEnclosing = () { | 615 serializeEnclosing = () { |
| 640 serializeClassSide(e, isStatic: false, omitEnclosing: omitEnclosing); | 616 serializeClassSide(e, isStatic: false, omitEnclosing: omitEnclosing); |
| 641 }; | 617 }; |
| 642 } else { | 618 } else { |
| 643 kind = 'instance side'; | 619 kind = 'instance side'; |
| 644 } | 620 } |
| 645 if (includeSuper) { | 621 if (includeSuper) { |
| 646 assert(!omitEnclosing && !isStatic); | 622 assert(!omitEnclosing && !isStatic); |
| 647 if (e.superclass == null) { | 623 if (e.superclass == null) { |
| 648 omitEnclosing = true; | 624 omitEnclosing = true; |
| 649 } else { | 625 } else { |
| 650 // Members of the superclass are represented as a separate scope. | 626 // Members of the superclass are represented as a separate scope. |
| 651 serializeEnclosing = () { | 627 serializeEnclosing = () { |
| 652 serializeClassSide( | 628 serializeClassSide( |
| 653 e.superclass, isStatic: false, omitEnclosing: false, | 629 e.superclass, isStatic: false, omitEnclosing: false, |
| 654 includeSuper: true); | 630 includeSuper: true); |
| 655 }; | 631 }; |
| 656 } | 632 } |
| 657 } | 633 } |
| 658 serialize( | 634 serialize( |
| 659 e, omitEnclosing: omitEnclosing, serializeEnclosing: serializeEnclosing, | 635 e, omitEnclosing: omitEnclosing, serializeEnclosing: serializeEnclosing, |
| 660 kind: kind, serializeMembers: () { | 636 kind: kind, serializeMembers: () { |
| 661 e.forEachLocalMember((Element member) { | 637 localMembersSorted(e).forEach((Element member) { |
| 662 // Filter out members that don't belong to this "side". | 638 // Filter out members that don't belong to this "side". |
| 663 if (member.isConstructor) { | 639 if (member.isConstructor) { |
| 664 // In dart2js, some constructors aren't static, but that isn't | 640 // In dart2js, some constructors aren't static, but that isn't |
| 665 // convenient here. | 641 // convenient here. |
| 666 if (!isStatic) return; | 642 if (!isStatic) return; |
| 667 } else if (member.isStatic != isStatic) { | 643 } else if (member.isStatic != isStatic) { |
| 668 return; | 644 return; |
| 669 } | 645 } |
| 670 if (!isFirst) { | 646 if (!isFirst) { |
| 671 buffer.write(','); | 647 buffer.write(','); |
| 672 } | 648 } |
| 673 buffer.write('\n'); | 649 buffer.write('\n'); |
| 674 indented; | 650 indented; |
| 675 serialize(member); | 651 serialize(member); |
| 676 isFirst = false; | 652 isFirst = false; |
| 677 }); | 653 }); |
| 678 }); | 654 }); |
| 679 } | 655 } |
| 680 | 656 |
| 681 void visitScopeContainerElement(ScopeContainerElement e) { | 657 void visitScopeContainerElement(ScopeContainerElement e) { |
| 682 bool isFirst = true; | 658 bool isFirst = true; |
| 683 serialize(e, omitEnclosing: false, serializeMembers: () { | 659 serialize(e, omitEnclosing: false, serializeMembers: () { |
| 684 e.forEachLocalMember((Element member) { | 660 localMembersSorted(e).forEach((Element member) { |
| 685 if (!isFirst) { | 661 if (!isFirst) { |
| 686 buffer.write(','); | 662 buffer.write(','); |
| 687 } | 663 } |
| 688 buffer.write('\n'); | 664 buffer.write('\n'); |
| 689 indented; | 665 indented; |
| 690 serialize(member); | 666 serialize(member); |
| 691 isFirst = false; | 667 isFirst = false; |
| 692 }); | 668 }); |
| 693 }); | 669 }); |
| 694 } | 670 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 kind: kind, | 710 kind: kind, |
| 735 name: name); | 711 name: name); |
| 736 } | 712 } |
| 737 return; | 713 return; |
| 738 } | 714 } |
| 739 DartType type; | 715 DartType type; |
| 740 int category = element.kind.category; | 716 int category = element.kind.category; |
| 741 if (category == ElementCategory.FUNCTION || | 717 if (category == ElementCategory.FUNCTION || |
| 742 category == ElementCategory.VARIABLE || | 718 category == ElementCategory.VARIABLE || |
| 743 element.isConstructor) { | 719 element.isConstructor) { |
| 744 type = element.computeType(cachedCompiler); | 720 type = element.computeType(compiler); |
| 745 } | 721 } |
| 746 if (name == null) { | 722 if (name == null) { |
| 747 name = element.name; | 723 name = element.name; |
| 748 } | 724 } |
| 749 if (kind == null) { | 725 if (kind == null) { |
| 750 kind = '${element.kind}'; | 726 kind = '${element.kind}'; |
| 751 } | 727 } |
| 752 buffer.write('{\n'); | 728 buffer.write('{\n'); |
| 753 indentationLevel++; | 729 indentationLevel++; |
| 754 if (name != '') { | 730 if (name != '') { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 783 if (serializeEnclosing != null) { | 759 if (serializeEnclosing != null) { |
| 784 serializeEnclosing(); | 760 serializeEnclosing(); |
| 785 } else { | 761 } else { |
| 786 element.enclosingElement.accept(this); | 762 element.enclosingElement.accept(this); |
| 787 } | 763 } |
| 788 } | 764 } |
| 789 indentationLevel--; | 765 indentationLevel--; |
| 790 buffer.write('\n'); | 766 buffer.write('\n'); |
| 791 indented.write('}'); | 767 indented.write('}'); |
| 792 } | 768 } |
| 769 |
| 770 List<Element> localMembersSorted(ScopeContainerElement element) { |
| 771 List<Element> result = <Element>[]; |
| 772 element.forEachLocalMember((Element member) { |
| 773 result.add(member); |
| 774 }); |
| 775 return sortElements(result); |
| 776 } |
| 777 |
| 778 List<Element> sortElements(Iterable<Element> elements) { |
| 779 List<Element> result = new List<Element>.from(elements); |
| 780 if (sortMembers) { |
| 781 result.sort((Element a, Element b) => a.name.compareTo(b.name)); |
| 782 } else { |
| 783 throw "Not sorting result"; |
| 784 } |
| 785 return result; |
| 786 } |
| 793 } | 787 } |
| 794 | 788 |
| 795 modelx.ScopeX localScope(modelx.LibraryElementX element) => element.localScope; | 789 modelx.ScopeX localScope(modelx.LibraryElementX element) => element.localScope; |
| 796 | 790 |
| 797 modelx.ImportScope importScope(modelx.LibraryElementX element) { | 791 modelx.ImportScope importScope(modelx.LibraryElementX element) { |
| 798 return element.importScope; | 792 return element.importScope; |
| 799 } | 793 } |
| 800 | |
| 801 class PoiTask extends CompilerTask { | |
| 802 PoiTask(Compiler compiler) : super(compiler); | |
| 803 | |
| 804 String get name => 'POI'; | |
| 805 } | |
| OLD | NEW |