Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Side by Side Diff: pkg/dartdoc/lib/dartdoc.dart

Issue 10985085: Members and comments inherited in dartdoc. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebased. Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/dartdoc/lib/mirrors.dart » ('j') | pkg/dartdoc/lib/mirrors_util.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 /** 5 /**
6 * To generate docs for a library, run this script with the path to an 6 * To generate docs for a library, run this script with the path to an
7 * entrypoint .dart file, like: 7 * entrypoint .dart file, like:
8 * 8 *
9 * $ dart dartdoc.dart foo.dart 9 * $ dart dartdoc.dart foo.dart
10 * 10 *
(...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 final List members = docMembersJson(library.declaredMembers); 568 final List members = docMembersJson(library.declaredMembers);
569 if (!members.isEmpty()) { 569 if (!members.isEmpty()) {
570 libraryInfo[MEMBERS] = members; 570 libraryInfo[MEMBERS] = members;
571 } 571 }
572 572
573 final types = []; 573 final types = [];
574 for (InterfaceMirror type in orderByName(library.types.getValues())) { 574 for (InterfaceMirror type in orderByName(library.types.getValues())) {
575 if (type.isPrivate) continue; 575 if (type.isPrivate) continue;
576 576
577 var typeInfo = {}; 577 var typeInfo = {};
578 typeInfo[NAME] = type.simpleName; 578 typeInfo[NAME] = type.displayName;
579 if (type.isClass) { 579 if (type.isClass) {
580 typeInfo[KIND] = CLASS; 580 typeInfo[KIND] = CLASS;
581 } else if (type.isInterface) { 581 } else if (type.isInterface) {
582 typeInfo[KIND] = INTERFACE; 582 typeInfo[KIND] = INTERFACE;
583 } else { 583 } else {
584 assert(type.isTypedef); 584 assert(type.isTypedef);
585 typeInfo[KIND] = TYPEDEF; 585 typeInfo[KIND] = TYPEDEF;
586 } 586 }
587 final List typeMembers = docMembersJson(type.declaredMembers); 587 final List typeMembers = docMembersJson(type.declaredMembers);
588 if (!typeMembers.isEmpty()) { 588 if (!typeMembers.isEmpty()) {
589 typeInfo[MEMBERS] = typeMembers; 589 typeInfo[MEMBERS] = typeMembers;
590 } 590 }
591 591
592 if (!type.declaration.typeVariables.isEmpty()) { 592 if (!type.declaration.typeVariables.isEmpty()) {
593 final typeVariables = []; 593 final typeVariables = [];
594 for (final typeVariable in type.declaration.typeVariables) { 594 for (final typeVariable in type.declaration.typeVariables) {
595 typeVariables.add(typeVariable.simpleName); 595 typeVariables.add(typeVariable.displayName);
596 } 596 }
597 typeInfo[ARGS] = Strings.join(typeVariables, ', '); 597 typeInfo[ARGS] = Strings.join(typeVariables, ', ');
598 } 598 }
599 types.add(typeInfo); 599 types.add(typeInfo);
600 } 600 }
601 if (!types.isEmpty()) { 601 if (!types.isEmpty()) {
602 libraryInfo[TYPES] = types; 602 libraryInfo[TYPES] = types;
603 } 603 }
604 604
605 libraryList.add(libraryInfo); 605 libraryList.add(libraryInfo);
606 } 606 }
607 607
608 List docMembersJson(Map<Object,MemberMirror> memberMap) { 608 List docMembersJson(Map<Object,MemberMirror> memberMap) {
609 final members = []; 609 final members = [];
610 for (MemberMirror member in orderByName(memberMap.getValues())) { 610 for (MemberMirror member in orderByName(memberMap.getValues())) {
611 if (member.isPrivate) continue; 611 if (member.isPrivate) continue;
612 612
613 var memberInfo = {}; 613 var memberInfo = {};
614 if (member.isField) { 614 if (member.isField) {
615 memberInfo[NAME] = member.simpleName;
616 memberInfo[KIND] = FIELD; 615 memberInfo[KIND] = FIELD;
617 } else { 616 } else {
618 MethodMirror method = member; 617 MethodMirror method = member;
619 if (method.isConstructor) { 618 if (method.isConstructor) {
620 if (method.constructorName != '') { 619 memberInfo[KIND] = CONSTRUCTOR;
621 memberInfo[NAME] = '${method.simpleName}.${method.constructorName}';
622 memberInfo[KIND] = CONSTRUCTOR;
623 } else {
624 memberInfo[NAME] = member.simpleName;
625 memberInfo[KIND] = CONSTRUCTOR;
626 }
627 } else if (method.isOperator) {
628 memberInfo[NAME] = '${method.simpleName} ${method.operatorName}';
629 memberInfo[KIND] = METHOD;
630 } else if (method.isSetter) { 620 } else if (method.isSetter) {
631 memberInfo[NAME] = member.simpleName;
632 memberInfo[KIND] = SETTER; 621 memberInfo[KIND] = SETTER;
633 } else if (method.isGetter) { 622 } else if (method.isGetter) {
634 memberInfo[NAME] = member.simpleName;
635 memberInfo[KIND] = GETTER; 623 memberInfo[KIND] = GETTER;
636 } else { 624 } else {
637 memberInfo[NAME] = member.simpleName;
638 memberInfo[KIND] = METHOD; 625 memberInfo[KIND] = METHOD;
639 } 626 }
640 } 627 }
628 memberInfo[NAME] = member.displayName;
641 var anchor = memberAnchor(member); 629 var anchor = memberAnchor(member);
642 if (anchor != memberInfo[NAME]) { 630 if (anchor != memberInfo[NAME]) {
643 memberInfo[LINK_NAME] = anchor; 631 memberInfo[LINK_NAME] = anchor;
644 } 632 }
645 members.add(memberInfo); 633 members.add(memberInfo);
646 } 634 }
647 return members; 635 return members;
648 } 636 }
649 637
650 void docNavigation() { 638 void docNavigation() {
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 _currentType = null; 713 _currentType = null;
726 714
727 startFile(libraryUrl(library)); 715 startFile(libraryUrl(library));
728 writeHeader('${library.simpleName} Library', 716 writeHeader('${library.simpleName} Library',
729 [library.simpleName, libraryUrl(library)]); 717 [library.simpleName, libraryUrl(library)]);
730 writeln('<h2><strong>${library.simpleName}</strong> library</h2>'); 718 writeln('<h2><strong>${library.simpleName}</strong> library</h2>');
731 719
732 // Look for a comment for the entire library. 720 // Look for a comment for the entire library.
733 final comment = getLibraryComment(library); 721 final comment = getLibraryComment(library);
734 if (comment != null) { 722 if (comment != null) {
735 writeln('<div class="doc">$comment</div>'); 723 writeln('<div class="doc">${comment.html}</div>');
736 } 724 }
737 725
738 // Document the top-level members. 726 // Document the top-level members.
739 docMembers(library); 727 docMembers(library);
740 728
741 // Document the types. 729 // Document the types.
742 final classes = <InterfaceMirror>[]; 730 final classes = <InterfaceMirror>[];
743 final interfaces = <InterfaceMirror>[]; 731 final interfaces = <InterfaceMirror>[];
744 final typedefs = <TypedefMirror>[]; 732 final typedefs = <TypedefMirror>[];
745 final exceptions = <InterfaceMirror>[]; 733 final exceptions = <InterfaceMirror>[];
(...skipping 25 matching lines...) Expand all
771 for (final type in library.types.getValues()) { 759 for (final type in library.types.getValues()) {
772 if (type.isPrivate) continue; 760 if (type.isPrivate) continue;
773 761
774 docType(type); 762 docType(type);
775 } 763 }
776 } 764 }
777 765
778 void docTypes(List types, String header) { 766 void docTypes(List types, String header) {
779 if (types.length == 0) return; 767 if (types.length == 0) return;
780 768
769 writeln('<div>');
781 writeln('<h3>$header</h3>'); 770 writeln('<h3>$header</h3>');
782 771
783 for (final type in types) { 772 for (final type in types) {
784 writeln( 773 writeln(
785 ''' 774 '''
786 <div class="type"> 775 <div class="type">
787 <h4> 776 <h4>
788 ${a(typeUrl(type), "<strong>${typeName(type)}</strong>")} 777 ${a(typeUrl(type), "<strong>${typeName(type)}</strong>")}
789 </h4> 778 </h4>
790 </div> 779 </div>
791 '''); 780 ''');
792 } 781 }
782 writeln('</div>');
793 } 783 }
794 784
795 void docType(InterfaceMirror type) { 785 void docType(InterfaceMirror type) {
796 if (verbose) { 786 if (verbose) {
797 print('- ${type.simpleName}'); 787 print('- ${type.simpleName}');
798 } 788 }
799 _totalTypes++; 789 _totalTypes++;
800 _currentType = type; 790 _currentType = type;
801 791
802 startFile(typeUrl(type)); 792 startFile(typeUrl(type));
(...skipping 13 matching lines...) Expand all
816 '${typeName(type)} ${kind}'; 806 '${typeName(type)} ${kind}';
817 writeHeader('$typeTitle / ${type.library.simpleName} Library', 807 writeHeader('$typeTitle / ${type.library.simpleName} Library',
818 [type.library.simpleName, libraryUrl(type.library), 808 [type.library.simpleName, libraryUrl(type.library),
819 typeName(type), typeUrl(type)]); 809 typeName(type), typeUrl(type)]);
820 writeln( 810 writeln(
821 ''' 811 '''
822 <h2><strong>${typeName(type, showBounds: true)}</strong> 812 <h2><strong>${typeName(type, showBounds: true)}</strong>
823 $kind 813 $kind
824 </h2> 814 </h2>
825 '''); 815 ''');
816 writeln('<span class="show-inherited">Hide inherited</span>');
Lasse Reichstein Nielsen 2012/10/04 07:41:19 Use a button! This is clearly a clickable thing wi
Johnni Winther 2012/10/04 12:46:21 Done.
826 817
827 docCode(type.location, getTypeComment(type)); 818 docCode(type, type.location, getTypeComment(type));
828 docInheritance(type); 819 docInheritance(type);
829 docTypedef(type); 820 docTypedef(type);
821
830 docConstructors(type); 822 docConstructors(type);
831 docMembers(type); 823 docMembers(type);
832 824
833 writeTypeFooter(); 825 writeTypeFooter();
834 writeFooter(); 826 writeFooter();
835 endFile(); 827 endFile();
836 } 828 }
837 829
838 /** Override this to write additional content at the end of a type's page. */ 830 /** Override this to write additional content at the end of a type's page. */
839 void writeTypeFooter() { 831 void writeTypeFooter() {
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
914 typeSpan(supertypes[i]); 906 typeSpan(supertypes[i]);
915 write('&nbsp;&gt;&nbsp;'); 907 write('&nbsp;&gt;&nbsp;');
916 } 908 }
917 909
918 // Write this class. 910 // Write this class.
919 typeSpan(type); 911 typeSpan(type);
920 writeln('</p>'); 912 writeln('</p>');
921 } 913 }
922 914
923 listTypes(subtypes, 'Subclasses'); 915 listTypes(subtypes, 'Subclasses');
924 listTypes(type.interfaces.getValues(), 'Implements'); 916 listTypes(type.interfaces, 'Implements');
925 } else { 917 } else {
926 // Show the default class. 918 // Show the default class.
927 if (type.defaultType != null) { 919 if (type.defaultType != null) {
928 listTypes([type.defaultType], 'Default class'); 920 listTypes([type.defaultType], 'Default class');
929 } 921 }
930 922
931 // List extended interfaces. 923 // List extended interfaces.
932 listTypes(type.interfaces.getValues(), 'Extends'); 924 listTypes(type.interfaces, 'Extends');
933 925
934 // List subinterfaces and implementing classes. 926 // List subinterfaces and implementing classes.
935 final subinterfaces = []; 927 final subinterfaces = [];
936 final implementing = []; 928 final implementing = [];
937 929
938 for (final subtype in subtypes) { 930 for (final subtype in subtypes) {
939 if (subtype.isClass) { 931 if (subtype.isClass) {
940 implementing.add(subtype); 932 implementing.add(subtype);
941 } else { 933 } else {
942 subinterfaces.add(subtype); 934 subinterfaces.add(subtype);
(...skipping 18 matching lines...) Expand all
961 writeln('<span class="show-code">Code</span>'); 953 writeln('<span class="show-code">Code</span>');
962 } 954 }
963 955
964 write('typedef '); 956 write('typedef ');
965 annotateType(type, type.definition, type.simpleName); 957 annotateType(type, type.definition, type.simpleName);
966 958
967 write(''' <a class="anchor-link" href="#${type.simpleName}" 959 write(''' <a class="anchor-link" href="#${type.simpleName}"
968 title="Permalink to ${type.simpleName}">#</a>'''); 960 title="Permalink to ${type.simpleName}">#</a>''');
969 writeln('</h4>'); 961 writeln('</h4>');
970 962
971 docCode(type.location, null, showCode: true); 963 docCode(type, type.location, null, showCode: true);
972 964
973 writeln('</div>'); 965 writeln('</div>');
974 } 966 }
975 967
976 /** Document the constructors for [Type], if any. */ 968 /** Document the constructors for [Type], if any. */
977 void docConstructors(InterfaceMirror type) { 969 void docConstructors(InterfaceMirror type) {
978 final constructors = <MethodMirror>[]; 970 final constructors = <MethodMirror>[];
979 for (var constructor in type.constructors.getValues()) { 971 for (var constructor in type.constructors.getValues()) {
980 if (!constructor.isPrivate) { 972 if (!constructor.isPrivate) {
981 constructors.add(constructor); 973 constructors.add(constructor);
982 } 974 }
983 } 975 }
984 976
985 if (constructors.length > 0) { 977 if (constructors.length > 0) {
978 writeln('<div>');
986 writeln('<h3>Constructors</h3>'); 979 writeln('<h3>Constructors</h3>');
987 constructors.sort((x, y) => x.simpleName.toUpperCase().compareTo( 980 constructors.sort((x, y) => x.simpleName.toUpperCase().compareTo(
988 y.simpleName.toUpperCase())); 981 y.simpleName.toUpperCase()));
989 982
990 for (final constructor in constructors) { 983 for (final constructor in constructors) {
991 docMethod(type, constructor); 984 docMethod(type, constructor);
992 } 985 }
986 writeln('</div>');
993 } 987 }
994 } 988 }
995 989
996 void docMembers(ObjectMirror host) { 990 void docMembers(ObjectMirror host) {
997 // Collect the different kinds of members. 991 // Collect the different kinds of members.
998 final staticMethods = []; 992 final staticMethods = [];
999 final staticFields = []; 993 final staticFields = [];
994 final memberMap = new Map<String,MemberMirror>();
1000 final instanceMethods = []; 995 final instanceMethods = [];
1001 final instanceFields = []; 996 final instanceFields = [];
1002 997
1003 for (MemberMirror member in orderByName(host.declaredMembers.getValues())) { 998 host.declaredMembers.forEach((_, MemberMirror member) {
Lasse Reichstein Nielsen 2012/10/04 07:41:19 Add a host.forEachDeclaredMember method instead of
Johnni Winther 2012/10/04 12:46:21 [declaredMembers] is also used for lookup where th
1004 if (member.isPrivate) continue; 999 if (member.isPrivate) return;
1000 if (member.isStatic) {
1001 if (member.isMethod) {
1002 staticMethods.add(member);
1003 } else if (member.isField) {
1004 staticFields.add(member);
1005 }
1006 }
1007 });
1005 1008
1006 final methods = member.isStatic ? staticMethods : instanceMethods; 1009 if (host is InterfaceMirror) {
1007 final fields = member.isStatic ? staticFields : instanceFields; 1010 var iterable = new HierarchyIterable(host, includeType: true);
1011 for (InterfaceMirror type in iterable) {
1012 type.declaredMembers.forEach((_, MemberMirror member) {
1013 if (member.isPrivate) return;
1014 if (!member.isStatic) {
1015 memberMap.putIfAbsent(member.simpleName, () => member);
1016 }
1017 });
1018 }
1019 }
1008 1020
1021 memberMap.forEach((_, MemberMirror member) {
1009 if (member.isMethod) { 1022 if (member.isMethod) {
1010 methods.add(member); 1023 instanceMethods.add(member);
1011 } else if (member.isField) { 1024 } else if (member.isField) {
1012 fields.add(member); 1025 instanceFields.add(member);
1013 } 1026 }
1027 });
1028
1029 if (staticFields.length > 0) {
1030 final title = host is LibraryMirror ? 'Variables' : 'Static Fields';
1031 writeln('<div>');
1032 writeln('<h3>$title</h3>');
1033 for (final field in orderByName(staticFields)) {
1034 docField(host, field);
1035 }
1036 writeln('</div>');
1014 } 1037 }
1015 1038
1016 if (staticMethods.length > 0) { 1039 if (staticMethods.length > 0) {
1017 final title = host is LibraryMirror ? 'Functions' : 'Static Methods'; 1040 final title = host is LibraryMirror ? 'Functions' : 'Static Methods';
1041 writeln('<div>');
Lasse Reichstein Nielsen 2012/10/04 07:41:19 Why wrap it in a div if it doesn't even have a cla
Johnni Winther 2012/10/04 12:46:21 Not quite sure. It was requested in dartbug.com/11
1018 writeln('<h3>$title</h3>'); 1042 writeln('<h3>$title</h3>');
1019 for (final method in orderByName(staticMethods)) { 1043 for (final method in orderByName(staticMethods)) {
1020 docMethod(host, method); 1044 docMethod(host, method);
1021 } 1045 }
1046 writeln('</div>');
1022 } 1047 }
1023 1048
1024 if (staticFields.length > 0) { 1049 if (instanceFields.length > 0) {
1025 final title = host is LibraryMirror ? 'Variables' : 'Static Fields'; 1050 writeln('<div>');
1026 writeln('<h3>$title</h3>'); 1051 writeln('<h3>Fields</h3>');
1027 for (final field in orderByName(staticFields)) { 1052 for (final field in orderByName(instanceFields)) {
1028 docField(host, field); 1053 docField(host, field);
1029 } 1054 }
1055 writeln('</div>');
1030 } 1056 }
1031 1057
1032 if (instanceMethods.length > 0) { 1058 if (instanceMethods.length > 0) {
1059 writeln('<div>');
1033 writeln('<h3>Methods</h3>'); 1060 writeln('<h3>Methods</h3>');
1034 for (final method in orderByName(instanceMethods)) { 1061 for (final method in orderByName(instanceMethods)) {
1035 docMethod(host, method); 1062 docMethod(host, method);
1036 } 1063 }
1037 } 1064 writeln('</div>');
1038
1039 if (instanceFields.length > 0) {
1040 writeln('<h3>Fields</h3>');
1041 for (final field in orderByName(instanceFields)) {
1042 docField(host, field);
1043 }
1044 } 1065 }
1045 } 1066 }
1046 1067
1047 /** 1068 /**
1048 * Documents the [method] in type [type]. Handles all kinds of methods 1069 * Documents the [method] in type [type]. Handles all kinds of methods
1049 * including getters, setters, and constructors. 1070 * including getters, setters, and constructors.
1050 */ 1071 */
1051 void docMethod(ObjectMirror host, MethodMirror method) { 1072 void docMethod(ObjectMirror host, MethodMirror method) {
1052 _totalMembers++; 1073 _totalMembers++;
1053 _currentMember = method; 1074 _currentMember = method;
1054 1075
1055 bool showCode = includeSource && !method.isAbstract; 1076 bool showCode = includeSource && !method.isAbstract;
1077 bool inherited = host != method.surroundingDeclaration;
1056 1078
1057 writeln('<div class="method"><h4 id="${memberAnchor(method)}">'); 1079 writeln('<div class="method${inherited ? ' inherited': ''}">'
1080 '<h4 id="${memberAnchor(method)}">');
1058 1081
1059 if (showCode) { 1082 if (showCode) {
1060 writeln('<span class="show-code">Code</span>'); 1083 writeln('<span class="show-code">Code</span>');
1061 } 1084 }
1062 1085
1063 if (method.isConstructor) { 1086 if (method.isConstructor) {
1064 if (method.isFactory) { 1087 if (method.isFactory) {
1065 write('factory '); 1088 write('factory ');
1066 } else { 1089 } else {
1067 write(method.isConst ? 'const ' : 'new '); 1090 write(method.isConst ? 'const ' : 'new ');
1068 } 1091 }
1069 } else if (method.isAbstract) { 1092 } else if (method.isAbstract) {
1070 write('abstract '); 1093 write('abstract ');
1071 } 1094 }
1072 1095
1073 if (method.constructorName == null) { 1096 if (!method.isConstructor) {
1074 annotateType(host, method.returnType); 1097 annotateType(host, method.returnType);
1075 } 1098 }
1076 1099
1077 var name = method.simpleName; 1100 var name = method.displayName;
1078 // Translate specially-named methods: getters, setters, operators. 1101 // Translate specially-named methods: getters, setters, operators.
1079 if (method.isGetter) { 1102 if (method.isGetter) {
1080 // Getter. 1103 // Getter.
1081 name = 'get $name'; 1104 name = 'get $name';
1082 } else if (method.isSetter) { 1105 } else if (method.isSetter) {
1083 // Setter. 1106 // Setter.
1084 name = 'set $name'; 1107 name = 'set $name';
1085 } else if (method.isOperator) {
1086 name = 'operator ${method.operatorName}';
1087 } 1108 }
1088 1109
1089 write('<strong>$name</strong>'); 1110 write('<strong>$name</strong>');
1090 1111
1091 // Named constructors.
1092 if (method.constructorName != null && method.constructorName != '') {
1093 write('.');
1094 write(method.constructorName);
1095 }
1096
1097 docParamList(host, method.parameters); 1112 docParamList(host, method.parameters);
1098 1113
1099 var prefix = host is LibraryMirror ? '' : '${typeName(host)}.'; 1114 var prefix = host is LibraryMirror ? '' : '${typeName(host)}.';
1100 write(''' <a class="anchor-link" href="#${memberAnchor(method)}" 1115 write(''' <a class="anchor-link" href="#${memberAnchor(method)}"
1101 title="Permalink to $prefix$name">#</a>'''); 1116 title="Permalink to $prefix$name">#</a>''');
1102 writeln('</h4>'); 1117 writeln('</h4>');
1103 1118
1104 docCode(method.location, getMethodComment(method), showCode: showCode); 1119 if (inherited) {
1120 write('<div class="inherited-from">inherited from ');
1121 annotateType(host, method.surroundingDeclaration);
1122 write('</div>');
1123 }
1124
1125 docCode(host, method.location, getMemberComment(method), showCode: showCode) ;
1105 1126
1106 writeln('</div>'); 1127 writeln('</div>');
1107 } 1128 }
1108 1129
1109 /** Documents the field [field] of type [type]. */ 1130 /** Documents the field [field] of type [type]. */
1110 void docField(ObjectMirror host, FieldMirror field) { 1131 void docField(ObjectMirror host, FieldMirror field) {
1111 _totalMembers++; 1132 _totalMembers++;
1112 _currentMember = field; 1133 _currentMember = field;
1113 1134
1114 writeln('<div class="field"><h4 id="${memberAnchor(field)}">'); 1135 bool inherited = host != field.surroundingDeclaration;
1136
1137 writeln('<div class="field${inherited ? ' inherited' : ''}">'
1138 '<h4 id="${memberAnchor(field)}">');
1115 1139
1116 if (includeSource) { 1140 if (includeSource) {
1117 writeln('<span class="show-code">Code</span>'); 1141 writeln('<span class="show-code">Code</span>');
1118 } 1142 }
1119 1143
1120 if (field.isFinal) { 1144 if (field.isFinal) {
1121 write('final '); 1145 write('final ');
1122 } else if (field.type.isDynamic) { 1146 } else if (field.type.isDynamic) {
1123 write('var '); 1147 write('var ');
1124 } 1148 }
1125 1149
1126 annotateType(host, field.type); 1150 annotateType(host, field.type);
1127 var prefix = host is LibraryMirror ? '' : '${typeName(host)}.'; 1151 var prefix = host is LibraryMirror ? '' : '${typeName(host)}.';
1128 write( 1152 write(
1129 ''' 1153 '''
1130 <strong>${field.simpleName}</strong> <a class="anchor-link" 1154 <strong>${field.simpleName}</strong> <a class="anchor-link"
1131 href="#${memberAnchor(field)}" 1155 href="#${memberAnchor(field)}"
1132 title="Permalink to $prefix${field.simpleName}">#</a> 1156 title="Permalink to $prefix${field.simpleName}">#</a>
1133 </h4> 1157 </h4>
1134 '''); 1158 ''');
1135 1159
1136 docCode(field.location, getFieldComment(field), showCode: true); 1160 if (inherited) {
1161 write('<div class="inherited-from">inherited from ');
1162 annotateType(host, field.surroundingDeclaration);
1163 write('</div>');
1164 }
1165
1166 docCode(host, field.location, getMemberComment(field), showCode: true);
1167
1137 writeln('</div>'); 1168 writeln('</div>');
1138 } 1169 }
1139 1170
1140 void docParamList(ObjectMirror enclosingType, 1171 void docParamList(ObjectMirror enclosingType,
1141 List<ParameterMirror> parameters) { 1172 List<ParameterMirror> parameters) {
1142 write('('); 1173 write('(');
1143 bool first = true; 1174 bool first = true;
1144 bool inOptionals = false; 1175 bool inOptionals = false;
1145 for (final parameter in parameters) { 1176 for (final parameter in parameters) {
1146 if (!first) write(', '); 1177 if (!first) write(', ');
(...skipping 15 matching lines...) Expand all
1162 } 1193 }
1163 1194
1164 if (inOptionals) write(']'); 1195 if (inOptionals) write(']');
1165 write(')'); 1196 write(')');
1166 } 1197 }
1167 1198
1168 /** 1199 /**
1169 * Documents the code contained within [span] with [comment]. If [showCode] 1200 * Documents the code contained within [span] with [comment]. If [showCode]
1170 * is `true` (and [includeSource] is set), also includes the source code. 1201 * is `true` (and [includeSource] is set), also includes the source code.
1171 */ 1202 */
1172 void docCode(Location location, String comment, [bool showCode = false]) { 1203 void docCode(ObjectMirror host, Location location, DocComment comment,
1204 [bool showCode = false]) {
1173 writeln('<div class="doc">'); 1205 writeln('<div class="doc">');
1174 if (comment != null) { 1206 if (comment != null) {
1175 writeln(comment); 1207 if (comment.inheritedFrom !== null) {
1208 writeln('<div class="inherited">');
1209 writeln(comment.html);
1210 write('<div class="docs-inherited-from">docs inherited from ');
1211 annotateType(host, comment.inheritedFrom);
1212 write('</div>');
1213 writeln('</div>');
1214 } else {
1215 writeln(comment.html);
1216 }
1176 } 1217 }
1177 1218
1178 if (includeSource && showCode) { 1219 if (includeSource && showCode) {
1179 writeln('<pre class="source">'); 1220 writeln('<pre class="source">');
1180 writeln(md.escapeHtml(unindentCode(location))); 1221 writeln(md.escapeHtml(unindentCode(location)));
1181 writeln('</pre>'); 1222 writeln('</pre>');
1182 } 1223 }
1183 1224
1184 writeln('</div>'); 1225 writeln('</div>');
1185 } 1226 }
1186 1227
1228 DocComment createDocComment(String text, [InterfaceMirror inheritedFrom]) =>
1229 new DocComment(text, inheritedFrom);
1230
1187 1231
1188 /** Get the doc comment associated with the given library. */ 1232 /** Get the doc comment associated with the given library. */
1189 String getLibraryComment(LibraryMirror library) { 1233 DocComment getLibraryComment(LibraryMirror library) {
1190 // Look for a comment for the entire library. 1234 // Look for a comment for the entire library.
1191 final comment = _comments.findLibrary(library.location.source); 1235 final comment = _comments.findLibrary(library.location.source);
1192 if (comment != null) { 1236 if (comment == null) return null;
1193 return md.markdownToHtml(comment); 1237 return createDocComment(comment);
1194 }
1195 return null;
1196 } 1238 }
1197 1239
1198 /** Get the doc comment associated with the given type. */ 1240 /** Get the doc comment associated with the given type. */
1199 String getTypeComment(TypeMirror type) { 1241 DocComment getTypeComment(TypeMirror type) {
1200 String comment = _comments.find(type.location); 1242 String comment = _comments.find(type.location);
1201 if (comment == null) return null; 1243 if (comment == null) return null;
1202 return commentToHtml(comment); 1244 return createDocComment(comment);
1203 } 1245 }
1204 1246
1205 /** Get the doc comment associated with the given method. */ 1247 /**
1206 String getMethodComment(MethodMirror method) { 1248 * Get the doc comment associated with the given member.
1207 String comment = _comments.find(method.location); 1249 *
1250 * If no comment was found on the member, the hierarchy is traversed to find
1251 * an inherited comment, favouring comments inherited from classes over
1252 * comments inherited from interfaces.
1253 */
1254 DocComment getMemberComment(MemberMirror member) {
1255 String comment = _comments.find(member.location);
1256 InterfaceMirror inheritedFrom = null;
1257 if (comment == null) {
1258 if (member.surroundingDeclaration is InterfaceMirror) {
1259 var iterable =
1260 new HierarchyIterable(member.surroundingDeclaration,
1261 includeType: false);
1262 for (InterfaceMirror type in iterable) {
1263 var inheritedMember = type.declaredMembers[member.simpleName];
1264 if (inheritedMember is MemberMirror) {
1265 comment = _comments.find(inheritedMember.location);
1266 if (comment != null) {
1267 inheritedFrom = type;
1268 break;
1269 }
1270 }
1271 }
1272 }
1273 }
1208 if (comment == null) return null; 1274 if (comment == null) return null;
1209 return commentToHtml(comment); 1275 return createDocComment(comment, inheritedFrom);
1210 } 1276 }
1211 1277
1212 /** Get the doc comment associated with the given field. */
1213 String getFieldComment(FieldMirror field) {
1214 String comment = _comments.find(field.location);
1215 if (comment == null) return null;
1216 return commentToHtml(comment);
1217 }
1218
1219 String commentToHtml(String comment) => md.markdownToHtml(comment);
1220
1221 /** 1278 /**
1222 * Converts [fullPath] which is understood to be a full path from the root of 1279 * Converts [fullPath] which is understood to be a full path from the root of
1223 * the generated docs to one relative to the current file. 1280 * the generated docs to one relative to the current file.
1224 */ 1281 */
1225 String relativePath(String fullPath) { 1282 String relativePath(String fullPath) {
1226 // Don't make it relative if it's an absolute path. 1283 // Don't make it relative if it's an absolute path.
1227 if (isAbsolute(fullPath)) return fullPath; 1284 if (isAbsolute(fullPath)) return fullPath;
1228 1285
1229 // TODO(rnystrom): Walks all the way up to root each time. Shouldn't do 1286 // TODO(rnystrom): Walks all the way up to root each time. Shouldn't do
1230 // this if the paths overlap. 1287 // this if the paths overlap.
(...skipping 28 matching lines...) Expand all
1259 } 1316 }
1260 1317
1261 /** Gets the URL for the documentation for [member]. */ 1318 /** Gets the URL for the documentation for [member]. */
1262 String memberUrl(MemberMirror member) { 1319 String memberUrl(MemberMirror member) {
1263 String url = typeUrl(member.surroundingDeclaration); 1320 String url = typeUrl(member.surroundingDeclaration);
1264 return '$url#${memberAnchor(member)}'; 1321 return '$url#${memberAnchor(member)}';
1265 } 1322 }
1266 1323
1267 /** Gets the anchor id for the document for [member]. */ 1324 /** Gets the anchor id for the document for [member]. */
1268 String memberAnchor(MemberMirror member) { 1325 String memberAnchor(MemberMirror member) {
1269 if (member.isField) { 1326 return member.simpleName;
1270 return member.simpleName;
1271 }
1272 MethodMirror method = member;
1273 if (method.isConstructor) {
1274 if (method.constructorName == '') {
1275 return method.simpleName;
1276 } else {
1277 return '${method.simpleName}.${method.constructorName}';
1278 }
1279 } else if (method.isOperator) {
1280 return '${method.simpleName} ${method.operatorName}';
1281 } else if (method.isSetter) {
1282 return '${method.simpleName}=';
1283 } else {
1284 return method.simpleName;
1285 }
1286 } 1327 }
1287 1328
1288 /** 1329 /**
1289 * Creates a hyperlink. Handles turning the [href] into an appropriate 1330 * Creates a hyperlink. Handles turning the [href] into an appropriate
1290 * relative path from the current file. 1331 * relative path from the current file.
1291 */ 1332 */
1292 String a(String href, String contents, [String css]) { 1333 String a(String href, String contents, [String css]) {
1293 // Mark outgoing external links, mainly so we can style them. 1334 // Mark outgoing external links, mainly so we can style them.
1294 final rel = isAbsolute(href) ? ' ref="external"' : ''; 1335 final rel = isAbsolute(href) ? ' ref="external"' : '';
1295 final cssClass = css == null ? '' : ' class="$css"'; 1336 final cssClass = css == null ? '' : ' class="$css"';
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
1469 if (parameter.simpleName == name) { 1510 if (parameter.simpleName == name) {
1470 final element = new md.Element.text('span', name); 1511 final element = new md.Element.text('span', name);
1471 element.attributes['class'] = 'param'; 1512 element.attributes['class'] = 'param';
1472 return element; 1513 return element;
1473 } 1514 }
1474 } 1515 }
1475 } 1516 }
1476 1517
1477 // See if it's another member of the current type. 1518 // See if it's another member of the current type.
1478 if (currentType != null) { 1519 if (currentType != null) {
1479 final foundMember = findMirror(currentType.declaredMembers, name); 1520 final foundMember = currentType.declaredMembers[name];
1480 if (foundMember != null) { 1521 if (foundMember != null) {
1481 return makeLink(memberUrl(foundMember)); 1522 return makeLink(memberUrl(foundMember));
1482 } 1523 }
1483 } 1524 }
1484 1525
1485 // See if it's another type or a member of another type in the current 1526 // See if it's another type or a member of another type in the current
1486 // library. 1527 // library.
1487 if (currentLibrary != null) { 1528 if (currentLibrary != null) {
1488 // See if it's a constructor 1529 // See if it's a constructor
1489 final constructorLink = (() { 1530 final constructorLink = (() {
1490 final match = 1531 final match =
1491 new RegExp(r'new ([\w$]+)(?:\.([\w$]+))?').firstMatch(name); 1532 new RegExp(r'new ([\w$]+)(?:\.([\w$]+))?').firstMatch(name);
1492 if (match == null) return; 1533 if (match == null) return;
1493 InterfaceMirror foundtype = findMirror(currentLibrary.types, match[1]); 1534 String typeName = match[1];
1535 InterfaceMirror foundtype = currentLibrary.types[typeName];
1494 if (foundtype == null) return; 1536 if (foundtype == null) return;
1537 String constructorName =
1538 match[2] == null ? typeName : '$typeName.${match[2]}';
Lasse Reichstein Nielsen 2012/10/04 07:41:19 I recommend parentheses around any non-trivial con
Johnni Winther 2012/10/04 12:46:21 Done.
1495 final constructor = 1539 final constructor =
1496 findMirror(foundtype.constructors, 1540 foundtype.constructors[constructorName];
1497 match[2] == null ? '' : match[2]);
1498 if (constructor == null) return; 1541 if (constructor == null) return;
1499 return makeLink(memberUrl(constructor)); 1542 return makeLink(memberUrl(constructor));
1500 })(); 1543 })();
1501 if (constructorLink != null) return constructorLink; 1544 if (constructorLink != null) return constructorLink;
1502 1545
1503 // See if it's a member of another type 1546 // See if it's a member of another type
1504 final foreignMemberLink = (() { 1547 final foreignMemberLink = (() {
1505 final match = new RegExp(r'([\w$]+)\.([\w$]+)').firstMatch(name); 1548 final match = new RegExp(r'([\w$]+)\.([\w$]+)').firstMatch(name);
1506 if (match == null) return; 1549 if (match == null) return;
1507 InterfaceMirror foundtype = findMirror(currentLibrary.types, match[1]); 1550 InterfaceMirror foundtype = currentLibrary.types[match[1]];
1508 if (foundtype == null) return; 1551 if (foundtype == null) return;
1509 MemberMirror foundMember = findMirror(foundtype.declaredMembers, match[2 ]); 1552 MemberMirror foundMember = foundtype.declaredMembers[match[2]];
1510 if (foundMember == null) return; 1553 if (foundMember == null) return;
1511 return makeLink(memberUrl(foundMember)); 1554 return makeLink(memberUrl(foundMember));
1512 })(); 1555 })();
1513 if (foreignMemberLink != null) return foreignMemberLink; 1556 if (foreignMemberLink != null) return foreignMemberLink;
1514 1557
1515 InterfaceMirror foundType = findMirror(currentLibrary.types, name); 1558 InterfaceMirror foundType = currentLibrary.types[name];
1516 if (foundType != null) { 1559 if (foundType != null) {
1517 return makeLink(typeUrl(foundType)); 1560 return makeLink(typeUrl(foundType));
1518 } 1561 }
1519 1562
1520 // See if it's a top-level member in the current library. 1563 // See if it's a top-level member in the current library.
1521 MemberMirror foundMember = findMirror(currentLibrary.declaredMembers, name ); 1564 MemberMirror foundMember = currentLibrary.declaredMembers[name];
1522 if (foundMember != null) { 1565 if (foundMember != null) {
1523 return makeLink(memberUrl(foundMember)); 1566 return makeLink(memberUrl(foundMember));
1524 } 1567 }
1525 } 1568 }
1526 1569
1527 // TODO(rnystrom): Should also consider: 1570 // TODO(rnystrom): Should also consider:
1528 // * Names imported by libraries this library imports. 1571 // * Names imported by libraries this library imports.
1529 // * Type parameters of the enclosing type. 1572 // * Type parameters of the enclosing type.
1530 1573
1531 return new md.Element.text('code', name); 1574 return new md.Element.text('code', name);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1575 1618
1576 /** 1619 /**
1577 * Used to report an unexpected error in the DartDoc tool or the 1620 * Used to report an unexpected error in the DartDoc tool or the
1578 * underlying data 1621 * underlying data
1579 */ 1622 */
1580 class InternalError { 1623 class InternalError {
1581 final String message; 1624 final String message;
1582 const InternalError(this.message); 1625 const InternalError(this.message);
1583 String toString() => "InternalError: '$message'"; 1626 String toString() => "InternalError: '$message'";
1584 } 1627 }
1628
1629 class DocComment {
1630 final String text;
1631
1632 /**
1633 * Non-null if the comment is inherited from another declaration.
1634 */
1635 final InterfaceMirror inheritedFrom;
1636
1637 DocComment(this.text, [this.inheritedFrom = null]) {
1638 assert(text != null && !text.trim().isEmpty());
1639 }
1640
1641 String get html => md.markdownToHtml(text);
Lasse Reichstein Nielsen 2012/10/04 07:41:19 Why isn't the "inherited from" HTML added by this
Johnni Winther 2012/10/04 12:46:21 The functionality might fit in the DocComment clas
1642
1643 String toString() => text;
1644 }
OLDNEW
« no previous file with comments | « no previous file | pkg/dartdoc/lib/mirrors.dart » ('j') | pkg/dartdoc/lib/mirrors_util.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698