blob: 71d2776954a6604491f03f023d793f2fb501c8a9 [file]
// Copyright (c) 2022, 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 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../summary/macros_environment.dart';
import 'context_collection_resolution.dart';
import 'resolution.dart';
main() {
try {
MacrosEnvironment.instance;
} catch (_) {
print('Cannot initialize environment. Skip macros tests.');
return;
}
defineReflectiveSuite(() {
defineReflectiveTests(MacroResolutionTest);
});
}
@reflectiveTest
class MacroResolutionTest extends PubPackageResolutionTest {
@override
void setUp() {
super.setUp();
writeTestPackageConfig(
PackageConfigFileBuilder(),
macrosEnvironment: MacrosEnvironment.instance,
);
newFile(
'$testPackageLibPath/append.dart',
getMacroCode('append.dart'),
);
newFile(
'$testPackageLibPath/diagnostic.dart',
getMacroCode('diagnostic.dart'),
);
}
test_declareType_class() async {
await assertNoErrorsInCode(r'''
import 'append.dart';
@DeclareType('B', 'class B {}')
class A {}
void f(B b) {}
''');
}
test_diagnostic_compilesWithError() async {
newFile('$testPackageLibPath/a.dart', r'''
import 'package:_fe_analyzer_shared/src/macros/api.dart';
macro class MyMacro implements ClassTypesMacro {
const MyMacro();
buildTypesForClass(clazz, builder) {
unresolved;
}
}
''');
await assertErrorsInCode('''
import 'a.dart';
@MyMacro()
class A {}
''', [
error(
CompileTimeErrorCode.MACRO_ERROR,
18,
10,
messageContains: [
'Unhandled error',
'package:test/a.dart',
'unresolved',
'MyMacro',
],
),
]);
}
test_diagnostic_notSupportedArgument() async {
await assertErrorsInCode('''
import 'diagnostic.dart';
class A {
@ReportAtTargetDeclaration()
void foo() {}
}
''', [
error(WarningCode.MACRO_WARNING, 75, 3),
]);
}
test_diagnostic_report_atDeclaration_class_error() async {
await assertErrorsInCode('''
import 'diagnostic.dart';
@ReportErrorAtTargetDeclaration()
class A {}
''', [
error(CompileTimeErrorCode.MACRO_ERROR, 67, 1),
]);
}
test_diagnostic_report_atDeclaration_class_info() async {
await assertErrorsInCode('''
import 'diagnostic.dart';
@ReportInfoAtTargetDeclaration()
class A {}
''', [
error(HintCode.MACRO_INFO, 66, 1),
]);
}
test_diagnostic_report_atDeclaration_class_warning() async {
await assertErrorsInCode('''
import 'diagnostic.dart';
@ReportAtTargetDeclaration()
class A {}
''', [
error(WarningCode.MACRO_WARNING, 62, 1),
]);
}
test_diagnostic_report_atDeclaration_constructor() async {
await assertErrorsInCode('''
import 'diagnostic.dart';
class A {
@ReportAtTargetDeclaration()
A.named();
}
''', [
error(WarningCode.MACRO_WARNING, 72, 5),
]);
}
test_diagnostic_report_atDeclaration_field() async {
await assertErrorsInCode('''
import 'diagnostic.dart';
class A {
@ReportAtTargetDeclaration()
final foo = 0;
}
''', [
error(WarningCode.MACRO_WARNING, 76, 3),
]);
}
test_diagnostic_report_atDeclaration_method() async {
await assertErrorsInCode('''
import 'diagnostic.dart';
class A {
@ReportAtTargetDeclaration()
void foo() {}
}
''', [
error(WarningCode.MACRO_WARNING, 75, 3),
]);
}
test_diagnostic_report_atDeclaration_mixin() async {
await assertErrorsInCode('''
import 'diagnostic.dart';
@ReportAtTargetDeclaration()
mixin A {}
''', [
error(WarningCode.MACRO_WARNING, 62, 1),
]);
}
test_diagnostic_report_atTarget_method() async {
await assertErrorsInCode('''
import 'diagnostic.dart';
@ReportAtFirstMethod()
class A {
void foo() {}
void bar() {}
}
''', [
error(WarningCode.MACRO_WARNING, 67, 3),
]);
}
test_diagnostic_report_contextMessages_superClassMethods() async {
newFile('$testPackageLibPath/a.dart', r'''
class A {
void foo() {}
void bar() {}
}
''');
await assertErrorsInCode('''
import 'a.dart';
import 'diagnostic.dart';
@ReportWithContextMessages(forSuperClass: true)
class B extends A {}
''', [
error(WarningCode.MACRO_WARNING, 98, 1, contextMessages: [
message('/home/test/lib/a.dart', 17, 3),
message('/home/test/lib/a.dart', 33, 3)
]),
]);
}
test_diagnostic_report_contextMessages_thisClassMethods() async {
await assertErrorsInCode('''
import 'diagnostic.dart';
@ReportWithContextMessages()
class A {
void foo() {}
void bar() {}
}
''', [
error(WarningCode.MACRO_WARNING, 62, 1, contextMessages: [
message('/home/test/lib/test.dart', 73, 3),
message('/home/test/lib/test.dart', 89, 3)
]),
]);
}
test_diagnostic_report_contextMessages_thisClassMethods_noTarget() async {
await assertErrorsInCode('''
import 'diagnostic.dart';
@ReportWithContextMessages(withDeclarationTarget: false)
class A {
void foo() {}
void bar() {}
}
''', [
error(WarningCode.MACRO_WARNING, 27, 56, contextMessages: [
message('/home/test/lib/test.dart', 101, 3),
message('/home/test/lib/test.dart', 117, 3)
]),
]);
}
test_diagnostic_throwsException() async {
newFile('$testPackageLibPath/a.dart', r'''
import 'package:_fe_analyzer_shared/src/macros/api.dart';
macro class MyMacro implements ClassTypesMacro {
const MyMacro();
buildTypesForClass(clazz, builder) {
throw 12345;
}
}
''');
await assertErrorsInCode('''
import 'a.dart';
@MyMacro()
class A {}
''', [
error(
CompileTimeErrorCode.MACRO_ERROR,
18,
10,
messageContains: [
'Unhandled error',
'package:test/a.dart',
'12345',
'MyMacro',
],
),
]);
}
test_getResolvedLibrary_macroAugmentation_hasErrors() async {
newFile(
'$testPackageLibPath/append.dart',
getMacroCode('append.dart'),
);
newFile('$testPackageLibPath/test.dart', r'''
import 'append.dart';
@DeclareInType(' NotType foo() {}')
class A {}
''');
final session = contextFor(testFile).currentSession;
final result = await session.getResolvedLibrary(testFile.path);
// 1. Has the macro augmentation unit.
// 2. It has an error reported.
assertResolvedLibraryResultText(result, configure: (configuration) {
configuration.unitConfiguration
..nodeSelector = (unitResult) {
if (unitResult.isMacroAugmentation) {
return unitResult.findNode.namedType('NotType');
}
return null;
}
..withContentPredicate = (unitResult) {
return unitResult.isAugmentation;
};
}, r'''
ResolvedLibraryResult
element: package:test/test.dart
units
/home/test/lib/test.dart
flags: exists isLibrary
uri: package:test/test.dart
/home/test/lib/test.macro.dart
flags: exists isAugmentation isMacroAugmentation
uri: package:test/test.macro.dart
content
---
library augment 'test.dart';
augment class A {
NotType foo() {}
}
---
errors
50 +7 UNDEFINED_CLASS
selectedNode: NamedType
name: NotType
element: <null>
type: InvalidType
''');
}
}