[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:
committed by
Commit Queue
parent
9683fd4a50
commit
fe2ea6a55f
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user