Chromium Code Reviews| Index: pkg/analyzer/lib/src/summary/resynthesize.dart |
| diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart |
| index dfcaa983bc0c7b83429038ee4f9822755f2c19b8..64d87b45202c2b7e9f1779dbdb1afe3cde941c04 100644 |
| --- a/pkg/analyzer/lib/src/summary/resynthesize.dart |
| +++ b/pkg/analyzer/lib/src/summary/resynthesize.dart |
| @@ -62,8 +62,8 @@ abstract class SummaryResynthesizer extends ElementResynthesizer { |
| * are the first two elements of the element's location (the library URI and |
| * the compilation unit URI). |
| */ |
| - final Map<String, Map<String, CompilationUnitElement>> _resynthesizedUnits = |
| - <String, Map<String, CompilationUnitElement>>{}; |
| + final Map<String, Map<String, CompilationUnitElementImpl>> |
| + _resynthesizedUnits = <String, Map<String, CompilationUnitElementImpl>>{}; |
| /** |
| * Map of top level elements resynthesized from summaries. The three map |
| @@ -125,18 +125,15 @@ abstract class SummaryResynthesizer extends ElementResynthesizer { |
| } |
| return element; |
| } else if (components.length == 3 || components.length == 4) { |
| - Map<String, Map<String, Element>> libraryMap = |
| - _resynthesizedElements[libraryUri]; |
| + Map<String, CompilationUnitElement> libraryMap = |
| + _resynthesizedUnits[libraryUri]; |
| if (libraryMap == null) { |
| getLibraryElement(libraryUri); |
| - libraryMap = _resynthesizedElements[libraryUri]; |
| + libraryMap = _resynthesizedUnits[libraryUri]; |
| assert(libraryMap != null); |
| } |
| - Map<String, Element> compilationUnitElements = libraryMap[components[1]]; |
| - Element element; |
| - if (compilationUnitElements != null) { |
| - element = compilationUnitElements[components[2]]; |
| - } |
| + CompilationUnitElementImpl unitElement = libraryMap[components[1]]; |
| + Element element = unitElement?.getChildNotImpl(components[2]); |
|
Paul Berry
2016/05/19 11:27:30
I have an efficiency concern here. You're replaci
scheglov
2016/05/19 16:54:57
That's fair.
I think that the approach with `getCh
|
| if (element != null && components.length == 4) { |
| String name = components[3]; |
| Element parentElement = element; |
| @@ -1025,8 +1022,8 @@ class _LibraryResynthesizer { |
| * Map of compilation unit elements that have been resynthesized so far. The |
| * key is the URI of the compilation unit. |
| */ |
| - final Map<String, CompilationUnitElement> resynthesizedUnits = |
| - <String, CompilationUnitElement>{}; |
| + final Map<String, CompilationUnitElementImpl> resynthesizedUnits = |
| + <String, CompilationUnitElementImpl>{}; |
| /** |
| * Map of top level elements that have been resynthesized so far. The first |
| @@ -1202,19 +1199,17 @@ class _LibraryResynthesizer { |
| LibraryElement buildLibrary() { |
| // Create LibraryElementImpl. |
| bool hasName = unlinkedUnits[0].libraryName.isNotEmpty; |
| - library = new LibraryElementImpl( |
| + library = new LibraryElementImpl.forSerialized( |
| summaryResynthesizer.context, |
| unlinkedUnits[0].libraryName, |
| hasName ? unlinkedUnits[0].libraryNameOffset : -1, |
| - unlinkedUnits[0].libraryNameLength); |
| + unlinkedUnits[0].libraryNameLength, |
| + new _LibraryResynthesizerContext(this), |
| + unlinkedUnits[0]); |
| // Create the defining unit. |
| _UnitResynthesizer definingUnitResynthesizer = |
| createUnitResynthesizer(0, librarySource, null); |
| CompilationUnitElementImpl definingUnit = definingUnitResynthesizer.unit; |
| - definingUnitResynthesizer.buildDocumentation( |
| - library, unlinkedUnits[0].libraryDocumentationComment); |
| - definingUnitResynthesizer.buildAnnotations( |
| - library, unlinkedUnits[0].libraryAnnotations); |
| library.definingCompilationUnit = definingUnit; |
| definingUnit.source = librarySource; |
| definingUnit.librarySource = librarySource; |
| @@ -1258,7 +1253,6 @@ class _LibraryResynthesizer { |
| for (_UnitResynthesizer partResynthesizer in partResynthesizers) { |
| populateUnit(partResynthesizer); |
| } |
| - BuildLibraryElementUtils.patchTopLevelAccessors(library); |
| // Update delayed Object class references. |
| if (isCoreLibrary) { |
| ClassElement objectElement = library.getType('Object'); |
| @@ -1267,18 +1261,6 @@ class _LibraryResynthesizer { |
| classElement.supertype = objectElement.type; |
| } |
| } |
| - // Compute namespaces. |
| - library.publicNamespace = |
| - new NamespaceBuilder().createPublicNamespaceForLibrary(library); |
| - library.exportNamespace = buildExportNamespace( |
| - library.publicNamespace, linkedLibrary.exportNames); |
| - // Find the entry point. Note: we can't use element.isEntryPoint because |
| - // that will trigger resynthesis of exported libraries. |
| - Element entryPoint = |
| - library.exportNamespace.get(FunctionElement.MAIN_FUNCTION_NAME); |
| - if (entryPoint is FunctionElement) { |
| - library.entryPoint = entryPoint; |
| - } |
| // Create the synthetic element for `loadLibrary`. |
| // Until the client received dart:core and dart:async, we cannot do this, |
| // because the TypeProvider is not fully initialized. So, it is up to the |
| @@ -1370,6 +1352,42 @@ class _LibraryResynthesizer { |
| } |
| } |
| +class _LibraryResynthesizerContext implements LibraryResynthesizerContext { |
|
Paul Berry
2016/05/19 11:27:30
Nit: a doc comment would be helpful here.
scheglov
2016/05/19 16:54:57
Done.
|
| + final _LibraryResynthesizer resynthesizer; |
| + |
| + _LibraryResynthesizerContext(this.resynthesizer); |
| + |
| + @override |
| + Namespace buildExportNamespace() { |
| + LibraryElementImpl library = resynthesizer.library; |
| + return resynthesizer.buildExportNamespace( |
| + library.publicNamespace, resynthesizer.linkedLibrary.exportNames); |
| + } |
| + |
| + @override |
| + Namespace buildPublicNamespace() { |
| + LibraryElementImpl library = resynthesizer.library; |
| + return new NamespaceBuilder().createPublicNamespaceForLibrary(library); |
| + } |
| + |
| + @override |
| + FunctionElement findEntryPoint() { |
| + LibraryElementImpl library = resynthesizer.library; |
| + Element entryPoint = |
| + library.exportNamespace.get(FunctionElement.MAIN_FUNCTION_NAME); |
| + if (entryPoint is FunctionElement) { |
| + return entryPoint; |
| + } |
| + return null; |
| + } |
| + |
| + @override |
| + void patchTopLevelAccessors() { |
| + LibraryElementImpl library = resynthesizer.library; |
| + BuildLibraryElementUtils.patchTopLevelAccessors(library); |
| + } |
| +} |
| + |
| /** |
| * Data structure used during resynthesis to record all the information that is |
| * known about how to resynthesize a single entry in [LinkedUnit.references] |
| @@ -1568,6 +1586,16 @@ class _ResynthesizerContext implements ResynthesizerContext { |
| } |
| @override |
| + UnitExplicitTopLevelAccessors buildTopLevelAccessors() { |
| + return _unitResynthesizer.buildUnitExplicitTopLevelAccessors(); |
| + } |
| + |
| + @override |
| + UnitExplicitTopLevelVariables buildTopLevelVariables() { |
| + return _unitResynthesizer.buildUnitExplicitTopLevelVariables(); |
| + } |
| + |
| + @override |
| DartType resolveTypeRef( |
| EntityRef type, TypeParameterizedElementMixin typeParameterContext, |
| {bool defaultVoid: false, bool instantiateToBoundsAllowed: true}) { |
| @@ -2074,6 +2102,11 @@ class _UnitResynthesizer { |
| break; |
| case UnlinkedExecutableKind.getter: |
| case UnlinkedExecutableKind.setter: |
| + // Top-level accessors are created lazily. |
| + if (isTopLevel) { |
| + break; |
| + } |
| + // Class member accessors. |
| PropertyAccessorElementImpl executableElement = |
| new PropertyAccessorElementImpl.forSerialized( |
| serializedExecutable, enclosingElement); |
| @@ -2085,19 +2118,13 @@ class _UnitResynthesizer { |
| type = executableElement.parameters[0].type; |
| } |
| holder.addAccessor(executableElement); |
| - PropertyInducingElementImpl implicitVariable; |
| - if (isTopLevel) { |
| - implicitVariable = buildImplicitTopLevelVariable(name, kind, holder); |
| - } else { |
| - FieldElementImpl field = buildImplicitField(name, type, kind, holder); |
| - field.static = serializedExecutable.isStatic; |
| - implicitVariable = field; |
| - } |
| - executableElement.variable = implicitVariable; |
| + FieldElementImpl field = buildImplicitField(name, type, kind, holder); |
| + field.static = serializedExecutable.isStatic; |
| + executableElement.variable = field; |
| if (kind == UnlinkedExecutableKind.getter) { |
| - implicitVariable.getter = executableElement; |
| + field.getter = executableElement; |
| } else { |
| - implicitVariable.setter = executableElement; |
| + field.setter = executableElement; |
| } |
| break; |
| default: |
| @@ -2154,33 +2181,12 @@ class _UnitResynthesizer { |
| String name = element.name; |
| DartType type = element.type; |
| PropertyAccessorElementImpl getter = |
| - new PropertyAccessorElementImpl(name, element.nameOffset); |
| - getter.getter = true; |
| - getter.static = element.isStatic; |
| - getter.synthetic = true; |
| - getter.returnType = type; |
| - getter.type = new FunctionTypeImpl(getter); |
| - getter.variable = element; |
| - getter.hasImplicitReturnType = element.hasImplicitType; |
| - holder.addAccessor(getter); |
| - element.getter = getter; |
| + buildImplicitGetter(element, name, type); |
| + holder?.addAccessor(getter); |
| if (!(element.isConst || element.isFinal)) { |
| PropertyAccessorElementImpl setter = |
| - new PropertyAccessorElementImpl(name, element.nameOffset); |
| - setter.setter = true; |
| - setter.static = element.isStatic; |
| - setter.synthetic = true; |
| - setter.parameters = <ParameterElement>[ |
| - new ParameterElementImpl('_$name', element.nameOffset) |
| - ..synthetic = true |
| - ..type = type |
| - ..parameterKind = ParameterKind.REQUIRED |
| - ]; |
| - setter.returnType = VoidTypeImpl.instance; |
| - setter.type = new FunctionTypeImpl(setter); |
| - setter.variable = element; |
| - holder.addAccessor(setter); |
| - element.setter = setter; |
| + buildImplicitSetter(element, name, type); |
| + holder?.addAccessor(setter); |
| } |
| } |
| @@ -2205,24 +2211,39 @@ class _UnitResynthesizer { |
| } |
| } |
| - /** |
| - * Build the implicit top level variable associated with a getter or setter, |
| - * and place it in [holder]. |
| - */ |
| - PropertyInducingElementImpl buildImplicitTopLevelVariable( |
| - String name, UnlinkedExecutableKind kind, ElementHolder holder) { |
| - TopLevelVariableElementImpl variable = holder.getTopLevelVariable(name); |
| - if (variable == null) { |
| - variable = new TopLevelVariableElementImpl(name, -1); |
| - variable.synthetic = true; |
| - variable.final2 = kind == UnlinkedExecutableKind.getter; |
| - holder.addTopLevelVariable(variable); |
| - return variable; |
| - } else { |
| - // TODO(paulberry): what if the getter and setter have a type mismatch? |
| - variable.final2 = false; |
| - return variable; |
| - } |
| + PropertyAccessorElementImpl buildImplicitGetter( |
|
Paul Berry
2016/05/19 11:27:30
Please add a doc comment here.
scheglov
2016/05/19 16:54:57
Done.
|
| + PropertyInducingElementImpl element, String name, DartType type) { |
| + PropertyAccessorElementImpl getter = |
| + new PropertyAccessorElementImpl(name, element.nameOffset); |
| + getter.getter = true; |
| + getter.static = element.isStatic; |
| + getter.synthetic = true; |
| + getter.returnType = type; |
| + getter.type = new FunctionTypeImpl(getter); |
| + getter.variable = element; |
| + getter.hasImplicitReturnType = element.hasImplicitType; |
| + element.getter = getter; |
| + return getter; |
| + } |
| + |
| + PropertyAccessorElementImpl buildImplicitSetter( |
|
Paul Berry
2016/05/19 11:27:30
Ditto.
scheglov
2016/05/19 16:54:57
Done.
|
| + PropertyInducingElementImpl element, String name, DartType type) { |
| + PropertyAccessorElementImpl setter = |
| + new PropertyAccessorElementImpl(name, element.nameOffset); |
| + setter.setter = true; |
| + setter.static = element.isStatic; |
| + setter.synthetic = true; |
| + setter.parameters = <ParameterElement>[ |
| + new ParameterElementImpl('_$name', element.nameOffset) |
| + ..synthetic = true |
| + ..type = type |
| + ..parameterKind = ParameterKind.REQUIRED |
| + ]; |
| + setter.returnType = VoidTypeImpl.instance; |
| + setter.type = new FunctionTypeImpl(setter); |
| + setter.variable = element; |
| + element.setter = setter; |
| + return setter; |
| } |
| /** |
| @@ -2404,9 +2425,10 @@ class _UnitResynthesizer { |
| * Handle the parts that are common to top level variables and fields. |
| */ |
| void buildPropertyIntroducingElementCommonParts( |
| - PropertyInducingElementImpl element, |
| - UnlinkedVariable serializedVariable) { |
| - buildVariableCommonParts(element, serializedVariable); |
| + PropertyInducingElementImpl element, UnlinkedVariable serializedVariable, |
| + {bool isLazilyResynthesized: false}) { |
| + buildVariableCommonParts(element, serializedVariable, |
| + isLazilyResynthesized: isLazilyResynthesized); |
| element.propagatedType = buildLinkedType( |
| serializedVariable.propagatedTypeSlot, |
| _currentTypeParameterizedElement); |
| @@ -2517,27 +2539,89 @@ class _UnitResynthesizer { |
| return typeParameters; |
| } |
| - /** |
| - * Resynthesize a [TopLevelVariableElement] or [FieldElement]. |
| - */ |
| - void buildVariable(UnlinkedVariable serializedVariable, |
| - [ElementHolder holder]) { |
| - if (holder == null) { |
| + UnitExplicitTopLevelAccessors buildUnitExplicitTopLevelAccessors() { |
| + HashMap<String, TopLevelVariableElementImpl> implicitVariables = |
| + new HashMap<String, TopLevelVariableElementImpl>(); |
| + UnitExplicitTopLevelAccessors accessorsData = |
| + new UnitExplicitTopLevelAccessors(); |
| + for (UnlinkedExecutable unlinkedExecutable in unlinkedUnit.executables) { |
| + UnlinkedExecutableKind kind = unlinkedExecutable.kind; |
| + if (kind == UnlinkedExecutableKind.getter || |
| + kind == UnlinkedExecutableKind.setter) { |
| + // name |
| + String name = unlinkedExecutable.name; |
| + if (kind == UnlinkedExecutableKind.setter) { |
| + assert(name.endsWith('=')); |
| + name = name.substring(0, name.length - 1); |
| + } |
| + // create |
| + PropertyAccessorElementImpl accessor = |
| + new PropertyAccessorElementImpl.forSerialized( |
| + unlinkedExecutable, unit); |
| + accessorsData.accessors.add(accessor); |
| + buildExecutableCommonParts(accessor, unlinkedExecutable); |
| + // implicit variable |
| + TopLevelVariableElementImpl variable = implicitVariables[name]; |
| + if (variable == null) { |
| + variable = new TopLevelVariableElementImpl(name, -1); |
| + implicitVariables[name] = variable; |
| + accessorsData.implicitVariables.add(variable); |
| + variable.synthetic = true; |
| + variable.final2 = kind == UnlinkedExecutableKind.getter; |
| + } else { |
| + variable.final2 = false; |
| + } |
| + accessor.variable = variable; |
| + // link |
| + if (kind == UnlinkedExecutableKind.getter) { |
| + variable.getter = accessor; |
| + } else { |
| + variable.setter = accessor; |
| + } |
| + } |
| + } |
| + return accessorsData; |
| + } |
| + |
| + UnitExplicitTopLevelVariables buildUnitExplicitTopLevelVariables() { |
| + UnitExplicitTopLevelVariables variablesData = |
| + new UnitExplicitTopLevelVariables(); |
| + for (UnlinkedVariable unlinkedVariable in unlinkedUnit.variables) { |
| TopLevelVariableElementImpl element; |
| - if (serializedVariable.constExpr != null && serializedVariable.isConst) { |
| + if (unlinkedVariable.constExpr != null && unlinkedVariable.isConst) { |
| ConstTopLevelVariableElementImpl constElement = |
| - new ConstTopLevelVariableElementImpl( |
| - serializedVariable.name, serializedVariable.nameOffset); |
| + new ConstTopLevelVariableElementImpl.forSerialized( |
| + unlinkedVariable, unit); |
| element = constElement; |
| constElement.constantInitializer = |
| - _buildConstExpression(serializedVariable.constExpr); |
| + _buildConstExpression(unlinkedVariable.constExpr); |
| } else { |
| - element = new TopLevelVariableElementImpl( |
| - serializedVariable.name, serializedVariable.nameOffset); |
| + element = new TopLevelVariableElementImpl.forSerialized( |
| + unlinkedVariable, unit); |
| } |
| - buildPropertyIntroducingElementCommonParts(element, serializedVariable); |
| - unitHolder.addTopLevelVariable(element); |
| - buildImplicitAccessors(element, unitHolder); |
| + buildPropertyIntroducingElementCommonParts(element, unlinkedVariable, |
| + isLazilyResynthesized: true); |
| + variablesData.variables.add(element); |
| + // implicit accessors |
| + String name = element.name; |
| + DartType type = element.type; |
| + variablesData.implicitAccessors |
| + .add(buildImplicitGetter(element, name, type)); |
| + if (!(element.isConst || element.isFinal)) { |
| + variablesData.implicitAccessors |
| + .add(buildImplicitSetter(element, name, type)); |
| + } |
| + } |
| + return variablesData; |
| + } |
| + |
| + /** |
| + * Resynthesize a [TopLevelVariableElement] or [FieldElement]. |
| + */ |
| + void buildVariable(UnlinkedVariable serializedVariable, |
| + [ElementHolder holder]) { |
| + if (holder == null) { |
| + throw new UnimplementedError('Must be lazy'); |
| } else { |
| FieldElementImpl element; |
| if (serializedVariable.constExpr != null && |
| @@ -2769,8 +2853,6 @@ class _UnitResynthesizer { |
| unlinkedUnit.enums.forEach(buildEnum); |
| unlinkedUnit.executables.forEach((e) => buildExecutable(e, unit)); |
| unlinkedUnit.typedefs.forEach(buildTypedef); |
| - unlinkedUnit.variables.forEach(buildVariable); |
| - unit.accessors = unitHolder.accessors; |
| unit.enums = unitHolder.enums; |
| unit.functions = unitHolder.functions; |
| List<FunctionTypeAliasElement> typeAliases = unitHolder.typeAliases; |
| @@ -2781,7 +2863,6 @@ class _UnitResynthesizer { |
| } |
| unit.typeAliases = typeAliases.where((e) => !e.isSynthetic).toList(); |
| unit.types = unitHolder.types; |
| - unit.topLevelVariables = unitHolder.topLevelVariables; |
| for (ClassElement cls in unit.types) { |
| elementMap[cls.name] = cls; |
| } |
| @@ -2794,9 +2875,6 @@ class _UnitResynthesizer { |
| for (FunctionElement function in unit.functions) { |
| elementMap[function.name] = function; |
| } |
| - for (PropertyAccessorElementImpl accessor in unit.accessors) { |
| - elementMap[accessor.identifier] = accessor; |
| - } |
| assert(currentTypeParameters.isEmpty); |
| } |