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 | 6 |
7 import 'package:analyzer/dart/ast/ast.dart'; | 7 import 'package:analyzer/dart/ast/ast.dart'; |
8 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; | 8 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; |
9 import 'package:analyzer/dart/ast/syntactic_entity.dart'; | 9 import 'package:analyzer/dart/ast/syntactic_entity.dart'; |
10 import 'package:analyzer/dart/ast/token.dart'; | 10 import 'package:analyzer/dart/ast/token.dart'; |
11 import 'package:analyzer/dart/ast/visitor.dart'; | 11 import 'package:analyzer/dart/ast/visitor.dart'; |
12 import 'package:analyzer/dart/element/element.dart'; | 12 import 'package:analyzer/dart/element/element.dart'; |
13 import 'package:analyzer/dart/element/type.dart'; | 13 import 'package:analyzer/dart/element/type.dart'; |
14 import 'package:analyzer/dart/element/visitor.dart'; | 14 import 'package:analyzer/dart/element/visitor.dart'; |
| 15 import 'package:analyzer/file_system/file_system.dart'; |
15 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart'; | 16 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart'; |
| 17 import 'package:analyzer/src/generated/bazel.dart'; |
| 18 import 'package:analyzer/src/generated/gn.dart'; |
16 import 'package:analyzer_plugin/protocol/protocol_common.dart' | 19 import 'package:analyzer_plugin/protocol/protocol_common.dart' |
17 show KytheEntry, KytheVName; | 20 show KytheEntry, KytheVName; |
18 | 21 |
19 import 'schema.dart' as schema; | 22 import 'schema.dart' as schema; |
20 | 23 |
21 const int _notFound = -1; | 24 const int _notFound = -1; |
22 | 25 |
23 /// Computes analysis of the given compilation [unit]. The unit is assumed to | |
24 /// exist in the given [corpus] and to have the given text [contents]. Analysis | |
25 /// results are returned as a list of [KytheEntry] objects. | |
26 List<KytheEntry> computeIndex( | |
27 String corpus, CompilationUnit unit, String contents) { | |
28 final List<KytheEntry> entries = []; | |
29 var visitor = new KytheDartVisitor( | |
30 entries, | |
31 corpus, | |
32 new InheritanceManager( | |
33 resolutionMap.elementDeclaredByCompilationUnit(unit).library), | |
34 contents); | |
35 unit.accept(visitor); | |
36 return entries; | |
37 } | |
38 | |
39 /// Given some [ConstructorElement], this method returns '<class-name>' as the | 26 /// Given some [ConstructorElement], this method returns '<class-name>' as the |
40 /// name of the constructor, unless the constructor is a named constructor in | 27 /// name of the constructor, unless the constructor is a named constructor in |
41 /// which '<class-name>.<constructor-name>' is returned. | 28 /// which '<class-name>.<constructor-name>' is returned. |
42 String _computeConstructorElementName(ConstructorElement element) { | 29 String _computeConstructorElementName(ConstructorElement element) { |
43 assert(element != null); | 30 assert(element != null); |
44 var name = element.enclosingElement.name; | 31 var name = element.enclosingElement.name; |
45 var constructorName = element.name; | 32 var constructorName = element.name; |
46 if (!constructorName.isEmpty) { | 33 if (!constructorName.isEmpty) { |
47 name = name + '.' + constructorName; | 34 name = name + '.' + constructorName; |
48 } | 35 } |
49 return name; | 36 return name; |
50 } | 37 } |
51 | 38 |
52 /// Create an anchor signature of the form '<start>-<end>'. | 39 /// Create an anchor signature of the form '<start>-<end>'. |
53 String _getAnchorSignature(int start, int end) { | 40 String _getAnchorSignature(int start, int end) { |
54 return '$start-$end'; | 41 return '$start-$end'; |
55 } | 42 } |
56 | 43 |
57 String _getPath(Element e) { | 44 String _getPath(ResourceProvider provider, Element e) { |
58 // TODO(jwren) This method simply serves to provide the WORKSPACE relative | 45 // 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. | 46 // path for sources in Elements, it needs to be written in a more robust way. |
60 // TODO(jwren) figure out what source generates a e != null, but | 47 // TODO(jwren) figure out what source generates a e != null, but |
61 // e.source == null to ensure that it is not a bug somewhere in the stack. | 48 // e.source == null to ensure that it is not a bug somewhere in the stack. |
62 if (e == null || e.source == null) { | 49 if (e == null || e.source == null) { |
63 // null sometimes when the element is used to generate the node type | 50 // null sometimes when the element is used to generate the node type |
64 // "dynamic" | 51 // "dynamic" |
65 return ''; | 52 return ''; |
66 } | 53 } |
67 var path = e.source.fullName; | 54 String path = e.source.fullName; |
68 assert(path.lastIndexOf('CORPUS_NAME') != -1); | 55 BazelWorkspace bazelWorkspace = BazelWorkspace.find(provider, path); |
69 return path.substring(path.lastIndexOf('CORPUS_NAME') + 12); | 56 if (bazelWorkspace != null) { |
| 57 return provider.pathContext.relative(path, from: bazelWorkspace.root); |
| 58 } |
| 59 GnWorkspace gnWorkspace = GnWorkspace.find(provider, path); |
| 60 if (gnWorkspace != null) { |
| 61 return provider.pathContext.relative(path, from: gnWorkspace.root); |
| 62 } |
| 63 if (path.lastIndexOf('CORPUS_NAME') != -1) { |
| 64 return path.substring(path.lastIndexOf('CORPUS_NAME') + 12); |
| 65 } |
| 66 return path; |
70 } | 67 } |
71 | 68 |
72 /// If a non-null element is passed, the [SignatureElementVisitor] is used to | 69 /// If a non-null element is passed, the [SignatureElementVisitor] is used to |
73 /// generate and return a [String] signature, otherwise [schema.DYNAMIC_KIND] is | 70 /// generate and return a [String] signature, otherwise [schema.DYNAMIC_KIND] is |
74 /// returned. | 71 /// returned. |
75 String _getSignature(Element element, String nodeKind, String corpus) { | 72 String _getSignature(ResourceProvider provider, Element element, |
| 73 String nodeKind, String corpus) { |
76 assert(nodeKind != schema.ANCHOR_KIND); // Call _getAnchorSignature instead | 74 assert(nodeKind != schema.ANCHOR_KIND); // Call _getAnchorSignature instead |
77 if (element == null) { | 75 if (element == null) { |
78 return schema.DYNAMIC_KIND; | 76 return schema.DYNAMIC_KIND; |
79 } | 77 } |
80 if (element is CompilationUnitElement) { | 78 if (element is CompilationUnitElement) { |
81 return _getPath(element); | 79 return _getPath(provider, element); |
82 } | 80 } |
83 return '$nodeKind:${element.accept(SignatureElementVisitor.instance)}'; | 81 return '$nodeKind:${element.accept(SignatureElementVisitor.instance)}'; |
84 } | 82 } |
85 | 83 |
86 class CodedBufferWriter { | 84 class CodedBufferWriter { |
87 CodedBufferWriter(var v); | 85 CodedBufferWriter(var v); |
88 toBuffer() {} | 86 toBuffer() {} |
89 } | 87 } |
90 | 88 |
91 /// This visitor writes out Kythe facts and edges as specified by the Kythe | 89 /// This visitor writes out Kythe facts and edges as specified by the Kythe |
92 /// Schema here https://kythe.io/docs/schema/. This visitor handles all nodes, | 90 /// Schema here https://kythe.io/docs/schema/. This visitor handles all nodes, |
93 /// facts and edges. | 91 /// facts and edges. |
94 class KytheDartVisitor extends GeneralizingAstVisitor with OutputUtils { | 92 class KytheDartVisitor extends GeneralizingAstVisitor with OutputUtils { |
| 93 final ResourceProvider resourceProvider; |
95 final List<KytheEntry> entries; | 94 final List<KytheEntry> entries; |
96 final String corpus; | 95 final String corpus; |
97 final InheritanceManager _inheritanceManager; | 96 final InheritanceManager _inheritanceManager; |
| 97 final String _contents; |
| 98 |
98 String _enclosingFilePath = ''; | 99 String _enclosingFilePath = ''; |
99 Element _enclosingElement; | 100 Element _enclosingElement; |
100 ClassElement _enclosingClassElement; | 101 ClassElement _enclosingClassElement; |
101 KytheVName _enclosingVName; | 102 KytheVName _enclosingVName; |
102 KytheVName _enclosingFileVName; | 103 KytheVName _enclosingFileVName; |
103 KytheVName _enclosingClassVName; | 104 KytheVName _enclosingClassVName; |
104 final String _contents; | |
105 | 105 |
106 KytheDartVisitor( | 106 KytheDartVisitor(this.resourceProvider, this.entries, this.corpus, |
107 this.entries, this.corpus, this._inheritanceManager, this._contents); | 107 this._inheritanceManager, this._contents); |
108 | 108 |
109 @override | 109 @override |
110 String get enclosingFilePath => _enclosingFilePath; | 110 String get enclosingFilePath => _enclosingFilePath; |
111 | 111 |
112 @override | 112 @override |
113 visitAnnotation(Annotation node) { | 113 visitAnnotation(Annotation node) { |
114 // TODO(jwren) To get the full set of cross refs correct, additional ref | 114 // TODO(jwren) To get the full set of cross refs correct, additional ref |
115 // edges are needed, example: from "A" in "A.namedConstructor()" | 115 // edges are needed, example: from "A" in "A.namedConstructor()" |
116 | 116 |
117 var start = node.name.offset; | 117 var start = node.name.offset; |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
331 _safelyVisit(node.documentationComment); | 331 _safelyVisit(node.documentationComment); |
332 _safelyVisitList(node.metadata); | 332 _safelyVisitList(node.metadata); |
333 _safelyVisit(node.typeParameters); | 333 _safelyVisit(node.typeParameters); |
334 _safelyVisit(node.withClause); | 334 _safelyVisit(node.withClause); |
335 _safelyVisit(node.implementsClause); | 335 _safelyVisit(node.implementsClause); |
336 }); | 336 }); |
337 } | 337 } |
338 | 338 |
339 @override | 339 @override |
340 visitCompilationUnit(CompilationUnit node) { | 340 visitCompilationUnit(CompilationUnit node) { |
341 _enclosingFilePath = _getPath(node.element); | 341 _enclosingFilePath = _getPath(resourceProvider, node.element); |
342 return _withEnclosingElement(node.element, () { | 342 return _withEnclosingElement(node.element, () { |
343 addFact(_enclosingFileVName, schema.NODE_KIND_FACT, | 343 addFact(_enclosingFileVName, schema.NODE_KIND_FACT, |
344 _encode(schema.FILE_KIND)); | 344 _encode(schema.FILE_KIND)); |
345 addFact(_enclosingFileVName, schema.TEXT_FACT, _encode(_contents)); | 345 addFact(_enclosingFileVName, schema.TEXT_FACT, _encode(_contents)); |
346 addFact(_enclosingFileVName, schema.TEXT_ENCODING_FACT, | 346 addFact(_enclosingFileVName, schema.TEXT_ENCODING_FACT, |
347 _encode(schema.DEFAULT_TEXT_ENCODING)); | 347 _encode(schema.DEFAULT_TEXT_ENCODING)); |
348 | 348 |
349 // handle LibraryDirective: | 349 // handle LibraryDirective: |
350 | 350 |
351 // A "package" VName in Kythe, schema.PACKAGE_KIND, is a Dart "library". | 351 // A "package" VName in Kythe, schema.PACKAGE_KIND, is a Dart "library". |
(...skipping 739 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1091 } | 1091 } |
1092 } | 1092 } |
1093 } | 1093 } |
1094 | 1094 |
1095 /// 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 |
1096 /// [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 |
1097 /// [KytheEntry] protos. | 1097 /// [KytheEntry] protos. |
1098 abstract class OutputUtils { | 1098 abstract class OutputUtils { |
1099 /// A set of [String]s which have already had a name [KytheVName] created. | 1099 /// A set of [String]s which have already had a name [KytheVName] created. |
1100 final Set<String> nameNodes = new Set<String>(); | 1100 final Set<String> nameNodes = new Set<String>(); |
| 1101 |
1101 String get corpus; | 1102 String get corpus; |
| 1103 |
1102 KytheVName get dynamicBuiltin => _vName(schema.DYNAMIC_KIND, '', '', ''); | 1104 KytheVName get dynamicBuiltin => _vName(schema.DYNAMIC_KIND, '', '', ''); |
1103 | 1105 |
1104 String get enclosingFilePath; | 1106 String get enclosingFilePath; |
1105 | 1107 |
1106 List<KytheEntry> get entries; | 1108 List<KytheEntry> get entries; |
| 1109 |
1107 KytheVName get fnBuiltin => _vName(schema.FN_BUILTIN, '', '', ''); | 1110 KytheVName get fnBuiltin => _vName(schema.FN_BUILTIN, '', '', ''); |
| 1111 |
| 1112 ResourceProvider get resourceProvider; |
| 1113 |
1108 KytheVName get voidBuiltin => _vName(schema.VOID_BUILTIN, '', '', ''); | 1114 KytheVName get voidBuiltin => _vName(schema.VOID_BUILTIN, '', '', ''); |
1109 | 1115 |
1110 /// This is a convenience method for adding anchors. If the [start] and [end] | 1116 /// This is a convenience method for adding anchors. If the [start] and [end] |
1111 /// offsets are provided, they are used, otherwise the offsets are computed by | 1117 /// offsets are provided, they are used, otherwise the offsets are computed by |
1112 /// using the [syntacticEntity]. If a non-empty list of edges is provided, as | 1118 /// using the [syntacticEntity]. If a non-empty list of edges is provided, as |
1113 /// well as a target, then this method also adds the edges from the anchor to | 1119 /// well as a target, then this method also adds the edges from the anchor to |
1114 /// target. The anchor [KytheVName] is returned. | 1120 /// target. The anchor [KytheVName] is returned. |
1115 /// | 1121 /// |
1116 /// If a [target] and [enclosingTarget] are provided, a childof edge is | 1122 /// If a [target] and [enclosingTarget] are provided, a childof edge is |
1117 /// written out from the target to the enclosing target. | 1123 /// written out from the target to the enclosing target. |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1188 String factName, List<int> factValue) { | 1194 String factName, List<int> factValue) { |
1189 assert(source != null); | 1195 assert(source != null); |
1190 assert(factName != null); | 1196 assert(factName != null); |
1191 assert(factValue != null); | 1197 assert(factValue != null); |
1192 // factValue may be an empty array, the fact may be that a file text or | 1198 // factValue may be an empty array, the fact may be that a file text or |
1193 // document text is empty | 1199 // document text is empty |
1194 if (edgeKind == null || edgeKind.isEmpty) { | 1200 if (edgeKind == null || edgeKind.isEmpty) { |
1195 edgeKind = null; | 1201 edgeKind = null; |
1196 target = null; | 1202 target = null; |
1197 } | 1203 } |
1198 var entry = new KytheEntry(source, edgeKind, target, factName, factValue); | 1204 var entry = new KytheEntry(source, factName, |
| 1205 kind: edgeKind, target: target, value: factValue); |
1199 entries.add(entry); | 1206 entries.add(entry); |
1200 return entry; | 1207 return entry; |
1201 } | 1208 } |
1202 | 1209 |
1203 /// This is a convenience method for visitors to add a fact [KytheEntry]. | 1210 /// This is a convenience method for visitors to add a fact [KytheEntry]. |
1204 KytheEntry addFact(KytheVName source, String factName, List<int> factValue) { | 1211 KytheEntry addFact(KytheVName source, String factName, List<int> factValue) { |
1205 return addEntry(source, null, null, factName, factValue); | 1212 return addEntry(source, null, null, factName, factValue); |
1206 } | 1213 } |
1207 | 1214 |
1208 /// This is a convenience method for adding function types. | 1215 /// This is a convenience method for adding function types. |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1316 KytheVName _vNameFile() { | 1323 KytheVName _vNameFile() { |
1317 // file vnames, the signature and language are not set | 1324 // file vnames, the signature and language are not set |
1318 return _vName('', corpus, '', enclosingFilePath, ''); | 1325 return _vName('', corpus, '', enclosingFilePath, ''); |
1319 } | 1326 } |
1320 | 1327 |
1321 /// Given some [Element] and Kythe node kind, this method generates and | 1328 /// Given some [Element] and Kythe node kind, this method generates and |
1322 /// returns the [KytheVName]. | 1329 /// returns the [KytheVName]. |
1323 KytheVName _vNameFromElement(Element e, String nodeKind) { | 1330 KytheVName _vNameFromElement(Element e, String nodeKind) { |
1324 assert(nodeKind != schema.FILE_KIND); | 1331 assert(nodeKind != schema.FILE_KIND); |
1325 // general case | 1332 // general case |
1326 return _vName(_getSignature(e, nodeKind, corpus), corpus, '', _getPath(e)); | 1333 return _vName(_getSignature(resourceProvider, e, nodeKind, corpus), corpus, |
| 1334 '', _getPath(resourceProvider, e)); |
1327 } | 1335 } |
1328 | 1336 |
1329 /// Returns a [KytheVName] corresponding to the given [DartType]. | 1337 /// Returns a [KytheVName] corresponding to the given [DartType]. |
1330 KytheVName _vNameFromType(DartType type) { | 1338 KytheVName _vNameFromType(DartType type) { |
1331 if (type == null || type.isDynamic) { | 1339 if (type == null || type.isDynamic) { |
1332 return dynamicBuiltin; | 1340 return dynamicBuiltin; |
1333 } else if (type.isVoid) { | 1341 } else if (type.isVoid) { |
1334 return voidBuiltin; | 1342 return voidBuiltin; |
1335 } else if (type.element is ClassElement) { | 1343 } else if (type.element is ClassElement) { |
1336 return _vNameFromElement(type.element, schema.RECORD_KIND); | 1344 return _vNameFromElement(type.element, schema.RECORD_KIND); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1380 } | 1388 } |
1381 | 1389 |
1382 @override | 1390 @override |
1383 StringBuffer visitTypeParameterElement(TypeParameterElement e) { | 1391 StringBuffer visitTypeParameterElement(TypeParameterElement e) { |
1384 // It is legal to have a named constructor with the same name as a type | 1392 // It is legal to have a named constructor with the same name as a type |
1385 // parameter. So we distinguish them by using '.' between the class (or | 1393 // parameter. So we distinguish them by using '.' between the class (or |
1386 // typedef) name and the type parameter name. | 1394 // typedef) name and the type parameter name. |
1387 return e.enclosingElement.accept(this)..write('.')..write(e.name); | 1395 return e.enclosingElement.accept(this)..write('.')..write(e.name); |
1388 } | 1396 } |
1389 } | 1397 } |
OLD | NEW |