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