blob: c6e3621e11030d497ae9148ac21d31f88ec0d88d [file] [log] [blame]
// Copyright (c) 2023, 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 'dart:async';
import 'package:macros/macros.dart';
/// Does not do anything useful, just augments the target in the definitions
/// phase, so that any omitted types are written into the augmentation.
/*macro*/ class AugmentForOmittedTypes
implements FieldDefinitionMacro, FunctionDefinitionMacro {
const AugmentForOmittedTypes();
@override
FutureOr<void> buildDefinitionForField(declaration, builder) {
builder.augment(
initializer: ExpressionCode.fromString('0'),
);
}
@override
FutureOr<void> buildDefinitionForFunction(declaration, builder) {
builder.augment(
FunctionBodyCode.fromString('{}'),
);
}
}
/*macro*/ class DeclarationsPhaseAnnotationType
implements
ClassDeclarationsMacro,
EnumDeclarationsMacro,
ExtensionDeclarationsMacro,
ExtensionTypeDeclarationsMacro,
FieldDeclarationsMacro,
FunctionDeclarationsMacro,
ConstructorDeclarationsMacro,
MethodDeclarationsMacro,
MixinDeclarationsMacro,
TypeAliasDeclarationsMacro,
VariableDeclarationsMacro {
const DeclarationsPhaseAnnotationType();
@override
buildDeclarationsForClass(declaration, builder) {
_build(declaration, builder);
}
@override
buildDeclarationsForConstructor(declaration, builder) {
_build(declaration, builder);
}
@override
buildDeclarationsForEnum(declaration, builder) {
_build(declaration, builder);
}
@override
buildDeclarationsForExtension(declaration, builder) {
_build(declaration, builder);
}
@override
buildDeclarationsForExtensionType(declaration, builder) {
_build(declaration, builder);
}
@override
buildDeclarationsForField(declaration, builder) {
_build(declaration, builder);
}
@override
buildDeclarationsForFunction(declaration, builder) {
_build(declaration, builder);
}
@override
FutureOr<void> buildDeclarationsForMethod(declaration, builder) {
_build(declaration, builder);
}
@override
buildDeclarationsForMixin(declaration, builder) {
_build(declaration, builder);
}
@override
buildDeclarationsForTypeAlias(declaration, builder) {
_build(declaration, builder);
}
@override
buildDeclarationsForVariable(declaration, builder) {
_build(declaration, builder);
}
void _build(Declaration declaration, DeclarationBuilder builder) {
var commaClassNamePairs = declaration.metadata
.map((annotation) {
annotation as ConstructorMetadataAnnotation;
return [', ', annotation.type.code];
})
.expand((elements) => elements)
.skip(1)
.toList();
var code = DeclarationCode.fromParts([
'var x = [',
...commaClassNamePairs,
'];',
]);
builder.declareInLibrary(code);
}
}
/*macro*/ class DefineToStringAsTypeName
implements ClassDefinitionMacro, MethodDefinitionMacro {
const DefineToStringAsTypeName();
@override
FutureOr<void> buildDefinitionForClass(
ClassDeclaration clazz,
TypeDefinitionBuilder builder,
) async {
var methods = await builder.methodsOf(clazz);
var toString = methods.firstWhereOrNull(
(e) => e.identifier.name == 'toString',
);
if (toString == null) {
throw StateError('No toString() declaration');
}
var toStringBuilder = await builder.buildMethod(
toString.identifier,
);
toStringBuilder.augment(
FunctionBodyCode.fromParts([
'{\n return \'${clazz.identifier.name}\';\n }',
]),
);
}
@override
FutureOr<void> buildDefinitionForMethod(
MethodDeclaration method,
FunctionDefinitionBuilder builder,
) {
builder.augment(
FunctionBodyCode.fromString("=> '${method.definingType.name}';"),
);
}
}
/*macro*/ class ReferenceFirstFormalParameter
implements FunctionDefinitionMacro {
const ReferenceFirstFormalParameter();
@override
Future<void> buildDefinitionForFunction(
FunctionDeclaration function,
FunctionDefinitionBuilder builder,
) async {
builder.augment(
FunctionBodyCode.fromParts([
'{\n ',
function.positionalParameters.first.identifier,
';\n}',
]),
);
}
}
/*macro*/ class ReferenceFirstTypeParameter implements FunctionDefinitionMacro {
const ReferenceFirstTypeParameter();
@override
Future<void> buildDefinitionForFunction(
FunctionDeclaration function,
FunctionDefinitionBuilder builder,
) async {
builder.augment(
FunctionBodyCode.fromParts([
'{\n ',
function.typeParameters.first.identifier,
';\n}',
]),
);
}
}
/*macro*/ class ReferenceIdentifier implements ClassDeclarationsMacro {
final String uriStr;
final String topName;
final String? memberName;
final String parametersCode;
final String leadCode;
const ReferenceIdentifier(
this.uriStr,
this.topName, {
this.memberName,
this.parametersCode = '',
this.leadCode = '',
});
@override
FutureOr<void> buildDeclarationsForClass(
ClassDeclaration declaration,
MemberDeclarationBuilder builder,
) async {
var uri = Uri.parse(uriStr);
// ignore: deprecated_member_use
var identifier = await builder.resolveIdentifier(uri, topName);
if (memberName case var memberName?) {
var type = await builder.typeDeclarationOf(identifier);
identifier = [
...await builder.constructorsOf(type),
...await builder.fieldsOf(type),
...await builder.methodsOf(type),
].map((e) => e.identifier).firstWhere((e) => e.name == memberName);
}
builder.declareInType(
DeclarationCode.fromParts([
' void doReference($parametersCode) {\n ',
leadCode,
identifier,
';\n }',
]),
);
}
}
extension<T> on Iterable<T> {
T? firstWhereOrNull(bool Function(T element) test) {
for (var element in this) {
if (test(element)) return element;
}
return null;
}
}