mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 21:01:20 +00:00
add Builder.report method and Diagnostic class to support macros sending diagnostics
Will follow up with tests once we agree on the API. At the same time I will handle translating any normal runtime errors into error diagnostics. Bug: https://github.com/dart-lang/language/issues/3234 Change-Id: I2fc22af088f0e50b1877022aa793337850257804 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/317221 Commit-Queue: Jake Macdonald <jakemac@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
6a2c9cb826
commit
abc7a21679
|
@ -3,8 +3,10 @@
|
||||||
// BSD-style license that can be found in the LICENSE file.
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:collection' show UnmodifiableListView;
|
||||||
|
|
||||||
part 'api/builders.dart';
|
part 'api/builders.dart';
|
||||||
part 'api/code.dart';
|
part 'api/code.dart';
|
||||||
|
part 'api/diagnostic.dart';
|
||||||
part 'api/introspection.dart';
|
part 'api/introspection.dart';
|
||||||
part 'api/macros.dart';
|
part 'api/macros.dart';
|
||||||
|
|
|
@ -6,7 +6,15 @@ part of '../api.dart';
|
||||||
|
|
||||||
/// The base interface used to add declarations to the program as well
|
/// The base interface used to add declarations to the program as well
|
||||||
/// as augment existing ones.
|
/// as augment existing ones.
|
||||||
abstract interface class Builder {}
|
///
|
||||||
|
/// Can also be used to emit diagnostic messages back to the parent tool.
|
||||||
|
abstract interface class Builder {
|
||||||
|
/// Attaches [diagnostic] to the result of this macro application phase.
|
||||||
|
///
|
||||||
|
/// Note that this will not immediately send the result, these will all be
|
||||||
|
/// collected and reported at once when the macro completes this phase.
|
||||||
|
void report(Diagnostic diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
/// The interface for all introspection that is allowed during the type phase
|
/// The interface for all introspection that is allowed during the type phase
|
||||||
/// (and later).
|
/// (and later).
|
||||||
|
|
96
pkg/_fe_analyzer_shared/lib/src/macros/api/diagnostic.dart
Normal file
96
pkg/_fe_analyzer_shared/lib/src/macros/api/diagnostic.dart
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
part of '../api.dart';
|
||||||
|
|
||||||
|
/// A diagnostic reported from a [Macro].
|
||||||
|
class Diagnostic {
|
||||||
|
/// Additional [DiagnosticMessage]s related to this one, to help with the
|
||||||
|
/// context.
|
||||||
|
final Iterable<DiagnosticMessage> contextMessages;
|
||||||
|
|
||||||
|
/// An optional message describing to the user how they might fix this
|
||||||
|
/// diagnostic.
|
||||||
|
final String? correctionMessage;
|
||||||
|
|
||||||
|
/// The primary message for this diagnostic.
|
||||||
|
final DiagnosticMessage message;
|
||||||
|
|
||||||
|
/// The severity of this diagnostic.
|
||||||
|
final Severity severity;
|
||||||
|
|
||||||
|
/// General diagnostics for the current macro application.
|
||||||
|
///
|
||||||
|
/// These will be attached to the macro application itself.
|
||||||
|
Diagnostic(this.message, this.severity,
|
||||||
|
{List<DiagnosticMessage> contextMessages = const [],
|
||||||
|
this.correctionMessage})
|
||||||
|
: contextMessages = new UnmodifiableListView(contextMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A message and optional target for a [Diagnostic] reported by a [Macro].
|
||||||
|
class DiagnosticMessage {
|
||||||
|
/// The primary message for this diagnostic message.
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
/// The optional target for this diagnostic message.
|
||||||
|
///
|
||||||
|
/// If provided, the diagnostic should be linked to this target.
|
||||||
|
///
|
||||||
|
/// If not provided, it should be implicitly linked to the macro application
|
||||||
|
/// that generated this diagnostic.
|
||||||
|
final DiagnosticTarget? target;
|
||||||
|
|
||||||
|
DiagnosticMessage(this.message, {this.target});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A target for a [DiagnosticMessage]. We use a sealed class to represent a
|
||||||
|
/// union type of the valid target types.
|
||||||
|
sealed class DiagnosticTarget {}
|
||||||
|
|
||||||
|
/// A [DiagnosticMessage] target which is a [Declaration].
|
||||||
|
final class DeclarationDiagnosticTarget extends DiagnosticTarget {
|
||||||
|
final Declaration declaration;
|
||||||
|
|
||||||
|
DeclarationDiagnosticTarget(this.declaration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A simplified way of creating a [DiagnosticTarget] target for a
|
||||||
|
/// [Declaration].
|
||||||
|
extension DeclarationAsTarget on Declaration {
|
||||||
|
DeclarationDiagnosticTarget get asDiagnosticTarget =>
|
||||||
|
new DeclarationDiagnosticTarget(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [DiagnosticMessage] target which is a [TypeAnnotation].
|
||||||
|
final class TypeAnnotationDiagnosticTarget extends DiagnosticTarget {
|
||||||
|
final TypeAnnotation typeAnnotation;
|
||||||
|
|
||||||
|
TypeAnnotationDiagnosticTarget(this.typeAnnotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A simplified way of creating a [DiagnosticTarget] target for a
|
||||||
|
/// [TypeAnnotation].
|
||||||
|
extension TypeAnnotationAsTarget on TypeAnnotation {
|
||||||
|
TypeAnnotationDiagnosticTarget get asDiagnosticTarget =>
|
||||||
|
new TypeAnnotationDiagnosticTarget(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The severities supported for [Diagnostic]s.
|
||||||
|
enum Severity {
|
||||||
|
/// Informational message only, for example a style guideline is not being
|
||||||
|
/// followed. These may not always be shown to the user depending on how the
|
||||||
|
/// app is being compiled and with what flags.
|
||||||
|
info,
|
||||||
|
|
||||||
|
/// Not a critical failure, but something is likely wrong and the code should
|
||||||
|
/// be changed. Always shown to the user by default, but may be silenceable by
|
||||||
|
/// some tools.
|
||||||
|
warning,
|
||||||
|
|
||||||
|
/// Critical failure, the macro could not proceed. Cannot be silenced and will
|
||||||
|
/// always prevent the app from compiling successfully. These are always shown
|
||||||
|
/// to the user and cannot be silenced.
|
||||||
|
error,
|
||||||
|
}
|
|
@ -155,6 +155,9 @@ abstract class MacroInstanceIdentifier implements Serializable {
|
||||||
/// All modifications are expressed in terms of library augmentation
|
/// All modifications are expressed in terms of library augmentation
|
||||||
/// declarations.
|
/// declarations.
|
||||||
abstract class MacroExecutionResult implements Serializable {
|
abstract class MacroExecutionResult implements Serializable {
|
||||||
|
/// All [Diagnostic]s reported as a result of executing a macro.
|
||||||
|
List<Diagnostic> get diagnostics;
|
||||||
|
|
||||||
/// Any augmentations to enum values that should be applied to an enum as a
|
/// Any augmentations to enum values that should be applied to an enum as a
|
||||||
/// result of executing a macro, indexed by the identifier of the enum.
|
/// result of executing a macro, indexed by the identifier of the enum.
|
||||||
Map<Identifier, Iterable<DeclarationCode>> get enumValueAugmentations;
|
Map<Identifier, Iterable<DeclarationCode>> get enumValueAugmentations;
|
||||||
|
|
|
@ -10,7 +10,10 @@ import '../executor.dart';
|
||||||
import '../api.dart';
|
import '../api.dart';
|
||||||
import 'response_impls.dart';
|
import 'response_impls.dart';
|
||||||
|
|
||||||
abstract class TypeBuilderBase implements TypePhaseIntrospector {
|
abstract class TypeBuilderBase implements TypePhaseIntrospector, Builder {
|
||||||
|
/// All the collected diagnostics for this builder.
|
||||||
|
final List<Diagnostic> _diagnostics = [];
|
||||||
|
|
||||||
/// All the enum values to be added, indexed by the identifier for the
|
/// All the enum values to be added, indexed by the identifier for the
|
||||||
/// augmented enum declaration.
|
/// augmented enum declaration.
|
||||||
final Map<IdentifierImpl, List<DeclarationCode>> _enumValueAugmentations;
|
final Map<IdentifierImpl, List<DeclarationCode>> _enumValueAugmentations;
|
||||||
|
@ -38,6 +41,7 @@ abstract class TypeBuilderBase implements TypePhaseIntrospector {
|
||||||
/// Creates and returns a [MacroExecutionResult] out of the [_augmentations]
|
/// Creates and returns a [MacroExecutionResult] out of the [_augmentations]
|
||||||
/// created by this builder.
|
/// created by this builder.
|
||||||
MacroExecutionResult get result => new MacroExecutionResultImpl(
|
MacroExecutionResult get result => new MacroExecutionResultImpl(
|
||||||
|
diagnostics: _diagnostics,
|
||||||
enumValueAugmentations: _enumValueAugmentations,
|
enumValueAugmentations: _enumValueAugmentations,
|
||||||
interfaceAugmentations: _interfaceAugmentations,
|
interfaceAugmentations: _interfaceAugmentations,
|
||||||
libraryAugmentations: _libraryAugmentations,
|
libraryAugmentations: _libraryAugmentations,
|
||||||
|
@ -58,6 +62,9 @@ abstract class TypeBuilderBase implements TypePhaseIntrospector {
|
||||||
_mixinAugmentations = parentMixinAugmentations ?? {},
|
_mixinAugmentations = parentMixinAugmentations ?? {},
|
||||||
_typeAugmentations = parentTypeAugmentations ?? {};
|
_typeAugmentations = parentTypeAugmentations ?? {};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void report(Diagnostic diagnostic) => _diagnostics.add(diagnostic);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Identifier> resolveIdentifier(Uri library, String identifier) =>
|
Future<Identifier> resolveIdentifier(Uri library, String identifier) =>
|
||||||
// ignore: deprecated_member_use_from_same_package
|
// ignore: deprecated_member_use_from_same_package
|
||||||
|
|
|
@ -10,47 +10,55 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||||
/// Runs [macro] in the types phase and returns a [MacroExecutionResult].
|
/// Runs [macro] in the types phase and returns a [MacroExecutionResult].
|
||||||
Future<MacroExecutionResult> executeTypesMacro(
|
Future<MacroExecutionResult> executeTypesMacro(
|
||||||
Macro macro, Object target, TypePhaseIntrospector introspector) async {
|
Macro macro, Object target, TypePhaseIntrospector introspector) async {
|
||||||
// This must be assigned by the end.
|
// Must be assigned, used for error reporting.
|
||||||
late final TypeBuilderImpl builder;
|
late final TypeBuilderBase builder;
|
||||||
|
|
||||||
// Shared code for most branches. If we do create it, assign it to `builder`.
|
// TODO(jakemac): More robust handling for unawaited async errors?
|
||||||
late final TypeBuilderImpl typeBuilder =
|
try {
|
||||||
builder = new TypeBuilderImpl(introspector);
|
// Shared code for most branches. If we do create it, assign it to
|
||||||
switch ((target, macro)) {
|
// `builder`.
|
||||||
case (Library target, LibraryTypesMacro macro):
|
late final TypeBuilderImpl typeBuilder =
|
||||||
await macro.buildTypesForLibrary(target, typeBuilder);
|
builder = new TypeBuilderImpl(introspector);
|
||||||
case (ConstructorDeclaration target, ConstructorTypesMacro macro):
|
switch ((target, macro)) {
|
||||||
await macro.buildTypesForConstructor(target, typeBuilder);
|
case (Library target, LibraryTypesMacro macro):
|
||||||
case (MethodDeclaration target, MethodTypesMacro macro):
|
await macro.buildTypesForLibrary(target, typeBuilder);
|
||||||
await macro.buildTypesForMethod(target, typeBuilder);
|
case (ConstructorDeclaration target, ConstructorTypesMacro macro):
|
||||||
case (FunctionDeclaration target, FunctionTypesMacro macro):
|
await macro.buildTypesForConstructor(target, typeBuilder);
|
||||||
await macro.buildTypesForFunction(target, typeBuilder);
|
case (MethodDeclaration target, MethodTypesMacro macro):
|
||||||
case (FieldDeclaration target, FieldTypesMacro macro):
|
await macro.buildTypesForMethod(target, typeBuilder);
|
||||||
await macro.buildTypesForField(target, typeBuilder);
|
case (FunctionDeclaration target, FunctionTypesMacro macro):
|
||||||
case (VariableDeclaration target, VariableTypesMacro macro):
|
await macro.buildTypesForFunction(target, typeBuilder);
|
||||||
await macro.buildTypesForVariable(target, typeBuilder);
|
case (FieldDeclaration target, FieldTypesMacro macro):
|
||||||
case (ClassDeclaration target, ClassTypesMacro macro):
|
await macro.buildTypesForField(target, typeBuilder);
|
||||||
await macro.buildTypesForClass(
|
case (VariableDeclaration target, VariableTypesMacro macro):
|
||||||
target,
|
await macro.buildTypesForVariable(target, typeBuilder);
|
||||||
builder = new ClassTypeBuilderImpl(
|
case (ClassDeclaration target, ClassTypesMacro macro):
|
||||||
target.identifier as IdentifierImpl, introspector));
|
await macro.buildTypesForClass(
|
||||||
case (EnumDeclaration target, EnumTypesMacro macro):
|
target,
|
||||||
await macro.buildTypesForEnum(
|
builder = new ClassTypeBuilderImpl(
|
||||||
target,
|
target.identifier as IdentifierImpl, introspector));
|
||||||
builder = new EnumTypeBuilderImpl(
|
case (EnumDeclaration target, EnumTypesMacro macro):
|
||||||
target.identifier as IdentifierImpl, introspector));
|
await macro.buildTypesForEnum(
|
||||||
case (ExtensionDeclaration target, ExtensionTypesMacro macro):
|
target,
|
||||||
await macro.buildTypesForExtension(target, typeBuilder);
|
builder = new EnumTypeBuilderImpl(
|
||||||
case (MixinDeclaration target, MixinTypesMacro macro):
|
target.identifier as IdentifierImpl, introspector));
|
||||||
await macro.buildTypesForMixin(
|
case (ExtensionDeclaration target, ExtensionTypesMacro macro):
|
||||||
target,
|
await macro.buildTypesForExtension(target, typeBuilder);
|
||||||
builder = new MixinTypeBuilderImpl(
|
case (MixinDeclaration target, MixinTypesMacro macro):
|
||||||
target.identifier as IdentifierImpl, introspector));
|
await macro.buildTypesForMixin(
|
||||||
case (EnumValueDeclaration target, EnumValueTypesMacro macro):
|
target,
|
||||||
await macro.buildTypesForEnumValue(target, typeBuilder);
|
builder = new MixinTypeBuilderImpl(
|
||||||
default:
|
target.identifier as IdentifierImpl, introspector));
|
||||||
throw new UnsupportedError('Unsupported macro type or invalid target:\n'
|
case (EnumValueDeclaration target, EnumValueTypesMacro macro):
|
||||||
'macro: $macro\ntarget: $target');
|
await macro.buildTypesForEnumValue(target, typeBuilder);
|
||||||
|
default:
|
||||||
|
throw new UnsupportedError('Unsupported macro type or invalid target:\n'
|
||||||
|
'macro: $macro\ntarget: $target');
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
builder.report(new Diagnostic(
|
||||||
|
new DiagnosticMessage('Unhandled error: $e\n' 'Stack trace:\n$s'),
|
||||||
|
Severity.error));
|
||||||
}
|
}
|
||||||
return builder.result;
|
return builder.result;
|
||||||
}
|
}
|
||||||
|
@ -58,9 +66,12 @@ Future<MacroExecutionResult> executeTypesMacro(
|
||||||
/// Runs [macro] in the declaration phase and returns a [MacroExecutionResult].
|
/// Runs [macro] in the declaration phase and returns a [MacroExecutionResult].
|
||||||
Future<MacroExecutionResult> executeDeclarationsMacro(Macro macro,
|
Future<MacroExecutionResult> executeDeclarationsMacro(Macro macro,
|
||||||
Object target, DeclarationPhaseIntrospector introspector) async {
|
Object target, DeclarationPhaseIntrospector introspector) async {
|
||||||
|
// Must be assigned, used for error reporting.
|
||||||
|
late final DeclarationBuilderBase builder;
|
||||||
|
|
||||||
// At most one of these will be used below.
|
// At most one of these will be used below.
|
||||||
late MemberDeclarationBuilderImpl memberBuilder =
|
late MemberDeclarationBuilderImpl memberBuilder =
|
||||||
new MemberDeclarationBuilderImpl(
|
builder = new MemberDeclarationBuilderImpl(
|
||||||
switch (target) {
|
switch (target) {
|
||||||
MemberDeclaration() => target.definingType as IdentifierImpl,
|
MemberDeclaration() => target.definingType as IdentifierImpl,
|
||||||
TypeDeclarationImpl() => target.identifier,
|
TypeDeclarationImpl() => target.identifier,
|
||||||
|
@ -70,158 +81,156 @@ Future<MacroExecutionResult> executeDeclarationsMacro(Macro macro,
|
||||||
},
|
},
|
||||||
introspector);
|
introspector);
|
||||||
late DeclarationBuilderImpl topLevelBuilder =
|
late DeclarationBuilderImpl topLevelBuilder =
|
||||||
new DeclarationBuilderImpl(introspector);
|
builder = new DeclarationBuilderImpl(introspector);
|
||||||
late EnumDeclarationBuilderImpl enumBuilder = new EnumDeclarationBuilderImpl(
|
late EnumDeclarationBuilderImpl enumBuilder =
|
||||||
switch (target) {
|
builder = new EnumDeclarationBuilderImpl(
|
||||||
EnumDeclarationImpl() => target.identifier,
|
switch (target) {
|
||||||
EnumValueDeclarationImpl() => target.definingEnum,
|
EnumDeclarationImpl() => target.identifier,
|
||||||
_ => throw new StateError(
|
EnumValueDeclarationImpl() => target.definingEnum,
|
||||||
'Can only create enum declaration builders for enum or enum '
|
_ => throw new StateError(
|
||||||
'value declarations, but got $target'),
|
'Can only create enum declaration builders for enum or enum '
|
||||||
},
|
'value declarations, but got $target'),
|
||||||
introspector);
|
},
|
||||||
|
introspector);
|
||||||
|
|
||||||
switch ((target, macro)) {
|
// TODO(jakemac): More robust handling for unawaited async errors?
|
||||||
case (Library target, LibraryDeclarationsMacro macro):
|
try {
|
||||||
await macro.buildDeclarationsForLibrary(target, topLevelBuilder);
|
switch ((target, macro)) {
|
||||||
return topLevelBuilder.result;
|
case (Library target, LibraryDeclarationsMacro macro):
|
||||||
case (ClassDeclaration target, ClassDeclarationsMacro macro):
|
await macro.buildDeclarationsForLibrary(target, topLevelBuilder);
|
||||||
if (target is! IntrospectableClassDeclarationImpl) {
|
case (ClassDeclaration target, ClassDeclarationsMacro macro):
|
||||||
throw new ArgumentError(
|
if (target is! IntrospectableClassDeclarationImpl) {
|
||||||
'Class declarations annotated with a macro should be '
|
throw new ArgumentError(
|
||||||
'introspectable in the declarations phase.');
|
'Class declarations annotated with a macro should be '
|
||||||
}
|
'introspectable in the declarations phase.');
|
||||||
await macro.buildDeclarationsForClass(target, memberBuilder);
|
}
|
||||||
return memberBuilder.result;
|
await macro.buildDeclarationsForClass(target, memberBuilder);
|
||||||
case (EnumDeclaration target, EnumDeclarationsMacro macro):
|
case (EnumDeclaration target, EnumDeclarationsMacro macro):
|
||||||
if (target is! IntrospectableEnumDeclarationImpl) {
|
if (target is! IntrospectableEnumDeclarationImpl) {
|
||||||
throw new ArgumentError(
|
throw new ArgumentError(
|
||||||
'Enum declarations annotated with a macro should be introspectable '
|
'Enum declarations annotated with a macro should be '
|
||||||
'in the declarations phase.');
|
'introspectable in the declarations phase.');
|
||||||
}
|
}
|
||||||
|
|
||||||
await macro.buildDeclarationsForEnum(target, enumBuilder);
|
await macro.buildDeclarationsForEnum(target, enumBuilder);
|
||||||
return enumBuilder.result;
|
case (ExtensionDeclaration target, ExtensionDeclarationsMacro macro):
|
||||||
case (ExtensionDeclaration target, ExtensionDeclarationsMacro macro):
|
if (target is! IntrospectableExtensionDeclarationImpl) {
|
||||||
if (target is! IntrospectableExtensionDeclarationImpl) {
|
throw new ArgumentError(
|
||||||
throw new ArgumentError(
|
'Extension declarations annotated with a macro should be '
|
||||||
'Extension declarations annotated with a macro should be '
|
'introspectable in the declarations phase.');
|
||||||
'introspectable in the declarations phase.');
|
}
|
||||||
}
|
await macro.buildDeclarationsForExtension(target, memberBuilder);
|
||||||
await macro.buildDeclarationsForExtension(target, memberBuilder);
|
case (MixinDeclaration target, MixinDeclarationsMacro macro):
|
||||||
return memberBuilder.result;
|
if (target is! IntrospectableMixinDeclarationImpl) {
|
||||||
case (MixinDeclaration target, MixinDeclarationsMacro macro):
|
throw new ArgumentError(
|
||||||
if (target is! IntrospectableMixinDeclarationImpl) {
|
'Mixin declarations annotated with a macro should be '
|
||||||
throw new ArgumentError(
|
'introspectable in the declarations phase.');
|
||||||
'Mixin declarations annotated with a macro should be '
|
}
|
||||||
'introspectable in the declarations phase.');
|
await macro.buildDeclarationsForMixin(target, memberBuilder);
|
||||||
}
|
case (EnumValueDeclaration target, EnumValueDeclarationsMacro macro):
|
||||||
await macro.buildDeclarationsForMixin(target, memberBuilder);
|
await macro.buildDeclarationsForEnumValue(target, enumBuilder);
|
||||||
return memberBuilder.result;
|
case (ConstructorDeclaration target, ConstructorDeclarationsMacro macro):
|
||||||
case (EnumValueDeclaration target, EnumValueDeclarationsMacro macro):
|
await macro.buildDeclarationsForConstructor(target, memberBuilder);
|
||||||
await macro.buildDeclarationsForEnumValue(target, enumBuilder);
|
case (MethodDeclaration target, MethodDeclarationsMacro macro):
|
||||||
return enumBuilder.result;
|
await macro.buildDeclarationsForMethod(target, memberBuilder);
|
||||||
case (ConstructorDeclaration target, ConstructorDeclarationsMacro macro):
|
case (FieldDeclaration target, FieldDeclarationsMacro macro):
|
||||||
await macro.buildDeclarationsForConstructor(target, memberBuilder);
|
await macro.buildDeclarationsForField(target, memberBuilder);
|
||||||
return memberBuilder.result;
|
case (FunctionDeclaration target, FunctionDeclarationsMacro macro):
|
||||||
case (MethodDeclaration target, MethodDeclarationsMacro macro):
|
await macro.buildDeclarationsForFunction(target, topLevelBuilder);
|
||||||
await macro.buildDeclarationsForMethod(target, memberBuilder);
|
case (VariableDeclaration target, VariableDeclarationsMacro macro):
|
||||||
return memberBuilder.result;
|
await macro.buildDeclarationsForVariable(target, topLevelBuilder);
|
||||||
case (FieldDeclaration target, FieldDeclarationsMacro macro):
|
default:
|
||||||
await macro.buildDeclarationsForField(target, memberBuilder);
|
throw new UnsupportedError('Unsupported macro type or invalid target:\n'
|
||||||
return memberBuilder.result;
|
'macro: $macro\ntarget: $target');
|
||||||
case (FunctionDeclaration target, FunctionDeclarationsMacro macro):
|
}
|
||||||
await macro.buildDeclarationsForFunction(target, topLevelBuilder);
|
} catch (e, s) {
|
||||||
return topLevelBuilder.result;
|
builder.report(new Diagnostic(
|
||||||
case (VariableDeclaration target, VariableDeclarationsMacro macro):
|
new DiagnosticMessage('Unhandled error: $e\n' 'Stack trace:\n$s'),
|
||||||
await macro.buildDeclarationsForVariable(target, topLevelBuilder);
|
Severity.error));
|
||||||
return topLevelBuilder.result;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedError('Unsupported macro type or invalid target:\n'
|
|
||||||
'macro: $macro\ntarget: $target');
|
|
||||||
}
|
}
|
||||||
|
return builder.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs [macro] in the definition phase and returns a [MacroExecutionResult].
|
/// Runs [macro] in the definition phase and returns a [MacroExecutionResult].
|
||||||
Future<MacroExecutionResult> executeDefinitionMacro(Macro macro, Object target,
|
Future<MacroExecutionResult> executeDefinitionMacro(Macro macro, Object target,
|
||||||
DefinitionPhaseIntrospector introspector) async {
|
DefinitionPhaseIntrospector introspector) async {
|
||||||
|
// Must be assigned, used for error reporting and returning a value.
|
||||||
|
late final DefinitionBuilderBase builder;
|
||||||
|
|
||||||
// At most one of these will be used below.
|
// At most one of these will be used below.
|
||||||
late FunctionDefinitionBuilderImpl functionBuilder =
|
late FunctionDefinitionBuilderImpl functionBuilder = builder =
|
||||||
new FunctionDefinitionBuilderImpl(
|
new FunctionDefinitionBuilderImpl(
|
||||||
target as FunctionDeclarationImpl, introspector);
|
target as FunctionDeclarationImpl, introspector);
|
||||||
late VariableDefinitionBuilderImpl variableBuilder =
|
late VariableDefinitionBuilderImpl variableBuilder = builder =
|
||||||
new VariableDefinitionBuilderImpl(
|
new VariableDefinitionBuilderImpl(
|
||||||
target as VariableDeclaration, introspector);
|
target as VariableDeclaration, introspector);
|
||||||
late TypeDefinitionBuilderImpl typeBuilder =
|
late TypeDefinitionBuilderImpl typeBuilder = builder =
|
||||||
new TypeDefinitionBuilderImpl(target as IntrospectableType, introspector);
|
new TypeDefinitionBuilderImpl(target as IntrospectableType, introspector);
|
||||||
|
|
||||||
switch ((target, macro)) {
|
// TODO(jakemac): More robust handling for unawaited async errors?
|
||||||
case (Library target, LibraryDefinitionMacro macro):
|
try {
|
||||||
LibraryDefinitionBuilderImpl builder =
|
switch ((target, macro)) {
|
||||||
new LibraryDefinitionBuilderImpl(target, introspector);
|
case (Library target, LibraryDefinitionMacro macro):
|
||||||
await macro.buildDefinitionForLibrary(target, builder);
|
LibraryDefinitionBuilderImpl libraryBuilder =
|
||||||
return builder.result;
|
builder = new LibraryDefinitionBuilderImpl(target, introspector);
|
||||||
case (ClassDeclaration target, ClassDefinitionMacro macro):
|
await macro.buildDefinitionForLibrary(target, libraryBuilder);
|
||||||
if (target is! IntrospectableClassDeclaration) {
|
case (ClassDeclaration target, ClassDefinitionMacro macro):
|
||||||
throw new ArgumentError(
|
if (target is! IntrospectableClassDeclaration) {
|
||||||
'Class declarations annotated with a macro should be '
|
throw new ArgumentError(
|
||||||
'introspectable in the definitions phase.');
|
'Class declarations annotated with a macro should be '
|
||||||
}
|
'introspectable in the definitions phase.');
|
||||||
await macro.buildDefinitionForClass(target, typeBuilder);
|
}
|
||||||
return typeBuilder.result;
|
await macro.buildDefinitionForClass(target, typeBuilder);
|
||||||
case (EnumDeclaration target, EnumDefinitionMacro macro):
|
case (EnumDeclaration target, EnumDefinitionMacro macro):
|
||||||
if (target is! IntrospectableEnumDeclaration) {
|
if (target is! IntrospectableEnumDeclaration) {
|
||||||
throw new ArgumentError(
|
throw new ArgumentError(
|
||||||
'Enum declarations annotated with a macro should be introspectable '
|
'Enum declarations annotated with a macro should be '
|
||||||
'in the definitions phase.');
|
'introspectable in the definitions phase.');
|
||||||
}
|
}
|
||||||
EnumDefinitionBuilderImpl builder =
|
EnumDefinitionBuilderImpl enumBuilder =
|
||||||
new EnumDefinitionBuilderImpl(target, introspector);
|
builder = new EnumDefinitionBuilderImpl(target, introspector);
|
||||||
await macro.buildDefinitionForEnum(target, builder);
|
await macro.buildDefinitionForEnum(target, enumBuilder);
|
||||||
return builder.result;
|
case (ExtensionDeclaration target, ExtensionDefinitionMacro macro):
|
||||||
case (ExtensionDeclaration target, ExtensionDefinitionMacro macro):
|
if (target is! IntrospectableExtensionDeclaration) {
|
||||||
if (target is! IntrospectableExtensionDeclaration) {
|
throw new ArgumentError(
|
||||||
throw new ArgumentError(
|
'Extension declarations annotated with a macro should be '
|
||||||
'Extension declarations annotated with a macro should be '
|
'introspectable in the definitions phase.');
|
||||||
'introspectable in the definitions phase.');
|
}
|
||||||
}
|
await macro.buildDefinitionForExtension(target, typeBuilder);
|
||||||
await macro.buildDefinitionForExtension(target, typeBuilder);
|
case (MixinDeclaration target, MixinDefinitionMacro macro):
|
||||||
return typeBuilder.result;
|
if (target is! IntrospectableMixinDeclaration) {
|
||||||
case (MixinDeclaration target, MixinDefinitionMacro macro):
|
throw new ArgumentError(
|
||||||
if (target is! IntrospectableMixinDeclaration) {
|
'Mixin declarations annotated with a macro should be '
|
||||||
throw new ArgumentError(
|
'introspectable in the definitions phase.');
|
||||||
'Mixin declarations annotated with a macro should be '
|
}
|
||||||
'introspectable in the definitions phase.');
|
await macro.buildDefinitionForMixin(target, typeBuilder);
|
||||||
}
|
case (EnumValueDeclaration target, EnumValueDefinitionMacro macro):
|
||||||
await macro.buildDefinitionForMixin(target, typeBuilder);
|
EnumValueDefinitionBuilderImpl enumValueBuilder = builder =
|
||||||
return typeBuilder.result;
|
new EnumValueDefinitionBuilderImpl(
|
||||||
case (EnumValueDeclaration target, EnumValueDefinitionMacro macro):
|
target as EnumValueDeclarationImpl, introspector);
|
||||||
EnumValueDefinitionBuilderImpl builder =
|
await macro.buildDefinitionForEnumValue(target, enumValueBuilder);
|
||||||
new EnumValueDefinitionBuilderImpl(
|
case (ConstructorDeclaration target, ConstructorDefinitionMacro macro):
|
||||||
target as EnumValueDeclarationImpl, introspector);
|
ConstructorDefinitionBuilderImpl constructorBuilder = builder =
|
||||||
await macro.buildDefinitionForEnumValue(target, builder);
|
new ConstructorDefinitionBuilderImpl(
|
||||||
return builder.result;
|
target as ConstructorDeclarationImpl, introspector);
|
||||||
case (ConstructorDeclaration target, ConstructorDefinitionMacro macro):
|
await macro.buildDefinitionForConstructor(target, constructorBuilder);
|
||||||
ConstructorDefinitionBuilderImpl builder =
|
case (MethodDeclaration target, MethodDefinitionMacro macro):
|
||||||
new ConstructorDefinitionBuilderImpl(
|
await macro.buildDefinitionForMethod(
|
||||||
target as ConstructorDeclarationImpl, introspector);
|
target as MethodDeclarationImpl, functionBuilder);
|
||||||
await macro.buildDefinitionForConstructor(target, builder);
|
case (FieldDeclaration target, FieldDefinitionMacro macro):
|
||||||
return builder.result;
|
await macro.buildDefinitionForField(target, variableBuilder);
|
||||||
case (MethodDeclaration target, MethodDefinitionMacro macro):
|
case (FunctionDeclaration target, FunctionDefinitionMacro macro):
|
||||||
await macro.buildDefinitionForMethod(
|
await macro.buildDefinitionForFunction(target, functionBuilder);
|
||||||
target as MethodDeclarationImpl, functionBuilder);
|
case (VariableDeclaration target, VariableDefinitionMacro macro):
|
||||||
return functionBuilder.result;
|
await macro.buildDefinitionForVariable(target, variableBuilder);
|
||||||
case (FieldDeclaration target, FieldDefinitionMacro macro):
|
default:
|
||||||
await macro.buildDefinitionForField(target, variableBuilder);
|
throw new UnsupportedError('Unsupported macro type or invalid target:\n'
|
||||||
return variableBuilder.result;
|
'macro: $macro\ntarget: $target');
|
||||||
case (FunctionDeclaration target, FunctionDefinitionMacro macro):
|
}
|
||||||
await macro.buildDefinitionForFunction(target, functionBuilder);
|
} catch (e, s) {
|
||||||
return functionBuilder.result;
|
builder.report(new Diagnostic(
|
||||||
case (VariableDeclaration target, VariableDefinitionMacro macro):
|
new DiagnosticMessage('Unhandled error: $e\n' 'Stack trace:\n$s'),
|
||||||
await macro.buildDefinitionForVariable(target, variableBuilder);
|
Severity.error));
|
||||||
return variableBuilder.result;
|
|
||||||
default:
|
|
||||||
throw new UnsupportedError('Unsupported macro type or invalid target:\n'
|
|
||||||
'macro: $macro\ntarget: $target');
|
|
||||||
}
|
}
|
||||||
|
return builder.result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,6 +251,9 @@ class MacroInstanceIdentifierImpl implements MacroInstanceIdentifier {
|
||||||
|
|
||||||
/// Implementation of [MacroExecutionResult].
|
/// Implementation of [MacroExecutionResult].
|
||||||
class MacroExecutionResultImpl implements MacroExecutionResult {
|
class MacroExecutionResultImpl implements MacroExecutionResult {
|
||||||
|
@override
|
||||||
|
final List<Diagnostic> diagnostics;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final Map<IdentifierImpl, List<DeclarationCode>> enumValueAugmentations;
|
final Map<IdentifierImpl, List<DeclarationCode>> enumValueAugmentations;
|
||||||
|
|
||||||
|
@ -270,6 +273,7 @@ class MacroExecutionResultImpl implements MacroExecutionResult {
|
||||||
final Map<IdentifierImpl, List<DeclarationCode>> typeAugmentations;
|
final Map<IdentifierImpl, List<DeclarationCode>> typeAugmentations;
|
||||||
|
|
||||||
MacroExecutionResultImpl({
|
MacroExecutionResultImpl({
|
||||||
|
required this.diagnostics,
|
||||||
required this.enumValueAugmentations,
|
required this.enumValueAugmentations,
|
||||||
required this.interfaceAugmentations,
|
required this.interfaceAugmentations,
|
||||||
required this.libraryAugmentations,
|
required this.libraryAugmentations,
|
||||||
|
@ -279,6 +283,13 @@ class MacroExecutionResultImpl implements MacroExecutionResult {
|
||||||
});
|
});
|
||||||
|
|
||||||
factory MacroExecutionResultImpl.deserialize(Deserializer deserializer) {
|
factory MacroExecutionResultImpl.deserialize(Deserializer deserializer) {
|
||||||
|
deserializer
|
||||||
|
..moveNext()
|
||||||
|
..expectList();
|
||||||
|
List<Diagnostic> diagnostics = [
|
||||||
|
for (; deserializer.moveNext();) deserializer.expectDiagnostic(),
|
||||||
|
];
|
||||||
|
|
||||||
deserializer
|
deserializer
|
||||||
..moveNext()
|
..moveNext()
|
||||||
..expectList();
|
..expectList();
|
||||||
|
@ -358,6 +369,7 @@ class MacroExecutionResultImpl implements MacroExecutionResult {
|
||||||
};
|
};
|
||||||
|
|
||||||
return new MacroExecutionResultImpl(
|
return new MacroExecutionResultImpl(
|
||||||
|
diagnostics: diagnostics,
|
||||||
enumValueAugmentations: enumValueAugmentations,
|
enumValueAugmentations: enumValueAugmentations,
|
||||||
interfaceAugmentations: interfaceAugmentations,
|
interfaceAugmentations: interfaceAugmentations,
|
||||||
libraryAugmentations: libraryAugmentations,
|
libraryAugmentations: libraryAugmentations,
|
||||||
|
@ -369,6 +381,12 @@ class MacroExecutionResultImpl implements MacroExecutionResult {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void serialize(Serializer serializer) {
|
void serialize(Serializer serializer) {
|
||||||
|
serializer.startList();
|
||||||
|
for (Diagnostic diagnostic in diagnostics) {
|
||||||
|
diagnostic.serialize(serializer);
|
||||||
|
}
|
||||||
|
serializer.endList();
|
||||||
|
|
||||||
serializer.startList();
|
serializer.startList();
|
||||||
for (IdentifierImpl enuum in enumValueAugmentations.keys) {
|
for (IdentifierImpl enuum in enumValueAugmentations.keys) {
|
||||||
enuum.serialize(serializer);
|
enuum.serialize(serializer);
|
||||||
|
|
|
@ -494,6 +494,38 @@ extension DeserializerExtensions on Deserializer {
|
||||||
if (checkNull()) return null;
|
if (checkNull()) return null;
|
||||||
return expectCode();
|
return expectCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Diagnostic expectDiagnostic() {
|
||||||
|
expectList();
|
||||||
|
List<DiagnosticMessage> context = [
|
||||||
|
for (; moveNext();) expectDiagnosticMessage(),
|
||||||
|
];
|
||||||
|
|
||||||
|
String? correctionMessage = (this..moveNext()).expectNullableString();
|
||||||
|
DiagnosticMessage message = (this..moveNext()).expectDiagnosticMessage();
|
||||||
|
Severity severity = Severity.values[(this..moveNext()).expectInt()];
|
||||||
|
|
||||||
|
return new Diagnostic(message, severity,
|
||||||
|
contextMessages: context, correctionMessage: correctionMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
DiagnosticMessage expectDiagnosticMessage() {
|
||||||
|
String message = expectString();
|
||||||
|
|
||||||
|
moveNext();
|
||||||
|
RemoteInstance? target = checkNull() ? null : expectRemoteInstance();
|
||||||
|
|
||||||
|
return switch (target) {
|
||||||
|
null => new DiagnosticMessage(message),
|
||||||
|
DeclarationImpl() =>
|
||||||
|
new DiagnosticMessage(message, target: target.asDiagnosticTarget),
|
||||||
|
TypeAnnotationImpl() =>
|
||||||
|
new DiagnosticMessage(message, target: target.asDiagnosticTarget),
|
||||||
|
_ => throw new UnsupportedError(
|
||||||
|
'Unsupported target type ${target.runtimeType}, only Declarations '
|
||||||
|
'and TypeAnnotations are allowed.'),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SerializeNullable on Serializable? {
|
extension SerializeNullable on Serializable? {
|
||||||
|
@ -626,6 +658,34 @@ extension SerializeCode on Code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension SerializeDiagnostic on Diagnostic {
|
||||||
|
void serialize(Serializer serializer) {
|
||||||
|
serializer.startList();
|
||||||
|
for (DiagnosticMessage message in contextMessages) {
|
||||||
|
message.serialize(serializer);
|
||||||
|
}
|
||||||
|
serializer.endList();
|
||||||
|
|
||||||
|
serializer.addNullableString(correctionMessage);
|
||||||
|
message.serialize(serializer);
|
||||||
|
serializer.addInt(severity.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SerializeDiagnosticMessage on DiagnosticMessage {
|
||||||
|
void serialize(Serializer serializer) {
|
||||||
|
serializer.addString(message);
|
||||||
|
switch (target) {
|
||||||
|
case null:
|
||||||
|
serializer.addNull();
|
||||||
|
case DeclarationDiagnosticTarget target:
|
||||||
|
(target.declaration as DeclarationImpl).serialize(serializer);
|
||||||
|
case TypeAnnotationDiagnosticTarget target:
|
||||||
|
(target.typeAnnotation as TypeAnnotationImpl).serialize(serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension Helpers on Serializer {
|
extension Helpers on Serializer {
|
||||||
void addUri(Uri uri) => addString('$uri');
|
void addUri(Uri uri) => addString('$uri');
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ void main() {
|
||||||
var results = [
|
var results = [
|
||||||
for (var i = 0; i < 2; i++)
|
for (var i = 0; i < 2; i++)
|
||||||
MacroExecutionResultImpl(
|
MacroExecutionResultImpl(
|
||||||
|
diagnostics: [],
|
||||||
enumValueAugmentations: {},
|
enumValueAugmentations: {},
|
||||||
interfaceAugmentations: {
|
interfaceAugmentations: {
|
||||||
for (var j = 0; j < 3; j++)
|
for (var j = 0; j < 3; j++)
|
||||||
|
@ -181,6 +182,7 @@ void main() {
|
||||||
uri: Uri.parse('package:bar/bar.dart'));
|
uri: Uri.parse('package:bar/bar.dart'));
|
||||||
var results = [
|
var results = [
|
||||||
MacroExecutionResultImpl(
|
MacroExecutionResultImpl(
|
||||||
|
diagnostics: [],
|
||||||
enumValueAugmentations: {},
|
enumValueAugmentations: {},
|
||||||
interfaceAugmentations: {},
|
interfaceAugmentations: {},
|
||||||
mixinAugmentations: {},
|
mixinAugmentations: {},
|
||||||
|
@ -236,6 +238,7 @@ void main() {
|
||||||
test('can handle omitted type annotations', () {
|
test('can handle omitted type annotations', () {
|
||||||
var results = [
|
var results = [
|
||||||
MacroExecutionResultImpl(
|
MacroExecutionResultImpl(
|
||||||
|
diagnostics: [],
|
||||||
enumValueAugmentations: {},
|
enumValueAugmentations: {},
|
||||||
interfaceAugmentations: {},
|
interfaceAugmentations: {},
|
||||||
mixinAugmentations: {},
|
mixinAugmentations: {},
|
||||||
|
@ -303,6 +306,7 @@ void main() {
|
||||||
uri: Uri.parse('package:bar/bar.dart'));
|
uri: Uri.parse('package:bar/bar.dart'));
|
||||||
var results = [
|
var results = [
|
||||||
MacroExecutionResultImpl(
|
MacroExecutionResultImpl(
|
||||||
|
diagnostics: [],
|
||||||
enumValueAugmentations: {},
|
enumValueAugmentations: {},
|
||||||
interfaceAugmentations: {},
|
interfaceAugmentations: {},
|
||||||
mixinAugmentations: {},
|
mixinAugmentations: {},
|
||||||
|
@ -399,7 +403,7 @@ void main() {
|
||||||
typeArguments: []));
|
typeArguments: []));
|
||||||
|
|
||||||
var results = [
|
var results = [
|
||||||
MacroExecutionResultImpl(enumValueAugmentations: {
|
MacroExecutionResultImpl(diagnostics: [], enumValueAugmentations: {
|
||||||
myEnum.identifier: [
|
myEnum.identifier: [
|
||||||
DeclarationCode.fromParts(['a(1),\n']),
|
DeclarationCode.fromParts(['a(1),\n']),
|
||||||
],
|
],
|
||||||
|
@ -461,6 +465,7 @@ void main() {
|
||||||
|
|
||||||
var results = [
|
var results = [
|
||||||
MacroExecutionResultImpl(
|
MacroExecutionResultImpl(
|
||||||
|
diagnostics: [],
|
||||||
enumValueAugmentations: {},
|
enumValueAugmentations: {},
|
||||||
typeAugmentations: {
|
typeAugmentations: {
|
||||||
clazz.identifier: [
|
clazz.identifier: [
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:isolate';
|
import 'dart:isolate';
|
||||||
|
|
||||||
|
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||||
import 'package:_fe_analyzer_shared/src/macros/bootstrap.dart';
|
import 'package:_fe_analyzer_shared/src/macros/bootstrap.dart';
|
||||||
import 'package:_fe_analyzer_shared/src/macros/executor.dart';
|
import 'package:_fe_analyzer_shared/src/macros/executor.dart';
|
||||||
import 'package:_fe_analyzer_shared/src/macros/executor/protocol.dart';
|
import 'package:_fe_analyzer_shared/src/macros/executor/protocol.dart';
|
||||||
|
@ -23,8 +24,10 @@ import '../util.dart';
|
||||||
void main() {
|
void main() {
|
||||||
late MacroExecutor executor;
|
late MacroExecutor executor;
|
||||||
late File kernelOutputFile;
|
late File kernelOutputFile;
|
||||||
final macroName = 'SimpleMacro';
|
final diagnosticMacroName = 'DiagnosticMacro';
|
||||||
late MacroInstanceIdentifier instanceId;
|
final simpleMacroName = 'SimpleMacro';
|
||||||
|
late MacroInstanceIdentifier diagnosticMacroInstanceId;
|
||||||
|
late MacroInstanceIdentifier simpleMacroInstanceId;
|
||||||
late Uri macroUri;
|
late Uri macroUri;
|
||||||
late File simpleMacroFile;
|
late File simpleMacroFile;
|
||||||
late Directory tmpDir;
|
late Directory tmpDir;
|
||||||
|
@ -45,7 +48,8 @@ void main() {
|
||||||
|
|
||||||
var bootstrapContent = bootstrapMacroIsolate({
|
var bootstrapContent = bootstrapMacroIsolate({
|
||||||
macroUri.toString(): {
|
macroUri.toString(): {
|
||||||
macroName: ['', 'named']
|
simpleMacroName: ['', 'named'],
|
||||||
|
diagnosticMacroName: [''],
|
||||||
}
|
}
|
||||||
}, mode);
|
}, mode);
|
||||||
var bootstrapFile =
|
var bootstrapFile =
|
||||||
|
@ -80,21 +84,21 @@ void main() {
|
||||||
: await processExecutor.start(mode,
|
: await processExecutor.start(mode,
|
||||||
CommunicationChannel.stdio, kernelOutputFile.path);
|
CommunicationChannel.stdio, kernelOutputFile.path);
|
||||||
|
|
||||||
instanceId = await executor.instantiateMacro(
|
simpleMacroInstanceId = await executor.instantiateMacro(
|
||||||
macroUri, macroName, '', Arguments([], {}));
|
macroUri, simpleMacroName, '', Arguments([], {}));
|
||||||
expect(instanceId, isNotNull,
|
expect(simpleMacroInstanceId, isNotNull,
|
||||||
reason: 'Can create an instance with no arguments.');
|
reason: 'Can create an instance with no arguments.');
|
||||||
executor.disposeMacro(instanceId);
|
executor.disposeMacro(simpleMacroInstanceId);
|
||||||
|
|
||||||
instanceId = await executor.instantiateMacro(
|
simpleMacroInstanceId = await executor.instantiateMacro(
|
||||||
macroUri, macroName, '', Arguments([IntArgument(1)], {}));
|
macroUri, simpleMacroName, '', Arguments([IntArgument(1)], {}));
|
||||||
expect(instanceId, isNotNull,
|
expect(simpleMacroInstanceId, isNotNull,
|
||||||
reason: 'Can create an instance with positional arguments.');
|
reason: 'Can create an instance with positional arguments.');
|
||||||
executor.disposeMacro(instanceId);
|
executor.disposeMacro(simpleMacroInstanceId);
|
||||||
|
|
||||||
instanceId = await executor.instantiateMacro(
|
simpleMacroInstanceId = await executor.instantiateMacro(
|
||||||
macroUri,
|
macroUri,
|
||||||
macroName,
|
simpleMacroName,
|
||||||
'named',
|
'named',
|
||||||
Arguments([], {
|
Arguments([], {
|
||||||
'myBool': BoolArgument(true),
|
'myBool': BoolArgument(true),
|
||||||
|
@ -125,14 +129,19 @@ void main() {
|
||||||
]),
|
]),
|
||||||
'myString': StringArgument('a'),
|
'myString': StringArgument('a'),
|
||||||
}));
|
}));
|
||||||
expect(instanceId, isNotNull,
|
expect(simpleMacroInstanceId, isNotNull,
|
||||||
reason: 'Can create an instance with named arguments.');
|
reason: 'Can create an instance with named arguments.');
|
||||||
|
|
||||||
|
diagnosticMacroInstanceId = await executor.instantiateMacro(
|
||||||
|
macroUri, diagnosticMacroName, '', Arguments([], {}));
|
||||||
|
expect(diagnosticMacroInstanceId, isNotNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDownAll(() async {
|
tearDownAll(() async {
|
||||||
executor.disposeMacro(instanceId);
|
executor.disposeMacro(diagnosticMacroInstanceId);
|
||||||
|
executor.disposeMacro(simpleMacroInstanceId);
|
||||||
await expectLater(
|
await expectLater(
|
||||||
() => executor.executeTypesPhase(instanceId,
|
() => executor.executeTypesPhase(simpleMacroInstanceId,
|
||||||
Fixtures.myFunction, TestTypePhaseIntrospector()),
|
Fixtures.myFunction, TestTypePhaseIntrospector()),
|
||||||
throwsA(isA<RemoteException>().having((e) => e.error, 'error',
|
throwsA(isA<RemoteException>().having((e) => e.error, 'error',
|
||||||
contains('Unrecognized macro instance'))),
|
contains('Unrecognized macro instance'))),
|
||||||
|
@ -149,8 +158,10 @@ void main() {
|
||||||
group('run macros', () {
|
group('run macros', () {
|
||||||
group('in the types phase', () {
|
group('in the types phase', () {
|
||||||
test('on functions', () async {
|
test('on functions', () async {
|
||||||
var result = await executor.executeTypesPhase(instanceId,
|
var result = await executor.executeTypesPhase(
|
||||||
Fixtures.myFunction, TestTypePhaseIntrospector());
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myFunction,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.interfaceAugmentations, isEmpty);
|
expect(result.interfaceAugmentations, isEmpty);
|
||||||
expect(result.mixinAugmentations, isEmpty);
|
expect(result.mixinAugmentations, isEmpty);
|
||||||
|
@ -162,7 +173,9 @@ void main() {
|
||||||
|
|
||||||
test('on methods', () async {
|
test('on methods', () async {
|
||||||
var result = await executor.executeTypesPhase(
|
var result = await executor.executeTypesPhase(
|
||||||
instanceId, Fixtures.myMethod, TestTypePhaseIntrospector());
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myMethod,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.interfaceAugmentations, isEmpty);
|
expect(result.interfaceAugmentations, isEmpty);
|
||||||
expect(result.mixinAugmentations, isEmpty);
|
expect(result.mixinAugmentations, isEmpty);
|
||||||
|
@ -173,8 +186,10 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('on getters', () async {
|
test('on getters', () async {
|
||||||
var result = await executor.executeTypesPhase(instanceId,
|
var result = await executor.executeTypesPhase(
|
||||||
Fixtures.myVariableGetter, TestTypePhaseIntrospector());
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myVariableGetter,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.interfaceAugmentations, isEmpty);
|
expect(result.interfaceAugmentations, isEmpty);
|
||||||
expect(result.mixinAugmentations, isEmpty);
|
expect(result.mixinAugmentations, isEmpty);
|
||||||
|
@ -186,8 +201,10 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('on setters', () async {
|
test('on setters', () async {
|
||||||
var result = await executor.executeTypesPhase(instanceId,
|
var result = await executor.executeTypesPhase(
|
||||||
Fixtures.myVariableSetter, TestTypePhaseIntrospector());
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myVariableSetter,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.interfaceAugmentations, isEmpty);
|
expect(result.interfaceAugmentations, isEmpty);
|
||||||
expect(result.mixinAugmentations, isEmpty);
|
expect(result.mixinAugmentations, isEmpty);
|
||||||
|
@ -199,8 +216,10 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('on variables', () async {
|
test('on variables', () async {
|
||||||
var result = await executor.executeTypesPhase(instanceId,
|
var result = await executor.executeTypesPhase(
|
||||||
Fixtures.myVariable, TestTypePhaseIntrospector());
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myVariable,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.interfaceAugmentations, isEmpty);
|
expect(result.interfaceAugmentations, isEmpty);
|
||||||
expect(result.mixinAugmentations, isEmpty);
|
expect(result.mixinAugmentations, isEmpty);
|
||||||
|
@ -212,8 +231,10 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('on constructors', () async {
|
test('on constructors', () async {
|
||||||
var result = await executor.executeTypesPhase(instanceId,
|
var result = await executor.executeTypesPhase(
|
||||||
Fixtures.myConstructor, TestTypePhaseIntrospector());
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myConstructor,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.interfaceAugmentations, isEmpty);
|
expect(result.interfaceAugmentations, isEmpty);
|
||||||
expect(result.mixinAugmentations, isEmpty);
|
expect(result.mixinAugmentations, isEmpty);
|
||||||
|
@ -226,7 +247,9 @@ void main() {
|
||||||
|
|
||||||
test('on fields', () async {
|
test('on fields', () async {
|
||||||
var result = await executor.executeTypesPhase(
|
var result = await executor.executeTypesPhase(
|
||||||
instanceId, Fixtures.myField, TestTypePhaseIntrospector());
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myField,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.interfaceAugmentations, isEmpty);
|
expect(result.interfaceAugmentations, isEmpty);
|
||||||
expect(result.mixinAugmentations, isEmpty);
|
expect(result.mixinAugmentations, isEmpty);
|
||||||
|
@ -238,7 +261,9 @@ void main() {
|
||||||
|
|
||||||
test('on classes', () async {
|
test('on classes', () async {
|
||||||
var result = await executor.executeTypesPhase(
|
var result = await executor.executeTypesPhase(
|
||||||
instanceId, Fixtures.myClass, TestTypePhaseIntrospector());
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myClass,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(
|
expect(
|
||||||
result.interfaceAugmentations.mapValuesToDebugCodeString(),
|
result.interfaceAugmentations.mapValuesToDebugCodeString(),
|
||||||
|
@ -269,7 +294,9 @@ void main() {
|
||||||
|
|
||||||
test('on enums', () async {
|
test('on enums', () async {
|
||||||
var result = await executor.executeTypesPhase(
|
var result = await executor.executeTypesPhase(
|
||||||
instanceId, Fixtures.myEnum, TestTypePhaseIntrospector());
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myEnum,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.interfaceAugmentations, isEmpty);
|
expect(result.interfaceAugmentations, isEmpty);
|
||||||
expect(result.mixinAugmentations, isEmpty);
|
expect(result.mixinAugmentations, isEmpty);
|
||||||
|
@ -280,8 +307,10 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('on enum values', () async {
|
test('on enum values', () async {
|
||||||
var result = await executor.executeTypesPhase(instanceId,
|
var result = await executor.executeTypesPhase(
|
||||||
Fixtures.myEnumValues.first, TestTypePhaseIntrospector());
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myEnumValues.first,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.interfaceAugmentations, isEmpty);
|
expect(result.interfaceAugmentations, isEmpty);
|
||||||
expect(result.mixinAugmentations, isEmpty);
|
expect(result.mixinAugmentations, isEmpty);
|
||||||
|
@ -292,8 +321,10 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('on extensions', () async {
|
test('on extensions', () async {
|
||||||
var result = await executor.executeTypesPhase(instanceId,
|
var result = await executor.executeTypesPhase(
|
||||||
Fixtures.myExtension, TestTypePhaseIntrospector());
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myExtension,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.typeAugmentations, isEmpty);
|
expect(result.typeAugmentations, isEmpty);
|
||||||
expect(
|
expect(
|
||||||
|
@ -303,7 +334,9 @@ void main() {
|
||||||
|
|
||||||
test('on mixins', () async {
|
test('on mixins', () async {
|
||||||
var result = await executor.executeTypesPhase(
|
var result = await executor.executeTypesPhase(
|
||||||
instanceId, Fixtures.myMixin, TestTypePhaseIntrospector());
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myMixin,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.interfaceAugmentations, isEmpty);
|
expect(result.interfaceAugmentations, isEmpty);
|
||||||
expect(result.mixinAugmentations, isEmpty);
|
expect(result.mixinAugmentations, isEmpty);
|
||||||
|
@ -316,7 +349,7 @@ void main() {
|
||||||
|
|
||||||
test('on libraries', () async {
|
test('on libraries', () async {
|
||||||
var result = await executor.executeTypesPhase(
|
var result = await executor.executeTypesPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.library,
|
Fixtures.library,
|
||||||
TestTypePhaseIntrospector(),
|
TestTypePhaseIntrospector(),
|
||||||
);
|
);
|
||||||
|
@ -341,7 +374,7 @@ class LibraryInfo {
|
||||||
group('in the declaration phase', () {
|
group('in the declaration phase', () {
|
||||||
test('on functions', () async {
|
test('on functions', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(
|
var result = await executor.executeDeclarationsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myFunction,
|
Fixtures.myFunction,
|
||||||
Fixtures.testDeclarationPhaseIntrospector);
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -356,7 +389,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on methods', () async {
|
test('on methods', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(
|
var result = await executor.executeDeclarationsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myMethod,
|
Fixtures.myMethod,
|
||||||
Fixtures.testDeclarationPhaseIntrospector);
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -372,7 +405,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on constructors', () async {
|
test('on constructors', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(
|
var result = await executor.executeDeclarationsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myConstructor,
|
Fixtures.myConstructor,
|
||||||
Fixtures.testDeclarationPhaseIntrospector);
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -393,7 +426,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on getters', () async {
|
test('on getters', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(
|
var result = await executor.executeDeclarationsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myVariableGetter,
|
Fixtures.myVariableGetter,
|
||||||
Fixtures.testDeclarationPhaseIntrospector);
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -408,7 +441,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on setters', () async {
|
test('on setters', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(
|
var result = await executor.executeDeclarationsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myVariableSetter,
|
Fixtures.myVariableSetter,
|
||||||
Fixtures.testDeclarationPhaseIntrospector);
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -423,7 +456,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on variables', () async {
|
test('on variables', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(
|
var result = await executor.executeDeclarationsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myVariable,
|
Fixtures.myVariable,
|
||||||
Fixtures.testDeclarationPhaseIntrospector);
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -438,7 +471,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on fields', () async {
|
test('on fields', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(
|
var result = await executor.executeDeclarationsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myField,
|
Fixtures.myField,
|
||||||
Fixtures.testDeclarationPhaseIntrospector);
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -458,7 +491,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on classes', () async {
|
test('on classes', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(
|
var result = await executor.executeDeclarationsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myClass,
|
Fixtures.myClass,
|
||||||
Fixtures.testDeclarationPhaseIntrospector);
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -476,8 +509,10 @@ class LibraryInfo {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('on enums', () async {
|
test('on enums', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(instanceId,
|
var result = await executor.executeDeclarationsPhase(
|
||||||
Fixtures.myEnum, Fixtures.testDeclarationPhaseIntrospector);
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.myEnum,
|
||||||
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.interfaceAugmentations, isEmpty);
|
expect(result.interfaceAugmentations, isEmpty);
|
||||||
expect(result.mixinAugmentations, isEmpty);
|
expect(result.mixinAugmentations, isEmpty);
|
||||||
|
@ -494,7 +529,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on enum values', () async {
|
test('on enum values', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(
|
var result = await executor.executeDeclarationsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myEnumValues.first,
|
Fixtures.myEnumValues.first,
|
||||||
Fixtures.testDeclarationPhaseIntrospector);
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -513,7 +548,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on extensions', () async {
|
test('on extensions', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(
|
var result = await executor.executeDeclarationsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myExtension,
|
Fixtures.myExtension,
|
||||||
Fixtures.testDeclarationPhaseIntrospector);
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -531,7 +566,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on mixins', () async {
|
test('on mixins', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(
|
var result = await executor.executeDeclarationsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myMixin,
|
Fixtures.myMixin,
|
||||||
Fixtures.testDeclarationPhaseIntrospector);
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -551,7 +586,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on libraries', () async {
|
test('on libraries', () async {
|
||||||
var result = await executor.executeDeclarationsPhase(
|
var result = await executor.executeDeclarationsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.library,
|
Fixtures.library,
|
||||||
Fixtures.testDeclarationPhaseIntrospector);
|
Fixtures.testDeclarationPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -568,7 +603,7 @@ class LibraryInfo {
|
||||||
group('in the definition phase', () {
|
group('in the definition phase', () {
|
||||||
test('on functions', () async {
|
test('on functions', () async {
|
||||||
var result = await executor.executeDefinitionsPhase(
|
var result = await executor.executeDefinitionsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myFunction,
|
Fixtures.myFunction,
|
||||||
Fixtures.testDefinitionPhaseIntrospector);
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -590,7 +625,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on methods', () async {
|
test('on methods', () async {
|
||||||
var definitionResult = await executor.executeDefinitionsPhase(
|
var definitionResult = await executor.executeDefinitionsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myMethod,
|
Fixtures.myMethod,
|
||||||
Fixtures.testDefinitionPhaseIntrospector);
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(definitionResult.enumValueAugmentations, isEmpty);
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
||||||
|
@ -607,7 +642,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on constructors', () async {
|
test('on constructors', () async {
|
||||||
var definitionResult = await executor.executeDefinitionsPhase(
|
var definitionResult = await executor.executeDefinitionsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myConstructor,
|
Fixtures.myConstructor,
|
||||||
Fixtures.testDefinitionPhaseIntrospector);
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(definitionResult.enumValueAugmentations, isEmpty);
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
||||||
|
@ -626,7 +661,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on getters', () async {
|
test('on getters', () async {
|
||||||
var result = await executor.executeDefinitionsPhase(
|
var result = await executor.executeDefinitionsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myVariableGetter,
|
Fixtures.myVariableGetter,
|
||||||
Fixtures.testDefinitionPhaseIntrospector);
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -648,7 +683,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on setters', () async {
|
test('on setters', () async {
|
||||||
var result = await executor.executeDefinitionsPhase(
|
var result = await executor.executeDefinitionsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myVariableSetter,
|
Fixtures.myVariableSetter,
|
||||||
Fixtures.testDefinitionPhaseIntrospector);
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -671,7 +706,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on variables', () async {
|
test('on variables', () async {
|
||||||
var result = await executor.executeDefinitionsPhase(
|
var result = await executor.executeDefinitionsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myVariable,
|
Fixtures.myVariable,
|
||||||
Fixtures.testDefinitionPhaseIntrospector);
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
|
@ -701,7 +736,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on fields', () async {
|
test('on fields', () async {
|
||||||
var definitionResult = await executor.executeDefinitionsPhase(
|
var definitionResult = await executor.executeDefinitionsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myField,
|
Fixtures.myField,
|
||||||
Fixtures.testDefinitionPhaseIntrospector);
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(definitionResult.enumValueAugmentations, isEmpty);
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
||||||
|
@ -718,7 +753,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on classes', () async {
|
test('on classes', () async {
|
||||||
var definitionResult = await executor.executeDefinitionsPhase(
|
var definitionResult = await executor.executeDefinitionsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myClass,
|
Fixtures.myClass,
|
||||||
Fixtures.testDefinitionPhaseIntrospector);
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(definitionResult.enumValueAugmentations, isEmpty);
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
||||||
|
@ -739,7 +774,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on enums', () async {
|
test('on enums', () async {
|
||||||
var definitionResult = await executor.executeDefinitionsPhase(
|
var definitionResult = await executor.executeDefinitionsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myEnum,
|
Fixtures.myEnum,
|
||||||
Fixtures.testDefinitionPhaseIntrospector);
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(definitionResult.enumValueAugmentations, hasLength(1));
|
expect(definitionResult.enumValueAugmentations, hasLength(1));
|
||||||
|
@ -775,7 +810,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on enum values', () async {
|
test('on enum values', () async {
|
||||||
var definitionResult = await executor.executeDefinitionsPhase(
|
var definitionResult = await executor.executeDefinitionsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myEnumValues.first,
|
Fixtures.myEnumValues.first,
|
||||||
Fixtures.testDefinitionPhaseIntrospector);
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(definitionResult.enumValueAugmentations, hasLength(1));
|
expect(definitionResult.enumValueAugmentations, hasLength(1));
|
||||||
|
@ -791,7 +826,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on extensions', () async {
|
test('on extensions', () async {
|
||||||
var definitionResult = await executor.executeDefinitionsPhase(
|
var definitionResult = await executor.executeDefinitionsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myExtension,
|
Fixtures.myExtension,
|
||||||
Fixtures.testDefinitionPhaseIntrospector);
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(definitionResult.enumValueAugmentations, isEmpty);
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
||||||
|
@ -809,7 +844,7 @@ class LibraryInfo {
|
||||||
|
|
||||||
test('on mixins', () async {
|
test('on mixins', () async {
|
||||||
var definitionResult = await executor.executeDefinitionsPhase(
|
var definitionResult = await executor.executeDefinitionsPhase(
|
||||||
instanceId,
|
simpleMacroInstanceId,
|
||||||
Fixtures.myMixin,
|
Fixtures.myMixin,
|
||||||
Fixtures.testDefinitionPhaseIntrospector);
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(definitionResult.enumValueAugmentations, isEmpty);
|
expect(definitionResult.enumValueAugmentations, isEmpty);
|
||||||
|
@ -827,8 +862,10 @@ class LibraryInfo {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('on libraries', () async {
|
test('on libraries', () async {
|
||||||
var result = await executor.executeDefinitionsPhase(instanceId,
|
var result = await executor.executeDefinitionsPhase(
|
||||||
Fixtures.library, Fixtures.testDefinitionPhaseIntrospector);
|
simpleMacroInstanceId,
|
||||||
|
Fixtures.library,
|
||||||
|
Fixtures.testDefinitionPhaseIntrospector);
|
||||||
expect(result.enumValueAugmentations, isEmpty);
|
expect(result.enumValueAugmentations, isEmpty);
|
||||||
expect(result.interfaceAugmentations, isEmpty);
|
expect(result.interfaceAugmentations, isEmpty);
|
||||||
expect(result.mixinAugmentations, isEmpty);
|
expect(result.mixinAugmentations, isEmpty);
|
||||||
|
@ -840,6 +877,32 @@ augment final LibraryInfo library = LibraryInfo(Uri.parse('package:foo/bar.dart'
|
||||||
'''));
|
'''));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('and report diagnostics', () async {
|
||||||
|
final result = await executor.executeTypesPhase(
|
||||||
|
diagnosticMacroInstanceId,
|
||||||
|
Fixtures.myClass,
|
||||||
|
TestTypePhaseIntrospector());
|
||||||
|
expect(result.diagnostics, [
|
||||||
|
predicate<Diagnostic>((d) =>
|
||||||
|
d.severity == Severity.info &&
|
||||||
|
d.message.message == 'superclass' &&
|
||||||
|
(d.message.target as TypeAnnotationDiagnosticTarget)
|
||||||
|
.typeAnnotation ==
|
||||||
|
Fixtures.mySuperclassType &&
|
||||||
|
d.contextMessages.single.message == 'interface' &&
|
||||||
|
(d.contextMessages.single.target
|
||||||
|
as TypeAnnotationDiagnosticTarget)
|
||||||
|
.typeAnnotation ==
|
||||||
|
Fixtures.myInterfaceType &&
|
||||||
|
d.correctionMessage == 'correct me!'),
|
||||||
|
predicate<Diagnostic>((d) =>
|
||||||
|
d.severity == Severity.error &&
|
||||||
|
d.message.message.contains('I threw an error!') &&
|
||||||
|
// Quick test that some stack trace also appears
|
||||||
|
d.message.message.contains('simple_macro.dart')),
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,28 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||||
|
|
||||||
|
/// A macro for testing diagnostics reporting, including error handling.
|
||||||
|
class DiagnosticMacro implements ClassTypesMacro {
|
||||||
|
@override
|
||||||
|
FutureOr<void> buildTypesForClass(
|
||||||
|
ClassDeclaration clazz, ClassTypeBuilder builder) {
|
||||||
|
builder.report(Diagnostic(
|
||||||
|
DiagnosticMessage('superclass',
|
||||||
|
target: clazz.superclass!.asDiagnosticTarget),
|
||||||
|
Severity.info,
|
||||||
|
contextMessages: [
|
||||||
|
DiagnosticMessage(
|
||||||
|
'interface',
|
||||||
|
target: clazz.interfaces.single.asDiagnosticTarget,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
correctionMessage: 'correct me!'));
|
||||||
|
|
||||||
|
// Test general error handling also
|
||||||
|
throw 'I threw an error!';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A very simple macro that augments any declaration it is given, usually
|
/// A very simple macro that augments any declaration it is given, usually
|
||||||
/// adding print statements and inlining values from the declaration object
|
/// adding print statements and inlining values from the declaration object
|
||||||
/// for comparison with expected values in tests.
|
/// for comparison with expected values in tests.
|
||||||
|
|
|
@ -61,6 +61,7 @@ void f(A_Macro a) {}
|
||||||
''');
|
''');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FailingTest(reason: 'Fails because exceptions are reported as diagnostics')
|
||||||
test_macroExecutionException_compileTimeError() async {
|
test_macroExecutionException_compileTimeError() async {
|
||||||
newFile('$testPackageLibPath/a.dart', r'''
|
newFile('$testPackageLibPath/a.dart', r'''
|
||||||
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||||
|
@ -82,6 +83,7 @@ class A {}
|
||||||
''', [error(CompileTimeErrorCode.MACRO_EXECUTION_EXCEPTION, 18, 10)]);
|
''', [error(CompileTimeErrorCode.MACRO_EXECUTION_EXCEPTION, 18, 10)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FailingTest(reason: 'Fails because exceptions are reported as diagnostics')
|
||||||
test_macroExecutionException_throwsException() async {
|
test_macroExecutionException_throwsException() async {
|
||||||
newFile('$testPackageLibPath/a.dart', r'''
|
newFile('$testPackageLibPath/a.dart', r'''
|
||||||
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||||
|
|
|
@ -354,6 +354,9 @@ class _MacroInstanceIdentifier implements MacroInstanceIdentifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MacroExecutionResult implements MacroExecutionResult {
|
class _MacroExecutionResult implements MacroExecutionResult {
|
||||||
|
@override
|
||||||
|
List<Diagnostic> diagnostics = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<Identifier, Iterable<DeclarationCode>> enumValueAugmentations = const {};
|
Map<Identifier, Iterable<DeclarationCode>> enumValueAugmentations = const {};
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,7 @@ atm
|
||||||
atom
|
atom
|
||||||
atoms
|
atoms
|
||||||
atop
|
atop
|
||||||
|
attaches
|
||||||
attributes
|
attributes
|
||||||
augment
|
augment
|
||||||
augmentation
|
augmentation
|
||||||
|
@ -325,6 +326,7 @@ cr
|
||||||
creator
|
creator
|
||||||
creators
|
creators
|
||||||
criterion
|
criterion
|
||||||
|
critical
|
||||||
cross
|
cross
|
||||||
cruft
|
cruft
|
||||||
cryptic
|
cryptic
|
||||||
|
@ -657,6 +659,7 @@ growth
|
||||||
gt
|
gt
|
||||||
guarantee
|
guarantee
|
||||||
guarded
|
guarded
|
||||||
|
guideline
|
||||||
guides
|
guides
|
||||||
gypi
|
gypi
|
||||||
gz
|
gz
|
||||||
|
@ -705,6 +708,7 @@ i'll
|
||||||
i'm
|
i'm
|
||||||
ic
|
ic
|
||||||
id
|
id
|
||||||
|
ide
|
||||||
ideal
|
ideal
|
||||||
identifies
|
identifies
|
||||||
identifying
|
identifying
|
||||||
|
@ -1112,6 +1116,7 @@ pkg
|
||||||
play
|
play
|
||||||
player
|
player
|
||||||
plugin
|
plugin
|
||||||
|
plugins
|
||||||
pm
|
pm
|
||||||
pn
|
pn
|
||||||
pointed
|
pointed
|
||||||
|
@ -1402,6 +1407,7 @@ setable
|
||||||
setable
|
setable
|
||||||
setables
|
setables
|
||||||
setaf
|
setaf
|
||||||
|
severities
|
||||||
sh
|
sh
|
||||||
sha
|
sha
|
||||||
shadowed
|
shadowed
|
||||||
|
@ -1428,6 +1434,8 @@ sides
|
||||||
sigmund
|
sigmund
|
||||||
signaling
|
signaling
|
||||||
significant
|
significant
|
||||||
|
silenceable
|
||||||
|
silenced
|
||||||
simplifier
|
simplifier
|
||||||
simplify
|
simplify
|
||||||
singleton
|
singleton
|
||||||
|
@ -1558,6 +1566,7 @@ superinterfaces
|
||||||
supernode
|
supernode
|
||||||
supers
|
supers
|
||||||
suppose
|
suppose
|
||||||
|
surfaced
|
||||||
surprising
|
surprising
|
||||||
surrounded
|
surrounded
|
||||||
surrounds
|
surrounds
|
||||||
|
@ -1639,6 +1648,7 @@ toplevel
|
||||||
topological
|
topological
|
||||||
tops
|
tops
|
||||||
tput
|
tput
|
||||||
|
traceable
|
||||||
traced
|
traced
|
||||||
tracker
|
tracker
|
||||||
traditional
|
traditional
|
||||||
|
@ -1674,6 +1684,7 @@ unaffected
|
||||||
unaligned
|
unaligned
|
||||||
unaltered
|
unaltered
|
||||||
unavailable
|
unavailable
|
||||||
|
unawaited
|
||||||
unbound
|
unbound
|
||||||
uncached
|
uncached
|
||||||
uncategorized
|
uncategorized
|
||||||
|
|
Loading…
Reference in a new issue