[vm] Add minimal support for mirrors of extension type members

Support extension type members in dart:mirrors similarly to extensions.
Add MethodMirror.isExtensionTypeMember and VariableMirror.isExtensionTypeMember.

TEST=tests/lib/mirrors/method_mirror_extension_test.dart
Fixes https://github.com/dart-lang/sdk/issues/54266

CoreLibraryReviewExempt: VM-only dart:mirrors API change
Change-Id: I9c1c22118ee52e98d5013c881eb6ad5686df656e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340284
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Alexander Markov
2023-12-07 21:48:50 +00:00
committed by Commit Queue
parent 9683fd4a50
commit fe2ea6a55f
6 changed files with 123 additions and 16 deletions
+8 -3
View File
@@ -244,7 +244,8 @@ static InstancePtr CreateMethodMirror(const Function& func,
args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func)));
String& name = String::Handle(func.name());
name = String::ScrubNameRetainPrivate(name, func.is_extension_member());
name = String::ScrubNameRetainPrivate(
name, func.is_extension_member() || func.is_extension_type_member());
args.SetAt(1, name);
args.SetAt(2, owner_mirror);
args.SetAt(3, instantiator);
@@ -273,6 +274,8 @@ static InstancePtr CreateMethodMirror(const Function& func,
kind_flags |= (static_cast<intptr_t>(is_synthetic) << Mirrors::kSynthetic);
kind_flags |= (static_cast<intptr_t>(func.is_extension_member())
<< Mirrors::kExtensionMember);
kind_flags |= (static_cast<intptr_t>(func.is_extension_type_member())
<< Mirrors::kExtensionTypeMember);
args.SetAt(5, Smi::Handle(Smi::New(kind_flags)));
return CreateMirror(Symbols::_MethodMirror(), args);
@@ -285,7 +288,7 @@ static InstancePtr CreateVariableMirror(const Field& field,
const String& name = String::Handle(field.name());
const Array& args = Array::Handle(Array::New(8));
const Array& args = Array::Handle(Array::New(9));
args.SetAt(0, field_ref);
args.SetAt(1, name);
args.SetAt(2, owner_mirror);
@@ -294,6 +297,7 @@ static InstancePtr CreateVariableMirror(const Field& field,
args.SetAt(5, Bool::Get(field.is_final()));
args.SetAt(6, Bool::Get(field.is_const()));
args.SetAt(7, Bool::Get(field.is_extension_member()));
args.SetAt(8, Bool::Get(field.is_extension_type_member()));
return CreateMirror(Symbols::_VariableMirror(), args);
}
@@ -1264,7 +1268,8 @@ DEFINE_NATIVE_ENTRY(ClosureMirror_function, 0, 1) {
bool callable = closure.IsCallable(&function);
if (callable) {
const Function& parent = Function::Handle(function.parent_function());
if (function.IsImplicitClosureFunction() || parent.is_extension_member()) {
if (function.IsImplicitClosureFunction() || parent.is_extension_member() ||
parent.is_extension_type_member()) {
// The VM uses separate Functions for tear-offs, but the mirrors consider
// the tear-offs to be the same as the torn-off methods. Avoid handing out
// a reference to the tear-off here to avoid a special case in the
+2 -1
View File
@@ -22,7 +22,8 @@ class Mirrors : public AllStatic {
V(kFactoryCtor) \
V(kExternal) \
V(kSynthetic) \
V(kExtensionMember)
V(kExtensionMember) \
V(kExtensionTypeMember)
// These offsets much be kept in sync with those in mirrors_impl.dart.
enum KindShifts {
+26 -11
View File
@@ -176,6 +176,7 @@ class _SyntheticAccessor implements MethodMirror {
bool get isRedirectingConstructor => false;
bool get isAbstract => false;
bool get isExtensionMember => false;
bool get isExtensionTypeMember => false;
bool get isSetter => !isGetter;
bool get isPrivate => _n(simpleName).startsWith('_');
@@ -213,6 +214,7 @@ class _SyntheticSetterParameter implements ParameterMirror {
bool get isFinal => true;
bool get isPrivate => false;
bool get isExtensionMember => false;
bool get isExtensionTypeMember => false;
bool get hasDefaultValue => false;
InstanceMirror? get defaultValue => null;
SourceLocation? get location => null;
@@ -1091,6 +1093,7 @@ class _MethodMirror extends _DeclarationMirror implements MethodMirror {
static const kExternal = 8;
static const kSynthetic = 9;
static const kExtensionMember = 10;
static const kExtensionTypeMember = 11;
// These offsets much be kept in sync with those in mirrors.h.
bool get isAbstract => 0 != (_kindFlags & (1 << kAbstract));
@@ -1106,6 +1109,8 @@ class _MethodMirror extends _DeclarationMirror implements MethodMirror {
bool get isExternal => 0 != (_kindFlags & (1 << kExternal));
bool get isSynthetic => 0 != (_kindFlags & (1 << kSynthetic));
bool get isExtensionMember => 0 != (_kindFlags & (1 << kExtensionMember));
bool get isExtensionTypeMember =>
0 != (_kindFlags & (1 << kExtensionTypeMember));
static const _operators = const [
"%", "&", "*", "+", "-", "/", "<", "<<", //
@@ -1205,9 +1210,18 @@ class _VariableMirror extends _DeclarationMirror implements VariableMirror {
final bool isFinal;
final bool isConst;
final bool isExtensionMember;
final bool isExtensionTypeMember;
_VariableMirror._(reflectee, String simpleName, this.owner, this._type,
this.isStatic, this.isFinal, this.isConst, this.isExtensionMember)
_VariableMirror._(
reflectee,
String simpleName,
this.owner,
this._type,
this.isStatic,
this.isFinal,
this.isConst,
this.isExtensionMember,
this.isExtensionTypeMember)
: super._(reflectee, _s(simpleName));
bool get isTopLevel => owner is LibraryMirror;
@@ -1256,15 +1270,16 @@ class _ParameterMirror extends _VariableMirror implements ParameterMirror {
this._defaultValueReflectee,
this._unmirroredMetadata)
: super._(
reflectee,
simpleName,
owner,
null, // We override the type.
false, // isStatic does not apply.
isFinal,
false, // Not const.
false // Not extension member.
);
reflectee,
simpleName,
owner,
null, // We override the type.
false, // isStatic does not apply.
isFinal,
false, // Not const.
false, // Not extension member.
false, // Not extension type member.
);
Object? _defaultValueReflectee;
InstanceMirror? _defaultValue;
+10
View File
@@ -1074,6 +1074,11 @@ abstract class MethodMirror implements DeclarationMirror {
*/
bool get isExtensionMember;
/**
* Is the reflectee an extension type method?
*/
bool get isExtensionTypeMember;
/**
* Whether this mirror is equal to [other].
*
@@ -1120,6 +1125,11 @@ abstract class VariableMirror implements DeclarationMirror {
*/
bool get isExtensionMember;
/**
* Is the reflectee an extension type member?
*/
bool get isExtensionTypeMember;
/**
* Whether this mirror is equal to [other].
*
@@ -0,0 +1,75 @@
// Copyright (c) 2023, 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 "dart:mirrors";
import "package:expect/expect.dart";
extension type T1(int value) {}
extension type T2(int value) {
T2 add(int arg) => T2(value + arg);
}
extension type T3(int value) implements int {
static T3 staticAdd(T3 a, int b) => T3(a + b);
static String staticField = 'hi';
}
class C {
final int value;
C(this.value);
C add(int arg) => C(value + arg);
}
checkIsExtensionTypeMember(closure, kind, simpleName) {
var closureMirror = reflect(closure) as ClosureMirror;
var methodMirror = closureMirror.function;
Expect.equals(Symbol(simpleName), methodMirror.simpleName);
Expect.equals(
kind, methodMirror.isExtensionTypeMember, "isExtensionTypeMember");
}
String? getExtensionTypeName(sym) {
final extensionTypeNames = {'T1', 'T2', 'T3'};
for (final extTypeName in extensionTypeNames) {
if (MirrorSystem.getName(sym).startsWith(extTypeName)) {
return extTypeName;
}
}
return null;
}
void testExtensionTypeMembers(sym, mirror) {
String? extensionTypeName = getExtensionTypeName(sym);
if (mirror is MethodMirror) {
final methodMirror = mirror as MethodMirror;
if (extensionTypeName != null) {
Expect.equals(
true, methodMirror.isExtensionTypeMember, "isExtensionTypeMember");
Expect.isTrue(
methodMirror.simpleName.toString().contains('$extensionTypeName.'));
} else {
Expect.equals(
false, methodMirror.isExtensionTypeMember, "isExtensionTypeMember");
}
} else if (mirror is VariableMirror) {
var variableMirror = mirror as VariableMirror;
if (extensionTypeName != null) {
Expect.equals(
true, variableMirror.isExtensionTypeMember, "isExtensionTypeMember");
} else {
Expect.equals(
false, variableMirror.isExtensionTypeMember, "isExtensionTypeMember");
}
}
}
main() {
checkIsExtensionTypeMember(C(42).add, false, 'add');
checkIsExtensionTypeMember(T2(42).add, true, 'T2.add');
checkIsExtensionTypeMember(T3.staticAdd, true, 'T3.staticAdd');
var libraryMirror = reflectClass(C).owner as LibraryMirror;
libraryMirror.declarations.forEach(testExtensionTypeMembers);
}
@@ -42,7 +42,8 @@ checkKinds(method, kinds) {
Expect.equals(kinds[2], method.isGetter, "isGetter");
Expect.equals(kinds[3], method.isSetter, "isSetter");
Expect.equals(kinds[4], method.isConstructor, "isConstructor");
Expect.equals(false, method.isExtensionMember, "isExtension");
Expect.equals(false, method.isExtensionMember, "isExtensionMember");
Expect.equals(false, method.isExtensionTypeMember, "isExtensionTypeMember");
}
main() {