Skip to content

Commit

Permalink
[macros] Add DiagnosticException that macro implementations can thr…
Browse files Browse the repository at this point in the history
…ow 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]>
  • Loading branch information
davidmorgan authored and Commit Queue committed Feb 6, 2024
1 parent f4b1d59 commit f367d1e
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 6 deletions.
8 changes: 8 additions & 0 deletions pkg/_fe_analyzer_shared/lib/src/macros/api/exceptions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@

part of '../api.dart';

/// Exception for use in macro implementations.
///
/// Throw to stop the current macro execution and report a [Diagnostic].
class DiagnosticException implements Exception {
final Diagnostic diagnostic;
DiagnosticException(this.diagnostic);
}

/// Base class for exceptions thrown by the host implementation during macro
/// execution.
///
Expand Down
18 changes: 12 additions & 6 deletions pkg/_fe_analyzer_shared/lib/src/macros/executor/execute_macro.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ Future<MacroExecutionResult> executeTypesMacro(
'macro: $macro\ntarget: $target');
}
} catch (e, s) {
// Preserve `MacroException`s thrown by SDK tools.
if (e is MacroExceptionImpl) {
if (e is DiagnosticException) {
builder.report(e.diagnostic);
} else if (e is MacroExceptionImpl) {
// Preserve `MacroException`s thrown by SDK tools.
builder.failWithException(e);
} else {
// Convert exceptions thrown by macro implementations into diagnostics.
Expand Down Expand Up @@ -137,8 +139,10 @@ Future<MacroExecutionResult> executeDeclarationsMacro(Macro macro,
'macro: $macro\ntarget: $target');
}
} catch (e, s) {
// Preserve `MacroException`s thrown by SDK tools.
if (e is MacroExceptionImpl) {
if (e is DiagnosticException) {
builder.report(e.diagnostic);
} else if (e is MacroExceptionImpl) {
// Preserve `MacroException`s thrown by SDK tools.
builder.failWithException(e);
} else {
// Convert exceptions thrown by macro implementations into diagnostics.
Expand Down Expand Up @@ -212,8 +216,10 @@ Future<MacroExecutionResult> executeDefinitionMacro(Macro macro, Object target,
'macro: $macro\ntarget: $target');
}
} catch (e, s) {
// Preserve `MacroException`s thrown by SDK tools.
if (e is MacroExceptionImpl) {
if (e is DiagnosticException) {
builder.report(e.diagnostic);
} else if (e is MacroExceptionImpl) {
// Preserve `MacroException`s thrown by SDK tools.
builder.failWithException(e);
} else {
// Convert exceptions thrown by macro implementations into diagnostics.
Expand Down
14 changes: 14 additions & 0 deletions tests/language/macros/error/diagnostic_exception_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) 2024, 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/throw_diagnostic_exception_macro.dart';

@ThrowDiagnosticException(atTypeDeclaration: 'B', withMessage: 'failed here')
class A {}

class B {}
// ^
// [analyzer] COMPILE_TIME_ERROR.MACRO_ERROR
// [cfe] failed here
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2024, 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 'package:_fe_analyzer_shared/src/macros/api.dart';

macro class ThrowDiagnosticException implements ClassDeclarationsMacro {
final String atTypeDeclaration;
final String withMessage;

const ThrowDiagnosticException({
required this.atTypeDeclaration, required this.withMessage});

Future<void> buildDeclarationsForClass(
ClassDeclaration clazz, MemberDeclarationBuilder builder) async {
final identifier = await builder.resolveIdentifier(clazz.library.uri, atTypeDeclaration);
final declaration = await builder.typeDeclarationOf(identifier);
throw DiagnosticException(Diagnostic(DiagnosticMessage(
withMessage, target: declaration.asDiagnosticTarget), Severity.error));
}
}

0 comments on commit f367d1e

Please sign in to comment.