blob: 77b64aed342dd928bc8ccf28055c8325029e22b1 [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/api.dart' as macro;
import 'package:_fe_analyzer_shared/src/macros/executor.dart' as macro;
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/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/ast/ast.dart' as ast;
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/utilities/extensions/collection.dart';
import 'package:analyzer/src/utilities/extensions/element.dart';
import 'package:collection/collection.dart';
class ClassDeclarationImpl extends macro.ClassDeclarationImpl
implements HasElement {
@override
final ClassElementImpl element;
ClassDeclarationImpl._({
required super.id,
required super.identifier,
required super.library,
required super.metadata,
required super.typeParameters,
required super.interfaces,
required super.hasAbstract,
required super.hasBase,
required super.hasFinal,
required super.hasExternal,
required super.hasInterface,
required super.hasMixin,
required super.hasSealed,
required super.mixins,
required super.superclass,
required this.element,
});
}
class ConstructorDeclarationImpl extends macro.ConstructorDeclarationImpl
implements HasElement {
@override
final ConstructorElementImpl element;
ConstructorDeclarationImpl._({
required super.id,
required super.identifier,
required super.library,
required super.metadata,
required super.hasBody,
required super.hasExternal,
required super.namedParameters,
required super.positionalParameters,
required super.returnType,
required super.typeParameters,
required super.definingType,
required super.isFactory,
required this.element,
});
}
class DeclarationBuilder {
final ast.AstNode? Function(Element?) nodeOfElement;
final Map<Element, IdentifierImpl> _identifierMap = Map.identity();
late final DeclarationBuilderFromNode fromNode =
DeclarationBuilderFromNode(this);
late final DeclarationBuilderFromElement fromElement =
DeclarationBuilderFromElement(this);
DeclarationBuilder({
required this.nodeOfElement,
});
macro.Declaration buildDeclaration(ast.AstNode node) {
switch (node) {
case ast.ClassDeclarationImpl():
return fromNode.classDeclaration(node);
case ast.ConstructorDeclarationImpl():
return fromNode.constructorDeclaration(node);
case ast.ExtensionDeclarationImpl():
return fromNode.extensionDeclaration(node);
case ast.ExtensionTypeDeclarationImpl():
return fromNode.extensionTypeDeclaration(node);
case ast.FunctionDeclarationImpl():
return fromNode.functionDeclaration(node);
case ast.MethodDeclarationImpl():
return fromNode.methodDeclaration(node);
case ast.MixinDeclarationImpl():
return fromNode.mixinDeclaration(node);
case ast.VariableDeclaration():
return fromNode.variableDeclaration(node);
}
// TODO(scheglov): incomplete
throw UnimplementedError('${node.runtimeType}');
}
/// See [macro.DefinitionPhaseIntrospector.declarationOf].
macro.DeclarationImpl declarationOf(macro.Identifier identifier) {
if (identifier is! IdentifierImpl) {
throw ArgumentError('Not analyzer identifier.');
}
final element = identifier.element;
if (element == null) {
throw ArgumentError('Identifier without element.');
}
final node = nodeOfElement(element);
if (node != null) {
// TODO(scheglov): implement
throw UnimplementedError();
} else {
return fromElement.declarationOf(element);
}
}
macro.TypeAnnotation inferOmittedType(
macro.OmittedTypeAnnotation omittedType,
) {
final type = resolveType(omittedType.code);
return fromElement._dartType(type);
}
macro.ResolvedIdentifier resolveIdentifier(macro.Identifier identifier) {
if (identifier is _VoidIdentifierImpl) {
return macro.ResolvedIdentifier(
kind: macro.IdentifierKind.topLevelMember,
name: 'void',
uri: null,
staticScope: null,
);
}
identifier as IdentifierImpl;
final element = identifier.element;
switch (element) {
case DynamicElementImpl():
return macro.ResolvedIdentifier(
kind: macro.IdentifierKind.topLevelMember,
name: 'dynamic',
uri: Uri.parse('dart:core'),
staticScope: null,
);
case FieldElement():
if (element.isStatic) {
return macro.ResolvedIdentifier(
kind: macro.IdentifierKind.staticInstanceMember,
name: element.name,
uri: element.source!.uri,
staticScope: element.enclosingElement.name,
);
} else {
return macro.ResolvedIdentifier(
kind: macro.IdentifierKind.instanceMember,
name: element.name,
uri: null,
staticScope: null,
);
}
case FunctionElement():
return macro.ResolvedIdentifier(
kind: macro.IdentifierKind.topLevelMember,
name: element.name,
uri: element.source.uri,
staticScope: null,
);
case InterfaceElement():
return macro.ResolvedIdentifier(
kind: macro.IdentifierKind.topLevelMember,
name: element.name,
uri: element.source.uri,
staticScope: null,
);
case TypeParameterElement():
return macro.ResolvedIdentifier(
kind: macro.IdentifierKind.local,
name: element.name,
uri: null,
staticScope: null,
);
default:
// TODO(scheglov): other elements
throw UnimplementedError('${element.runtimeType}');
}
}
DartType resolveType(macro.TypeAnnotationCode typeCode) {
switch (typeCode) {
case macro.NullableTypeAnnotationCode():
final type = resolveType(typeCode.underlyingType);
type as TypeImpl;
return type.withNullability(NullabilitySuffix.question);
case macro.FunctionTypeAnnotationCode():
return _resolveTypeCodeFunction(typeCode);
case macro.NamedTypeAnnotationCode():
return _resolveTypeCodeNamed(typeCode);
case macro.OmittedTypeAnnotationCode():
return _resolveTypeCodeOmitted(typeCode);
case macro.RawTypeAnnotationCode():
// TODO(scheglov): implement
throw UnimplementedError('(${typeCode.runtimeType}) $typeCode');
case macro.RecordTypeAnnotationCode():
return _resolveTypeCodeRecord(typeCode);
}
}
/// See [macro.DeclarationPhaseIntrospector.typeDeclarationOf].
macro.TypeDeclarationImpl typeDeclarationOf(macro.Identifier identifier) {
if (identifier is! IdentifierImpl) {
throw ArgumentError('Not analyzer identifier.');
}
final element = identifier.element;
if (element == null) {
throw ArgumentError('Identifier without element.');
}
final node = nodeOfElement(element);
if (node != null) {
return fromNode.typeDeclarationOf(node);
} else {
return fromElement.typeDeclarationOf(element);
}
}
List<macro.MetadataAnnotationImpl> _buildMetadata(Element element) {
return element.withAugmentations
.expand((current) => current.metadata)
.map(_buildMetadataElement)
.whereNotNull()
.toList();
}
macro.MetadataAnnotationImpl? _buildMetadataElement(
ElementAnnotation annotation,
) {
annotation as ElementAnnotationImpl;
final node = annotation.annotationAst;
final importPrefixNames = annotation.library.libraryImports
.map((e) => e.prefix?.element.name)
.whereNotNull()
.toSet();
final identifiers = <ast.SimpleIdentifier>[];
switch (node.name) {
case ast.PrefixedIdentifier node:
identifiers.add(node.prefix);
identifiers.add(node.identifier);
case ast.SimpleIdentifier node:
identifiers.add(node);
default:
return null;
}
identifiers.addIfNotNull(node.constructorName);
var nextIndex = 0;
if (importPrefixNames.contains(identifiers.first.name)) {
nextIndex++;
}
final identifierName = identifiers[nextIndex++];
final constructorName = identifiers.elementAtOrNull(nextIndex);
final identifierMacro = IdentifierImplFromNode(
id: macro.RemoteInstance.uniqueId,
name: identifierName.name,
getElement: () => identifierName.staticElement,
);
final argumentList = node.arguments;
if (argumentList != null) {
final arguments = argumentList.arguments;
return macro.ConstructorMetadataAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
constructor: IdentifierImplFromNode(
id: macro.RemoteInstance.uniqueId,
name: constructorName?.name ?? '',
getElement: () => node.element,
),
type: identifierMacro,
positionalArguments: arguments
.whereNotType<ast.NamedExpression>()
.map((e) => _expressionCode(e))
.toList(),
namedArguments: arguments.whereType<ast.NamedExpression>().map((e) {
return MapEntry(
e.name.label.name,
_expressionCode(e.expression),
);
}).mapFromEntries,
);
} else {
return macro.IdentifierMetadataAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: identifierMacro,
);
}
}
FunctionTypeImpl _resolveTypeCodeFunction(
macro.FunctionTypeAnnotationCode typeCode,
) {
ParameterElementImpl buildFormalParameter(
macro.ParameterCode e,
ParameterKind Function(macro.ParameterCode) getKind,
) {
final element = ParameterElementImpl(
name: e.name,
nameOffset: -1,
parameterKind: getKind(e),
);
element.type = switch (e.type) {
final type? => resolveType(type),
_ => DynamicTypeImpl.instance,
};
return element;
}
return FunctionTypeImpl(
typeFormals: typeCode.typeParameters
.map((e) => TypeParameterElementImpl(e.name, -1))
.toList(),
parameters: [
...typeCode.positionalParameters.map((e) {
return buildFormalParameter(e, (e) {
return ParameterKind.REQUIRED;
});
}),
...typeCode.optionalPositionalParameters.map((e) {
return buildFormalParameter(e, (e) {
return ParameterKind.POSITIONAL;
});
}),
...typeCode.namedParameters.map((e) {
return buildFormalParameter(e, (e) {
return e.keywords.contains('required')
? ParameterKind.NAMED_REQUIRED
: ParameterKind.NAMED;
});
}),
],
returnType: switch (typeCode.returnType) {
final returnType? => resolveType(returnType),
_ => DynamicTypeImpl.instance,
},
nullabilitySuffix: NullabilitySuffix.none,
);
}
DartType _resolveTypeCodeNamed(macro.NamedTypeAnnotationCode typeCode) {
final identifier = typeCode.name as IdentifierImpl;
if (identifier is _VoidIdentifierImpl) {
return VoidTypeImpl.instance;
}
final element = identifier.element;
switch (element) {
case DynamicElementImpl():
return DynamicTypeImpl.instance;
case InterfaceElementImpl():
return element.instantiate(
typeArguments: typeCode.typeArguments.map(resolveType).toList(),
nullabilitySuffix: NullabilitySuffix.none,
);
case TypeParameterElementImpl():
return element.instantiate(
nullabilitySuffix: NullabilitySuffix.none,
);
default:
throw UnimplementedError('(${element.runtimeType}) $element');
}
}
DartType _resolveTypeCodeOmitted(macro.OmittedTypeAnnotationCode typeCode) {
final omittedType = typeCode.typeAnnotation;
switch (omittedType) {
case _OmittedTypeAnnotationDynamic():
return DynamicTypeImpl.instance;
case _OmittedTypeAnnotationMethodReturnType():
return omittedType.element.returnType;
case _OmittedTypeAnnotationVariable():
return omittedType.element.type;
default:
throw UnimplementedError('${omittedType.runtimeType}');
}
}
RecordTypeImpl _resolveTypeCodeRecord(
macro.RecordTypeAnnotationCode typeCode,
) {
return RecordTypeImpl(
positionalFields: typeCode.positionalFields.map((e) {
return RecordTypePositionalFieldImpl(
type: resolveType(e.type),
);
}).toList(),
namedFields: typeCode.namedFields.map((e) {
return RecordTypeNamedFieldImpl(
name: e.name!,
type: resolveType(e.type),
);
}).toList(),
nullabilitySuffix: NullabilitySuffix.none,
);
}
static macro.ExpressionCode _expressionCode(ast.Expression node) {
return macro.ExpressionCode.fromString('$node');
}
}
class DeclarationBuilderFromElement {
final DeclarationBuilder declarationBuilder;
final Map<Element, LibraryImpl> _libraryMap = Map.identity();
final Map<ClassElement, ClassDeclarationImpl> _classMap = Map.identity();
final Map<MixinElement, MixinDeclarationImpl> _mixinMap = Map.identity();
final Map<ConstructorElement, ConstructorDeclarationImpl> _constructorMap =
Map.identity();
final Map<FieldElement, FieldDeclarationImpl> _fieldMap = Map.identity();
final Map<ExecutableElement, MethodDeclarationImpl> _methodMap =
Map.identity();
final Map<TypeParameterElement, macro.TypeParameterDeclarationImpl>
_typeParameterMap = Map.identity();
DeclarationBuilderFromElement(this.declarationBuilder);
macro.ClassDeclarationImpl classElement(
ClassElementImpl element,
) {
return _classMap[element] ??= _classElement(element);
}
ConstructorDeclarationImpl constructorElement(
ConstructorElementImpl element,
) {
return _constructorMap[element] ??= _constructorElement(element);
}
/// See [macro.DefinitionPhaseIntrospector.declarationOf].
macro.DeclarationImpl declarationOf(Element element) {
switch (element) {
case FunctionElementImpl():
return functionElement(element);
default:
// TODO(scheglov): other elements
return typeDeclarationOf(element);
}
}
macro.FieldDeclarationImpl fieldElement(FieldElementImpl element) {
return _fieldMap[element] ??= _fieldElement(element);
}
FunctionDeclarationImpl functionElement(ExecutableElementImpl element) {
return FunctionDeclarationImpl._(
element: element,
id: macro.RemoteInstance.uniqueId,
identifier: identifier(element),
library: library(element),
metadata: _buildMetadata(element),
hasBody: !element.isAbstract,
hasExternal: element.isExternal,
isGetter: element is PropertyAccessorElementImpl && element.isGetter,
isOperator: element.isOperator,
isSetter: element is PropertyAccessorElementImpl && element.isSetter,
namedParameters: _namedFormalParameters(element.parameters),
positionalParameters: _positionalFormalParameters(element.parameters),
returnType: _dartType(element.returnType),
typeParameters: element.typeParameters.map(_typeParameter).toList(),
);
}
macro.IdentifierImpl identifier(Element element) {
final name = switch (element) {
PropertyAccessorElement(isSetter: true) => element.displayName,
_ => element.name!,
};
final map = declarationBuilder._identifierMap;
return map[element] ??= IdentifierImplFromElement(
id: macro.RemoteInstance.uniqueId,
name: name,
element: element,
);
}
macro.LibraryImpl library(Element element) {
var library = _libraryMap[element.library];
if (library == null) {
final version = element.library!.languageVersion.effective;
library = LibraryImplFromElement(
id: macro.RemoteInstance.uniqueId,
languageVersion:
macro.LanguageVersionImpl(version.major, version.minor),
metadata: _buildMetadata(element),
uri: element.library!.source.uri,
element: element);
_libraryMap[element.library!] = library;
}
return library;
}
MethodDeclarationImpl methodElement(ExecutableElementImpl element) {
return _methodMap[element] ??= _methodElement(element);
}
macro.MixinDeclarationImpl mixinElement(
MixinElementImpl element,
) {
return _mixinMap[element] ??= _mixinElement(element);
}
/// See [macro.DeclarationPhaseIntrospector.typeDeclarationOf].
macro.TypeDeclarationImpl typeDeclarationOf(Element element) {
switch (element) {
case ClassElementImpl():
return classElement(element);
case MixinElementImpl():
return mixinElement(element);
default:
// TODO(scheglov): other elements
throw ArgumentError('element: $element');
}
}
macro.TypeParameterDeclarationImpl typeParameter(
TypeParameterElement element,
) {
return _typeParameterMap[element] ??= _typeParameter(element);
}
List<macro.MetadataAnnotationImpl> _buildMetadata(Element element) {
return declarationBuilder._buildMetadata(element);
}
ClassDeclarationImpl _classElement(
ClassElementImpl element,
) {
return ClassDeclarationImpl._(
id: macro.RemoteInstance.uniqueId,
identifier: identifier(element),
library: library(element),
metadata: _buildMetadata(element),
typeParameters: element.typeParameters.map(_typeParameter).toList(),
interfaces: element.interfaces.map(_interfaceType).toList(),
hasAbstract: element.isAbstract,
hasBase: element.isBase,
hasExternal: false,
hasFinal: element.isFinal,
hasInterface: element.isInterface,
hasMixin: element.isMixinClass,
hasSealed: element.isSealed,
mixins: element.mixins.map(_interfaceType).toList(),
superclass: element.supertype.mapOrNull(_interfaceType),
element: element,
);
}
ConstructorDeclarationImpl _constructorElement(
ConstructorElementImpl element,
) {
final enclosing = element.enclosingInstanceElement;
return ConstructorDeclarationImpl._(
element: element,
id: macro.RemoteInstance.uniqueId,
identifier: identifier(element),
library: library(element),
metadata: _buildMetadata(element),
hasBody: !element.isAbstract,
hasExternal: element.isExternal,
isFactory: element.isFactory,
namedParameters: _namedFormalParameters(element.parameters),
positionalParameters: _positionalFormalParameters(element.parameters),
returnType: _dartType(element.returnType),
typeParameters: element.typeParameters.map(_typeParameter).toList(),
definingType: identifier(enclosing),
);
}
macro.TypeAnnotationImpl _dartType(DartType type) {
switch (type) {
case DynamicType():
return macro.NamedTypeAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
isNullable: false,
identifier: identifier(DynamicElementImpl.instance),
typeArguments: const [],
);
case InterfaceType():
return _interfaceType(type);
case TypeParameterType():
return macro.NamedTypeAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
isNullable: type.nullabilitySuffix == NullabilitySuffix.question,
identifier: identifier(type.element),
typeArguments: const [],
);
case VoidType():
return macro.NamedTypeAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: _VoidIdentifierImpl(),
isNullable: false,
typeArguments: const [],
);
default:
// TODO(scheglov): implement other types
throw UnimplementedError('(${type.runtimeType}) $type');
}
}
FieldDeclarationImpl _fieldElement(FieldElementImpl element) {
final enclosing = element.enclosingInstanceElement;
return FieldDeclarationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: identifier(element),
library: library(element),
metadata: _buildMetadata(element),
hasAbstract: element.isAbstract,
hasExternal: element.isExternal,
hasFinal: element.isFinal,
hasLate: element.isLate,
type: _dartType(element.type),
definingType: identifier(enclosing),
isStatic: element.isStatic,
element: element,
);
}
macro.ParameterDeclarationImpl _formalParameter(ParameterElement element) {
return macro.ParameterDeclarationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: identifier(element),
isNamed: element.isNamed,
isRequired: element.isRequired,
library: library(element),
metadata: _buildMetadata(element),
type: _dartType(element.type),
);
}
macro.NamedTypeAnnotationImpl _interfaceType(InterfaceType type) {
return macro.NamedTypeAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
isNullable: type.nullabilitySuffix == NullabilitySuffix.question,
identifier: identifier(type.element),
typeArguments: type.typeArguments.map(_dartType).toList(),
);
}
MethodDeclarationImpl _methodElement(ExecutableElementImpl element) {
final enclosing = element.enclosingInstanceElement;
return MethodDeclarationImpl._(
element: element,
id: macro.RemoteInstance.uniqueId,
identifier: identifier(element),
library: library(element),
metadata: _buildMetadata(element),
hasBody: !element.isAbstract,
hasExternal: element.isExternal,
isGetter: element is PropertyAccessorElementImpl && element.isGetter,
isOperator: element.isOperator,
isSetter: element is PropertyAccessorElementImpl && element.isSetter,
isStatic: element.isStatic,
namedParameters: _namedFormalParameters(element.parameters),
positionalParameters: _positionalFormalParameters(element.parameters),
returnType: _dartType(element.returnType),
typeParameters: element.typeParameters.map(_typeParameter).toList(),
definingType: identifier(enclosing),
);
}
MixinDeclarationImpl _mixinElement(
MixinElementImpl element,
) {
return MixinDeclarationImpl._(
id: macro.RemoteInstance.uniqueId,
identifier: identifier(element),
library: library(element),
metadata: _buildMetadata(element),
typeParameters: element.typeParameters.map(_typeParameter).toList(),
hasBase: element.isBase,
interfaces: element.interfaces.map(_interfaceType).toList(),
superclassConstraints:
element.superclassConstraints.map(_interfaceType).toList(),
element: element,
);
}
List<macro.ParameterDeclarationImpl> _namedFormalParameters(
List<ParameterElement> elements,
) {
return elements
.where((element) => element.isNamed)
.map(_formalParameter)
.toList();
}
List<macro.ParameterDeclarationImpl> _positionalFormalParameters(
List<ParameterElement> elements,
) {
return elements
.where((element) => element.isPositional)
.map(_formalParameter)
.toList();
}
macro.TypeParameterDeclarationImpl _typeParameter(
TypeParameterElement element,
) {
return macro.TypeParameterDeclarationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: identifier(element),
library: library(element),
metadata: _buildMetadata(element),
bound: element.bound.mapOrNull(_dartType),
);
}
}
class DeclarationBuilderFromNode {
final DeclarationBuilder declarationBuilder;
final Map<ast.NamedType, IdentifierImpl> _namedTypeMap = Map.identity();
final Map<Element, LibraryImpl> _libraryMap = Map.identity();
DeclarationBuilderFromNode(this.declarationBuilder);
ClassDeclarationImpl classDeclaration(
ast.ClassDeclarationImpl node,
) {
final element = node.declaredElement!;
final interfaceNodes = <ast.NamedType>[];
final mixinNodes = <ast.NamedType>[];
for (var current = node;;) {
if (current.implementsClause case final clause?) {
interfaceNodes.addAll(clause.interfaces);
}
if (current.withClause case final clause?) {
mixinNodes.addAll(clause.mixinTypes);
}
final nextElement = current.declaredElement?.augmentation;
final nextNode = declarationBuilder.nodeOfElement(nextElement);
if (nextNode is! ast.ClassDeclarationImpl) {
break;
}
current = nextNode;
}
return ClassDeclarationImpl._(
id: macro.RemoteInstance.uniqueId,
identifier: _declaredIdentifier(node.name, element),
library: library(element),
metadata: _buildMetadata(element),
typeParameters: _typeParameters(node.typeParameters),
interfaces: _namedTypes(interfaceNodes),
hasAbstract: node.abstractKeyword != null,
hasBase: node.baseKeyword != null,
hasExternal: false,
hasFinal: node.finalKeyword != null,
hasInterface: node.interfaceKeyword != null,
hasMixin: node.mixinKeyword != null,
hasSealed: node.sealedKeyword != null,
mixins: _namedTypes(mixinNodes),
superclass: node.extendsClause?.superclass.mapOrNull(_namedType),
element: element,
);
}
macro.ConstructorDeclarationImpl constructorDeclaration(
ast.ConstructorDeclarationImpl node,
) {
final definingType = _definingType(node);
final element = node.declaredElement!;
return ConstructorDeclarationImpl._(
id: macro.RemoteInstance.uniqueId,
definingType: definingType,
element: element,
identifier: _declaredIdentifier2(node.name?.lexeme ?? '', element),
library: library(element),
metadata: _buildMetadata(element),
hasBody: node.body is! ast.EmptyFunctionBody,
hasExternal: node.externalKeyword != null,
isFactory: node.factoryKeyword != null,
namedParameters: _namedFormalParameters(node.parameters),
positionalParameters: _positionalFormalParameters(node.parameters),
returnType: macro.NamedTypeAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: definingType,
typeArguments: const [],
isNullable: false,
),
typeParameters: const [],
);
}
ExtensionDeclarationImpl extensionDeclaration(
ast.ExtensionDeclarationImpl node,
) {
final element = node.declaredElement!;
return ExtensionDeclarationImpl._(
id: macro.RemoteInstance.uniqueId,
identifier: _declaredIdentifier2(node.name?.lexeme ?? '', element),
library: library(element),
metadata: _buildMetadata(element),
typeParameters: _typeParameters(node.typeParameters),
onType: _typeAnnotation(node.extendedType),
element: element,
);
}
ExtensionTypeDeclarationImpl extensionTypeDeclaration(
ast.ExtensionTypeDeclarationImpl node,
) {
final element = node.declaredElement!;
return ExtensionTypeDeclarationImpl._(
id: macro.RemoteInstance.uniqueId,
identifier: _declaredIdentifier2(node.name.lexeme, element),
library: library(element),
metadata: _buildMetadata(element),
typeParameters: _typeParameters(node.typeParameters),
representationType: _typeAnnotation(node.representation.fieldType),
element: element,
);
}
macro.FunctionDeclarationImpl functionDeclaration(
ast.FunctionDeclarationImpl node,
) {
final element = node.declaredElement!;
final function = node.functionExpression;
return FunctionDeclarationImpl._(
id: macro.RemoteInstance.uniqueId,
element: element,
identifier: _declaredIdentifier(node.name, element),
library: library(element),
metadata: _buildMetadata(element),
hasBody: function.body is! ast.EmptyFunctionBody,
hasExternal: node.externalKeyword != null,
isGetter: node.isGetter,
isOperator: false,
isSetter: node.isSetter,
namedParameters: _namedFormalParameters(function.parameters),
positionalParameters: _positionalFormalParameters(function.parameters),
returnType: _typeAnnotationOrDynamic(node.returnType),
typeParameters: _typeParameters(function.typeParameters),
);
}
macro.LibraryImpl library(Element element) {
final library = element.library!;
if (_libraryMap[library] case final result?) {
return result;
}
final version = library.languageVersion.effective;
final uri = library.source.uri;
return _libraryMap[library] = LibraryImplFromElement(
id: macro.RemoteInstance.uniqueId,
languageVersion: macro.LanguageVersionImpl(
version.major,
version.minor,
),
metadata: _buildMetadata(element),
uri: uri,
element: library,
);
}
macro.MethodDeclarationImpl methodDeclaration(
ast.MethodDeclarationImpl node,
) {
return _methodDeclaration(node);
}
MixinDeclarationImpl mixinDeclaration(
ast.MixinDeclarationImpl node,
) {
final element = node.declaredElement!;
final onNodes = <ast.NamedType>[];
final interfaceNodes = <ast.NamedType>[];
for (var current = node;;) {
if (current.onClause case final clause?) {
onNodes.addAll(clause.superclassConstraints);
}
if (current.implementsClause case final clause?) {
interfaceNodes.addAll(clause.interfaces);
}
final nextElement = current.declaredElement?.augmentation;
final nextNode = declarationBuilder.nodeOfElement(nextElement);
if (nextNode is! ast.MixinDeclarationImpl) {
break;
}
current = nextNode;
}
return MixinDeclarationImpl._(
id: macro.RemoteInstance.uniqueId,
identifier: _declaredIdentifier(node.name, element),
library: library(element),
metadata: _buildMetadata(element),
typeParameters: _typeParameters(node.typeParameters),
hasBase: node.baseKeyword != null,
interfaces: _namedTypes(interfaceNodes),
superclassConstraints: _namedTypes(onNodes),
element: element,
);
}
/// See [macro.DeclarationPhaseIntrospector.typeDeclarationOf].
macro.TypeDeclarationImpl typeDeclarationOf(ast.AstNode node) {
switch (node) {
case ast.ClassDeclarationImpl():
return classDeclaration(node);
case ast.MixinDeclarationImpl():
return mixinDeclaration(node);
default:
throw ArgumentError('node: $node');
}
}
macro.VariableDeclarationImpl variableDeclaration(
ast.VariableDeclaration node,
) {
final variableList = node.parent as ast.VariableDeclarationList;
final variablesDeclaration = variableList.parent;
switch (variablesDeclaration) {
case ast.FieldDeclarationImpl():
final element = node.declaredElement as FieldElementImpl;
return FieldDeclarationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: _declaredIdentifier(node.name, element),
library: library(element),
metadata: _buildMetadata(element),
hasAbstract: variablesDeclaration.abstractKeyword != null,
hasExternal: variablesDeclaration.externalKeyword != null,
hasFinal: element.isFinal,
hasLate: element.isLate,
type: _typeAnnotationVariable(variableList.type, element),
definingType: _definingType(variablesDeclaration),
isStatic: element.isStatic,
element: element,
);
default:
// TODO(scheglov): top-level variables
throw UnimplementedError();
}
}
List<macro.MetadataAnnotationImpl> _buildMetadata(Element element) {
return declarationBuilder._buildMetadata(element);
}
macro.IdentifierImpl _declaredIdentifier(Token name, Element element) {
final map = declarationBuilder._identifierMap;
return map[element] ??= _DeclaredIdentifierImpl(
id: macro.RemoteInstance.uniqueId,
name: name.lexeme,
element: element,
);
}
macro.IdentifierImpl _declaredIdentifier2(String name, Element element) {
final map = declarationBuilder._identifierMap;
return map[element] ??= _DeclaredIdentifierImpl(
id: macro.RemoteInstance.uniqueId,
name: name,
element: element,
);
}
macro.IdentifierImpl _definingType(ast.AstNode node) {
final parentNode = node.parent;
switch (parentNode) {
case ast.ClassDeclaration():
final parentElement = parentNode.declaredElement!;
final typeElement = parentElement.augmentationTarget ?? parentElement;
return _declaredIdentifier(parentNode.name, typeElement);
case ast.ExtensionDeclaration():
final parentElement = parentNode.declaredElement!;
final typeElement = parentElement.augmentationTarget ?? parentElement;
return _declaredIdentifier2(parentNode.name?.lexeme ?? '', typeElement);
case ast.ExtensionTypeDeclaration():
final parentElement = parentNode.declaredElement!;
final typeElement = parentElement.augmentationTarget ?? parentElement;
return _declaredIdentifier(parentNode.name, typeElement);
case ast.MixinDeclaration():
final parentElement = parentNode.declaredElement!;
final typeElement = parentElement.augmentationTarget ?? parentElement;
return _declaredIdentifier(parentNode.name, typeElement);
default:
// TODO(scheglov): other parents
throw UnimplementedError('(${parentNode.runtimeType}) $parentNode');
}
}
macro.ParameterDeclarationImpl _formalParameter(ast.FormalParameter node) {
if (node is ast.DefaultFormalParameter) {
node = node.parameter;
}
final element = node.declaredElement!;
final macro.TypeAnnotationImpl typeAnnotation;
if (node is ast.SimpleFormalParameter) {
typeAnnotation = _typeAnnotationVariable(node.type, element);
} else {
throw UnimplementedError('(${node.runtimeType}) $node');
}
return macro.ParameterDeclarationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: _declaredIdentifier(node.name!, element),
isNamed: node.isNamed,
isRequired: node.isRequired,
library: library(element),
metadata: _buildMetadata(element),
type: typeAnnotation,
);
}
macro.FunctionTypeParameterImpl _functionTypeFormalParameter(
ast.FormalParameter node,
) {
if (node is ast.DefaultFormalParameter) {
node = node.parameter;
}
final element = node.declaredElement!;
final macro.TypeAnnotationImpl typeAnnotation;
if (node is ast.SimpleFormalParameter) {
typeAnnotation = _typeAnnotationOrDynamic(node.type);
} else {
throw UnimplementedError('(${node.runtimeType}) $node');
}
return macro.FunctionTypeParameterImpl(
id: macro.RemoteInstance.uniqueId,
isNamed: node.isNamed,
isRequired: node.isRequired,
metadata: _buildMetadata(element),
name: node.name?.lexeme,
type: typeAnnotation,
);
}
MethodDeclarationImpl _methodDeclaration(
ast.MethodDeclarationImpl node,
) {
final definingType = _definingType(node);
final element = node.declaredElement!;
return MethodDeclarationImpl._(
id: macro.RemoteInstance.uniqueId,
definingType: definingType,
element: element,
identifier: _declaredIdentifier(node.name, element),
library: library(element),
metadata: _buildMetadata(element),
hasBody: node.body is! ast.EmptyFunctionBody,
hasExternal: node.externalKeyword != null,
isGetter: node.isGetter,
isOperator: node.isOperator,
isSetter: node.isSetter,
isStatic: node.isStatic,
namedParameters: _namedFormalParameters(node.parameters),
positionalParameters: _positionalFormalParameters(node.parameters),
returnType: _typeAnnotationMethodReturnType(node),
typeParameters: _typeParameters(node.typeParameters),
);
}
List<macro.ParameterDeclarationImpl> _namedFormalParameters(
ast.FormalParameterList? node,
) {
if (node != null) {
return node.parameters
.where((e) => e.isNamed)
.map(_formalParameter)
.toList();
} else {
return const [];
}
}
macro.NamedTypeAnnotationImpl _namedType(ast.NamedType node) {
return macro.NamedTypeAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: _namedTypeIdentifier(node),
isNullable: node.question != null,
typeArguments: _typeAnnotations(node.typeArguments?.arguments),
);
}
macro.IdentifierImpl _namedTypeIdentifier(ast.NamedType node) {
if (node.importPrefix == null && node.name2.lexeme == 'void') {
return _namedTypeMap[node] ??= _VoidIdentifierImpl();
}
return _namedTypeMap[node] ??= _NamedTypeIdentifierImpl(
id: macro.RemoteInstance.uniqueId,
name: node.name2.lexeme,
node: node,
);
}
List<macro.NamedTypeAnnotationImpl> _namedTypes(
List<ast.NamedType>? elements,
) {
if (elements != null) {
return elements.map(_namedType).toList();
} else {
return const [];
}
}
List<macro.ParameterDeclarationImpl> _positionalFormalParameters(
ast.FormalParameterList? node,
) {
if (node != null) {
return node.parameters
.where((e) => e.isPositional)
.map(_formalParameter)
.toList();
} else {
return const [];
}
}
macro.TypeAnnotationImpl _typeAnnotation(ast.TypeAnnotation node) {
node as ast.TypeAnnotationImpl;
switch (node) {
case ast.GenericFunctionTypeImpl():
return macro.FunctionTypeAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
isNullable: node.question != null,
namedParameters: node.parameters.parameters
.where((e) => e.isNamed)
.map(_functionTypeFormalParameter)
.toList(),
positionalParameters: node.parameters.parameters
.where((e) => e.isPositional)
.map(_functionTypeFormalParameter)
.toList(),
returnType: _typeAnnotationOrDynamic(node.returnType),
typeParameters: _typeParameters(node.typeParameters),
);
case ast.NamedTypeImpl():
return _namedType(node);
case ast.RecordTypeAnnotationImpl():
return _typeAnnotationRecord(node);
}
}
macro.TypeAnnotationImpl _typeAnnotationMethodReturnType(
ast.MethodDeclaration node,
) {
final returnType = node.returnType;
if (returnType == null) {
final element = node.declaredElement!;
return _OmittedTypeAnnotationMethodReturnType(element);
}
return _typeAnnotation(returnType);
}
macro.TypeAnnotationImpl _typeAnnotationOrDynamic(ast.TypeAnnotation? node) {
if (node == null) {
return _OmittedTypeAnnotationDynamic();
}
return _typeAnnotation(node);
}
macro.RecordTypeAnnotationImpl _typeAnnotationRecord(
ast.RecordTypeAnnotation node,
) {
final unitNode = node.thisOrAncestorOfType<ast.CompilationUnit>()!;
final unitElement = unitNode.declaredElement!;
final macroLibrary = library(unitElement);
macro.RecordFieldDeclarationImpl buildField(
ast.RecordTypeAnnotationField field,
) {
final name = field.name?.lexeme ?? '';
return macro.RecordFieldDeclarationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: IdentifierImplFromNode(
id: macro.RemoteInstance.uniqueId,
name: name,
getElement: () => null,
),
library: macroLibrary,
metadata: const [],
name: name,
type: _typeAnnotationOrDynamic(field.type),
);
}
return macro.RecordTypeAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
positionalFields: node.positionalFields.map(buildField).toList(),
namedFields: node.namedFields?.fields.map(buildField).toList() ?? [],
isNullable: node.question != null,
);
}
List<macro.TypeAnnotationImpl> _typeAnnotations(
List<ast.TypeAnnotation>? elements,
) {
if (elements != null) {
return List.generate(
elements.length, (i) => _typeAnnotation(elements[i]));
} else {
return const [];
}
}
macro.TypeAnnotationImpl _typeAnnotationVariable(
ast.TypeAnnotation? type,
VariableElement element,
) {
if (type == null) {
return _OmittedTypeAnnotationVariable(element);
}
return _typeAnnotation(type);
}
macro.TypeParameterDeclarationImpl _typeParameter(
ast.TypeParameter node,
) {
final element = node.declaredElement!;
return macro.TypeParameterDeclarationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: _declaredIdentifier(node.name, element),
library: library(element),
metadata: _buildMetadata(element),
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 ExtensionDeclarationImpl extends macro.ExtensionDeclarationImpl
implements HasElement {
@override
final ExtensionElementImpl element;
ExtensionDeclarationImpl._({
required super.id,
required super.identifier,
required super.library,
required super.metadata,
required super.typeParameters,
required super.onType,
required this.element,
});
}
class ExtensionTypeDeclarationImpl extends macro.ExtensionTypeDeclarationImpl
implements HasElement {
@override
final ExtensionTypeElementImpl element;
ExtensionTypeDeclarationImpl._({
required super.id,
required super.identifier,
required super.library,
required super.metadata,
required super.typeParameters,
required super.representationType,
required this.element,
});
}
class FieldDeclarationImpl extends macro.FieldDeclarationImpl
implements HasElement {
@override
final FieldElementImpl element;
FieldDeclarationImpl({
required super.id,
required super.identifier,
required super.library,
required super.metadata,
required super.hasAbstract,
required super.hasExternal,
required super.hasFinal,
required super.hasLate,
required super.type,
required super.definingType,
required super.isStatic,
required this.element,
});
}
class FunctionDeclarationImpl extends macro.FunctionDeclarationImpl
implements HasElement {
@override
final ExecutableElementImpl element;
FunctionDeclarationImpl._({
required super.id,
required super.identifier,
required super.library,
required super.metadata,
required super.hasBody,
required super.hasExternal,
required super.isGetter,
required super.isOperator,
required super.isSetter,
required super.namedParameters,
required super.positionalParameters,
required super.returnType,
required super.typeParameters,
required this.element,
});
}
/// A macro declaration that has an [Element].
abstract interface class HasElement {
ElementImpl get element;
}
abstract class IdentifierImpl extends macro.IdentifierImpl {
IdentifierImpl({
required super.id,
required super.name,
});
Element? get element;
}
class IdentifierImplFromElement extends IdentifierImpl {
@override
final Element element;
IdentifierImplFromElement({
required super.id,
required super.name,
required this.element,
});
}
class IdentifierImplFromNode extends IdentifierImpl {
final Element? Function() getElement;
IdentifierImplFromNode({
required super.id,
required super.name,
required this.getElement,
});
@override
Element? get element => getElement();
}
abstract class LibraryImpl extends macro.LibraryImpl {
LibraryImpl({
required super.id,
required super.languageVersion,
required super.metadata,
required super.uri,
});
Element? get element;
}
class LibraryImplFromElement extends LibraryImpl {
@override
final Element element;
LibraryImplFromElement({
required super.id,
required super.languageVersion,
required super.metadata,
required super.uri,
required this.element,
});
}
class MethodDeclarationImpl extends macro.MethodDeclarationImpl
implements HasElement {
@override
final ExecutableElementImpl element;
MethodDeclarationImpl._({
required super.id,
required super.identifier,
required super.library,
required super.metadata,
required super.hasBody,
required super.hasExternal,
required super.isGetter,
required super.isOperator,
required super.isSetter,
required super.isStatic,
required super.namedParameters,
required super.positionalParameters,
required super.returnType,
required super.typeParameters,
required super.definingType,
required this.element,
});
}
class MixinDeclarationImpl extends macro.MixinDeclarationImpl
implements HasElement {
@override
final MixinElementImpl element;
MixinDeclarationImpl._({
required super.id,
required super.identifier,
required super.library,
required super.metadata,
required super.typeParameters,
required super.hasBase,
required super.interfaces,
required super.superclassConstraints,
required this.element,
});
}
class _DeclaredIdentifierImpl extends IdentifierImpl {
@override
final Element element;
_DeclaredIdentifierImpl({
required super.id,
required super.name,
required this.element,
});
}
class _NamedTypeIdentifierImpl extends IdentifierImpl {
final ast.NamedType node;
_NamedTypeIdentifierImpl({
required super.id,
required super.name,
required this.node,
});
@override
Element? get element => node.element;
}
sealed class _OmittedTypeAnnotation extends macro.OmittedTypeAnnotationImpl {
_OmittedTypeAnnotation()
: super(
id: macro.RemoteInstance.uniqueId,
);
}
class _OmittedTypeAnnotationDynamic extends _OmittedTypeAnnotation {
_OmittedTypeAnnotationDynamic();
}
class _OmittedTypeAnnotationMethodReturnType extends _OmittedTypeAnnotation {
final ExecutableElement element;
_OmittedTypeAnnotationMethodReturnType(this.element);
}
class _OmittedTypeAnnotationVariable extends _OmittedTypeAnnotation {
final VariableElement element;
_OmittedTypeAnnotationVariable(this.element);
}
class _VoidIdentifierImpl extends IdentifierImpl {
_VoidIdentifierImpl()
: super(
id: macro.RemoteInstance.uniqueId,
name: 'void',
);
@override
Element? get element => null;
}
extension<T> on T? {
R? mapOrNull<R>(R Function(T) mapper) {
final self = this;
return self != null ? mapper(self) : null;
}
}
extension on Element {
/// With the assumption that enclosing element is an [InstanceElement], and
/// is not an invalid augmentation, return the declaration - the start of
/// the augmentation chain.
InstanceElement get enclosingInstanceElement {
final enclosing = enclosingElement as InstanceElement;
return enclosing.augmented!.declaration;
}
}