| // 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. |
| |
| // ignore_for_file: analyzer_use_new_elements |
| |
| import 'package:analyzer/dart/ast/token.dart'; |
| import 'package:analyzer/dart/ast/visitor.dart'; |
| import 'package:analyzer/dart/element/element.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/augmentation.dart'; |
| import 'package:analyzer/src/summary2/library_builder.dart'; |
| import 'package:analyzer/src/summary2/link.dart'; |
| import 'package:analyzer/src/summary2/reference.dart'; |
| import 'package:analyzer/src/util/comment.dart'; |
| import 'package:analyzer/src/utilities/extensions/collection.dart'; |
| import 'package:analyzer/src/utilities/extensions/element.dart'; |
| import 'package:analyzer/src/utilities/extensions/string.dart'; |
| import 'package:collection/collection.dart'; |
| |
| class ElementBuilder extends ThrowingAstVisitor<void> { |
| final LibraryBuilder _libraryBuilder; |
| final CompilationUnitElementImpl _unitElement; |
| |
| var _exportDirectiveIndex = 0; |
| var _importDirectiveIndex = 0; |
| var _partDirectiveIndex = 0; |
| |
| _EnclosingContext _enclosingContext; |
| int _nextUnnamedId = 0; |
| |
| ElementBuilder({ |
| required LibraryBuilder libraryBuilder, |
| required CompilationUnitElementImpl unitElement, |
| }) : _libraryBuilder = libraryBuilder, |
| _unitElement = unitElement, |
| _enclosingContext = _EnclosingContext( |
| instanceElementBuilder: null, |
| fragment: unitElement, |
| ); |
| |
| Linker get _linker => _libraryBuilder.linker; |
| |
| void buildDeclarationElements(CompilationUnit unit) { |
| _visitPropertyFirst<TopLevelVariableDeclaration>(unit.declarations); |
| _unitElement.accessors = _enclosingContext.propertyAccessors; |
| _unitElement.classes = _enclosingContext.classes; |
| _unitElement.enums = _enclosingContext.enums; |
| _unitElement.extensions = _enclosingContext.extensions; |
| _unitElement.extensionTypes = _enclosingContext.extensionTypes; |
| _unitElement.functions = _enclosingContext.functions; |
| _unitElement.mixins = _enclosingContext.mixins; |
| _unitElement.topLevelVariables = _enclosingContext.topLevelVariables; |
| _unitElement.typeAliases = _enclosingContext.typeAliases; |
| } |
| |
| /// Builds exports and imports, metadata into [_unitElement]. |
| void buildDirectiveElements(CompilationUnitImpl unit) { |
| unit.directives.accept(this); |
| } |
| |
| /// Updates metadata and documentation for [_libraryBuilder]. |
| /// |
| /// This method must be invoked after [buildDirectiveElements]. |
| 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.documentationComment = getCommentNodeRawText( |
| libraryDirective.documentationComment, |
| ); |
| libraryElement.metadata = _buildAnnotations(libraryDirective.metadata); |
| return; |
| } |
| |
| // Otherwise use the first directive. |
| var firstDirective = unit.directives.firstOrNull; |
| if (firstDirective != null) { |
| libraryElement.documentationComment = getCommentNodeRawText( |
| firstDirective.documentationComment, |
| ); |
| var firstDirectiveMetadata = firstDirective.element?.metadata; |
| if (firstDirectiveMetadata != null) { |
| libraryElement.metadata = firstDirectiveMetadata; |
| } |
| } |
| } |
| |
| @override |
| void visitClassDeclaration(covariant ClassDeclarationImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var fragment = ClassElementImpl(name, nameToken.offset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| 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; |
| if (node.sealedKeyword != null) { |
| fragment.isAbstract = true; |
| fragment.isSealed = true; |
| } |
| fragment.hasExtendsClause = node.extendsClause != null; |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| _setDocumentation(fragment, node); |
| |
| node.declaredFragment = fragment; |
| _linker.elementNodes[fragment] = node; |
| |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| var fragmentReference = _enclosingContext.addClass(refName, fragment); |
| if (!fragment.isAugmentation) { |
| _libraryBuilder.declare(name, fragmentReference); |
| } |
| |
| var elementBuilder = _libraryBuilder.elementBuilderGetters[name]; |
| elementBuilder?.setPreviousFor(fragment); |
| if (fragment.isAugmentation && elementBuilder is ClassElementBuilder) { |
| } else { |
| var libraryRef = _libraryBuilder.reference; |
| var containerRef = libraryRef.getChild('@class'); |
| var elementReference = containerRef.addChild(refName); |
| var element = ClassElementImpl2(elementReference, fragment); |
| _libraryBuilder.element.classes.add(element); |
| |
| elementBuilder = ClassElementBuilder( |
| element: element, |
| firstFragment: fragment, |
| ); |
| _libraryBuilder.elementBuilderGetters[name] = elementBuilder; |
| } |
| |
| var holder = _EnclosingContext( |
| instanceElementBuilder: elementBuilder, |
| fragment: fragment, |
| constFieldsForFinalInstance: true, |
| ); |
| _withEnclosing(holder, () { |
| node.typeParameters?.accept(this); |
| _visitPropertyFirst<FieldDeclaration>(node.members); |
| }); |
| fragment.typeParameters = holder.typeParameters; |
| fragment.accessors = holder.propertyAccessors; |
| fragment.constructors = holder.constructors; |
| fragment.fields = holder.fields; |
| fragment.methods = holder.methods; |
| |
| node.extendsClause?.accept(this); |
| node.withClause?.accept(this); |
| node.implementsClause?.accept(this); |
| |
| elementBuilder.addFragment(fragment); |
| } |
| |
| @override |
| void visitClassTypeAlias(covariant ClassTypeAliasImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var fragment = ClassElementImpl(name, nameToken.offset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| 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; |
| if (node.sealedKeyword != null) { |
| fragment.isAbstract = true; |
| fragment.isSealed = true; |
| } |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| _setDocumentation(fragment, node); |
| |
| node.declaredFragment = fragment; |
| _linker.elementNodes[fragment] = node; |
| |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| var reference = _enclosingContext.addClass(refName, fragment); |
| if (!fragment.isAugmentation) { |
| _libraryBuilder.declare(name, reference); |
| } |
| |
| var elementBuilder = _libraryBuilder.elementBuilderGetters[name]; |
| elementBuilder?.setPreviousFor(fragment); |
| if (fragment.isAugmentation && elementBuilder is ClassElementBuilder) { |
| } else { |
| var libraryRef = _libraryBuilder.reference; |
| var containerRef = libraryRef.getChild('@class'); |
| var elementReference = containerRef.addChild(refName); |
| var element = ClassElementImpl2(elementReference, fragment); |
| _libraryBuilder.element.classes.add(element); |
| |
| elementBuilder = ClassElementBuilder( |
| element: element, |
| firstFragment: fragment, |
| ); |
| _libraryBuilder.elementBuilderGetters[name] = elementBuilder; |
| } |
| |
| var holder = _EnclosingContext( |
| instanceElementBuilder: elementBuilder, |
| fragment: fragment, |
| ); |
| _withEnclosing(holder, () { |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| fragment.typeParameters = holder.typeParameters; |
| } |
| }); |
| |
| node.superclass.accept(this); |
| node.withClause.accept(this); |
| node.implementsClause?.accept(this); |
| } |
| |
| @override |
| void visitConstructorDeclaration( |
| covariant ConstructorDeclarationImpl node, |
| ) { |
| var nameNode = node.name ?? node.returnType; |
| var name = node.name?.lexeme ?? ''; |
| if (name == 'new') { |
| // A constructor declared as `C.new` is unnamed, and is modeled as such. |
| name = ''; |
| } |
| var nameOffset = nameNode.offset; |
| |
| var element = ConstructorElementImpl(name, nameOffset); |
| element.isAugmentation = node.augmentKeyword != null; |
| element.isConst = node.constKeyword != null; |
| element.isExternal = node.externalKeyword != null; |
| element.isFactory = node.factoryKeyword != null; |
| element.metadata = _buildAnnotations(node.metadata); |
| element.typeName = node.returnType.name; |
| element.typeNameOffset = node.returnType.offset; |
| element.periodOffset = node.period?.offset; |
| element.nameEnd = nameNode.end; |
| if ((node.period, node.name) case (var _?, var name?)) { |
| element.name2 = name.lexeme; |
| element.nameOffset2 = name.offset; |
| } else { |
| element.name2 = 'new'; |
| } |
| _setCodeRange(element, node); |
| _setDocumentation(element, node); |
| |
| if (element.isConst || element.isFactory) { |
| element.constantInitializers = node.initializers; |
| } |
| |
| node.declaredFragment = element; |
| _linker.elementNodes[element] = node; |
| |
| var reference = _enclosingContext.addConstructor(element); |
| _buildExecutableElementChildren( |
| reference: reference, |
| fragment: element, |
| formalParameters: node.parameters, |
| ); |
| } |
| |
| @override |
| void visitDefaultFormalParameter(DefaultFormalParameter node) { |
| node.parameter.accept(this); |
| } |
| |
| @override |
| void visitEnumDeclaration(covariant EnumDeclarationImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| var nameOffset = nameToken.offset; |
| |
| var fragment = EnumElementImpl(name, nameOffset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.isAugmentation = node.augmentKeyword != null; |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| _setDocumentation(fragment, node); |
| |
| node.declaredFragment = fragment; |
| _linker.elementNodes[fragment] = node; |
| |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| var reference = _enclosingContext.addEnum(refName, fragment); |
| if (!fragment.isAugmentation) { |
| _libraryBuilder.declare(name, reference); |
| } |
| |
| var elementBuilder = _libraryBuilder.elementBuilderGetters[name]; |
| elementBuilder?.setPreviousFor(fragment); |
| if (fragment.isAugmentation && elementBuilder is EnumElementBuilder) { |
| } else { |
| var libraryRef = _libraryBuilder.reference; |
| var containerRef = libraryRef.getChild('@enum'); |
| var elementReference = containerRef.addChild(refName); |
| var element = EnumElementImpl2(elementReference, fragment); |
| _libraryBuilder.element.enums.add(element); |
| |
| elementBuilder = EnumElementBuilder( |
| firstFragment: fragment, |
| element: element, |
| ); |
| _libraryBuilder.elementBuilderGetters[name] = elementBuilder; |
| } |
| |
| var holder = _EnclosingContext( |
| instanceElementBuilder: elementBuilder, |
| fragment: fragment, |
| constFieldsForFinalInstance: true, |
| ); |
| |
| // Build fields for all enum constants. |
| var constants = node.constants; |
| var valuesElements = <SimpleIdentifierImpl>[]; |
| var valuesNames = <String>{}; |
| for (var i = 0; i < constants.length; ++i) { |
| var constant = constants[i]; |
| var nameToken = constant.name; |
| var name = nameToken.lexeme; |
| var field = ConstFieldElementImpl(name, constant.name.offset) |
| ..hasImplicitType = true |
| ..hasInitializer = true |
| ..isAugmentation = constant.augmentKeyword != null |
| ..isConst = true |
| ..isEnumConstant = true |
| ..isStatic = true; |
| field.name2 = _getFragmentName(nameToken); |
| field.nameOffset2 = _getFragmentNameOffset(nameToken); |
| _setCodeRange(field, constant); |
| _setDocumentation(field, constant); |
| field.metadata = _buildAnnotationsWithUnit( |
| _unitElement, |
| constant.metadata, |
| ); |
| |
| var constructorSelector = constant.arguments?.constructorSelector; |
| var constructorName = constructorSelector?.name.name; |
| |
| var initializer = InstanceCreationExpressionImpl( |
| keyword: null, |
| constructorName: ConstructorNameImpl( |
| type: NamedTypeImpl( |
| importPrefix: null, |
| name2: StringToken(TokenType.STRING, fragment.name, -1), |
| typeArguments: constant.arguments?.typeArguments, |
| question: null, |
| ), |
| period: constructorName != null ? Tokens.period() : null, |
| name: constructorName != null |
| ? SimpleIdentifierImpl( |
| StringToken(TokenType.STRING, constructorName, -1), |
| ) |
| : null, |
| ), |
| argumentList: ArgumentListImpl( |
| leftParenthesis: Tokens.openParenthesis(), |
| arguments: [ |
| ...?constant.arguments?.argumentList.arguments, |
| ], |
| rightParenthesis: Tokens.closeParenthesis(), |
| ), |
| typeArguments: null, |
| ); |
| |
| var variableDeclaration = VariableDeclarationImpl( |
| name: StringToken(TokenType.STRING, name, -1), |
| equals: Tokens.eq(), |
| initializer: initializer, |
| ); |
| constant.declaredFragment = field; |
| variableDeclaration.declaredFragment = field; |
| VariableDeclarationListImpl( |
| comment: null, |
| metadata: null, |
| lateKeyword: null, |
| keyword: null, |
| type: null, |
| variables: [variableDeclaration], |
| ); |
| _linker.elementNodes[field] = variableDeclaration; |
| |
| field.constantInitializer = initializer; |
| |
| var refName = field.name2 ?? '${_nextUnnamedId++}'; |
| holder.addNonSyntheticField(refName, field); |
| |
| valuesElements.add( |
| SimpleIdentifierImpl( |
| StringToken(TokenType.STRING, name, -1), |
| ), |
| ); |
| valuesNames.add(name); |
| } |
| |
| // Build the 'values' field. |
| if (fragment.augmentationTarget == null) { |
| var valuesField = ConstFieldElementImpl('values', -1) |
| ..isConst = true |
| ..isStatic = true |
| ..isSynthetic = true |
| ..name2 = 'values'; |
| var initializer = ListLiteralImpl( |
| constKeyword: null, |
| typeArguments: null, |
| leftBracket: Tokens.openSquareBracket(), |
| elements: valuesElements, |
| rightBracket: Tokens.closeSquareBracket(), |
| ); |
| valuesField.constantInitializer = initializer; |
| |
| var variableDeclaration = VariableDeclarationImpl( |
| name: StringToken(TokenType.STRING, 'values', -1), |
| equals: Tokens.eq(), |
| initializer: initializer, |
| ); |
| var valuesTypeNode = NamedTypeImpl( |
| importPrefix: null, |
| name2: StringToken(TokenType.STRING, 'List', -1), |
| typeArguments: TypeArgumentListImpl( |
| leftBracket: Tokens.lt(), |
| arguments: [ |
| NamedTypeImpl( |
| importPrefix: null, |
| name2: StringToken(TokenType.STRING, fragment.name, -1), |
| typeArguments: null, |
| question: null, |
| )..element2 = fragment.asElement2, |
| ], |
| rightBracket: Tokens.gt(), |
| ), |
| question: null, |
| ); |
| VariableDeclarationListImpl( |
| comment: null, |
| metadata: null, |
| lateKeyword: null, |
| keyword: Tokens.const_(), |
| variables: [variableDeclaration], |
| type: valuesTypeNode, |
| ); |
| _linker.elementNodes[valuesField] = variableDeclaration; |
| |
| holder.addNonSyntheticField('values', valuesField); |
| |
| _libraryBuilder.implicitEnumNodes[fragment] = ImplicitEnumNodes( |
| element: fragment, |
| valuesTypeNode: valuesTypeNode, |
| valuesNode: variableDeclaration, |
| valuesElement: valuesField, |
| valuesNames: valuesNames, |
| valuesInitializer: initializer, |
| ); |
| } else { |
| var declaration = elementBuilder.firstFragment; |
| var implicitNodes = _libraryBuilder.implicitEnumNodes[declaration]; |
| if (implicitNodes != null) { |
| var mergedValuesElements = [ |
| ...implicitNodes.valuesInitializer.elements, |
| for (var value in valuesElements) |
| if (implicitNodes.valuesNames.add(value.name)) value, |
| ]; |
| var initializer = ListLiteralImpl( |
| constKeyword: null, |
| typeArguments: null, |
| leftBracket: Tokens.openSquareBracket(), |
| elements: mergedValuesElements, |
| rightBracket: Tokens.closeSquareBracket(), |
| ); |
| implicitNodes.valuesElement.constantInitializer = initializer; |
| implicitNodes.valuesNode.initializer = initializer; |
| implicitNodes.valuesInitializer = initializer; |
| } |
| } |
| |
| node.withClause?.accept(this); |
| node.implementsClause?.accept(this); |
| |
| _withEnclosing(holder, () { |
| node.typeParameters?.accept(this); |
| _visitPropertyFirst<FieldDeclaration>(node.members); |
| }); |
| |
| fragment.accessors = holder.propertyAccessors; |
| fragment.constructors = holder.constructors; |
| fragment.fields = holder.fields; |
| fragment.methods = holder.methods; |
| fragment.typeParameters = holder.typeParameters; |
| elementBuilder.addFragment(fragment); |
| } |
| |
| @override |
| void visitExportDirective(covariant ExportDirectiveImpl node) { |
| var index = _exportDirectiveIndex++; |
| var exportElement = _unitElement.libraryExports[index]; |
| exportElement.metadata = _buildAnnotations(node.metadata); |
| node.element = exportElement; |
| } |
| |
| @override |
| void visitExtendsClause(ExtendsClause node) { |
| node.superclass.accept(this); |
| } |
| |
| @override |
| void visitExtensionDeclaration(covariant ExtensionDeclarationImpl node) { |
| var nameToken = node.name; |
| var name = nameToken?.lexeme; |
| var nameOffset = nameToken?.offset ?? -1; |
| |
| var fragment = ExtensionElementImpl(name, nameOffset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.isAugmentation = node.augmentKeyword != null; |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| _setDocumentation(fragment, node); |
| |
| node.declaredFragment = fragment; |
| _linker.elementNodes[fragment] = node; |
| |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| var reference = _enclosingContext.addExtension(refName, fragment); |
| |
| if (name != null) { |
| if (!fragment.isAugmentation) { |
| _libraryBuilder.declare(name, reference); |
| } |
| } |
| |
| FragmentedElementBuilder? elementBuilder; |
| if (name != null) { |
| elementBuilder = _libraryBuilder.elementBuilderGetters[name]; |
| elementBuilder?.setPreviousFor(fragment); |
| if (fragment.isAugmentation && |
| elementBuilder is ExtensionElementBuilder) { |
| } else { |
| var elementReference = |
| _libraryBuilder.reference.getChild('@extension').addChild(refName); |
| var element = ExtensionElementImpl2(elementReference, fragment); |
| _libraryBuilder.element.extensions.add(element); |
| |
| elementBuilder = ExtensionElementBuilder( |
| firstFragment: fragment, |
| element: element, |
| ); |
| _libraryBuilder.elementBuilderGetters[name] = elementBuilder; |
| } |
| } else { |
| var elementReference = |
| _libraryBuilder.reference.getChild('@extension').addChild(refName); |
| var element = ExtensionElementImpl2(elementReference, fragment); |
| _libraryBuilder.element.extensions.add(element); |
| elementBuilder = ExtensionElementBuilder( |
| firstFragment: fragment, |
| element: element, |
| ); |
| elementBuilder as ExtensionElementBuilder; // force |
| } |
| |
| var holder = _EnclosingContext( |
| instanceElementBuilder: elementBuilder, |
| fragment: fragment, |
| ); |
| _withEnclosing(holder, () { |
| node.typeParameters?.accept(this); |
| _visitPropertyFirst<FieldDeclaration>(node.members); |
| }); |
| fragment.typeParameters = holder.typeParameters; |
| fragment.accessors = holder.propertyAccessors; |
| fragment.fields = holder.fields; |
| fragment.methods = holder.methods; |
| |
| node.onClause?.accept(this); |
| elementBuilder.addFragment(fragment); |
| } |
| |
| @override |
| void visitExtensionOnClause(ExtensionOnClause node) { |
| node.extendedType.accept(this); |
| } |
| |
| @override |
| void visitExtensionTypeDeclaration( |
| covariant ExtensionTypeDeclarationImpl node, |
| ) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var fragment = ExtensionTypeElementImpl(name, nameToken.offset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.isAugmentation = node.augmentKeyword != null; |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| _setDocumentation(fragment, node); |
| |
| node.declaredFragment = fragment; |
| _linker.elementNodes[fragment] = node; |
| |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| var reference = _enclosingContext.addExtensionType(refName, fragment); |
| if (!fragment.isAugmentation) { |
| _libraryBuilder.declare(name, reference); |
| } |
| |
| var elementBuilder = _libraryBuilder.elementBuilderGetters[name]; |
| elementBuilder?.setPreviousFor(fragment); |
| if (fragment.isAugmentation && |
| elementBuilder is ExtensionTypeElementBuilder) { |
| } else { |
| var libraryRef = _libraryBuilder.reference; |
| var containerRef = libraryRef.getChild('@extensionType'); |
| var elementReference = containerRef.addChild(refName); |
| var element = ExtensionTypeElementImpl2(elementReference, fragment); |
| _libraryBuilder.element.extensionTypes.add(element); |
| |
| elementBuilder = ExtensionTypeElementBuilder( |
| firstFragment: fragment, |
| element: element, |
| ); |
| |
| fragment.isAugmentationChainStart = true; |
| _libraryBuilder.elementBuilderGetters[name] = elementBuilder; |
| } |
| |
| var holder = _EnclosingContext( |
| instanceElementBuilder: elementBuilder, |
| fragment: fragment, |
| ); |
| _withEnclosing(holder, () { |
| node.typeParameters?.accept(this); |
| _builtRepresentationDeclaration( |
| extensionNode: node, |
| representation: node.representation, |
| extensionFragment: fragment, |
| ); |
| _visitPropertyFirst<FieldDeclaration>(node.members); |
| }); |
| |
| fragment.accessors = holder.propertyAccessors; |
| fragment.constructors = holder.constructors; |
| fragment.fields = holder.fields; |
| fragment.methods = holder.methods; |
| fragment.typeParameters = holder.typeParameters; |
| |
| var executables = const <ExecutableElementImpl>[] |
| .followedBy(fragment.accessors) |
| .followedBy(fragment.methods); |
| for (var executable in executables) { |
| executable.isExtensionTypeMember = true; |
| } |
| |
| node.implementsClause?.accept(this); |
| elementBuilder.addFragment(fragment); |
| } |
| |
| @override |
| void visitFieldDeclaration( |
| covariant FieldDeclarationImpl node, |
| ) { |
| var metadata = _buildAnnotations(node.metadata); |
| for (var variable in node.fields.variables) { |
| var nameToken = variable.name; |
| var name = nameToken.lexeme; |
| var nameOffset = nameToken.offset; |
| |
| var fragment = FieldElementImpl(name, nameOffset); |
| if (variable.initializer case var initializer?) { |
| if (node.fields.isConst) { |
| fragment = ConstFieldElementImpl(name, nameOffset) |
| ..constantInitializer = initializer; |
| } else if (_enclosingContext.constFieldsForFinalInstance) { |
| if (node.fields.isFinal && !node.isStatic) { |
| var constElement = ConstFieldElementImpl(name, nameOffset) |
| ..constantInitializer = initializer; |
| fragment = constElement; |
| _libraryBuilder.finalInstanceFields.add(constElement); |
| } |
| } |
| } |
| |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.hasInitializer = variable.initializer != null; |
| fragment.isAbstract = node.abstractKeyword != null; |
| fragment.isAugmentation = node.augmentKeyword != null; |
| fragment.isConst = node.fields.isConst; |
| fragment.isCovariant = node.covariantKeyword != null; |
| fragment.isExternal = node.externalKeyword != null; |
| fragment.isFinal = node.fields.isFinal; |
| fragment.isLate = node.fields.isLate; |
| fragment.isStatic = node.isStatic; |
| fragment.metadata = metadata; |
| _setCodeRange(fragment, variable); |
| _setDocumentation(fragment, node); |
| |
| if (node.fields.type == null) { |
| fragment.hasImplicitType = true; |
| } |
| |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| _enclosingContext.addNonSyntheticField(refName, fragment); |
| |
| _linker.elementNodes[fragment] = variable; |
| variable.declaredFragment = fragment; |
| } |
| _buildType(node.fields.type); |
| } |
| |
| @override |
| void visitFieldFormalParameter( |
| covariant FieldFormalParameterImpl node, |
| ) { |
| var nameToken = node.name; |
| var name2 = nameToken.lexeme.nullIfEmpty; |
| var nameOffset2 = nameToken.offset.nullIfNegative; |
| |
| ParameterElementImpl fragment; |
| var parent = node.parent; |
| if (parent is DefaultFormalParameterImpl) { |
| fragment = DefaultFieldFormalParameterElementImpl( |
| name: name2 ?? '', |
| nameOffset: nameOffset2 ?? -1, |
| name2: name2, |
| nameOffset2: nameOffset2, |
| parameterKind: node.kind, |
| )..constantInitializer = parent.defaultValue; |
| _linker.elementNodes[fragment] = parent; |
| var refName = node.isNamed ? name2 : null; |
| _enclosingContext.addParameter(refName, fragment); |
| } else { |
| fragment = FieldFormalParameterElementImpl( |
| name: name2 ?? '', |
| nameOffset: nameOffset2 ?? -1, |
| name2: name2, |
| nameOffset2: nameOffset2, |
| parameterKind: node.kind, |
| ); |
| _linker.elementNodes[fragment] = node; |
| _enclosingContext.addParameter(null, fragment); |
| } |
| |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.hasImplicitType = node.type == null && node.parameters == null; |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| |
| node.declaredFragment = fragment; |
| |
| // TODO(scheglov): check that we don't set reference for parameters |
| var holder = _EnclosingContext( |
| instanceElementBuilder: null, |
| fragment: fragment, |
| ); |
| _withEnclosing(holder, () { |
| var formalParameters = node.parameters; |
| if (formalParameters != null) { |
| formalParameters.accept(this); |
| fragment.parameters = holder.parameters; |
| } |
| |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| fragment.typeParameters = holder.typeParameters; |
| } |
| }); |
| |
| _buildType(node.type); |
| } |
| |
| @override |
| void visitFormalParameterList(FormalParameterList node) { |
| node.parameters.accept(this); |
| } |
| |
| @override |
| void visitFunctionDeclaration(covariant FunctionDeclarationImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| var nameOffset = nameToken.offset; |
| |
| var functionExpression = node.functionExpression; |
| var body = functionExpression.body; |
| |
| Reference reference; |
| ExecutableElementImpl executableFragment; |
| FragmentedElementBuilder? elementBuilder; |
| if (node.isGetter) { |
| var getterFragment = GetterFragmentImpl(name, nameOffset); |
| getterFragment.name2 = _getFragmentName(nameToken); |
| getterFragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| getterFragment.isAugmentation = node.augmentKeyword != null; |
| getterFragment.isStatic = true; |
| |
| var refName = getterFragment.name2 ?? '${_nextUnnamedId++}'; |
| reference = _enclosingContext.addGetter(refName, getterFragment); |
| executableFragment = getterFragment; |
| |
| if (!getterFragment.isAugmentation) { |
| var variableFragment = _buildSyntheticVariable( |
| name: name, |
| accessorElement: getterFragment, |
| ) as TopLevelVariableElementImpl; |
| |
| var elementBuilder = TopLevelVariableElementBuilder( |
| element: variableFragment.element, |
| firstFragment: variableFragment, |
| ); |
| _libraryBuilder.elementBuilderVariables[name] = elementBuilder; |
| } |
| |
| elementBuilder = _libraryBuilder.elementBuilderGetters[name]; |
| elementBuilder ??= _libraryBuilder.elementBuilderSetters[name]; |
| elementBuilder?.setPreviousFor(getterFragment); |
| if (getterFragment.isAugmentation && |
| elementBuilder is GetterElementBuilder) { |
| elementBuilder.addFragment(getterFragment); |
| } else { |
| elementBuilder = GetterElementBuilder( |
| element: GetterElementImpl(getterFragment), |
| firstFragment: getterFragment, |
| ); |
| _libraryBuilder.elementBuilderGetters[name] = elementBuilder; |
| } |
| } else if (node.isSetter) { |
| var setterFragment = SetterFragmentImpl(name, nameOffset); |
| setterFragment.name2 = _getFragmentName(nameToken); |
| setterFragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| setterFragment.isAugmentation = node.augmentKeyword != null; |
| setterFragment.isStatic = true; |
| |
| var refName = setterFragment.name2 ?? '${_nextUnnamedId++}'; |
| reference = _enclosingContext.addSetter(refName, setterFragment); |
| executableFragment = setterFragment; |
| |
| if (!setterFragment.isAugmentation) { |
| var variableFragment = _buildSyntheticVariable( |
| name: name, |
| accessorElement: setterFragment, |
| ) as TopLevelVariableElementImpl; |
| |
| var elementBuilder = TopLevelVariableElementBuilder( |
| element: variableFragment.element, |
| firstFragment: variableFragment, |
| ); |
| _libraryBuilder.elementBuilderVariables[name] = elementBuilder; |
| } |
| |
| elementBuilder = _libraryBuilder.elementBuilderSetters[name]; |
| elementBuilder ??= _libraryBuilder.elementBuilderGetters[name]; |
| elementBuilder?.setPreviousFor(setterFragment); |
| if (setterFragment.isAugmentation && |
| elementBuilder is SetterElementBuilder) { |
| elementBuilder.addFragment(setterFragment); |
| } else { |
| elementBuilder = SetterElementBuilder( |
| element: SetterElementImpl(setterFragment), |
| firstFragment: setterFragment, |
| ); |
| _libraryBuilder.elementBuilderSetters[name] = elementBuilder; |
| } |
| } else { |
| var fragment = TopLevelFunctionFragmentImpl(name, nameOffset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.isAugmentation = node.augmentKeyword != null; |
| fragment.isStatic = true; |
| executableFragment = fragment; |
| |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| reference = _enclosingContext.addFunction(name, fragment); |
| |
| elementBuilder = _libraryBuilder.elementBuilderGetters[name]; |
| elementBuilder ??= _libraryBuilder.elementBuilderSetters[name]; |
| elementBuilder?.setPreviousFor(fragment); |
| if (fragment.isAugmentation && |
| elementBuilder is TopLevelFunctionElementBuilder) { |
| elementBuilder.addFragment(fragment); |
| } else { |
| var libraryRef = _libraryBuilder.reference; |
| var containerRef = libraryRef.getChild('@function'); |
| var elementReference = containerRef.addChild(refName); |
| var element = TopLevelFunctionElementImpl( |
| elementReference, |
| fragment, |
| ); |
| _libraryBuilder.element.topLevelFunctions.add(element); |
| |
| elementBuilder = TopLevelFunctionElementBuilder( |
| element: element, |
| firstFragment: fragment, |
| ); |
| _libraryBuilder.elementBuilderGetters[name] = elementBuilder; |
| } |
| } |
| |
| executableFragment.hasImplicitReturnType = node.returnType == null; |
| executableFragment.isAsynchronous = body.isAsynchronous; |
| executableFragment.isExternal = node.externalKeyword != null; |
| executableFragment.isGenerator = body.isGenerator; |
| executableFragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(executableFragment, node); |
| _setDocumentation(executableFragment, node); |
| |
| node.declaredFragment = executableFragment; |
| _linker.elementNodes[executableFragment] = node; |
| |
| _buildExecutableElementChildren( |
| reference: reference, |
| fragment: executableFragment, |
| formalParameters: functionExpression.parameters, |
| typeParameters: functionExpression.typeParameters, |
| ); |
| |
| var getterOrSetterName = node.isSetter ? '$name=' : name; |
| |
| if (!executableFragment.isAugmentation) { |
| _libraryBuilder.declare(getterOrSetterName, reference); |
| } |
| |
| _buildType(node.returnType); |
| } |
| |
| @override |
| void visitFunctionTypeAlias(covariant FunctionTypeAliasImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var fragment = TypeAliasElementImpl(name, nameToken.offset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.isFunctionTypeAliasBased = true; |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| _setDocumentation(fragment, node); |
| |
| node.declaredFragment = fragment; |
| _linker.elementNodes[fragment] = node; |
| |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| var reference = _enclosingContext.addTypeAlias(refName, fragment); |
| _libraryBuilder.declare(name, reference); |
| |
| var elementBuilder = _libraryBuilder.elementBuilderGetters[name]; |
| elementBuilder ??= _libraryBuilder.elementBuilderSetters[name]; |
| elementBuilder?.setPreviousFor(fragment); |
| if (fragment.isAugmentation && elementBuilder is TypeAliasElementBuilder) { |
| } else { |
| var libraryRef = _libraryBuilder.reference; |
| var containerRef = libraryRef.getChild('@typeAlias'); |
| var elementReference = containerRef.addChild(refName); |
| var element = TypeAliasElementImpl2(elementReference, fragment); |
| _libraryBuilder.element.typeAliases.add(element); |
| |
| elementBuilder = TypeAliasElementBuilder( |
| element: element, |
| firstFragment: fragment, |
| ); |
| _libraryBuilder.elementBuilderGetters[name] = elementBuilder; |
| } |
| |
| var holder = _EnclosingContext( |
| instanceElementBuilder: null, |
| fragment: fragment, |
| ); |
| _withEnclosing(holder, () { |
| node.typeParameters?.accept(this); |
| node.returnType?.accept(this); |
| node.parameters.accept(this); |
| }); |
| |
| var aliasedElement = GenericFunctionTypeElementImpl.forOffset( |
| nameToken.offset, |
| ); |
| aliasedElement.parameters = holder.parameters; |
| |
| fragment.typeParameters = holder.typeParameters; |
| fragment.aliasedElement = aliasedElement; |
| |
| elementBuilder.addFragment(fragment); |
| } |
| |
| @override |
| void visitFunctionTypedFormalParameter( |
| covariant FunctionTypedFormalParameterImpl node, |
| ) { |
| var nameToken = node.name; |
| var name2 = nameToken.lexeme.nullIfEmpty; |
| var nameOffset2 = nameToken.offset.nullIfNegative; |
| |
| ParameterElementImpl fragment; |
| var parent = node.parent; |
| if (parent is DefaultFormalParameterImpl) { |
| fragment = DefaultParameterElementImpl( |
| name: name2 ?? '', |
| nameOffset: nameOffset2 ?? -1, |
| name2: name2, |
| nameOffset2: nameOffset2, |
| parameterKind: node.kind, |
| )..constantInitializer = parent.defaultValue; |
| _linker.elementNodes[fragment] = parent; |
| } else { |
| fragment = ParameterElementImpl( |
| name: name2 ?? '', |
| nameOffset: nameOffset2 ?? -1, |
| name2: name2, |
| nameOffset2: nameOffset2, |
| parameterKind: node.kind, |
| ); |
| _linker.elementNodes[fragment] = node; |
| } |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.isExplicitlyCovariant = node.covariantKeyword != null; |
| fragment.isFinal = node.isFinal; |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| |
| node.declaredFragment = fragment; |
| _linker.elementNodes[fragment] = node; |
| var refName = node.isNamed ? name2 : null; |
| _enclosingContext.addParameter(refName, fragment); |
| |
| var holder = _EnclosingContext( |
| instanceElementBuilder: null, |
| fragment: fragment, |
| ); |
| _withEnclosing(holder, () { |
| var formalParameters = node.parameters; |
| formalParameters.accept(this); |
| fragment.parameters = holder.parameters; |
| |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| fragment.typeParameters = holder.typeParameters; |
| } |
| }); |
| |
| _buildType(node.returnType); |
| } |
| |
| @override |
| void visitGenericFunctionType(covariant GenericFunctionTypeImpl node) { |
| var fragment = GenericFunctionTypeElementImpl.forOffset(node.offset); |
| _unitElement.encloseElement(fragment); |
| |
| node.declaredFragment = fragment; |
| _linker.elementNodes[fragment] = node; |
| |
| var holder = _EnclosingContext( |
| instanceElementBuilder: null, |
| fragment: fragment, |
| ); |
| _withEnclosing(holder, () { |
| var formalParameters = node.parameters; |
| formalParameters.accept(this); |
| fragment.parameters = holder.parameters; |
| |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| fragment.typeParameters = holder.typeParameters; |
| } |
| }); |
| |
| _buildType(node.returnType); |
| } |
| |
| @override |
| void visitGenericTypeAlias(covariant GenericTypeAliasImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var fragment = TypeAliasElementImpl(name, nameToken.offset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.isAugmentation = node.augmentKeyword != null; |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| _setDocumentation(fragment, node); |
| |
| node.declaredFragment = fragment; |
| _linker.elementNodes[fragment] = node; |
| |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| var reference = _enclosingContext.addTypeAlias(refName, fragment); |
| if (!fragment.isAugmentation) { |
| _libraryBuilder.declare(name, reference); |
| } |
| |
| var elementBuilder = _libraryBuilder.elementBuilderGetters[name]; |
| elementBuilder ??= _libraryBuilder.elementBuilderSetters[name]; |
| elementBuilder?.setPreviousFor(fragment); |
| if (fragment.isAugmentation && elementBuilder is TypeAliasElementBuilder) { |
| } else { |
| var libraryRef = _libraryBuilder.reference; |
| var containerRef = libraryRef.getChild('@typeAlias'); |
| var elementReference = containerRef.addChild(refName); |
| var element = TypeAliasElementImpl2(elementReference, fragment); |
| _libraryBuilder.element.typeAliases.add(element); |
| |
| elementBuilder = TypeAliasElementBuilder( |
| element: element, |
| firstFragment: fragment, |
| ); |
| _libraryBuilder.elementBuilderGetters[name] = elementBuilder; |
| } |
| |
| var holder = _EnclosingContext( |
| instanceElementBuilder: null, |
| fragment: fragment, |
| ); |
| _withEnclosing(holder, () { |
| node.typeParameters?.accept(this); |
| }); |
| fragment.typeParameters = holder.typeParameters; |
| |
| var typeNode = node.type; |
| typeNode.accept(this); |
| |
| if (typeNode is GenericFunctionTypeImpl) { |
| fragment.aliasedElement = typeNode.declaredFragment!; |
| } |
| |
| elementBuilder.addFragment(fragment); |
| } |
| |
| @override |
| void visitImplementsClause(ImplementsClause node) { |
| node.interfaces.accept(this); |
| } |
| |
| @override |
| void visitImportDirective(covariant ImportDirectiveImpl node) { |
| var index = _importDirectiveIndex++; |
| var importElement = _unitElement.libraryImports[index]; |
| importElement.metadata = _buildAnnotations(node.metadata); |
| node.element = importElement; |
| } |
| |
| @override |
| void visitLibraryDirective(covariant LibraryDirectiveImpl node) {} |
| |
| @override |
| void visitMethodDeclaration(covariant MethodDeclarationImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| var nameOffset = nameToken.offset; |
| |
| Reference reference; |
| ExecutableElementImpl executableFragment; |
| if (node.isGetter) { |
| var fragment = GetterFragmentImpl(name, nameOffset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.isAbstract = node.isAbstract; |
| fragment.isAugmentation = node.augmentKeyword != null; |
| fragment.isStatic = node.isStatic; |
| |
| // `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 (_enclosingContext.isDartCoreEnum && name == 'index') { |
| fragment.isAbstract = false; |
| } |
| |
| reference = _enclosingContext.addGetter(name, fragment); |
| executableFragment = fragment; |
| |
| if (!fragment.isAugmentation) { |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| _buildSyntheticVariable(name: refName, accessorElement: fragment); |
| } |
| } else if (node.isSetter) { |
| var fragment = SetterFragmentImpl(name, nameOffset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.isAbstract = node.isAbstract; |
| fragment.isAugmentation = node.augmentKeyword != null; |
| fragment.isStatic = node.isStatic; |
| |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| reference = _enclosingContext.addSetter(refName, fragment); |
| executableFragment = fragment; |
| |
| if (!fragment.isAugmentation) { |
| _buildSyntheticVariable(name: name, accessorElement: fragment); |
| } |
| } else { |
| var isUnaryMinus = false; |
| if (nameToken.lexeme == '-') { |
| var parameters = node.parameters; |
| isUnaryMinus = parameters != null && parameters.parameters.isEmpty; |
| } |
| |
| if (isUnaryMinus) { |
| name = 'unary-'; |
| } |
| |
| var fragment = MethodElementImpl(name, nameOffset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.isAbstract = node.isAbstract; |
| fragment.isAugmentation = node.augmentKeyword != null; |
| fragment.isStatic = node.isStatic; |
| |
| String refName; |
| if (isUnaryMinus) { |
| refName = 'unary-'; |
| } else { |
| refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| } |
| |
| reference = _enclosingContext.addMethod(refName, fragment); |
| executableFragment = fragment; |
| |
| { |
| var enclosingBuilder = _enclosingContext.instanceElementBuilder!; |
| |
| var lastFragment = enclosingBuilder.replaceGetter(fragment); |
| if (fragment.isAugmentation) { |
| fragment.augmentationTargetAny = lastFragment; |
| } |
| } |
| } |
| 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.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(executableFragment, node); |
| _setDocumentation(executableFragment, node); |
| |
| node.declaredFragment = executableFragment; |
| _linker.elementNodes[executableFragment] = node; |
| |
| _buildExecutableElementChildren( |
| reference: reference, |
| fragment: executableFragment, |
| formalParameters: node.parameters, |
| typeParameters: node.typeParameters, |
| ); |
| |
| _buildType(node.returnType); |
| } |
| |
| @override |
| void visitMixinDeclaration(covariant MixinDeclarationImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var fragment = MixinElementImpl(name, nameToken.offset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.isAugmentation = node.augmentKeyword != null; |
| fragment.isBase = node.baseKeyword != null; |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| _setDocumentation(fragment, node); |
| |
| node.declaredFragment = fragment; |
| _linker.elementNodes[fragment] = node; |
| |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| var reference = _enclosingContext.addMixin(refName, fragment); |
| if (!fragment.isAugmentation) { |
| _libraryBuilder.declare(name, reference); |
| } |
| |
| var elementBuilder = _libraryBuilder.elementBuilderGetters[name]; |
| elementBuilder?.setPreviousFor(fragment); |
| |
| // If the fragment is an augmentation, and the corresponding builder |
| // has correct type, add the fragment to the builder. Otherwise, create |
| // a new builder. |
| if (fragment.isAugmentation && elementBuilder is MixinElementBuilder) { |
| } else { |
| var libraryRef = _libraryBuilder.reference; |
| var containerRef = libraryRef.getChild('@mixin'); |
| var elementReference = containerRef.addChild(refName); |
| var element = MixinElementImpl2(elementReference, fragment); |
| _libraryBuilder.element.mixins.add(element); |
| |
| elementBuilder = MixinElementBuilder( |
| firstFragment: fragment, |
| element: element, |
| ); |
| _libraryBuilder.elementBuilderGetters[name] = elementBuilder; |
| } |
| |
| var holder = _EnclosingContext( |
| instanceElementBuilder: elementBuilder, |
| fragment: fragment, |
| ); |
| _withEnclosing(holder, () { |
| node.typeParameters?.accept(this); |
| _visitPropertyFirst<FieldDeclaration>(node.members); |
| }); |
| fragment.typeParameters = holder.typeParameters; |
| fragment.accessors = holder.propertyAccessors; |
| fragment.fields = holder.fields; |
| fragment.methods = holder.methods; |
| |
| node.onClause?.accept(this); |
| node.implementsClause?.accept(this); |
| elementBuilder.addFragment(fragment); |
| } |
| |
| @override |
| void visitMixinOnClause(MixinOnClause node) { |
| node.superclassConstraints.accept(this); |
| } |
| |
| @override |
| void visitNamedType(NamedType node) { |
| node.typeArguments?.accept(this); |
| } |
| |
| @override |
| void visitPartDirective(PartDirective node) { |
| var index = _partDirectiveIndex++; |
| var partElement = _unitElement.parts[index]; |
| partElement.metadata = _buildAnnotations(node.metadata); |
| } |
| |
| @override |
| void visitPartOfDirective(PartOfDirective node) { |
| var libraryElement = _libraryBuilder.element; |
| libraryElement.hasPartOfDirective = true; |
| } |
| |
| @override |
| void visitRecordTypeAnnotation(RecordTypeAnnotation node) { |
| node.positionalFields.accept(this); |
| node.namedFields?.accept(this); |
| } |
| |
| @override |
| void visitRecordTypeAnnotationNamedField( |
| RecordTypeAnnotationNamedField node, |
| ) { |
| node.type.accept(this); |
| } |
| |
| @override |
| void visitRecordTypeAnnotationNamedFields( |
| RecordTypeAnnotationNamedFields node, |
| ) { |
| node.fields.accept(this); |
| } |
| |
| @override |
| void visitRecordTypeAnnotationPositionalField( |
| RecordTypeAnnotationPositionalField node, |
| ) { |
| node.type.accept(this); |
| } |
| |
| @override |
| void visitSimpleFormalParameter( |
| covariant SimpleFormalParameterImpl node, |
| ) { |
| var nameToken = node.name; |
| var name2 = nameToken?.lexeme.nullIfEmpty; |
| var nameOffset2 = nameToken?.offset; |
| |
| ParameterElementImpl fragment; |
| var parent = node.parent; |
| if (parent is DefaultFormalParameterImpl && |
| _enclosingContext.hasDefaultFormalParameters) { |
| fragment = DefaultParameterElementImpl( |
| name: name2 ?? '', |
| nameOffset: nameOffset2 ?? -1, |
| name2: name2, |
| nameOffset2: nameOffset2, |
| parameterKind: node.kind, |
| )..constantInitializer = parent.defaultValue; |
| _linker.elementNodes[fragment] = parent; |
| var refName = node.isNamed ? name2 : null; |
| _enclosingContext.addParameter(refName, fragment); |
| } else { |
| fragment = ParameterElementImpl( |
| name: name2 ?? '', |
| nameOffset: nameOffset2 ?? -1, |
| name2: name2, |
| nameOffset2: nameOffset2, |
| parameterKind: node.kind, |
| ); |
| _linker.elementNodes[fragment] = node; |
| _enclosingContext.addParameter(null, fragment); |
| } |
| |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.hasImplicitType = node.type == null; |
| fragment.isExplicitlyCovariant = node.covariantKeyword != null; |
| fragment.isFinal = node.isFinal; |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| |
| node.declaredFragment = fragment; |
| |
| _buildType(node.type); |
| } |
| |
| @override |
| void visitSuperFormalParameter( |
| covariant SuperFormalParameterImpl node, |
| ) { |
| var nameToken = node.name; |
| var name2 = nameToken.lexeme.nullIfEmpty; |
| var nameOffset2 = nameToken.offset.nullIfNegative; |
| |
| SuperFormalParameterElementImpl fragment; |
| var parent = node.parent; |
| if (parent is DefaultFormalParameterImpl) { |
| fragment = DefaultSuperFormalParameterElementImpl( |
| name: name2 ?? '', |
| nameOffset: nameOffset2 ?? -1, |
| name2: name2, |
| nameOffset2: nameOffset2, |
| parameterKind: node.kind, |
| )..constantInitializer = parent.defaultValue; |
| _linker.elementNodes[fragment] = parent; |
| var refName = node.isNamed ? name2 : null; |
| _enclosingContext.addParameter(refName, fragment); |
| } else { |
| fragment = SuperFormalParameterElementImpl( |
| name: name2 ?? '', |
| nameOffset: nameOffset2 ?? -1, |
| name2: name2, |
| nameOffset2: nameOffset2, |
| parameterKind: node.kind, |
| ); |
| _linker.elementNodes[fragment] = node; |
| _enclosingContext.addParameter(null, fragment); |
| } |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.hasImplicitType = node.type == null && node.parameters == null; |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| |
| node.declaredFragment = fragment; |
| |
| // TODO(scheglov): check that we don't set reference for parameters |
| var holder = _EnclosingContext( |
| instanceElementBuilder: null, |
| fragment: fragment, |
| ); |
| _withEnclosing(holder, () { |
| var formalParameters = node.parameters; |
| if (formalParameters != null) { |
| formalParameters.accept(this); |
| fragment.parameters = holder.parameters; |
| } |
| |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| fragment.typeParameters = holder.typeParameters; |
| } |
| }); |
| |
| _buildType(node.type); |
| } |
| |
| @override |
| void visitTopLevelVariableDeclaration( |
| covariant TopLevelVariableDeclarationImpl node, |
| ) { |
| var enclosingRef = _enclosingContext.fragmentReference; |
| |
| var metadata = _buildAnnotations(node.metadata); |
| for (var variable in node.variables.variables) { |
| var nameToken = variable.name; |
| var name = nameToken.lexeme; |
| var nameOffset = nameToken.offset; |
| |
| TopLevelVariableElementImpl fragment; |
| if (node.variables.isConst) { |
| fragment = ConstTopLevelVariableElementImpl(name, nameOffset) |
| ..constantInitializer = variable.initializer; |
| } else { |
| fragment = TopLevelVariableElementImpl(name, nameOffset); |
| } |
| |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.hasInitializer = variable.initializer != 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.metadata = metadata; |
| _setCodeRange(fragment, variable); |
| _setDocumentation(fragment, node); |
| |
| if (node.variables.type == null) { |
| fragment.hasImplicitType = true; |
| } |
| |
| var refName = fragment.name2 ?? '${_nextUnnamedId++}'; |
| _enclosingContext.addTopLevelVariable(refName, fragment); |
| |
| if (!fragment.isAugmentation) { |
| { |
| var ref = enclosingRef.getChild('@getter').addChild(refName); |
| var getter = fragment.createImplicitGetter(ref); |
| _enclosingContext.addPropertyAccessorSynthetic(getter); |
| _libraryBuilder.declare(name, ref); |
| |
| var elementBuilder = GetterElementBuilder( |
| element: GetterElementImpl(getter), |
| firstFragment: getter, |
| ); |
| _libraryBuilder.elementBuilderGetters[name] = elementBuilder; |
| } |
| |
| if (fragment.hasSetter) { |
| var ref = enclosingRef.getChild('@setter').addChild(refName); |
| var setter = fragment.createImplicitSetter(ref); |
| _enclosingContext.addPropertyAccessorSynthetic(setter); |
| _libraryBuilder.declare('$name=', ref); |
| |
| var elementBuilder = SetterElementBuilder( |
| element: SetterElementImpl(setter), |
| firstFragment: setter, |
| ); |
| _libraryBuilder.elementBuilderSetters[name] = elementBuilder; |
| } |
| } |
| |
| _linker.elementNodes[fragment] = variable; |
| variable.declaredFragment = fragment; |
| |
| var elementBuilder = _libraryBuilder.elementBuilderVariables[name]; |
| elementBuilder ??= _libraryBuilder.elementBuilderGetters[name]; |
| elementBuilder?.setPreviousFor(fragment); |
| if (fragment.isAugmentation && |
| elementBuilder is TopLevelVariableElementBuilder) { |
| elementBuilder.addFragment(fragment); |
| } else { |
| var elementReference = _libraryBuilder.reference |
| .getChild('@topLevelVariable') |
| .addChild(refName); |
| var element = TopLevelVariableElementImpl2( |
| elementReference, |
| fragment, |
| ); |
| _libraryBuilder.element.topLevelVariables.add(element); |
| |
| elementBuilder = TopLevelVariableElementBuilder( |
| element: element, |
| firstFragment: fragment, |
| ); |
| _libraryBuilder.elementBuilderVariables[name] = elementBuilder; |
| } |
| } |
| |
| _buildType(node.variables.type); |
| } |
| |
| @override |
| void visitTypeArgumentList(TypeArgumentList node) { |
| node.arguments.accept(this); |
| } |
| |
| @override |
| void visitTypeParameter(covariant TypeParameterImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var fragment = TypeParameterElementImpl(name, nameToken.offset); |
| fragment.name2 = _getFragmentName(nameToken); |
| fragment.nameOffset2 = _getFragmentNameOffset(nameToken); |
| fragment.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(fragment, node); |
| |
| node.declaredFragment = fragment; |
| _linker.elementNodes[fragment] = node; |
| _enclosingContext.addTypeParameter(name, fragment); |
| |
| _buildType(node.bound); |
| } |
| |
| @override |
| void visitTypeParameterList(TypeParameterList node) { |
| node.typeParameters.accept(this); |
| } |
| |
| @override |
| void visitWithClause(WithClause node) { |
| node.mixinTypes.accept(this); |
| } |
| |
| List<ElementAnnotationImpl> _buildAnnotations(List<Annotation> nodeList) { |
| return _buildAnnotationsWithUnit(_unitElement, nodeList); |
| } |
| |
| void _buildExecutableElementChildren({ |
| required Reference reference, |
| required ExecutableElementImpl fragment, |
| FormalParameterList? formalParameters, |
| TypeParameterList? typeParameters, |
| }) { |
| var holder = _EnclosingContext( |
| instanceElementBuilder: null, |
| fragment: fragment, |
| hasDefaultFormalParameters: true, |
| ); |
| _withEnclosing(holder, () { |
| if (formalParameters != null) { |
| formalParameters.accept(this); |
| fragment.parameters = holder.parameters; |
| } |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| fragment.typeParameters = holder.typeParameters; |
| } |
| }); |
| } |
| |
| /// The [accessorElement] should not be an augmentation. |
| PropertyInducingElementImpl _buildSyntheticVariable({ |
| required String name, |
| required PropertyAccessorElementImpl accessorElement, |
| }) { |
| var refName = accessorElement.name2 ?? '${_nextUnnamedId++}'; |
| var enclosingRef = _enclosingContext.fragmentReference; |
| var enclosingElement = _enclosingContext.fragment; |
| |
| bool canUseExisting(PropertyInducingElement property) { |
| return property.isSynthetic || |
| accessorElement.isSetter && property.setter == null; |
| } |
| |
| PropertyInducingElementImpl? property; |
| if (enclosingElement is CompilationUnitElement) { |
| // Try to find the variable to attach the accessor. |
| var containerRef = enclosingRef.getChild('@topLevelVariable'); |
| for (var reference in containerRef.getChildrenByName(name)) { |
| var existing = reference.element; |
| if (existing is TopLevelVariableElementImpl && |
| canUseExisting(existing)) { |
| property = existing; |
| break; |
| } |
| } |
| |
| // If no variable, add a new one. |
| // In error cases could be a duplicate. |
| if (property == null) { |
| var reference = containerRef.addChild(name); |
| var variable = property = TopLevelVariableElementImpl(name, -1) |
| ..isSynthetic = true |
| ..name2 = accessorElement.name2; |
| _enclosingContext.addTopLevelVariableSynthetic(reference, variable); |
| |
| var variableElementReference = _libraryBuilder.reference |
| .getChild('@topLevelVariable') |
| .addChild(refName); |
| var variableElement = TopLevelVariableElementImpl2( |
| variableElementReference, |
| variable, |
| ); |
| _libraryBuilder.element.topLevelVariables.add(variableElement); |
| } |
| } else { |
| // Try to find the variable to attach the accessor. |
| var containerRef = enclosingRef.getChild('@field'); |
| for (var reference in containerRef.getChildrenByName(name)) { |
| var existing = reference.element; |
| if (existing is FieldElementImpl && canUseExisting(existing)) { |
| property = existing; |
| break; |
| } |
| } |
| |
| // If no variable, add a new one. |
| // In error cases could be a duplicate. |
| if (property == null) { |
| var reference = containerRef.addChild(name); |
| var field = property = FieldElementImpl(name, -1) |
| ..isStatic = accessorElement.isStatic |
| ..isSynthetic = true |
| ..name2 = accessorElement.name2; |
| _enclosingContext.addFieldSynthetic(reference, field); |
| } |
| } |
| |
| accessorElement.variable2 = property; |
| switch (accessorElement) { |
| case GetterFragmentImpl(): |
| property.getter = accessorElement; |
| case SetterFragmentImpl(): |
| property.setter = accessorElement; |
| } |
| return property; |
| } |
| |
| // TODO(scheglov): Maybe inline? |
| void _buildType(TypeAnnotation? node) { |
| node?.accept(this); |
| } |
| |
| void _builtRepresentationDeclaration({ |
| required ExtensionTypeElementImpl extensionFragment, |
| required ExtensionTypeDeclarationImpl extensionNode, |
| required RepresentationDeclarationImpl representation, |
| }) { |
| if (extensionFragment.augmentationTarget != null) { |
| return; |
| } |
| |
| var fieldNameToken = representation.fieldName; |
| var fieldName = fieldNameToken.lexeme.ifNotEmptyOrElse('<empty>'); |
| |
| var fieldFragment = FieldElementImpl( |
| fieldName, |
| fieldNameToken.offset, |
| ); |
| fieldFragment.name2 = _getFragmentName(fieldNameToken); |
| fieldFragment.nameOffset2 = _getFragmentNameOffset(fieldNameToken); |
| fieldFragment.isFinal = true; |
| fieldFragment.metadata = _buildAnnotations(representation.fieldMetadata); |
| |
| var fieldBeginToken = |
| representation.fieldMetadata.beginToken ?? representation.fieldType; |
| var fieldCodeRangeOffset = fieldBeginToken.offset; |
| var fieldCodeRangeLength = fieldNameToken.end - fieldCodeRangeOffset; |
| fieldFragment.setCodeRange(fieldCodeRangeOffset, fieldCodeRangeLength); |
| |
| representation.fieldFragment = fieldFragment; |
| _linker.elementNodes[fieldFragment] = representation; |
| _enclosingContext.addNonSyntheticField(fieldName, fieldFragment); |
| |
| var nameOffset2 = fieldNameToken.offset.nullIfNegative; |
| |
| var formalParameterElement = FieldFormalParameterElementImpl( |
| name: fieldName, |
| nameOffset: nameOffset2 ?? -1, |
| name2: fieldName.nullIfEmpty, |
| nameOffset2: nameOffset2, |
| parameterKind: ParameterKind.REQUIRED, |
| ) |
| ..field = fieldFragment |
| ..hasImplicitType = true; |
| formalParameterElement.name2 = _getFragmentName(fieldNameToken); |
| formalParameterElement.nameOffset2 = _getFragmentNameOffset(fieldNameToken); |
| formalParameterElement.setCodeRange( |
| fieldCodeRangeOffset, |
| fieldCodeRangeLength, |
| ); |
| |
| extensionFragment.element.representation = fieldFragment; |
| |
| { |
| String name; |
| int? periodOffset; |
| int nameOffset; |
| int? nameEnd; |
| var constructorNameNode = representation.constructorName; |
| if (constructorNameNode != null) { |
| var nameToken = constructorNameNode.name; |
| name = nameToken.lexeme.ifEqualThen('new', ''); |
| periodOffset = constructorNameNode.period.offset; |
| nameOffset = nameToken.offset; |
| nameEnd = nameToken.end; |
| } else { |
| name = ''; |
| nameOffset = extensionNode.name.offset; |
| nameEnd = extensionNode.name.end; |
| } |
| |
| var constructorFragment = ConstructorElementImpl(name, nameOffset) |
| ..isAugmentation = extensionNode.augmentKeyword != null |
| ..isConst = extensionNode.constKeyword != null |
| ..periodOffset = periodOffset |
| ..nameEnd = nameEnd |
| ..parameters = [formalParameterElement]; |
| constructorFragment.typeName = extensionFragment.name2; |
| constructorFragment.typeNameOffset = extensionFragment.nameOffset2; |
| if (representation.constructorName case var constructorName?) { |
| constructorFragment.name2 = constructorName.name.lexeme; |
| constructorFragment.nameOffset2 = constructorName.name.offset; |
| } else { |
| constructorFragment.name2 = 'new'; |
| } |
| _setCodeRange(constructorFragment, representation); |
| |
| representation.constructorFragment = constructorFragment; |
| _linker.elementNodes[constructorFragment] = representation; |
| _enclosingContext.addConstructor(constructorFragment); |
| |
| extensionFragment.element.primaryConstructor = constructorFragment; |
| } |
| |
| representation.fieldType.accept(this); |
| } |
| |
| String? _getFragmentName(Token? nameToken) { |
| if (nameToken == null || nameToken.isSynthetic) { |
| return null; |
| } |
| return nameToken.lexeme; |
| } |
| |
| int? _getFragmentNameOffset(Token? nameToken) { |
| if (nameToken == null || nameToken.isSynthetic) { |
| return null; |
| } |
| return nameToken.offset; |
| } |
| |
| void _visitPropertyFirst<T extends AstNode>(List<AstNode> nodes) { |
| // When loading from bytes, we read fields first. |
| // There is no particular reason for this - we just have to store |
| // either non-synthetic fields first, or non-synthetic property |
| // accessors first. And we arbitrary decided to store fields first. |
| for (var node in nodes) { |
| if (node is T) { |
| node.accept(this); |
| } |
| } |
| |
| // ...then we load non-synthetic accessors. |
| for (var node in nodes) { |
| if (node is! T) { |
| node.accept(this); |
| } |
| } |
| } |
| |
| /// Make the given [context] be the current one while running [f]. |
| void _withEnclosing(_EnclosingContext context, void Function() f) { |
| var previousContext = _enclosingContext; |
| _enclosingContext = context; |
| try { |
| f(); |
| } finally { |
| _enclosingContext = previousContext; |
| } |
| } |
| |
| static List<ElementAnnotationImpl> _buildAnnotationsWithUnit( |
| CompilationUnitElementImpl unitElement, |
| List<Annotation> nodeList, |
| ) { |
| var length = nodeList.length; |
| if (length == 0) { |
| return const <ElementAnnotationImpl>[]; |
| } |
| |
| return List<ElementAnnotationImpl>.generate(length, (index) { |
| var ast = nodeList[index] as AnnotationImpl; |
| var element = ElementAnnotationImpl(unitElement); |
| element.annotationAst = ast; |
| ast.elementAnnotation = element; |
| return element; |
| }, growable: false); |
| } |
| |
| static void _setCodeRange(ElementImpl element, AstNode node) { |
| var parent = node.parent; |
| if (node is FormalParameter && parent is DefaultFormalParameter) { |
| node = parent; |
| } |
| |
| if (node is VariableDeclaration && parent is VariableDeclarationList) { |
| var fieldDeclaration = parent.parent; |
| if (fieldDeclaration != null && parent.variables.first == node) { |
| var offset = fieldDeclaration.offset; |
| element.setCodeRange(offset, node.end - offset); |
| return; |
| } |
| } |
| |
| element.setCodeRange(node.offset, node.length); |
| } |
| |
| static void _setDocumentation(ElementImpl element, AnnotatedNode node) { |
| element.documentationComment = |
| getCommentNodeRawText(node.documentationComment); |
| } |
| } |
| |
| class _EnclosingContext { |
| final InstanceElementBuilder? instanceElementBuilder; |
| final ElementImpl fragment; |
| final List<ClassElementImpl> _classes = []; |
| final List<ConstructorElementImpl> _constructors = []; |
| final List<EnumElementImpl> _enums = []; |
| final List<ExtensionElementImpl> _extensions = []; |
| final List<ExtensionTypeElementImpl> _extensionTypes = []; |
| final List<FieldElementImpl> _fields = []; |
| final List<TopLevelFunctionFragmentImpl> _functions = []; |
| final List<MethodElementImpl> _methods = []; |
| final List<MixinElementImpl> _mixins = []; |
| final List<ParameterElementImpl> _parameters = []; |
| final List<PropertyAccessorElementImpl> _propertyAccessors = []; |
| final List<TopLevelVariableElementImpl> _topLevelVariables = []; |
| final List<TypeAliasElementImpl> _typeAliases = []; |
| final List<TypeParameterElementImpl> _typeParameters = []; |
| |
| /// A class can have `const` constructors, and if it has we need values |
| /// of final instance fields. |
| final bool constFieldsForFinalInstance; |
| |
| /// Not all optional formal parameters can have default values. |
| /// For example, formal parameters of methods can, but formal parameters |
| /// of function types - not. This flag specifies if we should create |
| /// [ParameterElementImpl]s or [DefaultParameterElementImpl]s. |
| final bool hasDefaultFormalParameters; |
| |
| _EnclosingContext({ |
| required this.instanceElementBuilder, |
| required this.fragment, |
| this.constFieldsForFinalInstance = false, |
| this.hasDefaultFormalParameters = false, |
| }); |
| |
| List<ClassElementImpl> get classes { |
| return _classes.toFixedList(); |
| } |
| |
| List<ConstructorElementImpl> get constructors { |
| return _constructors.toFixedList(); |
| } |
| |
| List<EnumElementImpl> get enums { |
| return _enums.toFixedList(); |
| } |
| |
| List<ExtensionElementImpl> get extensions { |
| return _extensions.toFixedList(); |
| } |
| |
| List<ExtensionTypeElementImpl> get extensionTypes { |
| return _extensionTypes.toFixedList(); |
| } |
| |
| List<FieldElementImpl> get fields { |
| return _fields.toFixedList(); |
| } |
| |
| Reference get fragmentReference { |
| return fragment.reference!; |
| } |
| |
| List<TopLevelFunctionFragmentImpl> get functions { |
| return _functions.toFixedList(); |
| } |
| |
| bool get isDartCoreEnum { |
| var fragment = this.fragment; |
| return fragment is ClassElementImpl && fragment.isDartCoreEnum; |
| } |
| |
| List<MethodElementImpl> get methods { |
| return _methods.toFixedList(); |
| } |
| |
| List<MixinElementImpl> get mixins { |
| return _mixins.toFixedList(); |
| } |
| |
| List<ParameterElementImpl> get parameters { |
| return _parameters.toFixedList(); |
| } |
| |
| List<PropertyAccessorElementImpl> get propertyAccessors { |
| return _propertyAccessors.toFixedList(); |
| } |
| |
| List<TopLevelVariableElementImpl> get topLevelVariables { |
| return _topLevelVariables.toFixedList(); |
| } |
| |
| List<TypeAliasElementImpl> get typeAliases { |
| return _typeAliases.toFixedList(); |
| } |
| |
| List<TypeParameterElementImpl> get typeParameters { |
| return _typeParameters.toFixedList(); |
| } |
| |
| Reference addClass(String name, ClassElementImpl element) { |
| _classes.add(element); |
| var containerName = |
| element.isAugmentation ? '@classAugmentation' : '@class'; |
| return _addReference(containerName, name, element); |
| } |
| |
| Reference addConstructor(ConstructorElementImpl element) { |
| _constructors.add(element); |
| |
| var containerName = |
| element.isAugmentation ? '@constructorAugmentation' : '@constructor'; |
| var referenceName = element.name.ifNotEmptyOrElse('new'); |
| return _addReference(containerName, referenceName, element); |
| } |
| |
| Reference addEnum(String name, EnumElementImpl element) { |
| _enums.add(element); |
| var containerName = element.isAugmentation ? '@enumAugmentation' : '@enum'; |
| return _addReference(containerName, name, element); |
| } |
| |
| Reference addExtension(String name, ExtensionElementImpl element) { |
| _extensions.add(element); |
| var containerName = |
| element.isAugmentation ? '@extensionAugmentation' : '@extension'; |
| return _addReference(containerName, name, element); |
| } |
| |
| Reference addExtensionType(String name, ExtensionTypeElementImpl element) { |
| _extensionTypes.add(element); |
| var containerName = element.isAugmentation |
| ? '@extensionTypeAugmentation' |
| : '@extensionType'; |
| return _addReference(containerName, name, element); |
| } |
| |
| Reference addField(String name, FieldElementImpl element) { |
| _fields.add(element); |
| var containerName = |
| element.isAugmentation ? '@fieldAugmentation' : '@field'; |
| return _addReference(containerName, name, element); |
| } |
| |
| void addFieldSynthetic(Reference reference, FieldElementImpl element) { |
| _fields.add(element); |
| _bindReference(reference, element); |
| } |
| |
| Reference addFunction(String name, TopLevelFunctionFragmentImpl element) { |
| _functions.add(element); |
| var containerName = |
| element.isAugmentation ? '@functionAugmentation' : '@function'; |
| return _addReference(containerName, name, element); |
| } |
| |
| Reference addGetter(String name, PropertyAccessorElementImpl element) { |
| _propertyAccessors.add(element); |
| var containerName = |
| element.isAugmentation ? '@getterAugmentation' : '@getter'; |
| return _addReference(containerName, name, element); |
| } |
| |
| Reference addMethod(String name, MethodElementImpl element) { |
| _methods.add(element); |
| var containerName = |
| element.isAugmentation ? '@methodAugmentation' : '@method'; |
| return _addReference(containerName, name, element); |
| } |
| |
| Reference addMixin(String name, MixinElementImpl element) { |
| _mixins.add(element); |
| var containerName = |
| element.isAugmentation ? '@mixinAugmentation' : '@mixin'; |
| return _addReference(containerName, name, element); |
| } |
| |
| void addNonSyntheticField(String name, FieldElementImpl element) { |
| addField(name, element); |
| |
| // Augmenting a variable with a variable only alters its initializer. |
| // So, don't create getter and setter. |
| if (element.isAugmentation) { |
| return; |
| } |
| |
| { |
| var getterRef = fragmentReference.getChild('@getter').addChild(name); |
| var getter = element.createImplicitGetter(getterRef); |
| _propertyAccessors.add(getter); |
| } |
| |
| if (element.hasSetter) { |
| var setterRef = fragmentReference.getChild('@setter').addChild(name); |
| var setter = element.createImplicitSetter(setterRef); |
| _propertyAccessors.add(setter); |
| } |
| } |
| |
| Reference? addParameter(String? name, ParameterElementImpl element) { |
| _parameters.add(element); |
| if (name == null) { |
| return null; |
| } else { |
| return _addReference('@parameter', name, element); |
| } |
| } |
| |
| void addPropertyAccessorSynthetic(PropertyAccessorElementImpl element) { |
| _propertyAccessors.add(element); |
| } |
| |
| Reference addSetter(String name, PropertyAccessorElementImpl element) { |
| _propertyAccessors.add(element); |
| var containerName = |
| element.isAugmentation ? '@setterAugmentation' : '@setter'; |
| return _addReference(containerName, name, element); |
| } |
| |
| Reference addTopLevelVariable( |
| String name, TopLevelVariableElementImpl element) { |
| _topLevelVariables.add(element); |
| var containerName = element.isAugmentation |
| ? '@topLevelVariableAugmentation' |
| : '@topLevelVariable'; |
| return _addReference(containerName, name, element); |
| } |
| |
| void addTopLevelVariableSynthetic( |
| Reference reference, TopLevelVariableElementImpl element) { |
| _topLevelVariables.add(element); |
| _bindReference(reference, element); |
| } |
| |
| Reference addTypeAlias(String name, TypeAliasElementImpl element) { |
| _typeAliases.add(element); |
| var containerName = |
| element.isAugmentation ? '@typeAliasAugmentation' : '@typeAlias'; |
| return _addReference(containerName, name, element); |
| } |
| |
| void addTypeParameter(String name, TypeParameterElementImpl fragment) { |
| _typeParameters.add(fragment); |
| this.fragment.encloseElement(fragment); |
| } |
| |
| Reference _addReference( |
| String containerName, |
| String name, |
| ElementImpl element, |
| ) { |
| var containerRef = fragmentReference.getChild(containerName); |
| var reference = containerRef.addChild(name); |
| _bindReference(reference, element); |
| return reference; |
| } |
| |
| void _bindReference(Reference reference, ElementImpl fragment) { |
| reference.element = fragment; |
| fragment.reference = reference; |
| this.fragment.encloseElement(fragment); |
| } |
| } |