Macro. Support for TypeAliasDeclaration.

Change-Id: I4b85cfaf154591434729ba9ad5f94a6cfc2d1033
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/354060
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
This commit is contained in:
Konstantin Shcheglov 2024-02-23 19:55:10 +00:00 committed by Commit Queue
parent 9fa1c16029
commit 9018d41706
25 changed files with 399 additions and 7 deletions

View file

@ -264,3 +264,22 @@ abstract interface class ExtensionTypeDefinitionMacro implements Macro {
FutureOr<void> buildDefinitionForExtensionType( FutureOr<void> buildDefinitionForExtensionType(
ExtensionTypeDeclaration extension, TypeDefinitionBuilder builder); 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<void> 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<void> buildDeclarationsForTypeAlias(
TypeAliasDeclaration declaration,
DeclarationBuilder builder,
);
}

View file

@ -204,6 +204,7 @@ enum DeclarationKind {
library, library,
method, method,
mixinType, mixinType,
typeAlias,
variable, variable,
} }

View file

@ -54,6 +54,8 @@ Future<MacroExecutionResult> executeTypesMacro(
target.identifier as IdentifierImpl, introspector)); target.identifier as IdentifierImpl, introspector));
case (EnumValueDeclaration target, EnumValueTypesMacro macro): case (EnumValueDeclaration target, EnumValueTypesMacro macro):
await macro.buildTypesForEnumValue(target, typeBuilder); await macro.buildTypesForEnumValue(target, typeBuilder);
case (TypeAliasDeclaration target, TypeAliasTypesMacro macro):
await macro.buildTypesForTypeAlias(target, typeBuilder);
default: default:
throw new UnsupportedError('Unsupported macro type or invalid target:\n' throw new UnsupportedError('Unsupported macro type or invalid target:\n'
'macro: $macro\ntarget: $target'); 'macro: $macro\ntarget: $target');
@ -132,6 +134,8 @@ Future<MacroExecutionResult> executeDeclarationsMacro(Macro macro,
await macro.buildDeclarationsForFunction(target, topLevelBuilder); await macro.buildDeclarationsForFunction(target, topLevelBuilder);
case (VariableDeclaration target, VariableDeclarationsMacro macro): case (VariableDeclaration target, VariableDeclarationsMacro macro):
await macro.buildDeclarationsForVariable(target, topLevelBuilder); await macro.buildDeclarationsForVariable(target, topLevelBuilder);
case (TypeAliasDeclaration target, TypeAliasDeclarationsMacro macro):
await macro.buildDeclarationsForTypeAlias(target, topLevelBuilder);
default: default:
throw new UnsupportedError('Unsupported macro type or invalid target:\n' throw new UnsupportedError('Unsupported macro type or invalid target:\n'
'macro: $macro\ntarget: $target'); 'macro: $macro\ntarget: $target');

View file

@ -193,6 +193,20 @@ class MacroInstanceIdentifierImpl implements MacroInstanceIdentifier {
interfaces |= interfaceMask; 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: case DeclarationKind.variable:
switch (phase) { switch (phase) {
case Phase.types: case Phase.types:

View file

@ -343,6 +343,22 @@ void main() {
'class MyExtensionTypeOnMyClass {}')); '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 { test('on mixins', () async {
var result = await executor.executeTypesPhase( var result = await executor.executeTypesPhase(
simpleMacroInstanceId, simpleMacroInstanceId,
@ -594,6 +610,23 @@ class LibraryInfo {
expect(result.libraryAugmentations, isEmpty); 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<String> get aliasedTypeFieldNames;',
),
);
expect(result.typeAugmentations, isEmpty);
});
test('on mixins', () async { test('on mixins', () async {
var result = await executor.executeDeclarationsPhase( var result = await executor.executeDeclarationsPhase(
simpleMacroInstanceId, simpleMacroInstanceId,

View file

@ -14,7 +14,8 @@ void main() {
test('shouldExecute', () { test('shouldExecute', () {
for (var kind in DeclarationKind.values) { for (var kind in DeclarationKind.values) {
for (var phase in Phase.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 otherKind in DeclarationKind.values) {
for (var otherPhase in Phase.values) { for (var otherPhase in Phase.values) {
var expected = false; var expected = false;
@ -42,7 +43,8 @@ void main() {
test('supportsDeclarationKind', () { test('supportsDeclarationKind', () {
for (var kind in DeclarationKind.values) { for (var kind in DeclarationKind.values) {
for (var phase in Phase.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 otherKind in DeclarationKind.values) {
var expected = false; var expected = false;
if (kind == otherKind) { if (kind == otherKind) {
@ -154,6 +156,12 @@ final Map<DeclarationKind, Map<Phase, MacroInstanceIdentifierImpl>>
Phase.definitions: MacroInstanceIdentifierImpl( Phase.definitions: MacroInstanceIdentifierImpl(
FakeMixinDefinitionMacro(), RemoteInstance.uniqueId), FakeMixinDefinitionMacro(), RemoteInstance.uniqueId),
}, },
DeclarationKind.typeAlias: {
Phase.types: MacroInstanceIdentifierImpl(
FakeTypeAliasTypesMacro(), RemoteInstance.uniqueId),
Phase.declarations: MacroInstanceIdentifierImpl(
FakeTypeAliasDeclarationsMacro(), RemoteInstance.uniqueId),
},
DeclarationKind.variable: { DeclarationKind.variable: {
Phase.types: MacroInstanceIdentifierImpl( Phase.types: MacroInstanceIdentifierImpl(
FakeVariableTypesMacro(), RemoteInstance.uniqueId), FakeVariableTypesMacro(), RemoteInstance.uniqueId),
@ -254,3 +262,8 @@ class FakeLibraryDeclarationsMacro extends Fake
class FakeLibraryDefinitionMacro extends Fake class FakeLibraryDefinitionMacro extends Fake
implements LibraryDefinitionMacro {} implements LibraryDefinitionMacro {}
class FakeTypeAliasTypesMacro extends Fake implements TypeAliasTypesMacro {}
class FakeTypeAliasDeclarationsMacro extends Fake
implements TypeAliasDeclarationsMacro {}

View file

@ -69,6 +69,8 @@ class SimpleMacro
MixinTypesMacro, MixinTypesMacro,
MixinDeclarationsMacro, MixinDeclarationsMacro,
MixinDefinitionMacro, MixinDefinitionMacro,
TypeAliasTypesMacro,
TypeAliasDeclarationsMacro,
VariableTypesMacro, VariableTypesMacro,
VariableDeclarationsMacro, VariableDeclarationsMacro,
VariableDefinitionMacro { VariableDefinitionMacro {
@ -715,6 +717,32 @@ class LibraryInfo {
'];', '];',
])); ]));
} }
@override
FutureOr<void> 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<void> 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<FunctionBodyCode> _buildFunctionAugmentation( Future<FunctionBodyCode> _buildFunctionAugmentation(

View file

@ -687,6 +687,18 @@ class Fixtures {
typeParameters: [], typeParameters: [],
representationType: myClassType); 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( static final myGeneratedExtensionMethod = MethodDeclarationImpl(
id: RemoteInstance.uniqueId, id: RemoteInstance.uniqueId,
identifier: identifier:

View file

@ -95,7 +95,7 @@ import 'package:meta/meta.dart';
// TODO(scheglov): Clean up the list of implicitly analyzed files. // TODO(scheglov): Clean up the list of implicitly analyzed files.
class AnalysisDriver { class AnalysisDriver {
/// The version of data format, should be incremented on every format change. /// 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 /// The number of exception contexts allowed to write. Once this field is
/// zero, we stop writing any new exception contexts in this process. /// zero, we stop writing any new exception contexts in this process.

View file

@ -125,6 +125,12 @@ class DeclarationByElementLocator extends UnifyingAstVisitor<void> {
if (node is VariableDeclaration && _hasOffset2(node.name)) { if (node is VariableDeclaration && _hasOffset2(node.name)) {
result = node; result = node;
} }
} else if (element is TypeAliasElement) {
if (node is GenericTypeAlias) {
if (_hasOffset2(node.name)) {
result = node;
}
}
} }
if (result == null) { if (result == null) {

View file

@ -6736,7 +6736,7 @@ class TopLevelVariableElementImpl extends PropertyInducingElementImpl
/// ///
/// Clients may not extend, implement or mix-in this class. /// Clients may not extend, implement or mix-in this class.
class TypeAliasElementImpl extends _ExistingElementImpl class TypeAliasElementImpl extends _ExistingElementImpl
with TypeParameterizedElementMixin with TypeParameterizedElementMixin, MacroTargetElement
implements TypeAliasElement { implements TypeAliasElement {
/// Is `true` if the element has direct or indirect reference to itself /// Is `true` if the element has direct or indirect reference to itself
/// from anywhere except a class element or type parameter bounds. /// from anywhere except a class element or type parameter bounds.

View file

@ -932,12 +932,14 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
} }
@override @override
void visitGenericTypeAlias(GenericTypeAlias node) { void visitGenericTypeAlias(covariant GenericTypeAliasImpl node) {
var element = node.declaredElement as TypeAliasElementImpl;
_checkForBuiltInIdentifierAsName( _checkForBuiltInIdentifierAsName(
node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME); node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
_checkForMainFunction1(node.name, node.declaredElement!); _checkForMainFunction1(node.name, node.declaredElement!);
_checkForTypeAliasCannotReferenceItself( _checkForTypeAliasCannotReferenceItself(
node.name, node.declaredElement as TypeAliasElementImpl); node.name, node.declaredElement as TypeAliasElementImpl);
_reportMacroDiagnostics(element);
super.visitGenericTypeAlias(node); super.visitGenericTypeAlias(node);
} }
@ -6420,6 +6422,8 @@ class _MacroTypeAnnotationLocationConverter {
TypeAnnotationLocation location, TypeAnnotationLocation location,
) { ) {
switch (location) { switch (location) {
case AliasedTypeLocation():
return _aliasedType(location);
case ElementTypeLocation(): case ElementTypeLocation():
var element = location.element; var element = location.element;
return libraryVerificationContext.declarationByElement(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( _MacroSyntacticTypeAnnotationLocation? _extendsClause(
ExtendsClauseTypeLocation location, ExtendsClauseTypeLocation location,
) { ) {

View file

@ -149,6 +149,7 @@ class Tag {
} }
enum TypeAnnotationLocationKind { enum TypeAnnotationLocationKind {
aliasedType,
element, element,
extendsClause, extendsClause,
formalParameter, formalParameter,

View file

@ -2378,6 +2378,9 @@ class ResolutionReader {
TypeAnnotationLocation readTypeAnnotationLocation() { TypeAnnotationLocation readTypeAnnotationLocation() {
var kind = readEnum(TypeAnnotationLocationKind.values); var kind = readEnum(TypeAnnotationLocationKind.values);
switch (kind) { switch (kind) {
case TypeAnnotationLocationKind.aliasedType:
var parent = readTypeAnnotationLocation();
return AliasedTypeLocation(parent);
case TypeAnnotationLocationKind.element: case TypeAnnotationLocationKind.element:
var element = readElement()!; var element = readElement()!;
return ElementTypeLocation(element); return ElementTypeLocation(element);
@ -2603,6 +2606,7 @@ class TypeAliasElementLinkedData
element.metadata = reader._readAnnotationList( element.metadata = reader._readAnnotationList(
unitElement: unitElement, unitElement: unitElement,
); );
element.macroDiagnostics = reader.readMacroDiagnostics();
_readTypeParameters(reader, element.typeParameters); _readTypeParameters(reader, element.typeParameters);
element.aliasedElement = reader._readAliasedElement(unitElement); element.aliasedElement = reader._readAliasedElement(unitElement);
element.aliasedType = reader.readRequiredType(); element.aliasedType = reader.readRequiredType();

View file

@ -647,6 +647,7 @@ class BundleWriter {
TypeAliasElementFlags.write(_sink, element); TypeAliasElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata); _resolutionSink._writeAnnotationList(element.metadata);
_resolutionSink.writeMacroDiagnostics(element.macroDiagnostics);
_writeTypeParameters(element.typeParameters, () { _writeTypeParameters(element.typeParameters, () {
_resolutionSink._writeAliasedElement(element.aliasedElement); _resolutionSink._writeAliasedElement(element.aliasedElement);
@ -982,6 +983,9 @@ class ResolutionSink extends _SummaryDataWriter {
void writeTypeAnnotationLocation(TypeAnnotationLocation location) { void writeTypeAnnotationLocation(TypeAnnotationLocation location) {
switch (location) { switch (location) {
case AliasedTypeLocation():
writeEnum(TypeAnnotationLocationKind.aliasedType);
writeTypeAnnotationLocation(location.parent);
case ElementTypeLocation(): case ElementTypeLocation():
writeEnum(TypeAnnotationLocationKind.element); writeEnum(TypeAnnotationLocationKind.element);
writeElement(location.element); writeElement(location.element);

View file

@ -218,8 +218,14 @@ class LibraryMacroApplier {
// TODO(scheglov): implement it // TODO(scheglov): implement it
break; break;
case ast.GenericTypeAliasImpl(): case ast.GenericTypeAliasImpl():
// TODO(scheglov): implement it await _addAnnotations(
break; libraryElement: libraryElement,
container: container,
targetNode: declaration,
targetNodeElement: declaration.declaredElement,
targetDeclarationKind: macro.DeclarationKind.typeAlias,
annotations: declaration.metadata,
);
case ast.MixinDeclarationImpl(): case ast.MixinDeclarationImpl():
final element = declaration.declaredElement!; final element = declaration.declaredElement!;
final declarationElement = element.augmented?.declaration ?? element; final declarationElement = element.augmented?.declaration ?? element;

View file

@ -129,6 +129,8 @@ class DeclarationBuilder {
return fromNode.methodDeclaration(node); return fromNode.methodDeclaration(node);
case ast.MixinDeclarationImpl(): case ast.MixinDeclarationImpl():
return fromNode.mixinDeclaration(node); return fromNode.mixinDeclaration(node);
case ast.GenericTypeAliasImpl():
return fromNode.typeAliasDeclaration(node);
case ast.VariableDeclaration(): case ast.VariableDeclaration():
return fromNode.variableDeclaration(node); return fromNode.variableDeclaration(node);
} }
@ -579,6 +581,9 @@ class DeclarationBuilderFromElement {
final Map<ExecutableElement, MethodDeclarationImpl> _methodMap = final Map<ExecutableElement, MethodDeclarationImpl> _methodMap =
Map.identity(); Map.identity();
final Map<TypeAliasElementImpl, TypeAliasDeclarationImpl> _typeAliasMap =
Map.identity();
final Map<TypeParameterElement, macro.TypeParameterDeclarationImpl> final Map<TypeParameterElement, macro.TypeParameterDeclarationImpl>
_typeParameterDeclarationMap = Map.identity(); _typeParameterDeclarationMap = Map.identity();
@ -707,6 +712,12 @@ class DeclarationBuilderFromElement {
return _variableMap[element] ??= _topLevelVariableElement(element); return _variableMap[element] ??= _topLevelVariableElement(element);
} }
macro.TypeAliasDeclarationImpl typeAliasElement(
TypeAliasElementImpl element,
) {
return _typeAliasMap[element] ??= _typeAliasElement(element);
}
/// See [macro.DeclarationPhaseIntrospector.typeDeclarationOf]. /// See [macro.DeclarationPhaseIntrospector.typeDeclarationOf].
macro.TypeDeclarationImpl typeDeclarationOf(Element element) { macro.TypeDeclarationImpl typeDeclarationOf(Element element) {
switch (element) { switch (element) {
@ -720,6 +731,8 @@ class DeclarationBuilderFromElement {
return extensionTypeElement(element); return extensionTypeElement(element);
case MixinElementImpl(): case MixinElementImpl():
return mixinElement(element); return mixinElement(element);
case TypeAliasElementImpl():
return typeAliasElement(element);
default: default:
// TODO(scheglov): other elements // TODO(scheglov): other elements
throw macro.MacroImplementationExceptionImpl( 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( macro.TypeParameterImpl _typeParameter(
TypeParameterElement element, 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]. /// See [macro.DeclarationPhaseIntrospector.typeDeclarationOf].
macro.TypeDeclarationImpl typeDeclarationOf(ast.AstNode node) { macro.TypeDeclarationImpl typeDeclarationOf(ast.AstNode node) {
switch (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( macro.TypeAnnotationImpl _typeAnnotationFunctionReturnType(
ast.FunctionDeclaration node, 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 { abstract class TypeAnnotationWithLocation implements macro.TypeAnnotation {
TypeAnnotationLocation get location; TypeAnnotationLocation get location;
} }

View file

@ -5,6 +5,12 @@
import 'package:_fe_analyzer_shared/src/macros/api.dart' as macro; import 'package:_fe_analyzer_shared/src/macros/api.dart' as macro;
import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/element.dart';
final class AliasedTypeLocation extends TypeAnnotationLocation {
final TypeAnnotationLocation parent;
AliasedTypeLocation(this.parent);
}
final class ElementTypeLocation extends TypeAnnotationLocation { final class ElementTypeLocation extends TypeAnnotationLocation {
final Element element; final Element element;

View file

@ -273,6 +273,16 @@ typedef F = void Function();
expect(result, isNull); expect(result, isNull);
} }
test_genericTypeAlias() async {
await resolveTestCode(r'''
typedef A = List<int>;
''');
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 { test_getter_class() async {
await resolveTestCode(r''' await resolveTestCode(r'''
class A { class A {

View file

@ -743,6 +743,19 @@ class A {
]); ]);
} }
test_diagnostic_report_atTypeAnnotation_typeAlias_aliasedType() async {
await assertErrorsInCode('''
import 'diagnostic.dart';
@ReportAtTypeAnnotation([
'aliasedType',
])
typedef A = List<int>;
''', [
error(WarningCode.MACRO_WARNING, 85, 9),
]);
}
test_diagnostic_report_contextMessages_superClassMethods() async { test_diagnostic_report_contextMessages_superClassMethods() async {
var a = newFile('$testPackageLibPath/a.dart', r''' var a = newFile('$testPackageLibPath/a.dart', r'''
class A { class A {

View file

@ -743,6 +743,9 @@ class _ElementWriter {
void _writeMacroDiagnostics(Element e) { void _writeMacroDiagnostics(Element e) {
void writeTypeAnnotationLocation(TypeAnnotationLocation location) { void writeTypeAnnotationLocation(TypeAnnotationLocation location) {
switch (location) { switch (location) {
case AliasedTypeLocation():
writeTypeAnnotationLocation(location.parent);
_sink.writelnWithIndent('AliasedTypeLocation');
case ElementTypeLocation(): case ElementTypeLocation():
_sink.writelnWithIndent('ElementTypeLocation'); _sink.writelnWithIndent('ElementTypeLocation');
_sink.withIndent(() { _sink.withIndent(() {
@ -1370,6 +1373,8 @@ class _ElementWriter {
_writeReturnType(aliasedElement.returnType); _writeReturnType(aliasedElement.returnType);
}); });
} }
_writeMacroDiagnostics(e);
}); });
_assertNonSyntheticElementSelf(e); _assertNonSyntheticElementSelf(e);

View file

@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a // 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. // BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:_fe_analyzer_shared/src/macros/api.dart'; import 'package:_fe_analyzer_shared/src/macros/api.dart';
/*macro*/ class AskFieldsWillThrow implements ClassDefinitionMacro { /*macro*/ class AskFieldsWillThrow implements ClassDefinitionMacro {
@ -144,6 +146,7 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart';
FunctionDeclarationsMacro, FunctionDeclarationsMacro,
FieldDeclarationsMacro, FieldDeclarationsMacro,
MethodDeclarationsMacro, MethodDeclarationsMacro,
TypeAliasDeclarationsMacro,
VariableDeclarationsMacro { VariableDeclarationsMacro {
final List<String> pathList; final List<String> pathList;
@ -169,6 +172,11 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart';
await _report(declaration, builder); await _report(declaration, builder);
} }
@override
Future<void> buildDeclarationsForTypeAlias(declaration, builder) async {
await _report(declaration, builder);
}
@override @override
buildDeclarationsForVariable(declaration, builder) async { buildDeclarationsForVariable(declaration, builder) async {
await _report(declaration, builder); 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 (current is VariableDeclaration) {
if (step == 'variableType') { if (step == 'variableType') {
return current.type; return current.type;

View file

@ -19,6 +19,7 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart';
LibraryDeclarationsMacro, LibraryDeclarationsMacro,
MethodDeclarationsMacro, MethodDeclarationsMacro,
MixinDeclarationsMacro, MixinDeclarationsMacro,
TypeAliasDeclarationsMacro,
VariableDeclarationsMacro { VariableDeclarationsMacro {
final Set<Object?> withDetailsFor; final Set<Object?> withDetailsFor;
final bool withMetadata; final bool withMetadata;
@ -163,6 +164,16 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart';
}); });
} }
@override
Future<void> buildDeclarationsForTypeAlias(
TypeAliasDeclaration declaration,
DeclarationBuilder builder,
) async {
await _write(builder, declaration, (printer) async {
await printer.writeTypeAliasDeclaration(declaration);
});
}
@override @override
Future<void> buildDeclarationsForVariable( Future<void> buildDeclarationsForVariable(
VariableDeclaration declaration, VariableDeclaration declaration,
@ -438,6 +449,8 @@ class _Printer {
await writeFunctionDeclaration(declaration); await writeFunctionDeclaration(declaration);
case MixinDeclaration(): case MixinDeclaration():
await writeMixinDeclaration(declaration); await writeMixinDeclaration(declaration);
case TypeAliasDeclaration():
await writeTypeAliasDeclaration(declaration);
case VariableDeclaration(): case VariableDeclaration():
await writeVariable(declaration); await writeVariable(declaration);
default: default:
@ -652,6 +665,24 @@ class _Printer {
}); });
} }
Future<void> 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<void> writeVariable(VariableDeclaration e) async { Future<void> writeVariable(VariableDeclaration e) async {
sink.writelnWithIndent(e.identifier.name); sink.writelnWithIndent(e.identifier.name);

View file

@ -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<int>;
''');
configuration
..withConstructors = false
..withMetadata = false;
checkElementText(library, r'''
library
imports
package:test/diagnostic.dart
definingUnit
typeAliases
A @81
aliasedType: List<int>
macroDiagnostics
MacroDiagnostic
message: MacroDiagnosticMessage
message: Reported message
target: TypeAnnotationMacroDiagnosticTarget
ElementTypeLocation
element: self::@typeAlias::A
AliasedTypeLocation
severity: warning
''');
}
test_macroDiagnostics_report_contextMessages() async { test_macroDiagnostics_report_contextMessages() async {
newFile( newFile(
'$testPackageLibPath/diagnostic.dart', '$testPackageLibPath/diagnostic.dart',
@ -9002,6 +9040,17 @@ foo
'''); ''');
} }
test_unit_typeAlias() async {
newFile('$testPackageLibPath/a.dart', r'''
typedef A = List<int>;
''');
await _assertIntrospectText('A', r'''
typedef A
aliasedType: List<int>
''');
}
test_unit_variable() async { test_unit_variable() async {
newFile('$testPackageLibPath/a.dart', r''' newFile('$testPackageLibPath/a.dart', r'''
final foo = 0; final foo = 0;
@ -11416,6 +11465,16 @@ class A
'''); ''');
} }
test_typedef_modern_namedType() async {
await _assertIntrospectText(r'''
@Introspect()
typedef X = List<int>;
''', r'''
typedef X
aliasedType: List<int>
''');
}
test_unit_function() async { test_unit_function() async {
await _assertIntrospectText(r''' await _assertIntrospectText(r'''
@Introspect() @Introspect()

View file

@ -264,3 +264,22 @@ abstract interface class ExtensionTypeDefinitionMacro implements Macro {
FutureOr<void> buildDefinitionForExtensionType( FutureOr<void> buildDefinitionForExtensionType(
ExtensionTypeDeclaration extension, TypeDefinitionBuilder builder); 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<void> 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<void> buildDeclarationsForTypeAlias(
TypeAliasDeclaration declaration,
DeclarationBuilder builder,
);
}