| // 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: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/string.dart'; |
| import 'package:collection/collection.dart'; |
| |
| class ElementBuilder extends ThrowingAstVisitor<void> { |
| final LibraryBuilder _libraryBuilder; |
| final LibraryOrAugmentationElementImpl _container; |
| final CompilationUnitElementImpl _unitElement; |
| |
| var _isFirstLibraryDirective = true; |
| var _augmentationDirectiveIndex = 0; |
| var _exportDirectiveIndex = 0; |
| var _importDirectiveIndex = 0; |
| var _partDirectiveIndex = 0; |
| |
| _EnclosingContext _enclosingContext; |
| var _nextUnnamedExtensionId = 0; |
| |
| ElementBuilder({ |
| required LibraryBuilder libraryBuilder, |
| required LibraryOrAugmentationElementImpl container, |
| required Reference unitReference, |
| required CompilationUnitElementImpl unitElement, |
| }) : _libraryBuilder = libraryBuilder, |
| _container = container, |
| _unitElement = unitElement, |
| _enclosingContext = _EnclosingContext(unitReference, 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; |
| } |
| |
| /// Build exports and imports, metadata into [_container]. |
| void buildLibraryElementChildren(CompilationUnitImpl unit) { |
| unit.directives.accept(this); |
| |
| if (_isFirstLibraryDirective) { |
| _isFirstLibraryDirective = false; |
| var firstDirective = unit.directives.firstOrNull; |
| if (firstDirective != null) { |
| _container.documentationComment = getCommentNodeRawText( |
| firstDirective.documentationComment, |
| ); |
| var firstDirectiveMetadata = firstDirective.element?.metadata; |
| if (firstDirectiveMetadata != null) { |
| _container.metadata = firstDirectiveMetadata; |
| } |
| } |
| } |
| } |
| |
| @override |
| void visitAugmentationImportDirective(AugmentationImportDirective node) { |
| var index = _augmentationDirectiveIndex++; |
| var element = _container.augmentationImports[index]; |
| element.metadata = _buildAnnotations(node.metadata); |
| } |
| |
| @override |
| void visitClassDeclaration(covariant ClassDeclarationImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var element = ClassElementImpl(name, nameToken.offset); |
| element.isAbstract = node.abstractKeyword != null; |
| element.isAugmentation = node.augmentKeyword != null; |
| element.isBase = node.baseKeyword != null; |
| element.isFinal = node.finalKeyword != null; |
| element.isInterface = node.interfaceKeyword != null; |
| element.isMacro = node.macroKeyword != null; |
| element.isMixinClass = node.mixinKeyword != null; |
| if (node.sealedKeyword != null) { |
| element.isAbstract = true; |
| element.isSealed = true; |
| } |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| _setDocumentation(element, node); |
| |
| node.declaredElement = element; |
| _linker.elementNodes[element] = node; |
| |
| var reference = _enclosingContext.addClass(name, element); |
| if (!element.isAugmentation) { |
| _libraryBuilder.declare(name, reference); |
| } |
| |
| var holder = _EnclosingContext(reference, element); |
| _withEnclosing(holder, () { |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| element.typeParameters = holder.typeParameters; |
| } |
| }); |
| |
| node.extendsClause?.accept(this); |
| node.withClause?.accept(this); |
| node.implementsClause?.accept(this); |
| _buildClass(node); |
| |
| _libraryBuilder.updateAugmentationTarget(name, element); |
| |
| if (element.augmentationTarget != null) { |
| switch (_libraryBuilder.getAugmentedBuilder(name)) { |
| case AugmentedClassDeclarationBuilder builder: |
| builder.augment(element); |
| } |
| } else { |
| _libraryBuilder.putAugmentedBuilder( |
| name, |
| AugmentedClassDeclarationBuilder( |
| declaration: element, |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void visitClassTypeAlias(covariant ClassTypeAliasImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var element = ClassElementImpl(name, nameToken.offset); |
| element.isAbstract = node.abstractKeyword != null; |
| element.isBase = node.baseKeyword != null; |
| element.isFinal = node.finalKeyword != null; |
| element.isInterface = node.interfaceKeyword != null; |
| element.isMacro = node.macroKeyword != null; |
| element.isMixinApplication = true; |
| element.isMixinClass = node.mixinKeyword != null; |
| if (node.sealedKeyword != null) { |
| element.isAbstract = true; |
| element.isSealed = true; |
| } |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| _setDocumentation(element, node); |
| |
| node.declaredElement = element; |
| _linker.elementNodes[element] = node; |
| |
| var reference = _enclosingContext.addClass(name, element); |
| _libraryBuilder.declare(name, reference); |
| |
| var holder = _EnclosingContext(reference, element); |
| _withEnclosing(holder, () { |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| element.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.nameEnd = nameNode.end; |
| element.periodOffset = node.period?.offset; |
| _setCodeRange(element, node); |
| _setDocumentation(element, node); |
| |
| if (element.isConst || element.isFactory) { |
| element.constantInitializers = node.initializers; |
| } |
| |
| node.declaredElement = element; |
| _linker.elementNodes[element] = node; |
| |
| var reference = _enclosingContext.addConstructor(element); |
| _buildExecutableElementChildren( |
| reference: reference, |
| element: element, |
| formalParameters: node.parameters, |
| ); |
| } |
| |
| @override |
| void visitDefaultFormalParameter(DefaultFormalParameter node) { |
| node.parameter.accept(this); |
| } |
| |
| @override |
| void visitEnumDeclaration(covariant EnumDeclarationImpl node) { |
| var nameNode = node.name; |
| var name = nameNode.lexeme; |
| var nameOffset = nameNode.offset; |
| |
| var element = EnumElementImpl(name, nameOffset); |
| element.isAugmentation = node.augmentKeyword != null; |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| _setDocumentation(element, node); |
| |
| node.declaredElement = element; |
| _linker.elementNodes[element] = node; |
| |
| var reference = _enclosingContext.addEnum(name, element); |
| _libraryBuilder.declare(name, reference); |
| |
| _libraryBuilder.updateAugmentationTarget(name, element); |
| |
| var holder = _EnclosingContext( |
| reference, |
| element, |
| 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 name = constant.name.lexeme; |
| var field = ConstFieldElementImpl(name, constant.name.offset) |
| ..hasImplicitType = true |
| ..hasInitializer = true |
| ..isAugmentation = constant.augmentKeyword != null |
| ..isConst = true |
| ..isEnumConstant = true |
| ..isStatic = true; |
| _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, element.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.declaredElement = field; |
| variableDeclaration.declaredElement = field; |
| VariableDeclarationListImpl( |
| comment: null, |
| metadata: null, |
| lateKeyword: null, |
| keyword: null, |
| type: null, |
| variables: [variableDeclaration], |
| ); |
| _linker.elementNodes[field] = variableDeclaration; |
| |
| field.constantInitializer = initializer; |
| holder.addNonSyntheticField(field); |
| valuesElements.add( |
| SimpleIdentifierImpl( |
| StringToken(TokenType.STRING, name, -1), |
| ), |
| ); |
| valuesNames.add(name); |
| } |
| |
| // Build the 'values' field. |
| if (element.augmentationTarget == null) { |
| var valuesField = ConstFieldElementImpl('values', -1) |
| ..isConst = true |
| ..isStatic = true |
| ..isSynthetic = true; |
| 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, element.name, -1), |
| typeArguments: null, |
| question: null, |
| )..element = element, |
| ], |
| 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(valuesField); |
| |
| _libraryBuilder.implicitEnumNodes[element] = ImplicitEnumNodes( |
| element: element, |
| valuesTypeNode: valuesTypeNode, |
| valuesNode: variableDeclaration, |
| valuesElement: valuesField, |
| valuesNames: valuesNames, |
| valuesInitializer: initializer, |
| ); |
| } else { |
| var declaration = element.augmented.declaration; |
| 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); |
| }); |
| |
| element.accessors = holder.propertyAccessors; |
| element.constructors = holder.constructors; |
| element.fields = holder.fields; |
| element.methods = holder.methods; |
| element.typeParameters = holder.typeParameters; |
| |
| if (element.augmentationTarget != null) { |
| var builder = _libraryBuilder.getAugmentedBuilder(name); |
| if (builder is AugmentedEnumDeclarationBuilder) { |
| builder.augment(element); |
| } |
| } else { |
| _libraryBuilder.putAugmentedBuilder( |
| name, |
| AugmentedEnumDeclarationBuilder( |
| declaration: element, |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void visitExportDirective(covariant ExportDirectiveImpl node) { |
| var index = _exportDirectiveIndex++; |
| var exportElement = _container.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 element = ExtensionElementImpl(name, nameOffset); |
| element.isAugmentation = node.augmentKeyword != null; |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| _setDocumentation(element, node); |
| |
| node.declaredElement = element; |
| _linker.elementNodes[element] = node; |
| |
| var refName = name ?? '${_nextUnnamedExtensionId++}'; |
| var reference = _enclosingContext.addExtension(refName, element); |
| |
| if (name != null) { |
| _libraryBuilder.declare(name, reference); |
| } |
| |
| var holder = _EnclosingContext(reference, element); |
| _withEnclosing(holder, () { |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| element.typeParameters = holder.typeParameters; |
| } |
| }); |
| |
| // TODO(scheglov): don't create a duplicate |
| { |
| var holder = _EnclosingContext(reference, element); |
| _withEnclosing(holder, () { |
| _visitPropertyFirst<FieldDeclaration>(node.members); |
| }); |
| element.accessors = holder.propertyAccessors; |
| element.fields = holder.fields; |
| element.methods = holder.methods; |
| } |
| |
| node.onClause?.accept(this); |
| |
| if (name != null) { |
| _libraryBuilder.updateAugmentationTarget(name, element); |
| |
| if (element.augmentationTarget != null) { |
| var builder = _libraryBuilder.getAugmentedBuilder(name); |
| if (builder is AugmentedExtensionDeclarationBuilder) { |
| builder.augment(element); |
| } |
| } else { |
| _libraryBuilder.putAugmentedBuilder( |
| name, |
| AugmentedExtensionDeclarationBuilder( |
| declaration: element, |
| ), |
| ); |
| } |
| } |
| } |
| |
| @override |
| void visitExtensionOnClause(ExtensionOnClause node) { |
| node.extendedType.accept(this); |
| } |
| |
| @override |
| void visitExtensionTypeDeclaration( |
| covariant ExtensionTypeDeclarationImpl node, |
| ) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var element = ExtensionTypeElementImpl(name, nameToken.offset); |
| element.isAugmentation = node.augmentKeyword != null; |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| _setDocumentation(element, node); |
| |
| node.declaredElement = element; |
| _linker.elementNodes[element] = node; |
| |
| var reference = _enclosingContext.addExtensionType(name, element); |
| if (!element.isAugmentation) { |
| _libraryBuilder.declare(name, reference); |
| } |
| |
| element.isAugmentationChainStart = true; |
| _libraryBuilder.updateAugmentationTarget(name, element); |
| |
| var holder = _EnclosingContext(reference, element); |
| _withEnclosing(holder, () { |
| node.typeParameters?.accept(this); |
| _builtRepresentationDeclaration( |
| extensionNode: node, |
| representation: node.representation, |
| extensionElement: element, |
| ); |
| _visitPropertyFirst<FieldDeclaration>(node.members); |
| }); |
| |
| element.accessors = holder.propertyAccessors; |
| element.constructors = holder.constructors; |
| element.fields = holder.fields; |
| element.methods = holder.methods; |
| element.typeParameters = holder.typeParameters; |
| |
| var executables = const <ExecutableElementImpl>[] |
| .followedBy(element.accessors) |
| .followedBy(element.methods); |
| for (var executable in executables) { |
| executable.isExtensionTypeMember = true; |
| } |
| |
| node.implementsClause?.accept(this); |
| |
| // TODO(scheglov): We cannot do this anymore. |
| // Not for class augmentations, not for classes. |
| _resolveConstructorFieldFormals(element); |
| |
| if (element.augmentationTarget != null) { |
| var builder = _libraryBuilder.getAugmentedBuilder(name); |
| if (builder is AugmentedExtensionTypeDeclarationBuilder) { |
| builder.augment(element); |
| } |
| } else { |
| _libraryBuilder.putAugmentedBuilder( |
| name, |
| AugmentedExtensionTypeDeclarationBuilder( |
| declaration: element, |
| ), |
| ); |
| } |
| } |
| |
| @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 element = FieldElementImpl(name, nameOffset); |
| if (variable.initializer case var initializer?) { |
| if (node.fields.isConst) { |
| element = ConstFieldElementImpl(name, nameOffset) |
| ..constantInitializer = initializer; |
| } else if (_enclosingContext.constFieldsForFinalInstance) { |
| if (node.fields.isFinal && !node.isStatic) { |
| var constElement = ConstFieldElementImpl(name, nameOffset) |
| ..constantInitializer = initializer; |
| element = constElement; |
| _libraryBuilder.finalInstanceFields.add(constElement); |
| } |
| } |
| } |
| |
| element.hasInitializer = variable.initializer != null; |
| element.isAbstract = node.abstractKeyword != null; |
| element.isAugmentation = node.augmentKeyword != null; |
| element.isConst = node.fields.isConst; |
| element.isCovariant = node.covariantKeyword != null; |
| element.isExternal = node.externalKeyword != null; |
| element.isFinal = node.fields.isFinal; |
| element.isLate = node.fields.isLate; |
| element.isStatic = node.isStatic; |
| element.metadata = metadata; |
| _setCodeRange(element, variable); |
| _setDocumentation(element, node); |
| |
| if (node.fields.type == null) { |
| element.hasImplicitType = true; |
| } |
| |
| _enclosingContext.addNonSyntheticField(element); |
| |
| _linker.elementNodes[element] = variable; |
| variable.declaredElement = element; |
| } |
| _buildType(node.fields.type); |
| } |
| |
| @override |
| void visitFieldFormalParameter( |
| covariant FieldFormalParameterImpl node, |
| ) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| var nameOffset = nameToken.offset; |
| |
| ParameterElementImpl element; |
| var parent = node.parent; |
| if (parent is DefaultFormalParameterImpl) { |
| element = DefaultFieldFormalParameterElementImpl( |
| name: name, |
| nameOffset: nameOffset, |
| parameterKind: node.kind, |
| )..constantInitializer = parent.defaultValue; |
| _linker.elementNodes[element] = parent; |
| var refName = node.isNamed ? name : null; |
| _enclosingContext.addParameter(refName, element); |
| } else { |
| element = FieldFormalParameterElementImpl( |
| name: name, |
| nameOffset: nameOffset, |
| parameterKind: node.kind, |
| ); |
| _linker.elementNodes[element] = node; |
| _enclosingContext.addParameter(null, element); |
| } |
| element.hasImplicitType = node.type == null && node.parameters == null; |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| |
| node.declaredElement = element; |
| |
| // TODO(scheglov): check that we don't set reference for parameters |
| var fakeReference = Reference.root(); |
| var holder = _EnclosingContext(fakeReference, element); |
| _withEnclosing(holder, () { |
| var formalParameters = node.parameters; |
| if (formalParameters != null) { |
| formalParameters.accept(this); |
| element.parameters = holder.parameters; |
| } |
| |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| element.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 executableElement; |
| if (node.isGetter) { |
| var element = PropertyAccessorElementImpl(name, nameOffset); |
| element.isAugmentation = node.augmentKeyword != null; |
| element.isGetter = true; |
| element.isStatic = true; |
| |
| reference = _enclosingContext.addGetter(name, element); |
| executableElement = element; |
| |
| if (!element.isAugmentation) { |
| _buildSyntheticVariable(name: name, accessorElement: element); |
| } |
| |
| _libraryBuilder.topVariables.addAccessor(element); |
| } else if (node.isSetter) { |
| var element = PropertyAccessorElementImpl(name, nameOffset); |
| element.isAugmentation = node.augmentKeyword != null; |
| element.isSetter = true; |
| element.isStatic = true; |
| |
| reference = _enclosingContext.addSetter(name, element); |
| executableElement = element; |
| |
| if (!element.isAugmentation) { |
| _buildSyntheticVariable(name: name, accessorElement: element); |
| } |
| |
| _libraryBuilder.topVariables.addAccessor(element); |
| } else { |
| var element = FunctionElementImpl(name, nameOffset); |
| element.isAugmentation = node.augmentKeyword != null; |
| element.isStatic = true; |
| reference = _enclosingContext.addFunction(name, element); |
| executableElement = element; |
| |
| _libraryBuilder.updateAugmentationTarget(name, element); |
| } |
| |
| executableElement.hasImplicitReturnType = node.returnType == null; |
| executableElement.isAsynchronous = body.isAsynchronous; |
| executableElement.isExternal = node.externalKeyword != null; |
| executableElement.isGenerator = body.isGenerator; |
| executableElement.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(executableElement, node); |
| _setDocumentation(executableElement, node); |
| |
| node.declaredElement = executableElement; |
| _linker.elementNodes[executableElement] = node; |
| |
| _buildExecutableElementChildren( |
| reference: reference, |
| element: executableElement, |
| formalParameters: functionExpression.parameters, |
| typeParameters: functionExpression.typeParameters, |
| ); |
| |
| var getterOrSetterName = node.isSetter ? '$name=' : name; |
| |
| if (!executableElement.isAugmentation) { |
| _libraryBuilder.declare(getterOrSetterName, reference); |
| } |
| |
| _buildType(node.returnType); |
| } |
| |
| @override |
| void visitFunctionTypeAlias(covariant FunctionTypeAliasImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var element = TypeAliasElementImpl(name, nameToken.offset); |
| element.isFunctionTypeAliasBased = true; |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| _setDocumentation(element, node); |
| |
| node.declaredElement = element; |
| _linker.elementNodes[element] = node; |
| |
| var reference = _enclosingContext.addTypeAlias(name, element); |
| _libraryBuilder.declare(name, reference); |
| |
| var holder = _EnclosingContext(reference, element); |
| _withEnclosing(holder, () { |
| node.typeParameters?.accept(this); |
| node.returnType?.accept(this); |
| node.parameters.accept(this); |
| }); |
| |
| var aliasedElement = GenericFunctionTypeElementImpl.forOffset( |
| nameToken.offset, |
| ); |
| aliasedElement.parameters = holder.parameters; |
| |
| element.typeParameters = holder.typeParameters; |
| element.aliasedElement = aliasedElement; |
| } |
| |
| @override |
| void visitFunctionTypedFormalParameter( |
| covariant FunctionTypedFormalParameterImpl node, |
| ) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| var nameOffset = nameToken.offset; |
| |
| ParameterElementImpl element; |
| var parent = node.parent; |
| if (parent is DefaultFormalParameterImpl) { |
| element = DefaultParameterElementImpl( |
| name: name, |
| nameOffset: nameOffset, |
| parameterKind: node.kind, |
| )..constantInitializer = parent.defaultValue; |
| _linker.elementNodes[element] = parent; |
| } else { |
| element = ParameterElementImpl( |
| name: name, |
| nameOffset: nameOffset, |
| parameterKind: node.kind, |
| ); |
| _linker.elementNodes[element] = node; |
| } |
| element.isExplicitlyCovariant = node.covariantKeyword != null; |
| element.isFinal = node.isFinal; |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| |
| node.declaredElement = element; |
| _linker.elementNodes[element] = node; |
| var refName = node.isNamed ? name : null; |
| _enclosingContext.addParameter(refName, element); |
| |
| var fakeReference = Reference.root(); |
| var holder = _EnclosingContext(fakeReference, element); |
| _withEnclosing(holder, () { |
| var formalParameters = node.parameters; |
| formalParameters.accept(this); |
| element.parameters = holder.parameters; |
| |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| element.typeParameters = holder.typeParameters; |
| } |
| }); |
| |
| _buildType(node.returnType); |
| } |
| |
| @override |
| void visitGenericFunctionType(covariant GenericFunctionTypeImpl node) { |
| var element = GenericFunctionTypeElementImpl.forOffset(node.offset); |
| _unitElement.encloseElement(element); |
| |
| node.declaredElement = element; |
| _linker.elementNodes[element] = node; |
| |
| var fakeReference = Reference.root(); |
| var holder = _EnclosingContext(fakeReference, element); |
| _withEnclosing(holder, () { |
| var formalParameters = node.parameters; |
| formalParameters.accept(this); |
| element.parameters = holder.parameters; |
| |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| element.typeParameters = holder.typeParameters; |
| } |
| }); |
| |
| _buildType(node.returnType); |
| } |
| |
| @override |
| void visitGenericTypeAlias(covariant GenericTypeAliasImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var element = TypeAliasElementImpl(name, nameToken.offset); |
| element.isAugmentation = node.augmentKeyword != null; |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| _setDocumentation(element, node); |
| |
| node.declaredElement = element; |
| _linker.elementNodes[element] = node; |
| |
| var reference = _enclosingContext.addTypeAlias(name, element); |
| if (!element.isAugmentation) { |
| _libraryBuilder.declare(name, reference); |
| } |
| |
| var holder = _EnclosingContext(reference, element); |
| _withEnclosing(holder, () { |
| node.typeParameters?.accept(this); |
| }); |
| element.typeParameters = holder.typeParameters; |
| |
| var typeNode = node.type; |
| typeNode.accept(this); |
| |
| if (typeNode is GenericFunctionTypeImpl) { |
| element.aliasedElement = |
| typeNode.declaredElement as GenericFunctionTypeElementImpl; |
| } |
| |
| _libraryBuilder.updateAugmentationTarget(name, element); |
| } |
| |
| @override |
| void visitImplementsClause(ImplementsClause node) { |
| node.interfaces.accept(this); |
| } |
| |
| @override |
| void visitImportDirective(covariant ImportDirectiveImpl node) { |
| var index = _importDirectiveIndex++; |
| var importElement = _container.libraryImports[index]; |
| importElement.metadata = _buildAnnotations(node.metadata); |
| node.element = importElement; |
| } |
| |
| @override |
| void visitLibraryAugmentationDirective(LibraryAugmentationDirective node) { |
| _container.metadata = _buildAnnotations(node.metadata); |
| } |
| |
| @override |
| void visitLibraryDirective(covariant LibraryDirectiveImpl node) { |
| if (_isFirstLibraryDirective) { |
| _isFirstLibraryDirective = false; |
| node.element = _container; |
| _container.documentationComment = getCommentNodeRawText( |
| node.documentationComment, |
| ); |
| _container.metadata = _buildAnnotations(node.metadata); |
| } |
| } |
| |
| @override |
| void visitMethodDeclaration(covariant MethodDeclarationImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| var nameOffset = nameToken.offset; |
| |
| Reference reference; |
| ExecutableElementImpl executableElement; |
| if (node.isGetter) { |
| var element = PropertyAccessorElementImpl(name, nameOffset); |
| element.isAbstract = node.isAbstract; |
| element.isAugmentation = node.augmentKeyword != null; |
| element.isGetter = true; |
| element.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') { |
| element.isAbstract = false; |
| } |
| |
| reference = _enclosingContext.addGetter(name, element); |
| executableElement = element; |
| |
| _buildSyntheticVariable(name: name, accessorElement: element); |
| } else if (node.isSetter) { |
| var element = PropertyAccessorElementImpl(name, nameOffset); |
| element.isAbstract = node.isAbstract; |
| element.isAugmentation = node.augmentKeyword != null; |
| element.isSetter = true; |
| element.isStatic = node.isStatic; |
| |
| reference = _enclosingContext.addSetter(name, element); |
| executableElement = element; |
| |
| _buildSyntheticVariable(name: name, accessorElement: element); |
| } else { |
| if (name == '-') { |
| var parameters = node.parameters; |
| if (parameters != null && parameters.parameters.isEmpty) { |
| name = 'unary-'; |
| } |
| } |
| |
| var element = MethodElementImpl(name, nameOffset); |
| element.isAbstract = node.isAbstract; |
| element.isAugmentation = node.augmentKeyword != null; |
| element.isStatic = node.isStatic; |
| |
| reference = _enclosingContext.addMethod(name, element); |
| executableElement = element; |
| } |
| executableElement.hasImplicitReturnType = node.returnType == null; |
| executableElement.invokesSuperSelf = node.invokesSuperSelf; |
| executableElement.isAsynchronous = node.body.isAsynchronous; |
| executableElement.isExternal = |
| node.externalKeyword != null || node.body is NativeFunctionBody; |
| executableElement.isGenerator = node.body.isGenerator; |
| executableElement.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(executableElement, node); |
| _setDocumentation(executableElement, node); |
| |
| node.declaredElement = executableElement; |
| _linker.elementNodes[executableElement] = node; |
| |
| _buildExecutableElementChildren( |
| reference: reference, |
| element: executableElement, |
| formalParameters: node.parameters, |
| typeParameters: node.typeParameters, |
| ); |
| |
| _buildType(node.returnType); |
| } |
| |
| @override |
| void visitMixinDeclaration(covariant MixinDeclarationImpl node) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| |
| var element = MixinElementImpl(name, nameToken.offset); |
| element.isAugmentation = node.augmentKeyword != null; |
| element.isBase = node.baseKeyword != null; |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| _setDocumentation(element, node); |
| |
| node.declaredElement = element; |
| _linker.elementNodes[element] = node; |
| |
| var reference = _enclosingContext.addMixin(name, element); |
| if (!element.isAugmentation) { |
| _libraryBuilder.declare(name, reference); |
| } |
| |
| var holder = _EnclosingContext(reference, element); |
| _withEnclosing(holder, () { |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| element.typeParameters = holder.typeParameters; |
| } |
| }); |
| |
| node.onClause?.accept(this); |
| node.implementsClause?.accept(this); |
| _buildMixin(node); |
| |
| _libraryBuilder.updateAugmentationTarget(name, element); |
| |
| if (element.augmentationTarget != null) { |
| switch (_libraryBuilder.getAugmentedBuilder(name)) { |
| case AugmentedMixinDeclarationBuilder builder: |
| builder.augment(element); |
| } |
| } else { |
| _libraryBuilder.putAugmentedBuilder( |
| name, |
| AugmentedMixinDeclarationBuilder( |
| declaration: element, |
| ), |
| ); |
| } |
| } |
| |
| @override |
| void visitMixinOnClause(MixinOnClause node) { |
| node.superclassConstraints.accept(this); |
| } |
| |
| @override |
| void visitNamedType(NamedType node) { |
| node.typeArguments?.accept(this); |
| } |
| |
| @override |
| void visitPartDirective(PartDirective node) { |
| var libraryElement = _container; |
| if (libraryElement is LibraryElementImpl) { |
| var index = _partDirectiveIndex++; |
| var partElement = libraryElement.parts[index]; |
| partElement.metadata = _buildAnnotations(node.metadata); |
| } |
| } |
| |
| @override |
| void visitPartOfDirective(PartOfDirective node) { |
| var libraryElement = _container; |
| if (libraryElement is LibraryElementImpl) { |
| 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 name = nameToken?.lexeme ?? ''; |
| var nameOffset = nameToken?.offset ?? -1; |
| |
| ParameterElementImpl element; |
| var parent = node.parent; |
| if (parent is DefaultFormalParameterImpl && |
| _enclosingContext.hasDefaultFormalParameters) { |
| element = DefaultParameterElementImpl( |
| name: name, |
| nameOffset: nameOffset, |
| parameterKind: node.kind, |
| )..constantInitializer = parent.defaultValue; |
| _linker.elementNodes[element] = parent; |
| var refName = node.isNamed ? name : null; |
| _enclosingContext.addParameter(refName, element); |
| } else { |
| element = ParameterElementImpl( |
| name: name, |
| nameOffset: nameOffset, |
| parameterKind: node.kind, |
| ); |
| _linker.elementNodes[element] = node; |
| _enclosingContext.addParameter(null, element); |
| } |
| |
| element.hasImplicitType = node.type == null; |
| element.isExplicitlyCovariant = node.covariantKeyword != null; |
| element.isFinal = node.isFinal; |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| |
| node.declaredElement = element; |
| |
| _buildType(node.type); |
| } |
| |
| @override |
| void visitSuperFormalParameter( |
| covariant SuperFormalParameterImpl node, |
| ) { |
| var nameToken = node.name; |
| var name = nameToken.lexeme; |
| var nameOffset = nameToken.offset; |
| |
| SuperFormalParameterElementImpl element; |
| var parent = node.parent; |
| if (parent is DefaultFormalParameterImpl) { |
| element = DefaultSuperFormalParameterElementImpl( |
| name: name, |
| nameOffset: nameOffset, |
| parameterKind: node.kind, |
| )..constantInitializer = parent.defaultValue; |
| _linker.elementNodes[element] = parent; |
| var refName = node.isNamed ? name : null; |
| _enclosingContext.addParameter(refName, element); |
| } else { |
| element = SuperFormalParameterElementImpl( |
| name: name, |
| nameOffset: nameOffset, |
| parameterKind: node.kind, |
| ); |
| _linker.elementNodes[element] = node; |
| _enclosingContext.addParameter(null, element); |
| } |
| element.hasImplicitType = node.type == null && node.parameters == null; |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| |
| node.declaredElement = element; |
| |
| // TODO(scheglov): check that we don't set reference for parameters |
| var fakeReference = Reference.root(); |
| var holder = _EnclosingContext(fakeReference, element); |
| _withEnclosing(holder, () { |
| var formalParameters = node.parameters; |
| if (formalParameters != null) { |
| formalParameters.accept(this); |
| element.parameters = holder.parameters; |
| } |
| |
| var typeParameters = node.typeParameters; |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| element.typeParameters = holder.typeParameters; |
| } |
| }); |
| |
| _buildType(node.type); |
| } |
| |
| @override |
| void visitTopLevelVariableDeclaration( |
| covariant TopLevelVariableDeclarationImpl node, |
| ) { |
| var enclosingRef = _enclosingContext.reference; |
| |
| 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 element; |
| if (node.variables.isConst) { |
| element = ConstTopLevelVariableElementImpl(name, nameOffset) |
| ..constantInitializer = variable.initializer; |
| } else { |
| element = TopLevelVariableElementImpl(name, nameOffset); |
| } |
| |
| element.hasInitializer = variable.initializer != null; |
| element.isAugmentation = node.augmentKeyword != null; |
| element.isConst = node.variables.isConst; |
| element.isExternal = node.externalKeyword != null; |
| element.isFinal = node.variables.isFinal; |
| element.isLate = node.variables.isLate; |
| element.metadata = metadata; |
| _setCodeRange(element, variable); |
| _setDocumentation(element, node); |
| |
| if (node.variables.type == null) { |
| element.hasImplicitType = true; |
| } |
| |
| { |
| var ref = enclosingRef.getChild('@getter').addChild(name); |
| var getter = element.createImplicitGetter(ref); |
| _enclosingContext.addPropertyAccessorSynthetic(getter); |
| _libraryBuilder.declare(name, ref); |
| } |
| |
| if (element.hasSetter) { |
| var ref = enclosingRef.getChild('@setter').addChild(name); |
| var setter = element.createImplicitSetter(ref); |
| _enclosingContext.addPropertyAccessorSynthetic(setter); |
| _libraryBuilder.declare('$name=', ref); |
| } |
| |
| _linker.elementNodes[element] = variable; |
| _enclosingContext.addTopLevelVariable(name, element); |
| variable.declaredElement = element; |
| |
| _libraryBuilder.topVariables.addVariable(element); |
| } |
| |
| _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 element = TypeParameterElementImpl(name, nameToken.offset); |
| element.metadata = _buildAnnotations(node.metadata); |
| _setCodeRange(element, node); |
| |
| node.declaredElement = element; |
| _linker.elementNodes[element] = node; |
| _enclosingContext.addTypeParameter(name, element); |
| |
| _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 _buildClass(ClassDeclaration node) { |
| var element = node.declaredElement as ClassElementImpl; |
| // TODO(scheglov): don't create a duplicate |
| var holder = _EnclosingContext(element.reference!, element, |
| constFieldsForFinalInstance: true); |
| _withEnclosing(holder, () { |
| _visitPropertyFirst<FieldDeclaration>(node.members); |
| }); |
| |
| element.accessors = holder.propertyAccessors; |
| element.constructors = holder.constructors; |
| element.fields = holder.fields; |
| element.methods = holder.methods; |
| } |
| |
| void _buildExecutableElementChildren({ |
| required Reference reference, |
| required ExecutableElementImpl element, |
| FormalParameterList? formalParameters, |
| TypeParameterList? typeParameters, |
| }) { |
| var holder = _EnclosingContext( |
| reference, |
| element, |
| hasDefaultFormalParameters: true, |
| ); |
| _withEnclosing(holder, () { |
| if (formalParameters != null) { |
| formalParameters.accept(this); |
| element.parameters = holder.parameters; |
| } |
| if (typeParameters != null) { |
| typeParameters.accept(this); |
| element.typeParameters = holder.typeParameters; |
| } |
| }); |
| } |
| |
| void _buildMixin(MixinDeclaration node) { |
| var element = node.declaredElement as MixinElementImpl; |
| // TODO(scheglov): don't create a duplicate |
| var holder = _EnclosingContext(element.reference!, element); |
| _withEnclosing(holder, () { |
| _visitPropertyFirst<FieldDeclaration>(node.members); |
| }); |
| |
| element.accessors = holder.propertyAccessors; |
| element.fields = holder.fields; |
| element.methods = holder.methods; |
| } |
| |
| void _buildSyntheticVariable({ |
| required String name, |
| required PropertyAccessorElementImpl accessorElement, |
| }) { |
| if (accessorElement.isAugmentation) { |
| return; |
| } |
| |
| var enclosingRef = _enclosingContext.reference; |
| var enclosingElement = _enclosingContext.element; |
| |
| bool canUseExisting(PropertyInducingElement property) { |
| return property.isSynthetic || |
| accessorElement.isSetter && property.setter == null; |
| } |
| |
| PropertyInducingElementImpl property; |
| if (enclosingElement is CompilationUnitElement) { |
| var reference = enclosingRef.getChild('@variable').getChild(name); |
| var existing = reference.element; |
| if (existing is TopLevelVariableElementImpl && canUseExisting(existing)) { |
| property = existing; |
| } else { |
| var variable = property = TopLevelVariableElementImpl(name, -1) |
| ..isSynthetic = true; |
| _enclosingContext.addTopLevelVariableSynthetic(reference, variable); |
| } |
| } else { |
| var reference = enclosingRef.getChild('@field').getChild(name); |
| var existing = reference.element; |
| if (existing is FieldElementImpl && canUseExisting(existing)) { |
| property = existing; |
| } else { |
| var field = property = FieldElementImpl(name, -1) |
| ..isStatic = accessorElement.isStatic |
| ..isSynthetic = true; |
| _enclosingContext.addFieldSynthetic(reference, field); |
| } |
| } |
| |
| accessorElement.variable2 = property; |
| if (accessorElement.isGetter) { |
| property.getter = accessorElement; |
| } else { |
| property.setter = accessorElement; |
| } |
| } |
| |
| // TODO(scheglov): Maybe inline? |
| void _buildType(TypeAnnotation? node) { |
| node?.accept(this); |
| } |
| |
| void _builtRepresentationDeclaration({ |
| required ExtensionTypeElementImpl extensionElement, |
| required ExtensionTypeDeclarationImpl extensionNode, |
| required RepresentationDeclarationImpl representation, |
| }) { |
| if (extensionElement.augmentationTarget != null) { |
| return; |
| } |
| |
| var fieldNameToken = representation.fieldName; |
| var fieldName = fieldNameToken.lexeme.ifNotEmptyOrElse('<empty>'); |
| |
| var fieldElement = FieldElementImpl( |
| fieldName, |
| fieldNameToken.offset, |
| ); |
| fieldElement.isFinal = true; |
| fieldElement.metadata = _buildAnnotations(representation.fieldMetadata); |
| |
| var fieldBeginToken = |
| representation.fieldMetadata.beginToken ?? representation.fieldType; |
| var fieldCodeRangeOffset = fieldBeginToken.offset; |
| var fieldCodeRangeLength = fieldNameToken.end - fieldCodeRangeOffset; |
| fieldElement.setCodeRange(fieldCodeRangeOffset, fieldCodeRangeLength); |
| |
| representation.fieldElement = fieldElement; |
| _linker.elementNodes[fieldElement] = representation; |
| _enclosingContext.addNonSyntheticField(fieldElement); |
| |
| var formalParameterElement = FieldFormalParameterElementImpl( |
| name: fieldName, |
| nameOffset: fieldNameToken.offset, |
| parameterKind: ParameterKind.REQUIRED, |
| ) |
| ..field = fieldElement |
| ..hasImplicitType = true; |
| formalParameterElement.setCodeRange( |
| fieldCodeRangeOffset, |
| fieldCodeRangeLength, |
| ); |
| |
| extensionElement.augmented.representation = fieldElement; |
| |
| { |
| 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 constructorElement = ConstructorElementImpl(name, nameOffset) |
| ..isAugmentation = extensionNode.augmentKeyword != null |
| ..isConst = extensionNode.constKeyword != null |
| ..nameEnd = nameEnd |
| ..parameters = [formalParameterElement] |
| ..periodOffset = periodOffset; |
| _setCodeRange(constructorElement, representation); |
| |
| representation.constructorElement = constructorElement; |
| _linker.elementNodes[constructorElement] = representation; |
| _enclosingContext.addConstructor(constructorElement); |
| |
| extensionElement.augmented.primaryConstructor = constructorElement; |
| } |
| |
| representation.fieldType.accept(this); |
| } |
| |
| void _resolveConstructorFieldFormals(InterfaceElementImpl element) { |
| for (var constructor in element.constructors) { |
| for (var parameter in constructor.parameters) { |
| if (parameter is FieldFormalParameterElementImpl) { |
| parameter.field = element.getField(parameter.name); |
| } |
| } |
| } |
| } |
| |
| 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 Reference reference; |
| final ElementImpl element; |
| 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<FunctionElementImpl> _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( |
| this.reference, |
| this.element, { |
| 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(); |
| } |
| |
| List<FunctionElementImpl> get functions { |
| return _functions.toFixedList(); |
| } |
| |
| bool get isDartCoreEnum { |
| final element = this.element; |
| return element is ClassElementImpl && element.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, FunctionElementImpl 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(FieldElementImpl element) { |
| var name = element.name; |
| 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 = reference.getChild('@getter').addChild(name); |
| var getter = element.createImplicitGetter(getterRef); |
| _propertyAccessors.add(getter); |
| } |
| |
| if (element.hasSetter) { |
| var setterRef = reference.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 ? '@variableAugmentation' : '@variable'; |
| 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 element) { |
| _typeParameters.add(element); |
| this.element.encloseElement(element); |
| } |
| |
| Reference _addReference( |
| String containerName, |
| String name, |
| ElementImpl element, |
| ) { |
| var containerRef = this.reference.getChild(containerName); |
| var reference = containerRef.addChild(name); |
| _bindReference(reference, element); |
| return reference; |
| } |
| |
| void _bindReference(Reference reference, ElementImpl element) { |
| reference.element = element; |
| element.reference = reference; |
| this.element.encloseElement(element); |
| } |
| } |