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 |