Skip to content

Commit

Permalink
Macro. Include positional / named arguments for annotations.
Browse files Browse the repository at this point in the history
Follow up after https://dart-review.googlesource.com/c/sdk/+/335446

Change-Id: Ic188a29b1b034b28d8ad803108e15f87ea9c1330
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/335865
Reviewed-by: Brian Wilkerson <[email protected]>
Commit-Queue: Konstantin Shcheglov <[email protected]>
Reviewed-by: Phil Quitslund <[email protected]>
  • Loading branch information
scheglov authored and Commit Queue committed Nov 14, 2023
1 parent 6917656 commit 1306c6d
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 40 deletions.
21 changes: 17 additions & 4 deletions pkg/analyzer/lib/src/summary2/macro_declarations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,9 @@ class DeclarationBuilder {
getElement: () => identifierName.staticElement,
);

final arguments = node.arguments;
if (arguments != null) {
final argumentList = node.arguments;
if (argumentList != null) {
final arguments = argumentList.arguments;
return macro.ConstructorMetadataAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
constructor: IdentifierImplFromNode(
Expand All @@ -187,8 +188,16 @@ class DeclarationBuilder {
getElement: () => node.element,
),
type: identifierMacro,
positionalArguments: [], // TODO(scheglov) implement
namedArguments: {}, // TODO(scheglov) implement
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(
Expand All @@ -197,6 +206,10 @@ class DeclarationBuilder {
);
}
}

static macro.ExpressionCode _expressionCode(ast.Expression node) {
return macro.ExpressionCode.fromString('$node');
}
}

class DeclarationBuilderFromElement {
Expand Down
8 changes: 8 additions & 0 deletions pkg/analyzer/lib/src/utilities/extensions/collection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ extension IterableExtension<E> on Iterable<E> {
}
return result;
}

Iterable<E> whereNotType<U>() {
return whereNot((element) => element is U);
}
}

extension IterableMapEntryExtension<K, V> on Iterable<MapEntry<K, V>> {
Map<K, V> get mapFromEntries => Map.fromEntries(this);
}

extension ListExtension<E> on List<E> {
Expand Down
35 changes: 35 additions & 0 deletions pkg/analyzer/test/src/summary/macro/introspect_shared.dart
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,25 @@ abstract class SharedPrinter {
}
}

bool _shouldWriteArguments(ConstructorMetadataAnnotation annotation) {
return !const {
'IntrospectDeclarationsPhaseMacro',
'IntrospectTypesPhaseMacro',
}.contains(annotation.type.name);
}

Future<void> _writeExpressionCode(
ExpressionCode code, {
String? name,
}) async {
await sink.writeIndentedLine(() async {
if (name != null) {
sink.write('$name: ');
}
sink.write('${code.parts}');
});
}

Future<void> _writeFormalParameter(ParameterDeclaration e) async {
sink.writelnWithIndent(e.identifier.name);
await sink.withIndent(() async {
Expand Down Expand Up @@ -150,6 +169,22 @@ abstract class SharedPrinter {
if (constructorName.isNotEmpty) {
sink.writelnWithIndent('constructorName: $constructorName');
}
if (_shouldWriteArguments(e)) {
await sink.writeElements(
'positionalArguments',
e.positionalArguments,
(argument) async {
await _writeExpressionCode(argument);
},
);
await sink.writeElements(
'namedArguments',
e.namedArguments.entries,
(entry) async {
await _writeExpressionCode(name: entry.key, entry.value);
},
);
}
});
case IdentifierMetadataAnnotation():
sink.writelnWithIndent('IdentifierMetadataAnnotation');
Expand Down
104 changes: 68 additions & 36 deletions pkg/analyzer/test/src/summary/macro_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1931,11 +1931,10 @@ class X
test_element_class_metadata_constructor_named() async {
newFile('$testPackageLibPath/a.dart', r'''
class A {
final int f;
const A.named(this.f)
const A.named()
}
@A.named(42)
@A.named()
class B {}
''');

Expand Down Expand Up @@ -1965,15 +1964,14 @@ class X
test_element_class_metadata_constructor_named_imported() async {
newFile('$testPackageLibPath/a.dart', r'''
class A {
final int f;
const A.named(this.f)
const A.named()
}
''');

newFile('$testPackageLibPath/b.dart', r'''
import 'a.dart';
@A.named(42)
@A.named()
class B {}
''');

Expand Down Expand Up @@ -2003,15 +2001,14 @@ class X
test_element_class_metadata_constructor_named_imported_withPrefix() async {
newFile('$testPackageLibPath/a.dart', r'''
class A {
final int f;
const A.named(this.f)
const A.named()
}
''');

newFile('$testPackageLibPath/b.dart', r'''
import 'a.dart' as prefix;
@prefix.A.named(42)
@prefix.A.named()
class B {}
''');

Expand Down Expand Up @@ -2041,11 +2038,10 @@ class X
test_element_class_metadata_constructor_unnamed() async {
newFile('$testPackageLibPath/a.dart', r'''
class A {
final int f;
const A(this.f)
const A()
}
@A(42)
@A()
class B {}
''');

Expand Down Expand Up @@ -2074,15 +2070,14 @@ class X
test_element_class_metadata_constructor_unnamed_imported() async {
newFile('$testPackageLibPath/a.dart', r'''
class A {
final int f;
const A(this.f)
const A()
}
''');

newFile('$testPackageLibPath/b.dart', r'''
import 'a.dart';
@A(42)
@A()
class B {}
''');

Expand Down Expand Up @@ -2111,15 +2106,14 @@ class X
test_element_class_metadata_constructor_unnamed_imported_withPrefix() async {
newFile('$testPackageLibPath/a.dart', r'''
class A {
final int f;
const A(this.f)
const A()
}
''');

newFile('$testPackageLibPath/b.dart', r'''
import 'a.dart' as prefix;
@prefix.A(42)
@prefix.A()
class B {}
''');

Expand Down Expand Up @@ -4225,12 +4219,11 @@ class A
test_class_metadata_constructor_named() async {
await _assertIntrospectText(r'''
@IntrospectTypesPhaseMacro(withMetadata: true)
@A.named(42)
@A.named()
class X {}
class A {
final int f;
const A.named(this.f)
const A.named()
}
''', r'''
class X
Expand All @@ -4246,16 +4239,15 @@ class X
test_class_metadata_constructor_named_imported() async {
newFile('$testPackageLibPath/a.dart', r'''
class A {
final int f;
const A.named(this.f)
const A.named()
}
''');

await _assertIntrospectText(r'''
import 'a.dart';
@IntrospectTypesPhaseMacro(withMetadata: true)
@A.named(42)
@A.named()
class X {}
''', r'''
Expand All @@ -4272,16 +4264,15 @@ class X
test_class_metadata_constructor_named_imported_withPrefix() async {
newFile('$testPackageLibPath/a.dart', r'''
class A {
final int f;
const A.named(this.f)
const A.named()
}
''');

await _assertIntrospectText(r'''
import 'a.dart' as prefix;
@IntrospectTypesPhaseMacro(withMetadata: true)
@prefix.A.named(42)
@prefix.A.named()
class X {}
''', r'''
Expand All @@ -4295,15 +4286,58 @@ class X
''');
}

test_class_metadata_constructor_namedArguments() async {
await _assertIntrospectText(r'''
@IntrospectTypesPhaseMacro(withMetadata: true)
@A(a: 42, b: 'foo')
class X {}
class A {
const A({int? a, String? b});
}
''', r'''
class X
metadata
ConstructorMetadataAnnotation
type: IntrospectTypesPhaseMacro
ConstructorMetadataAnnotation
type: A
namedArguments
a: [42]
b: ['foo']
''');
}

test_class_metadata_constructor_positionalArguments() async {
await _assertIntrospectText(r'''
@IntrospectTypesPhaseMacro(withMetadata: true)
@A(42, 'foo')
class X {}
class A {
const A(int a, String b);
}
''', r'''
class X
metadata
ConstructorMetadataAnnotation
type: IntrospectTypesPhaseMacro
ConstructorMetadataAnnotation
type: A
positionalArguments
[42]
['foo']
''');
}

test_class_metadata_constructor_unnamed() async {
await _assertIntrospectText(r'''
@IntrospectTypesPhaseMacro(withMetadata: true)
@A(42)
@A()
class X {}
class A {
final int f;
const A(this.f)
const A()
}
''', r'''
class X
Expand All @@ -4318,16 +4352,15 @@ class X
test_class_metadata_constructor_unnamed_imported() async {
newFile('$testPackageLibPath/a.dart', r'''
class A {
final int f;
const A(this.f)
const A()
}
''');

await _assertIntrospectText(r'''
import 'a.dart';
@IntrospectTypesPhaseMacro(withMetadata: true)
@A(42)
@A()
class X {}
''', r'''
Expand All @@ -4343,16 +4376,15 @@ class X
test_class_metadata_constructor_unnamed_imported_withPrefix() async {
newFile('$testPackageLibPath/a.dart', r'''
class A {
final int f;
const A(this.f)
const A()
}
''');

await _assertIntrospectText(r'''
import 'a.dart' as prefix;
@IntrospectTypesPhaseMacro(withMetadata: true)
@prefix.A(42)
@prefix.A()
class X {}
''', r'''
Expand Down
17 changes: 17 additions & 0 deletions pkg/analyzer/test/src/utilities/extensions/collection_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,27 @@ import 'package:test_reflective_loader/test_reflective_loader.dart';

main() {
defineReflectiveSuite(() {
defineReflectiveTests(IterableExtensionTest);
defineReflectiveTests(IterableMapEntryExtensionTest);
defineReflectiveTests(ListExtensionTest);
});
}

@reflectiveTest
class IterableExtensionTest {
test_whereNotType() {
expect(<Object>['0', 1, '2'].whereNotType<int>(), ['0', '2']);
}
}

@reflectiveTest
class IterableMapEntryExtensionTest {
test_mapFromEntries() {
final entries = [MapEntry('foo', 0), MapEntry('bar', 1)];
expect(entries.mapFromEntries, {'foo': 0, 'bar': 1});
}
}

@reflectiveTest
class ListExtensionTest {
test_addIfNotNull_notNull() {
Expand Down

0 comments on commit 1306c6d

Please sign in to comment.