OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'dart:convert'; | 5 import 'dart:convert'; |
6 import 'dart:io'; | |
7 | 6 |
8 import 'package:analyzer/dart/ast/ast.dart'; | 7 import 'package:analyzer/dart/ast/ast.dart'; |
9 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; | 8 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; |
10 import 'package:analyzer/dart/ast/syntactic_entity.dart'; | 9 import 'package:analyzer/dart/ast/syntactic_entity.dart'; |
11 import 'package:analyzer/dart/ast/token.dart'; | 10 import 'package:analyzer/dart/ast/token.dart'; |
12 import 'package:analyzer/dart/ast/visitor.dart'; | 11 import 'package:analyzer/dart/ast/visitor.dart'; |
13 import 'package:analyzer/dart/element/element.dart'; | 12 import 'package:analyzer/dart/element/element.dart'; |
14 import 'package:analyzer/dart/element/type.dart'; | 13 import 'package:analyzer/dart/element/type.dart'; |
15 import 'package:analyzer/dart/element/visitor.dart'; | 14 import 'package:analyzer/dart/element/visitor.dart'; |
16 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart'; | 15 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart'; |
| 16 import 'package:analyzer_plugin/protocol/protocol_common.dart' |
| 17 show KytheEntry, KytheVName; |
17 | 18 |
18 import 'schema.dart' as schema; | 19 import 'schema.dart' as schema; |
19 | 20 |
20 const int _notFound = -1; | 21 const int _notFound = -1; |
21 | 22 |
22 /// Computes analysis of the given compilation [unit]. | 23 /// Computes analysis of the given compilation [unit]. The unit is assumed to |
23 /// | 24 /// exist in the given [corpus] and to have the given text [contents]. Analysis |
24 /// [unit] is the compilation unit to be analyzed; it is assumed to exist in the | 25 /// results are returned as a list of [KytheEntry] objects. |
25 /// given [corpus] and to have the given text [contents]. Analysis results are | 26 List<KytheEntry> computeIndex( |
26 /// returned as a list of Kythe [pb_Entry] objects. | |
27 List<pb_Entry> computeIndex( | |
28 String corpus, CompilationUnit unit, String contents) { | 27 String corpus, CompilationUnit unit, String contents) { |
29 final List<pb_Entry> entries = []; | 28 final List<KytheEntry> entries = []; |
30 var visitor = new KytheDartVisitor( | 29 var visitor = new KytheDartVisitor( |
31 entries, | 30 entries, |
32 corpus, | 31 corpus, |
33 new InheritanceManager( | 32 new InheritanceManager( |
34 resolutionMap.elementDeclaredByCompilationUnit(unit).library), | 33 resolutionMap.elementDeclaredByCompilationUnit(unit).library), |
35 contents); | 34 contents); |
36 unit.accept(visitor); | 35 unit.accept(visitor); |
37 return entries; | 36 return entries; |
38 } | 37 } |
39 | 38 |
40 /// Outputs analysis of the given compilation [unit] to the parent process. | |
41 /// | |
42 /// [unit] is the compilation unit to be analyzed; it is assumed to exist in the | |
43 /// given [corpus] and to have the given text [contents]. Analysis results are | |
44 /// sent do the parent process as raw Kythe [Entry] objects. | |
45 void writeOutIndex(CompilationUnit unit, String corpus, String contents) { | |
46 List<pb_Entry> entries = computeIndex(corpus, unit, contents); | |
47 for (pb_Entry e in entries) { | |
48 assert(e.source != null); | |
49 if (e.edgeKind == "") { | |
50 assert(e.target.toString() == ""); | |
51 } | |
52 _sendToParentProcess(e); | |
53 } | |
54 } | |
55 | |
56 /// Given some [ConstructorElement], this method returns '<class-name>' as the | 39 /// Given some [ConstructorElement], this method returns '<class-name>' as the |
57 /// name of the constructor, unless the constructor is a named constructor | 40 /// name of the constructor, unless the constructor is a named constructor in |
58 /// in which '<class-name>.<constructor-name>' is returned. | 41 /// which '<class-name>.<constructor-name>' is returned. |
59 String _computeConstructorElementName(ConstructorElement element) { | 42 String _computeConstructorElementName(ConstructorElement element) { |
60 assert(element != null); | 43 assert(element != null); |
61 var name = element.enclosingElement.name; | 44 var name = element.enclosingElement.name; |
62 var constructorName = element.name; | 45 var constructorName = element.name; |
63 if (!constructorName.isEmpty) { | 46 if (!constructorName.isEmpty) { |
64 name = name + '.' + constructorName; | 47 name = name + '.' + constructorName; |
65 } | 48 } |
66 return name; | 49 return name; |
67 } | 50 } |
68 | 51 |
69 /// Create an anchor signature of the form '<start>-<end>'. | 52 /// Create an anchor signature of the form '<start>-<end>'. |
70 String _getAnchorSignature(int start, int end) { | 53 String _getAnchorSignature(int start, int end) { |
71 return '$start-$end'; | 54 return '$start-$end'; |
72 } | 55 } |
73 | 56 |
74 String _getPath(Element e) { | 57 String _getPath(Element e) { |
| 58 // TODO(jwren) This method simply serves to provide the WORKSPACE relative |
| 59 // path for sources in Elements, it needs to be written in a more robust way. |
75 // TODO(jwren) figure out what source generates a e != null, but | 60 // TODO(jwren) figure out what source generates a e != null, but |
76 // e.source == null to ensure that it is not a bug somewhere in the stack. | 61 // e.source == null to ensure that it is not a bug somewhere in the stack. |
77 if (e == null || e.source == null) { | 62 if (e == null || e.source == null) { |
78 // null sometimes when the element is used to generate the node type | 63 // null sometimes when the element is used to generate the node type |
79 // "dynamic" | 64 // "dynamic" |
80 return ''; | 65 return ''; |
81 } | 66 } |
82 var path = e.source.fullName; | 67 var path = e.source.fullName; |
83 assert(path.lastIndexOf('CORPUS_NAME') != -1); | 68 assert(path.lastIndexOf('CORPUS_NAME') != -1); |
84 return path.substring(path.lastIndexOf('CORPUS_NAME') + 12); | 69 return path.substring(path.lastIndexOf('CORPUS_NAME') + 12); |
85 } | 70 } |
86 | 71 |
87 /// If a non-null element is passed, the [SignatureElementVisitor] is used to | 72 /// If a non-null element is passed, the [SignatureElementVisitor] is used to |
88 /// generate and return a [String] signature, otherwise | 73 /// generate and return a [String] signature, otherwise [schema.DYNAMIC_KIND] is |
89 /// [schema.DYNAMIC_KIND] is returned. | 74 /// returned. |
90 String _getSignature(Element element, String nodeKind, String corpus) { | 75 String _getSignature(Element element, String nodeKind, String corpus) { |
91 assert(nodeKind != schema.ANCHOR_KIND); // Call _getAnchorSignature instead | 76 assert(nodeKind != schema.ANCHOR_KIND); // Call _getAnchorSignature instead |
92 if (element == null) { | 77 if (element == null) { |
93 return schema.DYNAMIC_KIND; | 78 return schema.DYNAMIC_KIND; |
94 } | 79 } |
95 if (element is CompilationUnitElement) { | 80 if (element is CompilationUnitElement) { |
96 return _getPath(element); | 81 return _getPath(element); |
97 } | 82 } |
98 return '$nodeKind:${element.accept(SignatureElementVisitor.instance)}'; | 83 return '$nodeKind:${element.accept(SignatureElementVisitor.instance)}'; |
99 } | 84 } |
100 | 85 |
101 /// Send a [Reply] message to the parent process via standard output. | 86 class CodedBufferWriter { |
102 /// | 87 CodedBufferWriter(var v); |
103 /// The message is formatted as a base-128 encoded length followed by the | 88 toBuffer() {} |
104 /// serialized message data. The base-128 encoding is in little-endian order, | |
105 /// with the high bit set on all bytes but the last. This was chosen since | |
106 /// it's the same as the base-128 encoding used by protobufs, so it allows a | |
107 /// modest amount of code reuse. Also it parallels the format used by | |
108 /// [messageGrouper]. | |
109 void _sendToParentProcess(pb_Entry entry) { | |
110 var rawMessage = entry.writeToBuffer(); | |
111 var encodedLength = (new CodedBufferWriter(rawMessage.length)).toBuffer(); | |
112 stdout..add(encodedLength)..add(rawMessage); | |
113 } | 89 } |
114 | 90 |
115 // TODO(jwren) This method simply serves to provide the WORKSPACE relative path | |
116 // for sources in Elements, it needs to be written in a more robust way. | |
117 /// This visitor writes out Kythe facts and edges as specified by the Kythe | 91 /// This visitor writes out Kythe facts and edges as specified by the Kythe |
118 /// Schema here https://kythe.io/docs/schema/. This visitor handles all nodes, | 92 /// Schema here https://kythe.io/docs/schema/. This visitor handles all nodes, |
119 /// facts and edges. | 93 /// facts and edges. |
120 class KytheDartVisitor extends GeneralizingAstVisitor with OutputUtils { | 94 class KytheDartVisitor extends GeneralizingAstVisitor with OutputUtils { |
121 final List<pb_Entry> entries; | 95 final List<KytheEntry> entries; |
122 final String corpus; | 96 final String corpus; |
123 final InheritanceManager _inheritanceManager; | 97 final InheritanceManager _inheritanceManager; |
124 String _enclosingFilePath = ''; | 98 String _enclosingFilePath = ''; |
125 Element _enclosingElement; | 99 Element _enclosingElement; |
126 ClassElement _enclosingClassElement; | 100 ClassElement _enclosingClassElement; |
127 pb_VName _enclosingVName; | 101 KytheVName _enclosingVName; |
128 pb_VName _enclosingFileVName; | 102 KytheVName _enclosingFileVName; |
129 pb_VName _enclosingClassVName; | 103 KytheVName _enclosingClassVName; |
130 final String _contents; | 104 final String _contents; |
131 | 105 |
132 KytheDartVisitor( | 106 KytheDartVisitor( |
133 this.entries, this.corpus, this._inheritanceManager, this._contents); | 107 this.entries, this.corpus, this._inheritanceManager, this._contents); |
134 | 108 |
135 @override | 109 @override |
136 String get enclosingFilePath => _enclosingFilePath; | 110 String get enclosingFilePath => _enclosingFilePath; |
137 | 111 |
138 @override | 112 @override |
139 visitAnnotation(Annotation node) { | 113 visitAnnotation(Annotation node) { |
(...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
927 return schema.RECORD_KIND; | 901 return schema.RECORD_KIND; |
928 } | 902 } |
929 return null; | 903 return null; |
930 } | 904 } |
931 | 905 |
932 _handleRefCallEdge( | 906 _handleRefCallEdge( |
933 Element element, { | 907 Element element, { |
934 SyntacticEntity syntacticEntity: null, | 908 SyntacticEntity syntacticEntity: null, |
935 start: _notFound, | 909 start: _notFound, |
936 end: _notFound, | 910 end: _notFound, |
937 pb_VName enclosingTarget: null, | 911 KytheVName enclosingTarget: null, |
938 }) { | 912 }) { |
939 if (element is ExecutableElement && | 913 if (element is ExecutableElement && |
940 _enclosingVName != _enclosingFileVName) { | 914 _enclosingVName != _enclosingFileVName) { |
941 _handleRefEdge( | 915 _handleRefEdge( |
942 element, | 916 element, |
943 const <String>[schema.REF_CALL_EDGE, schema.REF_EDGE], | 917 const <String>[schema.REF_CALL_EDGE, schema.REF_EDGE], |
944 syntacticEntity: syntacticEntity, | 918 syntacticEntity: syntacticEntity, |
945 start: start, | 919 start: start, |
946 end: end, | 920 end: end, |
947 enclosingTarget: enclosingTarget, | 921 enclosingTarget: enclosingTarget, |
948 enclosingAnchor: _enclosingVName, | 922 enclosingAnchor: _enclosingVName, |
949 ); | 923 ); |
950 } else { | 924 } else { |
951 _handleRefEdge( | 925 _handleRefEdge( |
952 element, | 926 element, |
953 const <String>[schema.REF_EDGE], | 927 const <String>[schema.REF_EDGE], |
954 syntacticEntity: syntacticEntity, | 928 syntacticEntity: syntacticEntity, |
955 start: start, | 929 start: start, |
956 end: end, | 930 end: end, |
957 enclosingTarget: enclosingTarget, | 931 enclosingTarget: enclosingTarget, |
958 ); | 932 ); |
959 } | 933 } |
960 } | 934 } |
961 | 935 |
962 /// This is a convenience method for adding ref edges. If the [start] and | 936 /// This is a convenience method for adding ref edges. If the [start] and |
963 /// [end] offsets are provided, they are used, otherwise the offsets are | 937 /// [end] offsets are provided, they are used, otherwise the offsets are |
964 /// computed by using the [syntacticEntity]. | 938 /// computed by using the [syntacticEntity]. The list of edges is assumed to |
965 /// The list of edges is assumed to be non-empty, and are added from the | 939 /// be non-empty, and are added from the anchor to the target generated using |
966 /// anchor to the target generated using the passed [Element]. | 940 /// the passed [Element]. The created [KytheVName] is returned, if not `null` |
967 /// The created [pb_VName] is returned, if not `null` is returned. | 941 /// is returned. |
968 pb_VName _handleRefEdge( | 942 KytheVName _handleRefEdge( |
969 Element element, | 943 Element element, |
970 List<String> refEdgeTypes, { | 944 List<String> refEdgeTypes, { |
971 SyntacticEntity syntacticEntity: null, | 945 SyntacticEntity syntacticEntity: null, |
972 start: _notFound, | 946 start: _notFound, |
973 end: _notFound, | 947 end: _notFound, |
974 pb_VName enclosingTarget: null, | 948 KytheVName enclosingTarget: null, |
975 pb_VName enclosingAnchor: null, | 949 KytheVName enclosingAnchor: null, |
976 }) { | 950 }) { |
977 assert(refEdgeTypes.isNotEmpty); | 951 assert(refEdgeTypes.isNotEmpty); |
978 element = _findNonSyntheticElement(element); | 952 element = _findNonSyntheticElement(element); |
979 if (element == null) { | 953 if (element == null) { |
980 return null; | 954 return null; |
981 } | 955 } |
982 | 956 |
983 // vname | 957 // vname |
984 var nodeKind = _getNodeKind(element); | 958 var nodeKind = _getNodeKind(element); |
985 if (nodeKind == null || nodeKind.isEmpty) { | 959 if (nodeKind == null || nodeKind.isEmpty) { |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1054 addAnchorEdgesContainingEdge( | 1028 addAnchorEdgesContainingEdge( |
1055 start: start, | 1029 start: start, |
1056 end: end, | 1030 end: end, |
1057 edges: [schema.REF_IMPORTS_EDGE], | 1031 edges: [schema.REF_IMPORTS_EDGE], |
1058 target: packageVName, | 1032 target: packageVName, |
1059 enclosingTarget: _enclosingFileVName); | 1033 enclosingTarget: _enclosingFileVName); |
1060 } | 1034 } |
1061 } | 1035 } |
1062 | 1036 |
1063 _handleVariableDeclarationListAnnotations( | 1037 _handleVariableDeclarationListAnnotations( |
1064 VariableDeclarationList variableDeclarationList, pb_VName refVName) { | 1038 VariableDeclarationList variableDeclarationList, KytheVName refVName) { |
1065 assert(refVName != null); | 1039 assert(refVName != null); |
1066 for (var varDecl in variableDeclarationList.variables) { | 1040 for (var varDecl in variableDeclarationList.variables) { |
1067 if (varDecl.element != null) { | 1041 if (varDecl.element != null) { |
1068 var parentVName = | 1042 var parentVName = |
1069 _vNameFromElement(varDecl.element, schema.VARIABLE_KIND); | 1043 _vNameFromElement(varDecl.element, schema.VARIABLE_KIND); |
1070 addEdge(parentVName, schema.ANNOTATED_BY_EDGE, refVName); | 1044 addEdge(parentVName, schema.ANNOTATED_BY_EDGE, refVName); |
1071 } else { | 1045 } else { |
1072 // The element out of the VarDeclarationList is null | 1046 // The element out of the VarDeclarationList is null |
1073 assert(false); | 1047 assert(false); |
1074 } | 1048 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1113 _enclosingElement = outerEnclosingElement; | 1087 _enclosingElement = outerEnclosingElement; |
1114 _enclosingClassElement = outerEnclosingClassElement; | 1088 _enclosingClassElement = outerEnclosingClassElement; |
1115 _enclosingClassVName = outerEnclosingClassVName; | 1089 _enclosingClassVName = outerEnclosingClassVName; |
1116 _enclosingVName = outerEnclosingVName; | 1090 _enclosingVName = outerEnclosingVName; |
1117 } | 1091 } |
1118 } | 1092 } |
1119 } | 1093 } |
1120 | 1094 |
1121 /// This class is meant to be a mixin to concrete visitor methods to walk the | 1095 /// This class is meant to be a mixin to concrete visitor methods to walk the |
1122 /// [Element] or [AstNode]s produced by the Dart Analyzer to output Kythe | 1096 /// [Element] or [AstNode]s produced by the Dart Analyzer to output Kythe |
1123 /// [pb_Entry] protos. | 1097 /// [KytheEntry] protos. |
1124 abstract class OutputUtils { | 1098 abstract class OutputUtils { |
1125 /// A set of [String]s which have already had a name [pb_VName] created. | 1099 /// A set of [String]s which have already had a name [KytheVName] created. |
1126 final Set<String> nameNodes = new Set<String>(); | 1100 final Set<String> nameNodes = new Set<String>(); |
1127 String get corpus; | 1101 String get corpus; |
1128 pb_VName get dynamicBuiltin => _vName(schema.DYNAMIC_KIND, '', '', ''); | 1102 KytheVName get dynamicBuiltin => _vName(schema.DYNAMIC_KIND, '', '', ''); |
1129 | 1103 |
1130 String get enclosingFilePath; | 1104 String get enclosingFilePath; |
1131 | 1105 |
1132 List<pb_Entry> get entries; | 1106 List<KytheEntry> get entries; |
1133 pb_VName get fnBuiltin => _vName(schema.FN_BUILTIN, '', '', ''); | 1107 KytheVName get fnBuiltin => _vName(schema.FN_BUILTIN, '', '', ''); |
1134 pb_VName get voidBuiltin => _vName(schema.VOID_BUILTIN, '', '', ''); | 1108 KytheVName get voidBuiltin => _vName(schema.VOID_BUILTIN, '', '', ''); |
1135 | 1109 |
1136 /// This is a convenience method for adding anchors. If the [start] and [end] | 1110 /// This is a convenience method for adding anchors. If the [start] and [end] |
1137 /// offsets are provided, they are used, otherwise the offsets are computed by | 1111 /// offsets are provided, they are used, otherwise the offsets are computed by |
1138 /// using the [syntacticEntity]. If a non-empty list of edges is provided, as | 1112 /// using the [syntacticEntity]. If a non-empty list of edges is provided, as |
1139 /// well as a target, then this method also adds the edges from the anchor to | 1113 /// well as a target, then this method also adds the edges from the anchor to |
1140 /// target. The anchor [pb_VName] is returned. | 1114 /// target. The anchor [KytheVName] is returned. |
1141 /// | 1115 /// |
1142 /// If a [target] and [enclosingTarget] are provided, a childof edge is | 1116 /// If a [target] and [enclosingTarget] are provided, a childof edge is |
1143 /// written out from the target to the enclosing target. | 1117 /// written out from the target to the enclosing target. |
1144 /// | 1118 /// |
1145 /// If an [enclosingAnchor] is provided a childof edge is written out from the | 1119 /// If an [enclosingAnchor] is provided a childof edge is written out from the |
1146 /// anchor to the enclosing anchor. In cases where ref/call is an edge, this | 1120 /// anchor to the enclosing anchor. In cases where ref/call is an edge, this |
1147 /// is required to generate the callgraph. | 1121 /// is required to generate the callgraph. |
1148 /// | 1122 /// |
1149 /// Finally, for all anchors, a childof edge with a target of the enclosing | 1123 /// Finally, for all anchors, a childof edge with a target of the enclosing |
1150 /// file is written out. | 1124 /// file is written out. |
1151 pb_VName addAnchorEdgesContainingEdge({ | 1125 KytheVName addAnchorEdgesContainingEdge({ |
1152 SyntacticEntity syntacticEntity: null, | 1126 SyntacticEntity syntacticEntity: null, |
1153 int start: _notFound, | 1127 int start: _notFound, |
1154 int end: _notFound, | 1128 int end: _notFound, |
1155 List<String> edges: const [], | 1129 List<String> edges: const [], |
1156 pb_VName target: null, | 1130 KytheVName target: null, |
1157 pb_VName enclosingTarget: null, | 1131 KytheVName enclosingTarget: null, |
1158 pb_VName enclosingAnchor: null, | 1132 KytheVName enclosingAnchor: null, |
1159 }) { | 1133 }) { |
1160 if (start == _notFound && end == _notFound) { | 1134 if (start == _notFound && end == _notFound) { |
1161 if (syntacticEntity != null) { | 1135 if (syntacticEntity != null) { |
1162 start = syntacticEntity.offset; | 1136 start = syntacticEntity.offset; |
1163 end = syntacticEntity.end; | 1137 end = syntacticEntity.end; |
1164 } else { | 1138 } else { |
1165 throw new Exception('Offset positions were not provided when calling ' | 1139 throw new Exception('Offset positions were not provided when calling ' |
1166 'addAnchorEdgesContainingEdge'); | 1140 'addAnchorEdgesContainingEdge'); |
1167 } | 1141 } |
1168 } | 1142 } |
(...skipping 24 matching lines...) Expand all Loading... |
1193 } | 1167 } |
1194 | 1168 |
1195 // Finally add the childof edge to the enclosing file VName. | 1169 // Finally add the childof edge to the enclosing file VName. |
1196 addEdge(anchorVName, schema.CHILD_OF_EDGE, _vNameFile()); | 1170 addEdge(anchorVName, schema.CHILD_OF_EDGE, _vNameFile()); |
1197 return anchorVName; | 1171 return anchorVName; |
1198 } | 1172 } |
1199 | 1173 |
1200 /// TODO(jwren): for cases where the target is a name, we need the same kind | 1174 /// TODO(jwren): for cases where the target is a name, we need the same kind |
1201 /// of logic as [addNameFact] to prevent the edge from being written out. | 1175 /// of logic as [addNameFact] to prevent the edge from being written out. |
1202 /// This is a convenience method for visitors to add an edge Entry. | 1176 /// This is a convenience method for visitors to add an edge Entry. |
1203 pb_Entry addEdge(pb_VName source, String edgeKind, pb_VName target, | 1177 KytheEntry addEdge(KytheVName source, String edgeKind, KytheVName target, |
1204 {int ordinalIntValue: _notFound}) { | 1178 {int ordinalIntValue: _notFound}) { |
1205 if (ordinalIntValue == _notFound) { | 1179 if (ordinalIntValue == _notFound) { |
1206 return addEntry(source, edgeKind, target, "/", new List<int>()); | 1180 return addEntry(source, edgeKind, target, "/", new List<int>()); |
1207 } else { | 1181 } else { |
1208 return addEntry(source, edgeKind, target, schema.ORDINAL, | 1182 return addEntry(source, edgeKind, target, schema.ORDINAL, |
1209 _encodeInt(ordinalIntValue)); | 1183 _encodeInt(ordinalIntValue)); |
1210 } | 1184 } |
1211 } | 1185 } |
1212 | 1186 |
1213 pb_Entry addEntry(pb_VName source, String edgeKind, pb_VName target, | 1187 KytheEntry addEntry(KytheVName source, String edgeKind, KytheVName target, |
1214 String factName, List<int> factValue) { | 1188 String factName, List<int> factValue) { |
1215 assert(source != null); | 1189 assert(source != null); |
1216 assert(factName != null); | 1190 assert(factName != null); |
1217 assert(factValue != null); | 1191 assert(factValue != null); |
1218 // factValue may be an empty array, the fact may be that a file text or | 1192 // factValue may be an empty array, the fact may be that a file text or |
1219 // document text is empty | 1193 // document text is empty |
1220 var entry = pb_Entry.create() | 1194 if (edgeKind == null || edgeKind.isEmpty) { |
1221 ..source = source | 1195 edgeKind = null; |
1222 ..factName = factName | 1196 target = null; |
1223 ..factValue = factValue; | |
1224 if (edgeKind != null && edgeKind.isNotEmpty) { | |
1225 entry.edgeKind = edgeKind; | |
1226 entry.target = target; | |
1227 } | 1197 } |
| 1198 var entry = new KytheEntry(source, edgeKind, target, factName, factValue); |
1228 entries.add(entry); | 1199 entries.add(entry); |
1229 return entry; | 1200 return entry; |
1230 } | 1201 } |
1231 | 1202 |
1232 /// This is a convenience method for visitors to add a fact [pb_Entry]. | 1203 /// This is a convenience method for visitors to add a fact [KytheEntry]. |
1233 pb_Entry addFact(pb_VName source, String factName, List<int> factValue) { | 1204 KytheEntry addFact(KytheVName source, String factName, List<int> factValue) { |
1234 return addEntry(source, null, null, factName, factValue); | 1205 return addEntry(source, null, null, factName, factValue); |
1235 } | 1206 } |
1236 | 1207 |
1237 /// This is a convenience method for adding function types. | 1208 /// This is a convenience method for adding function types. |
1238 pb_VName addFunctionType( | 1209 KytheVName addFunctionType( |
1239 Element functionElement, | 1210 Element functionElement, |
1240 FormalParameterList paramNodes, | 1211 FormalParameterList paramNodes, |
1241 pb_VName functionVName, { | 1212 KytheVName functionVName, { |
1242 AstNode returnNode: null, | 1213 AstNode returnNode: null, |
1243 }) { | 1214 }) { |
1244 var i = 0; | 1215 var i = 0; |
1245 var funcTypeVName = | 1216 var funcTypeVName = |
1246 addNodeAndFacts(schema.TAPP_KIND, element: functionElement); | 1217 addNodeAndFacts(schema.TAPP_KIND, element: functionElement); |
1247 addEdge(funcTypeVName, schema.PARAM_EDGE, fnBuiltin, ordinalIntValue: i++); | 1218 addEdge(funcTypeVName, schema.PARAM_EDGE, fnBuiltin, ordinalIntValue: i++); |
1248 | 1219 |
1249 var returnTypeVName; | 1220 var returnTypeVName; |
1250 if (returnNode is TypeName) { | 1221 if (returnNode is TypeName) { |
1251 // MethodDeclaration and FunctionDeclaration both return a TypeName from | 1222 // MethodDeclaration and FunctionDeclaration both return a TypeName from |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1288 } | 1259 } |
1289 addEdge(funcTypeVName, schema.PARAM_EDGE, paramTypeVName, | 1260 addEdge(funcTypeVName, schema.PARAM_EDGE, paramTypeVName, |
1290 ordinalIntValue: i++); | 1261 ordinalIntValue: i++); |
1291 } | 1262 } |
1292 } | 1263 } |
1293 addEdge(functionVName, schema.TYPED_EDGE, funcTypeVName); | 1264 addEdge(functionVName, schema.TYPED_EDGE, funcTypeVName); |
1294 return funcTypeVName; | 1265 return funcTypeVName; |
1295 } | 1266 } |
1296 | 1267 |
1297 /// This is a convenience method for adding nodes with facts. | 1268 /// This is a convenience method for adding nodes with facts. |
1298 /// If an [pb_VName] is passed, it is used, otherwise an element is required | 1269 /// If an [KytheVName] is passed, it is used, otherwise an element is required |
1299 /// which is used to create a [pb_VName]. Either [nodeVName] must be non-null
or | 1270 /// which is used to create a [KytheVName]. Either [nodeVName] must be non-nu
ll or |
1300 /// [element] must be non-null. Other optional parameters if passed are then | 1271 /// [element] must be non-null. Other optional parameters if passed are then |
1301 /// used to set the associated facts on the [pb_VName]. This method does not | 1272 /// used to set the associated facts on the [KytheVName]. This method does not |
1302 /// currently guarantee that the inputs to these fact kinds are valid for the | 1273 /// currently guarantee that the inputs to these fact kinds are valid for the |
1303 /// associated nodeKind- if a non-null, then it will set. | 1274 /// associated nodeKind- if a non-null, then it will set. |
1304 pb_VName addNodeAndFacts(String nodeKind, | 1275 KytheVName addNodeAndFacts(String nodeKind, |
1305 {Element element: null, | 1276 {Element element: null, |
1306 pb_VName nodeVName: null, | 1277 KytheVName nodeVName: null, |
1307 String subKind: null, | 1278 String subKind: null, |
1308 String completeFact: null}) { | 1279 String completeFact: null}) { |
1309 if (nodeVName == null) { | 1280 if (nodeVName == null) { |
1310 nodeVName = _vNameFromElement(element, nodeKind); | 1281 nodeVName = _vNameFromElement(element, nodeKind); |
1311 } | 1282 } |
1312 addFact(nodeVName, schema.NODE_KIND_FACT, _encode(nodeKind)); | 1283 addFact(nodeVName, schema.NODE_KIND_FACT, _encode(nodeKind)); |
1313 if (subKind != null) { | 1284 if (subKind != null) { |
1314 addFact(nodeVName, schema.SUBKIND_FACT, _encode(subKind)); | 1285 addFact(nodeVName, schema.SUBKIND_FACT, _encode(subKind)); |
1315 } | 1286 } |
1316 if (completeFact != null) { | 1287 if (completeFact != null) { |
1317 addFact(nodeVName, schema.COMPLETE_FACT, _encode(completeFact)); | 1288 addFact(nodeVName, schema.COMPLETE_FACT, _encode(completeFact)); |
1318 } | 1289 } |
1319 return nodeVName; | 1290 return nodeVName; |
1320 } | 1291 } |
1321 | 1292 |
1322 List<int> _encode(String str) { | 1293 List<int> _encode(String str) { |
1323 return UTF8.encode(str); | 1294 return UTF8.encode(str); |
1324 } | 1295 } |
1325 | 1296 |
1326 List<int> _encodeInt(int i) { | 1297 List<int> _encodeInt(int i) { |
1327 return UTF8.encode(i.toString()); | 1298 return UTF8.encode(i.toString()); |
1328 } | 1299 } |
1329 | 1300 |
1330 /// Given all parameters for a [pb_VName] this method creates and returns a | 1301 /// Given all parameters for a [KytheVName] this method creates and returns a |
1331 /// [pb_VName]. | 1302 /// [KytheVName]. |
1332 pb_VName _vName(String signature, String corpus, String root, String path, | 1303 KytheVName _vName(String signature, String corpus, String root, String path, |
1333 [String language = schema.DART_LANG]) { | 1304 [String language = schema.DART_LANG]) { |
1334 return pb_VName.create() | 1305 return new KytheVName(signature, corpus, root, path, language); |
1335 ..signature = signature | |
1336 ..corpus = corpus | |
1337 ..root = root | |
1338 ..path = path | |
1339 ..language = language; | |
1340 } | 1306 } |
1341 | 1307 |
1342 /// Returns an anchor [pb_VName] corresponding to the given start and end | 1308 /// Returns an anchor [KytheVName] corresponding to the given start and end |
1343 /// offsets. | 1309 /// offsets. |
1344 pb_VName _vNameAnchor(int start, int end) { | 1310 KytheVName _vNameAnchor(int start, int end) { |
1345 return _vName( | 1311 return _vName( |
1346 _getAnchorSignature(start, end), corpus, '', enclosingFilePath); | 1312 _getAnchorSignature(start, end), corpus, '', enclosingFilePath); |
1347 } | 1313 } |
1348 | 1314 |
1349 /// Return the [pb_VName] for this file. | 1315 /// Return the [KytheVName] for this file. |
1350 pb_VName _vNameFile() { | 1316 KytheVName _vNameFile() { |
1351 // file vnames, the signature and language are not set | 1317 // file vnames, the signature and language are not set |
1352 return _vName('', corpus, '', enclosingFilePath, ''); | 1318 return _vName('', corpus, '', enclosingFilePath, ''); |
1353 } | 1319 } |
1354 | 1320 |
1355 /// Given some [Element] and Kythe node kind, this method generates and | 1321 /// Given some [Element] and Kythe node kind, this method generates and |
1356 /// returns the [pb_VName]. | 1322 /// returns the [KytheVName]. |
1357 pb_VName _vNameFromElement(Element e, String nodeKind) { | 1323 KytheVName _vNameFromElement(Element e, String nodeKind) { |
1358 assert(nodeKind != schema.FILE_KIND); | 1324 assert(nodeKind != schema.FILE_KIND); |
1359 // general case | 1325 // general case |
1360 return _vName(_getSignature(e, nodeKind, corpus), corpus, '', _getPath(e)); | 1326 return _vName(_getSignature(e, nodeKind, corpus), corpus, '', _getPath(e)); |
1361 } | 1327 } |
1362 | 1328 |
1363 /// Returns a [pb_VName] corresponding to the given [DartType]. | 1329 /// Returns a [KytheVName] corresponding to the given [DartType]. |
1364 pb_VName _vNameFromType(DartType type) { | 1330 KytheVName _vNameFromType(DartType type) { |
1365 if (type == null || type.isDynamic) { | 1331 if (type == null || type.isDynamic) { |
1366 return dynamicBuiltin; | 1332 return dynamicBuiltin; |
1367 } else if (type.isVoid) { | 1333 } else if (type.isVoid) { |
1368 return voidBuiltin; | 1334 return voidBuiltin; |
1369 } else if (type.element is ClassElement) { | 1335 } else if (type.element is ClassElement) { |
1370 return _vNameFromElement(type.element, schema.RECORD_KIND); | 1336 return _vNameFromElement(type.element, schema.RECORD_KIND); |
1371 } else { | 1337 } else { |
1372 return dynamicBuiltin; | 1338 return dynamicBuiltin; |
1373 } | 1339 } |
1374 } | 1340 } |
1375 } | 1341 } |
1376 | 1342 |
1377 class CodedBufferWriter { | |
1378 CodedBufferWriter(var v); | |
1379 toBuffer() {} | |
1380 } | |
1381 | |
1382 class pb_Entry { | |
1383 var source, edgeKind, target, factName, factValue; | |
1384 static pb_Entry create() => new pb_Entry(); | |
1385 writeToBuffer() {} | |
1386 } | |
1387 | |
1388 class pb_VName { | |
1389 var signature, corpus, root, path, language; | |
1390 static pb_VName create() => new pb_VName(); | |
1391 } | |
1392 | |
1393 /// This visitor class should be used by [_getSignature]. | 1343 /// This visitor class should be used by [_getSignature]. |
1394 /// | 1344 /// |
1395 /// This visitor is an [GeneralizingElementVisitor] which builds up a [String] | 1345 /// This visitor is an [GeneralizingElementVisitor] which builds up a [String] |
1396 /// signature for a given [Element], uniqueness is guaranteed within the | 1346 /// signature for a given [Element], uniqueness is guaranteed within the |
1397 /// enclosing file. | 1347 /// enclosing file. |
1398 class SignatureElementVisitor extends GeneralizingElementVisitor<StringBuffer> { | 1348 class SignatureElementVisitor extends GeneralizingElementVisitor<StringBuffer> { |
1399 static SignatureElementVisitor instance = new SignatureElementVisitor(); | 1349 static SignatureElementVisitor instance = new SignatureElementVisitor(); |
1400 | 1350 |
1401 @override | 1351 @override |
1402 StringBuffer visitCompilationUnitElement(CompilationUnitElement e) { | 1352 StringBuffer visitCompilationUnitElement(CompilationUnitElement e) { |
(...skipping 27 matching lines...) Expand all Loading... |
1430 } | 1380 } |
1431 | 1381 |
1432 @override | 1382 @override |
1433 StringBuffer visitTypeParameterElement(TypeParameterElement e) { | 1383 StringBuffer visitTypeParameterElement(TypeParameterElement e) { |
1434 // It is legal to have a named constructor with the same name as a type | 1384 // It is legal to have a named constructor with the same name as a type |
1435 // parameter. So we distinguish them by using '.' between the class (or | 1385 // parameter. So we distinguish them by using '.' between the class (or |
1436 // typedef) name and the type parameter name. | 1386 // typedef) name and the type parameter name. |
1437 return e.enclosingElement.accept(this)..write('.')..write(e.name); | 1387 return e.enclosingElement.accept(this)..write('.')..write(e.name); |
1438 } | 1388 } |
1439 } | 1389 } |
OLD | NEW |