| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library serialization.elements; | 5 library serialization.elements; |
| 6 | 6 |
| 7 import 'dart:convert'; | 7 import 'dart:convert'; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | |
| 10 import 'package:analyzer/dart/element/element.dart'; | |
| 11 import 'package:analyzer/dart/element/type.dart'; | |
| 12 import 'package:analyzer/src/dart/element/element.dart'; | |
| 13 import 'package:analyzer/src/dart/element/member.dart'; | |
| 14 import 'package:analyzer/src/dart/element/type.dart'; | |
| 15 import 'package:analyzer/src/generated/resolver.dart'; | |
| 16 import 'package:analyzer/src/generated/source.dart'; | 9 import 'package:analyzer/src/generated/source.dart'; |
| 17 import 'package:analyzer/src/generated/utilities_dart.dart'; | |
| 18 import 'package:analyzer/src/summary/api_signature.dart'; | 10 import 'package:analyzer/src/summary/api_signature.dart'; |
| 19 import 'package:analyzer/src/summary/format.dart'; | 11 import 'package:analyzer/src/summary/format.dart'; |
| 20 import 'package:analyzer/src/summary/idl.dart'; | 12 import 'package:analyzer/src/summary/idl.dart'; |
| 21 import 'package:analyzer/src/summary/name_filter.dart'; | |
| 22 import 'package:analyzer/src/summary/package_bundle_reader.dart'; | 13 import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
| 23 import 'package:analyzer/src/summary/summarize_const_expr.dart'; | |
| 24 import 'package:convert/convert.dart'; | 14 import 'package:convert/convert.dart'; |
| 25 import 'package:crypto/crypto.dart'; | 15 import 'package:crypto/crypto.dart'; |
| 26 | 16 |
| 27 /** | 17 /** |
| 28 * Serialize all the elements in [lib] to a summary using [ctx] as the context | |
| 29 * for building the summary, and using [typeProvider] to find built-in types. | |
| 30 */ | |
| 31 LibrarySerializationResult serializeLibrary( | |
| 32 LibraryElement lib, TypeProvider typeProvider, bool strongMode) { | |
| 33 _LibrarySerializer serializer = | |
| 34 new _LibrarySerializer(lib, typeProvider, strongMode); | |
| 35 LinkedLibraryBuilder linked = serializer.serializeLibrary(); | |
| 36 return new LibrarySerializationResult(linked, serializer.unlinkedUnits, | |
| 37 serializer.unitUris, serializer.unitSources); | |
| 38 } | |
| 39 | |
| 40 ReferenceKind _getReferenceKind(Element element) { | |
| 41 if (element == null || | |
| 42 element is ClassElement || | |
| 43 element is DynamicElementImpl) { | |
| 44 return ReferenceKind.classOrEnum; | |
| 45 } else if (element is ConstructorElement) { | |
| 46 return ReferenceKind.constructor; | |
| 47 } else if (element is FunctionElement) { | |
| 48 if (element.enclosingElement is CompilationUnitElement) { | |
| 49 return ReferenceKind.topLevelFunction; | |
| 50 } | |
| 51 return ReferenceKind.function; | |
| 52 } else if (element is FunctionTypeAliasElement) { | |
| 53 return ReferenceKind.typedef; | |
| 54 } else if (element is PropertyAccessorElement) { | |
| 55 if (element.enclosingElement is ClassElement) { | |
| 56 return ReferenceKind.propertyAccessor; | |
| 57 } | |
| 58 return ReferenceKind.topLevelPropertyAccessor; | |
| 59 } else if (element is MethodElement) { | |
| 60 return ReferenceKind.method; | |
| 61 } else if (element is TopLevelVariableElement) { | |
| 62 // Summaries don't need to distinguish between references to a variable and | |
| 63 // references to its getter. | |
| 64 return ReferenceKind.topLevelPropertyAccessor; | |
| 65 } else if (element is LocalVariableElement) { | |
| 66 return ReferenceKind.variable; | |
| 67 } else if (element is FieldElement) { | |
| 68 // Summaries don't need to distinguish between references to a field and | |
| 69 // references to its getter. | |
| 70 return ReferenceKind.propertyAccessor; | |
| 71 } else { | |
| 72 throw new Exception('Unexpected element kind: ${element.runtimeType}'); | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 /** | |
| 77 * Type of closures used by [_LibrarySerializer] to defer generation of | |
| 78 * [EntityRefBuilder] objects until the end of serialization of a | |
| 79 * compilation unit. | |
| 80 */ | |
| 81 typedef EntityRefBuilder _SerializeTypeRef(); | |
| 82 | |
| 83 /** | |
| 84 * Data structure holding the result of serializing a [LibraryElement]. | |
| 85 */ | |
| 86 class LibrarySerializationResult { | |
| 87 /** | |
| 88 * Linked information the given library. | |
| 89 */ | |
| 90 final LinkedLibraryBuilder linked; | |
| 91 | |
| 92 /** | |
| 93 * Unlinked information for the compilation units constituting the library. | |
| 94 * The zeroth entry in the list is the defining compilation unit; the | |
| 95 * remaining entries are the parts, in the order listed in the defining | |
| 96 * compilation unit's part declarations. | |
| 97 */ | |
| 98 final List<UnlinkedUnitBuilder> unlinkedUnits; | |
| 99 | |
| 100 /** | |
| 101 * Absolute URI of each compilation unit appearing in the library. | |
| 102 */ | |
| 103 final List<String> unitUris; | |
| 104 | |
| 105 /** | |
| 106 * Source object corresponding to each compilation unit appearing in the | |
| 107 * library. | |
| 108 */ | |
| 109 final List<Source> unitSources; | |
| 110 | |
| 111 LibrarySerializationResult( | |
| 112 this.linked, this.unlinkedUnits, this.unitUris, this.unitSources); | |
| 113 } | |
| 114 | |
| 115 /** | |
| 116 * Object that gathers information uses it to assemble a new | 18 * Object that gathers information uses it to assemble a new |
| 117 * [PackageBundleBuilder]. | 19 * [PackageBundleBuilder]. |
| 118 */ | 20 */ |
| 119 class PackageBundleAssembler { | 21 class PackageBundleAssembler { |
| 120 /** | 22 /** |
| 121 * Value that will be stored in [PackageBundle.majorVersion] for any summaries | 23 * Value that will be stored in [PackageBundle.majorVersion] for any summaries |
| 122 * created by this code. When making a breaking change to the summary format, | 24 * created by this code. When making a breaking change to the summary format, |
| 123 * this value should be incremented by 1 and [currentMinorVersion] should be | 25 * this value should be incremented by 1 and [currentMinorVersion] should be |
| 124 * reset to zero. | 26 * reset to zero. |
| 125 */ | 27 */ |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 | 91 |
| 190 /** | 92 /** |
| 191 * Use the dependency information in [summaryDataStore] to populate the | 93 * Use the dependency information in [summaryDataStore] to populate the |
| 192 * dependencies in the package bundle being assembled. | 94 * dependencies in the package bundle being assembled. |
| 193 */ | 95 */ |
| 194 void recordDependencies(SummaryDataStore summaryDataStore) { | 96 void recordDependencies(SummaryDataStore summaryDataStore) { |
| 195 _dependencies.addAll(summaryDataStore.dependencies); | 97 _dependencies.addAll(summaryDataStore.dependencies); |
| 196 } | 98 } |
| 197 | 99 |
| 198 /** | 100 /** |
| 199 * Serialize the library with the given [element]. | |
| 200 */ | |
| 201 void serializeLibraryElement(LibraryElement element) { | |
| 202 String uri = element.source.uri.toString(); | |
| 203 LibrarySerializationResult libraryResult = serializeLibrary( | |
| 204 element, | |
| 205 element.context.typeProvider, | |
| 206 element.context.analysisOptions.strongMode); | |
| 207 _linkedLibraryUris.add(uri); | |
| 208 _linkedLibraries.add(libraryResult.linked); | |
| 209 _unlinkedUnitUris.addAll(libraryResult.unitUris); | |
| 210 _unlinkedUnits.addAll(libraryResult.unlinkedUnits); | |
| 211 for (int i = 0; i < libraryResult.unitUris.length; i++) { | |
| 212 _unlinkedUnitMap[libraryResult.unitUris[i]] = | |
| 213 libraryResult.unlinkedUnits[i]; | |
| 214 } | |
| 215 for (Source source in libraryResult.unitSources) { | |
| 216 _unlinkedUnitHashes?.add(_hash(source.contents.data)); | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 /** | |
| 221 * Compute the API signature for this package bundle. | 101 * Compute the API signature for this package bundle. |
| 222 */ | 102 */ |
| 223 String _computeApiSignature() { | 103 String _computeApiSignature() { |
| 224 ApiSignature apiSignature = new ApiSignature(); | 104 ApiSignature apiSignature = new ApiSignature(); |
| 225 for (String unitUri in _unlinkedUnitMap.keys.toList()..sort()) { | 105 for (String unitUri in _unlinkedUnitMap.keys.toList()..sort()) { |
| 226 apiSignature.addString(unitUri); | 106 apiSignature.addString(unitUri); |
| 227 _unlinkedUnitMap[unitUri].collectApiSignature(apiSignature); | 107 _unlinkedUnitMap[unitUri].collectApiSignature(apiSignature); |
| 228 } | 108 } |
| 229 return apiSignature.toHex(); | 109 return apiSignature.toHex(); |
| 230 } | 110 } |
| 231 | 111 |
| 232 /** | 112 /** |
| 233 * Compute a hash of the given file contents. | 113 * Compute a hash of the given file contents. |
| 234 */ | 114 */ |
| 235 String _hash(String contents) { | 115 String _hash(String contents) { |
| 236 return hex.encode(md5.convert(UTF8.encode(contents)).bytes); | 116 return hex.encode(md5.convert(UTF8.encode(contents)).bytes); |
| 237 } | 117 } |
| 238 } | 118 } |
| 239 | |
| 240 /** | |
| 241 * Instances of this class keep track of intermediate state during | |
| 242 * serialization of a single compilation unit. | |
| 243 */ | |
| 244 class _CompilationUnitSerializer { | |
| 245 /** | |
| 246 * The [_LibrarySerializer] which is serializing the library of which | |
| 247 * [compilationUnit] is a part. | |
| 248 */ | |
| 249 final _LibrarySerializer librarySerializer; | |
| 250 | |
| 251 /** | |
| 252 * The [CompilationUnitElement] being serialized. | |
| 253 */ | |
| 254 final CompilationUnitElement compilationUnit; | |
| 255 | |
| 256 /** | |
| 257 * The ordinal index of [compilationUnit] within the library, where 0 | |
| 258 * represents the defining compilation unit. | |
| 259 */ | |
| 260 final int unitNum; | |
| 261 | |
| 262 /** | |
| 263 * The final linked summary of the compilation unit. | |
| 264 */ | |
| 265 final LinkedUnitBuilder linkedUnit = new LinkedUnitBuilder(); | |
| 266 | |
| 267 /** | |
| 268 * The final unlinked summary of the compilation unit. | |
| 269 */ | |
| 270 final UnlinkedUnitBuilder unlinkedUnit = new UnlinkedUnitBuilder(); | |
| 271 | |
| 272 /** | |
| 273 * Absolute URI of the compilation unit. | |
| 274 */ | |
| 275 String unitUri; | |
| 276 | |
| 277 /** | |
| 278 * Map from [Element] to the index of the entry in the "references table" | |
| 279 * that refers to it. | |
| 280 */ | |
| 281 final Map<Element, int> referenceMap = <Element, int>{}; | |
| 282 | |
| 283 /** | |
| 284 * The unlinked portion of the "references table". This is the list of | |
| 285 * objects which should be written to [UnlinkedUnit.references]. | |
| 286 */ | |
| 287 List<UnlinkedReferenceBuilder> unlinkedReferences; | |
| 288 | |
| 289 /** | |
| 290 * The linked portion of the "references table". This is the list of | |
| 291 * objects which should be written to [LinkedUnit.references]. | |
| 292 */ | |
| 293 List<LinkedReferenceBuilder> linkedReferences; | |
| 294 | |
| 295 /** | |
| 296 * The number of slot ids which have been assigned to this compilation unit. | |
| 297 */ | |
| 298 int numSlots = 0; | |
| 299 | |
| 300 /** | |
| 301 * List of closures which should be invoked at the end of serialization of a | |
| 302 * compilation unit, to produce [LinkedUnit.types]. | |
| 303 */ | |
| 304 final List<_SerializeTypeRef> deferredLinkedTypes = <_SerializeTypeRef>[]; | |
| 305 | |
| 306 /** | |
| 307 * List which should be stored in [LinkedUnit.constCycles]. | |
| 308 */ | |
| 309 final List<int> constCycles = <int>[]; | |
| 310 | |
| 311 /** | |
| 312 * Index into the "references table" representing an unresolved reference, if | |
| 313 * such an index exists. `null` if no such entry has been made in the | |
| 314 * references table yet. | |
| 315 */ | |
| 316 int unresolvedReferenceIndex = null; | |
| 317 | |
| 318 /** | |
| 319 * Index into the "references table" representing the "bottom" type, if such | |
| 320 * an index exists. `null` if no such entry has been made in the references | |
| 321 * table yet. | |
| 322 */ | |
| 323 int bottomReferenceIndex = null; | |
| 324 | |
| 325 /** | |
| 326 * If `true`, we are currently generating linked references, so new | |
| 327 * references will be not stored in [unlinkedReferences]. | |
| 328 */ | |
| 329 bool buildingLinkedReferences = false; | |
| 330 | |
| 331 _CompilationUnitSerializer( | |
| 332 this.librarySerializer, this.compilationUnit, this.unitNum); | |
| 333 | |
| 334 /** | |
| 335 * Source object for the compilation unit. | |
| 336 */ | |
| 337 Source get unitSource => compilationUnit.source; | |
| 338 | |
| 339 /** | |
| 340 * Add all classes, enums, typedefs, executables, and top level variables | |
| 341 * from the given compilation unit [element] to the compilation unit summary. | |
| 342 * [unitNum] indicates the ordinal position of this compilation unit in the | |
| 343 * library. | |
| 344 */ | |
| 345 void addCompilationUnitElements() { | |
| 346 unlinkedReferences = <UnlinkedReferenceBuilder>[ | |
| 347 new UnlinkedReferenceBuilder() | |
| 348 ]; | |
| 349 linkedReferences = <LinkedReferenceBuilder>[ | |
| 350 new LinkedReferenceBuilder(kind: ReferenceKind.unresolved) | |
| 351 ]; | |
| 352 List<UnlinkedPublicNameBuilder> names = <UnlinkedPublicNameBuilder>[]; | |
| 353 for (PropertyAccessorElement accessor in compilationUnit.accessors) { | |
| 354 if (accessor.isPublic) { | |
| 355 names.add(new UnlinkedPublicNameBuilder( | |
| 356 kind: ReferenceKind.topLevelPropertyAccessor, | |
| 357 name: accessor.name, | |
| 358 numTypeParameters: accessor.typeParameters.length)); | |
| 359 } | |
| 360 } | |
| 361 for (ClassElement cls in compilationUnit.types) { | |
| 362 if (cls.isPublic) { | |
| 363 names.add(new UnlinkedPublicNameBuilder( | |
| 364 kind: ReferenceKind.classOrEnum, | |
| 365 name: cls.name, | |
| 366 numTypeParameters: cls.typeParameters.length, | |
| 367 members: serializeClassStaticMembers(cls))); | |
| 368 } | |
| 369 } | |
| 370 for (ClassElement enm in compilationUnit.enums) { | |
| 371 if (enm.isPublic) { | |
| 372 names.add(new UnlinkedPublicNameBuilder( | |
| 373 kind: ReferenceKind.classOrEnum, | |
| 374 name: enm.name, | |
| 375 members: serializeClassStaticMembers(enm))); | |
| 376 } | |
| 377 } | |
| 378 for (FunctionElement function in compilationUnit.functions) { | |
| 379 if (function.isPublic) { | |
| 380 names.add(new UnlinkedPublicNameBuilder( | |
| 381 kind: ReferenceKind.topLevelFunction, | |
| 382 name: function.name, | |
| 383 numTypeParameters: function.typeParameters.length)); | |
| 384 } | |
| 385 } | |
| 386 for (FunctionTypeAliasElement typedef | |
| 387 in compilationUnit.functionTypeAliases) { | |
| 388 if (typedef.isPublic) { | |
| 389 names.add(new UnlinkedPublicNameBuilder( | |
| 390 kind: ReferenceKind.typedef, | |
| 391 name: typedef.name, | |
| 392 numTypeParameters: typedef.typeParameters.length)); | |
| 393 } | |
| 394 } | |
| 395 if (unitNum == 0) { | |
| 396 LibraryElement libraryElement = librarySerializer.libraryElement; | |
| 397 if (libraryElement.name.isNotEmpty) { | |
| 398 LibraryElement libraryElement = librarySerializer.libraryElement; | |
| 399 unlinkedUnit.libraryName = libraryElement.name; | |
| 400 unlinkedUnit.libraryNameOffset = libraryElement.nameOffset; | |
| 401 unlinkedUnit.libraryNameLength = libraryElement.nameLength; | |
| 402 unlinkedUnit.libraryDocumentationComment = | |
| 403 serializeDocumentation(libraryElement); | |
| 404 unlinkedUnit.libraryAnnotations = serializeAnnotations(libraryElement); | |
| 405 } | |
| 406 unlinkedUnit.publicNamespace = new UnlinkedPublicNamespaceBuilder( | |
| 407 exports: libraryElement.exports.map(serializeExportPublic).toList(), | |
| 408 parts: libraryElement.parts | |
| 409 .map((CompilationUnitElement e) => e.uri) | |
| 410 .toList(), | |
| 411 names: names); | |
| 412 unlinkedUnit.exports = | |
| 413 libraryElement.exports.map(serializeExportNonPublic).toList(); | |
| 414 unlinkedUnit.imports = | |
| 415 libraryElement.imports.map(serializeImport).toList(); | |
| 416 unlinkedUnit.parts = libraryElement.parts | |
| 417 .map((CompilationUnitElement e) => new UnlinkedPartBuilder( | |
| 418 uriOffset: e.uriOffset, | |
| 419 uriEnd: e.uriEnd, | |
| 420 annotations: serializeAnnotations(e))) | |
| 421 .toList(); | |
| 422 } else { | |
| 423 // TODO(paulberry): we need to figure out a way to record library, part, | |
| 424 // import, and export declarations that appear in non-defining | |
| 425 // compilation units (even though such declarations are prohibited by the | |
| 426 // language), so that if the user makes code changes that cause a | |
| 427 // non-defining compilation unit to become a defining compilation unit, | |
| 428 // we can create a correct summary by simply re-linking. | |
| 429 unlinkedUnit.publicNamespace = | |
| 430 new UnlinkedPublicNamespaceBuilder(names: names); | |
| 431 } | |
| 432 unlinkedUnit.codeRange = serializeCodeRange(compilationUnit); | |
| 433 unlinkedUnit.classes = compilationUnit.types.map(serializeClass).toList(); | |
| 434 unlinkedUnit.enums = compilationUnit.enums.map(serializeEnum).toList(); | |
| 435 unlinkedUnit.typedefs = | |
| 436 compilationUnit.functionTypeAliases.map(serializeTypedef).toList(); | |
| 437 List<UnlinkedExecutableBuilder> executables = | |
| 438 compilationUnit.functions.map(serializeExecutable).toList(); | |
| 439 for (PropertyAccessorElement accessor in compilationUnit.accessors) { | |
| 440 if (!accessor.isSynthetic) { | |
| 441 executables.add(serializeExecutable(accessor)); | |
| 442 } | |
| 443 } | |
| 444 unlinkedUnit.executables = executables; | |
| 445 List<UnlinkedVariableBuilder> variables = <UnlinkedVariableBuilder>[]; | |
| 446 for (PropertyAccessorElement accessor in compilationUnit.accessors) { | |
| 447 if (accessor.isSynthetic && accessor.isGetter) { | |
| 448 PropertyInducingElement variable = accessor.variable; | |
| 449 if (variable != null) { | |
| 450 assert(!variable.isSynthetic); | |
| 451 variables.add(serializeVariable(variable)); | |
| 452 } | |
| 453 } | |
| 454 } | |
| 455 unlinkedUnit.variables = variables; | |
| 456 unlinkedUnit.references = unlinkedReferences; | |
| 457 unlinkedUnit.lineStarts = | |
| 458 compilationUnit.context?.computeLineInfo(unitSource)?.lineStarts; | |
| 459 linkedUnit.references = linkedReferences; | |
| 460 unitUri = compilationUnit.source.uri.toString(); | |
| 461 } | |
| 462 | |
| 463 /** | |
| 464 * Create the [LinkedUnit.types] table based on deferred types that were | |
| 465 * found during [addCompilationUnitElements]. Also populate | |
| 466 * [LinkedUnit.constCycles]. | |
| 467 */ | |
| 468 void createLinkedInfo() { | |
| 469 buildingLinkedReferences = true; | |
| 470 linkedUnit.types = deferredLinkedTypes | |
| 471 .map((_SerializeTypeRef closure) => closure()) | |
| 472 .toList(); | |
| 473 linkedUnit.constCycles = constCycles; | |
| 474 buildingLinkedReferences = false; | |
| 475 } | |
| 476 | |
| 477 /** | |
| 478 * Compute the appropriate De Bruijn index to represent the given type | |
| 479 * parameter [type], or return `null` if the type parameter is not in scope. | |
| 480 */ | |
| 481 int findTypeParameterIndex(TypeParameterType type, Element context) { | |
| 482 int index = 0; | |
| 483 while (context != null) { | |
| 484 List<TypeParameterElement> typeParameters; | |
| 485 if (context is ClassElement) { | |
| 486 typeParameters = context.typeParameters; | |
| 487 } else if (context is FunctionTypeAliasElement) { | |
| 488 typeParameters = context.typeParameters; | |
| 489 } else if (context is ExecutableElement) { | |
| 490 typeParameters = context.typeParameters; | |
| 491 } | |
| 492 if (typeParameters != null) { | |
| 493 for (int i = 0; i < typeParameters.length; i++) { | |
| 494 TypeParameterElement param = typeParameters[i]; | |
| 495 if (param == type.element) { | |
| 496 return index + typeParameters.length - i; | |
| 497 } | |
| 498 } | |
| 499 index += typeParameters.length; | |
| 500 } | |
| 501 context = context.enclosingElement; | |
| 502 } | |
| 503 return null; | |
| 504 } | |
| 505 | |
| 506 /** | |
| 507 * Get the type arguments for the given [type], or `null` if the type has no | |
| 508 * type arguments. | |
| 509 * | |
| 510 * TODO(paulberry): consider adding an abstract getter to [DartType] to do | |
| 511 * this. | |
| 512 */ | |
| 513 List<DartType> getTypeArguments(DartType type) { | |
| 514 if (type is InterfaceType) { | |
| 515 return type.typeArguments; | |
| 516 } else if (type is FunctionType) { | |
| 517 return type.typeArguments; | |
| 518 } else { | |
| 519 return null; | |
| 520 } | |
| 521 } | |
| 522 | |
| 523 /** | |
| 524 * Serialize annotations from the given [element]. If [element] has no | |
| 525 * annotations, the empty list is returned. | |
| 526 */ | |
| 527 List<UnlinkedConstBuilder> serializeAnnotations(Element element) { | |
| 528 if (element.metadata.isEmpty) { | |
| 529 return const <UnlinkedConstBuilder>[]; | |
| 530 } | |
| 531 return element.metadata.map((ElementAnnotation a) { | |
| 532 _ConstExprSerializer serializer = | |
| 533 new _ConstExprSerializer(this, element, null, null); | |
| 534 serializer | |
| 535 .serializeAnnotation((a as ElementAnnotationImpl).annotationAst); | |
| 536 return serializer.toBuilder(); | |
| 537 }).toList(); | |
| 538 } | |
| 539 | |
| 540 /** | |
| 541 * Return the index of the entry in the references table | |
| 542 * ([LinkedLibrary.references]) used for the "bottom" type. A new entry is | |
| 543 * added to the table if necessary to satisfy the request. | |
| 544 */ | |
| 545 int serializeBottomReference() { | |
| 546 if (bottomReferenceIndex == null) { | |
| 547 // References to the "bottom" type are always implicit, since there is no | |
| 548 // way to explicitly refer to the "bottom" type. Therefore they should | |
| 549 // be stored only in the linked references table. | |
| 550 bottomReferenceIndex = linkedReferences.length; | |
| 551 linkedReferences.add(new LinkedReferenceBuilder( | |
| 552 name: '*bottom*', kind: ReferenceKind.classOrEnum)); | |
| 553 } | |
| 554 return bottomReferenceIndex; | |
| 555 } | |
| 556 | |
| 557 /** | |
| 558 * Serialize the given [classElement], creating an [UnlinkedClass]. | |
| 559 */ | |
| 560 UnlinkedClassBuilder serializeClass(ClassElement classElement) { | |
| 561 UnlinkedClassBuilder b = new UnlinkedClassBuilder(); | |
| 562 b.name = classElement.name; | |
| 563 b.nameOffset = classElement.nameOffset; | |
| 564 b.typeParameters = | |
| 565 classElement.typeParameters.map(serializeTypeParam).toList(); | |
| 566 if (classElement.supertype == null) { | |
| 567 b.hasNoSupertype = true; | |
| 568 } else if (!classElement.supertype.isObject) { | |
| 569 b.supertype = serializeTypeRef(classElement.supertype, classElement); | |
| 570 } | |
| 571 b.mixins = classElement.mixins | |
| 572 .map((InterfaceType t) => serializeTypeRef(t, classElement)) | |
| 573 .toList(); | |
| 574 b.interfaces = classElement.interfaces | |
| 575 .map((InterfaceType t) => serializeTypeRef(t, classElement)) | |
| 576 .toList(); | |
| 577 List<UnlinkedVariableBuilder> fields = <UnlinkedVariableBuilder>[]; | |
| 578 List<UnlinkedExecutableBuilder> executables = <UnlinkedExecutableBuilder>[]; | |
| 579 for (ConstructorElement executable in classElement.constructors) { | |
| 580 if (!executable.isSynthetic) { | |
| 581 executables.add(serializeExecutable(executable)); | |
| 582 } | |
| 583 } | |
| 584 for (MethodElement executable in classElement.methods) { | |
| 585 executables.add(serializeExecutable(executable)); | |
| 586 } | |
| 587 for (PropertyAccessorElement accessor in classElement.accessors) { | |
| 588 if (!accessor.isSynthetic) { | |
| 589 executables.add(serializeExecutable(accessor)); | |
| 590 } else if (accessor.isGetter) { | |
| 591 PropertyInducingElement field = accessor.variable; | |
| 592 if (field != null && !field.isSynthetic) { | |
| 593 fields.add(serializeVariable(field)); | |
| 594 } | |
| 595 } | |
| 596 } | |
| 597 b.fields = fields; | |
| 598 b.executables = executables; | |
| 599 b.isAbstract = classElement.isAbstract; | |
| 600 b.isMixinApplication = classElement.isMixinApplication; | |
| 601 b.documentationComment = serializeDocumentation(classElement); | |
| 602 b.annotations = serializeAnnotations(classElement); | |
| 603 b.codeRange = serializeCodeRange(classElement); | |
| 604 return b; | |
| 605 } | |
| 606 | |
| 607 /** | |
| 608 * If [cls] is a class, return the list of its static members - static | |
| 609 * constant fields, static methods and constructors. Otherwise return `null`. | |
| 610 */ | |
| 611 List<UnlinkedPublicNameBuilder> serializeClassStaticMembers( | |
| 612 ClassElement cls) { | |
| 613 if (cls.isMixinApplication) { | |
| 614 // Mixin application members can't be determined directly from the AST so | |
| 615 // we can't store them in UnlinkedPublicName. | |
| 616 // TODO(paulberry): find somewhere else to store them. | |
| 617 return null; | |
| 618 } | |
| 619 if (cls.kind == ElementKind.CLASS) { | |
| 620 List<UnlinkedPublicNameBuilder> bs = <UnlinkedPublicNameBuilder>[]; | |
| 621 for (MethodElement method in cls.methods) { | |
| 622 if (method.isStatic && method.isPublic) { | |
| 623 // TODO(paulberry): should numTypeParameters include class params? | |
| 624 bs.add(new UnlinkedPublicNameBuilder( | |
| 625 name: method.name, | |
| 626 kind: ReferenceKind.method, | |
| 627 numTypeParameters: method.typeParameters.length)); | |
| 628 } | |
| 629 } | |
| 630 for (PropertyAccessorElement accessor in cls.accessors) { | |
| 631 if (accessor.isStatic && accessor.isGetter && accessor.isPublic) { | |
| 632 // TODO(paulberry): should numTypeParameters include class params? | |
| 633 bs.add(new UnlinkedPublicNameBuilder( | |
| 634 name: accessor.name, kind: ReferenceKind.propertyAccessor)); | |
| 635 } | |
| 636 } | |
| 637 for (ConstructorElement constructor in cls.constructors) { | |
| 638 if (constructor.isPublic && constructor.name.isNotEmpty) { | |
| 639 // TODO(paulberry): should numTypeParameters include class params? | |
| 640 bs.add(new UnlinkedPublicNameBuilder( | |
| 641 name: constructor.name, | |
| 642 kind: ReferenceKind.constructor, | |
| 643 numTypeParameters: 0)); | |
| 644 } | |
| 645 } | |
| 646 return bs; | |
| 647 } | |
| 648 return null; | |
| 649 } | |
| 650 | |
| 651 CodeRangeBuilder serializeCodeRange(Element element) { | |
| 652 if (element is ElementImpl && element.codeOffset != null) { | |
| 653 return new CodeRangeBuilder( | |
| 654 offset: element.codeOffset, length: element.codeLength); | |
| 655 } | |
| 656 return null; | |
| 657 } | |
| 658 | |
| 659 /** | |
| 660 * Serialize the given [combinator] into an [UnlinkedCombinator]. | |
| 661 */ | |
| 662 UnlinkedCombinatorBuilder serializeCombinator( | |
| 663 NamespaceCombinator combinator) { | |
| 664 UnlinkedCombinatorBuilder b = new UnlinkedCombinatorBuilder(); | |
| 665 if (combinator is ShowElementCombinator) { | |
| 666 b.shows = combinator.shownNames; | |
| 667 b.offset = combinator.offset; | |
| 668 b.end = combinator.end; | |
| 669 } else if (combinator is HideElementCombinator) { | |
| 670 b.hides = combinator.hiddenNames; | |
| 671 } | |
| 672 return b; | |
| 673 } | |
| 674 | |
| 675 /** | |
| 676 * Serialize the given [expression], creating an [UnlinkedConstBuilder]. | |
| 677 */ | |
| 678 UnlinkedConstBuilder serializeConstExpr(Element context, | |
| 679 ExecutableElement executableContext, Expression expression, | |
| 680 [Set<String> constructorParameterNames]) { | |
| 681 _ConstExprSerializer serializer = new _ConstExprSerializer( | |
| 682 this, context, executableContext, constructorParameterNames); | |
| 683 serializer.serialize(expression); | |
| 684 return serializer.toBuilder(); | |
| 685 } | |
| 686 | |
| 687 /** | |
| 688 * Serialize documentation from the given [element], creating an | |
| 689 * [UnlinkedDocumentationComment]. | |
| 690 * | |
| 691 * If [element] has no documentation, `null` is returned. | |
| 692 */ | |
| 693 UnlinkedDocumentationCommentBuilder serializeDocumentation(Element element) { | |
| 694 if (element.documentationComment == null) { | |
| 695 return null; | |
| 696 } | |
| 697 return new UnlinkedDocumentationCommentBuilder( | |
| 698 text: element.documentationComment); | |
| 699 } | |
| 700 | |
| 701 /** | |
| 702 * Serialize the given [enumElement], creating an [UnlinkedEnum]. | |
| 703 */ | |
| 704 UnlinkedEnumBuilder serializeEnum(ClassElement enumElement) { | |
| 705 UnlinkedEnumBuilder b = new UnlinkedEnumBuilder(); | |
| 706 b.name = enumElement.name; | |
| 707 b.nameOffset = enumElement.nameOffset; | |
| 708 List<UnlinkedEnumValueBuilder> values = <UnlinkedEnumValueBuilder>[]; | |
| 709 for (FieldElement field in enumElement.fields) { | |
| 710 if (field.isConst && field.type.element == enumElement) { | |
| 711 values.add(new UnlinkedEnumValueBuilder( | |
| 712 name: field.name, | |
| 713 nameOffset: field.nameOffset, | |
| 714 documentationComment: serializeDocumentation(field))); | |
| 715 } | |
| 716 } | |
| 717 b.values = values; | |
| 718 b.documentationComment = serializeDocumentation(enumElement); | |
| 719 b.annotations = serializeAnnotations(enumElement); | |
| 720 b.codeRange = serializeCodeRange(enumElement); | |
| 721 return b; | |
| 722 } | |
| 723 | |
| 724 /** | |
| 725 * Serialize the given [executableElement], creating an [UnlinkedExecutable]. | |
| 726 */ | |
| 727 UnlinkedExecutableBuilder serializeExecutable( | |
| 728 ExecutableElement executableElement) { | |
| 729 UnlinkedExecutableBuilder b = new UnlinkedExecutableBuilder(); | |
| 730 b.name = executableElement.name; | |
| 731 b.nameOffset = executableElement.nameOffset; | |
| 732 if (executableElement is ConstructorElement) { | |
| 733 if (executableElement.name.isNotEmpty) { | |
| 734 b.nameEnd = executableElement.nameEnd; | |
| 735 b.periodOffset = executableElement.periodOffset; | |
| 736 } | |
| 737 } else { | |
| 738 if (!executableElement.hasImplicitReturnType) { | |
| 739 b.returnType = serializeTypeRef( | |
| 740 executableElement.type.returnType, executableElement); | |
| 741 } else if (!executableElement.isStatic) { | |
| 742 b.inferredReturnTypeSlot = | |
| 743 storeInferredType(executableElement.returnType, executableElement); | |
| 744 } | |
| 745 } | |
| 746 b.typeParameters = | |
| 747 executableElement.typeParameters.map(serializeTypeParam).toList(); | |
| 748 b.parameters = | |
| 749 executableElement.type.parameters.map(serializeParam).toList(); | |
| 750 if (executableElement is PropertyAccessorElement) { | |
| 751 if (executableElement.isGetter) { | |
| 752 b.kind = UnlinkedExecutableKind.getter; | |
| 753 } else { | |
| 754 b.kind = UnlinkedExecutableKind.setter; | |
| 755 } | |
| 756 } else if (executableElement is ConstructorElementImpl) { | |
| 757 b.kind = UnlinkedExecutableKind.constructor; | |
| 758 b.isConst = executableElement.isConst; | |
| 759 b.isFactory = executableElement.isFactory; | |
| 760 ConstructorElement redirectedConstructor = | |
| 761 executableElement.redirectedConstructor; | |
| 762 if (redirectedConstructor != null) { | |
| 763 b.isRedirectedConstructor = true; | |
| 764 if (executableElement.isFactory) { | |
| 765 InterfaceType returnType = redirectedConstructor is ConstructorMember | |
| 766 ? redirectedConstructor.definingType | |
| 767 : redirectedConstructor.enclosingElement.type; | |
| 768 EntityRefBuilder typeRef = | |
| 769 serializeTypeRef(returnType, executableElement); | |
| 770 if (redirectedConstructor.name.isNotEmpty) { | |
| 771 String name = redirectedConstructor.name; | |
| 772 int typeId = typeRef.reference; | |
| 773 LinkedReference typeLinkedRef = linkedReferences[typeId]; | |
| 774 int refId = serializeUnlinkedReference( | |
| 775 name, ReferenceKind.constructor, | |
| 776 unit: typeLinkedRef.unit, prefixReference: typeId); | |
| 777 b.redirectedConstructor = new EntityRefBuilder( | |
| 778 reference: refId, typeArguments: typeRef.typeArguments); | |
| 779 } else { | |
| 780 b.redirectedConstructor = typeRef; | |
| 781 } | |
| 782 } else { | |
| 783 b.redirectedConstructorName = redirectedConstructor.name; | |
| 784 } | |
| 785 } | |
| 786 if (executableElement.isConst) { | |
| 787 b.constCycleSlot = storeConstCycle(!executableElement.isCycleFree); | |
| 788 if (executableElement.constantInitializers != null) { | |
| 789 Set<String> constructorParameterNames = | |
| 790 executableElement.parameters.map((p) => p.name).toSet(); | |
| 791 b.constantInitializers = executableElement.constantInitializers | |
| 792 .map((ConstructorInitializer initializer) => | |
| 793 serializeConstructorInitializer( | |
| 794 initializer, | |
| 795 (expr) => serializeConstExpr(executableElement, | |
| 796 executableElement, expr, constructorParameterNames))) | |
| 797 .toList(); | |
| 798 } | |
| 799 } | |
| 800 } else { | |
| 801 b.kind = UnlinkedExecutableKind.functionOrMethod; | |
| 802 } | |
| 803 b.isAbstract = executableElement.isAbstract; | |
| 804 b.isAsynchronous = executableElement.isAsynchronous; | |
| 805 b.isGenerator = executableElement.isGenerator; | |
| 806 b.isStatic = executableElement.isStatic && | |
| 807 executableElement.enclosingElement is ClassElement; | |
| 808 b.isExternal = executableElement.isExternal; | |
| 809 b.documentationComment = serializeDocumentation(executableElement); | |
| 810 b.annotations = serializeAnnotations(executableElement); | |
| 811 b.codeRange = serializeCodeRange(executableElement); | |
| 812 if (executableElement is FunctionElement) { | |
| 813 SourceRange visibleRange = executableElement.visibleRange; | |
| 814 if (visibleRange != null) { | |
| 815 b.visibleOffset = visibleRange.offset; | |
| 816 b.visibleLength = visibleRange.length; | |
| 817 } | |
| 818 } | |
| 819 b.localFunctions = | |
| 820 executableElement.functions.map(serializeExecutable).toList(); | |
| 821 b.localLabels = executableElement.labels.map(serializeLabel).toList(); | |
| 822 b.localVariables = | |
| 823 executableElement.localVariables.map(serializeVariable).toList(); | |
| 824 return b; | |
| 825 } | |
| 826 | |
| 827 /** | |
| 828 * Serialize the given [exportElement] into an [UnlinkedExportNonPublic]. | |
| 829 */ | |
| 830 UnlinkedExportNonPublicBuilder serializeExportNonPublic( | |
| 831 ExportElement exportElement) { | |
| 832 UnlinkedExportNonPublicBuilder b = new UnlinkedExportNonPublicBuilder(); | |
| 833 b.offset = exportElement.nameOffset; | |
| 834 b.uriOffset = exportElement.uriOffset; | |
| 835 b.uriEnd = exportElement.uriEnd; | |
| 836 b.annotations = serializeAnnotations(exportElement); | |
| 837 return b; | |
| 838 } | |
| 839 | |
| 840 /** | |
| 841 * Serialize the given [exportElement] into an [UnlinkedExportPublic]. | |
| 842 */ | |
| 843 UnlinkedExportPublicBuilder serializeExportPublic( | |
| 844 ExportElement exportElement) { | |
| 845 UnlinkedExportPublicBuilder b = new UnlinkedExportPublicBuilder(); | |
| 846 b.uri = exportElement.uri; | |
| 847 b.combinators = exportElement.combinators.map(serializeCombinator).toList(); | |
| 848 return b; | |
| 849 } | |
| 850 | |
| 851 /** | |
| 852 * Serialize the given [importElement] yielding an [UnlinkedImportBuilder]. | |
| 853 * Also, add linked information about it to the [linkedImports] list. | |
| 854 */ | |
| 855 UnlinkedImportBuilder serializeImport(ImportElement importElement) { | |
| 856 UnlinkedImportBuilder b = new UnlinkedImportBuilder(); | |
| 857 b.annotations = serializeAnnotations(importElement); | |
| 858 b.isDeferred = importElement.isDeferred; | |
| 859 b.combinators = importElement.combinators.map(serializeCombinator).toList(); | |
| 860 if (importElement.prefix != null) { | |
| 861 b.prefixReference = serializePrefix(importElement.prefix); | |
| 862 b.prefixOffset = importElement.prefix.nameOffset; | |
| 863 } | |
| 864 if (importElement.isSynthetic) { | |
| 865 b.isImplicit = true; | |
| 866 } else { | |
| 867 b.offset = importElement.nameOffset; | |
| 868 b.uri = importElement.uri; | |
| 869 b.uriOffset = importElement.uriOffset; | |
| 870 b.uriEnd = importElement.uriEnd; | |
| 871 } | |
| 872 return b; | |
| 873 } | |
| 874 | |
| 875 /** | |
| 876 * Serialize the given [label], creating an [UnlinkedLabelBuilder]. | |
| 877 */ | |
| 878 UnlinkedLabelBuilder serializeLabel(LabelElement label) { | |
| 879 LabelElementImpl labelImpl = label as LabelElementImpl; | |
| 880 UnlinkedLabelBuilder b = new UnlinkedLabelBuilder(); | |
| 881 b.name = labelImpl.name; | |
| 882 b.nameOffset = labelImpl.nameOffset; | |
| 883 b.isOnSwitchMember = labelImpl.isOnSwitchMember; | |
| 884 b.isOnSwitchStatement = labelImpl.isOnSwitchStatement; | |
| 885 return b; | |
| 886 } | |
| 887 | |
| 888 /** | |
| 889 * Serialize the given [parameter] into an [UnlinkedParam]. | |
| 890 */ | |
| 891 UnlinkedParamBuilder serializeParam(ParameterElement parameter, | |
| 892 [Element context]) { | |
| 893 context ??= parameter; | |
| 894 UnlinkedParamBuilder b = new UnlinkedParamBuilder(); | |
| 895 b.name = parameter.name; | |
| 896 b.nameOffset = parameter.nameOffset >= 0 ? parameter.nameOffset : 0; | |
| 897 switch (parameter.parameterKind) { | |
| 898 case ParameterKind.REQUIRED: | |
| 899 b.kind = UnlinkedParamKind.required; | |
| 900 break; | |
| 901 case ParameterKind.POSITIONAL: | |
| 902 b.kind = UnlinkedParamKind.positional; | |
| 903 break; | |
| 904 case ParameterKind.NAMED: | |
| 905 b.kind = UnlinkedParamKind.named; | |
| 906 break; | |
| 907 } | |
| 908 b.annotations = serializeAnnotations(parameter); | |
| 909 b.codeRange = serializeCodeRange(parameter); | |
| 910 b.isInitializingFormal = parameter.isInitializingFormal; | |
| 911 DartType type = parameter.type; | |
| 912 if (parameter.hasImplicitType) { | |
| 913 Element contextParent = context.enclosingElement; | |
| 914 if (!parameter.isInitializingFormal && | |
| 915 contextParent is ExecutableElement && | |
| 916 !contextParent.isStatic && | |
| 917 contextParent is! ConstructorElement) { | |
| 918 b.inferredTypeSlot = storeInferredType(type, context); | |
| 919 } | |
| 920 } else { | |
| 921 if (type is FunctionType && type.element.isSynthetic) { | |
| 922 b.isFunctionTyped = true; | |
| 923 b.type = serializeTypeRef(type.returnType, parameter); | |
| 924 b.parameters = type.parameters | |
| 925 .map((parameter) => serializeParam(parameter, context)) | |
| 926 .toList(); | |
| 927 } else { | |
| 928 b.type = serializeTypeRef(type, context); | |
| 929 } | |
| 930 } | |
| 931 // TODO(scheglov) VariableMember.initializer is not implemented | |
| 932 if (parameter is! VariableMember && parameter.initializer != null) { | |
| 933 b.initializer = serializeExecutable(parameter.initializer); | |
| 934 } | |
| 935 if (parameter is ConstVariableElement) { | |
| 936 ConstVariableElement constParameter = parameter as ConstVariableElement; | |
| 937 Expression initializer = constParameter.constantInitializer; | |
| 938 if (initializer != null) { | |
| 939 b.initializer?.bodyExpr = serializeConstExpr( | |
| 940 parameter, | |
| 941 parameter.getAncestor((Element e) => e is ExecutableElement), | |
| 942 initializer); | |
| 943 b.defaultValueCode = parameter.defaultValueCode; | |
| 944 } | |
| 945 } | |
| 946 { | |
| 947 SourceRange visibleRange = parameter.visibleRange; | |
| 948 if (visibleRange != null) { | |
| 949 b.visibleOffset = visibleRange.offset; | |
| 950 b.visibleLength = visibleRange.length; | |
| 951 } | |
| 952 } | |
| 953 return b; | |
| 954 } | |
| 955 | |
| 956 /** | |
| 957 * Serialize the given [prefix] into an index into the references table. | |
| 958 */ | |
| 959 int serializePrefix(PrefixElement element) { | |
| 960 return referenceMap.putIfAbsent(element, | |
| 961 () => serializeUnlinkedReference(element.name, ReferenceKind.prefix)); | |
| 962 } | |
| 963 | |
| 964 /** | |
| 965 * Compute the reference index which should be stored in a [EntityRef]. | |
| 966 */ | |
| 967 int serializeReferenceForType(DartType type) { | |
| 968 Element element = type.element; | |
| 969 LibraryElement dependentLibrary = element?.library; | |
| 970 if (dependentLibrary == null) { | |
| 971 if (type.isBottom) { | |
| 972 // References to the "bottom" type are always implicit, since there is | |
| 973 // no way to explicitly refer to the "bottom" type. Therefore they | |
| 974 // should always be linked. | |
| 975 assert(buildingLinkedReferences); | |
| 976 return serializeBottomReference(); | |
| 977 } | |
| 978 assert(type.isDynamic || type.isVoid); | |
| 979 if (type is UndefinedTypeImpl) { | |
| 980 return serializeUnresolvedReference(); | |
| 981 } | |
| 982 // Note: for a type which is truly `dynamic` or `void`, fall through to | |
| 983 // use [_getElementReferenceId]. | |
| 984 } | |
| 985 return _getElementReferenceId(element); | |
| 986 } | |
| 987 | |
| 988 /** | |
| 989 * Serialize the given [typedefElement], creating an [UnlinkedTypedef]. | |
| 990 */ | |
| 991 UnlinkedTypedefBuilder serializeTypedef( | |
| 992 FunctionTypeAliasElement typedefElement) { | |
| 993 UnlinkedTypedefBuilder b = new UnlinkedTypedefBuilder(); | |
| 994 b.name = typedefElement.name; | |
| 995 b.nameOffset = typedefElement.nameOffset; | |
| 996 b.typeParameters = | |
| 997 typedefElement.typeParameters.map(serializeTypeParam).toList(); | |
| 998 b.returnType = serializeTypeRef(typedefElement.returnType, typedefElement); | |
| 999 b.parameters = typedefElement.parameters.map(serializeParam).toList(); | |
| 1000 b.documentationComment = serializeDocumentation(typedefElement); | |
| 1001 b.annotations = serializeAnnotations(typedefElement); | |
| 1002 b.codeRange = serializeCodeRange(typedefElement); | |
| 1003 return b; | |
| 1004 } | |
| 1005 | |
| 1006 /** | |
| 1007 * Serialize the given [typeParameter] into an [UnlinkedTypeParam]. | |
| 1008 */ | |
| 1009 UnlinkedTypeParamBuilder serializeTypeParam( | |
| 1010 TypeParameterElement typeParameter) { | |
| 1011 UnlinkedTypeParamBuilder b = new UnlinkedTypeParamBuilder(); | |
| 1012 b.name = typeParameter.name; | |
| 1013 b.nameOffset = typeParameter.nameOffset; | |
| 1014 if (typeParameter.bound != null) { | |
| 1015 b.bound = serializeTypeRef(typeParameter.bound, typeParameter); | |
| 1016 } | |
| 1017 b.annotations = serializeAnnotations(typeParameter); | |
| 1018 b.codeRange = serializeCodeRange(typeParameter); | |
| 1019 return b; | |
| 1020 } | |
| 1021 | |
| 1022 /** | |
| 1023 * Serialize the given [type] into a [EntityRef]. If [slot] is provided, | |
| 1024 * it should be included in the [EntityRef]. | |
| 1025 * | |
| 1026 * [context] is the element within which the [EntityRef] will be | |
| 1027 * interpreted; this is used to serialize type parameters. | |
| 1028 */ | |
| 1029 EntityRefBuilder serializeTypeRef(DartType type, Element context, | |
| 1030 {int slot}) { | |
| 1031 if (slot != null) { | |
| 1032 assert(buildingLinkedReferences); | |
| 1033 } | |
| 1034 EntityRefBuilder b = new EntityRefBuilder(slot: slot); | |
| 1035 Element typeElement = type.element; | |
| 1036 if (type is TypeParameterType) { | |
| 1037 int typeParameterIndex = findTypeParameterIndex(type, context); | |
| 1038 if (typeParameterIndex != null) { | |
| 1039 b.paramReference = typeParameterIndex; | |
| 1040 } else { | |
| 1041 // Out-of-scope type parameters only occur in circumstances where they | |
| 1042 // are irrelevant (i.e. when a type parameter is unused). So we can | |
| 1043 // safely convert them to `dynamic`. | |
| 1044 b.reference = serializeReferenceForType(DynamicTypeImpl.instance); | |
| 1045 } | |
| 1046 } else if (type is FunctionType && | |
| 1047 typeElement is FunctionElement && | |
| 1048 typeElement.enclosingElement == null) { | |
| 1049 b.syntheticReturnType = | |
| 1050 serializeTypeRef(typeElement.returnType, typeElement); | |
| 1051 b.syntheticParams = typeElement.parameters | |
| 1052 .map((ParameterElement param) => serializeParam(param, context)) | |
| 1053 .toList(); | |
| 1054 } else { | |
| 1055 if (type is FunctionType && | |
| 1056 typeElement.enclosingElement is ParameterElement) { | |
| 1057 // Code cannot refer to function types implicitly defined by parameters | |
| 1058 // directly, so if we get here, we must be serializing a linked | |
| 1059 // reference from type inference. | |
| 1060 assert(buildingLinkedReferences); | |
| 1061 ParameterElement parameterElement = typeElement.enclosingElement; | |
| 1062 while (true) { | |
| 1063 Element parent = parameterElement.enclosingElement; | |
| 1064 if (parent is ParameterElement) { | |
| 1065 // Function-typed parameter inside a function-typed parameter. | |
| 1066 b.implicitFunctionTypeIndices | |
| 1067 .insert(0, parent.parameters.indexOf(parameterElement)); | |
| 1068 parameterElement = parent; | |
| 1069 continue; | |
| 1070 } else if (parent is FunctionTypedElement) { | |
| 1071 b.implicitFunctionTypeIndices | |
| 1072 .insert(0, parent.parameters.indexOf(parameterElement)); | |
| 1073 // Function-typed parameter inside a top level function, method, or | |
| 1074 // typedef. | |
| 1075 b.reference = _getElementReferenceId(parent); | |
| 1076 break; | |
| 1077 } else { | |
| 1078 throw new StateError( | |
| 1079 'Unexpected element enclosing parameter: ${parent.runtimeType}')
; | |
| 1080 } | |
| 1081 } | |
| 1082 } else { | |
| 1083 b.reference = serializeReferenceForType(type); | |
| 1084 } | |
| 1085 List<DartType> typeArguments = getTypeArguments(type); | |
| 1086 if (typeArguments != null) { | |
| 1087 b.typeArguments = typeArguments | |
| 1088 .map((typeArgument) => serializeTypeRef(typeArgument, context)) | |
| 1089 .toList(); | |
| 1090 } | |
| 1091 } | |
| 1092 return b; | |
| 1093 } | |
| 1094 | |
| 1095 /** | |
| 1096 * Create a new entry in the references table ([UnlinkedUnit.references] | |
| 1097 * and [LinkedUnit.references]) representing an entity having the given | |
| 1098 * [name] and [kind]. If [unit] is given, it is the index of the compilation | |
| 1099 * unit containing the entity being referred to. If [prefixReference] is | |
| 1100 * given, it indicates the entry in the references table for the prefix. | |
| 1101 */ | |
| 1102 int serializeUnlinkedReference(String name, ReferenceKind kind, | |
| 1103 {int unit: 0, int prefixReference: 0}) { | |
| 1104 assert(unlinkedReferences.length == linkedReferences.length); | |
| 1105 int index = unlinkedReferences.length; | |
| 1106 unlinkedReferences.add(new UnlinkedReferenceBuilder( | |
| 1107 name: name, prefixReference: prefixReference)); | |
| 1108 linkedReferences.add(new LinkedReferenceBuilder(kind: kind, unit: unit)); | |
| 1109 return index; | |
| 1110 } | |
| 1111 | |
| 1112 /** | |
| 1113 * Return the index of the entry in the references table | |
| 1114 * ([UnlinkedLibrary.references] and [LinkedLibrary.references]) used for | |
| 1115 * unresolved references. A new entry is added to the table if necessary to | |
| 1116 * satisfy the request. | |
| 1117 */ | |
| 1118 int serializeUnresolvedReference() { | |
| 1119 // TODO(paulberry): in order for relinking to work, we need to record the | |
| 1120 // name and prefix of the unresolved symbol. This is not (yet) encoded in | |
| 1121 // the element model. For the moment we use a name that can't possibly | |
| 1122 // ever exist. | |
| 1123 if (unresolvedReferenceIndex == null) { | |
| 1124 unresolvedReferenceIndex = | |
| 1125 serializeUnlinkedReference('*unresolved*', ReferenceKind.unresolved); | |
| 1126 } | |
| 1127 return unresolvedReferenceIndex; | |
| 1128 } | |
| 1129 | |
| 1130 /** | |
| 1131 * Serialize the given [variable], creating an [UnlinkedVariable]. | |
| 1132 */ | |
| 1133 UnlinkedVariableBuilder serializeVariable(VariableElement variable) { | |
| 1134 UnlinkedVariableBuilder b = new UnlinkedVariableBuilder(); | |
| 1135 b.name = variable.name; | |
| 1136 b.nameOffset = variable.nameOffset; | |
| 1137 if (!variable.hasImplicitType) { | |
| 1138 b.type = serializeTypeRef(variable.type, variable); | |
| 1139 } | |
| 1140 b.isStatic = variable.isStatic && variable.enclosingElement is ClassElement; | |
| 1141 b.isFinal = variable.isFinal; | |
| 1142 b.isConst = variable.isConst; | |
| 1143 b.documentationComment = serializeDocumentation(variable); | |
| 1144 b.annotations = serializeAnnotations(variable); | |
| 1145 // TODO(scheglov) VariableMember.initializer is not implemented | |
| 1146 if (variable is! VariableMember && variable.initializer != null) { | |
| 1147 b.initializer = serializeExecutable(variable.initializer); | |
| 1148 } | |
| 1149 if (variable is ConstVariableElement) { | |
| 1150 ConstVariableElement constVariable = variable as ConstVariableElement; | |
| 1151 Expression initializer = constVariable.constantInitializer; | |
| 1152 if (initializer != null) { | |
| 1153 b.initializer?.bodyExpr = | |
| 1154 serializeConstExpr(variable, variable.initializer, initializer); | |
| 1155 } | |
| 1156 } | |
| 1157 if (variable is PropertyInducingElement) { | |
| 1158 if (b.isFinal || b.isConst) { | |
| 1159 b.propagatedTypeSlot = | |
| 1160 storeLinkedType(variable.propagatedType, variable); | |
| 1161 } else { | |
| 1162 // Variable is not propagable. | |
| 1163 assert(variable.propagatedType == null); | |
| 1164 } | |
| 1165 } | |
| 1166 if (variable.hasImplicitType && | |
| 1167 (variable.initializer != null || !variable.isStatic)) { | |
| 1168 b.inferredTypeSlot = storeInferredType(variable.type, variable); | |
| 1169 } | |
| 1170 b.codeRange = serializeCodeRange(variable); | |
| 1171 if (variable is LocalVariableElement) { | |
| 1172 SourceRange visibleRange = variable.visibleRange; | |
| 1173 if (visibleRange != null) { | |
| 1174 b.visibleOffset = visibleRange.offset; | |
| 1175 b.visibleLength = visibleRange.length; | |
| 1176 } | |
| 1177 } | |
| 1178 return b; | |
| 1179 } | |
| 1180 | |
| 1181 /** | |
| 1182 * Create a new slot id and return it. If [hasCycle] is `true`, arrange for | |
| 1183 * the slot id to be included in [LinkedUnit.constCycles]. | |
| 1184 */ | |
| 1185 int storeConstCycle(bool hasCycle) { | |
| 1186 int slot = ++numSlots; | |
| 1187 if (hasCycle) { | |
| 1188 constCycles.add(slot); | |
| 1189 } | |
| 1190 return slot; | |
| 1191 } | |
| 1192 | |
| 1193 /** | |
| 1194 * Create a slot id for the given [type] (which is an inferred type). If | |
| 1195 * [type] is not `dynamic`, it is stored in [linkedTypes] so that once the | |
| 1196 * compilation unit has been fully visited, it will be serialized into | |
| 1197 * [LinkedUnit.types]. | |
| 1198 * | |
| 1199 * [context] is the element within which the slot id will appear; this is | |
| 1200 * used to serialize type parameters. | |
| 1201 */ | |
| 1202 int storeInferredType(DartType type, Element context) { | |
| 1203 return storeLinkedType(type.isDynamic ? null : type, context); | |
| 1204 } | |
| 1205 | |
| 1206 /** | |
| 1207 * Create a slot id for the given [type] (which may be either a propagated | |
| 1208 * type or an inferred type). If [type] is not `null`, it is stored in | |
| 1209 * [linkedTypes] so that once the compilation unit has been fully visited, | |
| 1210 * it will be serialized to [LinkedUnit.types]. | |
| 1211 * | |
| 1212 * [context] is the element within which the slot id will appear; this is | |
| 1213 * used to serialize type parameters. | |
| 1214 */ | |
| 1215 int storeLinkedType(DartType type, Element context) { | |
| 1216 int slot = ++numSlots; | |
| 1217 if (type != null) { | |
| 1218 deferredLinkedTypes | |
| 1219 .add(() => serializeTypeRef(type, context, slot: slot)); | |
| 1220 } | |
| 1221 return slot; | |
| 1222 } | |
| 1223 | |
| 1224 int _getElementReferenceId(Element element) { | |
| 1225 return referenceMap.putIfAbsent(element, () { | |
| 1226 LibraryElement dependentLibrary = librarySerializer.libraryElement; | |
| 1227 int unit = 0; | |
| 1228 Element enclosingElement; | |
| 1229 if (element != null) { | |
| 1230 enclosingElement = element.enclosingElement; | |
| 1231 if (enclosingElement is CompilationUnitElement) { | |
| 1232 dependentLibrary = enclosingElement.library; | |
| 1233 unit = dependentLibrary.units.indexOf(enclosingElement); | |
| 1234 assert(unit != -1); | |
| 1235 } | |
| 1236 } | |
| 1237 ReferenceKind kind = _getReferenceKind(element); | |
| 1238 String name = element == null ? 'void' : element.name; | |
| 1239 int index; | |
| 1240 LinkedReferenceBuilder linkedReference; | |
| 1241 if (buildingLinkedReferences) { | |
| 1242 linkedReference = | |
| 1243 new LinkedReferenceBuilder(kind: kind, unit: unit, name: name); | |
| 1244 if (enclosingElement != null && | |
| 1245 enclosingElement is! CompilationUnitElement) { | |
| 1246 linkedReference.containingReference = | |
| 1247 _getElementReferenceId(enclosingElement); | |
| 1248 if (enclosingElement is ClassElement) { | |
| 1249 // Nothing to do. | |
| 1250 } else if (enclosingElement is ExecutableElement) { | |
| 1251 if (element is FunctionElement) { | |
| 1252 assert(enclosingElement.functions.contains(element)); | |
| 1253 linkedReference.localIndex = | |
| 1254 enclosingElement.functions.indexOf(element); | |
| 1255 } else if (element is LocalVariableElement) { | |
| 1256 assert(enclosingElement.localVariables.contains(element)); | |
| 1257 linkedReference.localIndex = | |
| 1258 enclosingElement.localVariables.indexOf(element); | |
| 1259 } else { | |
| 1260 throw new StateError( | |
| 1261 'Unexpected enclosed element type: ${element.runtimeType}'); | |
| 1262 } | |
| 1263 } else if (enclosingElement is VariableElement) { | |
| 1264 assert(identical(enclosingElement.initializer, element)); | |
| 1265 } else { | |
| 1266 throw new StateError( | |
| 1267 'Unexpected enclosing element type: ${enclosingElement.runtimeTy
pe}'); | |
| 1268 } | |
| 1269 } | |
| 1270 index = linkedReferences.length; | |
| 1271 linkedReferences.add(linkedReference); | |
| 1272 } else { | |
| 1273 assert(unlinkedReferences.length == linkedReferences.length); | |
| 1274 int prefixReference = 0; | |
| 1275 Element enclosing = element?.enclosingElement; | |
| 1276 if (enclosing == null || enclosing is CompilationUnitElement) { | |
| 1277 // Figure out a prefix that may be used to refer to the given element. | |
| 1278 // TODO(paulberry): to avoid subtle relinking inconsistencies we | |
| 1279 // should use the actual prefix from the AST (a given type may be | |
| 1280 // reachable via multiple prefixes), but sadly, this information is | |
| 1281 // not recorded in the element model. | |
| 1282 PrefixElement prefix = librarySerializer.prefixMap[element]; | |
| 1283 if (prefix != null) { | |
| 1284 prefixReference = serializePrefix(prefix); | |
| 1285 } | |
| 1286 } else { | |
| 1287 prefixReference = _getElementReferenceId(enclosing); | |
| 1288 } | |
| 1289 index = serializeUnlinkedReference(name, kind, | |
| 1290 prefixReference: prefixReference, unit: unit); | |
| 1291 linkedReference = linkedReferences[index]; | |
| 1292 } | |
| 1293 linkedReference.dependency = | |
| 1294 librarySerializer.serializeDependency(dependentLibrary); | |
| 1295 if (element is TypeParameterizedElement) { | |
| 1296 linkedReference.numTypeParameters += element.typeParameters.length; | |
| 1297 } | |
| 1298 return index; | |
| 1299 }); | |
| 1300 } | |
| 1301 } | |
| 1302 | |
| 1303 /** | |
| 1304 * Instances of this class keep track of intermediate state during | |
| 1305 * serialization of a single constant [Expression]. | |
| 1306 */ | |
| 1307 class _ConstExprSerializer extends AbstractConstExprSerializer { | |
| 1308 final _CompilationUnitSerializer serializer; | |
| 1309 final Element context; | |
| 1310 final ExecutableElement executableContext; | |
| 1311 | |
| 1312 /** | |
| 1313 * If a constructor initializer expression is being serialized, the names of | |
| 1314 * the constructor parameters. Otherwise `null`. | |
| 1315 */ | |
| 1316 final Set<String> constructorParameterNames; | |
| 1317 | |
| 1318 _ConstExprSerializer(this.serializer, this.context, this.executableContext, | |
| 1319 this.constructorParameterNames); | |
| 1320 | |
| 1321 @override | |
| 1322 bool isParameterName(String name) { | |
| 1323 return constructorParameterNames?.contains(name) ?? false; | |
| 1324 } | |
| 1325 | |
| 1326 @override | |
| 1327 void serializeAnnotation(Annotation annotation) { | |
| 1328 if (annotation.arguments == null) { | |
| 1329 assert(annotation.constructorName == null); | |
| 1330 serialize(annotation.name); | |
| 1331 } else { | |
| 1332 Identifier name = annotation.name; | |
| 1333 Element nameElement = name.staticElement; | |
| 1334 EntityRefBuilder constructor; | |
| 1335 if (nameElement is ConstructorElement && name is PrefixedIdentifier) { | |
| 1336 assert(annotation.constructorName == null); | |
| 1337 constructor = serializeConstructorRef( | |
| 1338 nameElement.returnType, name.prefix, null, name.identifier); | |
| 1339 } else if (nameElement is TypeDefiningElement) { | |
| 1340 constructor = serializeConstructorRef(nameElement.type, annotation.name, | |
| 1341 null, annotation.constructorName); | |
| 1342 } else if (nameElement == null) { | |
| 1343 // Unresolved annotation. | |
| 1344 if (name is PrefixedIdentifier && annotation.constructorName == null) { | |
| 1345 constructor = | |
| 1346 serializeConstructorRef(null, name.prefix, null, name.identifier); | |
| 1347 } else { | |
| 1348 constructor = serializeConstructorRef( | |
| 1349 null, annotation.name, null, annotation.constructorName); | |
| 1350 } | |
| 1351 } else { | |
| 1352 throw new StateError('Unexpected annotation nameElement type:' | |
| 1353 ' ${nameElement.runtimeType}'); | |
| 1354 } | |
| 1355 serializeInstanceCreation(constructor, annotation.arguments); | |
| 1356 } | |
| 1357 } | |
| 1358 | |
| 1359 @override | |
| 1360 EntityRefBuilder serializeConstructorRef(DartType type, Identifier typeName, | |
| 1361 TypeArgumentList typeArguments, SimpleIdentifier name) { | |
| 1362 EntityRefBuilder typeRef = serializeType(type, typeName, typeArguments); | |
| 1363 if (name == null) { | |
| 1364 return typeRef; | |
| 1365 } else { | |
| 1366 LinkedReference typeLinkedRef = | |
| 1367 serializer.linkedReferences[typeRef.reference]; | |
| 1368 int refId = serializer.serializeUnlinkedReference( | |
| 1369 name.name, | |
| 1370 name.staticElement != null | |
| 1371 ? ReferenceKind.constructor | |
| 1372 : ReferenceKind.unresolved, | |
| 1373 prefixReference: typeRef.reference, | |
| 1374 unit: typeLinkedRef.unit); | |
| 1375 return new EntityRefBuilder( | |
| 1376 reference: refId, typeArguments: typeRef.typeArguments); | |
| 1377 } | |
| 1378 } | |
| 1379 | |
| 1380 @override | |
| 1381 List<int> serializeFunctionExpression(FunctionExpression functionExpression) { | |
| 1382 if (executableContext == null) { | |
| 1383 return null; | |
| 1384 } | |
| 1385 ExecutableElement functionElement = functionExpression.element; | |
| 1386 // TOOD(paulberry): handle the situation where [functionExpression] is not | |
| 1387 // an immediate child of [executableContext]. | |
| 1388 assert(functionElement.enclosingElement == executableContext); | |
| 1389 int popCount = 0; | |
| 1390 int localIndex = executableContext.functions.indexOf(functionElement); | |
| 1391 assert(localIndex != -1); | |
| 1392 return <int>[popCount, localIndex]; | |
| 1393 } | |
| 1394 | |
| 1395 EntityRefBuilder serializeIdentifier(Identifier identifier, | |
| 1396 {int prefixReference: 0}) { | |
| 1397 if (identifier is SimpleIdentifier) { | |
| 1398 Element element = identifier.staticElement; | |
| 1399 if (element is TypeParameterElement) { | |
| 1400 int typeParameterIndex = | |
| 1401 serializer.findTypeParameterIndex(element.type, context); | |
| 1402 return new EntityRefBuilder(paramReference: typeParameterIndex); | |
| 1403 } else if (_isPrelinkResolvableElement(element)) { | |
| 1404 int ref = serializer._getElementReferenceId(element); | |
| 1405 return new EntityRefBuilder(reference: ref); | |
| 1406 } else { | |
| 1407 int ref = serializer.serializeUnlinkedReference( | |
| 1408 identifier.name, ReferenceKind.unresolved); | |
| 1409 return new EntityRefBuilder(reference: ref); | |
| 1410 } | |
| 1411 } else if (identifier is PrefixedIdentifier) { | |
| 1412 Element element = identifier.staticElement; | |
| 1413 if (_isPrelinkResolvableElement(element)) { | |
| 1414 int ref = serializer._getElementReferenceId(element); | |
| 1415 return new EntityRefBuilder(reference: ref); | |
| 1416 } else { | |
| 1417 int prefixRef = serializeIdentifier(identifier.prefix).reference; | |
| 1418 int ref = serializer.serializeUnlinkedReference( | |
| 1419 identifier.identifier.name, ReferenceKind.unresolved, | |
| 1420 prefixReference: prefixRef); | |
| 1421 return new EntityRefBuilder(reference: ref); | |
| 1422 } | |
| 1423 } else { | |
| 1424 throw new StateError( | |
| 1425 'Unexpected identifier type: ${identifier.runtimeType}'); | |
| 1426 } | |
| 1427 } | |
| 1428 | |
| 1429 @override | |
| 1430 EntityRefBuilder serializeIdentifierSequence(Expression expr) { | |
| 1431 if (expr is Identifier) { | |
| 1432 return serializeIdentifier(expr); | |
| 1433 } | |
| 1434 if (expr is PropertyAccess) { | |
| 1435 Element element = expr.propertyName.staticElement; | |
| 1436 if (_isPrelinkResolvableElement(element)) { | |
| 1437 int ref = serializer._getElementReferenceId(element); | |
| 1438 return new EntityRefBuilder(reference: ref); | |
| 1439 } else { | |
| 1440 int targetRef = serializeIdentifierSequence(expr.target).reference; | |
| 1441 int ref = serializer.serializeUnlinkedReference( | |
| 1442 expr.propertyName.name, ReferenceKind.unresolved, | |
| 1443 prefixReference: targetRef); | |
| 1444 return new EntityRefBuilder(reference: ref); | |
| 1445 } | |
| 1446 } else { | |
| 1447 throw new StateError('Unexpected node type: ${expr.runtimeType}'); | |
| 1448 } | |
| 1449 } | |
| 1450 | |
| 1451 @override | |
| 1452 EntityRefBuilder serializeType( | |
| 1453 DartType type, Identifier name, TypeArgumentList arguments) { | |
| 1454 if (name != null) { | |
| 1455 if (type == null || type.isUndefined) { | |
| 1456 return serializeIdentifier(name); | |
| 1457 } | |
| 1458 } | |
| 1459 DartType typeOrDynamic = type ?? DynamicTypeImpl.instance; | |
| 1460 return serializer.serializeTypeRef(typeOrDynamic, context); | |
| 1461 } | |
| 1462 | |
| 1463 /** | |
| 1464 * Return `true` if the given [element] can be resolved at prelink step. | |
| 1465 */ | |
| 1466 static bool _isPrelinkResolvableElement(Element element) { | |
| 1467 if (element == null) { | |
| 1468 return false; | |
| 1469 } | |
| 1470 if (element == DynamicTypeImpl.instance.element) { | |
| 1471 return true; | |
| 1472 } | |
| 1473 if (element is PrefixElement) { | |
| 1474 return true; | |
| 1475 } | |
| 1476 Element enclosingElement = element.enclosingElement; | |
| 1477 if (enclosingElement is CompilationUnitElement) { | |
| 1478 return true; | |
| 1479 } | |
| 1480 if (enclosingElement is ClassElement) { | |
| 1481 return element is ConstructorElement || | |
| 1482 element is ClassMemberElement && element.isStatic || | |
| 1483 element is PropertyAccessorElement && element.isStatic; | |
| 1484 } | |
| 1485 return false; | |
| 1486 } | |
| 1487 } | |
| 1488 | |
| 1489 /** | |
| 1490 * Instances of this class keep track of intermediate state during | |
| 1491 * serialization of a single library. | |
| 1492 */ | |
| 1493 class _LibrarySerializer { | |
| 1494 /** | |
| 1495 * The library to be serialized. | |
| 1496 */ | |
| 1497 final LibraryElement libraryElement; | |
| 1498 | |
| 1499 /** | |
| 1500 * The type provider. This is used to locate the library for `dart:core`. | |
| 1501 */ | |
| 1502 final TypeProvider typeProvider; | |
| 1503 | |
| 1504 /** | |
| 1505 * Indicates whether the element model being serialized was analyzed using | |
| 1506 * strong mode. | |
| 1507 */ | |
| 1508 final bool strongMode; | |
| 1509 | |
| 1510 /** | |
| 1511 * Map from [LibraryElement] to the index of the entry in the "dependency | |
| 1512 * table" that refers to it. | |
| 1513 */ | |
| 1514 final Map<LibraryElement, int> dependencyMap = <LibraryElement, int>{}; | |
| 1515 | |
| 1516 /** | |
| 1517 * The "dependency table". This is the list of objects which should be | |
| 1518 * written to [LinkedLibrary.dependencies]. | |
| 1519 */ | |
| 1520 final List<LinkedDependencyBuilder> dependencies = | |
| 1521 <LinkedDependencyBuilder>[]; | |
| 1522 | |
| 1523 /** | |
| 1524 * The linked portion of the "imports table". This is the list of ints | |
| 1525 * which should be written to [LinkedLibrary.imports]. | |
| 1526 */ | |
| 1527 final List<int> linkedImports = <int>[]; | |
| 1528 | |
| 1529 /** | |
| 1530 * The linked portion of the "exports table". This is the list of ints | |
| 1531 * which should be written to [LinkedLibrary.exports]. | |
| 1532 */ | |
| 1533 final List<int> linkedExports = <int>[]; | |
| 1534 | |
| 1535 /** | |
| 1536 * Set of libraries which have been seen so far while visiting the transitive | |
| 1537 * closure of exports. | |
| 1538 */ | |
| 1539 final Set<LibraryElement> librariesAddedToTransitiveExportClosure = | |
| 1540 new Set<LibraryElement>(); | |
| 1541 | |
| 1542 /** | |
| 1543 * Map from imported element to the prefix which may be used to refer to that | |
| 1544 * element; elements for which no prefix is needed are absent from this map. | |
| 1545 */ | |
| 1546 final Map<Element, PrefixElement> prefixMap = <Element, PrefixElement>{}; | |
| 1547 | |
| 1548 /** | |
| 1549 * List of serializers for the compilation units constituting this library. | |
| 1550 */ | |
| 1551 final List<_CompilationUnitSerializer> compilationUnitSerializers = | |
| 1552 <_CompilationUnitSerializer>[]; | |
| 1553 | |
| 1554 _LibrarySerializer(this.libraryElement, this.typeProvider, this.strongMode) { | |
| 1555 dependencies.add(new LinkedDependencyBuilder()); | |
| 1556 dependencyMap[libraryElement] = 0; | |
| 1557 } | |
| 1558 | |
| 1559 /** | |
| 1560 * Retrieve a list of the Sources for the compilation units in the library. | |
| 1561 */ | |
| 1562 List<Source> get unitSources => compilationUnitSerializers | |
| 1563 .map((_CompilationUnitSerializer s) => s.unitSource) | |
| 1564 .toList(); | |
| 1565 | |
| 1566 /** | |
| 1567 * Retrieve a list of the URIs for the compilation units in the library. | |
| 1568 */ | |
| 1569 List<String> get unitUris => compilationUnitSerializers | |
| 1570 .map((_CompilationUnitSerializer s) => s.unitUri) | |
| 1571 .toList(); | |
| 1572 | |
| 1573 /** | |
| 1574 * Retrieve a list of the [UnlinkedUnitBuilder]s for the compilation units in | |
| 1575 * the library. | |
| 1576 */ | |
| 1577 List<UnlinkedUnitBuilder> get unlinkedUnits => compilationUnitSerializers | |
| 1578 .map((_CompilationUnitSerializer s) => s.unlinkedUnit) | |
| 1579 .toList(); | |
| 1580 | |
| 1581 /** | |
| 1582 * Add [exportedLibrary] (and the transitive closure of all libraries it | |
| 1583 * exports) to the dependency table ([LinkedLibrary.dependencies]). | |
| 1584 */ | |
| 1585 void addTransitiveExportClosure(LibraryElement exportedLibrary) { | |
| 1586 if (librariesAddedToTransitiveExportClosure.add(exportedLibrary)) { | |
| 1587 serializeDependency(exportedLibrary); | |
| 1588 for (LibraryElement transitiveExport | |
| 1589 in exportedLibrary.exportedLibraries) { | |
| 1590 addTransitiveExportClosure(transitiveExport); | |
| 1591 } | |
| 1592 } | |
| 1593 } | |
| 1594 | |
| 1595 /** | |
| 1596 * Fill in [prefixMap] using information from [libraryElement.imports]. | |
| 1597 */ | |
| 1598 void computePrefixMap() { | |
| 1599 for (ImportElement import in libraryElement.imports) { | |
| 1600 if (import.prefix == null) { | |
| 1601 continue; | |
| 1602 } | |
| 1603 import.importedLibrary.exportNamespace.definedNames | |
| 1604 .forEach((String name, Element e) { | |
| 1605 if (new NameFilter.forNamespaceCombinators(import.combinators) | |
| 1606 .accepts(name)) { | |
| 1607 prefixMap[e] = import.prefix; | |
| 1608 } | |
| 1609 }); | |
| 1610 } | |
| 1611 } | |
| 1612 | |
| 1613 /** | |
| 1614 * Return the index of the entry in the dependency table | |
| 1615 * ([LinkedLibrary.dependencies]) for the given [dependentLibrary]. A new | |
| 1616 * entry is added to the table if necessary to satisfy the request. | |
| 1617 */ | |
| 1618 int serializeDependency(LibraryElement dependentLibrary) { | |
| 1619 return dependencyMap.putIfAbsent(dependentLibrary, () { | |
| 1620 int index = dependencies.length; | |
| 1621 List<String> parts = dependentLibrary.parts | |
| 1622 .map((CompilationUnitElement e) => e.source.uri.toString()) | |
| 1623 .toList(); | |
| 1624 dependencies.add(new LinkedDependencyBuilder( | |
| 1625 uri: dependentLibrary.source.uri.toString(), parts: parts)); | |
| 1626 return index; | |
| 1627 }); | |
| 1628 } | |
| 1629 | |
| 1630 /** | |
| 1631 * Serialize the whole library element into a [LinkedLibrary]. Should be | |
| 1632 * called exactly once for each instance of [_LibrarySerializer]. | |
| 1633 * | |
| 1634 * The unlinked compilation units are stored in [unlinkedUnits], and their | |
| 1635 * absolute URIs are stored in [unitUris]. | |
| 1636 */ | |
| 1637 LinkedLibraryBuilder serializeLibrary() { | |
| 1638 computePrefixMap(); | |
| 1639 LinkedLibraryBuilder pb = new LinkedLibraryBuilder(); | |
| 1640 for (ExportElement exportElement in libraryElement.exports) { | |
| 1641 addTransitiveExportClosure(exportElement.exportedLibrary); | |
| 1642 linkedExports.add(serializeDependency(exportElement.exportedLibrary)); | |
| 1643 } | |
| 1644 for (ImportElement importElement in libraryElement.imports) { | |
| 1645 addTransitiveExportClosure(importElement.importedLibrary); | |
| 1646 linkedImports.add(serializeDependency(importElement.importedLibrary)); | |
| 1647 } | |
| 1648 compilationUnitSerializers.add(new _CompilationUnitSerializer( | |
| 1649 this, libraryElement.definingCompilationUnit, 0)); | |
| 1650 for (int i = 0; i < libraryElement.parts.length; i++) { | |
| 1651 compilationUnitSerializers.add( | |
| 1652 new _CompilationUnitSerializer(this, libraryElement.parts[i], i + 1)); | |
| 1653 } | |
| 1654 for (_CompilationUnitSerializer compilationUnitSerializer | |
| 1655 in compilationUnitSerializers) { | |
| 1656 compilationUnitSerializer.addCompilationUnitElements(); | |
| 1657 } | |
| 1658 pb.units = compilationUnitSerializers | |
| 1659 .map((_CompilationUnitSerializer s) => s.linkedUnit) | |
| 1660 .toList(); | |
| 1661 pb.dependencies = dependencies; | |
| 1662 pb.numPrelinkedDependencies = dependencies.length; | |
| 1663 for (_CompilationUnitSerializer compilationUnitSerializer | |
| 1664 in compilationUnitSerializers) { | |
| 1665 compilationUnitSerializer.createLinkedInfo(); | |
| 1666 } | |
| 1667 pb.importDependencies = linkedImports; | |
| 1668 pb.exportDependencies = linkedExports; | |
| 1669 List<String> exportedNames = | |
| 1670 libraryElement.exportNamespace.definedNames.keys.toList(); | |
| 1671 exportedNames.sort(); | |
| 1672 List<LinkedExportNameBuilder> exportNames = <LinkedExportNameBuilder>[]; | |
| 1673 for (String name in exportedNames) { | |
| 1674 if (libraryElement.publicNamespace.definedNames.containsKey(name)) { | |
| 1675 continue; | |
| 1676 } | |
| 1677 Element element = libraryElement.exportNamespace.get(name); | |
| 1678 LibraryElement dependentLibrary = element.library; | |
| 1679 CompilationUnitElement unitElement = | |
| 1680 element.getAncestor((Element e) => e is CompilationUnitElement); | |
| 1681 int unit = dependentLibrary.units.indexOf(unitElement); | |
| 1682 assert(unit != -1); | |
| 1683 ReferenceKind kind = _getReferenceKind(element); | |
| 1684 exportNames.add(new LinkedExportNameBuilder( | |
| 1685 name: name, | |
| 1686 dependency: serializeDependency(dependentLibrary), | |
| 1687 unit: unit, | |
| 1688 kind: kind)); | |
| 1689 } | |
| 1690 pb.exportNames = exportNames; | |
| 1691 return pb; | |
| 1692 } | |
| 1693 } | |
| OLD | NEW |