| 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 |