| 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; |
| 6 | 6 |
| 7 import 'dart:async' show | 7 import 'dart:async' show |
| 8 Completer, | 8 Completer, |
| 9 Future; | 9 Future; |
| 10 | 10 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 EOF_TOKEN, | 56 EOF_TOKEN, |
| 57 IDENTIFIER_TOKEN, | 57 IDENTIFIER_TOKEN, |
| 58 KEYWORD_TOKEN, | 58 KEYWORD_TOKEN, |
| 59 PartialClassElement, | 59 PartialClassElement, |
| 60 PartialElement, | 60 PartialElement, |
| 61 Token; | 61 Token; |
| 62 | 62 |
| 63 import 'package:compiler/src/js/js.dart' show | 63 import 'package:compiler/src/js/js.dart' show |
| 64 js; | 64 js; |
| 65 | 65 |
| 66 import 'scope_information_visitor.dart' show |
| 67 ScopeInformationVisitor; |
| 68 |
| 66 /// Enabled by the option --enable-dart-mind. Controls if this program should | 69 /// Enabled by the option --enable-dart-mind. Controls if this program should |
| 67 /// be querying Dart Mind. | 70 /// be querying Dart Mind. |
| 68 bool isDartMindEnabled = false; | 71 bool isDartMindEnabled = false; |
| 69 | 72 |
| 70 /// Iterator over lines from standard input (or the argument array). | 73 /// Iterator over lines from standard input (or the argument array). |
| 71 Iterator<String> stdin; | 74 Iterator<String> stdin; |
| 72 | 75 |
| 73 /// Enabled by the option --simulate-mutation. When true, this program will | 76 /// Enabled by the option --simulate-mutation. When true, this program will |
| 74 /// only prompt for one file name, and subsequent runs will read | 77 /// only prompt for one file name, and subsequent runs will read |
| 75 /// FILENAME.N.dart, where N starts at 1, and is increased on each iteration. | 78 /// FILENAME.N.dart, where N starts at 1, and is increased on each iteration. |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 485 } | 488 } |
| 486 | 489 |
| 487 Element findPosition(int position, Element element) { | 490 Element findPosition(int position, Element element) { |
| 488 FindPositionVisitor visitor = new FindPositionVisitor(position, element); | 491 FindPositionVisitor visitor = new FindPositionVisitor(position, element); |
| 489 element.accept(visitor); | 492 element.accept(visitor); |
| 490 return visitor.element; | 493 return visitor.element; |
| 491 } | 494 } |
| 492 | 495 |
| 493 String scopeInformation(Element element, int position) { | 496 String scopeInformation(Element element, int position) { |
| 494 ScopeInformationVisitor visitor = | 497 ScopeInformationVisitor visitor = |
| 495 new ScopeInformationVisitor(element, position); | 498 new ScopeInformationVisitor(cachedCompiler, element, position); |
| 496 element.accept(visitor); | 499 element.accept(visitor); |
| 497 return '${visitor.buffer}'; | 500 return '${visitor.buffer}'; |
| 498 } | 501 } |
| 499 | 502 |
| 500 class FindPositionVisitor extends ElementVisitor { | 503 class FindPositionVisitor extends ElementVisitor { |
| 501 final int position; | 504 final int position; |
| 502 Element element; | 505 Element element; |
| 503 | 506 |
| 504 FindPositionVisitor(this.position, this.element); | 507 FindPositionVisitor(this.position, this.element); |
| 505 | 508 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 void processWorkItem(void f(WorkItem work), WorkItem work) { | 541 void processWorkItem(void f(WorkItem work), WorkItem work) { |
| 539 if (work.element.library.canonicalUri == script) { | 542 if (work.element.library.canonicalUri == script) { |
| 540 f(work); | 543 f(work); |
| 541 printWallClock('Processed ${work.element}.'); | 544 printWallClock('Processed ${work.element}.'); |
| 542 } else { | 545 } else { |
| 543 printWallClock('Skipped ${work.element}.'); | 546 printWallClock('Skipped ${work.element}.'); |
| 544 } | 547 } |
| 545 } | 548 } |
| 546 } | 549 } |
| 547 | 550 |
| 548 /** | |
| 549 * Serializes scope information about an element. This is accomplished by | |
| 550 * calling the [serialize] method on each element. Some elements need special | |
| 551 * treatment, as their enclosing scope must also be serialized. | |
| 552 */ | |
| 553 class ScopeInformationVisitor extends ElementVisitor/* <void> */ { | |
| 554 // TODO(ahe): Include function parameters and local variables. | |
| 555 | |
| 556 final Element currentElement; | |
| 557 final int position; | |
| 558 final StringBuffer buffer = new StringBuffer(); | |
| 559 int indentationLevel = 0; | |
| 560 ClassElement currentClass; | |
| 561 | |
| 562 ScopeInformationVisitor(this.currentElement, this.position); | |
| 563 | |
| 564 String get indentation => ' ' * indentationLevel; | |
| 565 | |
| 566 StringBuffer get indented => buffer..write(indentation); | |
| 567 | |
| 568 void visitElement(Element e) { | |
| 569 serialize(e, omitEnclosing: false); | |
| 570 } | |
| 571 | |
| 572 void visitLibraryElement(LibraryElement e) { | |
| 573 bool isFirst = true; | |
| 574 forEach(Element member) { | |
| 575 if (!isFirst) { | |
| 576 buffer.write(','); | |
| 577 } | |
| 578 buffer.write('\n'); | |
| 579 indented; | |
| 580 serialize(member); | |
| 581 isFirst = false; | |
| 582 } | |
| 583 serialize( | |
| 584 e, | |
| 585 // TODO(ahe): We omit the import scope if there is no current | |
| 586 // class. That's wrong. | |
| 587 omitEnclosing: currentClass == null, | |
| 588 name: e.getLibraryName(), | |
| 589 serializeEnclosing: () { | |
| 590 // The enclosing scope of a library is a scope which contains all the | |
| 591 // imported names. | |
| 592 isFirst = true; | |
| 593 buffer.write('{\n'); | |
| 594 indentationLevel++; | |
| 595 indented.write('"kind": "imports",\n'); | |
| 596 indented.write('"members": ['); | |
| 597 indentationLevel++; | |
| 598 importScope(e).importScope.values.forEach(forEach); | |
| 599 indentationLevel--; | |
| 600 buffer.write('\n'); | |
| 601 indented.write('],\n'); | |
| 602 // The enclosing scope of the imported names scope is the superclass | |
| 603 // scope of the current class. | |
| 604 indented.write('"enclosing": '); | |
| 605 serializeClassSide( | |
| 606 currentClass.superclass, isStatic: false, includeSuper: true); | |
| 607 buffer.write('\n'); | |
| 608 indentationLevel--; | |
| 609 indented.write('}'); | |
| 610 }, | |
| 611 serializeMembers: () { | |
| 612 isFirst = true; | |
| 613 localScope(e).values.forEach(forEach); | |
| 614 }); | |
| 615 } | |
| 616 | |
| 617 void visitClassElement(ClassElement e) { | |
| 618 currentClass = e; | |
| 619 serializeClassSide(e, isStatic: true); | |
| 620 } | |
| 621 | |
| 622 /// 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 | |
| 624 /// 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 | |
| 626 /// constructors. | |
| 627 /// The scope chain is ordered so that the "class side" is searched before | |
| 628 /// the "instance side". | |
| 629 void serializeClassSide( | |
| 630 ClassElement e, | |
| 631 {bool isStatic: false, | |
| 632 bool omitEnclosing: false, | |
| 633 bool includeSuper: false}) { | |
| 634 bool isFirst = true; | |
| 635 var serializeEnclosing; | |
| 636 String kind; | |
| 637 if (isStatic) { | |
| 638 kind = 'class side'; | |
| 639 serializeEnclosing = () { | |
| 640 serializeClassSide(e, isStatic: false, omitEnclosing: omitEnclosing); | |
| 641 }; | |
| 642 } else { | |
| 643 kind = 'instance side'; | |
| 644 } | |
| 645 if (includeSuper) { | |
| 646 assert(!omitEnclosing && !isStatic); | |
| 647 if (e.superclass == null) { | |
| 648 omitEnclosing = true; | |
| 649 } else { | |
| 650 // Members of the superclass are represented as a separate scope. | |
| 651 serializeEnclosing = () { | |
| 652 serializeClassSide( | |
| 653 e.superclass, isStatic: false, omitEnclosing: false, | |
| 654 includeSuper: true); | |
| 655 }; | |
| 656 } | |
| 657 } | |
| 658 serialize( | |
| 659 e, omitEnclosing: omitEnclosing, serializeEnclosing: serializeEnclosing, | |
| 660 kind: kind, serializeMembers: () { | |
| 661 e.forEachLocalMember((Element member) { | |
| 662 // Filter out members that don't belong to this "side". | |
| 663 if (member.isConstructor) { | |
| 664 // In dart2js, some constructors aren't static, but that isn't | |
| 665 // convenient here. | |
| 666 if (!isStatic) return; | |
| 667 } else if (member.isStatic != isStatic) { | |
| 668 return; | |
| 669 } | |
| 670 if (!isFirst) { | |
| 671 buffer.write(','); | |
| 672 } | |
| 673 buffer.write('\n'); | |
| 674 indented; | |
| 675 serialize(member); | |
| 676 isFirst = false; | |
| 677 }); | |
| 678 }); | |
| 679 } | |
| 680 | |
| 681 void visitScopeContainerElement(ScopeContainerElement e) { | |
| 682 bool isFirst = true; | |
| 683 serialize(e, omitEnclosing: false, serializeMembers: () { | |
| 684 e.forEachLocalMember((Element member) { | |
| 685 if (!isFirst) { | |
| 686 buffer.write(','); | |
| 687 } | |
| 688 buffer.write('\n'); | |
| 689 indented; | |
| 690 serialize(member); | |
| 691 isFirst = false; | |
| 692 }); | |
| 693 }); | |
| 694 } | |
| 695 | |
| 696 void visitCompilationUnitElement(CompilationUnitElement e) { | |
| 697 e.enclosingElement.accept(this); | |
| 698 } | |
| 699 | |
| 700 void visitAbstractFieldElement(AbstractFieldElement e) { | |
| 701 throw new UnsupportedError('AbstractFieldElement cannot be serialized.'); | |
| 702 } | |
| 703 | |
| 704 void serialize( | |
| 705 Element element, | |
| 706 {bool omitEnclosing: true, | |
| 707 void serializeMembers(), | |
| 708 void serializeEnclosing(), | |
| 709 String kind, | |
| 710 String name}) { | |
| 711 if (element.isAbstractField) { | |
| 712 AbstractFieldElement field = element; | |
| 713 FunctionElement getter = field.getter; | |
| 714 FunctionElement setter = field.setter; | |
| 715 if (getter != null) { | |
| 716 serialize( | |
| 717 getter, | |
| 718 omitEnclosing: omitEnclosing, | |
| 719 serializeMembers: serializeMembers, | |
| 720 serializeEnclosing: serializeEnclosing, | |
| 721 kind: kind, | |
| 722 name: name); | |
| 723 } | |
| 724 if (setter != null) { | |
| 725 if (getter != null) { | |
| 726 buffer.write(',\n'); | |
| 727 indented; | |
| 728 } | |
| 729 serialize( | |
| 730 getter, | |
| 731 omitEnclosing: omitEnclosing, | |
| 732 serializeMembers: serializeMembers, | |
| 733 serializeEnclosing: serializeEnclosing, | |
| 734 kind: kind, | |
| 735 name: name); | |
| 736 } | |
| 737 return; | |
| 738 } | |
| 739 DartType type; | |
| 740 int category = element.kind.category; | |
| 741 if (category == ElementCategory.FUNCTION || | |
| 742 category == ElementCategory.VARIABLE || | |
| 743 element.isConstructor) { | |
| 744 type = element.computeType(cachedCompiler); | |
| 745 } | |
| 746 if (name == null) { | |
| 747 name = element.name; | |
| 748 } | |
| 749 if (kind == null) { | |
| 750 kind = '${element.kind}'; | |
| 751 } | |
| 752 buffer.write('{\n'); | |
| 753 indentationLevel++; | |
| 754 if (name != '') { | |
| 755 indented | |
| 756 ..write('"name": "') | |
| 757 ..write(name) | |
| 758 ..write('",\n'); | |
| 759 } | |
| 760 indented | |
| 761 ..write('"kind": "') | |
| 762 ..write(kind) | |
| 763 ..write('"'); | |
| 764 if (type != null) { | |
| 765 buffer.write(',\n'); | |
| 766 indented | |
| 767 ..write('"type": "') | |
| 768 ..write(type) | |
| 769 ..write('"'); | |
| 770 } | |
| 771 if (serializeMembers != null) { | |
| 772 buffer.write(',\n'); | |
| 773 indented.write('"members": ['); | |
| 774 indentationLevel++; | |
| 775 serializeMembers(); | |
| 776 indentationLevel--; | |
| 777 buffer.write('\n'); | |
| 778 indented.write(']'); | |
| 779 } | |
| 780 if (!omitEnclosing) { | |
| 781 buffer.write(',\n'); | |
| 782 indented.write('"enclosing": '); | |
| 783 if (serializeEnclosing != null) { | |
| 784 serializeEnclosing(); | |
| 785 } else { | |
| 786 element.enclosingElement.accept(this); | |
| 787 } | |
| 788 } | |
| 789 indentationLevel--; | |
| 790 buffer.write('\n'); | |
| 791 indented.write('}'); | |
| 792 } | |
| 793 } | |
| 794 | |
| 795 modelx.ScopeX localScope(modelx.LibraryElementX element) => element.localScope; | |
| 796 | |
| 797 modelx.ImportScope importScope(modelx.LibraryElementX element) { | |
| 798 return element.importScope; | |
| 799 } | |
| 800 | |
| 801 class PoiTask extends CompilerTask { | 551 class PoiTask extends CompilerTask { |
| 802 PoiTask(Compiler compiler) : super(compiler); | 552 PoiTask(Compiler compiler) : super(compiler); |
| 803 | 553 |
| 804 String get name => 'POI'; | 554 String get name => 'POI'; |
| 805 } | 555 } |
| OLD | NEW |