Skip to content

Commit f367d1e

Browse files
davidmorganCommit Queue
authored andcommitted
[macros] Add DiagnosticException that macro implementations can throw to report a diagnostic.
[email protected] Change-Id: I7546aa84f3e0b8423465dcb49d90a89df9231b84 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/350302 Reviewed-by: Konstantin Shcheglov <[email protected]> Auto-Submit: Morgan :) <[email protected]> Reviewed-by: Jake Macdonald <[email protected]> Commit-Queue: Morgan :) <[email protected]>
1 parent f4b1d59 commit f367d1e

File tree

4 files changed

+55
-6
lines changed

4 files changed

+55
-6
lines changed

pkg/_fe_analyzer_shared/lib/src/macros/api/exceptions.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44

55
part of '../api.dart';
66

7+
/// Exception for use in macro implementations.
8+
///
9+
/// Throw to stop the current macro execution and report a [Diagnostic].
10+
class DiagnosticException implements Exception {
11+
final Diagnostic diagnostic;
12+
DiagnosticException(this.diagnostic);
13+
}
14+
715
/// Base class for exceptions thrown by the host implementation during macro
816
/// execution.
917
///

pkg/_fe_analyzer_shared/lib/src/macros/executor/execute_macro.dart

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ Future<MacroExecutionResult> executeTypesMacro(
5959
'macro: $macro\ntarget: $target');
6060
}
6161
} catch (e, s) {
62-
// Preserve `MacroException`s thrown by SDK tools.
63-
if (e is MacroExceptionImpl) {
62+
if (e is DiagnosticException) {
63+
builder.report(e.diagnostic);
64+
} else if (e is MacroExceptionImpl) {
65+
// Preserve `MacroException`s thrown by SDK tools.
6466
builder.failWithException(e);
6567
} else {
6668
// Convert exceptions thrown by macro implementations into diagnostics.
@@ -137,8 +139,10 @@ Future<MacroExecutionResult> executeDeclarationsMacro(Macro macro,
137139
'macro: $macro\ntarget: $target');
138140
}
139141
} catch (e, s) {
140-
// Preserve `MacroException`s thrown by SDK tools.
141-
if (e is MacroExceptionImpl) {
142+
if (e is DiagnosticException) {
143+
builder.report(e.diagnostic);
144+
} else if (e is MacroExceptionImpl) {
145+
// Preserve `MacroException`s thrown by SDK tools.
142146
builder.failWithException(e);
143147
} else {
144148
// Convert exceptions thrown by macro implementations into diagnostics.
@@ -212,8 +216,10 @@ Future<MacroExecutionResult> executeDefinitionMacro(Macro macro, Object target,
212216
'macro: $macro\ntarget: $target');
213217
}
214218
} catch (e, s) {
215-
// Preserve `MacroException`s thrown by SDK tools.
216-
if (e is MacroExceptionImpl) {
219+
if (e is DiagnosticException) {
220+
builder.report(e.diagnostic);
221+
} else if (e is MacroExceptionImpl) {
222+
// Preserve `MacroException`s thrown by SDK tools.
217223
builder.failWithException(e);
218224
} else {
219225
// Convert exceptions thrown by macro implementations into diagnostics.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
// SharedOptions=--enable-experiment=macros
5+
6+
import 'impl/throw_diagnostic_exception_macro.dart';
7+
8+
@ThrowDiagnosticException(atTypeDeclaration: 'B', withMessage: 'failed here')
9+
class A {}
10+
11+
class B {}
12+
// ^
13+
// [analyzer] COMPILE_TIME_ERROR.MACRO_ERROR
14+
// [cfe] failed here
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
// ignore_for_file: deprecated_member_use
5+
import 'package:_fe_analyzer_shared/src/macros/api.dart';
6+
7+
macro class ThrowDiagnosticException implements ClassDeclarationsMacro {
8+
final String atTypeDeclaration;
9+
final String withMessage;
10+
11+
const ThrowDiagnosticException({
12+
required this.atTypeDeclaration, required this.withMessage});
13+
14+
Future<void> buildDeclarationsForClass(
15+
ClassDeclaration clazz, MemberDeclarationBuilder builder) async {
16+
final identifier = await builder.resolveIdentifier(clazz.library.uri, atTypeDeclaration);
17+
final declaration = await builder.typeDeclarationOf(identifier);
18+
throw DiagnosticException(Diagnostic(DiagnosticMessage(
19+
withMessage, target: declaration.asDiagnosticTarget), Severity.error));
20+
}
21+
}

0 commit comments

Comments
 (0)