mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
Macro. More ordering for declarations phase.
Change-Id: I01e528a0f077367929e9e631992644b198165d6b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333581 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
7a343d0cc1
commit
f3cd5c1473
|
@ -350,66 +350,71 @@ class LibraryBuilder {
|
||||||
_declaredReferences[name] = reference;
|
_declaredReferences[name] = reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> executeMacroDeclarationsPhase({
|
/// Completes with `true` if a macro application was run in this library.
|
||||||
|
///
|
||||||
|
/// Completes with `false` if there are no macro applications to run, either
|
||||||
|
/// because we ran all, or those that we have not run yet have dependencies
|
||||||
|
/// of interfaces declared in other libraries that, and we have not run yet
|
||||||
|
/// declarations phase macro applications for them.
|
||||||
|
Future<bool> executeMacroDeclarationsPhase({
|
||||||
required OperationPerformanceImpl performance,
|
required OperationPerformanceImpl performance,
|
||||||
}) async {
|
}) async {
|
||||||
final macroApplier = linker.macroApplier;
|
final macroApplier = linker.macroApplier;
|
||||||
if (macroApplier == null) {
|
if (macroApplier == null) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
final results = await macroApplier.executeDeclarationsPhase(
|
||||||
final results = await macroApplier.executeDeclarationsPhase(
|
library: element,
|
||||||
typeSystem: element.typeSystem,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
// No more applications to execute.
|
// No more applications to execute.
|
||||||
if (results == null) {
|
if (results == null) {
|
||||||
break;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// No results from the application.
|
|
||||||
if (results.isEmpty) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
_macroResults.add(results);
|
|
||||||
|
|
||||||
final augmentationCode = macroApplier.buildAugmentationLibraryCode(
|
|
||||||
results,
|
|
||||||
);
|
|
||||||
if (augmentationCode == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final importState = kind.addMacroAugmentation(
|
|
||||||
augmentationCode,
|
|
||||||
addLibraryAugmentDirective: true,
|
|
||||||
partialIndex: _macroResults.length,
|
|
||||||
);
|
|
||||||
|
|
||||||
final augmentation = _addMacroAugmentation(importState);
|
|
||||||
|
|
||||||
final macroLinkingUnit = units.last;
|
|
||||||
ElementBuilder(
|
|
||||||
libraryBuilder: this,
|
|
||||||
container: macroLinkingUnit.container,
|
|
||||||
unitReference: macroLinkingUnit.reference,
|
|
||||||
unitElement: macroLinkingUnit.element,
|
|
||||||
).buildDeclarationElements(macroLinkingUnit.node);
|
|
||||||
|
|
||||||
final nodesToBuildType = NodesToBuildType();
|
|
||||||
final resolver =
|
|
||||||
ReferenceResolver(linker, nodesToBuildType, augmentation);
|
|
||||||
macroLinkingUnit.node.accept(resolver);
|
|
||||||
TypesBuilder(linker).build(nodesToBuildType);
|
|
||||||
|
|
||||||
// Append applications from the partial augmentation.
|
|
||||||
await macroApplier.add(
|
|
||||||
container: augmentation,
|
|
||||||
unit: macroLinkingUnit.node,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No results from the application.
|
||||||
|
if (results.isEmpty) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_macroResults.add(results);
|
||||||
|
|
||||||
|
final augmentationCode = macroApplier.buildAugmentationLibraryCode(
|
||||||
|
results,
|
||||||
|
);
|
||||||
|
if (augmentationCode == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final importState = kind.addMacroAugmentation(
|
||||||
|
augmentationCode,
|
||||||
|
addLibraryAugmentDirective: true,
|
||||||
|
partialIndex: _macroResults.length,
|
||||||
|
);
|
||||||
|
|
||||||
|
final augmentation = _addMacroAugmentation(importState);
|
||||||
|
|
||||||
|
final macroLinkingUnit = units.last;
|
||||||
|
ElementBuilder(
|
||||||
|
libraryBuilder: this,
|
||||||
|
container: macroLinkingUnit.container,
|
||||||
|
unitReference: macroLinkingUnit.reference,
|
||||||
|
unitElement: macroLinkingUnit.element,
|
||||||
|
).buildDeclarationElements(macroLinkingUnit.node);
|
||||||
|
|
||||||
|
final nodesToBuildType = NodesToBuildType();
|
||||||
|
final resolver = ReferenceResolver(linker, nodesToBuildType, augmentation);
|
||||||
|
macroLinkingUnit.node.accept(resolver);
|
||||||
|
TypesBuilder(linker).build(nodesToBuildType);
|
||||||
|
|
||||||
|
// Append applications from the partial augmentation.
|
||||||
|
await macroApplier.add(
|
||||||
|
libraryElement: element,
|
||||||
|
container: augmentation,
|
||||||
|
unit: macroLinkingUnit.node,
|
||||||
|
);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> executeMacroTypesPhase({
|
Future<void> executeMacroTypesPhase({
|
||||||
|
@ -460,6 +465,7 @@ class LibraryBuilder {
|
||||||
|
|
||||||
// Append applications from the partial augmentation.
|
// Append applications from the partial augmentation.
|
||||||
await macroApplier.add(
|
await macroApplier.add(
|
||||||
|
libraryElement: element,
|
||||||
container: augmentation,
|
container: augmentation,
|
||||||
unit: macroLinkingUnit.node,
|
unit: macroLinkingUnit.node,
|
||||||
);
|
);
|
||||||
|
@ -470,6 +476,7 @@ class LibraryBuilder {
|
||||||
Future<void> fillMacroApplier(LibraryMacroApplier macroApplier) async {
|
Future<void> fillMacroApplier(LibraryMacroApplier macroApplier) async {
|
||||||
for (final linkingUnit in units) {
|
for (final linkingUnit in units) {
|
||||||
await macroApplier.add(
|
await macroApplier.add(
|
||||||
|
libraryElement: element,
|
||||||
container: element,
|
container: element,
|
||||||
unit: linkingUnit.node,
|
unit: linkingUnit.node,
|
||||||
);
|
);
|
||||||
|
|
|
@ -305,10 +305,16 @@ class Linker {
|
||||||
Future<void> _executeMacroDeclarationsPhase({
|
Future<void> _executeMacroDeclarationsPhase({
|
||||||
required OperationPerformanceImpl performance,
|
required OperationPerformanceImpl performance,
|
||||||
}) async {
|
}) async {
|
||||||
for (final library in builders.values) {
|
while (true) {
|
||||||
await library.executeMacroDeclarationsPhase(
|
var hasProgress = false;
|
||||||
performance: performance,
|
for (final library in builders.values) {
|
||||||
);
|
hasProgress |= await library.executeMacroDeclarationsPhase(
|
||||||
|
performance: performance,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!hasProgress) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import 'package:_fe_analyzer_shared/src/macros/executor/multi_executor.dart';
|
||||||
import 'package:_fe_analyzer_shared/src/macros/executor/protocol.dart' as macro;
|
import 'package:_fe_analyzer_shared/src/macros/executor/protocol.dart' as macro;
|
||||||
import 'package:analyzer/dart/ast/ast.dart' as ast;
|
import 'package:analyzer/dart/ast/ast.dart' as ast;
|
||||||
import 'package:analyzer/dart/ast/token.dart';
|
import 'package:analyzer/dart/ast/token.dart';
|
||||||
|
import 'package:analyzer/dart/element/element.dart';
|
||||||
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
||||||
import 'package:analyzer/dart/element/type.dart';
|
import 'package:analyzer/dart/element/type.dart';
|
||||||
import 'package:analyzer/src/dart/ast/ast.dart' as ast;
|
import 'package:analyzer/src/dart/ast/ast.dart' as ast;
|
||||||
|
@ -18,6 +19,7 @@ import 'package:analyzer/src/summary2/macro.dart';
|
||||||
import 'package:analyzer/src/summary2/macro_application_error.dart';
|
import 'package:analyzer/src/summary2/macro_application_error.dart';
|
||||||
import 'package:analyzer/src/summary2/macro_declarations.dart';
|
import 'package:analyzer/src/summary2/macro_declarations.dart';
|
||||||
import 'package:analyzer/src/utilities/extensions/object.dart';
|
import 'package:analyzer/src/utilities/extensions/object.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
/// The full list of [macro.ArgumentKind]s for this dart type (includes the type
|
/// The full list of [macro.ArgumentKind]s for this dart type (includes the type
|
||||||
/// itself as well as type arguments, in source order with
|
/// itself as well as type arguments, in source order with
|
||||||
|
@ -71,8 +73,25 @@ class LibraryMacroApplier {
|
||||||
final MultiMacroExecutor macroExecutor;
|
final MultiMacroExecutor macroExecutor;
|
||||||
final bool Function(Uri) isLibraryBeingLinked;
|
final bool Function(Uri) isLibraryBeingLinked;
|
||||||
final DeclarationBuilder declarationBuilder;
|
final DeclarationBuilder declarationBuilder;
|
||||||
|
|
||||||
|
/// The reversed queue of macro applications to apply.
|
||||||
|
///
|
||||||
|
/// We add classes before methods, and methods in the reverse order,
|
||||||
|
/// classes in the reverse order, annotations in the direct order.
|
||||||
|
///
|
||||||
|
/// We iterate from the end looking for the next application to apply.
|
||||||
|
/// This way we ensure two ordering rules:
|
||||||
|
/// 1. inner before outer
|
||||||
|
/// 2. right to left
|
||||||
|
/// 3. source order
|
||||||
final List<_MacroApplication> _applications = [];
|
final List<_MacroApplication> _applications = [];
|
||||||
|
|
||||||
|
/// The map from [InstanceElement] to the applications associated with it.
|
||||||
|
/// This includes applications on the class itself, and on the methods of
|
||||||
|
/// the class.
|
||||||
|
final Map<InstanceElement, List<_MacroApplication>> _interfaceApplications =
|
||||||
|
{};
|
||||||
|
|
||||||
late final macro.TypePhaseIntrospector _typesPhaseIntrospector =
|
late final macro.TypePhaseIntrospector _typesPhaseIntrospector =
|
||||||
_TypePhaseIntrospector(elementFactory, declarationBuilder);
|
_TypePhaseIntrospector(elementFactory, declarationBuilder);
|
||||||
|
|
||||||
|
@ -84,6 +103,7 @@ class LibraryMacroApplier {
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<void> add({
|
Future<void> add({
|
||||||
|
required LibraryElementImpl libraryElement,
|
||||||
required LibraryOrAugmentationElementImpl container,
|
required LibraryOrAugmentationElementImpl container,
|
||||||
required ast.CompilationUnit unit,
|
required ast.CompilationUnit unit,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -92,23 +112,31 @@ class LibraryMacroApplier {
|
||||||
case ast.ClassDeclaration():
|
case ast.ClassDeclaration():
|
||||||
final element = declaration.declaredElement;
|
final element = declaration.declaredElement;
|
||||||
element as ClassElementImpl;
|
element as ClassElementImpl;
|
||||||
|
final declarationElement = element.augmented?.declaration ?? element;
|
||||||
|
declarationElement as ClassElementImpl;
|
||||||
await _addClassLike(
|
await _addClassLike(
|
||||||
|
libraryElement: libraryElement,
|
||||||
container: container,
|
container: container,
|
||||||
targetElement: element.declarationElement,
|
targetElement: declarationElement,
|
||||||
classNode: declaration,
|
classNode: declaration,
|
||||||
classDeclarationKind: macro.DeclarationKind.classType,
|
classDeclarationKind: macro.DeclarationKind.classType,
|
||||||
classAnnotations: declaration.metadata,
|
classAnnotations: declaration.metadata,
|
||||||
|
declarationsPhaseInterface: declarationElement,
|
||||||
members: declaration.members,
|
members: declaration.members,
|
||||||
);
|
);
|
||||||
case ast.MixinDeclaration():
|
case ast.MixinDeclaration():
|
||||||
final element = declaration.declaredElement;
|
final element = declaration.declaredElement;
|
||||||
element as MixinElementImpl;
|
element as MixinElementImpl;
|
||||||
|
final declarationElement = element.augmented?.declaration ?? element;
|
||||||
|
declarationElement as MixinElementImpl;
|
||||||
await _addClassLike(
|
await _addClassLike(
|
||||||
|
libraryElement: libraryElement,
|
||||||
container: container,
|
container: container,
|
||||||
targetElement: element.declarationElement,
|
targetElement: declarationElement,
|
||||||
classNode: declaration,
|
classNode: declaration,
|
||||||
classDeclarationKind: macro.DeclarationKind.mixinType,
|
classDeclarationKind: macro.DeclarationKind.mixinType,
|
||||||
classAnnotations: declaration.metadata,
|
classAnnotations: declaration.metadata,
|
||||||
|
declarationsPhaseInterface: declarationElement,
|
||||||
members: declaration.members,
|
members: declaration.members,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -134,9 +162,11 @@ class LibraryMacroApplier {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<macro.MacroExecutionResult>?> executeDeclarationsPhase({
|
Future<List<macro.MacroExecutionResult>?> executeDeclarationsPhase({
|
||||||
required TypeSystemImpl typeSystem,
|
required LibraryElementImpl library,
|
||||||
}) async {
|
}) async {
|
||||||
final application = _nextForDeclarationsPhase();
|
final application = _nextForDeclarationsPhase(
|
||||||
|
library: library,
|
||||||
|
);
|
||||||
if (application == null) {
|
if (application == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -150,7 +180,7 @@ class LibraryMacroApplier {
|
||||||
final introspector = _DeclarationPhaseIntrospector(
|
final introspector = _DeclarationPhaseIntrospector(
|
||||||
elementFactory,
|
elementFactory,
|
||||||
declarationBuilder,
|
declarationBuilder,
|
||||||
typeSystem,
|
library.typeSystem,
|
||||||
);
|
);
|
||||||
|
|
||||||
final result = await macroExecutor.executeDeclarationsPhase(
|
final result = await macroExecutor.executeDeclarationsPhase(
|
||||||
|
@ -204,7 +234,9 @@ class LibraryMacroApplier {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _addAnnotations({
|
Future<void> _addAnnotations({
|
||||||
|
required LibraryElementImpl libraryElement,
|
||||||
required LibraryOrAugmentationElementImpl container,
|
required LibraryOrAugmentationElementImpl container,
|
||||||
|
required InstanceElement? declarationsPhaseElement,
|
||||||
required ast.Declaration targetNode,
|
required ast.Declaration targetNode,
|
||||||
required macro.DeclarationKind targetDeclarationKind,
|
required macro.DeclarationKind targetDeclarationKind,
|
||||||
required List<ast.Annotation> annotations,
|
required List<ast.Annotation> annotations,
|
||||||
|
@ -251,39 +283,54 @@ class LibraryMacroApplier {
|
||||||
return instance.shouldExecute(targetDeclarationKind, phase);
|
return instance.shouldExecute(targetDeclarationKind, phase);
|
||||||
}).toSet();
|
}).toSet();
|
||||||
|
|
||||||
_applications.add(
|
final application = _MacroApplication(
|
||||||
_MacroApplication(
|
libraryElement: libraryElement,
|
||||||
targetNode: targetNode,
|
declarationsPhaseElement: declarationsPhaseElement,
|
||||||
targetElement: targetElement,
|
targetNode: targetNode,
|
||||||
targetDeclarationKind: targetDeclarationKind,
|
targetElement: targetElement,
|
||||||
instance: instance,
|
targetDeclarationKind: targetDeclarationKind,
|
||||||
phasesToExecute: phasesToExecute,
|
annotationNode: annotation,
|
||||||
),
|
instance: instance,
|
||||||
|
phasesToExecute: phasesToExecute,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_applications.add(application);
|
||||||
|
|
||||||
|
// Record mapping for declarations phase dependencies.
|
||||||
|
if (declarationsPhaseElement != null) {
|
||||||
|
(_interfaceApplications[declarationsPhaseElement] ??= [])
|
||||||
|
.add(application);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _addClassLike({
|
Future<void> _addClassLike({
|
||||||
|
required LibraryElementImpl libraryElement,
|
||||||
required LibraryOrAugmentationElementImpl container,
|
required LibraryOrAugmentationElementImpl container,
|
||||||
required MacroTargetElement targetElement,
|
required MacroTargetElement targetElement,
|
||||||
required ast.Declaration classNode,
|
required ast.Declaration classNode,
|
||||||
required macro.DeclarationKind classDeclarationKind,
|
required macro.DeclarationKind classDeclarationKind,
|
||||||
required List<ast.Annotation> classAnnotations,
|
required List<ast.Annotation> classAnnotations,
|
||||||
|
required InterfaceElement? declarationsPhaseInterface,
|
||||||
required List<ast.ClassMember> members,
|
required List<ast.ClassMember> members,
|
||||||
}) async {
|
}) async {
|
||||||
await _addAnnotations(
|
await _addAnnotations(
|
||||||
|
libraryElement: libraryElement,
|
||||||
container: container,
|
container: container,
|
||||||
targetNode: classNode,
|
targetNode: classNode,
|
||||||
targetDeclarationKind: classDeclarationKind,
|
targetDeclarationKind: classDeclarationKind,
|
||||||
|
declarationsPhaseElement: declarationsPhaseInterface,
|
||||||
annotations: classAnnotations,
|
annotations: classAnnotations,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (final member in members.reversed) {
|
for (final member in members.reversed) {
|
||||||
await _addAnnotations(
|
await _addAnnotations(
|
||||||
|
libraryElement: libraryElement,
|
||||||
container: container,
|
container: container,
|
||||||
targetNode: member,
|
targetNode: member,
|
||||||
// TODO(scheglov) incomplete
|
// TODO(scheglov) incomplete
|
||||||
targetDeclarationKind: macro.DeclarationKind.method,
|
targetDeclarationKind: macro.DeclarationKind.method,
|
||||||
|
declarationsPhaseElement: declarationsPhaseInterface,
|
||||||
annotations: member.metadata,
|
annotations: member.metadata,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -304,6 +351,28 @@ class LibraryMacroApplier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _hasInterfaceDependenciesSatisfied(_MacroApplication application) {
|
||||||
|
final dependencyElements = _interfaceDependencies(
|
||||||
|
application.declarationsPhaseElement,
|
||||||
|
);
|
||||||
|
if (dependencyElements == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final dependencyElement in dependencyElements) {
|
||||||
|
final applications = _interfaceApplications[dependencyElement];
|
||||||
|
if (applications != null) {
|
||||||
|
for (final dependencyApplication in applications) {
|
||||||
|
if (dependencyApplication.hasDeclarationsPhase) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// If [annotation] references a macro, invokes the right callback.
|
/// If [annotation] references a macro, invokes the right callback.
|
||||||
_AnnotationMacro? _importedMacro({
|
_AnnotationMacro? _importedMacro({
|
||||||
required LibraryOrAugmentationElementImpl container,
|
required LibraryOrAugmentationElementImpl container,
|
||||||
|
@ -385,13 +454,58 @@ class LibraryMacroApplier {
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO(scheglov) Should use dependencies.
|
Set<InstanceElement>? _interfaceDependencies(InstanceElement? element) {
|
||||||
_MacroApplication? _nextForDeclarationsPhase() {
|
// TODO(scheglov) other elements
|
||||||
for (final application in _applications.reversed) {
|
switch (element) {
|
||||||
if (application.phasesToExecute.remove(macro.Phase.declarations)) {
|
case ExtensionElement():
|
||||||
return application;
|
// TODO(scheglov) implement
|
||||||
}
|
throw UnimplementedError();
|
||||||
|
case MixinElement():
|
||||||
|
final augmented = element.augmented;
|
||||||
|
switch (augmented) {
|
||||||
|
case null:
|
||||||
|
return const {};
|
||||||
|
default:
|
||||||
|
return [
|
||||||
|
...augmented.superclassConstraints.map((e) => e.element),
|
||||||
|
...augmented.interfaces.map((e) => e.element),
|
||||||
|
].whereNotNull().toSet();
|
||||||
|
}
|
||||||
|
case InterfaceElement():
|
||||||
|
final augmented = element.augmented;
|
||||||
|
switch (augmented) {
|
||||||
|
case null:
|
||||||
|
return const {};
|
||||||
|
default:
|
||||||
|
return [
|
||||||
|
element.supertype?.element,
|
||||||
|
...augmented.mixins.map((e) => e.element),
|
||||||
|
...augmented.interfaces.map((e) => e.element),
|
||||||
|
].whereNotNull().toSet();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_MacroApplication? _nextForDeclarationsPhase({
|
||||||
|
required LibraryElementImpl library,
|
||||||
|
}) {
|
||||||
|
for (final application in _applications.reversed) {
|
||||||
|
if (!application.hasDeclarationsPhase) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (application.libraryElement != library) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!_hasInterfaceDependenciesSatisfied(application)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// The application has no dependencies to run.
|
||||||
|
application.removeDeclarationsPhase();
|
||||||
|
return application;
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,14 +724,22 @@ class _DeclarationPhaseIntrospector extends _TypePhaseIntrospector
|
||||||
.map(declarationBuilder.fromElement.fieldElement)
|
.map(declarationBuilder.fromElement.fieldElement)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
// TODO(scheglov) implement
|
||||||
throw UnsupportedError('Only introspection on classes is supported');
|
throw UnsupportedError('Only introspection on classes is supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<macro.MethodDeclaration>> methodsOf(
|
Future<List<macro.MethodDeclaration>> methodsOf(
|
||||||
covariant macro.IntrospectableType clazz) {
|
covariant macro.IntrospectableType type) async {
|
||||||
// TODO: implement methodsOf
|
switch (type) {
|
||||||
throw UnimplementedError();
|
case IntrospectableClassDeclarationImpl():
|
||||||
|
return type.element.augmented!.methods
|
||||||
|
.where((e) => !e.isSynthetic)
|
||||||
|
.map(declarationBuilder.fromElement.methodElement)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
// TODO(scheglov) implement
|
||||||
|
throw UnsupportedError('Only introspection on classes is supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -675,19 +797,33 @@ class _DeclarationPhaseIntrospector extends _TypePhaseIntrospector
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MacroApplication {
|
class _MacroApplication {
|
||||||
|
final LibraryElementImpl libraryElement;
|
||||||
|
final InstanceElement? declarationsPhaseElement;
|
||||||
final ast.AstNode targetNode;
|
final ast.AstNode targetNode;
|
||||||
final MacroTargetElement targetElement;
|
final MacroTargetElement targetElement;
|
||||||
final macro.DeclarationKind targetDeclarationKind;
|
final macro.DeclarationKind targetDeclarationKind;
|
||||||
|
final ast.Annotation annotationNode;
|
||||||
final macro.MacroInstanceIdentifier instance;
|
final macro.MacroInstanceIdentifier instance;
|
||||||
final Set<macro.Phase> phasesToExecute;
|
final Set<macro.Phase> phasesToExecute;
|
||||||
|
|
||||||
_MacroApplication({
|
_MacroApplication({
|
||||||
|
required this.libraryElement,
|
||||||
|
required this.declarationsPhaseElement,
|
||||||
required this.targetNode,
|
required this.targetNode,
|
||||||
required this.targetElement,
|
required this.targetElement,
|
||||||
required this.targetDeclarationKind,
|
required this.targetDeclarationKind,
|
||||||
|
required this.annotationNode,
|
||||||
required this.instance,
|
required this.instance,
|
||||||
required this.phasesToExecute,
|
required this.phasesToExecute,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bool get hasDeclarationsPhase {
|
||||||
|
return phasesToExecute.contains(macro.Phase.declarations);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeDeclarationsPhase() {
|
||||||
|
phasesToExecute.remove(macro.Phase.declarations);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _StaticTypeImpl implements macro.StaticType {
|
class _StaticTypeImpl implements macro.StaticType {
|
||||||
|
@ -736,14 +872,3 @@ extension on macro.MacroExecutionResult {
|
||||||
mixinAugmentations.isNotEmpty ||
|
mixinAugmentations.isNotEmpty ||
|
||||||
typeAugmentations.isNotEmpty;
|
typeAugmentations.isNotEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
extension<T extends InstanceElementImpl> on T {
|
|
||||||
T get declarationElement {
|
|
||||||
switch (augmented) {
|
|
||||||
case T(:final T declaration):
|
|
||||||
return declaration;
|
|
||||||
default:
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ class ElementTextConfiguration {
|
||||||
bool withPropertyLinking = false;
|
bool withPropertyLinking = false;
|
||||||
bool withRedirectedConstructors = false;
|
bool withRedirectedConstructors = false;
|
||||||
bool withReferences = false;
|
bool withReferences = false;
|
||||||
|
bool withReturnType = true;
|
||||||
bool withSyntheticDartCoreImport = false;
|
bool withSyntheticDartCoreImport = false;
|
||||||
|
|
||||||
ElementTextConfiguration({
|
ElementTextConfiguration({
|
||||||
|
@ -539,7 +540,7 @@ class _ElementWriter {
|
||||||
_writeCodeRange(e);
|
_writeCodeRange(e);
|
||||||
_writeTypeParameterElements(e.typeParameters);
|
_writeTypeParameterElements(e.typeParameters);
|
||||||
_writeParameterElements(e.parameters);
|
_writeParameterElements(e.parameters);
|
||||||
_writeType('returnType', e.returnType);
|
_writeReturnType(e.returnType);
|
||||||
_writeAugmentationTarget(e);
|
_writeAugmentationTarget(e);
|
||||||
_writeAugmentation(e);
|
_writeAugmentation(e);
|
||||||
});
|
});
|
||||||
|
@ -710,10 +711,12 @@ class _ElementWriter {
|
||||||
|
|
||||||
_writeElements('exports', e.libraryExports, _writeExportElement);
|
_writeElements('exports', e.libraryExports, _writeExportElement);
|
||||||
|
|
||||||
_sink.writelnWithIndent('definingUnit');
|
if (configuration.filter(e.definingCompilationUnit)) {
|
||||||
_sink.withIndent(() {
|
_sink.writelnWithIndent('definingUnit');
|
||||||
_writeUnitElement(e.definingCompilationUnit);
|
_sink.withIndent(() {
|
||||||
});
|
_writeUnitElement(e.definingCompilationUnit);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (e is LibraryElementImpl) {
|
if (e is LibraryElementImpl) {
|
||||||
_writeLibraryAugmentations(e);
|
_writeLibraryAugmentations(e);
|
||||||
|
@ -760,7 +763,7 @@ class _ElementWriter {
|
||||||
|
|
||||||
_writeTypeParameterElements(e.typeParameters);
|
_writeTypeParameterElements(e.typeParameters);
|
||||||
_writeParameterElements(e.parameters);
|
_writeParameterElements(e.parameters);
|
||||||
_writeType('returnType', e.returnType);
|
_writeReturnType(e.returnType);
|
||||||
_writeNonSyntheticElement(e);
|
_writeNonSyntheticElement(e);
|
||||||
|
|
||||||
if (e.isAugmentation) {
|
if (e.isAugmentation) {
|
||||||
|
@ -967,7 +970,7 @@ class _ElementWriter {
|
||||||
|
|
||||||
expect(e.typeParameters, isEmpty);
|
expect(e.typeParameters, isEmpty);
|
||||||
_writeParameterElements(e.parameters);
|
_writeParameterElements(e.parameters);
|
||||||
_writeType('returnType', e.returnType);
|
_writeReturnType(e.returnType);
|
||||||
_writeNonSyntheticElement(e);
|
_writeNonSyntheticElement(e);
|
||||||
writeLinking();
|
writeLinking();
|
||||||
_writeAugmentationTarget(e);
|
_writeAugmentationTarget(e);
|
||||||
|
@ -1058,6 +1061,12 @@ class _ElementWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _writeReturnType(DartType type) {
|
||||||
|
if (configuration.withReturnType) {
|
||||||
|
_writeType('returnType', type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _writeShouldUseTypeForInitializerInference(
|
void _writeShouldUseTypeForInitializerInference(
|
||||||
PropertyInducingElementImpl e,
|
PropertyInducingElementImpl e,
|
||||||
) {
|
) {
|
||||||
|
@ -1129,7 +1138,7 @@ class _ElementWriter {
|
||||||
_sink.withIndent(() {
|
_sink.withIndent(() {
|
||||||
_writeTypeParameterElements(aliasedElement.typeParameters);
|
_writeTypeParameterElements(aliasedElement.typeParameters);
|
||||||
_writeParameterElements(aliasedElement.parameters);
|
_writeParameterElements(aliasedElement.parameters);
|
||||||
_writeType('returnType', aliasedElement.returnType);
|
_writeReturnType(aliasedElement.returnType);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,18 +32,14 @@ abstract class ElementsBaseTest extends PubPackageResolutionTest {
|
||||||
|
|
||||||
final uriStr = 'package:test/test.dart';
|
final uriStr = 'package:test/test.dart';
|
||||||
final libraryResult = await analysisSession.getLibraryByUri(uriStr);
|
final libraryResult = await analysisSession.getLibraryByUri(uriStr);
|
||||||
libraryResult as LibraryElementResult;
|
|
||||||
|
|
||||||
if (keepLinkingLibraries) {
|
if (keepLinkingLibraries) {
|
||||||
return libraryResult.element as LibraryElementImpl;
|
return libraryResult.element;
|
||||||
} else {
|
} else {
|
||||||
analysisContext.changeFile(file.path);
|
analysisContext.changeFile(file.path);
|
||||||
await analysisContext.applyPendingFileChanges();
|
await analysisContext.applyPendingFileChanges();
|
||||||
// Ask again, should be read from bytes.
|
// Ask again, should be read from bytes.
|
||||||
final analysisSession = analysisContext.currentSession;
|
return testContextLibrary(uriStr);
|
||||||
final libraryResult = await analysisSession.getLibraryByUri(uriStr);
|
|
||||||
libraryResult as LibraryElementResult;
|
|
||||||
return libraryResult.element as LibraryElementImpl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,4 +55,17 @@ abstract class ElementsBaseTest extends PubPackageResolutionTest {
|
||||||
}
|
}
|
||||||
expect(actual, expected);
|
expect(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<LibraryElementImpl> testContextLibrary(String uriStr) async {
|
||||||
|
final analysisContext = contextFor(testFile);
|
||||||
|
final analysisSession = analysisContext.currentSession;
|
||||||
|
final libraryResult = await analysisSession.getLibraryByUri(uriStr);
|
||||||
|
return libraryResult.element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on SomeLibraryElementResult {
|
||||||
|
LibraryElementImpl get element {
|
||||||
|
return (this as LibraryElementResult).element as LibraryElementImpl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
|
|
||||||
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||||
|
|
||||||
/*macro*/ class AddClass implements ClassTypesMacro, MethodTypesMacro {
|
/*macro*/ class AddClass
|
||||||
|
implements ClassTypesMacro, MethodTypesMacro, MixinTypesMacro {
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
const AddClass(this.name);
|
const AddClass(this.name);
|
||||||
|
@ -19,6 +20,11 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||||
_add(builder);
|
_add(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
buildTypesForMixin(method, builder) {
|
||||||
|
_add(builder);
|
||||||
|
}
|
||||||
|
|
||||||
void _add(TypeBuilder builder) {
|
void _add(TypeBuilder builder) {
|
||||||
final code = 'class $name {}';
|
final code = 'class $name {}';
|
||||||
builder.declareType(name, DeclarationCode.fromString(code));
|
builder.declareType(name, DeclarationCode.fromString(code));
|
||||||
|
@ -26,7 +32,10 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||||
}
|
}
|
||||||
|
|
||||||
/*macro*/ class AddFunction
|
/*macro*/ class AddFunction
|
||||||
implements ClassDeclarationsMacro, MethodDeclarationsMacro {
|
implements
|
||||||
|
ClassDeclarationsMacro,
|
||||||
|
MethodDeclarationsMacro,
|
||||||
|
MixinDeclarationsMacro {
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
const AddFunction(this.name);
|
const AddFunction(this.name);
|
||||||
|
@ -41,9 +50,42 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||||
_add(builder);
|
_add(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
buildDeclarationsForMixin(method, builder) {
|
||||||
|
_add(builder);
|
||||||
|
}
|
||||||
|
|
||||||
void _add(DeclarationBuilder builder) {
|
void _add(DeclarationBuilder builder) {
|
||||||
final code = 'void $name() {}';
|
final code = 'void $name() {}';
|
||||||
final declaration = DeclarationCode.fromString(code);
|
final declaration = DeclarationCode.fromString(code);
|
||||||
builder.declareInLibrary(declaration);
|
builder.declareInLibrary(declaration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*macro*/ class AddHierarchyMethod implements ClassDeclarationsMacro {
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
const AddHierarchyMethod(this.name);
|
||||||
|
|
||||||
|
@override
|
||||||
|
buildDeclarationsForClass(clazz, builder) async {
|
||||||
|
// builder.typeDeclarationOf(identifier);
|
||||||
|
final methods = (await Future.wait(
|
||||||
|
clazz.interfaces.map(
|
||||||
|
(interface) async {
|
||||||
|
final type = await builder.typeDeclarationOf(interface.identifier);
|
||||||
|
type as IntrospectableType;
|
||||||
|
return await builder.methodsOf(type);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.expand((element) => element)
|
||||||
|
.toList();
|
||||||
|
final methodsStr = methods.map((e) => e.identifier.name).join('_');
|
||||||
|
|
||||||
|
final compoundName = methodsStr.isEmpty ? name : '${methodsStr}_$name';
|
||||||
|
final code = ' void $compoundName() {}';
|
||||||
|
final declaration = DeclarationCode.fromString(code);
|
||||||
|
builder.declareInType(declaration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue