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

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

Issue 1420053011: Introduce code to generate summaries from an element model. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Address code review comments. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library serialization.elements;
6
7 import 'package:analyzer/src/generated/element.dart';
8 import 'package:analyzer/src/generated/resolver.dart';
9 import 'package:analyzer/src/generated/utilities_dart.dart';
10 import 'package:analyzer/src/summary/builder.dart';
11 import 'package:analyzer/src/summary/format.dart';
12
13 /**
14 * Serialize all the elements in [lib] to a summary using [ctx] as the context
15 * for building the summary, and using [typeProvider] to find built-in types.
16 *
17 * Return an object which may safely be passed to [BuilderContext.getBuffer] or
18 * included in an aggregate summary.
19 */
20 Object serializeLibrary(
21 BuilderContext ctx, LibraryElement lib, TypeProvider typeProvider) {
22 return new _LibrarySerializer(ctx, lib, typeProvider).serializeLibrary();
23 }
24
25 /**
26 * Instances of this class keep track of intermediate state during
27 * serialization of a single library.`
28 */
29 class _LibrarySerializer {
30 /**
31 * The library to be serialized.
32 */
33 final LibraryElement libraryElement;
34
35 /**
36 * The type provider. This is used to locate the library for `dart:core`.
37 */
38 final TypeProvider typeProvider;
39
40 /**
41 * List of objects which should be written to [UnlinkedLibrary.classes].
42 */
43 final List<Object> classes = <Object>[];
44
45 /**
46 * List of objects which should be written to [UnlinkedLibrary.enums].
47 */
48 final List<Object> enums = <Object>[];
49
50 /**
51 * List of objects which should be written to [UnlinkedLibrary.executables].
52 */
53 final List<Object> executables = <Object>[];
54
55 /**
56 * List of objects which should be written to [UnlinkedLibrary.typedefs].
57 */
58 final List<Object> typedefs = <Object>[];
59
60 /**
61 * List of objects which should be written to [UnlinkedLibrary.units].
62 */
63 final List<Object> units = <Object>[];
64
65 /**
66 * List of objects which should be written to [UnlinkedLibrary.variables].
67 */
68 final List<Object> variables = <Object>[];
69
70 /**
71 * Map from [LibraryElement] to the index of the entry in the "dependency
72 * table" that refers to it.
73 */
74 final Map<LibraryElement, int> dependencyMap = <LibraryElement, int>{};
75
76 /**
77 * The "dependency table". This is the list of objects which should be
78 * written to [PrelinkedLibrary.dependencies].
79 */
80 final List<Object> dependencies = <Object>[];
81
82 /**
83 * The unlinked portion of the "imports table". This is the list of objects
84 * which should be written to [UnlinkedLibrary.imports].
85 */
86 final List<Object> unlinkedImports = <Object>[];
87
88 /**
89 * The prelinked portion of the "imports table". This is the list of ints
90 * which should be written to [PrelinkedLibrary.imports].
91 */
92 final List<Object> prelinkedImports = <int>[];
93
94 /**
95 * Map from prefix [String] to the index of the entry in the "prefix" table
96 * that refers to it. The empty prefix is not included in this map.
97 */
98 final Map<String, int> prefixMap = <String, int>{};
99
100 /**
101 * The "prefix table". This is the list of objects which should be written
102 * to [UnlinkedLibrary.prefixes].
103 */
104 final List<Object> prefixes = <Object>[];
105
106 /**
107 * Map from [Element] to the index of the entry in the "references table"
108 * that refers to it.
109 */
110 final Map<Element, int> referenceMap = <Element, int>{};
111
112 /**
113 * The unlinked portion of the "references table". This is the list of
114 * objects which should be written to [UnlinkedLibrary.references].
115 */
116 final List<Object> unlinkedReferences = <Object>[];
117
118 /**
119 * The prelinked portion of the "references table". This is the list of
120 * objects which should be written to [PrelinkedLibrary.references].
121 */
122 final List<Object> prelinkedReferences = <Object>[];
123
124 //final Map<String, int> prefixIndices = <String, int>{};
125
126 /**
127 * Index into the "references table" representing `dynamic`, if such an index
128 * exists. `null` if no such entry has been made in the references table
129 * yet.
130 */
131 int dynamicReferenceIndex = null;
132
133 /**
134 * Index into the "references table" representing an unresolved reference, if
135 * such an index exists. `null` if no such entry has been made in the
136 * references table yet.
137 */
138 int unresolvedReferenceIndex = null;
139
140 /**
141 * Set of libraries which have been seen so far while visiting the transitive
142 * closure of exports.
143 */
144 final Set<LibraryElement> librariesAddedToTransitiveExportClosure =
145 new Set<LibraryElement>();
146
147 /**
148 * [BuilderContext] used to serialize the output summary.
149 */
150 final BuilderContext ctx;
151
152 _LibrarySerializer(this.ctx, this.libraryElement, this.typeProvider) {
153 dependencies.add(encodePrelinkedDependency(ctx));
154 dependencyMap[libraryElement] = 0;
155 prefixes.add(encodeUnlinkedPrefix(ctx));
156 }
157
158 /**
159 * Retrieve the library element for `dart:core`.
160 */
161 LibraryElement get coreLibrary => typeProvider.objectType.element.library;
162
163 /**
164 * Add all classes, enums, typedefs, executables, and top level variables
165 * from the given compilation unit [element] to the library summary.
166 * [unitNum] indicates the ordinal position of this compilation unit in the
167 * library.
168 */
169 void addCompilationUnitElements(CompilationUnitElement element, int unitNum) {
170 UnlinkedUnitBuilder b = new UnlinkedUnitBuilder(ctx);
171 if (element.uri != null) {
172 b.uri = element.uri;
173 }
174 units.add(b.finish());
175 for (ClassElement cls in element.types) {
176 classes.add(serializeClass(cls, unitNum));
177 }
178 for (ClassElement e in element.enums) {
179 enums.add(serializeEnum(e, unitNum));
180 }
181 for (FunctionTypeAliasElement type in element.functionTypeAliases) {
182 typedefs.add(serializeTypedef(type, unitNum));
183 }
184 for (FunctionElement executable in element.functions) {
185 executables.add(serializeExecutable(executable, unitNum));
186 }
187 for (PropertyAccessorElement accessor in element.accessors) {
188 if (!accessor.isSynthetic) {
189 executables.add(serializeExecutable(accessor, unitNum));
190 } else if (accessor.isGetter) {
191 PropertyInducingElement variable = accessor.variable;
192 if (variable != null) {
193 assert(!variable.isSynthetic);
194 variables.add(serializeVariable(variable, unitNum));
195 }
196 }
197 }
198 }
199
200 /**
201 * Add [exportedLibrary] (and the transitive closure of all libraries it
202 * exports) to the dependency table ([PrelinkedLibrary.dependencies]).
203 */
204 void addTransitiveExportClosure(LibraryElement exportedLibrary) {
205 if (librariesAddedToTransitiveExportClosure.add(exportedLibrary)) {
206 serializeDependency(exportedLibrary);
207 for (LibraryElement transitiveExport
208 in exportedLibrary.exportedLibraries) {
209 addTransitiveExportClosure(transitiveExport);
210 }
211 }
212 }
213
214 /**
215 * Compute the appropriate De Bruijn index to represent the given type
216 * parameter [type].
217 */
218 int findTypeParameterIndex(TypeParameterType type) {
219 int index = 0;
220 Element enclosingElement = type.element.enclosingElement;
221 while (enclosingElement != null) {
222 List<TypeParameterElement> typeParameters;
223 if (enclosingElement is ClassElement) {
224 typeParameters = enclosingElement.typeParameters;
225 } else if (enclosingElement is FunctionTypeAliasElement) {
226 // TODO(paulberry): test this.
227 typeParameters = enclosingElement.typeParameters;
228 }
229 for (int i = 0; i < typeParameters.length; i++) {
230 TypeParameterElement param = typeParameters[i];
231 if (param == type.element) {
232 return index + typeParameters.length - i;
233 }
234 }
235 index += typeParameters.length;
236 enclosingElement = enclosingElement.enclosingElement;
237 }
238 throw new StateError('Unbound type parameter $type');
239 }
240
241 /**
242 * Serialize the given [classElement], which exists in the unit numbered
243 * [unitNum], creating an [UnlinkedClass].
244 */
245 Object serializeClass(ClassElement classElement, int unitNum) {
246 UnlinkedClassBuilder b = new UnlinkedClassBuilder(ctx);
247 b.name = classElement.name;
248 b.unit = unitNum;
249 b.typeParameters =
250 classElement.typeParameters.map(serializeTypeParam).toList();
251 if (classElement.supertype != null && !classElement.supertype.isObject) {
252 b.supertype = serializeTypeRef(classElement.supertype);
253 }
254 b.mixins = classElement.mixins.map(serializeTypeRef).toList();
255 b.interfaces = classElement.interfaces.map(serializeTypeRef).toList();
256 List<Object> fields = <Object>[];
257 List<Object> executables = <Object>[];
258 for (ConstructorElement executable in classElement.constructors) {
259 if (!executable.isSynthetic) {
260 executables.add(serializeExecutable(executable, 0));
261 }
262 }
263 for (MethodElement executable in classElement.methods) {
264 executables.add(serializeExecutable(executable, 0));
265 }
266 for (PropertyAccessorElement accessor in classElement.accessors) {
267 if (!accessor.isSynthetic) {
268 executables.add(serializeExecutable(accessor, 0));
269 } else if (accessor.isGetter) {
270 PropertyInducingElement field = accessor.variable;
271 if (field != null && !field.isSynthetic) {
272 fields.add(serializeVariable(field, 0));
273 }
274 }
275 }
276 b.fields = fields;
277 b.executables = executables;
278 b.isAbstract = classElement.isAbstract;
279 b.isMixinApplication = classElement.isMixinApplication;
280 return b.finish();
281 }
282
283 /**
284 * Serialize the given [combinator] into an [UnlinkedCombinator].
285 */
286 Object serializeCombinator(NamespaceCombinator combinator) {
287 UnlinkedCombinatorBuilder b = new UnlinkedCombinatorBuilder(ctx);
288 if (combinator is ShowElementCombinator) {
289 b.shows = combinator.shownNames.map(serializeCombinatorName).toList();
290 } else if (combinator is HideElementCombinator) {
291 b.hides = combinator.hiddenNames.map(serializeCombinatorName).toList();
292 }
293 return b.finish();
294 }
295
296 /**
297 * Serialize the given [name] into an [UnlinkedCombinatorName].
298 */
299 Object serializeCombinatorName(String name) {
300 return encodeUnlinkedCombinatorName(ctx, name: name);
301 }
302
303 /**
304 * Return the index of the entry in the dependency table
305 * ([PrelinkedLibrary.dependencies]) for the given [dependentLibrary]. A new
306 * entry is added to the table if necessary to satisfy the request.
307 */
308 int serializeDependency(LibraryElement dependentLibrary) {
309 return dependencyMap.putIfAbsent(dependentLibrary, () {
310 int index = dependencies.length;
311 dependencies.add(encodePrelinkedDependency(ctx,
312 uri: dependentLibrary.source.uri.toString()));
313 return index;
314 });
315 }
316
317 /**
318 * Return the index of the entry in the references table
319 * ([UnlinkedLibrary.references] and [PrelinkedLibrary.references])
320 * representing the pseudo-type `dynamic`. A new entry is added to the table
321 * if necessary to satisfy the request.
322 */
323 int serializeDynamicReference() {
324 if (dynamicReferenceIndex == null) {
325 assert(unlinkedReferences.length == prelinkedReferences.length);
326 dynamicReferenceIndex = unlinkedReferences.length;
327 unlinkedReferences.add(encodeUnlinkedReference(ctx));
328 prelinkedReferences.add(encodePrelinkedReference(ctx,
329 kind: PrelinkedReferenceKind.classOrEnum));
330 }
331 return dynamicReferenceIndex;
332 }
333
334 /**
335 * Serialize the given [enumElement], which exists in the unit numbered
336 * [unitNum], creating an [UnlinkedEnum].
337 */
338 Object serializeEnum(ClassElement enumElement, int unitNum) {
339 UnlinkedEnumBuilder b = new UnlinkedEnumBuilder(ctx);
340 b.name = enumElement.name;
341 List<Object> values = <Object>[];
342 for (FieldElement field in enumElement.fields) {
343 if (field.isConst && field.type.element == enumElement) {
344 values.add(encodeUnlinkedEnumValue(ctx, name: field.name));
345 }
346 }
347 b.values = values;
348 b.unit = unitNum;
349 return b.finish();
350 }
351
352 /**
353 * Serialize the given [executableElement], which exists in the unit numbered
354 * [unitNum], creating an [UnlinkedExecutable]. For elements declared inside
355 * a class, [unitNum] should be zero.
356 */
357 Object serializeExecutable(ExecutableElement executableElement, int unitNum) {
358 if (executableElement.enclosingElement is ClassElement) {
359 assert(unitNum == 0);
360 }
361 UnlinkedExecutableBuilder b = new UnlinkedExecutableBuilder(ctx);
362 b.name = executableElement.name;
363 b.unit = unitNum;
364 if (!executableElement.type.returnType.isVoid) {
365 b.returnType = serializeTypeRef(executableElement.type.returnType);
366 }
367 // TODO(paulberry): serialize type parameters.
368 b.parameters =
369 executableElement.type.parameters.map(serializeParam).toList();
370 if (executableElement is PropertyAccessorElement) {
371 if (executableElement.isGetter) {
372 b.kind = UnlinkedExecutableKind.getter;
373 } else {
374 b.kind = UnlinkedExecutableKind.setter;
375 }
376 } else if (executableElement is ConstructorElement) {
377 b.kind = UnlinkedExecutableKind.constructor;
378 b.isConst = executableElement.isConst;
379 b.isFactory = executableElement.isFactory;
380 } else {
381 b.kind = UnlinkedExecutableKind.functionOrMethod;
382 }
383 b.isAbstract = executableElement.isAbstract;
384 b.isStatic = executableElement.isStatic &&
385 executableElement.enclosingElement is ClassElement;
386 return b.finish();
387 }
388
389 /**
390 * Serialize the given [exportElement] into an [UnlinkedExport].
391 */
392 Object serializeExport(ExportElement exportElement) {
393 UnlinkedExportBuilder b = new UnlinkedExportBuilder(ctx);
394 b.uri = exportElement.uri;
395 b.combinators = exportElement.combinators.map(serializeCombinator).toList();
396 return b.finish();
397 }
398
399 /**
400 * Serialize the given [importElement], adding information about it to
401 * the [unlinkedImports] and [prelinkedImports] lists.
402 */
403 void serializeImport(ImportElement importElement) {
404 assert(unlinkedImports.length == prelinkedImports.length);
405 UnlinkedImportBuilder b = new UnlinkedImportBuilder(ctx);
406 b.isDeferred = importElement.isDeferred;
407 b.offset = importElement.nameOffset;
408 b.combinators = importElement.combinators.map(serializeCombinator).toList();
409 if (importElement.prefix != null) {
410 b.prefix = prefixMap.putIfAbsent(importElement.prefix.name, () {
411 int index = prefixes.length;
412 prefixes
413 .add(encodeUnlinkedPrefix(ctx, name: importElement.prefix.name));
414 return index;
415 });
416 }
417 if (importElement.isSynthetic) {
418 b.isImplicit = true;
419 } else {
420 b.uri = importElement.uri;
421 }
422 addTransitiveExportClosure(importElement.importedLibrary);
423 unlinkedImports.add(b.finish());
424 prelinkedImports.add(serializeDependency(importElement.importedLibrary));
425 }
426
427 /**
428 * Serialize the whole library element into a [PrelinkedLibrary]. Should be
429 * called exactly once for each instance of [_LibrarySerializer].
430 */
431 Object serializeLibrary() {
432 UnlinkedLibraryBuilder ub = new UnlinkedLibraryBuilder(ctx);
433 PrelinkedLibraryBuilder pb = new PrelinkedLibraryBuilder(ctx);
434 if (libraryElement.name.isNotEmpty) {
435 ub.name = libraryElement.name;
436 }
437 for (ImportElement importElement in libraryElement.imports) {
438 serializeImport(importElement);
439 }
440 ub.exports = libraryElement.exports.map(serializeExport).toList();
441 addCompilationUnitElements(libraryElement.definingCompilationUnit, 0);
442 for (int i = 0; i < libraryElement.parts.length; i++) {
443 addCompilationUnitElements(libraryElement.parts[i], i + 1);
444 }
445 ub.classes = classes;
446 ub.enums = enums;
447 ub.executables = executables;
448 ub.imports = unlinkedImports;
449 ub.prefixes = prefixes;
450 ub.references = unlinkedReferences;
451 ub.typedefs = typedefs;
452 ub.units = units;
453 ub.variables = variables;
454 pb.unlinked = ub.finish();
455 pb.dependencies = dependencies;
456 pb.importDependencies = prelinkedImports;
457 pb.references = prelinkedReferences;
458 return pb.finish();
459 }
460
461 /**
462 * Serialize the given [parameter] into an [UnlinkedParam].
463 */
464 Object serializeParam(ParameterElement parameter) {
465 UnlinkedParamBuilder b = new UnlinkedParamBuilder(ctx);
466 b.name = parameter.name;
467 switch (parameter.parameterKind) {
468 case ParameterKind.REQUIRED:
469 b.kind = UnlinkedParamKind.required;
470 break;
471 case ParameterKind.POSITIONAL:
472 b.kind = UnlinkedParamKind.positional;
473 break;
474 case ParameterKind.NAMED:
475 b.kind = UnlinkedParamKind.named;
476 break;
477 }
478 b.isInitializingFormal = parameter.isInitializingFormal;
479 DartType type = parameter.type;
480 if (type is FunctionType) {
481 b.isFunctionTyped = true;
482 if (!type.returnType.isVoid) {
483 b.type = serializeTypeRef(type.returnType);
484 }
485 b.parameters = type.parameters.map(serializeParam).toList();
486 } else {
487 b.type = serializeTypeRef(type);
488 }
489 return b.finish();
490 }
491
492 /**
493 * Serialize the given [typedefElement], which exists in the unit numbered
494 * [unitNum], creating an [UnlinkedTypedef].
495 */
496 Object serializeTypedef(
497 FunctionTypeAliasElement typedefElement, int unitNum) {
498 UnlinkedTypedefBuilder b = new UnlinkedTypedefBuilder(ctx);
499 b.name = typedefElement.name;
500 b.unit = unitNum;
501 b.typeParameters =
502 typedefElement.typeParameters.map(serializeTypeParam).toList();
503 if (!typedefElement.returnType.isVoid) {
504 b.returnType = serializeTypeRef(typedefElement.returnType);
505 }
506 b.parameters = typedefElement.parameters.map(serializeParam).toList();
507 return b.finish();
508 }
509
510 /**
511 * Serialize the given [typeParameter] into an [UnlinkedTypeParam].
512 */
513 Object serializeTypeParam(TypeParameterElement typeParameter) {
514 UnlinkedTypeParamBuilder b = new UnlinkedTypeParamBuilder(ctx);
515 b.name = typeParameter.name;
516 if (typeParameter.bound != null) {
517 b.bound = serializeTypeRef(typeParameter.bound);
518 }
519 return b.finish();
520 }
521
522 /**
523 * Serialize the given [type] into an [UnlinkedTypeRef].
524 */
525 Object serializeTypeRef(DartType type) {
526 UnlinkedTypeRefBuilder b = new UnlinkedTypeRefBuilder(ctx);
527 if (type is TypeParameterType) {
528 Element enclosingElement = type.element.enclosingElement;
529 b.paramReference = findTypeParameterIndex(type);
530 } else {
531 Element element = type.element;
532 CompilationUnitElement dependentCompilationUnit =
533 element.getAncestor((Element e) => e is CompilationUnitElement);
534 LibraryElement dependentLibrary = element.library;
535 if (dependentLibrary == null) {
536 assert(type.isDynamic);
537 if (type is UndefinedTypeImpl) {
538 b.reference = serializeUnresolvedReference();
539 } else {
540 b.reference = serializeDynamicReference();
541 }
542 } else {
543 b.reference = referenceMap.putIfAbsent(element, () {
544 assert(unlinkedReferences.length == prelinkedReferences.length);
545 int index = unlinkedReferences.length;
546 // TODO(paulberry): set UnlinkedReference.prefix.
547 unlinkedReferences
548 .add(encodeUnlinkedReference(ctx, name: element.name));
549 prelinkedReferences.add(encodePrelinkedReference(ctx,
550 dependency: serializeDependency(dependentLibrary),
551 kind: element is FunctionTypeAliasElement
552 ? PrelinkedReferenceKind.typedef
553 : PrelinkedReferenceKind.classOrEnum));
554 return index;
555 });
556 }
557 List<DartType> typeArguments;
558 if (type is InterfaceType) {
559 typeArguments = type.typeArguments;
560 } else if (type is FunctionType) {
561 typeArguments = type.typeArguments;
562 }
563 if (typeArguments != null &&
564 typeArguments.any((DartType argument) => !argument.isDynamic)) {
565 b.typeArguments = typeArguments.map(serializeTypeRef).toList();
566 }
567 }
568 return b.finish();
569 }
570
571 /**
572 * Return the index of the entry in the references table
573 * ([UnlinkedLibrary.references] and [PrelinkedLibrary.references]) used for
574 * unresolved references. A new entry is added to the table if necessary to
575 * satisfy the request.
576 */
577 int serializeUnresolvedReference() {
578 // TODO(paulberry): in order for relinking to work, we need to record the
579 // name and prefix of the unresolved symbol. This is not (yet) encoded in
580 // the element model.
581 if (unresolvedReferenceIndex == null) {
582 assert(unlinkedReferences.length == prelinkedReferences.length);
583 unresolvedReferenceIndex = unlinkedReferences.length;
584 unlinkedReferences.add(encodeUnlinkedReference(ctx));
585 prelinkedReferences.add(encodePrelinkedReference(ctx,
586 kind: PrelinkedReferenceKind.unresolved));
587 }
588 return unresolvedReferenceIndex;
589 }
590
591 /**
592 * Serialize the given [variable], which exists in the unit numbered
593 * [unitNum], creating an [UnlinkedVariable]. For variables declared inside
594 * a class (i.e. fields), [unitNum] should be zero.
595 */
596 Object serializeVariable(PropertyInducingElement variable, int unitNum) {
597 if (variable.enclosingElement is ClassElement) {
598 assert(unitNum == 0);
599 }
600 UnlinkedVariableBuilder b = new UnlinkedVariableBuilder(ctx);
601 b.name = variable.name;
602 b.unit = unitNum;
603 b.type = serializeTypeRef(variable.type);
604 b.isStatic = variable.isStatic && variable.enclosingElement is ClassElement;
605 b.isFinal = variable.isFinal;
606 b.isConst = variable.isConst;
607 return b.finish();
608 }
609 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698