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

Side by Side Diff: pkg/analyzer/lib/src/summary/index_unit.dart

Issue 1735243003: Initial package indexing implementation. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 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
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
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.
4
5 import 'package:analyzer/dart/ast/ast.dart';
6 import 'package:analyzer/dart/ast/token.dart';
7 import 'package:analyzer/dart/ast/visitor.dart';
8 import 'package:analyzer/dart/element/element.dart';
9 import 'package:analyzer/dart/element/type.dart';
10 import 'package:analyzer/src/generated/utilities_dart.dart';
11 import 'package:analyzer/src/summary/format.dart';
12 import 'package:analyzer/src/summary/idl.dart';
13
14 /**
15 * Object that gathers information about the whole package index and then uses
16 * it to assemble a new [PackageIndexBuilder].
Paul Berry 2016/02/25 23:05:13 It would be helpful to have a comment here explain
scheglov 2016/02/26 04:54:03 Done.
17 */
18 class PackageIndexAssembler {
19 final Map<Element, _ElementInfo> _elementMap = <Element, _ElementInfo>{};
20
21 final Map<CompilationUnitElement, int> _elementUnitMap =
Paul Berry 2016/02/25 23:05:12 Please add doc comments for all these fields. I'v
scheglov 2016/02/26 04:54:02 Done.
22 <CompilationUnitElement, int>{};
23 final List<int> _elementLibraryUris = <int>[];
24 final List<int> _elementUnitUris = <int>[];
25
26 final Map<String, int> _uriMap = <String, int>{};
27 final List<String> _uris = <String>[];
28
29 final List<_UnitIndexAssembler> _units = <_UnitIndexAssembler>[];
30
31 PackageIndexAssembler();
32
33 /**
34 * Assemble a new [PackageIndexBuilder] using the gathered information.
Paul Berry 2016/02/25 23:05:12 s/using the gathered information/using the informa
scheglov 2016/02/26 04:54:02 Done.
35 */
36 PackageIndexBuilder assemble() {
37 List<_ElementInfo> elements = _elementMap.values.toList();
Paul Berry 2016/02/25 23:05:12 Suggestion: rename this to "elementInfos" to avoid
scheglov 2016/02/26 04:54:02 Done.
38 elements.sort((a, b) {
39 return a.offset - b.offset;
40 });
41 for (int i = 0; i < elements.length; i++) {
42 elements[i].id = i;
43 }
44 return new PackageIndexBuilder(
45 elementLibraryUris: _elementLibraryUris,
46 elementUnitUris: _elementUnitUris,
47 elementUnits: elements.map((e) => e.unitId).toList(),
48 elementOffsets: elements.map((e) => e.offset).toList(),
49 uris: _uris,
50 units: _units.map((unit) => unit.assemble()).toList());
51 }
52
53 /**
54 * Index the given fully resolved [unit].
55 */
56 void index(CompilationUnit unit) {
57 CompilationUnitElement unitElement = unit.element;
58 _UnitIndexAssembler assembler = new _UnitIndexAssembler(this, unitElement);
59 _units.add(assembler);
60 unit.accept(new _IndexContributor(assembler));
61 }
62
63 _ElementInfo _getElementInfo(Element element) {
64 return _elementMap.putIfAbsent(element, () {
65 CompilationUnitElement unitElement = getUnitElement(element);
66 int unitId = _getUnitElementId(unitElement);
67 return new _ElementInfo(element, unitId);
68 });
69 }
70
71 int _getUnitElementId(CompilationUnitElement element) {
Paul Berry 2016/02/25 23:05:12 Documentation on these private methods would be he
scheglov 2016/02/26 04:54:03 Done.
72 return _elementUnitMap.putIfAbsent(element, () {
73 assert(_elementLibraryUris.length == _elementUnitUris.length);
74 int id = _elementUnitUris.length;
75 _elementLibraryUris.add(_getUriId(element.library.source.uri));
76 _elementUnitUris.add(_getUriId(element.source.uri));
77 return id;
78 });
79 }
80
81 int _getUriId(Uri uri) {
82 String str = uri.toString();
83 return _uriMap.putIfAbsent(str, () {
84 int id = _uris.length;
85 _uris.add(str);
86 return id;
87 });
88 }
89
90 /**
91 * Return the [CompilationUnitElement] that should be used for [element].
92 */
93 static CompilationUnitElement getUnitElement(Element element) {
Paul Berry 2016/02/25 23:05:13 It looks like this is only used by other code in t
scheglov 2016/02/26 04:54:03 It is used in tests. And it also will be used in i
94 CompilationUnitElement unitElement;
95 for (Element e = element; e != null; e = e.enclosingElement) {
96 if (e is CompilationUnitElement) {
97 unitElement = e;
98 break;
99 }
100 if (e is LibraryElement) {
101 unitElement = e.definingCompilationUnit;
102 break;
103 }
104 }
105 assert(unitElement != null);
106 return unitElement;
107 }
108 }
109
110 /**
111 * Information about an element referenced in index.
112 */
113 class _ElementInfo {
114 final Element element;
Paul Berry 2016/02/25 23:05:13 It looks like this is only used by the [offset] ge
scheglov 2016/02/26 04:54:03 Done.
115
116 /**
117 * The identifier of the [CompilationUnitElement] containing [element].
118 */
119 final int unitId;
120
121 /**
122 * The unique id of the [element] in the [PackageIndex]. It is set after
123 * after indexing of the whole package is done and we are assembling the
124 * full package index.
125 */
126 int id;
127
128 _ElementInfo(this.element, this.unitId);
129
130 int get offset => element.nameOffset;
131 }
132
133 /**
134 * Visits a resolved AST and adds relationships into [InternalIndexStore].
135 */
136 class _IndexContributor extends GeneralizingAstVisitor {
137 final _UnitIndexAssembler assembler;
138
139 _IndexContributor(this.assembler);
140
141 /**
142 * Record that [element] has a relation of the given [kind] at the location
143 * of the given [node].
144 */
145 void recordRelation(Element element, IndexRelationKind kind, AstNode node) {
146 if (element != null && node != null) {
147 recordRelationOffset(element, kind, node.offset, node.length);
148 }
149 }
150
151 /**
152 * Record that [element] has a relation of the given [kind] at the given
153 * [offset] and [length].
154 */
155 void recordRelationOffset(
156 Element element, IndexRelationKind kind, int offset, int length) {
157 // Ignore elements that can't be referenced outside of the unit.
158 if (element == null ||
159 element is LocalVariableElement ||
160 element is ParameterElement &&
161 element.parameterKind != ParameterKind.NAMED ||
162 element is FunctionElement &&
163 element.enclosingElement is ExecutableElement) {
164 return;
165 }
166 // Add the relation.
167 assembler.addRelation(element, kind, offset, length);
168 }
169
170 /**
171 * Record that [element] has a relation of the given [kind] at the location
172 * of the given [token].
173 */
174 void recordRelationToken(
175 Element element, IndexRelationKind kind, Token token) {
176 if (element != null && token != null) {
177 recordRelationOffset(element, kind, token.offset, token.length);
178 }
179 }
180
181 @override
182 visitAssignmentExpression(AssignmentExpression node) {
183 _recordOperatorReference(node.operator, node.bestElement);
184 super.visitAssignmentExpression(node);
185 }
186
187 @override
188 visitBinaryExpression(BinaryExpression node) {
189 _recordOperatorReference(node.operator, node.bestElement);
190 super.visitBinaryExpression(node);
191 }
192
193 @override
194 visitClassDeclaration(ClassDeclaration node) {
195 ClassElement element = node.element;
196 _recordTopLevelElementDefinition(element);
197 {
198 ExtendsClause extendsClause = node.extendsClause;
199 if (extendsClause != null) {
200 TypeName superclassNode = extendsClause.superclass;
201 _recordSuperType(superclassNode, IndexRelationKind.IS_EXTENDED_BY);
202 } else {
203 InterfaceType superType = element.supertype;
204 if (superType != null) {
205 ClassElement objectElement = superType.element;
206 recordRelationOffset(objectElement, IndexRelationKind.IS_EXTENDED_BY,
207 node.name.offset, 0);
208 }
209 }
210 }
211 {
212 WithClause withClause = node.withClause;
213 if (withClause != null) {
214 for (TypeName mixinNode in withClause.mixinTypes) {
215 _recordSuperType(mixinNode, IndexRelationKind.IS_MIXED_IN_BY);
216 }
217 }
218 }
219 {
220 ImplementsClause implementsClause = node.implementsClause;
221 if (implementsClause != null) {
222 for (TypeName interfaceNode in implementsClause.interfaces) {
223 _recordSuperType(interfaceNode, IndexRelationKind.IS_IMPLEMENTED_BY);
224 }
225 }
226 }
227 super.visitClassDeclaration(node);
228 }
229
230 @override
231 visitClassTypeAlias(ClassTypeAlias node) {
232 ClassElement element = node.element;
Paul Berry 2016/02/25 23:05:12 There's a lot of common code between this method a
scheglov 2016/02/26 04:54:02 Done.
233 _recordTopLevelElementDefinition(element);
234 {
235 TypeName superclassNode = node.superclass;
236 if (superclassNode != null) {
237 _recordSuperType(superclassNode, IndexRelationKind.IS_EXTENDED_BY);
238 }
239 }
240 {
241 WithClause withClause = node.withClause;
242 if (withClause != null) {
243 for (TypeName mixinNode in withClause.mixinTypes) {
244 _recordSuperType(mixinNode, IndexRelationKind.IS_MIXED_IN_BY);
245 }
246 }
247 }
248 {
249 ImplementsClause implementsClause = node.implementsClause;
250 if (implementsClause != null) {
251 for (TypeName interfaceNode in implementsClause.interfaces) {
252 _recordSuperType(interfaceNode, IndexRelationKind.IS_IMPLEMENTED_BY);
253 }
254 }
255 }
256 super.visitClassTypeAlias(node);
257 }
258
259 @override
260 visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
261 SimpleIdentifier fieldName = node.fieldName;
262 Expression expression = node.expression;
263 // field reference is write here
Paul Berry 2016/02/25 23:05:12 I don't understand this comment. Do you mean "rig
scheglov 2016/02/26 04:54:03 Initially the code was using IndexRelationKind.IS_
264 if (fieldName != null) {
265 Element element = fieldName.staticElement;
266 recordRelation(element, IndexRelationKind.IS_REFERENCED_BY, fieldName);
267 }
268 // index expression
269 if (expression != null) {
270 expression.accept(this);
271 }
272 }
273
274 @override
275 visitConstructorName(ConstructorName node) {
276 ConstructorElement element = node.staticElement;
277 // in 'class B = A;' actually A constructors are invoked
278 if (element != null &&
279 element.isSynthetic &&
280 element.redirectedConstructor != null) {
281 element = element.redirectedConstructor;
Paul Berry 2016/02/25 23:05:13 What if there are multiple levels of indirection?
scheglov 2016/02/26 04:54:03 I will add TODO and test/fix it in the next CL.
282 }
283 // record relation
284 if (node.name != null) {
285 int offset = node.period.offset;
286 int length = node.name.end - offset;
287 recordRelationOffset(
288 element, IndexRelationKind.IS_REFERENCED_BY, offset, length);
289 } else {
290 int offset = node.type.end;
291 recordRelationOffset(
292 element, IndexRelationKind.IS_REFERENCED_BY, offset, 0);
293 }
294 super.visitConstructorName(node);
295 }
296
297 @override
298 visitEnumDeclaration(EnumDeclaration node) {
299 ClassElement element = node.element;
300 _recordTopLevelElementDefinition(element);
301 super.visitEnumDeclaration(node);
302 }
303
304 @override
305 visitExportDirective(ExportDirective node) {
306 ExportElement element = node.element;
307 if (element != null) {
308 LibraryElement expLibrary = element.exportedLibrary;
309 _recordLibraryReference(node, expLibrary);
310 }
311 _recordUriFileReference(node);
312 super.visitExportDirective(node);
313 }
314
315 @override
316 visitFunctionDeclaration(FunctionDeclaration node) {
317 Element element = node.element;
318 _recordTopLevelElementDefinition(element);
319 super.visitFunctionDeclaration(node);
320 }
321
322 @override
323 visitFunctionTypeAlias(FunctionTypeAlias node) {
324 Element element = node.element;
325 _recordTopLevelElementDefinition(element);
326 super.visitFunctionTypeAlias(node);
327 }
328
329 @override
330 visitImportDirective(ImportDirective node) {
331 ImportElement element = node.element;
332 if (element != null) {
333 LibraryElement impLibrary = element.importedLibrary;
334 _recordLibraryReference(node, impLibrary);
335 }
336 _recordUriFileReference(node);
337 super.visitImportDirective(node);
338 }
339
340 @override
341 visitIndexExpression(IndexExpression node) {
342 MethodElement element = node.bestElement;
343 if (element is MethodElement) {
344 Token operator = node.leftBracket;
345 recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator);
346 }
347 super.visitIndexExpression(node);
348 }
349
350 @override
351 visitMethodInvocation(MethodInvocation node) {
352 SimpleIdentifier name = node.methodName;
353 // TODO(scheglov) do we need this?
354 // LocationImpl location = _createLocationForNode(name);
355 // // name invocation
356 // recordRelationshipIndexable(
357 // new IndexableName(name.name), IndexConstants.IS_INVOKED_BY, location);
358 // element invocation
359 Element element = name.bestElement;
360 if (element is MethodElement ||
361 element is PropertyAccessorElement ||
362 element is FunctionElement ||
363 element is VariableElement) {
364 recordRelation(element, IndexRelationKind.IS_INVOKED_BY, node);
365 } else if (element is ClassElement) {
366 recordRelation(element, IndexRelationKind.IS_REFERENCED_BY, node);
367 }
368 node.target?.accept(this);
369 node.argumentList?.accept(this);
370 }
371
372 @override
373 visitPartDirective(PartDirective node) {
374 recordRelation(node.element, IndexRelationKind.IS_REFERENCED_BY, node);
375 _recordUriFileReference(node);
376 super.visitPartDirective(node);
377 }
378
379 @override
380 visitPartOfDirective(PartOfDirective node) {
381 recordRelation(node.element, IndexRelationKind.IS_REFERENCED_BY, node);
382 }
383
384 @override
385 visitPostfixExpression(PostfixExpression node) {
386 _recordOperatorReference(node.operator, node.bestElement);
387 super.visitPostfixExpression(node);
388 }
389
390 @override
391 visitPrefixExpression(PrefixExpression node) {
392 _recordOperatorReference(node.operator, node.bestElement);
393 super.visitPrefixExpression(node);
394 }
395
396 @override
397 visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
398 ConstructorElement element = node.staticElement;
399 if (node.constructorName != null) {
400 int offset = node.period.offset;
401 int length = node.constructorName.end - offset;
402 recordRelationOffset(
403 element, IndexRelationKind.IS_REFERENCED_BY, offset, length);
404 } else {
405 int offset = node.thisKeyword.end;
406 recordRelationOffset(
407 element, IndexRelationKind.IS_REFERENCED_BY, offset, 0);
408 }
409 super.visitRedirectingConstructorInvocation(node);
410 }
411
412 @override
413 visitSimpleIdentifier(SimpleIdentifier node) {
414 // TODO(scheglov) do we need this?
415 // IndexableName indexableName = new IndexableName(node.name);
416 // LocationImpl location = _createLocationForNode(node);
417 // if (location == null) {
418 // return;
419 // }
420 // name in declaration
421 if (node.inDeclarationContext()) {
422 // TODO(scheglov) do we need this?
423 // recordRelationshipIndexable(
424 // indexableName, IndexConstants.NAME_IS_DEFINED_BY, location);
425 return;
426 }
427 // name in an extends/with/implements clause
428 if (_isInExtendsWithImplementsClause(node)) {
429 return;
430 }
431 Element element = node.bestElement;
432 // this.field parameter
433 if (element is FieldFormalParameterElement) {
434 recordRelation(element.field, IndexRelationKind.IS_REFERENCED_BY, node);
435 return;
436 }
437 // record specific relations
438 if (element is ClassElement ||
439 element is FunctionElement ||
440 element is FunctionTypeAliasElement ||
441 element is LabelElement ||
442 element is MethodElement ||
443 element is PropertyAccessorElement ||
444 element is PropertyInducingElement ||
445 element is TypeParameterElement) {
446 recordRelation(element, IndexRelationKind.IS_REFERENCED_BY, node);
447 } else if (element is PrefixElement) {
Paul Berry 2016/02/25 23:05:13 This clause can be combined with the "if" clause a
scheglov 2016/02/26 04:54:03 Done.
448 recordRelation(element, IndexRelationKind.IS_REFERENCED_BY, node);
449 }
450 super.visitSimpleIdentifier(node);
451 }
452
453 @override
454 visitSuperConstructorInvocation(SuperConstructorInvocation node) {
455 ConstructorElement element = node.staticElement;
456 if (node.constructorName != null) {
457 int offset = node.period.offset;
458 int length = node.constructorName.end - offset;
459 recordRelationOffset(
460 element, IndexRelationKind.IS_REFERENCED_BY, offset, length);
461 } else {
462 int offset = node.superKeyword.end;
463 recordRelationOffset(
464 element, IndexRelationKind.IS_REFERENCED_BY, offset, 0);
465 }
466 super.visitSuperConstructorInvocation(node);
467 }
468
469 @override
470 visitVariableDeclaration(VariableDeclaration node) {
471 VariableElement element = node.element;
472 _recordTopLevelElementDefinition(element);
473 // TODO(scheglov) do we need this?
474 // // record declaration
475 // {
476 // SimpleIdentifier name = node.name;
477 // LocationImpl location = _createLocationForNode(name);
478 // location = _getLocationWithExpressionType(location, node.initializer);
479 // recordRelationshipElement(
480 // element, IndexConstants.NAME_IS_DEFINED_BY, location);
481 // }
482 super.visitVariableDeclaration(node);
483 }
484
485 /**
486 * Records reference to defining [CompilationUnitElement] of the given
487 * [LibraryElement].
488 */
489 void _recordLibraryReference(UriBasedDirective node, LibraryElement library) {
Paul Berry 2016/02/25 23:05:13 All methods in this class are inherently private s
scheglov 2016/02/26 04:54:03 Done.
490 recordRelation(library, IndexRelationKind.IS_REFERENCED_BY, node?.uri);
491 }
492
493 /**
494 * Record reference to the given operator [Element] and name.
495 */
496 void _recordOperatorReference(Token operator, Element element) {
497 recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator);
498 // TODO(scheglov) do we need this?
499 // // prepare location
500 // LocationImpl location = _createLocationForToken(operator, element != null) ;
501 // // record name reference
502 // {
503 // String name = operator.lexeme;
504 // if (name == "++") {
505 // name = "+";
506 // }
507 // if (name == "--") {
508 // name = "-";
509 // }
510 // if (StringUtilities.endsWithChar(name, 0x3D) && name != "==") {
511 // name = name.substring(0, name.length - 1);
512 // }
513 // IndexableName indexableName = new IndexableName(name);
514 // recordRelationshipIndexable(
515 // indexableName, IndexConstants.IS_INVOKED_BY, location);
516 // }
517 // // record element reference
518 // if (element != null) {
519 // recordRelationshipElement(
520 // element, IndexConstants.IS_INVOKED_BY, location);
521 // }
522 }
523
524 /**
525 * Records a relation between [superNode] and its [Element].
526 */
527 void _recordSuperType(TypeName superNode, IndexRelationKind kind) {
528 if (superNode != null) {
529 Identifier superName = superNode.name;
530 if (superName != null) {
531 Element superElement = superName.staticElement;
532 recordRelation(superElement, kind, superName);
533 }
534 }
535 }
536
537 /**
538 * Record the top-level [element] definition.
539 */
540 void _recordTopLevelElementDefinition(Element element) {
541 // TODO(scheglov) do we need this?
542 // if (element?.enclosingElement is CompilationUnitElement) {
543 // IndexableElement indexable = new IndexableElement(element);
544 // int offset = element.nameOffset;
545 // int length = element.nameLength;
546 // LocationImpl location = new LocationImpl(indexable, offset, length);
547 // recordRelationshipElement(
548 // _libraryElement, IndexConstants.DEFINES, location);
549 // _store.recordTopLevelDeclaration(element);
550 // }
551 }
552
553 void _recordUriFileReference(UriBasedDirective directive) {
554 Element element = directive.element;
555 recordRelation(element, IndexRelationKind.IS_REFERENCED_BY, directive.uri);
556 }
557
558 static bool _isInExtendsWithImplementsClause(SimpleIdentifier node) {
559 TypeName typeName;
560 AstNode parent = node?.parent;
561 AstNode parent2 = parent?.parent;
562 if (parent is TypeName && parent.name == node) {
563 typeName = parent;
564 } else if (parent is PrefixedIdentifier &&
565 parent.identifier == node &&
566 parent2 is TypeName &&
567 parent2.name == node) {
568 typeName = parent2;
569 } else {
570 return false;
571 }
572 AstNode clause = typeName.parent;
573 return clause is ExtendsClause ||
574 clause is WithClause ||
575 clause is ImplementsClause;
576 }
577 }
578
579 /**
580 * Information about a single relation.
Paul Berry 2016/02/25 23:05:12 Add a comment explaining that [_RelationInfo] alwa
scheglov 2016/02/26 04:54:03 Done.
581 */
582 class _RelationInfo {
583 final _ElementInfo element;
Paul Berry 2016/02/25 23:05:13 Rename to "elementInfo". Otherwise it's easy to b
scheglov 2016/02/26 04:54:03 Done.
584 final IndexRelationKind kind;
585 final int offset;
586 final int length;
587
588 _RelationInfo(this.element, this.kind, this.offset, this.length);
589 }
590
591 /**
592 * Assembler of a single [CompilationUnit] index.
593 */
Paul Berry 2016/02/25 23:05:13 As with [PackageIndexAssembler], it would be helpf
scheglov 2016/02/26 04:54:03 Done.
594 class _UnitIndexAssembler {
595 final PackageIndexAssembler pkg;
596 final CompilationUnitElement unitElement;
597 final List<_RelationInfo> relations = <_RelationInfo>[];
598
599 _UnitIndexAssembler(this.pkg, this.unitElement);
600
601 void addRelation(
602 Element element, IndexRelationKind kind, int offset, int length) {
603 _ElementInfo elementInfo = pkg._getElementInfo(element);
604 relations.add(new _RelationInfo(elementInfo, kind, offset, length));
605 }
606
607 /**
608 * Assemble a new [UnitIndexBuilder] using the gathered information.
Paul Berry 2016/02/25 23:05:12 s/using the gathered information/using the informa
scheglov 2016/02/26 04:54:03 Done.
609 */
610 UnitIndexBuilder assemble() {
611 relations.sort((a, b) {
612 return a.element.id - b.element.id;
613 });
614 return new UnitIndexBuilder(
615 elements: relations.map((r) => r.element.id).toList(),
616 kinds: relations.map((r) => r.kind).toList(),
617 locationOffsets: relations.map((r) => r.offset).toList(),
618 locationLengths: relations.map((r) => r.length).toList(),
619 libraryUri: pkg._getUriId(unitElement.library.source.uri),
620 unitUri: pkg._getUriId(unitElement.source.uri));
621 }
622 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/src/abstract_single_unit.dart » ('j') | pkg/analyzer/test/src/summary/index_unit_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698