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

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

Issue 1526243002: Introduce code to resynthesize element models from summaries. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years 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 summary_resynthesizer;
6
7 import 'package:analyzer/analyzer.dart';
8 import 'package:analyzer/src/generated/element.dart';
9 import 'package:analyzer/src/generated/element_handle.dart';
10 import 'package:analyzer/src/generated/engine.dart';
11 import 'package:analyzer/src/generated/resolver.dart';
12 import 'package:analyzer/src/generated/source_io.dart';
13 import 'package:analyzer/src/summary/format.dart';
14
15 /**
16 * Callback used by [SummaryResynthesizer] to obtain the summary for a given
17 * URI.
18 */
19 typedef PrelinkedLibrary GetSummaryCallback(String uri);
20
21 /**
22 * Specialization of [FunctionTypeImpl] used for function types resynthesized
23 * from summaries.
24 */
25 class ResynthesizedFunctionTypeImpl extends FunctionTypeImpl
26 with ResynthesizedType {
27 final SummaryResynthesizer summaryResynthesizer;
28
29 ResynthesizedFunctionTypeImpl(
30 FunctionTypeAliasElement element, String name, this.summaryResynthesizer)
31 : super.elementWithName(element, name);
32
33 int get _numTypeParameters {
34 FunctionTypeAliasElement element = this.element;
35 return element.typeParameters.length;
36 }
37 }
38
39 /**
40 * Specialization of [InterfaceTypeImpl] used for interface types resynthesized
41 * from summaries.
42 */
43 class ResynthesizedInterfaceTypeImpl extends InterfaceTypeImpl
44 with ResynthesizedType {
45 final SummaryResynthesizer summaryResynthesizer;
46
47 ResynthesizedInterfaceTypeImpl(
48 ClassElement element, String name, this.summaryResynthesizer)
49 : super.elementWithName(element, name);
50
51 int get _numTypeParameters => element.typeParameters.length;
52 }
53
54 /**
55 * Common code for types resynthesized from summaries. This code takes care of
56 * filling in the appropriate number of copies of `dynamic` when it is queried
57 * for type parameters on a bare type reference (i.e. it converts `List` to
58 * `List<dynamic>`).
59 */
60 abstract class ResynthesizedType implements DartType {
61 /**
62 * The type arguments, if known. Otherwise `null`.
63 */
64 List<DartType> _typeArguments;
65
66 SummaryResynthesizer get summaryResynthesizer;
67
68 List<DartType> get typeArguments {
69 if (_typeArguments == null) {
70 // Default to replicating "dynamic" as many times as the class element
71 // requires.
72 _typeArguments = new List<DartType>.filled(
73 _numTypeParameters, summaryResynthesizer.typeProvider.dynamicType);
74 }
75 return _typeArguments;
76 }
77
78 int get _numTypeParameters;
79 }
80
81 /**
82 * Implementation of [ElementResynthesizer] used when resynthesizing an element
83 * model from summaries.
84 */
85 class SummaryResynthesizer extends ElementResynthesizer {
86 /**
87 * Callback used to obtain the summary for a given URI.
88 */
89 final GetSummaryCallback getSummary;
90
91 /**
92 * Source factory used to convert URIs to [Source] objects.
93 */
94 final SourceFactory sourceFactory;
95
96 /**
97 * Cache of [Source] objects that have already been converted from URIs.
98 */
99 final Map<String, Source> _sources = <String, Source>{};
100
101 /**
102 * The [TypeProvider] used to obtain core types (such as Object, int, List,
103 * and dynamic) during resynthesis.
104 *
105 * TODO(paulberry): will this create a chicken-and-egg problem when trying to
106 * resynthesize the core library from summaries?
107 */
108 final TypeProvider typeProvider;
109
110 /**
111 * Map of top level elements resynthesized from summaries. The three map
112 * keys are the first three elements of the element's location (the library
113 * URI, the compilation unit URI, and the name of the top level declaration).
114 */
115 final Map<String, Map<String, Map<String, Element>>> _resynthesizedElements =
116 <String, Map<String, Map<String, Element>>>{};
117
118 /**
119 * Map of libraries which have been resynthesized from summaries. The map
120 * key is the library URI.
121 */
122 final Map<String, LibraryElement> _resynthesizedLibraries =
123 <String, LibraryElement>{};
124
125 SummaryResynthesizer(
126 AnalysisContext context, this.getSummary, this.sourceFactory)
127 : super(context),
128 typeProvider = context.typeProvider;
129
130 /**
131 * Number of libraries that have been resynthesized so far.
132 */
133 int get resynthesisCount => _resynthesizedLibraries.length;
134
135 @override
136 Element getElement(ElementLocation location) {
137 if (location.components.length == 1) {
138 return getLibraryElement(location.components[0]);
139 } else if (location.components.length == 3) {
140 String uri = location.components[0];
141 Map<String, Map<String, Element>> libraryMap =
142 _resynthesizedElements[uri];
143 if (libraryMap == null) {
144 getLibraryElement(uri);
145 libraryMap = _resynthesizedElements[uri];
146 assert(libraryMap != null);
147 }
148 Element element = libraryMap[location.components[1]]
scheglov 2015/12/16 01:46:49 Can this expression be null?
Paul Berry 2015/12/16 16:34:20 Good point. It could happen, if files are updated
149 [location.components[2]];
150 if (element == null) {
151 throw new Exception('Failed to resynthesize $location');
152 }
153 assert(element != null);
154 return element;
155 } else {
156 throw new UnimplementedError(location.toString());
157 }
158 }
159
160 /**
161 * Get the [LibraryElement] for the given [uri], resynthesizing it if it
162 * hasn't been resynthesized already.
163 */
164 LibraryElement getLibraryElement(String uri) {
165 return _resynthesizedLibraries.putIfAbsent(uri, () {
166 PrelinkedLibrary serializedLibrary = getSummary(uri);
167 _LibraryResynthesizer libraryResynthesizer =
168 new _LibraryResynthesizer(this, serializedLibrary, _getSource(uri));
169 LibraryElement library = libraryResynthesizer.buildLibrary();
170 _resynthesizedElements[uri] = libraryResynthesizer.resummarizedElements;
171 return library;
172 });
173 }
174
175 /**
176 * Get the [Source] object for the given [uri].
177 */
178 Source _getSource(String uri) {
179 return _sources.putIfAbsent(uri, () => sourceFactory.forUri(uri));
180 }
181 }
182
183 /**
184 * An instance of [_LibraryResynthesizer] is responsible for resynthesizing the
185 * elements in a single library from that library's summary.
186 */
187 class _LibraryResynthesizer {
188 /**
189 * The [SummaryResynthesizer] which is being used to obtain summaries.
190 */
191 final SummaryResynthesizer summaryResynthesizer;
192
193 /**
194 * The library to be resynthesized.
195 */
196 final PrelinkedLibrary prelinkedLibrary;
197
198 /**
199 * [Source] object for the library to be resynthesized.
200 */
201 final Source librarySource;
202
203 /**
204 * [ElementHolder] into which resynthesized elements should be placed. This
205 * object is recreated afresh for each unit in the library, and is used to
206 * populate the [CompilationUnitElement].
207 */
208 ElementHolder unitHolder;
209
210 /**
211 * The [PrelinkedUnit] from which elements are currently being resynthesized.
212 */
213 PrelinkedUnit prelinkedUnit;
214
215 /**
216 * Map of top level elements that have been resynthesized so far. The first
217 * key is the URI of the compilation unit; the second is the name of the top
218 * level element.
219 */
220 final Map<String, Map<String, Element>> resummarizedElements =
221 <String, Map<String, Element>>{};
222
223 /**
224 * Type parameters for the class or typedef currently being resynthesized.
225 *
226 * TODO(paulberry): extend this to do the right thing for generic methods.
227 */
228 List<TypeParameterElement> currentTypeParameters;
229
230 _LibraryResynthesizer(this.summaryResynthesizer,
231 PrelinkedLibrary serializedLibrary, this.librarySource)
232 : prelinkedLibrary = serializedLibrary;
233
234 /**
235 * Resynthesize a [ClassElement] and place it in [unitHolder].
236 */
237 void buildClass(UnlinkedClass serializedClass) {
238 try {
239 currentTypeParameters =
240 serializedClass.typeParameters.map(buildTypeParameter).toList();
241 for (int i = 0; i < serializedClass.typeParameters.length; i++) {
242 finishTypeParameter(
243 serializedClass.typeParameters[i], currentTypeParameters[i]);
244 }
245 ClassElementImpl classElement;
246 if (serializedClass.isMixinApplication) {
247 classElement = new ClassElementImpl(serializedClass.name, -1);
248 classElement.setModifier(Modifier.MIXIN_APPLICATION, true);
249 } else {
250 classElement = new ClassElementImpl(serializedClass.name, -1);
Brian Wilkerson 2015/12/16 00:29:07 Unless I'm missing something, this line is inside
Paul Berry 2015/12/16 16:34:20 Oops, you're right. Fixed.
251 }
252 InterfaceTypeImpl correspondingType = new InterfaceTypeImpl(classElement);
253 if (serializedClass.supertype != null) {
254 classElement.supertype = buildType(serializedClass.supertype);
255 } else {
256 // TODO(paulberry): don't make Object point to itself.
257 classElement.supertype = summaryResynthesizer.typeProvider.objectType;
258 }
259 classElement.interfaces =
260 serializedClass.interfaces.map(buildType).toList();
261 classElement.mixins = serializedClass.mixins.map(buildType).toList();
262 classElement.typeParameters = currentTypeParameters;
263 ElementHolder memberHolder = new ElementHolder();
264 bool constructorFound = false;
265 for (UnlinkedExecutable serializedExecutable
266 in serializedClass.executables) {
267 switch (serializedExecutable.kind) {
268 case UnlinkedExecutableKind.constructor:
269 constructorFound = true;
270 buildConstructor(serializedExecutable, memberHolder);
271 break;
272 case UnlinkedExecutableKind.functionOrMethod:
273 case UnlinkedExecutableKind.getter:
274 case UnlinkedExecutableKind.setter:
275 buildExecutable(serializedExecutable, memberHolder);
276 break;
277 }
278 }
279 for (UnlinkedVariable serializedVariable in serializedClass.fields) {
280 buildVariable(serializedVariable, memberHolder);
281 }
282 if (!serializedClass.isMixinApplication) {
283 if (!constructorFound) {
284 // Synthesize implicit constructors.
285 ConstructorElementImpl constructor =
286 new ConstructorElementImpl('', -1);
287 constructor.setModifier(Modifier.SYNTHETIC, true);
288 constructor.returnType = correspondingType;
289 constructor.type = new FunctionTypeImpl(constructor);
290 memberHolder.addConstructor(constructor);
291 }
292 classElement.constructors = memberHolder.constructors;
293 }
294 classElement.accessors = memberHolder.accessors;
295 classElement.fields = memberHolder.fields;
296 classElement.methods = memberHolder.methods;
297 correspondingType.typeArguments =
298 currentTypeParameters.map((param) => param.type).toList();
299 classElement.type = correspondingType;
300 unitHolder.addType(classElement);
301 } finally {
302 currentTypeParameters = null;
303 }
304 }
305
306 /**
307 * Resynthesize a [NamespaceCombinator].
308 */
309 NamespaceCombinator buildCombinator(UnlinkedCombinator serializedCombinator) {
310 if (serializedCombinator.shows.isNotEmpty) {
311 ShowElementCombinatorImpl combinator = new ShowElementCombinatorImpl();
312 combinator.shownNames = serializedCombinator.shows
313 .map((UnlinkedCombinatorName n) => n.name)
314 .toList();
315 return combinator;
316 } else {
317 HideElementCombinatorImpl combinator = new HideElementCombinatorImpl();
318 combinator.hiddenNames = serializedCombinator.hides
319 .map((UnlinkedCombinatorName n) => n.name)
320 .toList();
321 return combinator;
322 }
323 }
324
325 /**
326 * Resynthesize a [ConstructorElement] and place it in the given [holder].
327 */
328 void buildConstructor(
329 UnlinkedExecutable serializedExecutable, ElementHolder holder) {
330 assert(serializedExecutable.kind == UnlinkedExecutableKind.constructor);
331 ConstructorElementImpl constructorElement =
332 new ConstructorElementImpl(serializedExecutable.name, -1);
333 buildExecutableCommonParts(constructorElement, serializedExecutable);
334 if (serializedExecutable.isFactory) {
335 constructorElement.setModifier(Modifier.FACTORY, true);
scheglov 2015/12/16 01:46:49 ConstructorElementImpl has a setter "factory". ...
Paul Berry 2015/12/16 16:34:20 Good point. I'll do a follow-up commit that repla
336 }
337 if (serializedExecutable.isConst) {
338 constructorElement.setModifier(Modifier.CONST, true);
339 }
340 holder.addConstructor(constructorElement);
341 }
342
343 /**
344 * Resynthesize the [ClassElement] corresponding to an enum, along with the
345 * associated fields and implicit accessors.
346 */
347 void buildEnum(UnlinkedEnum serializedEnum) {
348 ClassElementImpl classElement =
349 new ClassElementImpl(serializedEnum.name, -1);
Brian Wilkerson 2015/12/16 00:29:07 I assume that we'll get offsets at some point.
Paul Berry 2015/12/16 16:34:20 Yes, that's the plan. I've added a TODO comment t
350 classElement.setModifier(Modifier.ENUM, true);
351 InterfaceType enumType = new InterfaceTypeImpl(classElement);
352 classElement.type = enumType;
353 classElement.supertype = summaryResynthesizer.typeProvider.objectType;
354 ElementHolder memberHolder = new ElementHolder();
355 FieldElementImpl indexField = new FieldElementImpl('index', -1);
356 indexField.setModifier(Modifier.FINAL, true);
357 indexField.setModifier(Modifier.SYNTHETIC, true);
358 indexField.type = summaryResynthesizer.typeProvider.intType;
359 memberHolder.addField(indexField);
360 buildImplicitAccessors(indexField, memberHolder);
361 FieldElementImpl valuesField = new ConstFieldElementImpl('values', -1);
362 valuesField.setModifier(Modifier.SYNTHETIC, true);
363 valuesField.setModifier(Modifier.CONST, true);
364 valuesField.setModifier(Modifier.STATIC, true);
365 valuesField.type = summaryResynthesizer.typeProvider.listType
366 .substitute4(<DartType>[enumType]);
367 memberHolder.addField(valuesField);
368 buildImplicitAccessors(valuesField, memberHolder);
369 for (UnlinkedEnumValue serializedEnumValue in serializedEnum.values) {
370 ConstFieldElementImpl valueField =
371 new ConstFieldElementImpl(serializedEnumValue.name, -1);
372 valueField.setModifier(Modifier.CONST, true);
373 valueField.setModifier(Modifier.STATIC, true);
374 valueField.type = enumType;
375 memberHolder.addField(valueField);
376 buildImplicitAccessors(valueField, memberHolder);
377 }
378 classElement.fields = memberHolder.fields;
379 classElement.accessors = memberHolder.accessors;
380 classElement.constructors = <ConstructorElement>[];
381 unitHolder.addEnum(classElement);
382 }
383
384 /**
385 * Resynthesize an [ExecutableElement] and place it in the given [holder].
386 */
387 void buildExecutable(UnlinkedExecutable serializedExecutable,
388 [ElementHolder holder]) {
389 bool isTopLevel = holder == null;
390 if (holder == null) {
391 holder = unitHolder;
392 }
393 String name = serializedExecutable.name;
394 if (name.endsWith('=')) {
395 name = name.substring(0, name.length - 1);
396 }
397 UnlinkedExecutableKind kind = serializedExecutable.kind;
398 switch (kind) {
399 case UnlinkedExecutableKind.functionOrMethod:
400 if (isTopLevel) {
401 FunctionElementImpl executableElement =
402 new FunctionElementImpl(name, -1);
403 buildExecutableCommonParts(executableElement, serializedExecutable);
404 holder.addFunction(executableElement);
405 } else {
406 MethodElementImpl executableElement = new MethodElementImpl(name, -1);
407 buildExecutableCommonParts(executableElement, serializedExecutable);
408 executableElement.setModifier(
409 Modifier.STATIC, serializedExecutable.isStatic);
410 holder.addMethod(executableElement);
411 }
412 break;
413 case UnlinkedExecutableKind.getter:
414 case UnlinkedExecutableKind.setter:
415 PropertyAccessorElementImpl executableElement =
416 new PropertyAccessorElementImpl(name, -1);
417 if (isTopLevel) {
418 executableElement.setModifier(Modifier.STATIC, true);
419 } else {
420 executableElement.setModifier(
421 Modifier.STATIC, serializedExecutable.isStatic);
422 }
423 buildExecutableCommonParts(executableElement, serializedExecutable);
424 DartType type;
425 if (kind == UnlinkedExecutableKind.getter) {
426 executableElement.setModifier(Modifier.GETTER, true);
427 type = executableElement.returnType;
428 } else {
429 executableElement.setModifier(Modifier.SETTER, true);
430 type = executableElement.parameters[0].type;
431 }
432 holder.addAccessor(executableElement);
433 // TODO(paulberry): consider removing implicit variables from the
434 // element model; the spec doesn't call for them, and they cause
435 // trouble when getters/setters exist in different parts.
436 PropertyInducingElementImpl implicitVariable;
437 if (isTopLevel) {
438 implicitVariable = buildImplicitTopLevelVariable(name, kind, holder);
439 } else {
440 implicitVariable = buildImplicitField(name, type, kind, holder);
441 implicitVariable.setModifier(
442 Modifier.STATIC, serializedExecutable.isStatic);
443 }
444 executableElement.variable = implicitVariable;
445 if (kind == UnlinkedExecutableKind.getter) {
446 implicitVariable.getter = executableElement;
447 } else {
448 implicitVariable.setter = executableElement;
449 }
450 // TODO(paulberry): do the right thing when getter and setter are in
451 // different units.
452 break;
453 default:
454 // The only other executable type is a constructor, and that is handled
455 // separately (in [buildConstructor]. So this code should be
456 // unreachable.
457 assert(false);
458 }
459 }
460
461 /**
462 * Handle the parts of an executable element that are common to constructors,
463 * functions, methods, getters, and setters.
464 */
465 void buildExecutableCommonParts(ExecutableElementImpl executableElement,
466 UnlinkedExecutable serializedExecutable) {
467 executableElement.parameters =
468 serializedExecutable.parameters.map(buildParameter).toList();
469 if (serializedExecutable.returnType != null) {
470 executableElement.returnType = buildType(serializedExecutable.returnType);
471 } else {
472 executableElement.returnType = VoidTypeImpl.instance;
473 }
474 executableElement.type = new FunctionTypeImpl(executableElement);
475 if (serializedExecutable.hasImplicitReturnType) {
476 executableElement.setModifier(Modifier.IMPLICIT_TYPE, true);
477 }
478 }
479
480 /**
481 * Resynthesize an [ExportElement],
482 */
483 ExportElement buildExport(UnlinkedExport serializedExport) {
484 ExportElementImpl exportElement = new ExportElementImpl(0);
485 String exportedLibraryUri = summaryResynthesizer.sourceFactory
486 .resolveUri(librarySource, serializedExport.uri)
487 .uri
488 .toString();
489 exportElement.exportedLibrary = new LibraryElementHandle(
490 summaryResynthesizer,
491 new ElementLocationImpl.con3(<String>[exportedLibraryUri]));
492 exportElement.uri = serializedExport.uri;
493 exportElement.combinators =
494 serializedExport.combinators.map(buildCombinator).toList();
495 return exportElement;
496 }
497
498 /**
499 * Resynthesize a [FieldElement].
500 */
501 FieldElement buildField(UnlinkedVariable serializedField) {
502 FieldElementImpl fieldElement =
503 new FieldElementImpl(serializedField.name, -1);
504 fieldElement.type = buildType(serializedField.type);
505 if (serializedField.isConst) {
506 fieldElement.setModifier(Modifier.CONST, true);
507 }
508 return fieldElement;
509 }
510
511 /**
512 * Build the implicit getter and setter associated with [element], and place
513 * them in [holder].
514 */
515 void buildImplicitAccessors(
516 PropertyInducingElementImpl element, ElementHolder holder) {
517 String name = element.name;
518 DartType type = element.type;
519 PropertyAccessorElementImpl getter =
520 new PropertyAccessorElementImpl(name, -1);
521 getter.setModifier(Modifier.GETTER, true);
522 getter.setModifier(Modifier.STATIC, element.isStatic);
523 getter.setModifier(Modifier.SYNTHETIC, true);
524 getter.returnType = type;
525 getter.type = new FunctionTypeImpl(getter);
526 getter.variable = element;
527 holder.addAccessor(getter);
528 element.getter = getter;
529 if (!(element.isConst || element.isFinal)) {
530 PropertyAccessorElementImpl setter =
531 new PropertyAccessorElementImpl(name, -1);
532 setter.setModifier(Modifier.SETTER, true);
533 setter.setModifier(Modifier.STATIC, element.isStatic);
534 setter.setModifier(Modifier.SYNTHETIC, true);
535 setter.parameters = <ParameterElement>[
536 new ParameterElementImpl('_$name', -1)
537 ..setModifier(Modifier.SYNTHETIC, true)
538 ..type = type
539 ..parameterKind = ParameterKind.REQUIRED
540 ];
541 setter.returnType = VoidTypeImpl.instance;
542 setter.type = new FunctionTypeImpl(setter);
543 setter.variable = element;
544 holder.addAccessor(setter);
545 element.setter = setter;
546 }
547 }
548
549 /**
550 * Build the implicit field associated with a getter or setter, and place it
551 * in [holder].
552 */
553 PropertyInducingElementImpl buildImplicitField(String name, DartType type,
554 UnlinkedExecutableKind kind, ElementHolder holder) {
555 if (holder.getField(name) == null) {
556 FieldElementImpl field = new FieldElementImpl(name, -1);
557 field.setModifier(Modifier.SYNTHETIC, true);
558 if (kind == UnlinkedExecutableKind.getter) {
559 field.setModifier(Modifier.FINAL, true);
560 }
561 field.type = type;
562 holder.addField(field);
563 return field;
564 } else {
565 // TODO(paulberry): if adding a setter where there was previously
566 // only a getter, remove "final" modifier.
567 // TODO(paulberry): what if the getter and setter have a type mismatch?
568 throw new UnimplementedError();
569 }
570 }
571
572 /**
573 * Build the implicit top level variable associated with a getter or setter,
574 * and place it in [holder].
575 */
576 PropertyInducingElementImpl buildImplicitTopLevelVariable(
577 String name, UnlinkedExecutableKind kind, ElementHolder holder) {
578 if (holder.getTopLevelVariable(name) == null) {
579 TopLevelVariableElementImpl variable =
580 new TopLevelVariableElementImpl(name, -1);
581 variable.setModifier(Modifier.SYNTHETIC, true);
582 if (kind == UnlinkedExecutableKind.getter) {
583 variable.setModifier(Modifier.FINAL, true);
584 }
585 holder.addTopLevelVariable(variable);
586 return variable;
587 } else {
588 // TODO(paulberry): if adding a setter where there was previously
589 // only a getter, remove "final" modifier.
590 // TODO(paulberry): what if the getter and setter have a type mismatch?
591 throw new UnimplementedError();
592 }
593 }
594
595 /**
596 * Resynthesize an [ImportElement].
597 */
598 ImportElement buildImport(UnlinkedImport serializedImport, int dependency) {
599 bool isSynthetic = serializedImport.isImplicit;
600 // TODO(paulberry): it seems problematic for the offset to be 0 for
601 // non-synthetic imports, since it is used to disambiguate location.
602 ImportElementImpl importElement =
603 new ImportElementImpl(isSynthetic ? -1 : serializedImport.offset);
604 String absoluteUri = summaryResynthesizer.sourceFactory
605 .resolveUri(
606 librarySource, prelinkedLibrary.dependencies[dependency].uri)
607 .uri
608 .toString();
609 importElement.importedLibrary = new LibraryElementHandle(
610 summaryResynthesizer,
611 new ElementLocationImpl.con3(<String>[absoluteUri]));
612 if (isSynthetic) {
613 importElement.setModifier(Modifier.SYNTHETIC, true);
614 } else {
615 importElement.uri = serializedImport.uri;
616 }
617 if (serializedImport.prefixReference != 0) {
618 UnlinkedReference serializedPrefix = prelinkedLibrary.units[0]
619 .unlinked
620 .references[serializedImport.prefixReference];
621 importElement.prefix = new PrefixElementImpl(serializedPrefix.name, -1);
622 }
623 importElement.combinators =
624 serializedImport.combinators.map(buildCombinator).toList();
625 return importElement;
626 }
627
628 /**
629 * Main entry point. Resynthesize the [LibraryElement] and return it.
630 */
631 LibraryElement buildLibrary() {
632 // TODO(paulberry): is it ok to pass -1 for offset and nameLength?
633 LibraryElementImpl libraryElement = new LibraryElementImpl(
634 summaryResynthesizer.context,
635 prelinkedLibrary.units[0].unlinked.libraryName,
636 -1,
637 -1);
638 CompilationUnitElementImpl definingCompilationUnit =
639 new CompilationUnitElementImpl(librarySource.shortName);
640 libraryElement.definingCompilationUnit = definingCompilationUnit;
641 definingCompilationUnit.source = librarySource;
642 definingCompilationUnit.librarySource = librarySource;
643 List<CompilationUnitElement> parts = <CompilationUnitElement>[];
644 UnlinkedUnit unlinkedDefiningUnit = prelinkedLibrary.units[0].unlinked;
645 assert(
646 unlinkedDefiningUnit.parts.length + 1 == prelinkedLibrary.units.length);
647 for (int i = 1; i < prelinkedLibrary.units.length; i++) {
648 CompilationUnitElementImpl part = buildPart(
649 unlinkedDefiningUnit.parts[i - 1].uri,
650 prelinkedLibrary.units[i].unlinked);
651 parts.add(part);
652 }
653 libraryElement.parts = parts;
654 List<ImportElement> imports = <ImportElement>[];
655 for (int i = 0; i < unlinkedDefiningUnit.imports.length; i++) {
656 imports.add(buildImport(unlinkedDefiningUnit.imports[i],
657 prelinkedLibrary.importDependencies[i]));
658 }
659 libraryElement.imports = imports;
660 libraryElement.exports =
661 unlinkedDefiningUnit.exports.map(buildExport).toList();
662 populateUnit(definingCompilationUnit, 0);
663 for (int i = 0; i < parts.length; i++) {
664 populateUnit(parts[i], i + 1);
665 }
666 return libraryElement;
667 }
668
669 /**
670 * Resynthesize a [ParameterElement].
671 */
672 ParameterElement buildParameter(UnlinkedParam serializedParameter) {
673 ParameterElementImpl parameterElement =
674 new ParameterElementImpl(serializedParameter.name, -1);
675 if (serializedParameter.isFunctionTyped) {
676 FunctionElementImpl parameterTypeElement =
677 new FunctionElementImpl('', -1);
678 parameterTypeElement.setModifier(Modifier.SYNTHETIC, true);
679 parameterElement.parameters =
680 serializedParameter.parameters.map(buildParameter).toList();
681 parameterTypeElement.enclosingElement = parameterElement;
682 parameterTypeElement.shareParameters(parameterElement.parameters);
683 if (serializedParameter.type != null) {
684 parameterTypeElement.returnType = buildType(serializedParameter.type);
685 } else {
686 parameterTypeElement.returnType = VoidTypeImpl.instance;
687 }
688 parameterElement.type = new FunctionTypeImpl(parameterTypeElement);
689 } else {
690 parameterElement.type = buildType(serializedParameter.type);
691 if (serializedParameter.hasImplicitType) {
692 parameterElement.setModifier(Modifier.IMPLICIT_TYPE, true);
693 }
694 }
695 switch (serializedParameter.kind) {
696 case UnlinkedParamKind.named:
697 parameterElement.parameterKind = ParameterKind.NAMED;
698 break;
699 case UnlinkedParamKind.positional:
700 parameterElement.parameterKind = ParameterKind.POSITIONAL;
701 break;
702 case UnlinkedParamKind.required:
703 parameterElement.parameterKind = ParameterKind.REQUIRED;
704 break;
705 }
706 return parameterElement;
707 }
708
709 /**
710 * Create, but do not populate, the [CompilationUnitElement] for a part other
711 * than the defining compilation unit.
712 */
713 CompilationUnitElementImpl buildPart(
714 String uri, UnlinkedUnit serializedPart) {
715 Source unitSource =
716 summaryResynthesizer.sourceFactory.resolveUri(librarySource, uri);
717 CompilationUnitElementImpl partUnit =
718 new CompilationUnitElementImpl(unitSource.shortName);
719 partUnit.source = unitSource;
720 partUnit.librarySource = librarySource;
721 partUnit.uri = uri;
722 return partUnit;
723 }
724
725 /**
726 * Build a [DartType] object based on an [UnlinkedTypeRef]. This [DartType]
727 * may refer to elements in other libraries than the library being
728 * deserialized, so handles are used to avoid having to deserialize other
729 * libraries in the process.
730 */
731 DartType buildType(UnlinkedTypeRef type) {
732 if (type.paramReference != 0) {
733 // TODO(paulberry): make this work for generic methods.
734 return currentTypeParameters[
735 currentTypeParameters.length - type.paramReference].type;
736 } else {
737 // TODO(paulberry): handle references to things other than classes (note:
738 // this should only occur in the case of erroneous code).
739 // TODO(paulberry): test reference to something inside a part.
740 // TODO(paulberry): test reference to something inside a part of the
741 // current lib.
742 UnlinkedReference reference =
743 prelinkedUnit.unlinked.references[type.reference];
744 PrelinkedReference referenceResolution =
745 prelinkedUnit.references[type.reference];
746 String referencedLibraryUri;
747 String partUri;
748 if (referenceResolution.dependency != 0) {
749 PrelinkedDependency dependency =
750 prelinkedLibrary.dependencies[referenceResolution.dependency];
751 Source referencedLibrarySource = summaryResynthesizer.sourceFactory
752 .resolveUri(librarySource, dependency.uri);
753 referencedLibraryUri = referencedLibrarySource.uri.toString();
754 PrelinkedLibrary referencedLibrary =
755 summaryResynthesizer.getSummary(referencedLibraryUri);
756 // TODO(paulberry): consider changing Location format so that this is
757 // not necessary (2nd string in location should just be the unit
758 // number).
759 if (referenceResolution.unit != 0) {
760 String uri = referencedLibrary.units[0].unlinked.parts[0].uri;
761 Source partSource = summaryResynthesizer.sourceFactory
762 .resolveUri(referencedLibrarySource, uri);
763 partUri = partSource.uri.toString();
764 } else {
765 partUri = referencedLibraryUri;
766 }
767 } else if (referenceResolution.kind ==
768 PrelinkedReferenceKind.unresolved) {
769 return summaryResynthesizer.typeProvider.undefinedType;
770 } else if (reference.name.isEmpty) {
771 return summaryResynthesizer.typeProvider.dynamicType;
772 } else {
773 referencedLibraryUri = librarySource.uri.toString();
774 if (referenceResolution.unit != 0) {
775 String uri = prelinkedLibrary.units[0].unlinked.parts[
776 referenceResolution.unit - 1].uri;
777 Source partSource =
778 summaryResynthesizer.sourceFactory.resolveUri(librarySource, uri);
779 partUri = partSource.uri.toString();
780 } else {
781 partUri = referencedLibraryUri;
782 }
783 }
784 ResynthesizedType resynthesizedType;
785 ElementLocationImpl location = new ElementLocationImpl.con3(
786 <String>[referencedLibraryUri, partUri, reference.name]);
787 switch (referenceResolution.kind) {
788 case PrelinkedReferenceKind.classOrEnum:
789 resynthesizedType = new ResynthesizedInterfaceTypeImpl(
790 new ClassElementHandle(summaryResynthesizer, location),
791 reference.name,
792 summaryResynthesizer);
793 break;
794 case PrelinkedReferenceKind.typedef:
795 resynthesizedType = new ResynthesizedFunctionTypeImpl(
796 new FunctionTypeAliasElementHandle(
797 summaryResynthesizer, location),
798 reference.name,
799 summaryResynthesizer);
800 break;
801 default:
802 // TODO(paulberry): figure out how to handle this case (which should
803 // only occur in the event of erroneous code).
804 throw new UnimplementedError();
805 }
806 if (type.typeArguments.isNotEmpty) {
807 resynthesizedType._typeArguments =
808 type.typeArguments.map(buildType).toList();
809 }
810 return resynthesizedType;
811 }
812 }
813
814 /**
815 * Resynthesize a [FunctionTypeAliasElement] and place it in the
816 * [unitHolder].
817 */
818 void buildTypedef(UnlinkedTypedef serializedTypedef) {
819 try {
820 currentTypeParameters =
821 serializedTypedef.typeParameters.map(buildTypeParameter).toList();
822 for (int i = 0; i < serializedTypedef.typeParameters.length; i++) {
823 finishTypeParameter(
824 serializedTypedef.typeParameters[i], currentTypeParameters[i]);
825 }
826 FunctionTypeAliasElementImpl functionTypeAliasElement =
827 new FunctionTypeAliasElementImpl(serializedTypedef.name, -1);
828 functionTypeAliasElement.parameters =
829 serializedTypedef.parameters.map(buildParameter).toList();
830 if (serializedTypedef.returnType != null) {
831 functionTypeAliasElement.returnType =
832 buildType(serializedTypedef.returnType);
833 } else {
834 functionTypeAliasElement.returnType = VoidTypeImpl.instance;
835 }
836 functionTypeAliasElement.type =
837 new FunctionTypeImpl.forTypedef(functionTypeAliasElement);
838 functionTypeAliasElement.typeParameters = currentTypeParameters;
839 unitHolder.addTypeAlias(functionTypeAliasElement);
840 } finally {
841 currentTypeParameters = null;
842 }
843 }
844
845 /**
846 * Resynthesize a [TypeParameterElement], handling all parts of its except
847 * its bound.
848 *
849 * The bound is deferred until later since it may refer to other type
850 * parameters that have not been resynthesized yet. To handle the bound,
851 * call [finishTypeParameter].
852 */
853 TypeParameterElement buildTypeParameter(
854 UnlinkedTypeParam serializedTypeParameter) {
855 TypeParameterElementImpl typeParameterElement =
856 new TypeParameterElementImpl(serializedTypeParameter.name, -1);
857 typeParameterElement.type = new TypeParameterTypeImpl(typeParameterElement);
858 return typeParameterElement;
859 }
860
861 /**
862 * Resynthesize a [TopLevelVariableElement] or [FieldElement].
863 */
864 void buildVariable(UnlinkedVariable serializedVariable,
865 [ElementHolder holder]) {
866 if (holder == null) {
867 TopLevelVariableElementImpl element =
868 new TopLevelVariableElementImpl(serializedVariable.name, -1);
869 buildVariableCommonParts(element, serializedVariable);
870 unitHolder.addTopLevelVariable(element);
871 buildImplicitAccessors(element, unitHolder);
872 } else {
873 FieldElementImpl element =
874 new FieldElementImpl(serializedVariable.name, -1);
875 buildVariableCommonParts(element, serializedVariable);
876 holder.addField(element);
877 buildImplicitAccessors(element, holder);
878 }
879 }
880
881 /**
882 * Handle the parts that are common to top level variables and fields.
883 */
884 void buildVariableCommonParts(PropertyInducingElementImpl element,
885 UnlinkedVariable serializedVariable) {
886 element.type = buildType(serializedVariable.type);
887 element.setModifier(Modifier.CONST, serializedVariable.isConst);
888 element.setModifier(Modifier.STATIC, serializedVariable.isStatic);
889 }
890
891 /**
892 * Finish creating a [TypeParameterElement] by deserializing its bound.
893 */
894 void finishTypeParameter(UnlinkedTypeParam serializedTypeParameter,
895 TypeParameterElementImpl typeParameterElement) {
896 if (serializedTypeParameter.bound != null) {
897 typeParameterElement.bound = buildType(serializedTypeParameter.bound);
898 }
899 }
900
901 /**
902 * Populate a [CompilationUnitElement] by deserializing all the elements
903 * contained in it.
904 */
905 void populateUnit(CompilationUnitElementImpl unit, int unitNum) {
906 prelinkedUnit = prelinkedLibrary.units[unitNum];
907 unitHolder = new ElementHolder();
908 UnlinkedUnit unlinkedUnit = prelinkedUnit.unlinked;
909 unlinkedUnit.classes.forEach(buildClass);
910 unlinkedUnit.enums.forEach(buildEnum);
911 unlinkedUnit.executables.forEach(buildExecutable);
912 unlinkedUnit.typedefs.forEach(buildTypedef);
913 unlinkedUnit.variables.forEach(buildVariable);
914 String absoluteUri = unit.source.uri.toString();
915 unit.accessors = unitHolder.accessors;
916 unit.enums = unitHolder.enums;
917 unit.functions = unitHolder.functions;
918 List<FunctionTypeAliasElement> typeAliases = unitHolder.typeAliases;
919 for (FunctionTypeAliasElementImpl typeAlias in typeAliases) {
920 if (typeAlias.isSynthetic) {
921 typeAlias.enclosingElement = unit;
922 }
923 }
924 unit.typeAliases = typeAliases.where((e) => !e.isSynthetic).toList();
925 unit.types = unitHolder.types;
926 unit.topLevelVariables = unitHolder.topLevelVariables;
927 Map<String, Element> elementMap = <String, Element>{};
928 for (ClassElement cls in unit.types) {
929 elementMap[cls.name] = cls;
930 }
931 for (ClassElement cls in unit.enums) {
932 elementMap[cls.name] = cls;
933 }
934 for (FunctionTypeAliasElement typeAlias in unit.functionTypeAliases) {
935 elementMap[typeAlias.name] = typeAlias;
936 }
937 resummarizedElements[absoluteUri] = elementMap;
938 unitHolder = null;
939 prelinkedUnit = null;
940 }
941 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/generated/element_handle.dart ('k') | pkg/analyzer/test/generated/resolver_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698