Restore building types from macros.
Now that we can be async during linking, we can re-apply it. Change-Id: I6a5bfb1881e4e04028fcaa75c43407699483d5d5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/240781 Reviewed-by: Samuel Rawlins <srawlins@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
committed by
Commit Bot
parent
cd005ecdd4
commit
425fb22638
@@ -2,6 +2,8 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/macros/executor/multi_executor.dart'
|
||||
as macro;
|
||||
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
|
||||
import 'package:analyzer/dart/analysis/context_locator.dart';
|
||||
import 'package:analyzer/dart/analysis/declared_variables.dart';
|
||||
@@ -22,6 +24,9 @@ class AnalysisContextCollectionImpl implements AnalysisContextCollection {
|
||||
/// The resource provider used to access the file system.
|
||||
final ResourceProvider resourceProvider;
|
||||
|
||||
/// The instance of macro executor that is used for all macros.
|
||||
final macro.MultiMacroExecutor? macroExecutor = macro.MultiMacroExecutor();
|
||||
|
||||
/// The list of analysis contexts.
|
||||
@override
|
||||
final List<DriverBasedAnalysisContext> contexts = [];
|
||||
@@ -77,6 +82,7 @@ class AnalysisContextCollectionImpl implements AnalysisContextCollection {
|
||||
updateAnalysisOptions: updateAnalysisOptions,
|
||||
fileContentCache: fileContentCache,
|
||||
macroKernelBuilder: macroKernelBuilder,
|
||||
macroExecutor: macroExecutor,
|
||||
);
|
||||
contexts.add(context);
|
||||
}
|
||||
@@ -109,6 +115,13 @@ class AnalysisContextCollectionImpl implements AnalysisContextCollection {
|
||||
throw StateError('Unable to find the context to $path');
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
for (var analysisContext in contexts) {
|
||||
analysisContext.driver.dispose();
|
||||
}
|
||||
macroExecutor?.close();
|
||||
}
|
||||
|
||||
/// Check every element with [_throwIfNotAbsoluteNormalizedPath].
|
||||
void _throwIfAnyNotAbsoluteNormalizedPath(List<String> paths) {
|
||||
for (var path in paths) {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/macros/executor/multi_executor.dart'
|
||||
as macro;
|
||||
import 'package:analyzer/dart/analysis/context_builder.dart';
|
||||
import 'package:analyzer/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/dart/analysis/declared_variables.dart';
|
||||
@@ -60,6 +62,7 @@ class ContextBuilderImpl implements ContextBuilder {
|
||||
void Function(AnalysisOptionsImpl)? updateAnalysisOptions,
|
||||
FileContentCache? fileContentCache,
|
||||
MacroKernelBuilder? macroKernelBuilder,
|
||||
macro.MultiMacroExecutor? macroExecutor,
|
||||
}) {
|
||||
// TODO(scheglov) Remove this, and make `sdkPath` required.
|
||||
sdkPath ??= getSdkPath();
|
||||
@@ -118,6 +121,7 @@ class ContextBuilderImpl implements ContextBuilder {
|
||||
retainDataForTesting: retainDataForTesting,
|
||||
fileContentCache: fileContentCache,
|
||||
macroKernelBuilder: macroKernelBuilder,
|
||||
macroExecutor: macroExecutor,
|
||||
);
|
||||
|
||||
if (declaredVariables != null) {
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/macros/executor/multi_executor.dart'
|
||||
as macro;
|
||||
import 'package:analyzer/dart/analysis/analysis_context.dart' as api;
|
||||
import 'package:analyzer/dart/analysis/declared_variables.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
@@ -124,6 +126,9 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
|
||||
final MacroKernelBuilder? macroKernelBuilder;
|
||||
|
||||
/// The instance of macro executor that is used for all macros.
|
||||
final macro.MultiMacroExecutor? macroExecutor;
|
||||
|
||||
/// The declared environment variables.
|
||||
DeclaredVariables declaredVariables = DeclaredVariables();
|
||||
|
||||
@@ -258,6 +263,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
required AnalysisOptionsImpl analysisOptions,
|
||||
required Packages packages,
|
||||
this.macroKernelBuilder,
|
||||
this.macroExecutor,
|
||||
FileContentCache? fileContentCache,
|
||||
this.enableIndex = false,
|
||||
SummaryDataStore? externalSummaries,
|
||||
@@ -325,6 +331,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
declaredVariables: declaredVariables,
|
||||
sourceFactory: _sourceFactory,
|
||||
macroKernelBuilder: macroKernelBuilder,
|
||||
macroExecutor: macroExecutor,
|
||||
externalSummaries: _externalSummaries,
|
||||
fileSystemState: _fsState,
|
||||
);
|
||||
@@ -525,6 +532,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
/// periodically.
|
||||
@visibleForTesting
|
||||
void clearLibraryContext() {
|
||||
_libraryContext?.dispose();
|
||||
_libraryContext = null;
|
||||
}
|
||||
|
||||
@@ -578,6 +586,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
@override
|
||||
void dispose() {
|
||||
_scheduler.remove(this);
|
||||
clearLibraryContext();
|
||||
}
|
||||
|
||||
/// Return the cached [ResolvedUnitResult] for the Dart file with the given
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/macros/executor/multi_executor.dart'
|
||||
as macro;
|
||||
import 'package:analyzer/dart/analysis/declared_variables.dart';
|
||||
import 'package:analyzer/dart/element/element.dart'
|
||||
show CompilationUnitElement, LibraryElement;
|
||||
@@ -43,6 +45,7 @@ class LibraryContext {
|
||||
final ByteStore byteStore;
|
||||
final FileSystemState fileSystemState;
|
||||
final MacroKernelBuilder? macroKernelBuilder;
|
||||
final macro.MultiMacroExecutor? macroExecutor;
|
||||
final SummaryDataStore store = SummaryDataStore();
|
||||
|
||||
late final AnalysisContextImpl analysisContext;
|
||||
@@ -57,7 +60,8 @@ class LibraryContext {
|
||||
required AnalysisOptionsImpl analysisOptions,
|
||||
required DeclaredVariables declaredVariables,
|
||||
required SourceFactory sourceFactory,
|
||||
this.macroKernelBuilder,
|
||||
required this.macroKernelBuilder,
|
||||
required this.macroExecutor,
|
||||
required SummaryDataStore? externalSummaries,
|
||||
}) {
|
||||
var synchronousSession =
|
||||
@@ -92,6 +96,10 @@ class LibraryContext {
|
||||
return element as CompilationUnitElement;
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
elementFactory.dispose();
|
||||
}
|
||||
|
||||
/// Get the [LibraryElement] for the given library.
|
||||
LibraryElement getLibraryElement(Uri uri) {
|
||||
_createElementFactoryTypeProvider();
|
||||
@@ -206,7 +214,8 @@ class LibraryContext {
|
||||
LinkResult linkResult;
|
||||
try {
|
||||
timerLinking.start();
|
||||
linkResult = await link(elementFactory, inputLibraries);
|
||||
linkResult = await link(elementFactory, inputLibraries,
|
||||
macroExecutor: macroExecutor);
|
||||
librariesLinked += cycle.libraries.length;
|
||||
counterLinkedLibraries += inputLibraries.length;
|
||||
timerLinking.stop();
|
||||
@@ -236,12 +245,31 @@ class LibraryContext {
|
||||
final macroKernelBuilder = this.macroKernelBuilder;
|
||||
if (macroKernelBuilder != null && macroLibraries.isNotEmpty) {
|
||||
var macroKernelKey = cycle.transitiveSignature + '.macro_kernel';
|
||||
var macroKernelBytes = macroKernelBuilder.build(
|
||||
fileSystem: _MacroFileSystem(fileSystemState),
|
||||
libraries: macroLibraries,
|
||||
);
|
||||
byteStore.put(macroKernelKey, macroKernelBytes);
|
||||
bytesPut += macroKernelBytes.length;
|
||||
var macroKernelBytes = byteStore.get(macroKernelKey);
|
||||
if (macroKernelBytes == null) {
|
||||
macroKernelBytes = macroKernelBuilder.build(
|
||||
fileSystem: _MacroFileSystem(fileSystemState),
|
||||
libraries: macroLibraries,
|
||||
);
|
||||
byteStore.put(macroKernelKey, macroKernelBytes);
|
||||
bytesPut += macroKernelBytes.length;
|
||||
} else {
|
||||
bytesGet += macroKernelBytes.length;
|
||||
}
|
||||
|
||||
final macroExecutor = this.macroExecutor;
|
||||
if (macroExecutor != null) {
|
||||
var bundleMacroExecutor = BundleMacroExecutor(
|
||||
macroExecutor: macroExecutor,
|
||||
kernelBytes: macroKernelBytes,
|
||||
libraries: cycle.libraries.map((e) => e.uri).toSet(),
|
||||
);
|
||||
for (var libraryFile in cycle.libraries) {
|
||||
var libraryUriStr = libraryFile.uriStr;
|
||||
var libraryElement = elementFactory.libraryOfUri2(libraryUriStr);
|
||||
libraryElement.bundleMacroExecutor = bundleMacroExecutor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import 'package:analyzer/src/generated/utilities_collection.dart';
|
||||
import 'package:analyzer/src/generated/utilities_dart.dart';
|
||||
import 'package:analyzer/src/summary2/ast_binary_tokens.dart';
|
||||
import 'package:analyzer/src/summary2/bundle_reader.dart';
|
||||
import 'package:analyzer/src/summary2/macro.dart';
|
||||
import 'package:analyzer/src/summary2/reference.dart';
|
||||
import 'package:analyzer/src/task/inference_error.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
@@ -3678,6 +3679,9 @@ class LibraryElementImpl extends _ExistingElementImpl
|
||||
/// The scope of this library, `null` if it has not been created yet.
|
||||
LibraryScope? _scope;
|
||||
|
||||
/// The macro executor for the bundle to which this library belongs.
|
||||
BundleMacroExecutor? bundleMacroExecutor;
|
||||
|
||||
/// Initialize a newly created library element in the given [context] to have
|
||||
/// the given [name] and [offset].
|
||||
LibraryElementImpl(this.context, this.session, String name, int offset,
|
||||
|
||||
@@ -2,18 +2,22 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/dart/analysis/features.dart';
|
||||
import 'package:analyzer/dart/analysis/utilities.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart' as ast;
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/ast/ast.dart' as ast;
|
||||
import 'package:analyzer/src/dart/ast/mixin_super_invoked_names.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/resolver/scope.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/src/summary2/combinator.dart';
|
||||
import 'package:analyzer/src/summary2/constructor_initializer_resolver.dart';
|
||||
import 'package:analyzer/src/summary2/default_value_resolver.dart';
|
||||
import 'package:analyzer/src/summary2/element_builder.dart';
|
||||
import 'package:analyzer/src/summary2/export.dart';
|
||||
import 'package:analyzer/src/summary2/link.dart';
|
||||
import 'package:analyzer/src/summary2/macro_application.dart';
|
||||
import 'package:analyzer/src/summary2/metadata_resolver.dart';
|
||||
import 'package:analyzer/src/summary2/reference.dart';
|
||||
import 'package:analyzer/src/summary2/reference_resolver.dart';
|
||||
@@ -57,6 +61,10 @@ class LibraryBuilder {
|
||||
required this.units,
|
||||
});
|
||||
|
||||
SourceFactory get _sourceFactory {
|
||||
return linker.elementFactory.analysisContext.sourceFactory;
|
||||
}
|
||||
|
||||
void addExporters() {
|
||||
for (var element in element.exports) {
|
||||
var exportedLibrary = element.exportedLibrary;
|
||||
@@ -169,6 +177,55 @@ class LibraryBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> executeMacroTypesPhase() async {
|
||||
if (!element.featureSet.isEnabled(Feature.macros)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var applier = LibraryMacroApplier(this);
|
||||
var augmentationLibrary = await applier.executeMacroTypesPhase();
|
||||
if (augmentationLibrary == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var parseResult = parseString(
|
||||
content: augmentationLibrary,
|
||||
featureSet: element.featureSet,
|
||||
throwIfDiagnostics: false,
|
||||
);
|
||||
var unitNode = parseResult.unit as ast.CompilationUnitImpl;
|
||||
|
||||
// For now we model augmentation libraries as parts.
|
||||
var unitUri = uri.resolve('_macro_types.dart');
|
||||
var unitElement = CompilationUnitElementImpl(
|
||||
source: _sourceFactory.forUri2(unitUri)!,
|
||||
librarySource: element.source,
|
||||
lineInfo: parseResult.lineInfo,
|
||||
)
|
||||
..enclosingElement = element
|
||||
..isSynthetic = true;
|
||||
|
||||
var unitReference = reference.getChild('@unit').getChild('$unitUri');
|
||||
_bindReference(unitReference, unitElement);
|
||||
|
||||
element.parts.add(unitElement);
|
||||
|
||||
ElementBuilder(
|
||||
libraryBuilder: this,
|
||||
unitReference: unitReference,
|
||||
unitElement: unitElement,
|
||||
).buildDeclarationElements(unitNode);
|
||||
|
||||
units.add(
|
||||
LinkingUnit(
|
||||
isDefiningUnit: false,
|
||||
reference: unitReference,
|
||||
node: unitNode,
|
||||
element: unitElement,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void resolveConstructors() {
|
||||
ConstructorInitializerResolver(linker, element).resolve();
|
||||
}
|
||||
@@ -281,7 +338,6 @@ class LibraryBuilder {
|
||||
unitElements.add(unitElement);
|
||||
linkingUnits.add(
|
||||
LinkingUnit(
|
||||
input: inputUnit,
|
||||
isDefiningUnit: isDefiningUnit,
|
||||
reference: unitReference,
|
||||
node: unitNode,
|
||||
@@ -312,14 +368,12 @@ class LibraryBuilder {
|
||||
}
|
||||
|
||||
class LinkingUnit {
|
||||
final LinkInputUnit input;
|
||||
final bool isDefiningUnit;
|
||||
final Reference reference;
|
||||
final ast.CompilationUnitImpl node;
|
||||
final CompilationUnitElementImpl element;
|
||||
|
||||
LinkingUnit({
|
||||
required this.input,
|
||||
required this.isDefiningUnit,
|
||||
required this.reference,
|
||||
required this.node,
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/macros/executor/multi_executor.dart'
|
||||
as macro;
|
||||
import 'package:analyzer/dart/analysis/declared_variables.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart' as ast;
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
@@ -28,10 +30,11 @@ var timerLinkingLinkingBundle = Stopwatch();
|
||||
/// Note that AST units and tokens of [inputLibraries] will be damaged.
|
||||
Future<LinkResult> link(
|
||||
LinkedElementFactory elementFactory,
|
||||
List<LinkInputLibrary> inputLibraries,
|
||||
) async {
|
||||
var linker = Linker(elementFactory);
|
||||
linker.link(inputLibraries);
|
||||
List<LinkInputLibrary> inputLibraries, {
|
||||
macro.MultiMacroExecutor? macroExecutor,
|
||||
}) async {
|
||||
var linker = Linker(elementFactory, macroExecutor);
|
||||
await linker.link(inputLibraries);
|
||||
return LinkResult(
|
||||
resolutionBytes: linker.resolutionBytes,
|
||||
);
|
||||
@@ -48,6 +51,7 @@ Future<LinkResult> link2(
|
||||
|
||||
class Linker {
|
||||
final LinkedElementFactory elementFactory;
|
||||
final macro.MultiMacroExecutor? macroExecutor;
|
||||
|
||||
/// Libraries that are being linked.
|
||||
final Map<Uri, LibraryBuilder> builders = {};
|
||||
@@ -58,7 +62,7 @@ class Linker {
|
||||
|
||||
late Uint8List resolutionBytes;
|
||||
|
||||
Linker(this.elementFactory);
|
||||
Linker(this.elementFactory, this.macroExecutor);
|
||||
|
||||
AnalysisContextImpl get analysisContext {
|
||||
return elementFactory.analysisContext;
|
||||
@@ -81,12 +85,12 @@ class Linker {
|
||||
return elementNodes[element];
|
||||
}
|
||||
|
||||
void link(List<LinkInputLibrary> inputLibraries) {
|
||||
Future<void> link(List<LinkInputLibrary> inputLibraries) async {
|
||||
for (var inputLibrary in inputLibraries) {
|
||||
LibraryBuilder.build(this, inputLibrary);
|
||||
}
|
||||
|
||||
_buildOutlines();
|
||||
await _buildOutlines();
|
||||
|
||||
timerLinkingLinkingBundle.start();
|
||||
_writeLibraries();
|
||||
@@ -99,9 +103,9 @@ class Linker {
|
||||
}
|
||||
}
|
||||
|
||||
void _buildOutlines() {
|
||||
Future<void> _buildOutlines() async {
|
||||
_createTypeSystemIfNotLinkingDartCore();
|
||||
_computeLibraryScopes();
|
||||
await _computeLibraryScopes();
|
||||
_createTypeSystem();
|
||||
_resolveTypes();
|
||||
_buildEnumChildren();
|
||||
@@ -121,11 +125,15 @@ class Linker {
|
||||
}
|
||||
}
|
||||
|
||||
void _computeLibraryScopes() {
|
||||
Future<void> _computeLibraryScopes() async {
|
||||
for (var library in builders.values) {
|
||||
library.buildElements();
|
||||
}
|
||||
|
||||
for (var library in builders.values) {
|
||||
await library.executeMacroTypesPhase();
|
||||
}
|
||||
|
||||
for (var library in builders.values) {
|
||||
library.buildInitialExportScope();
|
||||
}
|
||||
|
||||
@@ -114,6 +114,12 @@ class LinkedElementFactory {
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
for (var libraryReference in rootReference.children) {
|
||||
_disposeLibrary(libraryReference.element);
|
||||
}
|
||||
}
|
||||
|
||||
Element? elementOfReference(Reference reference) {
|
||||
if (reference.element != null) {
|
||||
return reference.element;
|
||||
@@ -184,7 +190,8 @@ class LinkedElementFactory {
|
||||
void removeLibraries(Set<String> uriStrSet) {
|
||||
for (var uriStr in uriStrSet) {
|
||||
_libraryReaders.remove(uriStr);
|
||||
rootReference.removeChild(uriStr);
|
||||
var libraryReference = rootReference.removeChild(uriStr);
|
||||
_disposeLibrary(libraryReference?.element);
|
||||
}
|
||||
|
||||
analysisSession.classHierarchy.removeOfLibraries(uriStrSet);
|
||||
@@ -238,4 +245,10 @@ class LinkedElementFactory {
|
||||
|
||||
libraryElement.createLoadLibraryFunction();
|
||||
}
|
||||
|
||||
void _disposeLibrary(Element? libraryElement) {
|
||||
if (libraryElement is LibraryElementImpl) {
|
||||
libraryElement.bundleMacroExecutor?.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,72 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:isolate';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/macros/api.dart' as macro;
|
||||
import 'package:_fe_analyzer_shared/src/macros/executor.dart' as macro;
|
||||
import 'package:_fe_analyzer_shared/src/macros/executor/isolated_executor.dart'
|
||||
as isolated_executor;
|
||||
import 'package:_fe_analyzer_shared/src/macros/executor/multi_executor.dart'
|
||||
as macro;
|
||||
import 'package:_fe_analyzer_shared/src/macros/executor/serialization.dart'
|
||||
as macro;
|
||||
import 'package:path/path.dart' as package_path;
|
||||
|
||||
export 'package:_fe_analyzer_shared/src/macros/executor.dart' show Arguments;
|
||||
|
||||
class BundleMacroExecutor {
|
||||
final macro.MultiMacroExecutor macroExecutor;
|
||||
late final macro.ExecutorFactoryToken _executorFactoryToken;
|
||||
final Uint8List kernelBytes;
|
||||
Uri? _kernelUriCached;
|
||||
|
||||
BundleMacroExecutor({
|
||||
required this.macroExecutor,
|
||||
required Uint8List kernelBytes,
|
||||
required Set<Uri> libraries,
|
||||
}) : kernelBytes = Uint8List.fromList(kernelBytes) {
|
||||
_executorFactoryToken = macroExecutor.registerExecutorFactory(
|
||||
() => isolated_executor.start(
|
||||
macro.SerializationMode.byteDataServer,
|
||||
_kernelUri,
|
||||
),
|
||||
libraries,
|
||||
);
|
||||
}
|
||||
|
||||
Uri get _kernelUri {
|
||||
return _kernelUriCached ??=
|
||||
// ignore: avoid_dynamic_calls
|
||||
(Isolate.current as dynamic).createUriForKernelBlob(kernelBytes);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
macroExecutor.unregisterExecutorFactory(_executorFactoryToken);
|
||||
final kernelUriCached = _kernelUriCached;
|
||||
if (kernelUriCached != null) {
|
||||
// ignore: avoid_dynamic_calls
|
||||
(Isolate.current as dynamic).unregisterKernelBlobUri(kernelUriCached);
|
||||
_kernelUriCached = null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<MacroClassInstance> instantiate({
|
||||
required Uri libraryUri,
|
||||
required String className,
|
||||
required String constructorName,
|
||||
required macro.Arguments arguments,
|
||||
required macro.Declaration declaration,
|
||||
required macro.IdentifierResolver identifierResolver,
|
||||
}) async {
|
||||
var instanceIdentifier = await macroExecutor.instantiateMacro(
|
||||
libraryUri, className, constructorName, arguments);
|
||||
return MacroClassInstance._(
|
||||
this, identifierResolver, declaration, instanceIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
class MacroClass {
|
||||
final String name;
|
||||
final List<String> constructors;
|
||||
@@ -16,6 +78,26 @@ class MacroClass {
|
||||
});
|
||||
}
|
||||
|
||||
class MacroClassInstance {
|
||||
final BundleMacroExecutor _bundleExecutor;
|
||||
final macro.IdentifierResolver _identifierResolver;
|
||||
final macro.Declaration _declaration;
|
||||
final macro.MacroInstanceIdentifier _instanceIdentifier;
|
||||
|
||||
MacroClassInstance._(
|
||||
this._bundleExecutor,
|
||||
this._identifierResolver,
|
||||
this._declaration,
|
||||
this._instanceIdentifier,
|
||||
);
|
||||
|
||||
Future<macro.MacroExecutionResult> executeTypesPhase() async {
|
||||
macro.MacroExecutor executor = _bundleExecutor.macroExecutor;
|
||||
return await executor.executeTypesPhase(
|
||||
_instanceIdentifier, _declaration, _identifierResolver);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MacroFileEntry {
|
||||
String get content;
|
||||
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/macros/api.dart' as macro;
|
||||
import 'package:_fe_analyzer_shared/src/macros/executor.dart' as macro;
|
||||
import 'package:_fe_analyzer_shared/src/macros/executor/introspection_impls.dart'
|
||||
as macro;
|
||||
import 'package:_fe_analyzer_shared/src/macros/executor/remote_instance.dart'
|
||||
as macro;
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/summary2/library_builder.dart';
|
||||
import 'package:analyzer/src/summary2/macro.dart';
|
||||
|
||||
class LibraryMacroApplier {
|
||||
final LibraryBuilder libraryBuilder;
|
||||
|
||||
final Map<ClassDeclaration, macro.ClassDeclaration> _classDeclarations = {};
|
||||
|
||||
LibraryMacroApplier(this.libraryBuilder);
|
||||
|
||||
/// TODO(scheglov) check `shouldExecute`.
|
||||
/// TODO(scheglov) check `supportsDeclarationKind`.
|
||||
Future<String?> executeMacroTypesPhase() async {
|
||||
var macroResults = <macro.MacroExecutionResult>[];
|
||||
for (var unitElement in libraryBuilder.element.units) {
|
||||
for (var classElement in unitElement.classes) {
|
||||
var classNode = libraryBuilder.linker.elementNodes[classElement];
|
||||
// TODO(scheglov) support other declarations
|
||||
if (classNode is ClassDeclaration) {
|
||||
for (var annotation in classNode.metadata) {
|
||||
var annotationNameNode = annotation.name;
|
||||
if (annotationNameNode is SimpleIdentifier &&
|
||||
annotation.arguments != null) {
|
||||
// TODO(scheglov) Create a Scope.
|
||||
for (var import in libraryBuilder.element.imports) {
|
||||
var importedLibrary = import.importedLibrary;
|
||||
if (importedLibrary is LibraryElementImpl) {
|
||||
var importedUri = importedLibrary.source.uri;
|
||||
if (!libraryBuilder.linker.builders
|
||||
.containsKey(importedUri)) {
|
||||
var lookupResult = importedLibrary.scope.lookup(
|
||||
annotationNameNode.name,
|
||||
);
|
||||
var getter = lookupResult.getter;
|
||||
if (getter is ClassElementImpl && getter.isMacro) {
|
||||
var macroExecutor = importedLibrary.bundleMacroExecutor;
|
||||
if (macroExecutor != null) {
|
||||
var macroResult = await _runSingleMacro(
|
||||
macroExecutor,
|
||||
getClassDeclaration(classNode),
|
||||
getter,
|
||||
);
|
||||
if (macroResult.isNotEmpty) {
|
||||
macroResults.add(macroResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var macroExecutor = libraryBuilder.linker.macroExecutor;
|
||||
if (macroExecutor != null && macroResults.isNotEmpty) {
|
||||
return macroExecutor.buildAugmentationLibrary(
|
||||
macroResults,
|
||||
_resolveIdentifier,
|
||||
_inferOmittedType,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
macro.ClassDeclaration getClassDeclaration(ClassDeclaration node) {
|
||||
return _classDeclarations[node] ??= _createClassDeclaration(node);
|
||||
}
|
||||
|
||||
macro.ClassDeclaration _createClassDeclaration(ClassDeclaration node) {
|
||||
return macro.ClassDeclarationImpl(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
identifier: _IdentifierImpl(
|
||||
id: macro.RemoteInstance.uniqueId,
|
||||
name: node.name.name,
|
||||
),
|
||||
// TODO(scheglov): Support typeParameters
|
||||
typeParameters: [],
|
||||
// TODO(scheglov): Support interfaces
|
||||
interfaces: [],
|
||||
isAbstract: node.abstractKeyword != null,
|
||||
isExternal: false,
|
||||
// TODO(scheglov): Support mixins
|
||||
mixins: [],
|
||||
// TODO(scheglov): Support superclass
|
||||
superclass: null,
|
||||
);
|
||||
}
|
||||
|
||||
macro.TypeAnnotation _inferOmittedType(
|
||||
macro.OmittedTypeAnnotation omittedType,
|
||||
) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
macro.ResolvedIdentifier _resolveIdentifier(macro.Identifier identifier) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
Future<macro.MacroExecutionResult> _runSingleMacro(
|
||||
BundleMacroExecutor macroExecutor,
|
||||
macro.Declaration declaration,
|
||||
ClassElementImpl classElement,
|
||||
) async {
|
||||
var macroInstance = await macroExecutor.instantiate(
|
||||
libraryUri: classElement.librarySource.uri,
|
||||
className: classElement.name,
|
||||
constructorName: '', // TODO
|
||||
arguments: Arguments([], {}), // TODO
|
||||
declaration: declaration,
|
||||
identifierResolver: _FakeIdentifierResolver(),
|
||||
);
|
||||
return await macroInstance.executeTypesPhase();
|
||||
}
|
||||
}
|
||||
|
||||
class _FakeIdentifierResolver extends macro.IdentifierResolver {
|
||||
@override
|
||||
Future<macro.Identifier> resolveIdentifier(Uri library, String name) {
|
||||
// TODO: implement resolveIdentifier
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
class _IdentifierImpl extends macro.IdentifierImpl {
|
||||
_IdentifierImpl({required int id, required String name})
|
||||
: super(id: id, name: name);
|
||||
}
|
||||
|
||||
extension on macro.MacroExecutionResult {
|
||||
bool get isNotEmpty =>
|
||||
libraryAugmentations.isNotEmpty || classAugmentations.isNotEmpty;
|
||||
}
|
||||
@@ -177,7 +177,9 @@ abstract class ContextResolutionTest
|
||||
}
|
||||
|
||||
void disposeAnalysisContextCollection() {
|
||||
if (_analysisContextCollection != null) {
|
||||
final analysisContextCollection = _analysisContextCollection;
|
||||
if (analysisContextCollection != null) {
|
||||
analysisContextCollection.dispose();
|
||||
_analysisContextCollection = null;
|
||||
}
|
||||
}
|
||||
@@ -216,6 +218,10 @@ abstract class ContextResolutionTest
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> tearDown() async {
|
||||
disposeAnalysisContextCollection();
|
||||
}
|
||||
|
||||
/// Override this method to update [analysisOptions] for every context root,
|
||||
/// the default or already updated with `analysis_options.yaml` file.
|
||||
void updateAnalysisOptions(AnalysisOptionsImpl analysisOptions) {}
|
||||
|
||||
@@ -34,6 +34,9 @@ class MacroResolutionTest extends PubPackageResolutionTest {
|
||||
void setUp() {
|
||||
super.setUp();
|
||||
|
||||
// TODO(scheglov) Dependency tracking for macros is not right yet.
|
||||
useEmptyByteStore();
|
||||
|
||||
writeTestPackageConfig(
|
||||
PackageConfigFileBuilder(),
|
||||
macrosEnvironment: MacrosEnvironment.instance,
|
||||
@@ -41,14 +44,30 @@ class MacroResolutionTest extends PubPackageResolutionTest {
|
||||
}
|
||||
|
||||
test_0() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
newFile2('$testPackageLibPath/a.dart', r'''
|
||||
import 'dart:async';
|
||||
import 'package:_fe_analyzer_shared/src/macros/api.dart';
|
||||
|
||||
macro class EmptyMacro implements ClassTypesMacro {
|
||||
const EmptyMacro();
|
||||
FutureOr<void> buildTypesForClass(clazz, builder) {}
|
||||
|
||||
FutureOr<void> buildTypesForClass(clazz, builder) {
|
||||
var targetName = clazz.identifier.name;
|
||||
builder.declareType(
|
||||
'${targetName}_Macro',
|
||||
DeclarationCode.fromString('class ${targetName}_Macro {}'),
|
||||
);
|
||||
}
|
||||
}
|
||||
''');
|
||||
|
||||
await assertNoErrorsInCode('''
|
||||
import 'a.dart';
|
||||
|
||||
@EmptyMacro()
|
||||
class A {}
|
||||
|
||||
void f(A_Macro a) {}
|
||||
''');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user