| // Copyright (c) 2019, 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/visitor.dart'; | |
| import 'package:analyzer/dart/element/element.dart'; | |
| import 'package:analyzer/dart/element/nullability_suffix.dart'; | |
| import 'package:analyzer/dart/element/scope.dart'; | |
| import 'package:analyzer/src/dart/ast/ast.dart'; | |
| import 'package:analyzer/src/dart/element/element.dart'; | |
| import 'package:analyzer/src/dart/element/type.dart'; | |
| import 'package:analyzer/src/dart/element/type_system.dart'; | |
| import 'package:analyzer/src/dart/resolver/scope_context.dart'; | |
| import 'package:analyzer/src/summary2/function_type_builder.dart'; | |
| import 'package:analyzer/src/summary2/link.dart'; | |
| import 'package:analyzer/src/summary2/named_type_builder.dart'; | |
| import 'package:analyzer/src/summary2/record_type_builder.dart'; | |
| import 'package:analyzer/src/summary2/types_builder.dart'; | |
| /// Recursive visitor of LinkedNodes that resolves explicit type annotations | |
| /// in outlines. This includes resolving element references in identifiers | |
| /// in type annotation, and setting LinkedNodeTypes for corresponding type | |
| /// annotation nodes. | |
| /// | |
| /// Declarations that have type annotations, e.g. return types of methods, get | |
| /// the corresponding type set (so, if there is an explicit type annotation, | |
| /// the type is set, otherwise we keep it empty, so we will attempt to infer | |
| /// it later). | |
| class ReferenceResolver extends ThrowingAstVisitor2<void> { | |
| /// The library fragment in which the AST nodes are being resolved. | |
| final LibraryFragmentImpl libraryFragment; | |
| final ScopeContext _scopeContext; | |
| final Linker linker; | |
| final TypeSystemImpl typeSystem; | |
| final NodesToBuildType nodesToBuildType; | |
| ReferenceResolver( | |
| this.linker, | |
| this.nodesToBuildType, | |
| this.typeSystem, | |
| Scope scope, { | |
| required this.libraryFragment, | |
| }) : _scopeContext = ScopeContext( | |
| libraryFragment: libraryFragment, | |
| nameScope: scope, | |
| ); | |
| Scope get nameScope => _scopeContext.nameScope; | |
| @override | |
| void visitAnnotation(covariant AnnotationImpl node) { | |
| // Annotations are resolved after types, by `MetadataResolver`. | |
| } | |
| @override | |
| void visitBlockClassBody(BlockClassBody node) { | |
| node.members.accept2(this); | |
| } | |
| @override | |
| void visitBlockEnumBody(BlockEnumBody node) { | |
| node.constants.accept2(this); | |
| node.members.accept2(this); | |
| } | |
| @override | |
| void visitBlockFunctionBody(BlockFunctionBody node) {} | |
| @override | |
| void visitClassDeclaration(covariant ClassDeclarationImpl node) { | |
| _scopeContext.visitClassDeclaration(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| @override | |
| void visitClassTypeAlias(covariant ClassTypeAliasImpl node) { | |
| _scopeContext.visitClassTypeAlias(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| @override | |
| void visitComment(Comment node) {} | |
| @override | |
| void visitCompilationUnit(CompilationUnit node) { | |
| node.declarations2.accept2(this); | |
| } | |
| @override | |
| void visitConstructorDeclaration(covariant ConstructorDeclarationImpl node) { | |
| _scopeContext.visitConstructorDeclaration( | |
| node, | |
| visitor: this, | |
| visitInitializers: (_) {}, | |
| visitFactoryRedirectionTarget: (_) {}, | |
| ); | |
| } | |
| @override | |
| void visitEmptyClassBody(EmptyClassBody node) {} | |
| @override | |
| void visitEmptyEnumBody(EmptyEnumBody node) {} | |
| @override | |
| void visitEmptyFunctionBody(EmptyFunctionBody node) {} | |
| @override | |
| void visitEnumConstantDeclaration(EnumConstantDeclaration node) {} | |
| @override | |
| void visitEnumDeclaration(covariant EnumDeclarationImpl node) { | |
| var fragment = node.declaredFragment!; | |
| _scopeContext.visitEnumDeclaration(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| for (var field in fragment.fields) { | |
| if (field.isEnumConstant || field.isOriginEnumValues) { | |
| var fieldNode = linker.getLinkingNode(field); | |
| fieldNode as VariableDeclarationImpl; | |
| fieldNode.initializerScope = node.bodyScope; | |
| } | |
| } | |
| } | |
| @override | |
| void visitExpressionFunctionBody(ExpressionFunctionBody node) {} | |
| @override | |
| void visitExtendsClause(ExtendsClause node) { | |
| node.superclass.accept2(this); | |
| } | |
| @override | |
| void visitExtensionDeclaration(covariant ExtensionDeclarationImpl node) { | |
| _scopeContext.visitExtensionDeclaration(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| @override | |
| void visitExtensionOnClause(ExtensionOnClause node) { | |
| node.extendedType.accept2(this); | |
| } | |
| @override | |
| void visitExtensionTypeDeclaration( | |
| covariant ExtensionTypeDeclarationImpl node, | |
| ) { | |
| _scopeContext.visitExtensionTypeDeclaration(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| @override | |
| void visitFieldDeclaration(covariant FieldDeclarationImpl node) { | |
| _scopeContext.visitFieldDeclaration(node, visitor: this); | |
| } | |
| @override | |
| void visitFieldFormalParameter(covariant FieldFormalParameterImpl node) { | |
| _visitFormalParameter(node); | |
| } | |
| @override | |
| void visitFormalParameterDefaultClause(FormalParameterDefaultClause node) {} | |
| @override | |
| void visitFormalParameterList(FormalParameterList node) { | |
| node.requiredPositionalFormalParameters.accept2(this); | |
| node.delimitedFormalParameters?.formalParameters.accept2(this); | |
| } | |
| @override | |
| void visitFunctionDeclaration(covariant FunctionDeclarationImpl node) { | |
| _scopeContext.visitFunctionDeclaration(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| @override | |
| void visitFunctionTypeAlias(covariant FunctionTypeAliasImpl node) { | |
| _scopeContext.visitFunctionTypeAlias(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| @override | |
| void visitGenericFunctionType(covariant GenericFunctionTypeImpl node) { | |
| _scopeContext.visitGenericFunctionType(node, visitor: this); | |
| var nullabilitySuffix = _getNullabilitySuffix(node.question != null); | |
| var builder = FunctionTypeBuilder.of(node, nullabilitySuffix); | |
| node.type = builder; | |
| nodesToBuildType.addDeclaration(node); | |
| nodesToBuildType.addTypeBuilder(builder); | |
| } | |
| @override | |
| void visitGenericTypeAlias(covariant GenericTypeAliasImpl node) { | |
| _scopeContext.visitGenericTypeAlias(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| @override | |
| void visitImplementsClause(ImplementsClause node) { | |
| node.interfaces.accept2(this); | |
| } | |
| @override | |
| void visitMethodDeclaration(covariant MethodDeclarationImpl node) { | |
| _scopeContext.visitMethodDeclaration(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| @override | |
| void visitMixinDeclaration(covariant MixinDeclarationImpl node) { | |
| _scopeContext.visitMixinDeclaration(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| @override | |
| void visitMixinOnClause(MixinOnClause node) { | |
| node.superclassConstraints.accept2(this); | |
| } | |
| @override | |
| void visitNamedType(covariant NamedTypeImpl node) { | |
| Element? element; | |
| var importPrefix = node.importPrefix; | |
| if (importPrefix != null) { | |
| var prefixToken = importPrefix.name; | |
| var prefixName = prefixToken.lexeme; | |
| var prefixElement = nameScope.lookup(prefixName).getter; | |
| importPrefix.element = prefixElement; | |
| if (prefixElement is PrefixElement) { | |
| var name = node.name.lexeme; | |
| element = prefixElement.scope.lookup(name).getter; | |
| } | |
| } else { | |
| var name = node.name.lexeme; | |
| if (name == 'void') { | |
| node.type = VoidTypeImpl.instance; | |
| return; | |
| } | |
| element = nameScope.lookup(name).getter; | |
| } | |
| node.element = element; | |
| node.typeArguments?.accept2(this); | |
| var nullabilitySuffix = _getNullabilitySuffix(node.question != null); | |
| if (element == null) { | |
| node.type = InvalidTypeImpl.instance; | |
| } else if (element is TypeParameterElementImpl) { | |
| node.type = _scopeContext.instantiateTypeParameter( | |
| element: element, | |
| nullability: nullabilitySuffix, | |
| ); | |
| } else { | |
| var builder = NamedTypeBuilder.of( | |
| linker: linker, | |
| typeSystem: typeSystem, | |
| node: node, | |
| element: element, | |
| nullabilitySuffix: nullabilitySuffix, | |
| ); | |
| node.type = builder; | |
| nodesToBuildType.addTypeBuilder(builder); | |
| } | |
| } | |
| @override | |
| void visitNameWithTypeParameters(NameWithTypeParameters node) { | |
| node.typeParameters?.accept2(this); | |
| } | |
| @override | |
| void visitNativeClause(NativeClause node) {} | |
| @override | |
| void visitNativeFunctionBody(NativeFunctionBody node) {} | |
| @override | |
| void visitPrimaryConstructorBody(covariant PrimaryConstructorBodyImpl node) { | |
| _scopeContext.visitPrimaryConstructorBody( | |
| node, | |
| visitor: this, | |
| visitInitializers: (_) {}, | |
| ); | |
| } | |
| @override | |
| void visitRecordTypeAnnotation(covariant RecordTypeAnnotationImpl node) { | |
| node.positionalFields.accept2(this); | |
| node.namedFields?.accept2(this); | |
| var builder = RecordTypeBuilder.of(typeSystem, node); | |
| node.type = builder; | |
| nodesToBuildType.addTypeBuilder(builder); | |
| } | |
| @override | |
| void visitRecordTypeAnnotationNamedField( | |
| RecordTypeAnnotationNamedField node, | |
| ) { | |
| node.type.accept2(this); | |
| } | |
| @override | |
| void visitRecordTypeAnnotationNamedFields( | |
| RecordTypeAnnotationNamedFields node, | |
| ) { | |
| node.fields.accept2(this); | |
| } | |
| @override | |
| void visitRecordTypeAnnotationPositionalField( | |
| RecordTypeAnnotationPositionalField node, | |
| ) { | |
| node.type.accept2(this); | |
| } | |
| @override | |
| void visitRegularFormalParameter(covariant RegularFormalParameterImpl node) { | |
| _visitFormalParameter(node); | |
| } | |
| @override | |
| void visitSuperFormalParameter(covariant SuperFormalParameterImpl node) { | |
| _visitFormalParameter(node); | |
| } | |
| @override | |
| void visitTopLevelGetterDeclaration( | |
| covariant TopLevelGetterDeclarationImpl node, | |
| ) { | |
| _scopeContext.visitTopLevelGetterDeclaration(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| @override | |
| void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | |
| node.visitChildren2(this); | |
| } | |
| @override | |
| void visitTypeArgumentList(TypeArgumentList node) { | |
| node.arguments.accept2(this); | |
| } | |
| @override | |
| void visitTypeParameter(covariant TypeParameterImpl node) { | |
| var bound = node.bound; | |
| if (bound != null) { | |
| bound.accept2(this); | |
| var fragment = node.declaredFragment!; | |
| if (fragment.previousFragment == null) { | |
| fragment.element.bound = bound.type; | |
| } | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| } | |
| @override | |
| void visitTypeParameterList(TypeParameterList node) { | |
| node.typeParameters.accept2(this); | |
| } | |
| @override | |
| void visitVariableDeclaration(covariant VariableDeclarationImpl node) { | |
| node.initializerScope = nameScope; | |
| } | |
| @override | |
| void visitVariableDeclarationList( | |
| covariant VariableDeclarationListImpl node, | |
| ) { | |
| _scopeContext.visitVariableDeclarationList(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| @override | |
| void visitWithClause(WithClause node) { | |
| node.mixinTypes.accept2(this); | |
| } | |
| NullabilitySuffix _getNullabilitySuffix(bool hasQuestion) { | |
| if (hasQuestion) { | |
| return NullabilitySuffix.question; | |
| } else { | |
| return NullabilitySuffix.none; | |
| } | |
| } | |
| void _visitFormalParameter(FormalParameterImpl node) { | |
| _scopeContext.visitFormalParameter(node, visitor: this); | |
| nodesToBuildType.addDeclaration(node); | |
| } | |
| } |