Build FunctionTypeAnnotation(s) for macros.
Change-Id: Ia18c132cb05c4a9cd1df569bb65202a8f1379596
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/241801
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/summary2/macro_application.dart b/pkg/analyzer/lib/src/summary2/macro_application.dart
index 9f618ae..3cfe128 100644
--- a/pkg/analyzer/lib/src/summary2/macro_application.dart
+++ b/pkg/analyzer/lib/src/summary2/macro_application.dart
@@ -172,6 +172,30 @@
);
}
+ static macro.ParameterDeclarationImpl _buildFormalParameter(
+ FormalParameter node,
+ ) {
+ if (node is DefaultFormalParameter) {
+ node = node.parameter;
+ }
+
+ final macro.TypeAnnotationImpl typeAnnotation;
+ if (node is SimpleFormalParameter) {
+ typeAnnotation = _buildTypeAnnotation(node.type);
+ } else {
+ throw UnimplementedError('(${node.runtimeType}) $node');
+ }
+
+ return macro.ParameterDeclarationImpl(
+ id: macro.RemoteInstance.uniqueId,
+ identifier:
+ _buildIdentifier(node.identifier!), // TODO(scheglov) might be null
+ isNamed: node.isNamed,
+ isRequired: node.isRequired,
+ type: typeAnnotation,
+ );
+ }
+
static macro.IdentifierImpl _buildIdentifier(Identifier node) {
final String name;
if (node is SimpleIdentifier) {
@@ -185,8 +209,27 @@
);
}
- static macro.TypeAnnotationImpl _buildTypeAnnotation(TypeAnnotation node) {
- if (node is NamedType) {
+ static macro.TypeAnnotationImpl _buildTypeAnnotation(TypeAnnotation? node) {
+ if (node == null) {
+ return macro.OmittedTypeAnnotationImpl(
+ id: macro.RemoteInstance.uniqueId,
+ );
+ } else if (node is GenericFunctionType) {
+ return macro.FunctionTypeAnnotationImpl(
+ id: macro.RemoteInstance.uniqueId,
+ isNullable: node.question != null,
+ namedParameters: node.parameters.parameters
+ .where((e) => e.isNamed)
+ .map(_buildFormalParameter)
+ .toList(),
+ positionalParameters: node.parameters.parameters
+ .where((e) => e.isPositional)
+ .map(_buildFormalParameter)
+ .toList(),
+ returnType: _buildTypeAnnotation(node.returnType),
+ typeParameters: _buildTypeParameters(node.typeParameters),
+ );
+ } else if (node is NamedType) {
return macro.NamedTypeAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: _buildIdentifier(node.name),
diff --git a/pkg/analyzer/lib/src/summary2/macro_application_error.dart b/pkg/analyzer/lib/src/summary2/macro_application_error.dart
index a7b9018..de56919 100644
--- a/pkg/analyzer/lib/src/summary2/macro_application_error.dart
+++ b/pkg/analyzer/lib/src/summary2/macro_application_error.dart
@@ -33,7 +33,8 @@
@override
String toStringForTest() {
- return 'Argument(annotation: $annotationIndex, argument: $argumentIndex)';
+ return 'Argument(annotation: $annotationIndex, '
+ 'argument: $argumentIndex, message: $message)';
}
@override
@@ -118,7 +119,7 @@
@override
String toStringForTest() {
- return 'Unknown(annotation: $annotationIndex)';
+ return 'Unknown(annotation: $annotationIndex, message: $message)';
}
@override
diff --git a/pkg/analyzer/test/src/summary/macro/declaration_text.dart b/pkg/analyzer/test/src/summary/macro/declaration_text.dart
index 066c9b6..85ec1ed 100644
--- a/pkg/analyzer/test/src/summary/macro/declaration_text.dart
+++ b/pkg/analyzer/test/src/summary/macro/declaration_text.dart
@@ -131,15 +131,12 @@
_TypeStringBuilder(this._sink);
void write(TypeAnnotation type) {
- if (type is NamedTypeAnnotation) {
- _sink.write(type.identifier.name);
- _sink.writeList(
- elements: type.typeArguments,
- write: write,
- separator: ', ',
- open: '<',
- close: '>',
- );
+ if (type is FunctionTypeAnnotation) {
+ _writeFunctionTypeAnnotation(type);
+ } else if (type is NamedTypeAnnotation) {
+ _writeNamedTypeAnnotation(type);
+ } else if (type is OmittedTypeAnnotation) {
+ _sink.write('OmittedType');
} else {
throw UnimplementedError('(${type.runtimeType}) $type');
}
@@ -147,6 +144,80 @@
_sink.write('?');
}
}
+
+ void _writeFormalParameter(ParameterDeclaration node) {
+ final String closeSeparator;
+ if (node.isNamed) {
+ _sink.write('{');
+ closeSeparator = '}';
+ if (node.isRequired) {
+ _sink.write('required ');
+ }
+ } else if (!node.isRequired) {
+ _sink.write('[');
+ closeSeparator = ']';
+ } else {
+ closeSeparator = '';
+ }
+
+ write(node.type);
+ _sink.write(' ');
+ _sink.write(node.identifier.name);
+
+ _sink.write(closeSeparator);
+ }
+
+ void _writeFunctionTypeAnnotation(FunctionTypeAnnotation type) {
+ write(type.returnType);
+ _sink.write(' Function');
+
+ _sink.writeList(
+ elements: type.typeParameters,
+ write: _writeTypeParameter,
+ separator: ', ',
+ open: '<',
+ close: '>',
+ );
+
+ _sink.write('(');
+ var hasFormalParameter = false;
+ for (final formalParameter in type.positionalParameters) {
+ if (hasFormalParameter) {
+ _sink.write(', ');
+ }
+ _writeFormalParameter(formalParameter);
+ hasFormalParameter = true;
+ }
+ for (final formalParameter in type.namedParameters) {
+ if (hasFormalParameter) {
+ _sink.write(', ');
+ }
+ _writeFormalParameter(formalParameter);
+ hasFormalParameter = true;
+ }
+ _sink.write(')');
+ }
+
+ void _writeNamedTypeAnnotation(NamedTypeAnnotation type) {
+ _sink.write(type.identifier.name);
+ _sink.writeList(
+ elements: type.typeArguments,
+ write: write,
+ separator: ', ',
+ open: '<',
+ close: '>',
+ );
+ }
+
+ void _writeTypeParameter(TypeParameterDeclaration node) {
+ _sink.write(node.identifier.name);
+
+ final bound = node.bound;
+ if (bound != null) {
+ _sink.write(' extends ');
+ write(bound);
+ }
+ }
}
extension on StringSink {
@@ -158,22 +229,24 @@
String? close,
}) {
elements = elements.toList();
- if (elements.isNotEmpty) {
- if (open != null) {
- this.write(open);
+ if (elements.isEmpty) {
+ return;
+ }
+
+ if (open != null) {
+ this.write(open);
+ }
+ var isFirst = true;
+ for (var element in elements) {
+ if (isFirst) {
+ isFirst = false;
+ } else {
+ this.write(separator);
}
- var isFirst = true;
- for (var element in elements) {
- if (isFirst) {
- isFirst = false;
- } else {
- this.write(separator);
- }
- write(element);
- }
- if (close != null) {
- this.write(close);
- }
+ write(element);
+ }
+ if (close != null) {
+ this.write(close);
}
}
}
diff --git a/pkg/analyzer/test/src/summary/macro_test.dart b/pkg/analyzer/test/src/summary/macro_test.dart
index 0c3f764..c861ab4 100644
--- a/pkg/analyzer/test/src/summary/macro_test.dart
+++ b/pkg/analyzer/test/src/summary/macro_test.dart
@@ -5,6 +5,7 @@
import 'package:_fe_analyzer_shared/src/macros/executor/multi_executor.dart'
as macro;
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/summary2/kernel_compilation_service.dart';
import 'package:analyzer/src/summary2/macro.dart';
@@ -83,7 +84,8 @@
},
constructorParametersCode: '(this.foo, this.bar)',
argumentsCode: '(0, const Object())',
- expectedErrors: 'Argument(annotation: 0, argument: 1)',
+ expectedErrors: 'Argument(annotation: 0, argument: 1, '
+ 'message: Not supported: InstanceCreationExpressionImpl)',
);
}
@@ -385,6 +387,88 @@
''');
}
+ test_introspect_types_functionTypeAnnotation_formalParameters_namedOptional_simpleFormalParameter() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function(int a, {int? b, int? c})> {}
+''', r'''
+class A
+ superclass: B<void Function(int a, {int? b}, {int? c})>
+''');
+ }
+
+ test_introspect_types_functionTypeAnnotation_formalParameters_namedRequired_simpleFormalParameter() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function(int a, {required int b, required int c})> {}
+''', r'''
+class A
+ superclass: B<void Function(int a, {required int b}, {required int c})>
+''');
+ }
+
+ test_introspect_types_functionTypeAnnotation_formalParameters_positionalOptional_simpleFormalParameter() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function(int a, [int b, int c])> {}
+''', r'''
+class A
+ superclass: B<void Function(int a, [int b], [int c])>
+''');
+ }
+
+ /// TODO(scheglov) Tests for unnamed positional formal parameters.
+ test_introspect_types_functionTypeAnnotation_formalParameters_positionalRequired_simpleFormalParameter() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function(int a, double b)> {}
+''', r'''
+class A
+ superclass: B<void Function(int a, double b)>
+''');
+ }
+
+ test_introspect_types_functionTypeAnnotation_nullable() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function()?> {}
+''', r'''
+class A
+ superclass: B<void Function()?>
+''');
+ }
+
+ test_introspect_types_functionTypeAnnotation_returnType() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function()> {}
+''', r'''
+class A
+ superclass: B<void Function()>
+''');
+ }
+
+ test_introspect_types_functionTypeAnnotation_returnType_omitted() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<Function()> {}
+''', r'''
+class A
+ superclass: B<OmittedType Function()>
+''');
+ }
+
+ test_introspect_types_functionTypeAnnotation_typeParameters() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function<T, U extends num>()> {}
+''', r'''
+class A
+ superclass: B<void Function<T, U extends num>()>
+''');
+ }
+
+ test_introspect_types_namedTypeAnnotation_prefixed() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends prefix.B {}
+''', r'''
+class A
+ superclass: B
+''');
+ }
+
test_macroFlag_class() async {
var library = await buildLibrary(r'''
macro class A {}
@@ -504,6 +588,14 @@
{'package:test/arguments_text.dart'}
]);
+ final A = library.definingCompilationUnit.getType('A');
+ if (expectedErrors != null) {
+ expect(_errorsStrForClassElement(A), expectedErrors);
+ return;
+ } else {
+ _assertNoErrorsForClassElement(A);
+ }
+
if (expected != null) {
final x = library.parts.single.topLevelVariables.single;
expect(x.name, 'x');
@@ -514,13 +606,6 @@
print(actual);
}
expect(actual, expected);
- } else if (expectedErrors != null) {
- var A = library.definingCompilationUnit.getType('A');
- A as ClassElementImpl;
- expect(
- A.macroApplicationErrors.map((e) => e.toStringForTest()).join('\n'),
- expectedErrors,
- );
} else {
fail("Either 'expected' or 'expectedErrors' must be provided.");
}
@@ -561,10 +646,26 @@
{'package:test/declaration_text.dart'}
]);
+ _assertNoErrorsForClassElement(
+ library.definingCompilationUnit.getType('A'),
+ );
+
var x = library.parts.single.topLevelVariables.single;
expect(x.name, 'x');
x as ConstTopLevelVariableElementImpl;
var x_literal = x.constantInitializer as SimpleStringLiteral;
return x_literal.value;
}
+
+ static void _assertNoErrorsForClassElement(ClassElement? element) {
+ var actual = _errorsStrForClassElement(element);
+ expect(actual, isEmpty);
+ }
+
+ static String _errorsStrForClassElement(ClassElement? element) {
+ element as ClassElementImpl;
+ return element.macroApplicationErrors.map((e) {
+ return e.toStringForTest();
+ }).join('\n');
+ }
}