OLD | NEW |
---|---|
(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 } | |
OLD | NEW |