| // Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'package:_fe_analyzer_shared/src/scanner/token_impl.dart'; | |
| import 'package:analyzer/dart/analysis/features.dart'; | |
| import 'package:analyzer/dart/ast/token.dart'; | |
| import 'package:analyzer/dart/ast/visitor.dart'; | |
| import 'package:analyzer/src/dart/ast/ast.dart'; | |
| import 'package:analyzer/src/dart/ast/invokes_super_self.dart'; | |
| import 'package:analyzer/src/dart/ast/token.dart'; | |
| import 'package:analyzer/src/dart/element/element.dart'; | |
| import 'package:analyzer/src/generated/utilities_dart.dart'; | |
| import 'package:analyzer/src/summary2/ast_binary_tokens.dart'; | |
| import 'package:analyzer/src/summary2/library_builder.dart'; | |
| import 'package:analyzer/src/summary2/link.dart'; | |
| import 'package:analyzer/src/utilities/extensions/collection.dart'; | |
| import 'package:analyzer/src/utilities/extensions/object.dart'; | |
| class ElementBuilder { | |
| final LibraryBuilder libraryBuilder; | |
| final _executableElements = <ExecutableElementImpl>[]; | |
| ElementBuilder({required this.libraryBuilder}); | |
| LibraryElementImpl get libraryElement => libraryBuilder.element; | |
| void buildElements({ | |
| required Map<LibraryFragmentImpl, List<FragmentImpl>> topFragments, | |
| required Map<FragmentImpl, List<FragmentImpl>> parentChildFragments, | |
| }) { | |
| _buildTopFragments(topFragments); | |
| _addExtensionTypeRecoveryFragments(parentChildFragments); | |
| _buildInstanceElementMembers(parentChildFragments); | |
| _buildFormalParameterElements(); | |
| } | |
| /// Ensures that every extension type has the representation field and primary | |
| /// constructor fragments expected by element model. | |
| /// | |
| /// Augmentations and invalid declarations can reach this point without those | |
| /// fragments, so this synthesizes recovery fragments before member elements | |
| /// are built. | |
| void _addExtensionTypeRecoveryFragments( | |
| Map<FragmentImpl, List<FragmentImpl>> parentChildFragments, | |
| ) { | |
| for (var extensionType in libraryElement.extensionTypes) { | |
| var firstFragment = extensionType.firstFragment; | |
| var childFragments = parentChildFragments[firstFragment] ??= []; | |
| var hasPrimaryConstructor = childFragments.any( | |
| (fragment) => fragment is ConstructorFragmentImpl && fragment.isPrimary, | |
| ); | |
| if (!hasPrimaryConstructor) { | |
| void prependChild(FragmentImpl child) { | |
| child.enclosingFragment = firstFragment; | |
| childFragments.insert(0, child); | |
| } | |
| prependChild( | |
| ConstructorFragmentImpl(name: 'new') | |
| ..isPrimary = true | |
| ..isConst = true | |
| ..isOriginExtensionTypeRecovery = true | |
| ..typeName = extensionType.name, | |
| ); | |
| prependChild( | |
| FieldFragmentImpl(name: null) | |
| ..isFinal = true | |
| ..isOriginExtensionTypeRecoveryRepresentation = true | |
| ..hasImplicitType = true, | |
| ); | |
| } | |
| } | |
| } | |
| /// Builds elements for formal parameter fragment chains. | |
| /// | |
| /// This runs after fragment chains are formed for constructors, methods, | |
| /// functions, and setters. Building those declaration chains also forms the | |
| /// corresponding formal parameter fragment chains. A formal parameter that | |
| /// starts as regular can later have a field-formal or super-formal formal | |
| /// parameter fragment in the same chain, and the element class must be chosen | |
| /// from the complete formal parameter fragment chain. | |
| void _buildFormalParameterElements() { | |
| for (var element in _executableElements) { | |
| for (var formalParameter in element.firstFragment.formalParameters) { | |
| formalParameter.initElement(); | |
| } | |
| } | |
| } | |
| void _buildInstanceElementMembers( | |
| Map<FragmentImpl, List<FragmentImpl>> parentChildFragments, | |
| ) { | |
| for (var instanceElement in libraryElement.children) { | |
| if (instanceElement is! InstanceElementImpl) { | |
| continue; | |
| } | |
| var childFragments = [ | |
| for (var instanceFragment in instanceElement.fragments) | |
| ...?parentChildFragments[instanceFragment], | |
| ]; | |
| var lastInstanceFragments = <String?, FragmentImpl>{}; | |
| var lastStaticFragments = <String?, FragmentImpl>{}; | |
| for (var fragment in childFragments) { | |
| var isInStaticNamespace = switch (fragment) { | |
| ConstructorFragmentImpl() => true, | |
| FieldFragmentImpl(:var isStatic) => isStatic, | |
| GetterFragmentImpl(:var isStatic) => isStatic, | |
| SetterFragmentImpl(:var isStatic) => isStatic, | |
| MethodFragmentImpl(:var isStatic) => isStatic, | |
| _ => false, | |
| }; | |
| var lastFragments = isInStaticNamespace | |
| ? lastStaticFragments | |
| : lastInstanceFragments; | |
| var lastFragment = lastFragments[fragment.name]; | |
| var fragmentToTrack = fragment; | |
| switch (fragment) { | |
| case FieldFragmentImpl(): | |
| fragmentToTrack = _handleInstanceFieldFragment( | |
| instanceElement, | |
| lastFragment, | |
| fragment, | |
| ); | |
| case GetterFragmentImpl(): | |
| _handleInstanceGetterFragment( | |
| instanceElement, | |
| lastFragment, | |
| fragment, | |
| ); | |
| case SetterFragmentImpl(): | |
| _handleInstanceSetterFragment( | |
| instanceElement, | |
| lastFragment, | |
| fragment, | |
| ); | |
| case MethodFragmentImpl(): | |
| _handleInstanceMethodFragment( | |
| instanceElement, | |
| lastFragment, | |
| fragment, | |
| ); | |
| case ConstructorFragmentImpl(): | |
| _handleInstanceConstructorFragment( | |
| instanceElement as InterfaceElementImpl, | |
| lastFragment, | |
| fragment, | |
| ); | |
| default: | |
| throw UnimplementedError('${fragment.runtimeType}'); | |
| } | |
| lastFragments[fragmentToTrack.name] = fragmentToTrack; | |
| } | |
| // Mark extension type members. | |
| if (instanceElement is ExtensionTypeElementImpl) { | |
| for (var executable in instanceElement.children) { | |
| if (executable case ExecutableElementImpl executable) { | |
| executable.isExtensionTypeMember = true; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| void _buildTopFragments( | |
| Map<LibraryFragmentImpl, List<FragmentImpl>> topFragments, | |
| ) { | |
| var lastFragments = <String?, FragmentImpl>{}; | |
| for (var libraryFragmentEntry in topFragments.entries) { | |
| var libraryFragment = libraryFragmentEntry.key; | |
| for (var fragment in libraryFragmentEntry.value) { | |
| if (fragment is ExtensionFragmentImpl && | |
| fragment.isAugmentation && | |
| fragment.name == null) { | |
| _handleExtensionFragment(libraryFragment, null, fragment); | |
| continue; | |
| } | |
| var lastFragment = lastFragments[fragment.name]; | |
| switch (fragment) { | |
| case ClassFragmentImpl(): | |
| _handleClassFragment(libraryFragment, lastFragment, fragment); | |
| case EnumFragmentImpl(): | |
| _handleEnumFragment(libraryFragment, lastFragment, fragment); | |
| case ExtensionFragmentImpl(): | |
| _handleExtensionFragment(libraryFragment, lastFragment, fragment); | |
| case ExtensionTypeFragmentImpl(): | |
| _handleExtensionTypeFragment( | |
| libraryFragment, | |
| lastFragment, | |
| fragment, | |
| ); | |
| case GetterFragmentImpl(): | |
| _handleTopLevelGetterFragment( | |
| libraryFragment, | |
| lastFragment, | |
| fragment, | |
| ); | |
| case MixinFragmentImpl(): | |
| _handleMixinFragment(libraryFragment, lastFragment, fragment); | |
| case SetterFragmentImpl(): | |
| _handleTopLevelSetterFragment( | |
| libraryFragment, | |
| lastFragment, | |
| fragment, | |
| ); | |
| case TopLevelFunctionFragmentImpl(): | |
| _handleTopLevelFunctionFragment( | |
| libraryFragment, | |
| lastFragment, | |
| fragment, | |
| ); | |
| case TopLevelVariableFragmentImpl(): | |
| _handleTopLevelVariableFragment( | |
| libraryFragment, | |
| lastFragment, | |
| fragment, | |
| ); | |
| case TypeAliasFragmentImpl(): | |
| _handleTypeAliasFragment(libraryFragment, fragment); | |
| default: | |
| throw UnimplementedError('${fragment.runtimeType}'); | |
| } | |
| lastFragments[fragment.name] = fragment; | |
| } | |
| } | |
| } | |
| FieldElementImpl? _fieldElement(FragmentImpl? fragment) { | |
| switch (fragment) { | |
| case FieldFragmentImpl(): | |
| return fragment.element; | |
| case GetterFragmentImpl(): | |
| return fragment.element.variable.tryCast(); | |
| case SetterFragmentImpl(): | |
| return fragment.element.variable.tryCast(); | |
| } | |
| return null; | |
| } | |
| void _handleClassFragment( | |
| LibraryFragmentImpl libraryFragment, | |
| FragmentImpl? lastFragment, | |
| ClassFragmentImpl fragment, | |
| ) { | |
| libraryFragment.addClass(fragment); | |
| if (fragment.isAugmentation && | |
| lastFragment is ClassFragmentImpl && | |
| !lastFragment.isMixinApplication) { | |
| lastFragment.addFragment(fragment); | |
| _linkTypeParameters( | |
| previousFragment: lastFragment, | |
| currentFragment: fragment, | |
| ); | |
| return; | |
| } | |
| var element = ClassElementImpl( | |
| libraryBuilder.references.declareClass(fragment.name), | |
| fragment, | |
| ); | |
| if (fragment.isAugmentation && lastFragment != null) { | |
| element.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| libraryElement.addClass(element); | |
| libraryBuilder.declare(element, element.reference); | |
| } | |
| void _handleEnumFragment( | |
| LibraryFragmentImpl libraryFragment, | |
| FragmentImpl? lastFragment, | |
| EnumFragmentImpl fragment, | |
| ) { | |
| libraryFragment.addEnum(fragment); | |
| if (fragment.isAugmentation && lastFragment is EnumFragmentImpl) { | |
| lastFragment.addFragment(fragment); | |
| _linkTypeParameters( | |
| previousFragment: lastFragment, | |
| currentFragment: fragment, | |
| ); | |
| return; | |
| } | |
| var element = EnumElementImpl( | |
| libraryBuilder.references.declareEnum(fragment.name), | |
| fragment, | |
| ); | |
| if (fragment.isAugmentation && lastFragment != null) { | |
| element.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| libraryElement.addEnum(element); | |
| libraryBuilder.declare(element, element.reference); | |
| } | |
| void _handleExtensionFragment( | |
| LibraryFragmentImpl libraryFragment, | |
| FragmentImpl? lastFragment, | |
| ExtensionFragmentImpl fragment, | |
| ) { | |
| libraryFragment.addExtension(fragment); | |
| if (fragment.isAugmentation && lastFragment is ExtensionFragmentImpl) { | |
| lastFragment.addFragment(fragment); | |
| _linkTypeParameters( | |
| previousFragment: lastFragment, | |
| currentFragment: fragment, | |
| ); | |
| return; | |
| } | |
| var element = ExtensionElementImpl( | |
| libraryBuilder.references.declareExtension(fragment.name), | |
| fragment, | |
| ); | |
| if (fragment.isAugmentation && lastFragment != null) { | |
| element.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| libraryElement.addExtension(element); | |
| libraryBuilder.declare(element, element.reference); | |
| } | |
| void _handleExtensionTypeFragment( | |
| LibraryFragmentImpl libraryFragment, | |
| FragmentImpl? lastFragment, | |
| ExtensionTypeFragmentImpl fragment, | |
| ) { | |
| libraryFragment.addExtensionType(fragment); | |
| if (fragment.isAugmentation && lastFragment is ExtensionTypeFragmentImpl) { | |
| lastFragment.addFragment(fragment); | |
| _linkTypeParameters( | |
| previousFragment: lastFragment, | |
| currentFragment: fragment, | |
| ); | |
| return; | |
| } | |
| var element = ExtensionTypeElementImpl( | |
| libraryBuilder.references.declareExtensionType(fragment.name), | |
| fragment, | |
| ); | |
| if (fragment.isAugmentation && lastFragment != null) { | |
| element.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| libraryElement.addExtensionType(element); | |
| libraryBuilder.declare(element, element.reference); | |
| } | |
| void _handleInstanceConstructorFragment( | |
| InterfaceElementImpl interfaceElement, | |
| FragmentImpl? lastFragment, | |
| ConstructorFragmentImpl fragment, | |
| ) { | |
| var interfaceFragment = fragment.enclosingFragment; | |
| interfaceFragment.addConstructor(fragment); | |
| if (fragment.isAugmentation && lastFragment is ConstructorFragmentImpl) { | |
| lastFragment.addFragment(fragment); | |
| _linkTypeParameters( | |
| previousFragment: lastFragment, | |
| currentFragment: fragment, | |
| ); | |
| _linkFormalParameters( | |
| previousFragment: lastFragment, | |
| currentFragment: fragment, | |
| ); | |
| return; | |
| } | |
| var element = ConstructorElementImpl( | |
| name: fragment.name, | |
| reference: libraryBuilder.references.declareMemberConstructor( | |
| container: interfaceElement.reference, | |
| name: fragment.name, | |
| ), | |
| firstFragment: fragment, | |
| ); | |
| _executableElements.add(element); | |
| if (fragment.isAugmentation && lastFragment != null) { | |
| element.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| interfaceElement.addConstructor(element); | |
| } | |
| /// Adds [fieldFragment] into the element model for [instanceElement]. | |
| /// | |
| /// The returned fragment is the one that should be tracked as the last | |
| /// fragment with this name in its namespace. Usually this is [fieldFragment]. | |
| /// For a synthetic enum `values` field from an augmentation, the synthetic | |
| /// field itself is discarded after its initializer elements are moved into | |
| /// the introductory `values` field, so the introductory `values` fragment is | |
| /// returned instead. | |
| FieldFragmentImpl _handleInstanceFieldFragment( | |
| InstanceElementImpl instanceElement, | |
| FragmentImpl? lastFragment, | |
| FieldFragmentImpl fieldFragment, | |
| ) { | |
| var instanceFragment = fieldFragment.enclosingFragment; | |
| // Move elements of `values` from augmentation to the first fragment. | |
| if (fieldFragment.isOriginEnumValues && | |
| instanceFragment is EnumFragmentImpl && | |
| instanceFragment.previousFragment != null) { | |
| var implicitsMap = libraryBuilder.implicitEnumNodes; | |
| var augmentationImplicit = implicitsMap.remove(instanceFragment)!; | |
| var firstFragment = instanceFragment.element.firstFragment; | |
| var firstImplicit = implicitsMap[firstFragment]!; | |
| firstImplicit.valuesInitializer.addElements( | |
| augmentationImplicit.valuesInitializer.elements2, | |
| ); | |
| return firstImplicit.valuesFragment; | |
| } | |
| instanceFragment.addField(fieldFragment); | |
| FieldElementImpl fieldElement; | |
| var lastFieldElement = _fieldElement(lastFragment); | |
| var lastFieldFragment = lastFieldElement?.lastFragment; | |
| if (fieldFragment.isAugmentation && | |
| lastFieldFragment is FieldFragmentImpl) { | |
| lastFieldFragment.addFragment(fieldFragment); | |
| fieldElement = lastFieldElement!; | |
| } else { | |
| fieldElement = FieldElementImpl( | |
| reference: libraryBuilder.references.declareMemberField( | |
| container: instanceElement.reference, | |
| name: fieldFragment.name, | |
| ), | |
| firstFragment: fieldFragment, | |
| ); | |
| if (fieldFragment.isAugmentation && lastFragment != null) { | |
| fieldElement.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| instanceElement.addField(fieldElement); | |
| } | |
| { | |
| var getterFragment = GetterFragmentImpl(name: fieldFragment.name) | |
| ..isOriginVariable = true | |
| ..isAbstract = fieldFragment.isAbstract | |
| ..isAugmentation = fieldFragment.isAugmentation | |
| ..isComplete = !fieldFragment.isAbstract | |
| ..isStatic = fieldFragment.isStatic; | |
| fieldFragment.inducedGetter = getterFragment; | |
| instanceFragment.addGetter(getterFragment); | |
| // A field augmentation can target a setter-only property, so create | |
| // or append each induced accessor independently. | |
| if (fieldElement.getter case var getterElement?) { | |
| getterElement.lastFragment.addFragment(getterFragment); | |
| } else { | |
| var getterElement = GetterElementImpl( | |
| libraryBuilder.references.declareMemberGetter( | |
| container: instanceElement.reference, | |
| name: fieldFragment.name, | |
| ), | |
| getterFragment, | |
| ); | |
| _executableElements.add(getterElement); | |
| instanceElement.addGetter(getterElement); | |
| fieldElement.getter = getterElement; | |
| getterElement.variable = fieldElement; | |
| } | |
| } | |
| if (fieldFragment.hasSetter) { | |
| var setterFragment = SetterFragmentImpl(name: fieldFragment.name) | |
| ..isOriginVariable = true | |
| ..isAbstract = fieldFragment.isAbstract | |
| ..isAugmentation = fieldFragment.isAugmentation | |
| ..isComplete = !fieldFragment.isAbstract | |
| ..isStatic = fieldFragment.isStatic; | |
| fieldFragment.inducedSetter = setterFragment; | |
| instanceFragment.addSetter(setterFragment); | |
| var valueFragment = FormalParameterFragmentImpl( | |
| name: 'value', | |
| nameOffset: null, | |
| parameterKind: ParameterKind.REQUIRED, | |
| ); | |
| valueFragment.isExplicitlyCovariant = fieldFragment.isExplicitlyCovariant; | |
| setterFragment.formalParameters = [valueFragment]; | |
| // A field augmentation can target a getter-only property, so create | |
| // or append each induced accessor independently. | |
| if (fieldElement.setter case var setterElement?) { | |
| var lastSetterFragment = setterElement.lastFragment; | |
| lastSetterFragment.addFragment(setterFragment); | |
| _linkFormalParameters( | |
| previousFragment: lastSetterFragment, | |
| currentFragment: setterFragment, | |
| ); | |
| } else { | |
| var setterElement = SetterElementImpl( | |
| libraryBuilder.references.declareMemberSetter( | |
| container: instanceElement.reference, | |
| name: fieldFragment.name, | |
| ), | |
| setterFragment, | |
| ); | |
| _executableElements.add(setterElement); | |
| instanceElement.addSetter(setterElement); | |
| fieldElement.setter = setterElement; | |
| setterElement.variable = fieldElement; | |
| } | |
| } | |
| return fieldFragment; | |
| } | |
| void _handleInstanceGetterFragment( | |
| InstanceElementImpl instanceElement, | |
| FragmentImpl? lastFragment, | |
| GetterFragmentImpl getterFragment, | |
| ) { | |
| assert(getterFragment.isOriginDeclaration); | |
| var instanceFragment = | |
| getterFragment.enclosingFragment as InstanceFragmentImpl; | |
| instanceFragment.addGetter(getterFragment); | |
| var lastFieldElement = _fieldElement(lastFragment); | |
| var lastGetterFragment = lastFieldElement?.getter?.lastFragment; | |
| if (getterFragment.isAugmentation && lastGetterFragment != null) { | |
| lastGetterFragment.addFragment(getterFragment); | |
| return; | |
| } | |
| // Not augmentation, create new element. | |
| var getterElement = GetterElementImpl( | |
| libraryBuilder.references.declareMemberGetter( | |
| container: instanceElement.reference, | |
| name: getterFragment.name, | |
| ), | |
| getterFragment, | |
| ); | |
| _executableElements.add(getterElement); | |
| if (getterFragment.isAugmentation && lastFragment != null) { | |
| getterElement.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| instanceElement.addGetter(getterElement); | |
| // `class Enum {}` in `dart:core` declares `int get index` as abstract. | |
| // But the specification says that practically a different class | |
| // implementing `Enum` is used as a superclass, so `index` should be | |
| // considered to have non-abstract implementation. | |
| if (instanceElement is ClassElementImpl && | |
| instanceElement.isDartCoreEnum && | |
| getterFragment.name == 'index') { | |
| getterFragment.isAbstract = false; | |
| } | |
| // If `getter` is already set, this is a compile-time error. | |
| // Reset to `null`, so create a new variable. | |
| if (lastFieldElement != null) { | |
| if (lastFieldElement.getter != null) { | |
| lastFieldElement = null; | |
| } | |
| } | |
| if (lastFieldElement == null) { | |
| var fieldFragment = FieldFragmentImpl(name: getterFragment.name) | |
| ..isOriginGetterSetter = true | |
| ..isStatic = getterFragment.isStatic; | |
| instanceFragment.addField(fieldFragment); | |
| lastFieldElement = FieldElementImpl( | |
| reference: libraryBuilder.references.declareMemberField( | |
| container: instanceElement.reference, | |
| name: getterFragment.name, | |
| ), | |
| firstFragment: fieldFragment, | |
| ); | |
| instanceElement.addField(lastFieldElement); | |
| } | |
| getterElement.variable = lastFieldElement; | |
| lastFieldElement.getter = getterElement; | |
| } | |
| void _handleInstanceMethodFragment( | |
| InstanceElementImpl instanceElement, | |
| FragmentImpl? lastFragment, | |
| MethodFragmentImpl fragment, | |
| ) { | |
| var instanceFragment = fragment.enclosingFragment; | |
| instanceFragment.addMethod(fragment); | |
| if (lastFragment is MethodFragmentImpl && fragment.isAugmentation) { | |
| lastFragment.addFragment(fragment); | |
| _linkTypeParameters( | |
| previousFragment: lastFragment, | |
| currentFragment: fragment, | |
| ); | |
| _linkFormalParameters( | |
| previousFragment: lastFragment, | |
| currentFragment: fragment, | |
| ); | |
| return; | |
| } | |
| var element = MethodElementImpl( | |
| name: fragment.name, | |
| reference: libraryBuilder.references.declareMemberMethod( | |
| container: instanceElement.reference, | |
| name: fragment.lookupName, | |
| ), | |
| firstFragment: fragment, | |
| ); | |
| _executableElements.add(element); | |
| if (fragment.isAugmentation && lastFragment != null) { | |
| element.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| instanceElement.addMethod(element); | |
| } | |
| void _handleInstanceSetterFragment( | |
| InstanceElementImpl instanceElement, | |
| FragmentImpl? lastFragment, | |
| SetterFragmentImpl setterFragment, | |
| ) { | |
| assert(setterFragment.isOriginDeclaration); | |
| var instanceFragment = | |
| setterFragment.enclosingFragment as InstanceFragmentImpl; | |
| instanceFragment.addSetter(setterFragment); | |
| var lastFieldElement = _fieldElement(lastFragment); | |
| var lastSetterFragment = lastFieldElement?.setter?.lastFragment; | |
| if (setterFragment.isAugmentation && lastSetterFragment != null) { | |
| lastSetterFragment.addFragment(setterFragment); | |
| _linkFormalParameters( | |
| previousFragment: lastSetterFragment, | |
| currentFragment: setterFragment, | |
| ); | |
| return; | |
| } | |
| // Not augmentation, create new element. | |
| var setterElement = SetterElementImpl( | |
| libraryBuilder.references.declareMemberSetter( | |
| container: instanceElement.reference, | |
| name: setterFragment.name, | |
| ), | |
| setterFragment, | |
| ); | |
| _executableElements.add(setterElement); | |
| if (setterFragment.isAugmentation && lastFragment != null) { | |
| setterElement.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| instanceElement.addSetter(setterElement); | |
| // If `setter` is already set, this is a compile-time error. | |
| // Reset to `null`, so create a new variable. | |
| if (lastFieldElement != null) { | |
| if (lastFieldElement.setter != null) { | |
| lastFieldElement = null; | |
| } | |
| } | |
| if (lastFieldElement == null) { | |
| var fieldFragment = FieldFragmentImpl(name: setterFragment.name) | |
| ..isOriginGetterSetter = true | |
| ..isStatic = setterFragment.isStatic; | |
| instanceFragment.addField(fieldFragment); | |
| lastFieldElement = FieldElementImpl( | |
| reference: libraryBuilder.references.declareMemberField( | |
| container: instanceElement.reference, | |
| name: setterFragment.name, | |
| ), | |
| firstFragment: fieldFragment, | |
| ); | |
| instanceElement.addField(lastFieldElement); | |
| } | |
| setterElement.variable = lastFieldElement; | |
| lastFieldElement.setter = setterElement; | |
| } | |
| void _handleMixinFragment( | |
| LibraryFragmentImpl libraryFragment, | |
| FragmentImpl? lastFragment, | |
| MixinFragmentImpl fragment, | |
| ) { | |
| libraryFragment.addMixin(fragment); | |
| if (fragment.isAugmentation && lastFragment is MixinFragmentImpl) { | |
| lastFragment.addFragment(fragment); | |
| _linkTypeParameters( | |
| previousFragment: lastFragment, | |
| currentFragment: fragment, | |
| ); | |
| return; | |
| } | |
| var element = MixinElementImpl( | |
| libraryBuilder.references.declareMixin(fragment.name), | |
| fragment, | |
| ); | |
| if (fragment.isAugmentation && lastFragment != null) { | |
| element.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| libraryElement.addMixin(element); | |
| libraryBuilder.declare(element, element.reference); | |
| } | |
| void _handleTopLevelFunctionFragment( | |
| LibraryFragmentImpl libraryFragment, | |
| FragmentImpl? lastFragment, | |
| TopLevelFunctionFragmentImpl fragment, | |
| ) { | |
| libraryFragment.addFunction(fragment); | |
| if (lastFragment is TopLevelFunctionFragmentImpl && | |
| fragment.isAugmentation) { | |
| lastFragment.addFragment(fragment); | |
| _linkTypeParameters( | |
| previousFragment: lastFragment, | |
| currentFragment: fragment, | |
| ); | |
| _linkFormalParameters( | |
| previousFragment: lastFragment, | |
| currentFragment: fragment, | |
| ); | |
| return; | |
| } | |
| var element = TopLevelFunctionElementImpl( | |
| libraryBuilder.references.declareTopLevelFunction(fragment.name), | |
| fragment, | |
| ); | |
| _executableElements.add(element); | |
| if (fragment.isAugmentation && lastFragment != null) { | |
| element.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| libraryElement.addTopLevelFunction(element); | |
| libraryBuilder.declare(element, element.reference); | |
| } | |
| void _handleTopLevelGetterFragment( | |
| LibraryFragmentImpl libraryFragment, | |
| FragmentImpl? lastFragment, | |
| GetterFragmentImpl getterFragment, | |
| ) { | |
| assert(getterFragment.isOriginDeclaration); | |
| libraryFragment.addGetter(getterFragment); | |
| var lastVariableElement = _topLevelVariableElement(lastFragment); | |
| var lastGetterFragment = lastVariableElement?.getter?.lastFragment; | |
| if (getterFragment.isAugmentation && lastGetterFragment != null) { | |
| lastGetterFragment.addFragment(getterFragment); | |
| return; | |
| } | |
| // Not augmentation, create new element. | |
| var getterReference = libraryBuilder.references.declareGetter( | |
| getterFragment.name, | |
| ); | |
| var getterElement = GetterElementImpl(getterReference, getterFragment); | |
| _executableElements.add(getterElement); | |
| if (getterFragment.isAugmentation && lastFragment != null) { | |
| getterElement.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| libraryElement.addGetter(getterElement); | |
| libraryBuilder.declare(getterElement, getterReference); | |
| // If `getter` is already set, this is a compile-time error. | |
| // Reset to `null`, so create a new variable. | |
| if (lastVariableElement != null) { | |
| if (lastVariableElement.getter != null) { | |
| lastVariableElement = null; | |
| } | |
| } | |
| if (lastVariableElement == null) { | |
| var variableFragment = TopLevelVariableFragmentImpl( | |
| name: getterFragment.name, | |
| )..isOriginGetterSetter = true; | |
| libraryFragment.addTopLevelVariable(variableFragment); | |
| lastVariableElement = TopLevelVariableElementImpl( | |
| libraryBuilder.references.declareTopLevelVariable(getterFragment.name), | |
| variableFragment, | |
| ); | |
| libraryElement.addTopLevelVariable(lastVariableElement); | |
| } | |
| getterElement.variable = lastVariableElement; | |
| lastVariableElement.getter = getterElement; | |
| } | |
| void _handleTopLevelSetterFragment( | |
| LibraryFragmentImpl libraryFragment, | |
| FragmentImpl? lastFragment, | |
| SetterFragmentImpl setterFragment, | |
| ) { | |
| assert(setterFragment.isOriginDeclaration); | |
| libraryFragment.addSetter(setterFragment); | |
| var lastVariableElement = _topLevelVariableElement(lastFragment); | |
| var lastSetterFragment = lastVariableElement?.setter?.lastFragment; | |
| if (setterFragment.isAugmentation && lastSetterFragment != null) { | |
| lastSetterFragment.addFragment(setterFragment); | |
| _linkFormalParameters( | |
| previousFragment: lastSetterFragment, | |
| currentFragment: setterFragment, | |
| ); | |
| return; | |
| } | |
| // Not augmentation, create new element. | |
| var setterReference = libraryBuilder.references.declareSetter( | |
| setterFragment.name, | |
| ); | |
| var setterElement = SetterElementImpl(setterReference, setterFragment); | |
| _executableElements.add(setterElement); | |
| if (setterFragment.isAugmentation && lastFragment != null) { | |
| setterElement.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| libraryElement.addSetter(setterElement); | |
| libraryBuilder.declare(setterElement, setterReference); | |
| // If `setter` is already set, this is a compile-time error. | |
| // Reset to `null`, so create a new variable. | |
| if (lastVariableElement != null) { | |
| if (lastVariableElement.setter != null) { | |
| lastVariableElement = null; | |
| } | |
| } | |
| if (lastVariableElement == null) { | |
| var variableFragment = TopLevelVariableFragmentImpl( | |
| name: setterFragment.name, | |
| )..isOriginGetterSetter = true; | |
| libraryFragment.addTopLevelVariable(variableFragment); | |
| lastVariableElement = TopLevelVariableElementImpl( | |
| libraryBuilder.references.declareTopLevelVariable(setterFragment.name), | |
| variableFragment, | |
| ); | |
| libraryElement.addTopLevelVariable(lastVariableElement); | |
| } | |
| setterElement.variable = lastVariableElement; | |
| lastVariableElement.setter = setterElement; | |
| } | |
| void _handleTopLevelVariableFragment( | |
| LibraryFragmentImpl libraryFragment, | |
| FragmentImpl? lastFragment, | |
| TopLevelVariableFragmentImpl variableFragment, | |
| ) { | |
| assert(variableFragment.isOriginDeclaration); | |
| libraryFragment.addTopLevelVariable(variableFragment); | |
| TopLevelVariableElementImpl variableElement; | |
| var lastVariableElement = _topLevelVariableElement(lastFragment); | |
| if (variableFragment.isAugmentation && lastVariableElement != null) { | |
| lastVariableElement.lastFragment.addFragment(variableFragment); | |
| variableElement = lastVariableElement; | |
| } else { | |
| variableElement = TopLevelVariableElementImpl( | |
| libraryBuilder.references.declareTopLevelVariable( | |
| variableFragment.name, | |
| ), | |
| variableFragment, | |
| ); | |
| if (variableFragment.isAugmentation && lastFragment != null) { | |
| variableElement.previousFragmentOfDifferentKind = lastFragment; | |
| } | |
| libraryElement.addTopLevelVariable(variableElement); | |
| } | |
| { | |
| var getterFragment = GetterFragmentImpl(name: variableFragment.name) | |
| ..isOriginVariable = true | |
| ..isAbstract = variableFragment.isAbstract | |
| ..isAugmentation = variableFragment.isAugmentation | |
| ..isComplete = | |
| variableFragment.isExternal || !variableFragment.isAbstract | |
| ..isStatic = true; | |
| variableFragment.inducedGetter = getterFragment; | |
| libraryFragment.addGetter(getterFragment); | |
| // A variable augmentation can target a setter-only property, so create | |
| // or append each induced accessor independently. | |
| if (variableElement.getter case var getterElement?) { | |
| var lastGetterFragment = getterElement.lastFragment; | |
| lastGetterFragment.addFragment(getterFragment); | |
| } else { | |
| var getterReference = libraryBuilder.references.declareGetter( | |
| variableFragment.name, | |
| ); | |
| var getterElement = GetterElementImpl(getterReference, getterFragment); | |
| _executableElements.add(getterElement); | |
| libraryElement.addGetter(getterElement); | |
| libraryBuilder.declare(getterElement, getterReference); | |
| variableElement.getter = getterElement; | |
| getterElement.variable = variableElement; | |
| } | |
| } | |
| if (variableFragment.hasSetter) { | |
| var setterFragment = SetterFragmentImpl(name: variableFragment.name) | |
| ..isOriginVariable = true | |
| ..isAbstract = variableFragment.isAbstract | |
| ..isAugmentation = variableFragment.isAugmentation | |
| ..isComplete = | |
| variableFragment.isExternal || !variableFragment.isAbstract | |
| ..isStatic = true; | |
| variableFragment.inducedSetter = setterFragment; | |
| libraryFragment.addSetter(setterFragment); | |
| var valueFragment = FormalParameterFragmentImpl( | |
| name: 'value', | |
| nameOffset: null, | |
| parameterKind: ParameterKind.REQUIRED, | |
| ); | |
| setterFragment.formalParameters = [valueFragment]; | |
| // A variable augmentation can target a getter-only property, so create | |
| // or append each induced accessor independently. | |
| if (variableElement.setter case var setterElement?) { | |
| var lastSetterFragment = setterElement.lastFragment; | |
| lastSetterFragment.addFragment(setterFragment); | |
| _linkFormalParameters( | |
| previousFragment: lastSetterFragment, | |
| currentFragment: setterFragment, | |
| ); | |
| } else { | |
| var setterReference = libraryBuilder.references.declareSetter( | |
| variableFragment.name, | |
| ); | |
| var setterElement = SetterElementImpl(setterReference, setterFragment); | |
| _executableElements.add(setterElement); | |
| libraryElement.addSetter(setterElement); | |
| libraryBuilder.declare(setterElement, setterReference); | |
| variableElement.setter = setterElement; | |
| setterElement.variable = variableElement; | |
| } | |
| } | |
| } | |
| void _handleTypeAliasFragment( | |
| LibraryFragmentImpl libraryFragment, | |
| TypeAliasFragmentImpl fragment, | |
| ) { | |
| libraryFragment.addTypeAlias(fragment); | |
| var element = TypeAliasElementImpl( | |
| libraryBuilder.references.declareTypeAlias(fragment.name), | |
| fragment, | |
| ); | |
| libraryElement.typeAliases.add(element); | |
| libraryBuilder.declare(element, element.reference); | |
| } | |
| /// Links formal parameter fragments in an executable augmentation chain. | |
| /// | |
| /// Each executable fragment's parameter list is kept chain-complete: if a | |
| /// parameter exists in another fragment of the same executable, missing | |
| /// fragments are represented by `isOriginOtherFragmentOfEnclosing` | |
| /// parameters. Consumers that need the parameters declared by a concrete AST | |
| /// node should filter to `isOriginDeclaration`. | |
| void _linkFormalParameters({ | |
| required ExecutableFragmentImpl previousFragment, | |
| required ExecutableFragmentImpl currentFragment, | |
| }) { | |
| var previousParameters = previousFragment.formalParameters; | |
| var currentParameters = currentFragment.formalParameters; | |
| int getPositionalSize(List<FormalParameterFragmentImpl> fragments) { | |
| return fragments.takeWhile((f) => f.isPositional).length; | |
| } | |
| FormalParameterFragmentImpl createSyntheticFragment( | |
| FormalParameterFragmentImpl template, | |
| ) { | |
| switch (template) { | |
| case FieldFormalParameterFragmentImpl(): | |
| return FieldFormalParameterFragmentImpl( | |
| name: template.name, | |
| nameOffset: null, | |
| parameterKind: template.parameterKind, | |
| privateName: template.privateName, | |
| )..isOriginOtherFragmentOfEnclosing = true; | |
| case SuperFormalParameterFragmentImpl(): | |
| return SuperFormalParameterFragmentImpl( | |
| name: template.name, | |
| nameOffset: null, | |
| parameterKind: template.parameterKind, | |
| )..isOriginOtherFragmentOfEnclosing = true; | |
| default: | |
| return FormalParameterFragmentImpl( | |
| name: template.name, | |
| nameOffset: null, | |
| parameterKind: template.parameterKind, | |
| )..isOriginOtherFragmentOfEnclosing = true; | |
| } | |
| } | |
| void growPrecedingFragmentsWithPositional({ | |
| required int index, | |
| required FormalParameterFragmentImpl template, | |
| }) { | |
| FormalParameterFragmentImpl? previousSyntheticParameter; | |
| var fragmentsToGrow = currentFragment.precedingFragments.reversed; | |
| for (var fragmentToGrow in fragmentsToGrow) { | |
| var syntheticParameter = createSyntheticFragment(template); | |
| var newParameters = fragmentToGrow.formalParameters.toList(); | |
| newParameters.insert(index, syntheticParameter); | |
| fragmentToGrow.formalParameters = newParameters; | |
| previousSyntheticParameter?.addFragment(syntheticParameter); | |
| previousSyntheticParameter = syntheticParameter; | |
| } | |
| } | |
| void growPrecedingFragmentsWithNamed( | |
| FormalParameterFragmentImpl currentParameter, | |
| ) { | |
| FormalParameterFragmentImpl? previousSyntheticParameter; | |
| var fragmentsToGrow = currentFragment.precedingFragments.reversed; | |
| for (var fragmentToGrow in fragmentsToGrow) { | |
| var syntheticParameter = createSyntheticFragment(currentParameter); | |
| fragmentToGrow.formalParameters = [ | |
| ...fragmentToGrow.formalParameters, | |
| syntheticParameter, | |
| ]; | |
| previousSyntheticParameter?.addFragment(syntheticParameter); | |
| previousSyntheticParameter = syntheticParameter; | |
| } | |
| previousSyntheticParameter?.addFragment(currentParameter); | |
| } | |
| var previousPositionalSize = getPositionalSize(previousParameters); | |
| var currentPositionalSize = getPositionalSize(currentParameters); | |
| // Grow all previous fragments if current has more positional parameters. | |
| if (previousPositionalSize < currentPositionalSize) { | |
| for (var i = previousPositionalSize; i < currentPositionalSize; i++) { | |
| growPrecedingFragmentsWithPositional( | |
| index: i, | |
| template: currentParameters[i], | |
| ); | |
| } | |
| } | |
| // Refresh lists after growing. | |
| previousParameters = previousFragment.formalParameters; | |
| currentParameters = currentFragment.formalParameters; | |
| previousPositionalSize = getPositionalSize(previousParameters); | |
| currentPositionalSize = getPositionalSize(currentParameters); | |
| var (previousPositional, previousNamed) = previousParameters.splitAt( | |
| previousPositionalSize, | |
| ); | |
| var (currentPositionalResult, currentNamedResult) = currentParameters | |
| .splitAt(currentPositionalSize); | |
| var hasSyntheticCurrentParameter = false; | |
| // Synthesize missing positional parameters in current fragment. | |
| while (currentPositionalResult.length < previousPositional.length) { | |
| var previousParameter = | |
| previousPositional[currentPositionalResult.length]; | |
| var syntheticParameter = createSyntheticFragment(previousParameter); | |
| currentPositionalResult.add(syntheticParameter); | |
| hasSyntheticCurrentParameter = true; | |
| } | |
| for (var i = 0; i < currentPositionalResult.length; i++) { | |
| previousPositional[i].addFragment(currentPositionalResult[i]); | |
| } | |
| var previousNamedMap = <String?, List<FormalParameterFragmentImpl>>{}; | |
| for (var previousParameter in previousNamed) { | |
| previousNamedMap.add(previousParameter.name, previousParameter); | |
| } | |
| // Link common formal parameters between previous and current fragments. | |
| for (var currentParameter in currentNamedResult) { | |
| var previousParameter = previousNamedMap[currentParameter.name] | |
| ?.removeFirstOrNull(); | |
| if (previousParameter != null) { | |
| previousParameter.addFragment(currentParameter); | |
| } else { | |
| growPrecedingFragmentsWithNamed(currentParameter); | |
| } | |
| } | |
| // Synthesize missing named parameters in current fragment. | |
| for (var previousParameters in previousNamedMap.values) { | |
| for (var previousParameter in previousParameters) { | |
| var syntheticParameter = createSyntheticFragment(previousParameter); | |
| previousParameter.addFragment(syntheticParameter); | |
| currentNamedResult.add(syntheticParameter); | |
| hasSyntheticCurrentParameter = true; | |
| } | |
| } | |
| if (hasSyntheticCurrentParameter) { | |
| currentFragment.formalParameters = [ | |
| ...currentPositionalResult, | |
| ...currentNamedResult, | |
| ]; | |
| } | |
| } | |
| void _linkTypeParameters({ | |
| required FragmentImpl previousFragment, | |
| required FragmentImpl currentFragment, | |
| }) { | |
| List<TypeParameterFragmentImpl> getTypeParameterFragments( | |
| FragmentImpl fragment, | |
| ) { | |
| switch (fragment) { | |
| case InstanceFragmentImpl instance: | |
| return instance.typeParameters; | |
| case ExecutableFragmentImpl executable: | |
| return executable.typeParameters; | |
| default: | |
| throw StateError('${fragment.runtimeType}'); | |
| } | |
| } | |
| void addTypeParameterFragment( | |
| FragmentImpl fragment, | |
| TypeParameterFragmentImpl typeParameter, | |
| ) { | |
| switch (fragment) { | |
| case InstanceFragmentImpl(): | |
| fragment.typeParameters = [...fragment.typeParameters, typeParameter]; | |
| case ExecutableFragmentImpl(): | |
| fragment.typeParameters = [...fragment.typeParameters, typeParameter]; | |
| default: | |
| throw StateError('${fragment.runtimeType}'); | |
| } | |
| } | |
| var previousTypeParameters = getTypeParameterFragments(previousFragment); | |
| var currentTypeParameters = getTypeParameterFragments(currentFragment); | |
| // Grow all previous fragments if current fragment has more type parameters. | |
| if (previousTypeParameters.length < currentTypeParameters.length) { | |
| var fragmentsToGrow = currentFragment.precedingFragments.reversed; | |
| for ( | |
| var i = previousTypeParameters.length; | |
| i < currentTypeParameters.length; | |
| i++ | |
| ) { | |
| var name = currentTypeParameters[i].name; | |
| TypeParameterFragmentImpl? previousSyntheticTypeParameter; | |
| for (var fragmentToGrow in fragmentsToGrow) { | |
| var syntheticTypeParameter = TypeParameterFragmentImpl(name: name) | |
| ..isOriginOtherFragmentOfEnclosing = true; | |
| addTypeParameterFragment(fragmentToGrow, syntheticTypeParameter); | |
| if (previousSyntheticTypeParameter == null) { | |
| TypeParameterElementImpl(firstFragment: syntheticTypeParameter); | |
| } else { | |
| previousSyntheticTypeParameter.addFragment(syntheticTypeParameter); | |
| } | |
| previousSyntheticTypeParameter = syntheticTypeParameter; | |
| } | |
| } | |
| } | |
| // Synthesize missing type parameters in current fragment. | |
| if (previousTypeParameters.length > currentTypeParameters.length) { | |
| for ( | |
| var i = currentTypeParameters.length; | |
| i < previousTypeParameters.length; | |
| i++ | |
| ) { | |
| addTypeParameterFragment( | |
| currentFragment, | |
| TypeParameterFragmentImpl(name: previousTypeParameters[i].name) | |
| ..isOriginOtherFragmentOfEnclosing = true, | |
| ); | |
| } | |
| } | |
| // Refresh lists after growing. | |
| previousTypeParameters = getTypeParameterFragments(previousFragment); | |
| currentTypeParameters = getTypeParameterFragments(currentFragment); | |
| for (var i = 0; i < previousTypeParameters.length; i++) { | |
| previousTypeParameters[i].addFragment(currentTypeParameters[i]); | |
| } | |
| } | |
| TopLevelVariableElementImpl? _topLevelVariableElement( | |
| FragmentImpl? fragment, | |
| ) { | |
| switch (fragment) { | |
| case TopLevelVariableFragmentImpl(): | |
| return fragment.element; | |
| case GetterFragmentImpl(): | |
| return fragment.element.variable.tryCast(); | |
| case SetterFragmentImpl(): | |
| return fragment.element.variable.tryCast(); | |
| } | |
| return null; | |
| } | |
| } | |
| class FragmentBuilder extends ThrowingAstVisitor2<void> { | |
| final LibraryBuilder _libraryBuilder; | |
| final LibraryFragmentImpl _libraryFragment; | |
| var _exportDirectiveIndex = 0; | |
| var _importDirectiveIndex = 0; | |
| var _partDirectiveIndex = 0; | |
| _EnclosingContext _enclosingContext; | |
| FragmentBuilder({ | |
| required LibraryBuilder libraryBuilder, | |
| required LibraryFragmentImpl libraryFragment, | |
| }) : _libraryBuilder = libraryBuilder, | |
| _libraryFragment = libraryFragment, | |
| _enclosingContext = _EnclosingContext(fragment: libraryFragment); | |
| Linker get _linker => _libraryBuilder.linker; | |
| void buildDeclarationFragments(CompilationUnit unit) { | |
| unit.declarations2.accept2(this); | |
| } | |
| /// Builds exports and imports, metadata into [_libraryFragment]. | |
| void buildDirectives(CompilationUnitImpl unit) { | |
| unit.directives.accept2(this); | |
| } | |
| /// Updates metadata and documentation for [_libraryBuilder]. | |
| /// | |
| /// This method must be invoked after [buildDirectives]. | |
| void buildLibraryMetadata(CompilationUnitImpl unit) { | |
| var libraryElement = _libraryBuilder.element; | |
| // Prefer the actual library directive. | |
| var libraryDirective = unit.directives | |
| .whereType<LibraryDirectiveImpl>() | |
| .firstOrNull; | |
| if (libraryDirective != null) { | |
| libraryDirective.element = libraryElement; | |
| libraryElement.metadata = _buildMetadata(libraryDirective.metadata); | |
| return; | |
| } | |
| // Otherwise use the first directive. | |
| var firstDirective = unit.directives.firstOrNull; | |
| if (firstDirective != null) { | |
| MetadataImpl? firstDirectiveMetadata; | |
| switch (firstDirective) { | |
| case ExportDirectiveImpl(): | |
| firstDirectiveMetadata = firstDirective.libraryExport?.metadata; | |
| case ImportDirectiveImpl(): | |
| firstDirectiveMetadata = firstDirective.libraryImport?.metadata; | |
| case PartDirectiveImpl(): | |
| firstDirectiveMetadata = firstDirective.partInclude?.metadata; | |
| case LibraryDirectiveImpl(): | |
| // Impossible, since there is no library directive. | |
| break; | |
| case PartOfDirectiveImpl(): | |
| // Can only occur in erroneous code (this is the defining | |
| // compilation unit) | |
| break; | |
| } | |
| if (firstDirectiveMetadata != null) { | |
| libraryElement.metadata = firstDirectiveMetadata; | |
| } | |
| } | |
| } | |
| @override | |
| void visitBlockClassBody(BlockClassBody node) { | |
| node.members.accept2(this); | |
| } | |
| @override | |
| void visitClassDeclaration(covariant ClassDeclarationImpl node) { | |
| var nameToken = node.namePart.typeName; | |
| var fragmentName = _getFragmentName(nameToken); | |
| var fragment = ClassFragmentImpl(name: fragmentName); | |
| fragment.isAbstract = node.abstractKeyword != null; | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.isBase = node.baseKeyword != null; | |
| fragment.isFinal = node.finalKeyword != null; | |
| fragment.isInterface = node.interfaceKeyword != null; | |
| fragment.isMixinClass = node.mixinKeyword != null; | |
| fragment.isSealed = node.sealedKeyword != null; | |
| fragment.hasExtendsClause = node.extendsClause != null; | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| _libraryBuilder.addTopFragment(_libraryFragment, fragment); | |
| var holder = _EnclosingContext(fragment: fragment); | |
| _withEnclosing(holder, () { | |
| node.namePart.accept2(this); | |
| node.body.accept2(this); | |
| }); | |
| fragment.typeParameters = holder.typeParameters; | |
| node.extendsClause?.accept2(this); | |
| node.withClause?.accept2(this); | |
| node.implementsClause?.accept2(this); | |
| } | |
| @override | |
| void visitClassTypeAlias(covariant ClassTypeAliasImpl node) { | |
| var nameToken = node.name; | |
| var fragmentName = _getFragmentName(nameToken); | |
| var fragment = ClassFragmentImpl(name: fragmentName); | |
| fragment.isAbstract = node.abstractKeyword != null; | |
| fragment.isBase = node.baseKeyword != null; | |
| fragment.isFinal = node.finalKeyword != null; | |
| fragment.isInterface = node.interfaceKeyword != null; | |
| fragment.isMixinApplication = true; | |
| fragment.isMixinClass = node.mixinKeyword != null; | |
| fragment.isSealed = node.sealedKeyword != null; | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| _libraryBuilder.addTopFragment(_libraryFragment, fragment); | |
| var holder = _EnclosingContext(fragment: fragment); | |
| _withEnclosing(holder, () { | |
| var typeParameters = node.typeParameters; | |
| if (typeParameters != null) { | |
| typeParameters.accept2(this); | |
| fragment.typeParameters = holder.typeParameters; | |
| } | |
| }); | |
| node.superclass.accept2(this); | |
| node.withClause.accept2(this); | |
| node.implementsClause?.accept2(this); | |
| } | |
| @override | |
| void visitConstructorDeclaration(covariant ConstructorDeclarationImpl node) { | |
| var fragmentName = _getFragmentName(node.name) ?? 'new'; | |
| var fragment = ConstructorFragmentImpl(name: fragmentName); | |
| fragment.isOriginDeclaration = true; | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.isConst = node.constKeyword != null; | |
| fragment.isExternal = node.externalKeyword != null; | |
| fragment.isFactory = node.factoryKeyword != null; | |
| fragment.isRedirecting = | |
| node.factoryRedirectionTarget != null || | |
| node.initializers.any((e) => e is RedirectingConstructorInvocation); | |
| fragment.isComplete = node.isComplete; | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| fragment.typeName = node.typeName2?.lexeme; | |
| if (_enclosingContext.fragment is EnumFragmentImpl && | |
| fragment.isGenerative && | |
| _libraryBuilder.element.featureSet.isEnabled( | |
| Feature.primary_constructors, | |
| )) { | |
| fragment.isConst = true; | |
| } | |
| if (fragment.isConst || fragment.isFactory) { | |
| fragment.constantInitializers = node.initializers; | |
| } | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| _addChildFragment(fragment); | |
| _buildExecutableElementChildren( | |
| fragment: fragment, | |
| formalParameters: node.parameters, | |
| ); | |
| } | |
| @override | |
| void visitEmptyClassBody(EmptyClassBody node) {} | |
| @override | |
| void visitEnumDeclaration(covariant EnumDeclarationImpl node) { | |
| var nameToken = node.namePart.typeName; | |
| var fragmentName = _getFragmentName(nameToken); | |
| var fragment = EnumFragmentImpl(name: fragmentName); | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| _libraryBuilder.addTopFragment(_libraryFragment, fragment); | |
| node.withClause?.accept2(this); | |
| node.implementsClause?.accept2(this); | |
| var holder = _EnclosingContext(fragment: fragment); | |
| _withEnclosing(holder, () { | |
| // Build fields for all enum constants. | |
| var valuesElements = <UnqualifiedNameExpressionImpl>[]; | |
| var valuesNames = <String>{}; | |
| for (var constant in node.body.constants) { | |
| var nameToken = constant.name; | |
| var name = nameToken.lexeme; | |
| var field = FieldFragmentImpl(name: _getFragmentName(nameToken)) | |
| ..hasImplicitType = true | |
| ..hasInitializer = true | |
| ..isAugmentation = constant.augmentKeyword != null | |
| ..isConst = true | |
| ..isEnumConstant = true | |
| ..isOriginDeclaration = true | |
| ..isStatic = true; | |
| field.metadata = _buildMetadata(constant.metadata); | |
| var constantArguments = constant.arguments; | |
| var constructorSelector = constantArguments?.constructorSelector; | |
| var constructorName = constructorSelector?.name2.lexeme; | |
| var initializer = ConstructorInvocationImpl( | |
| keyword: null, | |
| constructorReference: ConstructorReference2Impl( | |
| typeReference: ConstructorTypeReferenceImpl( | |
| importPrefix: null, | |
| name: StringToken(TokenType.STRING, fragment.name ?? '', -1), | |
| typeArguments: constantArguments?.typeArguments, | |
| ), | |
| selector: constructorName != null | |
| ? ConstructorSelectorImpl.v2( | |
| period: Token(TokenType.PERIOD, -1), | |
| name2: StringToken(TokenType.STRING, constructorName, -1), | |
| ) | |
| : null, | |
| ), | |
| argumentList: | |
| constantArguments?.argumentList ?? | |
| ArgumentListImpl( | |
| leftParenthesis: Tokens.openParenthesis(), | |
| arguments2: [], | |
| rightParenthesis: Tokens.closeParenthesis(), | |
| ), | |
| typeArguments: null, | |
| ); | |
| var variableDeclaration = VariableDeclarationImpl( | |
| comment: null, | |
| metadata: [], | |
| name: StringToken(TokenType.STRING, name, -1), | |
| equals: Tokens.eq(), | |
| initializer2: initializer, | |
| ); | |
| constant.declaredFragment = field; | |
| variableDeclaration.declaredFragment = field; | |
| VariableDeclarationListImpl( | |
| comment: null, | |
| metadata: null, | |
| lateKeyword: null, | |
| keyword: null, | |
| type: null, | |
| variables: [variableDeclaration], | |
| ); | |
| _linker.setFragmentNode(field, variableDeclaration); | |
| _addChildFragment(field); | |
| AstNodeImpl.linkNodeTokens(initializer); | |
| field.constantInitializer2 = initializer; | |
| valuesElements.add( | |
| UnqualifiedNameExpressionImpl( | |
| name: StringToken(TokenType.STRING, name, -1), | |
| ), | |
| ); | |
| valuesNames.add(name); | |
| } | |
| // Build the 'values' field. | |
| var valuesField = FieldFragmentImpl(name: 'values') | |
| ..isConst = true | |
| ..isStatic = true | |
| ..isOriginEnumValues = true; | |
| var initializer = ListLiteralImpl( | |
| constKeyword: null, | |
| typeArguments: null, | |
| leftBracket: Tokens.openSquareBracket(), | |
| elements2: valuesElements, | |
| rightBracket: Tokens.closeSquareBracket(), | |
| ); | |
| AstNodeImpl.linkNodeTokens(initializer); | |
| valuesField.constantInitializer2 = initializer; | |
| var variableDeclaration = VariableDeclarationImpl( | |
| comment: null, | |
| metadata: [], | |
| name: StringToken(TokenType.STRING, 'values', -1), | |
| equals: Tokens.eq(), | |
| initializer2: initializer, | |
| ); | |
| var valuesTypeNode = NamedTypeImpl( | |
| importPrefix: null, | |
| name: StringToken(TokenType.STRING, 'List', -1), | |
| typeArguments: TypeArgumentListImpl( | |
| leftBracket: Tokens.lt(), | |
| arguments: [ | |
| NamedTypeImpl( | |
| importPrefix: null, | |
| name: StringToken(TokenType.STRING, fragment.name ?? '', -1), | |
| typeArguments: null, | |
| question: null, | |
| ), | |
| ], | |
| rightBracket: Tokens.gt(), | |
| ), | |
| question: null, | |
| ); | |
| VariableDeclarationListImpl( | |
| comment: null, | |
| metadata: null, | |
| lateKeyword: null, | |
| keyword: Tokens.const_(), | |
| variables: [variableDeclaration], | |
| type: valuesTypeNode, | |
| ); | |
| _linker.setFragmentNode(valuesField, variableDeclaration); | |
| _addChildFragment(valuesField); | |
| _libraryBuilder.implicitEnumNodes[fragment] = ImplicitEnumNodes( | |
| fragment: fragment, | |
| valuesTypeNode: valuesTypeNode, | |
| valuesNode: variableDeclaration, | |
| valuesFragment: valuesField, | |
| valuesNames: valuesNames, | |
| valuesInitializer: initializer, | |
| ); | |
| node.namePart.accept2(this); | |
| for (var member in node.body.members) { | |
| member.accept2(this); | |
| } | |
| }); | |
| fragment.typeParameters = holder.typeParameters; | |
| } | |
| @override | |
| void visitExportDirective(covariant ExportDirectiveImpl node) { | |
| var index = _exportDirectiveIndex++; | |
| var exportElement = _libraryFragment.libraryExports[index]; | |
| exportElement.metadata = _buildMetadata(node.metadata); | |
| node.libraryExport = exportElement; | |
| } | |
| @override | |
| void visitExtendsClause(ExtendsClause node) { | |
| node.superclass.accept2(this); | |
| } | |
| @override | |
| void visitExtensionDeclaration(covariant ExtensionDeclarationImpl node) { | |
| var nameToken = node.name; | |
| var fragmentName = _getFragmentName(nameToken); | |
| var fragment = ExtensionFragmentImpl(name: fragmentName); | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| _libraryBuilder.addTopFragment(_libraryFragment, fragment); | |
| var holder = _EnclosingContext(fragment: fragment); | |
| _withEnclosing(holder, () { | |
| node.typeParameters?.accept2(this); | |
| for (var member in node.body.members) { | |
| member.accept2(this); | |
| } | |
| }); | |
| fragment.typeParameters = holder.typeParameters; | |
| node.onClause?.accept2(this); | |
| } | |
| @override | |
| void visitExtensionOnClause(ExtensionOnClause node) { | |
| node.extendedType.accept2(this); | |
| } | |
| @override | |
| void visitExtensionTypeDeclaration( | |
| covariant ExtensionTypeDeclarationImpl node, | |
| ) { | |
| var nameToken = node.namePart.typeName; | |
| var fragmentName = _getFragmentName(nameToken); | |
| var fragment = ExtensionTypeFragmentImpl(name: fragmentName); | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| _libraryBuilder.addTopFragment(_libraryFragment, fragment); | |
| var holder = _EnclosingContext(fragment: fragment); | |
| _withEnclosing(holder, () { | |
| node.namePart.accept2(this); | |
| node.body.accept2(this); | |
| }); | |
| fragment.typeParameters = holder.typeParameters; | |
| node.implementsClause?.accept2(this); | |
| } | |
| @override | |
| void visitFieldDeclaration(covariant FieldDeclarationImpl node) { | |
| var metadata = _buildMetadata(node.metadata); | |
| for (var variable in node.fields.variables) { | |
| var nameToken = variable.name; | |
| var fragment = FieldFragmentImpl(name: _getFragmentName(nameToken)); | |
| fragment.hasInitializer = variable.initializer2 != null; | |
| fragment.isAbstract = node.abstractKeyword != null; | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.isConst = node.fields.isConst; | |
| fragment.isExplicitlyCovariant = node.covariantKeyword != null; | |
| fragment.isExternal = node.externalKeyword != null; | |
| fragment.isFinal = node.fields.isFinal; | |
| fragment.isLate = node.fields.isLate; | |
| fragment.isOriginDeclaration = true; | |
| fragment.isStatic = node.isStatic; | |
| fragment.metadata = metadata; | |
| if (variable.initializer2 case var initializer?) { | |
| if (node.fields.isConst) { | |
| fragment.constantInitializer2 = initializer; | |
| } else if (node.fields.isFinal && !node.isStatic) { | |
| fragment.constantInitializer2 = initializer; | |
| _libraryBuilder.finalInstanceFields.add(fragment); | |
| } | |
| } | |
| if (node.fields.type == null) { | |
| fragment.hasImplicitType = true; | |
| } | |
| variable.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, variable); | |
| _addChildFragment(fragment); | |
| } | |
| node.fields.type?.accept2(this); | |
| } | |
| @override | |
| void visitFieldFormalParameter(covariant FieldFormalParameterImpl node) { | |
| var nameToken = node.name; | |
| var name2 = _getFragmentName(nameToken); | |
| // If this is a private named parameter, then use the corresponding public | |
| // name as the element name and store the original private name separately. | |
| String? privateName; | |
| if (name2 != null && | |
| node.isNamed && | |
| _libraryBuilder.element.featureSet.isEnabled( | |
| Feature.private_named_parameters, | |
| )) { | |
| var publicName = correspondingPublicName(name2); | |
| if (publicName != null) { | |
| privateName = name2; | |
| name2 = publicName; | |
| } | |
| } | |
| var fragment = FieldFormalParameterFragmentImpl( | |
| name: name2, | |
| nameOffset: null, | |
| parameterKind: node.kind, | |
| privateName: privateName, | |
| ); | |
| _linker.setFragmentNode(fragment, node); | |
| _enclosingContext.addParameter(fragment); | |
| fragment.constantInitializer2 = node.defaultClause?.value2; | |
| fragment.hasImplicitType = | |
| node.type == null && node.functionTypedSuffix == null; | |
| fragment.isOriginDeclaration = true; | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = fragment; | |
| // TODO(scheglov): check that we don't set reference for parameters | |
| _buildFunctionTypedParameterSuffix(fragment, node.functionTypedSuffix); | |
| node.type?.accept2(this); | |
| } | |
| @override | |
| void visitFormalParameterList(FormalParameterList node) { | |
| node.requiredPositionalFormalParameters.accept2(this); | |
| node.delimitedFormalParameters?.formalParameters.accept2(this); | |
| } | |
| @override | |
| void visitFunctionDeclaration(covariant FunctionDeclarationImpl node) { | |
| var nameToken = node.name; | |
| var name2 = _getFragmentName(nameToken); | |
| var functionExpression = node.functionExpression; | |
| var body = functionExpression.body; | |
| ExecutableFragmentImpl executableFragment; | |
| if (node.isGetter) { | |
| var getterFragment = GetterFragmentImpl(name: name2); | |
| getterFragment.isAugmentation = node.augmentKeyword != null; | |
| getterFragment.isOriginDeclaration = true; | |
| getterFragment.isStatic = true; | |
| getterFragment.enclosingFragment = _libraryFragment; | |
| executableFragment = getterFragment; | |
| _libraryBuilder.addTopFragment(_libraryFragment, getterFragment); | |
| } else if (node.isSetter) { | |
| var setterFragment = SetterFragmentImpl(name: name2); | |
| setterFragment.isAugmentation = node.augmentKeyword != null; | |
| setterFragment.isOriginDeclaration = true; | |
| setterFragment.isStatic = true; | |
| setterFragment.enclosingFragment = _libraryFragment; | |
| executableFragment = setterFragment; | |
| _libraryBuilder.addTopFragment(_libraryFragment, setterFragment); | |
| } else { | |
| var fragment = TopLevelFunctionFragmentImpl(name: name2); | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.isOriginDeclaration = true; | |
| fragment.isStatic = true; | |
| executableFragment = fragment; | |
| _libraryBuilder.addTopFragment(_libraryFragment, fragment); | |
| } | |
| executableFragment.hasImplicitReturnType = node.returnType == null; | |
| executableFragment.isAsynchronous = body.isAsynchronous; | |
| executableFragment.isExternal = node.externalKeyword != null; | |
| executableFragment.isGenerator = body.isGenerator; | |
| executableFragment.isComplete = node.isComplete; | |
| executableFragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = executableFragment; | |
| _linker.setFragmentNode(executableFragment, node); | |
| _buildExecutableElementChildren( | |
| fragment: executableFragment, | |
| formalParameters: functionExpression.parameters, | |
| typeParameters: functionExpression.typeParameters, | |
| ); | |
| node.returnType?.accept2(this); | |
| } | |
| @override | |
| void visitFunctionTypeAlias(covariant FunctionTypeAliasImpl node) { | |
| var nameToken = node.name; | |
| var name2 = _getFragmentName(nameToken); | |
| var fragment = TypeAliasFragmentImpl( | |
| name: name2, | |
| firstTokenOffset: node.offset, | |
| ); | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| _libraryBuilder.addTopFragment(_libraryFragment, fragment); | |
| var holder = _EnclosingContext(fragment: fragment); | |
| _withEnclosing(holder, () { | |
| node.typeParameters?.accept2(this); | |
| node.returnType?.accept2(this); | |
| node.parameters.accept2(this); | |
| }); | |
| fragment.typeParameters = holder.typeParameters; | |
| for (var formalParameter in holder.formalParameters) { | |
| formalParameter.initElement(); | |
| } | |
| } | |
| @override | |
| void visitGenericFunctionType(covariant GenericFunctionTypeImpl node) { | |
| var fragment = GenericFunctionTypeFragmentImpl(); | |
| _libraryFragment.encloseElement(fragment); | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| var holder = _EnclosingContext(fragment: fragment); | |
| _withEnclosing(holder, () { | |
| node.typeParameters?.accept2(this); | |
| fragment.typeParameters = holder.typeParameters; | |
| node.parameters.accept2(this); | |
| fragment.formalParameters = holder.formalParameters; | |
| }); | |
| GenericFunctionTypeElementImpl(fragment); | |
| node.returnType?.accept2(this); | |
| } | |
| @override | |
| void visitGenericTypeAlias(covariant GenericTypeAliasImpl node) { | |
| var nameToken = node.name; | |
| var name2 = _getFragmentName(nameToken); | |
| var fragment = TypeAliasFragmentImpl( | |
| name: name2, | |
| firstTokenOffset: node.offset, | |
| ); | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| _libraryBuilder.addTopFragment(_libraryFragment, fragment); | |
| var holder = _EnclosingContext(fragment: fragment); | |
| _withEnclosing(holder, () { | |
| node.typeParameters?.accept2(this); | |
| }); | |
| fragment.typeParameters = holder.typeParameters; | |
| node.type.accept2(this); | |
| } | |
| @override | |
| void visitImplementsClause(ImplementsClause node) { | |
| node.interfaces.accept2(this); | |
| } | |
| @override | |
| void visitImportDirective(covariant ImportDirectiveImpl node) { | |
| var index = _importDirectiveIndex++; | |
| var importElement = _libraryFragment.libraryImports[index]; | |
| importElement.metadata = _buildMetadata(node.metadata); | |
| node.libraryImport = importElement; | |
| } | |
| @override | |
| void visitLibraryDirective(covariant LibraryDirectiveImpl node) {} | |
| @override | |
| void visitMethodDeclaration(covariant MethodDeclarationImpl node) { | |
| var nameToken = node.name; | |
| ExecutableFragmentImpl executableFragment; | |
| if (node.isGetter) { | |
| var fragment = GetterFragmentImpl(name: _getFragmentName(nameToken)); | |
| fragment.isAbstract = !node.isComplete; | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.isOriginDeclaration = true; | |
| fragment.isStatic = node.isStatic; | |
| _addChildFragment(fragment); | |
| executableFragment = fragment; | |
| } else if (node.isSetter) { | |
| var fragment = SetterFragmentImpl(name: _getFragmentName(nameToken)); | |
| fragment.isAbstract = !node.isComplete; | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.isOriginDeclaration = true; | |
| fragment.isStatic = node.isStatic; | |
| _addChildFragment(fragment); | |
| executableFragment = fragment; | |
| } else { | |
| var fragment = MethodFragmentImpl(name: _getFragmentName(nameToken)); | |
| fragment.isAbstract = !node.isComplete; | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.isOriginDeclaration = true; | |
| fragment.isStatic = node.isStatic; | |
| _addChildFragment(fragment); | |
| executableFragment = fragment; | |
| } | |
| executableFragment.hasImplicitReturnType = node.returnType == null; | |
| executableFragment.invokesSuperSelf = node.invokesSuperSelf; | |
| executableFragment.isAsynchronous = node.body.isAsynchronous; | |
| executableFragment.isExternal = | |
| node.externalKeyword != null || node.body is NativeFunctionBody; | |
| executableFragment.isGenerator = node.body.isGenerator; | |
| executableFragment.isComplete = node.isComplete; | |
| executableFragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = executableFragment; | |
| _linker.setFragmentNode(executableFragment, node); | |
| _buildExecutableElementChildren( | |
| fragment: executableFragment, | |
| formalParameters: node.parameters, | |
| typeParameters: node.typeParameters, | |
| ); | |
| node.returnType?.accept2(this); | |
| } | |
| @override | |
| void visitMixinDeclaration(covariant MixinDeclarationImpl node) { | |
| var nameToken = node.name; | |
| var fragmentName = _getFragmentName(nameToken); | |
| var fragment = MixinFragmentImpl(name: fragmentName); | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.isBase = node.baseKeyword != null; | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| _libraryBuilder.addTopFragment(_libraryFragment, fragment); | |
| var holder = _EnclosingContext(fragment: fragment); | |
| _withEnclosing(holder, () { | |
| node.typeParameters?.accept2(this); | |
| node.body.accept2(this); | |
| }); | |
| fragment.typeParameters = holder.typeParameters; | |
| node.onClause?.accept2(this); | |
| node.implementsClause?.accept2(this); | |
| } | |
| @override | |
| void visitMixinOnClause(MixinOnClause node) { | |
| node.superclassConstraints.accept2(this); | |
| } | |
| @override | |
| void visitNamedType(NamedType node) { | |
| node.typeArguments?.accept2(this); | |
| } | |
| @override | |
| void visitNameWithTypeParameters(NameWithTypeParameters node) { | |
| node.typeParameters?.accept2(this); | |
| } | |
| @override | |
| void visitPartDirective(covariant PartDirectiveImpl node) { | |
| var index = _partDirectiveIndex++; | |
| var partElement = _libraryFragment.parts[index]; | |
| partElement.metadata = _buildMetadata(node.metadata); | |
| node.partInclude = partElement; | |
| } | |
| @override | |
| void visitPartOfDirective(PartOfDirective node) {} | |
| @override | |
| void visitPrimaryConstructorBody(PrimaryConstructorBody node) { | |
| // We copy initializers in [visitPrimaryConstructorDeclaration]. | |
| } | |
| @override | |
| void visitPrimaryConstructorDeclaration( | |
| covariant PrimaryConstructorDeclarationImpl node, | |
| ) { | |
| node.typeParameters?.accept2(this); | |
| var fragmentName = 'new'; | |
| if (node.constructorName?.name case var nameToken?) { | |
| fragmentName = _getFragmentName(nameToken) ?? 'new'; | |
| } | |
| var parent = node.parent2; | |
| var isAugmentation = | |
| parent is ExtensionTypeDeclarationImpl && parent.augmentKeyword != null; | |
| var fragment = ConstructorFragmentImpl(name: fragmentName); | |
| fragment.isAugmentation = isAugmentation; | |
| fragment.isOriginDeclaration = true; | |
| fragment.isConst = | |
| node.constKeyword != null || parent is EnumDeclarationImpl; | |
| fragment.isPrimary = true; | |
| fragment.isComplete = node.isComplete; | |
| fragment.typeName = node.typeName.lexeme; | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| _addChildFragment(fragment); | |
| if (node.body case var body?) { | |
| fragment.metadata = _buildMetadata(body.metadata); | |
| if (fragment.isConst) { | |
| fragment.constantInitializers = body.initializers; | |
| } | |
| } | |
| // Handle declaring formal parameters. | |
| var formalParameters = node.formalParameters.allFormalParameters; | |
| var isFirstFormalExtensionTypeRepresentation = false; | |
| if (parent is ExtensionTypeDeclarationImpl) { | |
| var firstFormalParameter = formalParameters.firstOrNull; | |
| isFirstFormalExtensionTypeRepresentation = | |
| firstFormalParameter is RegularFormalParameterImpl; | |
| if (!isFirstFormalExtensionTypeRepresentation) { | |
| var fieldFragment = FieldFragmentImpl(name: null); | |
| fieldFragment.isAugmentation = isAugmentation; | |
| fieldFragment.isFinal = true; | |
| fieldFragment.isOriginExtensionTypeRecoveryRepresentation = true; | |
| _addChildFragment(fieldFragment); | |
| } | |
| } | |
| for (var (i, formalParameter) in formalParameters.indexed) { | |
| if (formalParameter is! RegularFormalParameterImpl) { | |
| continue; | |
| } | |
| var isExtensionTypeRepresentation = | |
| i == 0 && isFirstFormalExtensionTypeRepresentation; | |
| if (formalParameter.finalOrVarKeyword != null || | |
| isExtensionTypeRepresentation) { | |
| var name = _getFragmentName(formalParameter.name); | |
| var fieldFragment = FieldFragmentImpl(name: name); | |
| fieldFragment.isAugmentation = isAugmentation; | |
| fieldFragment.isExplicitlyCovariant = | |
| formalParameter.covariantKeyword != null; | |
| fieldFragment.isFinal = | |
| formalParameter.isFinal || isExtensionTypeRepresentation; | |
| fieldFragment.isOriginDeclaringFormalParameter = true; | |
| fieldFragment.hasImplicitType = !formalParameter.isExplicitlyTyped; | |
| _linker.setFragmentNode(fieldFragment, formalParameter); | |
| _addChildFragment(fieldFragment); | |
| var formalParameterName = name; | |
| String? formalParameterPrivateName; | |
| if (formalParameterName != null && | |
| formalParameter.isNamed && | |
| _libraryBuilder.element.featureSet.isEnabled( | |
| Feature.private_named_parameters, | |
| )) { | |
| var publicName = correspondingPublicName(formalParameterName); | |
| if (publicName != null) { | |
| formalParameterPrivateName = formalParameterName; | |
| formalParameterName = publicName; | |
| } | |
| } | |
| var formalFragment = FieldFormalParameterFragmentImpl( | |
| name: formalParameterName, | |
| nameOffset: null, | |
| parameterKind: formalParameter.kind, | |
| privateName: formalParameterPrivateName, | |
| ); | |
| formalFragment.isDeclaring = true; | |
| _linker.declaringFormalParameters[formalParameter] = | |
| DeclaringFormalParameterInfo( | |
| node: formalParameter, | |
| fieldFragment: fieldFragment, | |
| formalFragment: formalFragment, | |
| ); | |
| } | |
| } | |
| _buildExecutableElementChildren( | |
| fragment: fragment, | |
| formalParameters: node.formalParameters, | |
| ); | |
| } | |
| @override | |
| void visitRecordTypeAnnotation(RecordTypeAnnotation node) { | |
| node.positionalFields.accept2(this); | |
| node.namedFields?.accept2(this); | |
| } | |
| @override | |
| void visitRecordTypeAnnotationNamedField( | |
| RecordTypeAnnotationNamedField node, | |
| ) { | |
| node.type.accept2(this); | |
| } | |
| @override | |
| void visitRecordTypeAnnotationNamedFields( | |
| RecordTypeAnnotationNamedFields node, | |
| ) { | |
| node.fields.accept2(this); | |
| } | |
| @override | |
| void visitRecordTypeAnnotationPositionalField( | |
| RecordTypeAnnotationPositionalField node, | |
| ) { | |
| node.type.accept2(this); | |
| } | |
| @override | |
| void visitRegularFormalParameter(covariant RegularFormalParameterImpl node) { | |
| var declaringFormalInfo = _linker.getDeclaringFormalInfo(node); | |
| FormalParameterFragmentImpl fragment; | |
| if (declaringFormalInfo != null) { | |
| fragment = declaringFormalInfo.formalFragment; | |
| } else { | |
| var name = _getFragmentName(node.name); | |
| fragment = FormalParameterFragmentImpl( | |
| name: name, | |
| nameOffset: null, | |
| parameterKind: node.kind, | |
| ); | |
| } | |
| _linker.setFragmentNode(fragment, node); | |
| _enclosingContext.addParameter(fragment); | |
| fragment.constantInitializer2 = node.defaultClause?.value2; | |
| fragment.hasImplicitType = | |
| node.type == null && node.functionTypedSuffix == null; | |
| fragment.isExplicitlyCovariant = | |
| declaringFormalInfo == null && node.covariantKeyword != null; | |
| fragment.isFinal = node.isFinal; | |
| fragment.isOriginDeclaration = true; | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = fragment; | |
| _buildFunctionTypedParameterSuffix(fragment, node.functionTypedSuffix); | |
| node.type?.accept2(this); | |
| } | |
| @override | |
| void visitSuperFormalParameter(covariant SuperFormalParameterImpl node) { | |
| var nameToken = node.name; | |
| var name2 = _getFragmentName(nameToken); | |
| var fragment = SuperFormalParameterFragmentImpl( | |
| name: name2, | |
| nameOffset: null, | |
| parameterKind: node.kind, | |
| ); | |
| _linker.setFragmentNode(fragment, node); | |
| _enclosingContext.addParameter(fragment); | |
| fragment.constantInitializer2 = node.defaultClause?.value2; | |
| fragment.hasImplicitType = | |
| node.type == null && node.functionTypedSuffix == null; | |
| fragment.isOriginDeclaration = true; | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = fragment; | |
| // TODO(scheglov): check that we don't set reference for parameters | |
| _buildFunctionTypedParameterSuffix(fragment, node.functionTypedSuffix); | |
| node.type?.accept2(this); | |
| } | |
| @override | |
| void visitTopLevelGetterDeclaration( | |
| covariant TopLevelGetterDeclarationImpl node, | |
| ) { | |
| var name2 = _getFragmentName(node.name); | |
| var body = node.body; | |
| var fragment = GetterFragmentImpl(name: name2); | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.isOriginDeclaration = true; | |
| fragment.isStatic = true; | |
| fragment.enclosingFragment = _libraryFragment; | |
| fragment.hasImplicitReturnType = node.returnType == null; | |
| fragment.isAsynchronous = body.isAsynchronous; | |
| fragment.isExternal = node.externalKeyword != null; | |
| fragment.isGenerator = body.isGenerator; | |
| fragment.isComplete = node.isComplete; | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| _libraryBuilder.addTopFragment(_libraryFragment, fragment); | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| _buildExecutableElementChildren( | |
| fragment: fragment, | |
| formalParameters: node.recoveryFormalParameters, | |
| typeParameters: node.recoveryTypeParameters, | |
| ); | |
| node.returnType?.accept2(this); | |
| } | |
| @override | |
| void visitTopLevelVariableDeclaration( | |
| covariant TopLevelVariableDeclarationImpl node, | |
| ) { | |
| var metadata = _buildMetadata(node.metadata); | |
| for (var variable in node.variables.variables) { | |
| var nameToken = variable.name; | |
| var name2 = _getFragmentName(nameToken); | |
| var fragment = TopLevelVariableFragmentImpl(name: name2); | |
| fragment.hasInitializer = variable.initializer2 != null; | |
| fragment.isAbstract = node.abstractKeyword != null; | |
| fragment.isAugmentation = node.augmentKeyword != null; | |
| fragment.isConst = node.variables.isConst; | |
| fragment.isExternal = node.externalKeyword != null; | |
| fragment.isFinal = node.variables.isFinal; | |
| fragment.isLate = node.variables.isLate; | |
| fragment.isOriginDeclaration = true; | |
| fragment.metadata = metadata; | |
| if (fragment.isConst) { | |
| fragment.constantInitializer2 = variable.initializer2; | |
| } | |
| if (node.variables.type == null) { | |
| fragment.hasImplicitType = true; | |
| } | |
| _libraryBuilder.addTopFragment(_libraryFragment, fragment); | |
| _linker.setFragmentNode(fragment, variable); | |
| variable.declaredFragment = fragment; | |
| } | |
| node.variables.type?.accept2(this); | |
| } | |
| @override | |
| void visitTypeArgumentList(TypeArgumentList node) { | |
| node.arguments.accept2(this); | |
| } | |
| @override | |
| void visitTypeParameter(covariant TypeParameterImpl node) { | |
| var nameToken = node.name; | |
| var fragment = TypeParameterFragmentImpl(name: _getFragmentName(nameToken)); | |
| fragment.metadata = _buildMetadata(node.metadata); | |
| node.declaredFragment = fragment; | |
| _linker.setFragmentNode(fragment, node); | |
| _enclosingContext.addTypeParameter(fragment); | |
| node.bound?.accept2(this); | |
| } | |
| @override | |
| void visitTypeParameterList(TypeParameterList node) { | |
| node.typeParameters.accept2(this); | |
| } | |
| @override | |
| void visitWithClause(WithClause node) { | |
| node.mixinTypes.accept2(this); | |
| } | |
| void _addChildFragment(FragmentImpl child) { | |
| var parent = _enclosingContext.fragment; | |
| _libraryBuilder.addChildFragment(parent, child); | |
| } | |
| void _buildExecutableElementChildren({ | |
| required ExecutableFragmentImpl fragment, | |
| FormalParameterList? formalParameters, | |
| TypeParameterList? typeParameters, | |
| }) { | |
| var holder = _EnclosingContext(fragment: fragment); | |
| _withEnclosing(holder, () { | |
| if (formalParameters != null) { | |
| formalParameters.accept2(this); | |
| fragment.formalParameters = holder.formalParameters; | |
| } | |
| if (typeParameters != null) { | |
| typeParameters.accept2(this); | |
| fragment.typeParameters = holder.typeParameters; | |
| } | |
| }); | |
| } | |
| void _buildFunctionTypedParameterSuffix( | |
| FormalParameterFragmentImpl fragment, | |
| FunctionTypedFormalParameterSuffix? suffix, | |
| ) { | |
| if (suffix == null) { | |
| return; | |
| } | |
| var holder = _EnclosingContext(fragment: fragment); | |
| _withEnclosing(holder, () { | |
| suffix.typeParameters?.accept2(this); | |
| suffix.formalParameters.accept2(this); | |
| }); | |
| for (var typeParameter in holder.typeParameters) { | |
| TypeParameterElementImpl(firstFragment: typeParameter); | |
| } | |
| for (var formalParameter in holder.formalParameters) { | |
| formalParameter.initElement(); | |
| } | |
| } | |
| MetadataImpl _buildMetadata(List<AnnotationImpl> nodeList) { | |
| var length = nodeList.length; | |
| if (length == 0) return MetadataImpl(const []); | |
| return MetadataImpl( | |
| List.generate( | |
| length, | |
| (index) => ElementAnnotationImpl(_libraryFragment, nodeList[index]), | |
| growable: false, | |
| ), | |
| ); | |
| } | |
| String? _getFragmentName(Token? nameToken) { | |
| if (nameToken == null || nameToken.isSynthetic) { | |
| return null; | |
| } | |
| return nameToken.lexeme; | |
| } | |
| void _withEnclosing(_EnclosingContext context, void Function() f) { | |
| var previous = _enclosingContext; | |
| _enclosingContext = context; | |
| try { | |
| f(); | |
| } finally { | |
| _enclosingContext = previous; | |
| } | |
| } | |
| } | |
| class _EnclosingContext { | |
| final FragmentImpl fragment; | |
| final List<FormalParameterFragmentImpl> formalParameters = []; | |
| final List<TypeParameterFragmentImpl> typeParameters = []; | |
| _EnclosingContext({required this.fragment}); | |
| void addParameter(FormalParameterFragmentImpl fragment) { | |
| fragment.enclosingFragment = this.fragment; | |
| formalParameters.add(fragment); | |
| } | |
| void addTypeParameter(TypeParameterFragmentImpl fragment) { | |
| fragment.enclosingFragment = this.fragment; | |
| typeParameters.add(fragment); | |
| } | |
| } | |
| extension _LinkerExtension on Linker { | |
| DeclaringFormalParameterInfo? getDeclaringFormalInfo( | |
| FormalParameterImpl node, | |
| ) { | |
| return declaringFormalParameters[node]; | |
| } | |
| } |