| // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'package:_fe_analyzer_shared/src/macros/executor/introspection_impls.dart' |
| as macro; |
| import 'package:_fe_analyzer_shared/src/macros/executor/remote_instance.dart' |
| as macro; |
| import 'package:analyzer/dart/ast/ast.dart' as ast; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/dart/element/nullability_suffix.dart'; |
| import 'package:analyzer/dart/element/type.dart'; |
| |
| class ClassDeclarationImpl extends macro.ClassDeclarationImpl { |
| late final ClassElement element; |
| |
| ClassDeclarationImpl._({ |
| required int id, |
| required macro.IdentifierImpl identifier, |
| required List<macro.TypeParameterDeclarationImpl> typeParameters, |
| required List<macro.TypeAnnotationImpl> interfaces, |
| required bool isAbstract, |
| required bool isExternal, |
| required List<macro.TypeAnnotationImpl> mixins, |
| required macro.TypeAnnotationImpl? superclass, |
| }) : super( |
| id: id, |
| identifier: identifier, |
| typeParameters: typeParameters, |
| interfaces: interfaces, |
| isAbstract: isAbstract, |
| isExternal: isExternal, |
| mixins: mixins, |
| superclass: superclass, |
| ); |
| } |
| |
| class DeclarationBuilder { |
| final DeclarationBuilderFromNode fromNode = DeclarationBuilderFromNode(); |
| |
| final DeclarationBuilderFromElement fromElement = |
| DeclarationBuilderFromElement(); |
| |
| /// Associate declarations that were previously created for nodes with the |
| /// corresponding elements. So, we can access them uniformly via interfaces, |
| /// mixins, etc. |
| void transferToElements() { |
| for (final entry in fromNode._identifierMap.entries) { |
| final element = entry.key.staticElement; |
| if (element != null) { |
| final declaration = entry.value; |
| declaration.element = element; |
| fromElement._identifierMap[element] = declaration; |
| } |
| } |
| |
| for (final entry in fromNode._classMap.entries) { |
| final element = entry.key.declaredElement as ClassElement; |
| final declaration = entry.value; |
| declaration.element = element; |
| fromElement._classMap[element] = declaration; |
| } |
| } |
| } |
| |
| class DeclarationBuilderFromElement { |
| final Map<Element, IdentifierImpl> _identifierMap = Map.identity(); |
| |
| final Map<ClassElement, ClassDeclarationImpl> _classMap = Map.identity(); |
| |
| final Map<FieldElement, FieldDeclarationImpl> _fieldMap = Map.identity(); |
| |
| final Map<TypeParameterElement, macro.TypeParameterDeclarationImpl> |
| _typeParameterMap = Map.identity(); |
| |
| macro.ClassDeclarationImpl classElement(ClassElement element) { |
| return _classMap[element] ??= _classElement(element); |
| } |
| |
| macro.FieldDeclarationImpl fieldElement(FieldElement element) { |
| return _fieldMap[element] ??= _fieldElement(element); |
| } |
| |
| macro.IdentifierImpl identifier(Element element) { |
| return _identifierMap[element] ??= IdentifierImpl( |
| id: macro.RemoteInstance.uniqueId, |
| name: element.name!, |
| )..element = element; |
| } |
| |
| macro.TypeParameterDeclarationImpl typeParameter( |
| TypeParameterElement element, |
| ) { |
| return _typeParameterMap[element] ??= _typeParameter(element); |
| } |
| |
| ClassDeclarationImpl _classElement(ClassElement element) { |
| assert(!_classMap.containsKey(element)); |
| return ClassDeclarationImpl._( |
| id: macro.RemoteInstance.uniqueId, |
| identifier: identifier(element), |
| typeParameters: element.typeParameters.map(_typeParameter).toList(), |
| interfaces: element.interfaces.map(_dartType).toList(), |
| isAbstract: element.isAbstract, |
| isExternal: false, |
| mixins: element.mixins.map(_dartType).toList(), |
| superclass: element.supertype.mapOrNull(_dartType), |
| )..element = element; |
| } |
| |
| macro.TypeAnnotationImpl _dartType(DartType type) { |
| if (type is InterfaceType) { |
| return macro.NamedTypeAnnotationImpl( |
| id: macro.RemoteInstance.uniqueId, |
| isNullable: type.nullabilitySuffix == NullabilitySuffix.question, |
| identifier: identifier(type.element), |
| typeArguments: type.typeArguments.map(_dartType).toList(), |
| ); |
| } else if (type is TypeParameterType) { |
| return macro.NamedTypeAnnotationImpl( |
| id: macro.RemoteInstance.uniqueId, |
| isNullable: type.nullabilitySuffix == NullabilitySuffix.question, |
| identifier: identifier(type.element), |
| typeArguments: const [], |
| ); |
| } else { |
| // TODO(scheglov) other types |
| throw UnimplementedError('(${type.runtimeType}) $type'); |
| } |
| } |
| |
| FieldDeclarationImpl _fieldElement(FieldElement element) { |
| assert(!_fieldMap.containsKey(element)); |
| final enclosingClass = element.enclosingElement as ClassElement; |
| return FieldDeclarationImpl( |
| id: macro.RemoteInstance.uniqueId, |
| identifier: identifier(element), |
| isExternal: element.isExternal, |
| isFinal: element.isFinal, |
| isLate: element.isLate, |
| type: _dartType(element.type), |
| definingClass: identifier(enclosingClass), |
| isStatic: element.isStatic, |
| ); |
| } |
| |
| macro.TypeParameterDeclarationImpl _typeParameter( |
| TypeParameterElement element, |
| ) { |
| return macro.TypeParameterDeclarationImpl( |
| id: macro.RemoteInstance.uniqueId, |
| identifier: identifier(element), |
| bound: element.bound.mapOrNull(_dartType), |
| ); |
| } |
| } |
| |
| class DeclarationBuilderFromNode { |
| final Map<ast.SimpleIdentifier, IdentifierImpl> _identifierMap = |
| Map.identity(); |
| |
| final Map<ast.ClassDeclaration, ClassDeclarationImpl> _classMap = |
| Map.identity(); |
| |
| macro.ClassDeclarationImpl classDeclaration( |
| ast.ClassDeclaration node, |
| ) { |
| return _classMap[node] ??= _classDeclaration(node); |
| } |
| |
| ClassDeclarationImpl _classDeclaration( |
| ast.ClassDeclaration node, |
| ) { |
| assert(!_classMap.containsKey(node)); |
| return ClassDeclarationImpl._( |
| id: macro.RemoteInstance.uniqueId, |
| identifier: _identifier(node.name), |
| typeParameters: _typeParameters(node.typeParameters), |
| interfaces: _typeAnnotations(node.implementsClause?.interfaces), |
| isAbstract: node.abstractKeyword != null, |
| isExternal: false, |
| mixins: _typeAnnotations(node.withClause?.mixinTypes), |
| superclass: node.extendsClause?.superclass.mapOrNull( |
| _typeAnnotation, |
| ), |
| ); |
| } |
| |
| macro.FunctionTypeParameterImpl _formalParameter( |
| ast.FormalParameter node, |
| ) { |
| if (node is ast.DefaultFormalParameter) { |
| node = node.parameter; |
| } |
| |
| final macro.TypeAnnotationImpl typeAnnotation; |
| if (node is ast.SimpleFormalParameter) { |
| typeAnnotation = _typeAnnotation(node.type); |
| } else { |
| throw UnimplementedError('(${node.runtimeType}) $node'); |
| } |
| |
| return macro.FunctionTypeParameterImpl( |
| id: macro.RemoteInstance.uniqueId, |
| isNamed: node.isNamed, |
| isRequired: node.isRequired, |
| name: node.identifier?.name, |
| type: typeAnnotation, |
| ); |
| } |
| |
| macro.IdentifierImpl _identifier(ast.Identifier node) { |
| final ast.SimpleIdentifier simpleIdentifier; |
| if (node is ast.SimpleIdentifier) { |
| simpleIdentifier = node; |
| } else { |
| simpleIdentifier = (node as ast.PrefixedIdentifier).identifier; |
| } |
| return _identifierMap[simpleIdentifier] ??= IdentifierImpl( |
| id: macro.RemoteInstance.uniqueId, |
| name: simpleIdentifier.name, |
| ); |
| } |
| |
| macro.TypeAnnotationImpl _typeAnnotation(ast.TypeAnnotation? node) { |
| if (node == null) { |
| return macro.OmittedTypeAnnotationImpl( |
| id: macro.RemoteInstance.uniqueId, |
| ); |
| } else if (node is ast.GenericFunctionType) { |
| return macro.FunctionTypeAnnotationImpl( |
| id: macro.RemoteInstance.uniqueId, |
| isNullable: node.question != null, |
| namedParameters: node.parameters.parameters |
| .where((e) => e.isNamed) |
| .map(_formalParameter) |
| .toList(), |
| positionalParameters: node.parameters.parameters |
| .where((e) => e.isPositional) |
| .map(_formalParameter) |
| .toList(), |
| returnType: _typeAnnotation(node.returnType), |
| typeParameters: _typeParameters(node.typeParameters), |
| ); |
| } else if (node is ast.NamedType) { |
| return macro.NamedTypeAnnotationImpl( |
| id: macro.RemoteInstance.uniqueId, |
| identifier: _identifier(node.name), |
| isNullable: node.question != null, |
| typeArguments: _typeAnnotations(node.typeArguments?.arguments), |
| ); |
| } else { |
| throw UnimplementedError('(${node.runtimeType}) $node'); |
| } |
| } |
| |
| List<macro.TypeAnnotationImpl> _typeAnnotations( |
| List<ast.TypeAnnotation>? elements, |
| ) { |
| if (elements != null) { |
| return elements.map(_typeAnnotation).toList(); |
| } else { |
| return const []; |
| } |
| } |
| |
| macro.TypeParameterDeclarationImpl _typeParameter( |
| ast.TypeParameter node, |
| ) { |
| return macro.TypeParameterDeclarationImpl( |
| id: macro.RemoteInstance.uniqueId, |
| identifier: _identifier(node.name), |
| bound: node.bound?.mapOrNull(_typeAnnotation), |
| ); |
| } |
| |
| List<macro.TypeParameterDeclarationImpl> _typeParameters( |
| ast.TypeParameterList? typeParameterList, |
| ) { |
| if (typeParameterList != null) { |
| return typeParameterList.typeParameters.map(_typeParameter).toList(); |
| } else { |
| return const []; |
| } |
| } |
| } |
| |
| class FieldDeclarationImpl extends macro.FieldDeclarationImpl { |
| FieldDeclarationImpl({ |
| required int id, |
| required macro.IdentifierImpl identifier, |
| required bool isExternal, |
| required bool isFinal, |
| required bool isLate, |
| required macro.TypeAnnotationImpl type, |
| required macro.IdentifierImpl definingClass, |
| required bool isStatic, |
| }) : super( |
| id: id, |
| identifier: identifier, |
| isExternal: isExternal, |
| isFinal: isFinal, |
| isLate: isLate, |
| type: type, |
| definingClass: definingClass, |
| isStatic: isStatic, |
| ); |
| } |
| |
| class IdentifierImpl extends macro.IdentifierImpl { |
| late final Element? element; |
| |
| IdentifierImpl({required int id, required String name}) |
| : super(id: id, name: name); |
| } |
| |
| extension<T> on T? { |
| R? mapOrNull<R>(R Function(T) mapper) { |
| final self = this; |
| return self != null ? mapper(self) : null; |
| } |
| } |