blob: 21707bc6b0e6f6032c9f9128e98f1f38516838d4 [file] [log] [blame]
// 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._classMap.entries) {
final element = entry.key.declaredElement as ClassElement;
final declaration = entry.value;
declaration.element = element;
fromElement._classMap[element] = declaration;
}
}
}
class DeclarationBuilderFromElement {
final Map<ClassElement, ClassDeclarationImpl> _classMap = Map.identity();
final Map<TypeParameterElement, macro.TypeParameterDeclarationImpl>
_typeParameterMap = Map.identity();
macro.ClassDeclarationImpl classElement(ClassElement element) {
return _classMap[element] ??= _classElement(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.name),
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.name),
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.name),
typeArguments: const [],
);
} else {
// TODO(scheglov) other types
throw UnimplementedError('(${type.runtimeType}) $type');
}
}
macro.IdentifierImpl _identifier(String name) {
return _IdentifierImpl(
id: macro.RemoteInstance.uniqueId,
name: name,
);
}
macro.TypeParameterDeclarationImpl _typeParameter(
TypeParameterElement element,
) {
return macro.TypeParameterDeclarationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: _identifier(element.name),
bound: element.bound.mapOrNull(_dartType),
);
}
}
class DeclarationBuilderFromNode {
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 String name;
if (node is ast.SimpleIdentifier) {
name = node.name;
} else {
name = (node as ast.PrefixedIdentifier).identifier.name;
}
return _IdentifierImpl(
id: macro.RemoteInstance.uniqueId,
name: 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 _IdentifierImpl extends macro.IdentifierImpl {
_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;
}
}