From 9018d41706da212c2de6aba5699f9861885dbb3f Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Fri, 23 Feb 2024 19:55:10 +0000 Subject: [PATCH] Macro. Support for TypeAliasDeclaration. Change-Id: I4b85cfaf154591434729ba9ad5f94a6cfc2d1033 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/354060 Reviewed-by: Brian Wilkerson Commit-Queue: Konstantin Shcheglov Reviewed-by: Jake Macdonald --- .../lib/src/macros/api/macros.dart | 19 +++++ .../lib/src/macros/executor.dart | 1 + .../src/macros/executor/execute_macro.dart | 4 ++ .../src/macros/executor/response_impls.dart | 14 ++++ .../test/macros/executor/executor_test.dart | 33 +++++++++ .../macros/executor/response_impls_test.dart | 17 ++++- .../test/macros/executor/simple_macro.dart | 28 ++++++++ pkg/_fe_analyzer_shared/test/macros/util.dart | 12 ++++ .../lib/src/dart/analysis/driver.dart | 2 +- .../lib/src/dart/analysis/results.dart | 6 ++ .../lib/src/dart/element/element.dart | 2 +- .../lib/src/generated/error_verifier.dart | 22 +++++- .../lib/src/summary2/ast_binary_tag.dart | 1 + .../lib/src/summary2/bundle_reader.dart | 4 ++ .../lib/src/summary2/bundle_writer.dart | 4 ++ .../lib/src/summary2/macro_application.dart | 10 ++- .../lib/src/summary2/macro_declarations.dart | 70 +++++++++++++++++++ .../lib/src/summary2/macro_type_location.dart | 6 ++ .../results/get_element_declaration_test.dart | 10 +++ .../test/src/dart/resolution/macro_test.dart | 13 ++++ .../test/src/summary/element_text.dart | 5 ++ .../test/src/summary/macro/diagnostic.dart | 14 ++++ .../test/src/summary/macro/introspect.dart | 31 ++++++++ pkg/analyzer/test/src/summary/macro_test.dart | 59 ++++++++++++++++ sdk/lib/_macros/macro.dart | 19 +++++ 25 files changed, 399 insertions(+), 7 deletions(-) diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/api/macros.dart b/pkg/_fe_analyzer_shared/lib/src/macros/api/macros.dart index 6ed9aad2445..2e04fd99828 100644 --- a/pkg/_fe_analyzer_shared/lib/src/macros/api/macros.dart +++ b/pkg/_fe_analyzer_shared/lib/src/macros/api/macros.dart @@ -264,3 +264,22 @@ abstract interface class ExtensionTypeDefinitionMacro implements Macro { FutureOr buildDefinitionForExtensionType( ExtensionTypeDeclaration extension, TypeDefinitionBuilder builder); } + +/// The interface for [Macro]s that can be applied to any type alias +/// declaration, and want to contribute new type declarations to the program. +abstract interface class TypeAliasTypesMacro implements Macro { + FutureOr buildTypesForTypeAlias( + TypeAliasDeclaration declaration, + TypeBuilder builder, + ); +} + +/// The interface for [Macro]s that can be applied to any type alias +/// declaration, and want to contribute new non-type declarations to the +/// program. +abstract interface class TypeAliasDeclarationsMacro implements Macro { + FutureOr buildDeclarationsForTypeAlias( + TypeAliasDeclaration declaration, + DeclarationBuilder builder, + ); +} diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart index ef21e1acaac..e12cc410556 100644 --- a/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart +++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart @@ -204,6 +204,7 @@ enum DeclarationKind { library, method, mixinType, + typeAlias, variable, } diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor/execute_macro.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor/execute_macro.dart index 785dda0626e..effd4408352 100644 --- a/pkg/_fe_analyzer_shared/lib/src/macros/executor/execute_macro.dart +++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor/execute_macro.dart @@ -54,6 +54,8 @@ Future executeTypesMacro( target.identifier as IdentifierImpl, introspector)); case (EnumValueDeclaration target, EnumValueTypesMacro macro): await macro.buildTypesForEnumValue(target, typeBuilder); + case (TypeAliasDeclaration target, TypeAliasTypesMacro macro): + await macro.buildTypesForTypeAlias(target, typeBuilder); default: throw new UnsupportedError('Unsupported macro type or invalid target:\n' 'macro: $macro\ntarget: $target'); @@ -132,6 +134,8 @@ Future executeDeclarationsMacro(Macro macro, await macro.buildDeclarationsForFunction(target, topLevelBuilder); case (VariableDeclaration target, VariableDeclarationsMacro macro): await macro.buildDeclarationsForVariable(target, topLevelBuilder); + case (TypeAliasDeclaration target, TypeAliasDeclarationsMacro macro): + await macro.buildDeclarationsForTypeAlias(target, topLevelBuilder); default: throw new UnsupportedError('Unsupported macro type or invalid target:\n' 'macro: $macro\ntarget: $target'); diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor/response_impls.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor/response_impls.dart index 5b2afcb49c1..c0ab0c60b11 100644 --- a/pkg/_fe_analyzer_shared/lib/src/macros/executor/response_impls.dart +++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor/response_impls.dart @@ -193,6 +193,20 @@ class MacroInstanceIdentifierImpl implements MacroInstanceIdentifier { interfaces |= interfaceMask; } } + case DeclarationKind.typeAlias: + switch (phase) { + case Phase.types: + if (macro is TypeAliasTypesMacro) { + interfaces |= interfaceMask; + } + case Phase.declarations: + if (macro is TypeAliasDeclarationsMacro) { + interfaces |= interfaceMask; + } + case Phase.definitions: + // Does not have definitions. + break; + } case DeclarationKind.variable: switch (phase) { case Phase.types: diff --git a/pkg/_fe_analyzer_shared/test/macros/executor/executor_test.dart b/pkg/_fe_analyzer_shared/test/macros/executor/executor_test.dart index ab0e1b655e9..148ffceb3a9 100644 --- a/pkg/_fe_analyzer_shared/test/macros/executor/executor_test.dart +++ b/pkg/_fe_analyzer_shared/test/macros/executor/executor_test.dart @@ -343,6 +343,22 @@ void main() { 'class MyExtensionTypeOnMyClass {}')); }); + test('on type aliases', () async { + var result = await executor.executeTypesPhase( + simpleMacroInstanceId, + Fixtures.myTypeAlias, + TestTypePhaseIntrospector(), + ); + expect(result.enumValueAugmentations, isEmpty); + expect(result.typeAugmentations, isEmpty); + expect( + result.libraryAugmentations.single.debugString().toString(), + equalsIgnoringWhitespace( + 'class MyTypeAliasAliasedTypeMyClass {}', + ), + ); + }); + test('on mixins', () async { var result = await executor.executeTypesPhase( simpleMacroInstanceId, @@ -594,6 +610,23 @@ class LibraryInfo { expect(result.libraryAugmentations, isEmpty); }); + test('on type aliases', () async { + var result = await executor.executeDeclarationsPhase( + simpleMacroInstanceId, + Fixtures.myTypeAlias, + Fixtures.testDeclarationPhaseIntrospector, + ); + expect(result.enumValueAugmentations, isEmpty); + expect(result.libraryAugmentations, hasLength(1)); + expect( + result.libraryAugmentations.single.debugString().toString(), + equalsIgnoringWhitespace( + 'List get aliasedTypeFieldNames;', + ), + ); + expect(result.typeAugmentations, isEmpty); + }); + test('on mixins', () async { var result = await executor.executeDeclarationsPhase( simpleMacroInstanceId, diff --git a/pkg/_fe_analyzer_shared/test/macros/executor/response_impls_test.dart b/pkg/_fe_analyzer_shared/test/macros/executor/response_impls_test.dart index e216c75602b..8e7bd892a5a 100644 --- a/pkg/_fe_analyzer_shared/test/macros/executor/response_impls_test.dart +++ b/pkg/_fe_analyzer_shared/test/macros/executor/response_impls_test.dart @@ -14,7 +14,8 @@ void main() { test('shouldExecute', () { for (var kind in DeclarationKind.values) { for (var phase in Phase.values) { - var instance = instancesByKindAndPhase[kind]![phase]!; + var instance = instancesByKindAndPhase[kind]?[phase]; + if (instance == null) continue; for (var otherKind in DeclarationKind.values) { for (var otherPhase in Phase.values) { var expected = false; @@ -42,7 +43,8 @@ void main() { test('supportsDeclarationKind', () { for (var kind in DeclarationKind.values) { for (var phase in Phase.values) { - var instance = instancesByKindAndPhase[kind]![phase]!; + var instance = instancesByKindAndPhase[kind]?[phase]; + if (instance == null) continue; for (var otherKind in DeclarationKind.values) { var expected = false; if (kind == otherKind) { @@ -154,6 +156,12 @@ final Map> Phase.definitions: MacroInstanceIdentifierImpl( FakeMixinDefinitionMacro(), RemoteInstance.uniqueId), }, + DeclarationKind.typeAlias: { + Phase.types: MacroInstanceIdentifierImpl( + FakeTypeAliasTypesMacro(), RemoteInstance.uniqueId), + Phase.declarations: MacroInstanceIdentifierImpl( + FakeTypeAliasDeclarationsMacro(), RemoteInstance.uniqueId), + }, DeclarationKind.variable: { Phase.types: MacroInstanceIdentifierImpl( FakeVariableTypesMacro(), RemoteInstance.uniqueId), @@ -254,3 +262,8 @@ class FakeLibraryDeclarationsMacro extends Fake class FakeLibraryDefinitionMacro extends Fake implements LibraryDefinitionMacro {} + +class FakeTypeAliasTypesMacro extends Fake implements TypeAliasTypesMacro {} + +class FakeTypeAliasDeclarationsMacro extends Fake + implements TypeAliasDeclarationsMacro {} diff --git a/pkg/_fe_analyzer_shared/test/macros/executor/simple_macro.dart b/pkg/_fe_analyzer_shared/test/macros/executor/simple_macro.dart index 7ae630a90d7..c314eec48ce 100644 --- a/pkg/_fe_analyzer_shared/test/macros/executor/simple_macro.dart +++ b/pkg/_fe_analyzer_shared/test/macros/executor/simple_macro.dart @@ -69,6 +69,8 @@ class SimpleMacro MixinTypesMacro, MixinDeclarationsMacro, MixinDefinitionMacro, + TypeAliasTypesMacro, + TypeAliasDeclarationsMacro, VariableTypesMacro, VariableDeclarationsMacro, VariableDefinitionMacro { @@ -715,6 +717,32 @@ class LibraryInfo { '];', ])); } + + @override + FutureOr buildTypesForTypeAlias( + TypeAliasDeclaration extensionType, TypeBuilder builder) { + final representationType = extensionType.aliasedType as NamedTypeAnnotation; + final name = '${extensionType.identifier.name}AliasedType' + '${representationType.identifier.name}'; + builder.declareType(name, DeclarationCode.fromString('class $name {}')); + } + + @override + FutureOr buildDeclarationsForTypeAlias( + TypeAliasDeclaration extensionType, DeclarationBuilder builder) async { + final dartCoreList = + // ignore: deprecated_member_use_from_same_package + await builder.resolveIdentifier(Uri.parse('dart:core'), 'List'); + final dartCoreString = + // ignore: deprecated_member_use_from_same_package + await builder.resolveIdentifier(Uri.parse('dart:core'), 'String'); + builder.declareInLibrary(DeclarationCode.fromParts([ + NamedTypeAnnotationCode(name: dartCoreList, typeArguments: [ + NamedTypeAnnotationCode(name: dartCoreString), + ]), + ' get aliasedTypeFieldNames;', + ])); + } } Future _buildFunctionAugmentation( diff --git a/pkg/_fe_analyzer_shared/test/macros/util.dart b/pkg/_fe_analyzer_shared/test/macros/util.dart index 5ad671357b9..df296297ca5 100644 --- a/pkg/_fe_analyzer_shared/test/macros/util.dart +++ b/pkg/_fe_analyzer_shared/test/macros/util.dart @@ -687,6 +687,18 @@ class Fixtures { typeParameters: [], representationType: myClassType); + static final myTypeAlias = TypeAliasDeclarationImpl( + id: RemoteInstance.uniqueId, + identifier: IdentifierImpl( + id: RemoteInstance.uniqueId, + name: 'MyTypeAlias', + ), + library: Fixtures.library, + metadata: [], + typeParameters: [], + aliasedType: myClassType, + ); + static final myGeneratedExtensionMethod = MethodDeclarationImpl( id: RemoteInstance.uniqueId, identifier: diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart index d293a2b677c..104fde3aa13 100644 --- a/pkg/analyzer/lib/src/dart/analysis/driver.dart +++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart @@ -95,7 +95,7 @@ import 'package:meta/meta.dart'; // TODO(scheglov): Clean up the list of implicitly analyzed files. class AnalysisDriver { /// The version of data format, should be incremented on every format change. - static const int DATA_VERSION = 346; + static const int DATA_VERSION = 347; /// The number of exception contexts allowed to write. Once this field is /// zero, we stop writing any new exception contexts in this process. diff --git a/pkg/analyzer/lib/src/dart/analysis/results.dart b/pkg/analyzer/lib/src/dart/analysis/results.dart index a4e3fd8f5f1..2aac1c1344a 100644 --- a/pkg/analyzer/lib/src/dart/analysis/results.dart +++ b/pkg/analyzer/lib/src/dart/analysis/results.dart @@ -125,6 +125,12 @@ class DeclarationByElementLocator extends UnifyingAstVisitor { if (node is VariableDeclaration && _hasOffset2(node.name)) { result = node; } + } else if (element is TypeAliasElement) { + if (node is GenericTypeAlias) { + if (_hasOffset2(node.name)) { + result = node; + } + } } if (result == null) { diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart index 2ad0bcc5518..5a36e069f68 100644 --- a/pkg/analyzer/lib/src/dart/element/element.dart +++ b/pkg/analyzer/lib/src/dart/element/element.dart @@ -6736,7 +6736,7 @@ class TopLevelVariableElementImpl extends PropertyInducingElementImpl /// /// Clients may not extend, implement or mix-in this class. class TypeAliasElementImpl extends _ExistingElementImpl - with TypeParameterizedElementMixin + with TypeParameterizedElementMixin, MacroTargetElement implements TypeAliasElement { /// Is `true` if the element has direct or indirect reference to itself /// from anywhere except a class element or type parameter bounds. diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart index 372ea398c4d..c6714aadd41 100644 --- a/pkg/analyzer/lib/src/generated/error_verifier.dart +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart @@ -932,12 +932,14 @@ class ErrorVerifier extends RecursiveAstVisitor } @override - void visitGenericTypeAlias(GenericTypeAlias node) { + void visitGenericTypeAlias(covariant GenericTypeAliasImpl node) { + var element = node.declaredElement as TypeAliasElementImpl; _checkForBuiltInIdentifierAsName( node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME); _checkForMainFunction1(node.name, node.declaredElement!); _checkForTypeAliasCannotReferenceItself( node.name, node.declaredElement as TypeAliasElementImpl); + _reportMacroDiagnostics(element); super.visitGenericTypeAlias(node); } @@ -6420,6 +6422,8 @@ class _MacroTypeAnnotationLocationConverter { TypeAnnotationLocation location, ) { switch (location) { + case AliasedTypeLocation(): + return _aliasedType(location); case ElementTypeLocation(): var element = location.element; return libraryVerificationContext.declarationByElement(element); @@ -6442,6 +6446,22 @@ class _MacroTypeAnnotationLocationConverter { } } + _MacroSyntacticTypeAnnotationLocation? _aliasedType( + AliasedTypeLocation location, + ) { + var nodeLocation = convert(location.parent); + if (nodeLocation == null) { + return null; + } + var node = nodeLocation.entity; + switch (node) { + case GenericTypeAlias(): + return nodeLocation.next(node.type); + default: + throw UnimplementedError('${node.runtimeType}'); + } + } + _MacroSyntacticTypeAnnotationLocation? _extendsClause( ExtendsClauseTypeLocation location, ) { diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart b/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart index a09b6ce8764..3dc863d4ca0 100644 --- a/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart +++ b/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart @@ -149,6 +149,7 @@ class Tag { } enum TypeAnnotationLocationKind { + aliasedType, element, extendsClause, formalParameter, diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart index a880f1b5bc6..a31a95f6415 100644 --- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart +++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart @@ -2378,6 +2378,9 @@ class ResolutionReader { TypeAnnotationLocation readTypeAnnotationLocation() { var kind = readEnum(TypeAnnotationLocationKind.values); switch (kind) { + case TypeAnnotationLocationKind.aliasedType: + var parent = readTypeAnnotationLocation(); + return AliasedTypeLocation(parent); case TypeAnnotationLocationKind.element: var element = readElement()!; return ElementTypeLocation(element); @@ -2603,6 +2606,7 @@ class TypeAliasElementLinkedData element.metadata = reader._readAnnotationList( unitElement: unitElement, ); + element.macroDiagnostics = reader.readMacroDiagnostics(); _readTypeParameters(reader, element.typeParameters); element.aliasedElement = reader._readAliasedElement(unitElement); element.aliasedType = reader.readRequiredType(); diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart index 7fc064875b5..15c3a80ad09 100644 --- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart +++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart @@ -647,6 +647,7 @@ class BundleWriter { TypeAliasElementFlags.write(_sink, element); _resolutionSink._writeAnnotationList(element.metadata); + _resolutionSink.writeMacroDiagnostics(element.macroDiagnostics); _writeTypeParameters(element.typeParameters, () { _resolutionSink._writeAliasedElement(element.aliasedElement); @@ -982,6 +983,9 @@ class ResolutionSink extends _SummaryDataWriter { void writeTypeAnnotationLocation(TypeAnnotationLocation location) { switch (location) { + case AliasedTypeLocation(): + writeEnum(TypeAnnotationLocationKind.aliasedType); + writeTypeAnnotationLocation(location.parent); case ElementTypeLocation(): writeEnum(TypeAnnotationLocationKind.element); writeElement(location.element); diff --git a/pkg/analyzer/lib/src/summary2/macro_application.dart b/pkg/analyzer/lib/src/summary2/macro_application.dart index 32e2aba4a77..fc82d9bf87e 100644 --- a/pkg/analyzer/lib/src/summary2/macro_application.dart +++ b/pkg/analyzer/lib/src/summary2/macro_application.dart @@ -218,8 +218,14 @@ class LibraryMacroApplier { // TODO(scheglov): implement it break; case ast.GenericTypeAliasImpl(): - // TODO(scheglov): implement it - break; + await _addAnnotations( + libraryElement: libraryElement, + container: container, + targetNode: declaration, + targetNodeElement: declaration.declaredElement, + targetDeclarationKind: macro.DeclarationKind.typeAlias, + annotations: declaration.metadata, + ); case ast.MixinDeclarationImpl(): final element = declaration.declaredElement!; final declarationElement = element.augmented?.declaration ?? element; diff --git a/pkg/analyzer/lib/src/summary2/macro_declarations.dart b/pkg/analyzer/lib/src/summary2/macro_declarations.dart index 7f7b11ee96a..2ac7e558a7f 100644 --- a/pkg/analyzer/lib/src/summary2/macro_declarations.dart +++ b/pkg/analyzer/lib/src/summary2/macro_declarations.dart @@ -129,6 +129,8 @@ class DeclarationBuilder { return fromNode.methodDeclaration(node); case ast.MixinDeclarationImpl(): return fromNode.mixinDeclaration(node); + case ast.GenericTypeAliasImpl(): + return fromNode.typeAliasDeclaration(node); case ast.VariableDeclaration(): return fromNode.variableDeclaration(node); } @@ -579,6 +581,9 @@ class DeclarationBuilderFromElement { final Map _methodMap = Map.identity(); + final Map _typeAliasMap = + Map.identity(); + final Map _typeParameterDeclarationMap = Map.identity(); @@ -707,6 +712,12 @@ class DeclarationBuilderFromElement { return _variableMap[element] ??= _topLevelVariableElement(element); } + macro.TypeAliasDeclarationImpl typeAliasElement( + TypeAliasElementImpl element, + ) { + return _typeAliasMap[element] ??= _typeAliasElement(element); + } + /// See [macro.DeclarationPhaseIntrospector.typeDeclarationOf]. macro.TypeDeclarationImpl typeDeclarationOf(Element element) { switch (element) { @@ -720,6 +731,8 @@ class DeclarationBuilderFromElement { return extensionTypeElement(element); case MixinElementImpl(): return mixinElement(element); + case TypeAliasElementImpl(): + return typeAliasElement(element); default: // TODO(scheglov): other elements throw macro.MacroImplementationExceptionImpl( @@ -1042,6 +1055,20 @@ class DeclarationBuilderFromElement { ); } + TypeAliasDeclarationImpl _typeAliasElement( + TypeAliasElementImpl element, + ) { + return TypeAliasDeclarationImpl._( + id: macro.RemoteInstance.uniqueId, + element: element, + identifier: identifier(element), + library: library(element), + metadata: _buildMetadata(element), + aliasedType: _dartType(element.aliasedType), + typeParameters: _typeParameterDeclarations(element.typeParameters), + ); + } + macro.TypeParameterImpl _typeParameter( TypeParameterElement element, ) { @@ -1439,6 +1466,22 @@ class DeclarationBuilderFromNode { ); } + macro.TypeAliasDeclarationImpl typeAliasDeclaration( + ast.GenericTypeAliasImpl node, + ) { + final element = node.declaredElement as TypeAliasElementImpl; + + return TypeAliasDeclarationImpl._( + id: macro.RemoteInstance.uniqueId, + element: element, + identifier: _declaredIdentifier(node.name, element), + library: library(element), + metadata: _buildMetadata(element), + aliasedType: _typeAnnotationAliasedType(node), + typeParameters: _typeParameterDeclarations(node.typeParameters), + ); + } + /// See [macro.DeclarationPhaseIntrospector.typeDeclarationOf]. macro.TypeDeclarationImpl typeDeclarationOf(ast.AstNode node) { switch (node) { @@ -1791,6 +1834,17 @@ class DeclarationBuilderFromNode { } } + macro.TypeAnnotationImpl _typeAnnotationAliasedType( + ast.GenericTypeAliasImpl node, + ) { + final element = node.declaredElement as TypeAliasElementImpl; + var location = AliasedTypeLocation( + ElementTypeLocation(element), + ); + + return _typeAnnotation(node.type, location); + } + macro.TypeAnnotationImpl _typeAnnotationFunctionReturnType( ast.FunctionDeclaration node, ) { @@ -2206,6 +2260,22 @@ class MixinDeclarationImpl extends macro.MixinDeclarationImpl }); } +class TypeAliasDeclarationImpl extends macro.TypeAliasDeclarationImpl + implements HasElement { + @override + final TypeAliasElementImpl element; + + TypeAliasDeclarationImpl._({ + required super.id, + required super.identifier, + required super.library, + required super.metadata, + required super.typeParameters, + required super.aliasedType, + required this.element, + }); +} + abstract class TypeAnnotationWithLocation implements macro.TypeAnnotation { TypeAnnotationLocation get location; } diff --git a/pkg/analyzer/lib/src/summary2/macro_type_location.dart b/pkg/analyzer/lib/src/summary2/macro_type_location.dart index b4bc929254c..1b652c73254 100644 --- a/pkg/analyzer/lib/src/summary2/macro_type_location.dart +++ b/pkg/analyzer/lib/src/summary2/macro_type_location.dart @@ -5,6 +5,12 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart' as macro; import 'package:analyzer/dart/element/element.dart'; +final class AliasedTypeLocation extends TypeAnnotationLocation { + final TypeAnnotationLocation parent; + + AliasedTypeLocation(this.parent); +} + final class ElementTypeLocation extends TypeAnnotationLocation { final Element element; diff --git a/pkg/analyzer/test/src/dart/analysis/results/get_element_declaration_test.dart b/pkg/analyzer/test/src/dart/analysis/results/get_element_declaration_test.dart index c2f940168bb..c6da32352ce 100644 --- a/pkg/analyzer/test/src/dart/analysis/results/get_element_declaration_test.dart +++ b/pkg/analyzer/test/src/dart/analysis/results/get_element_declaration_test.dart @@ -273,6 +273,16 @@ typedef F = void Function(); expect(result, isNull); } + test_genericTypeAlias() async { + await resolveTestCode(r''' +typedef A = List; +'''); + var element = findNode.genericTypeAlias('A').declaredElement!; + var result = await getElementDeclaration(element); + var node = result!.node as GenericTypeAlias; + expect(node.name.lexeme, 'A'); + } + test_getter_class() async { await resolveTestCode(r''' class A { diff --git a/pkg/analyzer/test/src/dart/resolution/macro_test.dart b/pkg/analyzer/test/src/dart/resolution/macro_test.dart index 26564c933d4..7148e9332d7 100644 --- a/pkg/analyzer/test/src/dart/resolution/macro_test.dart +++ b/pkg/analyzer/test/src/dart/resolution/macro_test.dart @@ -743,6 +743,19 @@ class A { ]); } + test_diagnostic_report_atTypeAnnotation_typeAlias_aliasedType() async { + await assertErrorsInCode(''' +import 'diagnostic.dart'; + +@ReportAtTypeAnnotation([ + 'aliasedType', +]) +typedef A = List; +''', [ + error(WarningCode.MACRO_WARNING, 85, 9), + ]); + } + test_diagnostic_report_contextMessages_superClassMethods() async { var a = newFile('$testPackageLibPath/a.dart', r''' class A { diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart index ab53e0b650f..3c2762070d4 100644 --- a/pkg/analyzer/test/src/summary/element_text.dart +++ b/pkg/analyzer/test/src/summary/element_text.dart @@ -743,6 +743,9 @@ class _ElementWriter { void _writeMacroDiagnostics(Element e) { void writeTypeAnnotationLocation(TypeAnnotationLocation location) { switch (location) { + case AliasedTypeLocation(): + writeTypeAnnotationLocation(location.parent); + _sink.writelnWithIndent('AliasedTypeLocation'); case ElementTypeLocation(): _sink.writelnWithIndent('ElementTypeLocation'); _sink.withIndent(() { @@ -1370,6 +1373,8 @@ class _ElementWriter { _writeReturnType(aliasedElement.returnType); }); } + + _writeMacroDiagnostics(e); }); _assertNonSyntheticElementSelf(e); diff --git a/pkg/analyzer/test/src/summary/macro/diagnostic.dart b/pkg/analyzer/test/src/summary/macro/diagnostic.dart index e0d37aa1859..42754f9ac48 100644 --- a/pkg/analyzer/test/src/summary/macro/diagnostic.dart +++ b/pkg/analyzer/test/src/summary/macro/diagnostic.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 'dart:async'; + import 'package:_fe_analyzer_shared/src/macros/api.dart'; /*macro*/ class AskFieldsWillThrow implements ClassDefinitionMacro { @@ -144,6 +146,7 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart'; FunctionDeclarationsMacro, FieldDeclarationsMacro, MethodDeclarationsMacro, + TypeAliasDeclarationsMacro, VariableDeclarationsMacro { final List pathList; @@ -169,6 +172,11 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart'; await _report(declaration, builder); } + @override + Future buildDeclarationsForTypeAlias(declaration, builder) async { + await _report(declaration, builder); + } + @override buildDeclarationsForVariable(declaration, builder) async { await _report(declaration, builder); @@ -248,6 +256,12 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart'; } } + if (current is TypeAliasDeclaration) { + if (step == 'aliasedType') { + return current.aliasedType; + } + } + if (current is VariableDeclaration) { if (step == 'variableType') { return current.type; diff --git a/pkg/analyzer/test/src/summary/macro/introspect.dart b/pkg/analyzer/test/src/summary/macro/introspect.dart index a1e190115dc..aeb8d8e4218 100644 --- a/pkg/analyzer/test/src/summary/macro/introspect.dart +++ b/pkg/analyzer/test/src/summary/macro/introspect.dart @@ -19,6 +19,7 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart'; LibraryDeclarationsMacro, MethodDeclarationsMacro, MixinDeclarationsMacro, + TypeAliasDeclarationsMacro, VariableDeclarationsMacro { final Set withDetailsFor; final bool withMetadata; @@ -163,6 +164,16 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart'; }); } + @override + Future buildDeclarationsForTypeAlias( + TypeAliasDeclaration declaration, + DeclarationBuilder builder, + ) async { + await _write(builder, declaration, (printer) async { + await printer.writeTypeAliasDeclaration(declaration); + }); + } + @override Future buildDeclarationsForVariable( VariableDeclaration declaration, @@ -438,6 +449,8 @@ class _Printer { await writeFunctionDeclaration(declaration); case MixinDeclaration(): await writeMixinDeclaration(declaration); + case TypeAliasDeclaration(): + await writeTypeAliasDeclaration(declaration); case VariableDeclaration(): await writeVariable(declaration); default: @@ -652,6 +665,24 @@ class _Printer { }); } + Future writeTypeAliasDeclaration(TypeAliasDeclaration e) async { + if (!shouldWriteDetailsFor(e)) { + return; + } + + sink.writelnWithIndent('typedef ${e.identifier.name}'); + + await sink.withIndent(() async { + await _writeMetadata(e); + + await _writeTypeParameters(e.typeParameters); + await _writeNamedTypeAnnotation( + 'aliasedType', + e.aliasedType, + ); + }); + } + Future writeVariable(VariableDeclaration e) async { sink.writelnWithIndent(e.identifier.name); diff --git a/pkg/analyzer/test/src/summary/macro_test.dart b/pkg/analyzer/test/src/summary/macro_test.dart index e8cc4b3cb5d..c2a20d9e151 100644 --- a/pkg/analyzer/test/src/summary/macro_test.dart +++ b/pkg/analyzer/test/src/summary/macro_test.dart @@ -6690,6 +6690,44 @@ library '''); } + test_macroDiagnostics_report_atTypeAnnotation_typeAlias_aliasedType() async { + newFile( + '$testPackageLibPath/diagnostic.dart', + _getMacroCode('diagnostic.dart'), + ); + + final library = await buildLibrary(r''' +import 'diagnostic.dart'; + +@ReportAtTypeAnnotation([ + 'aliasedType', +]) +typedef A = List; +'''); + + configuration + ..withConstructors = false + ..withMetadata = false; + checkElementText(library, r''' +library + imports + package:test/diagnostic.dart + definingUnit + typeAliases + A @81 + aliasedType: List + macroDiagnostics + MacroDiagnostic + message: MacroDiagnosticMessage + message: Reported message + target: TypeAnnotationMacroDiagnosticTarget + ElementTypeLocation + element: self::@typeAlias::A + AliasedTypeLocation + severity: warning +'''); + } + test_macroDiagnostics_report_contextMessages() async { newFile( '$testPackageLibPath/diagnostic.dart', @@ -9002,6 +9040,17 @@ foo '''); } + test_unit_typeAlias() async { + newFile('$testPackageLibPath/a.dart', r''' +typedef A = List; +'''); + + await _assertIntrospectText('A', r''' +typedef A + aliasedType: List +'''); + } + test_unit_variable() async { newFile('$testPackageLibPath/a.dart', r''' final foo = 0; @@ -11416,6 +11465,16 @@ class A '''); } + test_typedef_modern_namedType() async { + await _assertIntrospectText(r''' +@Introspect() +typedef X = List; +''', r''' +typedef X + aliasedType: List +'''); + } + test_unit_function() async { await _assertIntrospectText(r''' @Introspect() diff --git a/sdk/lib/_macros/macro.dart b/sdk/lib/_macros/macro.dart index 73c20f97bba..f85c57f927f 100644 --- a/sdk/lib/_macros/macro.dart +++ b/sdk/lib/_macros/macro.dart @@ -264,3 +264,22 @@ abstract interface class ExtensionTypeDefinitionMacro implements Macro { FutureOr buildDefinitionForExtensionType( ExtensionTypeDeclaration extension, TypeDefinitionBuilder builder); } + +/// The interface for [Macro]s that can be applied to any type alias +/// declaration, and want to contribute new type declarations to the program. +abstract interface class TypeAliasTypesMacro implements Macro { + FutureOr buildTypesForTypeAlias( + TypeAliasDeclaration declaration, + TypeBuilder builder, + ); +} + +/// The interface for [Macro]s that can be applied to any type alias +/// declaration, and want to contribute new non-type declarations to the +/// program. +abstract interface class TypeAliasDeclarationsMacro implements Macro { + FutureOr buildDeclarationsForTypeAlias( + TypeAliasDeclaration declaration, + DeclarationBuilder builder, + ); +}