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

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: Remove more unnecessary TODOs. 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(
Brian Wilkerson 2015/11/11 15:26:10 The class 'Object' is used a lot in this library.
Paul Berry 2015/11/11 19:12:22 Yeah, I'm not happy about that either. I have an
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 && !variable.isSynthetic) {
Brian Wilkerson 2015/11/11 15:26:10 Under what conditions will the variable be non-syn
Paul Berry 2015/11/11 19:12:22 Did you perhaps mean to ask "Under what conditions
193 variables.add(serializeVariable(variable, unitNum));
194 }
195 }
196 }
197 }
198
199 /**
200 * Add [exportedLibrary] (and the transitive closure of all libraries it
201 * exports) to the dependency table ([PrelinkedLibrary.dependencies]).
202 */
203 void addTransitiveExportClosure(LibraryElement exportedLibrary) {
204 if (librariesAddedToTransitiveExportClosure.add(exportedLibrary)) {
205 serializeDependency(exportedLibrary);
206 for (LibraryElement transitiveExport
207 in exportedLibrary.exportedLibraries) {
208 addTransitiveExportClosure(transitiveExport);
209 }
210 }
211 }
212
213 /**
214 * Compute the appropriate De Bruijn index to represent the given type
215 * parameter [type].
216 */
217 int findTypeParameterIndex(TypeParameterType type) {
218 int index = 0;
219 Element enclosingElement = type.element.enclosingElement;
220 while (enclosingElement != null) {
221 List<TypeParameterElement> typeParameters;
222 if (enclosingElement is ClassElement) {
223 typeParameters = enclosingElement.typeParameters;
224 } else if (enclosingElement is FunctionTypeAliasElement) {
225 // TODO(paulberry): test this.
226 typeParameters = enclosingElement.typeParameters;
227 }
228 for (int i = 0; i < typeParameters.length; i++) {
229 TypeParameterElement param = typeParameters[i];
230 if (param == type.element) {
231 return index + typeParameters.length - i;
232 }
233 }
234 index += typeParameters.length;
235 enclosingElement = enclosingElement.enclosingElement;
236 }
237 throw new StateError('Unbound type parameter $type');
238 }
239
240 /**
241 * Serialize the given [classElement], which exists in the unit numbered
242 * [unitNum], creating an [UnlinkedClass].
243 */
244 Object serializeClass(ClassElement classElement, int unitNum) {
245 UnlinkedClassBuilder b = new UnlinkedClassBuilder(ctx);
246 b.name = classElement.name;
247 b.unit = unitNum;
248 b.typeParameters =
249 classElement.typeParameters.map(serializeTypeParam).toList();
250 if (classElement.supertype != null && !classElement.supertype.isObject) {
251 b.supertype = serializeTypeRef(classElement.supertype);
252 }
253 b.mixins = classElement.mixins.map(serializeTypeRef).toList();
254 b.interfaces = classElement.interfaces.map(serializeTypeRef).toList();
255 List<Object> fields = <Object>[];
256 List<Object> executables = <Object>[];
257 for (ConstructorElement executable in classElement.constructors) {
258 if (!executable.isSynthetic) {
259 executables.add(serializeExecutable(executable, 0));
260 }
261 }
262 for (MethodElement executable in classElement.methods) {
263 executables.add(serializeExecutable(executable, 0));
264 }
265 for (PropertyAccessorElement accessor in classElement.accessors) {
266 if (!accessor.isSynthetic) {
267 executables.add(serializeExecutable(accessor, 0));
268 } else if (accessor.isGetter) {
269 PropertyInducingElement field = accessor.variable;
270 if (field != null && !field.isSynthetic) {
271 fields.add(serializeVariable(field, 0));
272 }
273 }
274 }
275 b.fields = fields;
276 b.executables = executables;
277 b.isAbstract = classElement.isAbstract;
278 b.isMixinApplication = classElement.isMixinApplication;
279 return b.finish();
280 }
281
282 /**
283 * Serialize the given [combinator] into an [UnlinkedCombinator].
284 */
285 Object serializeCombinator(NamespaceCombinator combinator) {
286 UnlinkedCombinatorBuilder b = new UnlinkedCombinatorBuilder(ctx);
287 if (combinator is ShowElementCombinator) {
288 b.shows = combinator.shownNames.map(serializeCombinatorName).toList();
289 } else if (combinator is HideElementCombinator) {
290 b.hides = combinator.hiddenNames.map(serializeCombinatorName).toList();
291 }
292 return b.finish();
293 }
294
295 /**
296 * Serialize the given [name] into an [UnlinkedCombinatorName].
297 */
298 Object serializeCombinatorName(String name) {
299 return encodeUnlinkedCombinatorName(ctx, name: name);
300 }
301
302 /**
303 * Return the index of the entry in the dependency table
304 * ([PrelinkedLibrary.dependencies]) for the given [dependentLibrary]. A new
305 * entry is added to the table if necessary to satisfy the request.
306 */
307 int serializeDependency(LibraryElement dependentLibrary) {
308 return dependencyMap.putIfAbsent(dependentLibrary, () {
309 int index = dependencies.length;
310 dependencies.add(encodePrelinkedDependency(ctx,
311 uri: dependentLibrary.source.uri.toString()));
312 return index;
313 });
314 }
315
316 /**
317 * Return the index of the entry in the references table
318 * ([UnlinkedLibrary.references] and [PrelinkedLibrary.references])
319 * representing the pseudo-type `dynamic`. A new entry is added to the table
320 * if necessary to satisfy the request.
321 */
322 int serializeDynamicReference() {
323 if (dynamicReferenceIndex == null) {
324 assert(unlinkedReferences.length == prelinkedReferences.length);
325 dynamicReferenceIndex = unlinkedReferences.length;
326 unlinkedReferences.add(encodeUnlinkedReference(ctx));
327 prelinkedReferences.add(encodePrelinkedReference(ctx,
328 kind: PrelinkedReferenceKind.classOrEnum));
329 }
330 return dynamicReferenceIndex;
331 }
332
333 /**
334 * Serialize the given [enumElement], which exists in the unit numbered
335 * [unitNum], creating an [UnlinkedEnum].
336 */
337 Object serializeEnum(ClassElement enumElement, int unitNum) {
338 UnlinkedEnumBuilder b = new UnlinkedEnumBuilder(ctx);
339 b.name = enumElement.name;
340 List<Object> values = <Object>[];
341 for (FieldElement field in enumElement.fields) {
342 if (field.isConst && field.type.element == enumElement) {
343 values.add(encodeUnlinkedEnumValue(ctx, name: field.name));
344 }
345 }
346 b.values = values;
347 b.unit = unitNum;
348 return b.finish();
349 }
350
351 /**
352 * Serialize the given [executableElement], which exists in the unit numbered
353 * [unitNum], creating an [UnlinkedExecutable]. For elements declared inside
354 * a class, [unitNum] should be zero.
355 */
356 Object serializeExecutable(ExecutableElement executableElement, int unitNum) {
357 if (executableElement.enclosingElement is ClassElement) {
358 assert(unitNum == 0);
359 }
360 UnlinkedExecutableBuilder b = new UnlinkedExecutableBuilder(ctx);
361 b.name = executableElement.name;
362 b.unit = unitNum;
363 if (!executableElement.type.returnType.isVoid) {
364 b.returnType = serializeTypeRef(executableElement.type.returnType);
365 }
366 // TODO(paulberry): serialize type parameters.
367 b.parameters =
368 executableElement.type.parameters.map(serializeParam).toList();
369 if (executableElement is PropertyAccessorElement) {
370 if (executableElement.isGetter) {
371 b.kind = UnlinkedExecutableKind.getter;
372 } else {
373 b.kind = UnlinkedExecutableKind.setter;
374 }
375 } else if (executableElement is ConstructorElement) {
376 b.kind = UnlinkedExecutableKind.constructor;
377 b.isConst = executableElement.isConst;
378 b.isFactory = executableElement.isFactory;
379 } else {
380 b.kind = UnlinkedExecutableKind.functionOrMethod;
381 }
382 b.isAbstract = executableElement.isAbstract;
383 b.isStatic = executableElement.isStatic &&
384 executableElement.enclosingElement is ClassElement;
385 return b.finish();
386 }
387
388 /**
389 * Serialize the given [exportElement] into an [UnlinkedExport].
390 */
391 Object serializeExport(ExportElement exportElement) {
392 UnlinkedExportBuilder b = new UnlinkedExportBuilder(ctx);
393 b.uri = exportElement.uri;
394 b.combinators = exportElement.combinators.map(serializeCombinator).toList();
395 return b.finish();
396 }
397
398 /**
399 * Serialize the given [importElement], adding information about it to
400 * the [unlinkedImports] and [prelinkedImports] lists.
401 */
402 void serializeImport(ImportElement importElement) {
403 assert(unlinkedImports.length == prelinkedImports.length);
404 UnlinkedImportBuilder b = new UnlinkedImportBuilder(ctx);
405 b.isDeferred = importElement.isDeferred;
406 b.offset = importElement.nameOffset;
407 b.combinators = importElement.combinators.map(serializeCombinator).toList();
408 if (importElement.prefix != null) {
409 b.prefix = prefixMap.putIfAbsent(importElement.prefix.name, () {
410 int index = prefixes.length;
411 prefixes
412 .add(encodeUnlinkedPrefix(ctx, name: importElement.prefix.name));
413 return index;
414 });
415 }
416 if (importElement.isSynthetic) {
417 b.isImplicit = true;
418 } else {
419 b.uri = importElement.uri;
420 }
421 addTransitiveExportClosure(importElement.importedLibrary);
422 unlinkedImports.add(b.finish());
423 prelinkedImports.add(serializeDependency(importElement.importedLibrary));
424 }
425
426 /**
427 * Serialize the whole library element into a [PrelinkedLibrary]. Should be
428 * called exactly once for each instance of [_LibrarySerializer].
429 */
430 Object serializeLibrary() {
431 UnlinkedLibraryBuilder ub = new UnlinkedLibraryBuilder(ctx);
432 PrelinkedLibraryBuilder pb = new PrelinkedLibraryBuilder(ctx);
433 if (libraryElement.name.isNotEmpty) {
434 ub.name = libraryElement.name;
435 }
436 for (ImportElement importElement in libraryElement.imports) {
437 serializeImport(importElement);
438 }
439 ub.exports = libraryElement.exports.map(serializeExport).toList();
440 addCompilationUnitElements(libraryElement.definingCompilationUnit, 0);
441 for (int i = 0; i < libraryElement.parts.length; i++) {
442 addCompilationUnitElements(libraryElement.parts[i], i + 1);
443 }
444 ub.classes = classes;
445 ub.enums = enums;
446 ub.executables = executables;
447 ub.imports = unlinkedImports;
448 ub.prefixes = prefixes;
449 ub.references = unlinkedReferences;
450 ub.typedefs = typedefs;
451 ub.units = units;
452 ub.variables = variables;
453 pb.unlinked = ub.finish();
454 pb.dependencies = dependencies;
455 pb.importDependencies = prelinkedImports;
456 pb.references = prelinkedReferences;
457 return pb.finish();
458 }
459
460 /**
461 * Serialize the given [parameter] into an [UnlinkedParam].
462 */
463 Object serializeParam(ParameterElement parameter) {
464 UnlinkedParamBuilder b = new UnlinkedParamBuilder(ctx);
465 b.name = parameter.name;
466 switch (parameter.parameterKind) {
467 case ParameterKind.REQUIRED:
468 b.kind = UnlinkedParamKind.required;
469 break;
470 case ParameterKind.POSITIONAL:
471 b.kind = UnlinkedParamKind.positional;
472 break;
473 case ParameterKind.NAMED:
474 b.kind = UnlinkedParamKind.named;
475 break;
476 }
477 b.isInitializingFormal = parameter.isInitializingFormal;
478 DartType type = parameter.type;
479 if (type is FunctionType) {
480 b.isFunctionTyped = true;
481 if (!type.returnType.isVoid) {
482 b.type = serializeTypeRef(type.returnType);
483 }
484 b.parameters = type.parameters.map(serializeParam).toList();
485 } else {
486 b.type = serializeTypeRef(type);
487 }
488 return b.finish();
489 }
490
491 /**
492 * Serialize the given [typedefElement], which exists in the unit numbered
493 * [unitNum], creating an [UnlinkedTypedef].
494 */
495 Object serializeTypedef(
496 FunctionTypeAliasElement typedefElement, int unitNum) {
497 UnlinkedTypedefBuilder b = new UnlinkedTypedefBuilder(ctx);
498 b.name = typedefElement.name;
499 b.unit = unitNum;
500 b.typeParameters =
501 typedefElement.typeParameters.map(serializeTypeParam).toList();
502 if (!typedefElement.returnType.isVoid) {
503 b.returnType = serializeTypeRef(typedefElement.returnType);
504 }
505 b.parameters = typedefElement.parameters.map(serializeParam).toList();
506 return b.finish();
507 }
508
509 /**
510 * Serialize the given [typeParameter] into an [UnlinkedTypeParam].
511 */
512 Object serializeTypeParam(TypeParameterElement typeParameter) {
513 UnlinkedTypeParamBuilder b = new UnlinkedTypeParamBuilder(ctx);
514 b.name = typeParameter.name;
515 if (typeParameter.bound != null) {
516 b.bound = serializeTypeRef(typeParameter.bound);
517 }
518 return b.finish();
519 }
520
521 /**
522 * Serialize the given [type] into an [UnlinkedTypeRef].
523 */
524 Object serializeTypeRef(DartType type) {
525 UnlinkedTypeRefBuilder b = new UnlinkedTypeRefBuilder(ctx);
526 if (type is TypeParameterType) {
527 Element enclosingElement = type.element.enclosingElement;
528 b.paramReference = findTypeParameterIndex(type);
529 } else {
530 Element element = type.element;
531 CompilationUnitElement dependentCompilationUnit =
532 element.getAncestor((Element e) => e is CompilationUnitElement);
533 LibraryElement dependentLibrary = element.library;
534 if (dependentLibrary == null) {
535 assert(type.isDynamic);
536 if (type is UndefinedTypeImpl) {
537 b.reference = serializeUnresolvedReference();
538 } else {
539 b.reference = serializeDynamicReference();
540 }
541 } else {
542 b.reference = referenceMap.putIfAbsent(element, () {
543 assert(unlinkedReferences.length == prelinkedReferences.length);
544 int index = unlinkedReferences.length;
545 // TODO(paulberry): set UnlinkedReference.prefix.
546 unlinkedReferences
547 .add(encodeUnlinkedReference(ctx, name: element.name));
548 prelinkedReferences.add(encodePrelinkedReference(ctx,
549 dependency: serializeDependency(dependentLibrary),
550 kind: element is FunctionTypeAliasElement
551 ? PrelinkedReferenceKind.typedef
552 : PrelinkedReferenceKind.classOrEnum));
553 return index;
554 });
555 }
556 List<DartType> typeArguments;
557 if (type is InterfaceType) {
558 typeArguments = type.typeArguments;
559 } else if (type is FunctionType) {
560 typeArguments = type.typeArguments;
561 }
562 if (typeArguments != null &&
563 typeArguments.any((DartType argument) => !argument.isDynamic)) {
564 b.typeArguments = typeArguments.map(serializeTypeRef).toList();
565 }
566 }
567 return b.finish();
568 }
569
570 /**
571 * Return the index of the entry in the references table
572 * ([UnlinkedLibrary.references] and [PrelinkedLibrary.references]) used for
573 * unresolved references. A new entry is added to the table if necessary to
574 * satisfy the request.
575 */
576 int serializeUnresolvedReference() {
577 // TODO(paulberry): in order for relinking to work, we need to record the
578 // name and prefix of the unresolved symbol. This is not (yet) encoded in
579 // the element model.
580 if (unresolvedReferenceIndex == null) {
581 assert(unlinkedReferences.length == prelinkedReferences.length);
582 unresolvedReferenceIndex = unlinkedReferences.length;
583 unlinkedReferences.add(encodeUnlinkedReference(ctx));
584 prelinkedReferences.add(encodePrelinkedReference(ctx,
585 kind: PrelinkedReferenceKind.unresolved));
586 }
587 return unresolvedReferenceIndex;
588 }
589
590 /**
591 * Serialize the given [variable], which exists in the unit numbered
592 * [unitNum], creating an [UnlinkedVariable]. For variables declared inside
593 * a class (i.e. fields), [unitNum] should be zero.
594 */
595 Object serializeVariable(PropertyInducingElement variable, int unitNum) {
596 if (variable.enclosingElement is ClassElement) {
597 assert(unitNum == 0);
598 }
599 UnlinkedVariableBuilder b = new UnlinkedVariableBuilder(ctx);
600 b.name = variable.name;
601 b.unit = unitNum;
602 b.type = serializeTypeRef(variable.type);
603 b.isStatic = variable.isStatic && variable.enclosingElement is ClassElement;
604 b.isFinal = variable.isFinal;
605 b.isConst = variable.isConst;
606 return b.finish();
607 }
608 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698