diff --git a/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart b/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart index 266ad412c53..e7ff31dafb0 100644 --- a/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart +++ b/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart @@ -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 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 paths) { for (var path in paths) { diff --git a/pkg/analyzer/lib/src/dart/analysis/context_builder.dart b/pkg/analyzer/lib/src/dart/analysis/context_builder.dart index ddb9cc99eda..c1185f28342 100644 --- a/pkg/analyzer/lib/src/dart/analysis/context_builder.dart +++ b/pkg/analyzer/lib/src/dart/analysis/context_builder.dart @@ -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) { diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart index 457e79db469..5e40995b916 100644 --- a/pkg/analyzer/lib/src/dart/analysis/driver.dart +++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart @@ -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 diff --git a/pkg/analyzer/lib/src/dart/analysis/library_context.dart b/pkg/analyzer/lib/src/dart/analysis/library_context.dart index 96dcbb787e7..eceff2428db 100644 --- a/pkg/analyzer/lib/src/dart/analysis/library_context.dart +++ b/pkg/analyzer/lib/src/dart/analysis/library_context.dart @@ -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; + } + } } } diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart index f646b7e4e29..f8e242643f7 100644 --- a/pkg/analyzer/lib/src/dart/element/element.dart +++ b/pkg/analyzer/lib/src/dart/element/element.dart @@ -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, diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart index 323b31eaa20..db1a3ed4473 100644 --- a/pkg/analyzer/lib/src/summary2/library_builder.dart +++ b/pkg/analyzer/lib/src/summary2/library_builder.dart @@ -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 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, diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart index d4b9866176f..e7c7a536e19 100644 --- a/pkg/analyzer/lib/src/summary2/link.dart +++ b/pkg/analyzer/lib/src/summary2/link.dart @@ -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 link( LinkedElementFactory elementFactory, - List inputLibraries, -) async { - var linker = Linker(elementFactory); - linker.link(inputLibraries); + List inputLibraries, { + macro.MultiMacroExecutor? macroExecutor, +}) async { + var linker = Linker(elementFactory, macroExecutor); + await linker.link(inputLibraries); return LinkResult( resolutionBytes: linker.resolutionBytes, ); @@ -48,6 +51,7 @@ Future link2( class Linker { final LinkedElementFactory elementFactory; + final macro.MultiMacroExecutor? macroExecutor; /// Libraries that are being linked. final Map 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 inputLibraries) { + Future link(List 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 _buildOutlines() async { _createTypeSystemIfNotLinkingDartCore(); - _computeLibraryScopes(); + await _computeLibraryScopes(); _createTypeSystem(); _resolveTypes(); _buildEnumChildren(); @@ -121,11 +125,15 @@ class Linker { } } - void _computeLibraryScopes() { + Future _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(); } diff --git a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart index 64cb301f90a..c296291a53d 100644 --- a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart +++ b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart @@ -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 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(); + } + } } diff --git a/pkg/analyzer/lib/src/summary2/macro.dart b/pkg/analyzer/lib/src/summary2/macro.dart index a3502d0e5b7..e9fa100e329 100644 --- a/pkg/analyzer/lib/src/summary2/macro.dart +++ b/pkg/analyzer/lib/src/summary2/macro.dart @@ -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 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 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 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 executeTypesPhase() async { + macro.MacroExecutor executor = _bundleExecutor.macroExecutor; + return await executor.executeTypesPhase( + _instanceIdentifier, _declaration, _identifierResolver); + } +} + abstract class MacroFileEntry { String get content; diff --git a/pkg/analyzer/lib/src/summary2/macro_application.dart b/pkg/analyzer/lib/src/summary2/macro_application.dart new file mode 100644 index 00000000000..e1988a5fc4c --- /dev/null +++ b/pkg/analyzer/lib/src/summary2/macro_application.dart @@ -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 _classDeclarations = {}; + + LibraryMacroApplier(this.libraryBuilder); + + /// TODO(scheglov) check `shouldExecute`. + /// TODO(scheglov) check `supportsDeclarationKind`. + Future executeMacroTypesPhase() async { + var macroResults = []; + 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 _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 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; +} diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart index 5b9d9a40b16..85b0d8ca6f3 100644 --- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart +++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart @@ -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 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) {} diff --git a/pkg/analyzer/test/src/dart/resolution/macro_test.dart b/pkg/analyzer/test/src/dart/resolution/macro_test.dart index 2b415734c6b..a3d12b2413a 100644 --- a/pkg/analyzer/test/src/dart/resolution/macro_test.dart +++ b/pkg/analyzer/test/src/dart/resolution/macro_test.dart @@ -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 buildTypesForClass(clazz, builder) {} + + FutureOr 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) {} '''); } }