Macro. Find the declaration to introspect by URI and name, when from elements.

This makes the output more compact.

This also allows to introspect declarations that are otherwise hard
to reference, such as functions. I will add more in following CLs.

Change-Id: I4775beca6aac5e642028b05f40aac31b079ba9de
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/341391
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Phil Quitslund <pquitslund@google.com>
This commit is contained in:
Konstantin Shcheglov
2023-12-14 02:27:26 +00:00
committed by Commit Queue
parent 1800039c2a
commit 55bd60be32
4 changed files with 536 additions and 904 deletions
@@ -904,9 +904,8 @@ class _DefinitionPhaseIntrospector extends _DeclarationPhaseIntrospector
@override
Future<macro.Declaration> declarationOf(
covariant macro.Identifier identifier,
) {
// TODO(scheglov): implement declarationOf
throw UnimplementedError();
) async {
return declarationBuilder.declarationOf(identifier);
}
@override
@@ -105,6 +105,26 @@ class DeclarationBuilder {
throw UnimplementedError('${node.runtimeType}');
}
/// See [macro.DefinitionPhaseIntrospector.declarationOf].
macro.DeclarationImpl declarationOf(macro.Identifier identifier) {
if (identifier is! IdentifierImpl) {
throw ArgumentError('Not analyzer identifier.');
}
final element = identifier.element;
if (element == null) {
throw ArgumentError('Identifier without element.');
}
final node = nodeOfElement(element);
if (node != null) {
// TODO(scheglov): implement
throw UnimplementedError();
} else {
return fromElement.declarationOf(element);
}
}
macro.TypeAnnotation inferOmittedType(
macro.OmittedTypeAnnotation omittedType,
) {
@@ -437,10 +457,40 @@ class DeclarationBuilderFromElement {
return _constructorMap[element] ??= _constructorElement(element);
}
/// See [macro.DefinitionPhaseIntrospector.declarationOf].
macro.DeclarationImpl declarationOf(Element element) {
switch (element) {
case FunctionElementImpl():
return functionElement(element);
default:
// TODO(scheglov): other elements
return typeDeclarationOf(element);
}
}
macro.FieldDeclarationImpl fieldElement(FieldElementImpl element) {
return _fieldMap[element] ??= _fieldElement(element);
}
FunctionDeclarationImpl functionElement(ExecutableElementImpl element) {
return FunctionDeclarationImpl._(
element: element,
id: macro.RemoteInstance.uniqueId,
identifier: identifier(element),
library: library(element),
metadata: _buildMetadata(element),
hasBody: !element.isAbstract,
hasExternal: element.isExternal,
isGetter: element is PropertyAccessorElementImpl && element.isGetter,
isOperator: element.isOperator,
isSetter: element is PropertyAccessorElementImpl && element.isSetter,
namedParameters: _namedFormalParameters(element.parameters),
positionalParameters: _positionalFormalParameters(element.parameters),
returnType: _dartType(element.returnType),
typeParameters: element.typeParameters.map(_typeParameter).toList(),
);
}
macro.IdentifierImpl identifier(Element element) {
final name = switch (element) {
PropertyAccessorElement(isSetter: true) => element.displayName,
@@ -483,12 +533,14 @@ class DeclarationBuilderFromElement {
/// See [macro.DeclarationPhaseIntrospector.typeDeclarationOf].
macro.TypeDeclarationImpl typeDeclarationOf(Element element) {
if (element is ClassElementImpl) {
return classElement(element);
} else if (element is MixinElementImpl) {
return mixinElement(element);
} else {
throw ArgumentError('element: $element');
switch (element) {
case ClassElementImpl():
return classElement(element);
case MixinElementImpl():
return mixinElement(element);
default:
// TODO(scheglov): other elements
throw ArgumentError('element: $element');
}
}
@@ -131,6 +131,58 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart';
}
}
/*macro*/ class IntrospectDeclaration implements FunctionDefinitionMacro {
final String uriStr;
final String name;
final bool withUnnamedConstructor;
IntrospectDeclaration({
required this.uriStr,
required this.name,
this.withUnnamedConstructor = false,
});
@override
Future<void> buildDefinitionForFunction(declaration, builder) async {
final buffer = StringBuffer();
final sink = TreeStringSink(
sink: buffer,
indent: '',
);
final printer = _Printer(
sink: sink,
withMetadata: true,
withUnnamedConstructor: withUnnamedConstructor,
introspector: builder,
withDetailsFor: {name},
);
// ignore: deprecated_member_use
final identifier = await builder.resolveIdentifier(
Uri.parse(uriStr),
name,
);
final declaration = await builder.declarationOf(identifier);
switch (declaration) {
case ClassDeclaration():
await printer.writeClassDeclaration(declaration);
case FunctionDeclaration():
await printer.writeFunctionDeclaration(declaration);
case MixinDeclaration():
await printer.writeMixinDeclaration(declaration);
default:
throw UnimplementedError('${declaration.runtimeType}');
}
final text = buffer.toString();
builder.augment(
FunctionBodyCode.fromString('=> r"""$text""";'),
);
}
}
/// Wrapper around a [StringSink] for writing tree structures.
class TreeStringSink {
final StringSink _sink;
File diff suppressed because it is too large Load Diff