Macro. Introspect MethodDeclaration node.
Change-Id: I2d790cd82586db8686c92b30b7599c332b73a2be
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/331842
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/summary2/macro_declarations.dart b/pkg/analyzer/lib/src/summary2/macro_declarations.dart
index f779dcc..8fd21bf 100644
--- a/pkg/analyzer/lib/src/summary2/macro_declarations.dart
+++ b/pkg/analyzer/lib/src/summary2/macro_declarations.dart
@@ -35,7 +35,10 @@
}
class DeclarationBuilder {
- final DeclarationBuilderFromNode fromNode = DeclarationBuilderFromNode();
+ final Map<Uri, List<ast.Annotation>> libraryMetadataMap = {};
+
+ late final DeclarationBuilderFromNode fromNode =
+ DeclarationBuilderFromNode(this);
final DeclarationBuilderFromElement fromElement =
DeclarationBuilderFromElement();
@@ -44,7 +47,6 @@
/// corresponding elements. So, we can access them uniformly via interfaces,
/// mixins, etc.
void transferToElements() {
- // TODO(scheglov) Make sure that these are only declarations?
for (final entry in fromNode._namedTypeMap.entries) {
final element = entry.key.element;
if (element != null) {
@@ -61,9 +63,13 @@
for (final entry in fromNode._classMap.entries) {
final element = entry.key.declaredElement!;
final declaration = entry.value;
- declaration.element = element;
fromElement._classMap[element] = declaration;
}
+ for (final entry in fromNode._methodMap.entries) {
+ final element = entry.key.declaredElement!;
+ final declaration = entry.value;
+ fromElement._methodMap[element] = declaration;
+ }
}
}
@@ -76,6 +82,9 @@
final Map<FieldElement, FieldDeclarationImpl> _fieldMap = Map.identity();
+ final Map<ExecutableElement, MethodDeclarationImpl> _methodMap =
+ Map.identity();
+
final Map<TypeParameterElement, macro.TypeParameterDeclarationImpl>
_typeParameterMap = Map.identity();
@@ -103,8 +112,7 @@
id: macro.RemoteInstance.uniqueId,
languageVersion:
macro.LanguageVersionImpl(version.major, version.minor),
- // TODO: Provide metadata annotations.
- metadata: const [],
+ metadata: _buildMetadata(element),
uri: element.library!.source.uri,
element: element);
_libraryMap[element.library!] = library;
@@ -112,12 +120,21 @@
return library;
}
+ macro.MethodDeclarationImpl methodElement(MethodElement element) {
+ return _methodMap[element] ??= _methodElement(element);
+ }
+
macro.TypeParameterDeclarationImpl typeParameter(
TypeParameterElement element,
) {
return _typeParameterMap[element] ??= _typeParameter(element);
}
+ List<macro.MetadataAnnotationImpl> _buildMetadata(Element element) {
+ // TODO: Provide metadata annotations.
+ return const [];
+ }
+
macro.TypeAnnotationImpl _dartType(DartType type) {
switch (type) {
case InterfaceType():
@@ -129,20 +146,28 @@
identifier: identifier(type.element),
typeArguments: const [],
);
+ case VoidType():
+ return macro.NamedTypeAnnotationImpl(
+ id: macro.RemoteInstance.uniqueId,
+ identifier: macro.IdentifierImpl(
+ id: macro.RemoteInstance.uniqueId,
+ name: 'void',
+ ),
+ isNullable: false,
+ typeArguments: const [],
+ );
default:
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),
library: library(element),
- // TODO: Provide metadata annotations.
- metadata: const [],
+ metadata: _buildMetadata(element),
hasExternal: element.isExternal,
hasFinal: element.isFinal,
hasLate: element.isLate,
@@ -163,13 +188,11 @@
IntrospectableClassDeclarationImpl _introspectableClassElement(
ClassElement element) {
- assert(!_classMap.containsKey(element));
return IntrospectableClassDeclarationImpl._(
id: macro.RemoteInstance.uniqueId,
identifier: identifier(element),
library: library(element),
- // TODO: Provide metadata annotations.
- metadata: const [],
+ metadata: _buildMetadata(element),
typeParameters: element.typeParameters.map(_typeParameter).toList(),
interfaces: element.interfaces.map(_interfaceType).toList(),
hasAbstract: element.isAbstract,
@@ -181,7 +204,37 @@
hasSealed: element.isSealed,
mixins: element.mixins.map(_interfaceType).toList(),
superclass: element.supertype.mapOrNull(_interfaceType),
- )..element = element;
+ element: element,
+ );
+ }
+
+ MethodDeclarationImpl _methodElement(MethodElement element) {
+ final enclosingClass = element.enclosingElement as ClassElement;
+ return MethodDeclarationImpl._(
+ element: element,
+ id: macro.RemoteInstance.uniqueId,
+ identifier: identifier(element),
+ library: library(element),
+ metadata: _buildMetadata(element),
+ hasAbstract: false,
+ // hasBody: node.body is! ast.EmptyFunctionBody,
+ hasBody: true,
+ // hasExternal: node.externalKeyword != null,
+ hasExternal: false,
+ // isGetter: node.isGetter,
+ isGetter: false,
+ // isOperator: node.isOperator,
+ isOperator: false,
+ // isSetter: node.isSetter,
+ isSetter: false,
+ // isStatic: node.isStatic,
+ isStatic: element.isStatic,
+ namedParameters: [], // TODO(scheglov) implement
+ positionalParameters: [], // TODO(scheglov) implement
+ returnType: _dartType(element.returnType),
+ typeParameters: element.typeParameters.map(_typeParameter).toList(),
+ definingType: identifier(enclosingClass),
+ );
}
macro.TypeParameterDeclarationImpl _typeParameter(
@@ -191,14 +244,15 @@
id: macro.RemoteInstance.uniqueId,
identifier: identifier(element),
library: library(element),
- // TODO: Provide metadata annotations.
- metadata: const [],
+ metadata: _buildMetadata(element),
bound: element.bound.mapOrNull(_dartType),
);
}
}
class DeclarationBuilderFromNode {
+ final DeclarationBuilder declarationBuilder;
+
final Map<ast.NamedType, IdentifierImpl> _namedTypeMap = Map.identity();
final Map<Element, IdentifierImpl> _declaredIdentifierMap = Map.identity();
@@ -210,6 +264,8 @@
final Map<ast.MethodDeclaration, MethodDeclarationImpl> _methodMap =
Map.identity();
+ DeclarationBuilderFromNode(this.declarationBuilder);
+
macro.ClassDeclarationImpl classDeclaration(
ast.ClassDeclaration node,
) {
@@ -217,20 +273,26 @@
}
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),
- // TODO: Provide metadata annotations.
- metadata: const [],
- uri: element.library!.source.uri,
- element: element);
- _libraryMap[element.library!] = library;
+ final library = element.library!;
+
+ if (_libraryMap[library] case final result?) {
+ return result;
}
- return library;
+
+ final version = library.languageVersion.effective;
+ final uri = library.source.uri;
+ final metadataNodes = declarationBuilder.libraryMetadataMap[uri] ?? [];
+
+ return _libraryMap[library] = LibraryImplFromElement(
+ id: macro.RemoteInstance.uniqueId,
+ languageVersion: macro.LanguageVersionImpl(
+ version.major,
+ version.minor,
+ ),
+ metadata: _buildMetadata(metadataNodes),
+ uri: uri,
+ element: library,
+ );
}
macro.MethodDeclarationImpl methodDeclaration(
@@ -239,6 +301,13 @@
return _methodMap[node] ??= _methodDeclaration(node);
}
+ List<macro.MetadataAnnotationImpl> _buildMetadata(
+ List<ast.Annotation> elements,
+ ) {
+ // TODO: Provide metadata annotations.
+ return const [];
+ }
+
macro.IdentifierImpl _declaredIdentifier(Token name, Element element) {
return _declaredIdentifierMap[element] ??= _DeclaredIdentifierImpl(
id: macro.RemoteInstance.uniqueId,
@@ -247,7 +316,32 @@
);
}
- macro.FunctionTypeParameterImpl _formalParameter(
+ macro.ParameterDeclarationImpl _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');
+ }
+
+ final element = node.declaredElement!;
+
+ return macro.ParameterDeclarationImpl(
+ id: macro.RemoteInstance.uniqueId,
+ identifier: _declaredIdentifier(node.name!, element),
+ isNamed: node.isNamed,
+ isRequired: node.isRequired,
+ library: library(element),
+ metadata: _buildMetadata(node.metadata),
+ type: typeAnnotation,
+ );
+ }
+
+ macro.FunctionTypeParameterImpl _functionTypeFormalParameter(
ast.FormalParameter node,
) {
if (node is ast.DefaultFormalParameter) {
@@ -265,9 +359,8 @@
id: macro.RemoteInstance.uniqueId,
isNamed: node.isNamed,
isRequired: node.isRequired,
+ metadata: _buildMetadata(node.metadata),
name: node.name?.lexeme,
- // TODO: Provide metadata annotations.
- metadata: const [],
type: typeAnnotation,
);
}
@@ -275,13 +368,12 @@
IntrospectableClassDeclarationImpl _introspectableClassDeclaration(
ast.ClassDeclaration node,
) {
- assert(!_classMap.containsKey(node));
+ final element = node.declaredElement!;
return IntrospectableClassDeclarationImpl._(
id: macro.RemoteInstance.uniqueId,
- identifier: _declaredIdentifier(node.name, node.declaredElement!),
- library: library(node.declaredElement!),
- // TODO: Provide metadata annotations.
- metadata: const [],
+ identifier: _declaredIdentifier(node.name, element),
+ library: library(element),
+ metadata: _buildMetadata(node.metadata),
typeParameters: _typeParameters(node.typeParameters),
interfaces: _namedTypes(node.implementsClause?.interfaces),
hasAbstract: node.abstractKeyword != null,
@@ -293,27 +385,28 @@
hasSealed: node.sealedKeyword != null,
mixins: _namedTypes(node.withClause?.mixinTypes),
superclass: node.extendsClause?.superclass.mapOrNull(_namedType),
+ element: element,
);
}
MethodDeclarationImpl _methodDeclaration(
ast.MethodDeclaration node,
) {
- assert(!_methodMap.containsKey(node));
-
// TODO(scheglov) other parents
final parentNode = node.parent as ast.ClassDeclaration;
final parentElement = parentNode.declaredElement!;
final typeElement = parentElement.augmentationTarget ?? parentElement;
final definingType = _declaredIdentifier(parentNode.name, typeElement);
+ final element = node.declaredElement!;
+
return MethodDeclarationImpl._(
- element: node.declaredElement as MethodElement,
id: macro.RemoteInstance.uniqueId,
- identifier: _declaredIdentifier(node.name, node.declaredElement!),
- library: library(node.declaredElement!),
- // TODO: Provide metadata annotations.
- metadata: const [],
+ definingType: definingType,
+ element: element,
+ identifier: _declaredIdentifier(node.name, element),
+ library: library(element),
+ metadata: _buildMetadata(node.metadata),
hasAbstract: false,
hasBody: node.body is! ast.EmptyFunctionBody,
hasExternal: node.externalKeyword != null,
@@ -321,14 +414,26 @@
isOperator: node.isOperator,
isSetter: node.isSetter,
isStatic: node.isStatic,
- namedParameters: [], // TODO(scheglov) implement
- positionalParameters: [], // TODO(scheglov) implement
+ namedParameters: _namedFormalParameters(node.parameters),
+ positionalParameters: _positionalFormalParameters(node.parameters),
returnType: _typeAnnotation(node.returnType),
typeParameters: _typeParameters(node.typeParameters),
- definingType: definingType,
);
}
+ 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,
@@ -356,6 +461,19 @@
}
}
+ 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) {
switch (node) {
case null:
@@ -368,11 +486,11 @@
isNullable: node.question != null,
namedParameters: node.parameters.parameters
.where((e) => e.isNamed)
- .map(_formalParameter)
+ .map(_functionTypeFormalParameter)
.toList(),
positionalParameters: node.parameters.parameters
.where((e) => e.isPositional)
- .map(_formalParameter)
+ .map(_functionTypeFormalParameter)
.toList(),
returnType: _typeAnnotation(node.returnType),
typeParameters: _typeParameters(node.typeParameters),
@@ -402,8 +520,7 @@
id: macro.RemoteInstance.uniqueId,
identifier: _declaredIdentifier(node.name, node.declaredElement!),
library: library(node.declaredElement!),
- // TODO: Provide metadata annotations.
- metadata: const [],
+ metadata: _buildMetadata(node.metadata),
bound: node.bound.mapOrNull(_typeAnnotation),
);
}
@@ -456,7 +573,7 @@
class IntrospectableClassDeclarationImpl
extends macro.IntrospectableClassDeclarationImpl {
- late final ClassElement element;
+ final ClassElement element;
IntrospectableClassDeclarationImpl._({
required super.id,
@@ -474,6 +591,7 @@
required super.hasSealed,
required super.mixins,
required super.superclass,
+ required this.element,
});
}
@@ -502,7 +620,7 @@
}
class MethodDeclarationImpl extends macro.MethodDeclarationImpl {
- final MethodElement element;
+ final ExecutableElement element;
MethodDeclarationImpl._({
required super.id,
@@ -515,12 +633,12 @@
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 super.isStatic,
required this.element,
});
}
diff --git a/pkg/analyzer/test/src/summary/macro/declaration_text.dart b/pkg/analyzer/test/src/summary/macro/declaration_text.dart
index f0f228d..ea8744a 100644
--- a/pkg/analyzer/test/src/summary/macro/declaration_text.dart
+++ b/pkg/analyzer/test/src/summary/macro/declaration_text.dart
@@ -8,7 +8,8 @@
import 'introspect_shared.dart';
-/*macro*/ class DeclarationTextMacro implements ClassTypesMacro {
+/*macro*/ class DeclarationTextMacro
+ implements ClassTypesMacro, MethodTypesMacro {
const DeclarationTextMacro();
@override
@@ -24,6 +25,20 @@
),
);
}
+
+ @override
+ FutureOr<void> buildTypesForMethod(method, builder) {
+ final printer = _DeclarationPrinter();
+ printer.writeMethodDeclaration(method);
+ final text = printer._sink.toString();
+
+ builder.declareType(
+ 'x',
+ DeclarationCode.fromString(
+ 'const x = r"""$text""";',
+ ),
+ );
+ }
}
class _DeclarationPrinter {
@@ -48,6 +63,43 @@
});
}
+ void writeIndent() {
+ _sink.write(_indent);
+ }
+
+ /// TODO(scheglov) Copy TreeStringSink here
+ void writeIndentedLine(void Function() f) {
+ writeIndent();
+ f();
+ writeln();
+ }
+
+ void writeln([Object? object = '']) {
+ _sink.writeln(object);
+ }
+
+ void writeMethodDeclaration(MethodDeclaration e) {
+ _writelnWithIndent(e.identifier.name);
+
+ _withIndent(() {
+ _writeFlags({
+ 'hasAbstract': e.hasAbstract,
+ 'hasBody': e.hasBody,
+ 'hasExternal': e.hasExternal,
+ 'isGetter': e.isGetter,
+ 'isOperator': e.isOperator,
+ 'isSetter': e.isSetter,
+ 'isStatic': e.isStatic,
+ });
+
+ _writeMetadata(e);
+ _writeNamedFormalParameters(e.namedParameters);
+ _writePositionalFormalParameters(e.positionalParameters);
+ _writeTypeAnnotation('returnType', e.returnType);
+ _writeTypeParameters(e.typeParameters);
+ });
+ }
+
void _withIndent(void Function() f) {
var savedIndent = _indent;
_indent = '$savedIndent ';
@@ -70,6 +122,30 @@
}
}
+ void _writeFlags(Map<String, bool> flags) {
+ if (flags.values.any((flag) => flag)) {
+ writeIndentedLine(() {
+ _sink.write('flags:');
+ for (final entry in flags.entries) {
+ if (entry.value) {
+ _sink.write(' ${entry.key}');
+ }
+ }
+ });
+ }
+ }
+
+ void _writeFormalParameter(ParameterDeclaration e) {
+ _writelnWithIndent(e.identifier.name);
+ _withIndent(() {
+ _writeFlags({
+ 'isNamed': e.isNamed,
+ 'isRequired': e.isRequired,
+ });
+ _writeTypeAnnotation('type', e.type);
+ });
+ }
+
void _writeIf(bool flag, String str) {
if (flag) {
_sink.write(str);
@@ -85,6 +161,26 @@
_sink.writeln(line);
}
+ void _writeMetadata(Annotatable e) {
+ _writeElements('metadata', e.metadata, _writeMetadataAnnotation);
+ }
+
+ void _writeMetadataAnnotation(MetadataAnnotation e) {
+ // TODO(scheglov) implement
+ }
+
+ void _writeNamedFormalParameters(
+ Iterable<ParameterDeclaration> elements,
+ ) {
+ _writeElements('namedParameters', elements, _writeFormalParameter);
+ }
+
+ void _writePositionalFormalParameters(
+ Iterable<ParameterDeclaration> elements,
+ ) {
+ _writeElements('positionalParameters', elements, _writeFormalParameter);
+ }
+
void _writeTypeAnnotation(String name, TypeAnnotation? type) {
_sink.write(_indent);
_sink.write('$name: ');
diff --git a/pkg/analyzer/test/src/summary/macro_test.dart b/pkg/analyzer/test/src/summary/macro_test.dart
index 460ecb6..dd6c89a 100644
--- a/pkg/analyzer/test/src/summary/macro_test.dart
+++ b/pkg/analyzer/test/src/summary/macro_test.dart
@@ -1412,8 +1412,116 @@
return code.replaceAll('/*macro*/', 'macro');
}
+ test_class_methodDeclaration_getter() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+abstract class A {
+ @DeclarationTextMacro()
+ int get foo => 0;
+}
+''', r'''
+foo
+ flags: hasBody isGetter
+ returnType: int
+''');
+ }
+
+ test_class_methodDeclaration_method_hasBody_false() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+abstract class A {
+ @DeclarationTextMacro()
+ void foo();
+}
+''', r'''
+foo
+ returnType: void
+''');
+ }
+
+ test_class_methodDeclaration_method_hasExternal() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+abstract class A {
+ @DeclarationTextMacro()
+ external void foo();
+}
+''', r'''
+foo
+ flags: hasExternal
+ returnType: void
+''');
+ }
+
+ test_class_methodDeclaration_method_isStatic() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A {
+ @DeclarationTextMacro()
+ static void foo() {}
+}
+''', r'''
+foo
+ flags: hasBody isStatic
+ returnType: void
+''');
+ }
+
+ test_class_methodDeclaration_method_namedParameters() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+abstract class A {
+ @DeclarationTextMacro()
+ void foo({required int a, String? b}]) {}
+}
+''', r'''
+foo
+ flags: hasBody
+ namedParameters
+ a
+ flags: isNamed isRequired
+ type: int
+ b
+ flags: isNamed
+ type: String?
+ returnType: void
+''');
+ }
+
+ test_class_methodDeclaration_method_positionalParameters() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+abstract class A {
+ @DeclarationTextMacro()
+ void foo(int a, [String? b]) {}
+}
+''', r'''
+foo
+ flags: hasBody
+ positionalParameters
+ a
+ flags: isRequired
+ type: int
+ b
+ type: String?
+ returnType: void
+''');
+ }
+
+ test_class_methodDeclaration_setter() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+abstract class A {
+ @DeclarationTextMacro()
+ set foo(int value) {}
+}
+''', r'''
+foo
+ flags: hasBody isSetter
+ positionalParameters
+ value
+ flags: isRequired
+ type: int
+ returnType: OmittedType
+''');
+ }
+
test_classDeclaration_interfaces() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A implements B, C<int, String> {}
''', r'''
class A
@@ -1425,6 +1533,7 @@
test_classDeclaration_isAbstract() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
abstract class A {}
''', r'''
abstract class A
@@ -1433,6 +1542,7 @@
test_classDeclaration_mixins() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A with B, C<int, String> {}
''', r'''
class A
@@ -1444,6 +1554,7 @@
test_classDeclaration_superclass() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A extends B {}
''', r'''
class A
@@ -1453,6 +1564,7 @@
test_classDeclaration_superclass_nullable() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A extends B<int?> {}
''', r'''
class A
@@ -1462,6 +1574,7 @@
test_classDeclaration_superclass_typeArguments() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A extends B<String, List<int>> {}
''', r'''
class A
@@ -1471,6 +1584,7 @@
test_classDeclaration_typeParameters() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A<T, U extends List<T>> {}
''', r'''
class A
@@ -1483,6 +1597,7 @@
test_functionTypeAnnotation_formalParameters_namedOptional_simpleFormalParameter() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A extends B<void Function(int a, {int? b, int? c})> {}
''', r'''
class A
@@ -1492,6 +1607,7 @@
test_functionTypeAnnotation_formalParameters_namedRequired_simpleFormalParameter() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A extends B<void Function(int a, {required int b, required int c})> {}
''', r'''
class A
@@ -1501,6 +1617,7 @@
test_functionTypeAnnotation_formalParameters_positionalOptional_simpleFormalParameter() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A extends B<void Function(int a, [int b, int c])> {}
''', r'''
class A
@@ -1511,6 +1628,7 @@
/// TODO(scheglov) Tests for unnamed positional formal parameters.
test_functionTypeAnnotation_formalParameters_positionalRequired_simpleFormalParameter() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A extends B<void Function(int a, double b)> {}
''', r'''
class A
@@ -1520,6 +1638,7 @@
test_functionTypeAnnotation_nullable() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A extends B<void Function()?> {}
''', r'''
class A
@@ -1529,6 +1648,7 @@
test_functionTypeAnnotation_returnType() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A extends B<void Function()> {}
''', r'''
class A
@@ -1538,6 +1658,7 @@
test_functionTypeAnnotation_returnType_omitted() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A extends B<Function()> {}
''', r'''
class A
@@ -1547,6 +1668,7 @@
test_functionTypeAnnotation_typeParameters() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A extends B<void Function<T, U extends num>()> {}
''', r'''
class A
@@ -1556,6 +1678,7 @@
test_namedTypeAnnotation_prefixed() async {
await _assertTypesPhaseIntrospectionText(r'''
+@DeclarationTextMacro()
class A extends prefix.B {}
''', r'''
class A
@@ -1597,7 +1720,6 @@
var library = await buildLibrary('''
import 'declaration_text.dart';
-@DeclarationTextMacro()
$declarationCode
''');