mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 16:59:47 +00:00
[macros] Add first language tests for introspection.
R=jakemac@google.com Change-Id: Ic6e081a0a97f23c35b90bc3d935d3c97f4ec5bcd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/341963 Reviewed-by: Jake Macdonald <jakemac@google.com> Auto-Submit: Morgan :) <davidmorgan@google.com> Commit-Queue: Morgan :) <davidmorgan@google.com>
This commit is contained in:
parent
3eeba4a4e2
commit
12c548d331
8
tests/language/macros/introspect/README.md
Normal file
8
tests/language/macros/introspect/README.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Macro "Introspect" Tests
|
||||
|
||||
These tests (will) cover the "read" half of the macro API, the introspection
|
||||
of source during macro execution.
|
||||
|
||||
The macros under `impl` accept an introspection target library and type name.
|
||||
They do all the introspection possible, convert the results to primitives then
|
||||
compare with expectations also passed as an argument to the macro.
|
65
tests/language/macros/introspect/class_test.dart
Normal file
65
tests/language/macros/introspect/class_test.dart
Normal file
|
@ -0,0 +1,65 @@
|
|||
// 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.
|
||||
// SharedOptions=--enable-experiment=macros
|
||||
|
||||
import 'impl/assert_in_declarations_phase_macro.dart';
|
||||
import 'impl/assert_in_definitions_phase_macro.dart';
|
||||
import 'impl/assert_in_types_phase_macro.dart';
|
||||
|
||||
@AssertInTypesPhase(
|
||||
targetLibrary: 'dart:core',
|
||||
targetName: 'int',
|
||||
resolveIdentifier: 'int',
|
||||
)
|
||||
@AssertInDefinitionsPhase(
|
||||
targetName: 'A',
|
||||
constructorsOf: ['()', 'b()', 'c()'],
|
||||
fieldsOf: ['int d', 'String e'],
|
||||
methodsOf: ['int f()', 'String g()'],
|
||||
)
|
||||
@AssertInDeclarationsPhase(
|
||||
targetName: 'A',
|
||||
constructorsOf: ['()', 'b()', 'c()'],
|
||||
fieldsOf: ['int d', 'String e'],
|
||||
methodsOf: ['int f()', 'String g()'],
|
||||
)
|
||||
abstract class A {
|
||||
A();
|
||||
A.b();
|
||||
A.c();
|
||||
|
||||
final int d = 1;
|
||||
final String e = 'two';
|
||||
|
||||
int f();
|
||||
String g();
|
||||
}
|
||||
|
||||
abstract class B {
|
||||
B();
|
||||
B.h();
|
||||
B.i();
|
||||
|
||||
final int j = 1;
|
||||
final String k = 'two';
|
||||
|
||||
int l();
|
||||
String m();
|
||||
}
|
||||
|
||||
@AssertInDefinitionsPhase(
|
||||
targetName: 'B',
|
||||
constructorsOf: ['()', 'h()', 'i()'],
|
||||
fieldsOf: ['int j', 'String k'],
|
||||
methodsOf: ['int l()', 'String m()'],
|
||||
)
|
||||
@AssertInDeclarationsPhase(
|
||||
targetName: 'B',
|
||||
constructorsOf: ['()', 'h()', 'i()'],
|
||||
fieldsOf: ['int j', 'String k'],
|
||||
methodsOf: ['int l()', 'String m()'],
|
||||
)
|
||||
class C {}
|
||||
|
||||
void main() {}
|
34
tests/language/macros/introspect/failure_test.dart
Normal file
34
tests/language/macros/introspect/failure_test.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
// 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.
|
||||
// SharedOptions=--enable-experiment=macros
|
||||
|
||||
import 'impl/assert_in_declarations_phase_macro.dart';
|
||||
import 'impl/assert_in_definitions_phase_macro.dart';
|
||||
import 'impl/assert_in_types_phase_macro.dart';
|
||||
|
||||
// If any of the "assert" macros is broken then tests that use them might
|
||||
// pass with a false positive. This test should start failing at the same time.
|
||||
|
||||
@AssertInTypesPhase(
|
||||
// [error line 13, column 1, length 218]
|
||||
// [analyzer] COMPILE_TIME_ERROR.MACRO_ERROR
|
||||
targetLibrary: 'dart:core',
|
||||
targetName: 'int',
|
||||
resolveIdentifier: '<intentional mismatch and failure>',
|
||||
)
|
||||
@AssertInDefinitionsPhase(
|
||||
// [error line 20, column 1, length 191]
|
||||
// [analyzer] COMPILE_TIME_ERROR.MACRO_ERROR
|
||||
targetName: 'A',
|
||||
constructorsOf: ['<intentional mismatch and failure>'],
|
||||
)
|
||||
@AssertInDeclarationsPhase(
|
||||
// [error line 26, column 1, length 191]
|
||||
// [analyzer] COMPILE_TIME_ERROR.MACRO_ERROR
|
||||
targetName: 'A',
|
||||
constructorsOf: ['<intentional mismatch and failure'],
|
||||
)
|
||||
class A {}
|
||||
|
||||
// TODO(davidmorgan): add CFE error coverage.
|
|
@ -0,0 +1,57 @@
|
|||
// 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.
|
||||
// ignore_for_file: deprecated_member_use
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
import 'impl.dart';
|
||||
|
||||
macro class AssertInDeclarationsPhase
|
||||
implements ClassDeclarationsMacro {
|
||||
final String? targetLibrary;
|
||||
final String targetName;
|
||||
final List? constructorsOf;
|
||||
final List? fieldsOf;
|
||||
final List? methodsOf;
|
||||
|
||||
const AssertInDeclarationsPhase(
|
||||
{this.targetLibrary,
|
||||
required this.targetName,
|
||||
this.constructorsOf,
|
||||
this.fieldsOf,
|
||||
this.methodsOf});
|
||||
|
||||
@override
|
||||
Future<void> buildDeclarationsForClass(
|
||||
ClassDeclaration clazz, MemberDeclarationBuilder builder) =>
|
||||
_assert(clazz, builder);
|
||||
|
||||
// TODO(davidmorgan): support asserting in more places.
|
||||
|
||||
Future<void> _assert(TypeDeclaration typeDeclaration,
|
||||
DeclarationPhaseIntrospector builder) async {
|
||||
final targetIdentifier = await builder.resolveIdentifier(
|
||||
targetLibrary == null
|
||||
? typeDeclaration.library.uri
|
||||
: Uri.parse(targetLibrary!),
|
||||
targetName);
|
||||
final declaration = await builder.typeDeclarationOf(targetIdentifier);
|
||||
|
||||
if (constructorsOf != null) {
|
||||
Expect.deepEquals(
|
||||
constructorsOf, stringify(await builder.constructorsOf(declaration)));
|
||||
}
|
||||
if (fieldsOf != null) {
|
||||
Expect.deepEquals(
|
||||
fieldsOf, stringify(await builder.fieldsOf(declaration)));
|
||||
}
|
||||
if (methodsOf != null) {
|
||||
Expect.deepEquals(
|
||||
methodsOf, stringify(await builder.methodsOf(declaration)));
|
||||
}
|
||||
// TODO(davidmorgan): cover typeDeclarationsOf, typesOf, valuesOf.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
// 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.
|
||||
// ignore_for_file: deprecated_member_use
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
import 'impl.dart';
|
||||
|
||||
macro class AssertInDefinitionsPhase implements ClassDefinitionMacro {
|
||||
final String? targetLibrary;
|
||||
final String targetName;
|
||||
final List? constructorsOf;
|
||||
final List? fieldsOf;
|
||||
final List? methodsOf;
|
||||
|
||||
const AssertInDefinitionsPhase(
|
||||
{this.targetLibrary,
|
||||
required this.targetName,
|
||||
this.constructorsOf,
|
||||
this.fieldsOf,
|
||||
this.methodsOf});
|
||||
|
||||
@override
|
||||
Future<void> buildDefinitionForClass(
|
||||
ClassDeclaration clazz, TypeDefinitionBuilder builder) =>
|
||||
_assert(clazz, builder);
|
||||
|
||||
// TODO(davidmorgan): support asserting in more places.
|
||||
|
||||
Future<void> _assert(TypeDeclaration typeDeclaration,
|
||||
DefinitionPhaseIntrospector builder) async {
|
||||
final targetIdentifier = await builder.resolveIdentifier(
|
||||
targetLibrary == null
|
||||
? typeDeclaration.library.uri
|
||||
: Uri.parse(targetLibrary!),
|
||||
targetName);
|
||||
final declaration = await builder.typeDeclarationOf(targetIdentifier);
|
||||
|
||||
if (constructorsOf != null) {
|
||||
Expect.deepEquals(
|
||||
constructorsOf, stringify(await builder.constructorsOf(declaration)));
|
||||
}
|
||||
if (fieldsOf != null) {
|
||||
Expect.deepEquals(
|
||||
fieldsOf, stringify(await builder.fieldsOf(declaration)));
|
||||
}
|
||||
if (methodsOf != null) {
|
||||
Expect.deepEquals(
|
||||
methodsOf, stringify(await builder.methodsOf(declaration)));
|
||||
}
|
||||
// TODO(davidmorgan): cover typeDeclarationsOf, typesOf, valuesOf.
|
||||
// TODO(davidmorgan): cover DefinitionPhaseIntrospector methods.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// 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.
|
||||
// ignore_for_file: deprecated_member_use
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
import 'impl.dart';
|
||||
|
||||
macro class AssertInTypesPhase implements ClassTypesMacro {
|
||||
final String targetLibrary;
|
||||
final String targetName;
|
||||
final String? resolveIdentifier;
|
||||
|
||||
const AssertInTypesPhase(
|
||||
{required this.targetLibrary,
|
||||
required this.targetName,
|
||||
this.resolveIdentifier});
|
||||
|
||||
@override
|
||||
Future<void> buildTypesForClass(
|
||||
ClassDeclaration clazz, ClassTypeBuilder builder) =>
|
||||
_assert(clazz, builder);
|
||||
|
||||
// TODO(davidmorgan): support asserting in more places.
|
||||
|
||||
Future<void> _assert(
|
||||
TypeDeclaration typeDeclaration, TypePhaseIntrospector builder) async {
|
||||
if (resolveIdentifier != null) {
|
||||
Expect.deepEquals(
|
||||
resolveIdentifier,
|
||||
stringify(await builder.resolveIdentifier(
|
||||
Uri.parse(targetLibrary), targetName)));
|
||||
}
|
||||
}
|
||||
}
|
27
tests/language/macros/introspect/impl/impl.dart
Normal file
27
tests/language/macros/introspect/impl/impl.dart
Normal file
|
@ -0,0 +1,27 @@
|
|||
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||
|
||||
/// Converts an object into primitives.
|
||||
///
|
||||
/// This allows test expectations for the object to be passed to the macro
|
||||
/// application.
|
||||
///
|
||||
/// Conversion might not contain all the data in the object: there is a
|
||||
/// tradeoff, more data makes the test more precise but also more brittle.
|
||||
Object stringify(Object? object) {
|
||||
if (object is List) {
|
||||
return object.map(stringify).toList();
|
||||
} else if (object is ConstructorDeclaration) {
|
||||
return '${object.identifier.name}()';
|
||||
} else if (object is FieldDeclaration) {
|
||||
return '${stringify(object.type)} ${object.identifier.name}';
|
||||
} else if (object is Identifier) {
|
||||
return object.name;
|
||||
} else if (object is MethodDeclaration) {
|
||||
return '${stringify(object.returnType)} ${object.identifier.name}()';
|
||||
} else if (object is NamedTypeAnnotation) {
|
||||
return object.identifier.name;
|
||||
} else {
|
||||
throw new UnsupportedError('Don’t know how to stringify with type '
|
||||
'${object.runtimeType}: "$object"');
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue