Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions packages/reflectable/lib/mirrors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ abstract class CombinatorMirror implements Mirror {

/// A [TypeMirror] reflects a Dart language class, typedef,
/// function type or type variable.
abstract class TypeMirror implements DeclarationMirror {
abstract class TypeMirror<T> implements DeclarationMirror {
/// Returns true if this mirror reflects dynamic, a non-generic class or
/// typedef, or an instantiated generic class or typedef with support in
/// the execution mode. Otherwise, returns false.
Expand Down Expand Up @@ -817,10 +817,16 @@ abstract class TypeMirror implements DeclarationMirror {
/// Returns true iff this type mirror represents a potentially non-nullable
/// type.
bool get isPotentiallyNonNullable;

/// Invokes the provided function with the reflected type as a type argument.
///
/// Allows executing generic code with the actual runtime type represented
/// by this mirror.
R callWithReflectedType<R>(R Function<X>() f);
}

/// A [ClassMirror] reflects a Dart language class.
abstract class ClassMirror implements TypeMirror, ObjectMirror {
abstract class ClassMirror<T> implements TypeMirror<T>, ObjectMirror {
/// A mirror on the superclass on the reflectee.
///
/// If this type is [:Object:], the superclass will be null.
Expand Down Expand Up @@ -1077,7 +1083,7 @@ abstract class FunctionTypeMirror implements ClassMirror {
}

/// A [TypeVariableMirror] represents a type parameter of a generic type.
abstract class TypeVariableMirror extends TypeMirror {
abstract class TypeVariableMirror<T> extends TypeMirror<T> {
/// A mirror on the type that is the upper bound of this type variable.
///
/// Required capabilities: [upperBound] requires a [TypeCapability].
Expand Down
2 changes: 1 addition & 1 deletion packages/reflectable/lib/reflectable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ abstract class ReflectableInterface {
///
/// Throws a [NoSuchCapabilityError] if the class of [o] has not been marked
/// for reflection.
InstanceMirror reflect(Object o);
InstanceMirror reflect<T extends Object>(T o);

/// Returns true if this reflector has capabilities for the given Type.
bool canReflectType(Type type);
Expand Down
64 changes: 40 additions & 24 deletions packages/reflectable/lib/src/reflectable_builder_based.dart
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,15 @@ class ReflectorData {
return typeToTypeMirrorCache[type];
}

ClassMirror? classMirrorForInstance(Object? instance) {
ClassMirror? classMirrorForInstance<T>(Object? instance) {
TypeMirror? result = typeMirrorForType(instance.runtimeType);

if (result is ClassMirror) return result;
// Check if we have a generic class that matches.
for (TypeMirror typeMirror in _typeToTypeMirrorCache!.values) {
if (typeMirror is GenericClassMirrorImpl) {
if (typeMirror._isGenericRuntimeTypeOf(instance)) {
return _createInstantiatedGenericClass(
return _createInstantiatedGenericClass<T>(
typeMirror,
instance.runtimeType,
null,
Expand Down Expand Up @@ -205,15 +206,15 @@ abstract class _DataCaching {
}
}

class _InstanceMirrorImpl extends _DataCaching implements InstanceMirror {
class _InstanceMirrorImpl<T> extends _DataCaching implements InstanceMirror {
@override
final ReflectableImpl _reflector;

@override
final Object? reflectee;

_InstanceMirrorImpl(this.reflectee, this._reflector) {
_type = _data.classMirrorForInstance(reflectee) as ClassMirrorBase?;
_type = _data.classMirrorForInstance<T>(reflectee) as ClassMirrorBase?;
if (_type == null) {
// If there is no `TypeCapability` and also no `InstanceInvokeCapability`
// then can do almost nothing. Nevertheless, we can still offer a
Expand Down Expand Up @@ -390,7 +391,8 @@ class _InstanceMirrorImpl extends _DataCaching implements InstanceMirror {

typedef MethodMirrorProvider = MethodMirror? Function(String methodName);

abstract class ClassMirrorBase extends _DataCaching implements ClassMirror {
abstract class ClassMirrorBase<T> extends _DataCaching
implements ClassMirror<T> {
/// The reflector which represents the mirror system that this
/// mirror belongs to.
@override
Expand Down Expand Up @@ -974,9 +976,12 @@ abstract class ClassMirrorBase extends _DataCaching implements ClassMirror {
if (_superclassIndex == null) return null; // Superclass of [Object].
return _data.typeMirrors[_superclassIndex] as ClassMirrorBase?;
}

@override
D callWithReflectedType<D>(D Function<X>() f) => f<T>();
}

class NonGenericClassMirrorImpl extends ClassMirrorBase {
class NonGenericClassMirrorImpl<T> extends ClassMirrorBase<T> {
NonGenericClassMirrorImpl(
super.simpleName,
super.qualifiedName,
Expand Down Expand Up @@ -1067,7 +1072,7 @@ class NonGenericClassMirrorImpl extends ClassMirrorBase {

typedef InstanceChecker = bool Function(Object?);

class GenericClassMirrorImpl extends ClassMirrorBase {
class GenericClassMirrorImpl<T> extends ClassMirrorBase<T> {
/// Used to enable instance checks. Let O be an instance and let C denote the
/// generic class modeled by this mirror. The check is then such that the
/// result is true iff there exists a list of type arguments X1..Xk such that
Expand Down Expand Up @@ -1216,7 +1221,7 @@ class GenericClassMirrorImpl extends ClassMirrorBase {
String toString() => 'GenericClassMirrorImpl($qualifiedName)';
}

class InstantiatedGenericClassMirrorImpl extends ClassMirrorBase {
class InstantiatedGenericClassMirrorImpl<T> extends ClassMirrorBase<T> {
final GenericClassMirrorImpl _originalDeclaration;
final Type? _reflectedType;

Expand Down Expand Up @@ -1360,11 +1365,14 @@ class InstantiatedGenericClassMirrorImpl extends ClassMirrorBase {
@override
int get hashCode => originalDeclaration.hashCode ^ _reflectedType.hashCode;

@override
D callWithReflectedType<D>(D Function<X>() f) => f<T>();

@override
String toString() => 'InstantiatedGenericClassMirrorImpl($qualifiedName)';
}

InstantiatedGenericClassMirrorImpl _createInstantiatedGenericClass(
InstantiatedGenericClassMirrorImpl<T> _createInstantiatedGenericClass<T>(
GenericClassMirrorImpl genericClassMirror,
Type? reflectedType,
List<int>? reflectedTypeArguments, [
Expand All @@ -1373,7 +1381,7 @@ InstantiatedGenericClassMirrorImpl _createInstantiatedGenericClass(
// TODO(eernst) implement: Pass a representation of type arguments to this
// method, and create an instantiated generic class which includes that
// information.
return InstantiatedGenericClassMirrorImpl(
return InstantiatedGenericClassMirrorImpl<T>(
genericClassMirror.simpleName,
genericClassMirror.qualifiedName,
descriptor ?? genericClassMirror._descriptor,
Expand Down Expand Up @@ -1573,6 +1581,11 @@ class TypeVariableMirrorImpl extends _DataCaching
}
return _data.typeMirrors[_ownerIndex];
}

@override
D callWithReflectedType<D>(D Function<X>() f) => throw UnsupportedError(
'Attempt to call `callWithReflectedType` on type variable $simpleName',
);
}

class LibraryMirrorImpl extends _DataCaching implements LibraryMirror {
Expand Down Expand Up @@ -1820,7 +1833,7 @@ class LibraryMirrorImpl extends _DataCaching implements LibraryMirror {
throw unimplementedError('libraryDependencies');
}

class MethodMirrorImpl extends _DataCaching implements MethodMirror {
class MethodMirrorImpl<T> extends _DataCaching implements MethodMirror {
/// An encoding of the attributes and kind of this mirror.
final int _descriptor;

Expand Down Expand Up @@ -1997,7 +2010,7 @@ class MethodMirrorImpl extends _DataCaching implements MethodMirror {
if (_hasClassReturnType) {
TypeMirror typeMirror = _data.typeMirrors[_returnTypeIndex];
return _hasGenericReturnType
? _createInstantiatedGenericClass(
? _createInstantiatedGenericClass<T>(
typeMirror as GenericClassMirrorImpl,
null,
_reflectedTypeArgumentsOfReturnType,
Expand Down Expand Up @@ -2307,7 +2320,7 @@ class ImplicitSetterMirrorImpl extends ImplicitAccessorMirrorImpl {
String toString() => 'ImplicitSetterMirrorImpl($qualifiedName)';
}

abstract class VariableMirrorBase extends _DataCaching
abstract class VariableMirrorBase<T> extends _DataCaching
implements VariableMirror {
final String _name;
final int _descriptor;
Expand Down Expand Up @@ -2401,15 +2414,15 @@ abstract class VariableMirrorBase extends _DataCaching
if (typeMirror.isNullable != _isNullable ||
typeMirror.isNonNullable != _isNonNullable) {
if (_isGenericType) {
return _createInstantiatedGenericClass(
return _createInstantiatedGenericClass<T>(
typeMirror as GenericClassMirrorImpl,
hasReflectedType ? reflectedType : null,
_reflectedTypeArguments,
_descriptor,
);
} else {
var classMirror = typeMirror as NonGenericClassMirrorImpl;
return NonGenericClassMirrorImpl(
return NonGenericClassMirrorImpl<T>(
classMirror.simpleName,
classMirror.qualifiedName,
_descriptor,
Expand All @@ -2431,7 +2444,7 @@ abstract class VariableMirrorBase extends _DataCaching
}
} else {
return _isGenericType
? _createInstantiatedGenericClass(
? _createInstantiatedGenericClass<T>(
typeMirror as GenericClassMirrorImpl,
hasReflectedType ? reflectedType : null,
_reflectedTypeArguments,
Expand Down Expand Up @@ -2487,7 +2500,7 @@ abstract class VariableMirrorBase extends _DataCaching
int get hashCode => simpleName.hashCode ^ owner.hashCode;
}

class VariableMirrorImpl extends VariableMirrorBase {
class VariableMirrorImpl<T> extends VariableMirrorBase<T> {
@override
DeclarationMirror get owner {
if (_ownerIndex == noCapabilityIndex) {
Expand Down Expand Up @@ -2532,7 +2545,7 @@ class VariableMirrorImpl extends VariableMirrorBase {
int get hashCode;
}

class ParameterMirrorImpl extends VariableMirrorBase
class ParameterMirrorImpl<T> extends VariableMirrorBase<T>
implements ParameterMirror {
final Object? _defaultValue;

Expand Down Expand Up @@ -2601,7 +2614,7 @@ class ParameterMirrorImpl extends VariableMirrorBase
int get hashCode;
}

abstract class SpecialTypeMirrorImpl implements TypeMirror {
abstract class SpecialTypeMirrorImpl<T> implements TypeMirror<T> {
@override
bool get isPrivate => false;

Expand Down Expand Up @@ -2637,11 +2650,14 @@ abstract class SpecialTypeMirrorImpl implements TypeMirror {

@override
List<Object> get metadata => <Object>[];

@override
D callWithReflectedType<D>(D Function<X>() f) => f<T>();
}

Type _typeOf<X>() => X;

class DynamicMirrorImpl extends SpecialTypeMirrorImpl {
class DynamicMirrorImpl extends SpecialTypeMirrorImpl<dynamic> {
@override
bool get isNullable => true;

Expand Down Expand Up @@ -2669,7 +2685,7 @@ class DynamicMirrorImpl extends SpecialTypeMirrorImpl {
bool isAssignableTo(TypeMirror other) => true;
}

class VoidMirrorImpl extends SpecialTypeMirrorImpl {
class VoidMirrorImpl extends SpecialTypeMirrorImpl<void> {
@override
bool get isNullable => true;

Expand Down Expand Up @@ -2702,7 +2718,7 @@ class VoidMirrorImpl extends SpecialTypeMirrorImpl {
other is DynamicMirrorImpl || other is VoidMirrorImpl;
}

class NeverMirrorImpl extends SpecialTypeMirrorImpl {
class NeverMirrorImpl extends SpecialTypeMirrorImpl<Never> {
final bool hasQuestionMark;

NeverMirrorImpl({this.hasQuestionMark = false});
Expand Down Expand Up @@ -2761,8 +2777,8 @@ abstract class ReflectableImpl extends ReflectableBase
}

@override
InstanceMirror reflect(Object reflectee) {
return _InstanceMirrorImpl(reflectee, this);
InstanceMirror reflect<T extends Object>(T reflectee) {
return _InstanceMirrorImpl<T>(reflectee, this);
}

bool get _hasTypeCapability {
Expand Down
55 changes: 49 additions & 6 deletions packages/reflectable_builder/lib/src/builder_implementation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,49 @@ class _ReflectorDomain {
return 'const $prefix${_reflector.name}()';
}

/// Returns code for generic type arguments to use in mirror declarations.
///
/// Generates a string like `<PrefixClassName>` for generic type parameters
/// in mirror constructors. Returns empty string if the type cannot be
/// represented (e.g., private classes, mixin applications, or non-interface
/// types).
Future<String> _typeGenericCode(
_ImportCollector importCollector, {
DartType? type,
InterfaceElement? element,
}) async {
if (type == null && element == null) {
return '';
}

if (type != null && type is! InterfaceType) {
return '';
}

InterfaceElement classElement =
(type as InterfaceType?)?.element ?? element!;

// MixinApplications cannot be used as type arguments
if (classElement is MixinApplication) {
return '';
}

if (classElement.isPrivate) {
return '';
}

String prefix = importCollector._getPrefix(classElement.library);
if (_isPrivateName(classElement.name)) {
await _severe(
'Cannot access private name `${classElement.name}`',
classElement,
);
return '';
}

return '<$prefix${classElement.name}>';
}

/// Generate the code which will create a `ReflectorData` instance
/// containing the mirrors and other reflection data which is needed for
/// `_reflector` to behave correctly.
Expand Down Expand Up @@ -1706,7 +1749,7 @@ class _ReflectorDomain {
}

if (interfaceElement.typeParameters.isEmpty) {
return "r.NonGenericClassMirrorImpl(r'${classDomain._simpleName}', "
return "r.NonGenericClassMirrorImpl${await _typeGenericCode(importCollector, element: classDomain._interfaceElement)}(r'${classDomain._simpleName}', "
"r'${_qualifiedName(interfaceElement)}', $descriptor, $classIndex, "
'${await _constConstructionCode(importCollector)}, '
'$declarationsCode, $instanceMembersCode, $staticMembersCode, '
Expand Down Expand Up @@ -1792,7 +1835,7 @@ class _ReflectorDomain {
typedefs,
);

return "r.GenericClassMirrorImpl(r'${classDomain._simpleName}', "
return "r.GenericClassMirrorImpl${await _typeGenericCode(importCollector, element: classDomain._interfaceElement)}(r'${classDomain._simpleName}', "
"r'${_qualifiedName(interfaceElement)}', $descriptor, $classIndex, "
'${await _constConstructionCode(importCollector)}, '
'$declarationsCode, $instanceMembersCode, $staticMembersCode, '
Expand Down Expand Up @@ -1889,7 +1932,7 @@ class _ReflectorDomain {
_generatedLibraryId,
)
: null;
return "r.MethodMirrorImpl(r'${element.name}', $descriptor, "
return "r.MethodMirrorImpl${await _typeGenericCode(importCollector, type: element.returnType)}(r'${element.name}', $descriptor, "
'$ownerIndex, $returnTypeIndex, $reflectedReturnTypeIndex, '
'$dynamicReflectedReturnTypeIndex, '
'$reflectedTypeArgumentsOfReturnType, $parameterIndicesCode, '
Expand Down Expand Up @@ -1950,7 +1993,7 @@ class _ReflectorDomain {
// it is a `List<Object>`, which has no other natural encoding.
metadataCode = null;
}
return "r.VariableMirrorImpl(r'${element.name}', $descriptor, "
return "r.VariableMirrorImpl${await _typeGenericCode(importCollector, type: element.type)}(r'${element.name}', $descriptor, "
'$ownerIndex, ${await _constConstructionCode(importCollector)}, '
'$classMirrorIndex, $reflectedTypeIndex, '
'$dynamicReflectedTypeIndex, $reflectedTypeArguments, '
Expand Down Expand Up @@ -2011,7 +2054,7 @@ class _ReflectorDomain {
// it is a `List<Object>`, which has no other natural encoding.
metadataCode = null;
}
return "r.VariableMirrorImpl(r'${element.name}', $descriptor, "
return "r.VariableMirrorImpl${await _typeGenericCode(importCollector, type: element.type)}(r'${element.name}', $descriptor, "
'$ownerIndex, ${await _constConstructionCode(importCollector)}, '
'$classMirrorIndex, $reflectedTypeIndex, '
'$dynamicReflectedTypeIndex, $reflectedTypeArguments, $metadataCode)';
Expand Down Expand Up @@ -2664,7 +2707,7 @@ class _ReflectorDomain {
? '#${element.name}'
: 'null';

return "r.ParameterMirrorImpl(r'${element.name}', $descriptor, "
return "r.ParameterMirrorImpl${await _typeGenericCode(importCollector, type: element.type)}(r'${element.name}', $descriptor, "
'$ownerIndex, ${await _constConstructionCode(importCollector)}, '
'$classMirrorIndex, $reflectedTypeIndex, $dynamicReflectedTypeIndex, '
'$reflectedTypeArguments, $metadataCode, $defaultValueCode, '
Expand Down
Loading