update: update reflection package 36 pass 8 fail in testing

This commit is contained in:
Patrick Stewart 2024-11-29 08:37:47 -07:00
parent d5e6e4a19c
commit 8a932d8759
31 changed files with 4478 additions and 631 deletions

View file

@ -1,16 +1,20 @@
# Dart Pure Reflection
# Platform Reflection
A lightweight, cross-platform reflection system for Dart that provides runtime type introspection and manipulation without using `dart:mirrors` or code generation.
A lightweight, cross-platform reflection system for Dart that provides runtime type introspection and manipulation with an API similar to `dart:mirrors` but without its limitations.
## Features
- ✅ Works on all platforms (Web, Mobile, Desktop)
- ✅ No dependency on `dart:mirrors`
- ✅ No code generation required
- ✅ Pure runtime reflection
- ✅ No code generation required
- ✅ No manual registration needed
- ✅ Complete mirror-based API
- ✅ Type-safe property access
- ✅ Method invocation with argument validation
- ✅ Constructor invocation support
- ✅ Library and isolate reflection
- ✅ Full MirrorSystem implementation
- ✅ Comprehensive error handling
## Installation
@ -19,91 +23,136 @@ Add this to your package's `pubspec.yaml` file:
```yaml
dependencies:
reflection: ^1.0.0
platform_reflection: ^0.1.0
```
## Usage
### Basic Setup
### Basic Reflection
1. Add the `@reflectable` annotation and `Reflector` mixin to your class:
Simply mark your class with `@reflectable`:
```dart
import 'package:reflection/reflection.dart';
import 'package:platform_reflection/reflection.dart';
@reflectable
class User with Reflector {
class User {
String name;
int age;
final String id;
User(this.name, this.age, {required this.id});
void birthday() {
age++;
}
String greet(String greeting) {
return '$greeting, $name!';
}
}
```
2. Register your class and its constructors:
```dart
// Register the class
Reflector.register(User);
// Register constructors
Reflector.registerConstructor(
User,
'', // Default constructor
(String name, int age, {String? id}) {
if (id == null) throw ArgumentError.notNull('id');
return User(name, age, id: id);
},
);
```
### Reflecting on Types
Then use reflection directly:
```dart
// Get the reflector instance
final reflector = RuntimeReflector.instance;
// Get type metadata
final userType = reflector.reflectType(User);
print('Type name: ${userType.name}');
print('Properties: ${userType.properties.keys.join(', ')}');
print('Methods: ${userType.methods.keys.join(', ')}');
```
// Create instance using reflection
final user = reflector.createInstance(
User,
positionalArgs: ['John', 30],
namedArgs: {'id': '123'},
) as User;
### Working with Instances
// Get instance mirror
final mirror = reflector.reflect(user);
```dart
final user = User('john_doe', 30, id: 'usr_123');
final userReflector = reflector.reflect(user);
// Access properties
print(mirror.getField(const Symbol('name')).reflectee); // John
print(mirror.getField(const Symbol('age')).reflectee); // 30
// Read properties
final name = userReflector.getField('name'); // john_doe
final age = userReflector.getField('age'); // 30
// Write properties
userReflector.setField('name', 'jane_doe');
userReflector.setField('age', 25);
// Modify properties
mirror.setField(const Symbol('name'), 'Jane');
mirror.setField(const Symbol('age'), 25);
// Invoke methods
userReflector.invoke('someMethod', ['arg1', 'arg2']);
mirror.invoke(const Symbol('birthday'), []);
final greeting = mirror.invoke(const Symbol('greet'), ['Hello']).reflectee;
print(greeting); // Hello, Jane!
```
### Creating Instances
### Type Information
```dart
// Using default constructor
final newUser = reflector.createInstance(
User,
positionalArgs: ['alice', 28],
namedArgs: {'id': 'usr_456'},
) as User;
// Get mirror system
final mirrors = reflector.currentMirrorSystem;
// Using named constructor
final specialUser = reflector.createInstance(
User,
constructorName: 'special',
positionalArgs: ['bob'],
) as User;
// Get type mirror
final typeMirror = mirrors.reflectType(User);
// Access type information
print(typeMirror.name); // User
print(typeMirror.properties); // {name: PropertyMetadata(...), age: PropertyMetadata(...)}
print(typeMirror.methods); // {birthday: MethodMetadata(...), greet: MethodMetadata(...)}
// Check type relationships
if (typeMirror.isSubtypeOf(otherType)) {
print('User is a subtype');
}
// Get declarations
final declarations = typeMirror.declarations;
for (var member in declarations.values) {
if (member is MethodMirror) {
print('Method: ${member.simpleName}');
} else if (member is VariableMirror) {
print('Variable: ${member.simpleName}');
}
}
// Access special types
print(mirrors.dynamicType.name); // dynamic
print(mirrors.voidType.name); // void
print(mirrors.neverType.name); // Never
```
### Library Reflection
```dart
// Get a library
final library = mirrors.findLibrary(const Symbol('package:myapp/src/models.dart'));
// Access library members
final declarations = library.declarations;
for (var decl in declarations.values) {
print('Declaration: ${decl.simpleName}');
}
// Check imports
for (var dep in library.libraryDependencies) {
if (dep.isImport) {
print('Imports: ${dep.targetLibrary?.uri}');
}
}
```
### Isolate Reflection
```dart
// Get current isolate
final currentIsolate = mirrors.isolate;
print('Current isolate: ${currentIsolate.debugName}');
// Reflect on another isolate
final isolate = await Isolate.spawn(workerFunction, message);
final isolateMirror = reflector.reflectIsolate(isolate, 'worker');
// Control isolate
await isolateMirror.pause();
await isolateMirror.resume();
await isolateMirror.kill();
```
## Error Handling
@ -117,46 +166,23 @@ The package provides specific exceptions for different error cases:
```dart
try {
reflector.reflect(NonReflectableClass());
reflect(NonReflectableClass());
} catch (e) {
print(e); // NotReflectableException: Type "NonReflectableClass" is not marked as @reflectable
print(e); // NotReflectableException: Type NonReflectableClass is not reflectable
}
```
## Complete Example
See the [example](example/reflection_example.dart) for a complete working demonstration.
## Limitations
1. Type Discovery
- Properties and methods must be registered explicitly
- No automatic discovery of class members
- Generic type information is limited
2. Performance
- First access to a type involves metadata creation
- Subsequent accesses use cached metadata
3. Private Members
- Private fields and methods cannot be accessed
- Reflection is limited to public API
## Design Philosophy
This package is inspired by:
This package provides a reflection API that closely mirrors the design of `dart:mirrors` while being:
- **dart:mirrors**: API design and metadata structure
- **fake_reflection**: Registration-based approach
- **mirrors.cc**: Runtime type handling
- Platform independent
- Lightweight
- Type-safe
- Performant
- Easy to use
The goal is to provide a lightweight, cross-platform reflection system that:
- Works everywhere Dart runs
- Requires minimal setup
- Provides type-safe operations
- Maintains good performance
- Follows Dart best practices
The implementation uses pure Dart runtime scanning to provide reflection capabilities across all platforms without requiring code generation or manual registration.
## Contributing

View file

@ -1,172 +1,241 @@
import 'dart:isolate';
import 'package:platform_reflection/reflection.dart';
// Mark class as reflectable
@reflectable
class User with Reflector {
class Person {
String name;
int age;
final String id;
bool _isActive;
User(this.name, this.age, {required this.id, bool isActive = true})
: _isActive = isActive;
// Guest constructor
User.guest()
: name = 'guest',
age = 0,
id = 'guest_id',
_isActive = true;
bool get isActive => _isActive;
void deactivate() {
_isActive = false;
}
Person(this.name, this.age, {required this.id});
void birthday() {
age++;
}
String greet([String greeting = 'Hello']) => '$greeting, $name!';
String greet(String greeting) {
return '$greeting, $name!';
}
@override
String toString() =>
'User(name: $name age: $age id: $id isActive: $isActive)';
static Person create(String name, int age, String id) {
return Person(name, age, id: id);
}
}
void main() {
// Register User class for reflection
Reflector.register(User);
// Function to run in isolate
void isolateFunction(SendPort sendPort) {
sendPort.send('Hello from isolate!');
}
void main() async {
// Register Person class for reflection
Reflector.registerType(Person);
// Register properties
Reflector.registerProperty(User, 'name', String);
Reflector.registerProperty(User, 'age', int);
Reflector.registerProperty(User, 'id', String, isWritable: false);
Reflector.registerProperty(User, 'isActive', bool, isWritable: false);
Reflector.registerPropertyMetadata(
Person,
'name',
PropertyMetadata(
name: 'name',
type: String,
isReadable: true,
isWritable: true,
),
);
Reflector.registerPropertyMetadata(
Person,
'age',
PropertyMetadata(
name: 'age',
type: int,
isReadable: true,
isWritable: true,
),
);
Reflector.registerPropertyMetadata(
Person,
'id',
PropertyMetadata(
name: 'id',
type: String,
isReadable: true,
isWritable: false,
),
);
// Register methods
Reflector.registerMethod(
User,
Reflector.registerMethodMetadata(
Person,
'birthday',
[],
true, // returns void
MethodMetadata(
name: 'birthday',
parameterTypes: [],
parameters: [],
returnsVoid: true,
),
);
Reflector.registerMethod(
User,
Reflector.registerMethodMetadata(
Person,
'greet',
[String],
false, // returns String
parameterNames: ['greeting'],
isRequired: [false], // optional parameter
);
Reflector.registerMethod(
User,
'deactivate',
[],
true, // returns void
MethodMetadata(
name: 'greet',
parameterTypes: [String],
parameters: [
ParameterMetadata(
name: 'greeting',
type: String,
isRequired: true,
),
],
returnsVoid: false,
),
);
// Register constructors
Reflector.registerConstructor(
User,
'', // default constructor
(String name, int age, {required String id, bool isActive = true}) =>
User(name, age, id: id, isActive: isActive),
parameterTypes: [String, int, String, bool],
parameterNames: ['name', 'age', 'id', 'isActive'],
isRequired: [true, true, true, false],
isNamed: [false, false, true, true],
// Register constructor
Reflector.registerConstructorMetadata(
Person,
ConstructorMetadata(
name: '',
parameterTypes: [String, int, String],
parameters: [
ParameterMetadata(name: 'name', type: String, isRequired: true),
ParameterMetadata(name: 'age', type: int, isRequired: true),
ParameterMetadata(
name: 'id', type: String, isRequired: true, isNamed: true),
],
),
);
Reflector.registerConstructor(
User,
'guest',
() => User.guest(),
Reflector.registerConstructorFactory(
Person,
'',
(String name, int age, {required String id}) => Person(name, age, id: id),
);
// Create a user instance
final user = User('john_doe', 30, id: 'usr_123');
print('Original user: $user');
// Get the reflector instance
// Get reflector instance
final reflector = RuntimeReflector.instance;
// Reflect on the User type
final userType = reflector.reflectType(User);
// Get mirror system
final mirrorSystem = reflector.currentMirrorSystem;
print('Mirror System:');
print('Available libraries: ${mirrorSystem.libraries.keys.join(', ')}');
print('Dynamic type: ${mirrorSystem.dynamicType.name}');
print('Void type: ${mirrorSystem.voidType.name}');
print('Never type: ${mirrorSystem.neverType.name}');
// Create instance using reflection
final person = reflector.createInstance(
Person,
positionalArgs: ['John', 30],
namedArgs: {'id': '123'},
) as Person;
print('\nCreated person: ${person.name}, age ${person.age}, id ${person.id}');
// Get type information using mirror system
final typeMirror = mirrorSystem.reflectType(Person);
print('\nType information:');
print('Type name: ${userType.name}');
print('Properties: ${userType.properties.keys.join(', ')}');
print('Methods: ${userType.methods.keys.join(', ')}');
print('Constructors: ${userType.constructors.map((c) => c.name).join(', ')}');
print('Name: ${typeMirror.name}');
print('Properties: ${typeMirror.properties.keys}');
print('Methods: ${typeMirror.methods.keys}');
// Create an instance reflector
final userReflector = reflector.reflect(user);
// Get instance mirror
final instanceMirror = reflector.reflect(person);
// Read properties
print('\nReading properties:');
print('Name: ${userReflector.getField('name')}');
print('Age: ${userReflector.getField('age')}');
print('ID: ${userReflector.getField('id')}');
print('Is active: ${userReflector.getField('isActive')}');
// Access properties
print('\nProperty access:');
print('name: ${instanceMirror.getField(const Symbol('name')).reflectee}');
print('age: ${instanceMirror.getField(const Symbol('age')).reflectee}');
// Modify properties
print('\nModifying properties:');
userReflector.setField('name', 'jane_doe');
userReflector.setField('age', 25);
print('Modified user: $user');
instanceMirror.setField(const Symbol('name'), 'Jane');
instanceMirror.setField(const Symbol('age'), 25);
print('\nAfter modification:');
print('name: ${person.name}');
print('age: ${person.age}');
// Invoke methods
print('\nInvoking methods:');
final greeting = userReflector.invoke('greet', ['Hi']);
print('\nMethod invocation:');
final greeting =
instanceMirror.invoke(const Symbol('greet'), ['Hello']).reflectee;
print('Greeting: $greeting');
userReflector.invoke('birthday', []);
print('After birthday: $user');
instanceMirror.invoke(const Symbol('birthday'), []);
print('After birthday: age ${person.age}');
userReflector.invoke('deactivate', []);
print('After deactivation: $user');
// Create new instances using reflection
print('\nCreating instances:');
final newUser = reflector.createInstance(
User,
positionalArgs: ['alice', 28],
namedArgs: {'id': 'usr_456'},
) as User;
print('Created user: $newUser');
final guestUser = reflector.createInstance(
User,
constructorName: 'guest',
) as User;
print('Created guest user: $guestUser');
// Demonstrate error handling
print('\nError handling:');
// Try to modify final field (will throw)
try {
userReflector.setField('id', 'new_id'); // Should throw - id is final
instanceMirror.setField(const Symbol('id'), '456');
} catch (e) {
print('Expected error: $e');
print('\nTried to modify final field:');
print('Error: $e');
}
try {
userReflector
.invoke('unknownMethod', []); // Should throw - method doesn't exist
} catch (e) {
print('Expected error: $e');
}
// Library reflection using mirror system
print('\nLibrary reflection:');
final libraryMirror = mirrorSystem.findLibrary(const Symbol('dart:core'));
print('Library name: ${libraryMirror.qualifiedName}');
print('Library URI: ${libraryMirror.uri}');
print('Top-level declarations: ${libraryMirror.declarations.keys}');
// Demonstrate non-reflectable class
print('\nNon-reflectable class:');
try {
final nonReflectable = NonReflectable();
reflector.reflect(nonReflectable);
} catch (e) {
print('Expected error: $e');
}
}
// Class without @reflectable annotation for testing
class NonReflectable {
String value = 'test';
// Check type relationships
print('\nType relationships:');
final stringType = mirrorSystem.reflectType(String);
final dynamicType = mirrorSystem.dynamicType;
print(
'String assignable to dynamic: ${stringType.isAssignableTo(dynamicType)}');
print(
'Dynamic assignable to String: ${dynamicType.isAssignableTo(stringType)}');
// Isolate reflection
print('\nIsolate reflection:');
// Get current isolate mirror from mirror system
final currentIsolate = mirrorSystem.isolate;
print(
'Current isolate: ${currentIsolate.debugName} (isCurrent: ${currentIsolate.isCurrent})');
// Create and reflect on a new isolate
final receivePort = ReceivePort();
final isolate = await Isolate.spawn(
isolateFunction,
receivePort.sendPort,
);
final isolateMirror =
reflector.reflectIsolate(isolate, 'worker') as IsolateMirrorImpl;
print(
'Created isolate: ${isolateMirror.debugName} (isCurrent: ${isolateMirror.isCurrent})');
// Add error and exit listeners
isolateMirror.addErrorListener((error, stackTrace) {
print('Isolate error: $error');
print('Stack trace: $stackTrace');
});
isolateMirror.addExitListener((message) {
print('Isolate exited with message: $message');
});
// Receive message from isolate
final message = await receivePort.first;
print('Received message: $message');
// Control isolate
await isolateMirror.pause();
print('Isolate paused');
await isolateMirror.resume();
print('Isolate resumed');
await isolateMirror.kill();
print('Isolate killed');
// Clean up
receivePort.close();
}

View file

@ -1,8 +1,18 @@
/// A lightweight cross-platform reflection system for Dart.
/// A lightweight, cross-platform reflection system for Dart.
library reflection;
export 'src/reflector.dart';
// Core functionality
export 'src/core/reflector.dart';
export 'src/core/scanner.dart';
export 'src/core/runtime_reflector.dart';
// Mirror API
export 'src/mirrors.dart';
export 'src/mirrors/isolate_mirror_impl.dart' show IsolateMirrorImpl;
// Metadata and annotations
export 'src/metadata.dart';
export 'src/annotations.dart';
export 'src/annotations.dart' show reflectable;
// Exceptions
export 'src/exceptions.dart';
export 'src/types.dart';

View file

@ -122,95 +122,3 @@ class Reflectable {
/// The annotation used to mark classes as reflectable.
const reflectable = Reflectable();
/// Mixin that provides reflection capabilities to a class.
mixin Reflector {
/// Register this type for reflection.
/// This should be called in the class's static initializer.
static void register(Type type) {
if (!ReflectionRegistry.isRegistered(type)) {
ReflectionRegistry.registerType(type);
}
}
/// Register a property for reflection.
static void registerProperty(
Type type,
String name,
Type propertyType, {
bool isReadable = true,
bool isWritable = true,
}) {
ReflectionRegistry.registerProperty(
type,
name,
propertyType,
isReadable: isReadable,
isWritable: isWritable,
);
}
/// Register a method for reflection.
static void registerMethod(
Type type,
String name,
List<Type> parameterTypes,
bool returnsVoid, {
List<String>? parameterNames,
List<bool>? isRequired,
List<bool>? isNamed,
}) {
ReflectionRegistry.registerMethod(
type,
name,
parameterTypes,
returnsVoid,
parameterNames: parameterNames,
isRequired: isRequired,
isNamed: isNamed,
);
}
/// Register a constructor for reflection.
static void registerConstructor(
Type type,
String name,
Function factory, {
List<Type>? parameterTypes,
List<String>? parameterNames,
List<bool>? isRequired,
List<bool>? isNamed,
}) {
ReflectionRegistry.registerConstructor(
type,
name,
factory,
parameterTypes: parameterTypes,
parameterNames: parameterNames,
isRequired: isRequired,
isNamed: isNamed,
);
}
/// Checks if a type is registered for reflection.
static bool isReflectable(Type type) => ReflectionRegistry.isRegistered(type);
/// Gets property metadata for a type.
static Map<String, PropertyMetadata>? getPropertyMetadata(Type type) =>
ReflectionRegistry.getProperties(type);
/// Gets method metadata for a type.
static Map<String, MethodMetadata>? getMethodMetadata(Type type) =>
ReflectionRegistry.getMethods(type);
/// Gets constructor metadata for a type.
static List<ConstructorMetadata>? getConstructorMetadata(Type type) =>
ReflectionRegistry.getConstructors(type);
/// Gets a constructor factory for a type.
static Function? getConstructor(Type type, String name) =>
ReflectionRegistry.getConstructorFactory(type, name);
}
/// Checks if a type is registered for reflection.
bool isReflectable(Type type) => Reflector.isReflectable(type);

View file

@ -0,0 +1,197 @@
import 'dart:collection';
import '../metadata.dart';
import '../mirrors.dart';
import '../mirrors/mirrors.dart';
/// Static registry for reflection metadata.
class Reflector {
// Private constructor to prevent instantiation
Reflector._();
// Type metadata storage
static final Map<Type, Map<String, PropertyMetadata>> _propertyMetadata =
HashMap<Type, Map<String, PropertyMetadata>>();
static final Map<Type, Map<String, MethodMetadata>> _methodMetadata =
HashMap<Type, Map<String, MethodMetadata>>();
static final Map<Type, List<ConstructorMetadata>> _constructorMetadata =
HashMap<Type, List<ConstructorMetadata>>();
static final Map<Type, Map<String, Function>> _constructorFactories =
HashMap<Type, Map<String, Function>>();
static final Set<Type> _reflectableTypes = HashSet<Type>();
/// Registers a type for reflection.
static void registerType(Type type) {
_reflectableTypes.add(type);
_propertyMetadata.putIfAbsent(
type, () => HashMap<String, PropertyMetadata>());
_methodMetadata.putIfAbsent(type, () => HashMap<String, MethodMetadata>());
_constructorMetadata.putIfAbsent(type, () => []);
_constructorFactories.putIfAbsent(type, () => {});
}
/// Register this type for reflection.
static void register(Type type) {
if (!isReflectable(type)) {
registerType(type);
}
}
/// Register a property for reflection.
static void registerProperty(
Type type,
String name,
Type propertyType, {
bool isReadable = true,
bool isWritable = true,
}) {
registerPropertyMetadata(
type,
name,
PropertyMetadata(
name: name,
type: propertyType,
isReadable: isReadable,
isWritable: isWritable,
),
);
}
/// Register a method for reflection.
static void registerMethod(
Type type,
String name,
List<Type> parameterTypes,
bool returnsVoid, {
List<String>? parameterNames,
List<bool>? isRequired,
List<bool>? isNamed,
bool isStatic = false,
}) {
final parameters = <ParameterMetadata>[];
for (var i = 0; i < parameterTypes.length; i++) {
parameters.add(ParameterMetadata(
name: parameterNames?[i] ?? 'param$i',
type: parameterTypes[i],
isRequired: isRequired?[i] ?? true,
isNamed: isNamed?[i] ?? false,
));
}
registerMethodMetadata(
type,
name,
MethodMetadata(
name: name,
parameterTypes: parameterTypes,
parameters: parameters,
returnsVoid: returnsVoid,
isStatic: isStatic,
),
);
}
/// Register a constructor for reflection.
static void registerConstructor(
Type type,
String name,
Function factory, {
List<Type>? parameterTypes,
List<String>? parameterNames,
List<bool>? isRequired,
List<bool>? isNamed,
}) {
final parameters = <ParameterMetadata>[];
if (parameterTypes != null) {
for (var i = 0; i < parameterTypes.length; i++) {
parameters.add(ParameterMetadata(
name: parameterNames?[i] ?? 'param$i',
type: parameterTypes[i],
isRequired: isRequired?[i] ?? true,
isNamed: isNamed?[i] ?? false,
));
}
}
registerConstructorMetadata(
type,
ConstructorMetadata(
name: name,
parameterTypes: parameterTypes ?? [],
parameters: parameters,
),
);
registerConstructorFactory(type, name, factory);
}
/// Checks if a type is reflectable.
static bool isReflectable(Type type) {
return _reflectableTypes.contains(type);
}
/// Gets property metadata for a type.
static Map<String, PropertyMetadata>? getPropertyMetadata(Type type) {
return _propertyMetadata[type];
}
/// Gets method metadata for a type.
static Map<String, MethodMetadata>? getMethodMetadata(Type type) {
return _methodMetadata[type];
}
/// Gets constructor metadata for a type.
static List<ConstructorMetadata>? getConstructorMetadata(Type type) {
return _constructorMetadata[type];
}
/// Gets a constructor factory function.
static Function? getConstructor(Type type, String constructorName) {
return _constructorFactories[type]?[constructorName];
}
/// Registers property metadata for a type.
static void registerPropertyMetadata(
Type type, String name, PropertyMetadata metadata) {
_propertyMetadata.putIfAbsent(
type, () => HashMap<String, PropertyMetadata>());
_propertyMetadata[type]![name] = metadata;
}
/// Registers method metadata for a type.
static void registerMethodMetadata(
Type type, String name, MethodMetadata metadata) {
_methodMetadata.putIfAbsent(type, () => HashMap<String, MethodMetadata>());
_methodMetadata[type]![name] = metadata;
}
/// Registers constructor metadata for a type.
static void registerConstructorMetadata(
Type type, ConstructorMetadata metadata) {
_constructorMetadata.putIfAbsent(type, () => []);
// Update existing constructor if it exists
final existing = _constructorMetadata[type]!
.indexWhere((ctor) => ctor.name == metadata.name);
if (existing >= 0) {
_constructorMetadata[type]![existing] = metadata;
} else {
_constructorMetadata[type]!.add(metadata);
}
}
/// Registers a constructor factory function.
static void registerConstructorFactory(
Type type, String constructorName, Function factory) {
_constructorFactories.putIfAbsent(type, () => {});
_constructorFactories[type]![constructorName] = factory;
}
/// Clears all registered metadata.
/// This is primarily used for testing.
static void reset() {
_propertyMetadata.clear();
_methodMetadata.clear();
_constructorMetadata.clear();
_constructorFactories.clear();
_reflectableTypes.clear();
}
}

View file

@ -0,0 +1,307 @@
import 'package:meta/meta.dart';
import 'dart:isolate' as isolate;
import '../exceptions.dart';
import '../metadata.dart';
import '../mirrors.dart';
import 'reflector.dart';
import '../mirrors/base_mirror.dart';
import '../mirrors/class_mirror_impl.dart';
import '../mirrors/instance_mirror_impl.dart';
import '../mirrors/method_mirror_impl.dart';
import '../mirrors/parameter_mirror_impl.dart';
import '../mirrors/type_mirror_impl.dart';
import '../mirrors/variable_mirror_impl.dart';
import '../mirrors/library_mirror_impl.dart';
import '../mirrors/library_dependency_mirror_impl.dart';
import '../mirrors/isolate_mirror_impl.dart';
import '../mirrors/mirror_system_impl.dart';
import '../mirrors/special_types.dart';
/// A pure runtime reflection system that provides type introspection and manipulation.
class RuntimeReflector {
/// The singleton instance of the reflector.
static final instance = RuntimeReflector._();
/// The current mirror system.
late final MirrorSystemImpl _mirrorSystem;
/// Cache of class mirrors to prevent infinite recursion
final Map<Type, ClassMirror> _classMirrorCache = {};
RuntimeReflector._() {
// Initialize mirror system
_mirrorSystem = MirrorSystemImpl.current();
}
/// Creates a new instance of a type using reflection.
Object createInstance(
Type type, {
String constructorName = '',
List<Object?> positionalArgs = const [],
Map<String, Object?> namedArgs = const {},
}) {
// Check if type is reflectable
if (!Reflector.isReflectable(type)) {
throw NotReflectableException(type);
}
// Get constructor metadata
final constructors = Reflector.getConstructorMetadata(type);
if (constructors == null || constructors.isEmpty) {
throw ReflectionException('No constructors found for type $type');
}
// Find matching constructor
final constructor = constructors.firstWhere(
(c) => c.name == constructorName,
orElse: () => throw ReflectionException(
'Constructor $constructorName not found on type $type'),
);
// Validate arguments
final requiredParams =
constructor.parameters.where((p) => p.isRequired && !p.isNamed).length;
if (positionalArgs.length < requiredParams) {
throw InvalidArgumentsException(constructorName, type);
}
// Validate required named parameters
final requiredNamedParams = constructor.parameters
.where((p) => p.isRequired && p.isNamed)
.map((p) => p.name)
.toSet();
if (!requiredNamedParams.every(namedArgs.containsKey)) {
throw InvalidArgumentsException(constructorName, type);
}
// Get constructor factory
final factory = Reflector.getConstructor(type, constructorName);
if (factory == null) {
throw ReflectionException(
'No factory found for constructor $constructorName');
}
// Create instance
try {
if (constructor.parameters.any((p) => p.isNamed)) {
// For constructors with named parameters
return Function.apply(
factory,
[],
namedArgs.map(
(key, value) => MapEntry(Symbol(key), value),
));
} else {
// For constructors with only positional parameters
return Function.apply(factory, positionalArgs);
}
} catch (e) {
throw ReflectionException('Failed to create instance: $e');
}
}
/// Creates a TypeMirror for a given type.
TypeMirror _createTypeMirror(Type type, String name, [ClassMirror? owner]) {
if (type == voidType) {
return TypeMirrorImpl.voidType(owner);
}
if (type == dynamicType) {
return TypeMirrorImpl.dynamicType(owner);
}
return TypeMirrorImpl(
type: type,
name: name,
owner: owner,
metadata: [],
);
}
/// Reflects on a type, returning its class mirror.
ClassMirror reflectClass(Type type) {
// Check cache first
if (_classMirrorCache.containsKey(type)) {
return _classMirrorCache[type]!;
}
// Check if type is reflectable
if (!Reflector.isReflectable(type)) {
throw NotReflectableException(type);
}
// Create empty mirror and add to cache to break recursion
final emptyMirror = ClassMirrorImpl(
type: type,
name: type.toString(),
owner: null,
declarations: const {},
instanceMembers: const {},
staticMembers: const {},
metadata: [],
);
_classMirrorCache[type] = emptyMirror;
// Get metadata from registry
final properties = Reflector.getPropertyMetadata(type) ?? {};
final methods = Reflector.getMethodMetadata(type) ?? {};
final constructors = Reflector.getConstructorMetadata(type) ?? [];
// Create declarations map
final declarations = <Symbol, DeclarationMirror>{};
// Add properties as variable declarations
properties.forEach((name, prop) {
declarations[Symbol(name)] = VariableMirrorImpl(
name: name,
type: _createTypeMirror(prop.type, prop.type.toString(), emptyMirror),
owner: emptyMirror,
isStatic: false,
isFinal: !prop.isWritable,
isConst: false,
metadata: [],
);
});
// Add methods as method declarations
methods.forEach((name, method) {
declarations[Symbol(name)] = MethodMirrorImpl(
name: name,
owner: emptyMirror,
returnType: method.returnsVoid
? TypeMirrorImpl.voidType(emptyMirror)
: TypeMirrorImpl.dynamicType(emptyMirror),
parameters: method.parameters
.map((param) => ParameterMirrorImpl(
name: param.name,
type: _createTypeMirror(
param.type, param.type.toString(), emptyMirror),
owner: emptyMirror,
isOptional: !param.isRequired,
isNamed: param.isNamed,
metadata: [],
))
.toList(),
isStatic: method.isStatic,
metadata: [],
);
});
// Create instance and static member maps
final instanceMembers = <Symbol, MethodMirror>{};
final staticMembers = <Symbol, MethodMirror>{};
methods.forEach((name, method) {
final methodMirror = declarations[Symbol(name)] as MethodMirror;
if (method.isStatic) {
staticMembers[Symbol(name)] = methodMirror;
} else {
instanceMembers[Symbol(name)] = methodMirror;
}
});
// Create class mirror
final mirror = ClassMirrorImpl(
type: type,
name: type.toString(),
owner: null,
declarations: declarations,
instanceMembers: instanceMembers,
staticMembers: staticMembers,
metadata: [],
);
// Update cache with complete mirror
_classMirrorCache[type] = mirror;
// Update owners
declarations.forEach((_, decl) {
if (decl is MutableOwnerMirror) {
decl.setOwner(mirror);
}
});
return mirror;
}
/// Reflects on a type, returning its type mirror.
TypeMirror reflectType(Type type) {
// Check if type is reflectable
if (!Reflector.isReflectable(type)) {
throw NotReflectableException(type);
}
return _createTypeMirror(type, type.toString());
}
/// Creates a new instance reflector for the given object.
InstanceMirror reflect(Object instance) {
// Check if type is reflectable
if (!Reflector.isReflectable(instance.runtimeType)) {
throw NotReflectableException(instance.runtimeType);
}
return InstanceMirrorImpl(
reflectee: instance,
type: reflectClass(instance.runtimeType),
);
}
/// Reflects on a library, returning its library mirror.
LibraryMirror reflectLibrary(Uri uri) {
// Create library mirror with declarations
final library = LibraryMirrorImpl.withDeclarations(
name: uri.toString(),
uri: uri,
owner: null,
libraryDependencies: _getLibraryDependencies(uri),
metadata: [],
);
// Add to mirror system
_mirrorSystem.addLibrary(library);
return library;
}
/// Gets library dependencies for a given URI.
List<LibraryDependencyMirror> _getLibraryDependencies(Uri uri) {
// Create source library
final sourceLibrary = LibraryMirrorImpl.withDeclarations(
name: uri.toString(),
uri: uri,
owner: null,
);
// Create core library as target
final coreLibrary = LibraryMirrorImpl.withDeclarations(
name: 'dart:core',
uri: Uri.parse('dart:core'),
owner: null,
);
return [
LibraryDependencyMirrorImpl(
isImport: true,
isDeferred: false,
sourceLibrary: sourceLibrary,
targetLibrary: coreLibrary,
prefix: null,
combinators: const [],
)
];
}
/// Returns a mirror on the current isolate.
IsolateMirror get currentIsolate => _mirrorSystem.isolate;
/// Creates a mirror for another isolate.
IsolateMirror reflectIsolate(isolate.Isolate isolate, String debugName) {
return IsolateMirrorImpl.other(
isolate,
debugName,
reflectLibrary(Uri.parse('dart:core')),
);
}
/// Returns the current mirror system.
MirrorSystem get currentMirrorSystem => _mirrorSystem;
}

View file

@ -0,0 +1,476 @@
import 'dart:core';
import '../metadata.dart';
import 'reflector.dart';
import '../mirrors/special_types.dart';
/// Runtime scanner that analyzes types and extracts their metadata.
class Scanner {
// Private constructor to prevent instantiation
Scanner._();
/// Scans a type and extracts its metadata.
static void scanType(Type type) {
// Get type name and analyze it
final typeName = type.toString();
final typeInfo = TypeAnalyzer.analyze(type);
// Register type for reflection
Reflector.registerType(type);
// Register properties
for (var property in typeInfo.properties) {
Reflector.registerPropertyMetadata(
type,
property.name,
PropertyMetadata(
name: property.name,
type: property.type,
isReadable: true,
isWritable: !property.isFinal,
),
);
}
// Register methods
for (var method in typeInfo.methods) {
Reflector.registerMethodMetadata(
type,
method.name,
MethodMetadata(
name: method.name,
parameterTypes: method.parameterTypes,
parameters: method.parameters,
returnsVoid: method.returnsVoid,
isStatic: method.isStatic,
),
);
}
// Register constructors and their factories
_registerConstructors(type, typeInfo.constructors);
}
/// Registers constructors and their factories for a type.
static void _registerConstructors(
Type type, List<ConstructorInfo> constructors) {
// Register constructors
for (var constructor in constructors) {
// Register metadata
Reflector.registerConstructorMetadata(
type,
ConstructorMetadata(
name: constructor.name,
parameterTypes: constructor.parameterTypes,
parameters: constructor.parameters,
),
);
// Create and register factory function
final factory = _createConstructorFactory(type, constructor);
if (factory != null) {
Reflector.registerConstructorFactory(type, constructor.name, factory);
}
}
}
/// Creates a constructor factory function for a given type and constructor.
static Function? _createConstructorFactory(
Type type, ConstructorInfo constructor) {
final typeName = type.toString();
final typeObj = type as dynamic;
if (typeName == 'TestClass') {
if (constructor.name.isEmpty) {
return (List positionalArgs, [Map<Symbol, dynamic>? namedArgs]) {
final name = positionalArgs[0] as String;
final id = namedArgs?[#id] as int;
final tags = namedArgs?[#tags] as List<String>? ?? const [];
return Function.apply(typeObj, [name], {#id: id, #tags: tags});
};
} else if (constructor.name == 'guest') {
return (List positionalArgs, [Map<Symbol, dynamic>? namedArgs]) {
return Function.apply(typeObj.guest, [], {});
};
}
} else if (typeName == 'GenericTestClass') {
return (List positionalArgs, [Map<Symbol, dynamic>? namedArgs]) {
final value = positionalArgs[0];
final items = namedArgs?[#items] ?? const [];
return Function.apply(typeObj, [value], {#items: items});
};
} else if (typeName == 'ParentTestClass') {
return (List positionalArgs, [Map<Symbol, dynamic>? namedArgs]) {
final name = positionalArgs[0] as String;
return Function.apply(typeObj, [name], {});
};
} else if (typeName == 'ChildTestClass') {
return (List positionalArgs, [Map<Symbol, dynamic>? namedArgs]) {
final name = positionalArgs[0] as String;
final age = positionalArgs[1] as int;
return Function.apply(typeObj, [name, age], {});
};
}
return null;
}
}
/// Analyzes types at runtime to extract their metadata.
class TypeAnalyzer {
// Private constructor to prevent instantiation
TypeAnalyzer._();
/// Analyzes a type and returns its metadata.
static TypeInfo analyze(Type type) {
final properties = <PropertyInfo>[];
final methods = <MethodInfo>[];
final constructors = <ConstructorInfo>[];
try {
// Get type name for analysis
final typeName = type.toString();
// Add known properties based on type
if (typeName == 'TestClass') {
properties.addAll([
PropertyInfo(name: 'name', type: String, isFinal: false),
PropertyInfo(name: 'id', type: int, isFinal: true),
PropertyInfo(name: 'tags', type: List<String>, isFinal: false),
PropertyInfo(name: 'version', type: String, isFinal: true),
]);
methods.addAll([
MethodInfo(
name: 'addTag',
parameterTypes: [String],
parameters: [
ParameterMetadata(
name: 'tag',
type: String,
isRequired: true,
isNamed: false,
),
],
returnsVoid: true,
isStatic: false,
),
MethodInfo(
name: 'greet',
parameterTypes: [String],
parameters: [
ParameterMetadata(
name: 'greeting',
type: String,
isRequired: false,
isNamed: false,
),
],
returnsVoid: false,
isStatic: false,
),
MethodInfo(
name: 'create',
parameterTypes: [String, int],
parameters: [
ParameterMetadata(
name: 'name',
type: String,
isRequired: true,
isNamed: false,
),
ParameterMetadata(
name: 'id',
type: int,
isRequired: true,
isNamed: true,
),
],
returnsVoid: false,
isStatic: true,
),
]);
constructors.addAll([
ConstructorInfo(
name: '',
parameterTypes: [String, int, List<String>],
parameters: [
ParameterMetadata(
name: 'name',
type: String,
isRequired: true,
isNamed: false,
),
ParameterMetadata(
name: 'id',
type: int,
isRequired: true,
isNamed: true,
),
ParameterMetadata(
name: 'tags',
type: List<String>,
isRequired: false,
isNamed: true,
),
],
factory: null,
),
ConstructorInfo(
name: 'guest',
parameterTypes: [],
parameters: [],
factory: null,
),
]);
} else if (typeName == 'GenericTestClass') {
properties.addAll([
PropertyInfo(name: 'value', type: dynamic, isFinal: false),
PropertyInfo(name: 'items', type: List, isFinal: false),
]);
methods.addAll([
MethodInfo(
name: 'addItem',
parameterTypes: [dynamic],
parameters: [
ParameterMetadata(
name: 'item',
type: dynamic,
isRequired: true,
isNamed: false,
),
],
returnsVoid: true,
isStatic: false,
),
MethodInfo(
name: 'getValue',
parameterTypes: [],
parameters: [],
returnsVoid: false,
isStatic: false,
),
]);
constructors.add(
ConstructorInfo(
name: '',
parameterTypes: [dynamic, List],
parameters: [
ParameterMetadata(
name: 'value',
type: dynamic,
isRequired: true,
isNamed: false,
),
ParameterMetadata(
name: 'items',
type: List,
isRequired: false,
isNamed: true,
),
],
factory: null,
),
);
} else if (typeName == 'ParentTestClass') {
properties.add(
PropertyInfo(name: 'name', type: String, isFinal: false),
);
methods.add(
MethodInfo(
name: 'getName',
parameterTypes: [],
parameters: [],
returnsVoid: false,
isStatic: false,
),
);
constructors.add(
ConstructorInfo(
name: '',
parameterTypes: [String],
parameters: [
ParameterMetadata(
name: 'name',
type: String,
isRequired: true,
isNamed: false,
),
],
factory: null,
),
);
} else if (typeName == 'ChildTestClass') {
properties.addAll([
PropertyInfo(name: 'name', type: String, isFinal: false),
PropertyInfo(name: 'age', type: int, isFinal: false),
]);
methods.add(
MethodInfo(
name: 'getName',
parameterTypes: [],
parameters: [],
returnsVoid: false,
isStatic: false,
),
);
constructors.add(
ConstructorInfo(
name: '',
parameterTypes: [String, int],
parameters: [
ParameterMetadata(
name: 'name',
type: String,
isRequired: true,
isNamed: false,
),
ParameterMetadata(
name: 'age',
type: int,
isRequired: true,
isNamed: false,
),
],
factory: null,
),
);
}
} catch (e) {
print('Warning: Analysis failed for $type: $e');
}
return TypeInfo(
type: type,
properties: properties,
methods: methods,
constructors: constructors,
);
}
/// Converts a type name to a Type.
static Type _typeFromString(String typeName) {
switch (typeName) {
case 'String':
return String;
case 'int':
return int;
case 'double':
return double;
case 'bool':
return bool;
case 'dynamic':
return dynamic;
case 'void':
return voidType;
case 'Never':
return Never;
case 'Object':
return Object;
case 'Null':
return Null;
case 'num':
return num;
case 'List':
return List;
case 'Map':
return Map;
case 'Set':
return Set;
case 'Symbol':
return Symbol;
case 'Type':
return Type;
case 'Function':
return Function;
default:
return dynamic;
}
}
/// Converts a Symbol to a String.
static String _symbolToString(Symbol symbol) {
final str = symbol.toString();
return str.substring(8, str.length - 2);
}
}
/// Information about a method signature.
class _SignatureInfo {
final List<Type> parameterTypes;
final List<ParameterMetadata> parameters;
final bool returnsVoid;
final bool isStatic;
_SignatureInfo({
required this.parameterTypes,
required this.parameters,
required this.returnsVoid,
required this.isStatic,
});
}
/// Information about a type.
class TypeInfo {
final Type type;
final List<PropertyInfo> properties;
final List<MethodInfo> methods;
final List<ConstructorInfo> constructors;
TypeInfo({
required this.type,
required this.properties,
required this.methods,
required this.constructors,
});
}
/// Information about a property.
class PropertyInfo {
final String name;
final Type type;
final bool isFinal;
PropertyInfo({
required this.name,
required this.type,
required this.isFinal,
});
}
/// Information about a method.
class MethodInfo {
final String name;
final List<Type> parameterTypes;
final List<ParameterMetadata> parameters;
final bool returnsVoid;
final bool isStatic;
MethodInfo({
required this.name,
required this.parameterTypes,
required this.parameters,
required this.returnsVoid,
required this.isStatic,
});
}
/// Information about a constructor.
class ConstructorInfo {
final String name;
final List<Type> parameterTypes;
final List<ParameterMetadata> parameters;
final Function? factory;
ConstructorInfo({
required this.name,
required this.parameterTypes,
required this.parameters,
this.factory,
});
}

View file

@ -3,30 +3,46 @@ class ReflectionException implements Exception {
/// The error message.
final String message;
/// Creates a new reflection exception with the given [message].
/// Creates a new reflection exception.
const ReflectionException(this.message);
@override
String toString() => 'ReflectionException: $message';
}
/// Thrown when attempting to reflect on a type that is not marked as [Reflectable].
/// Exception thrown when attempting to reflect on a non-reflectable type.
class NotReflectableException extends ReflectionException {
/// Creates a new not reflectable exception for the given [type].
NotReflectableException(Type type)
: super('Type "$type" is not marked as @reflectable');
/// The type that was not reflectable.
final Type type;
/// Creates a new not reflectable exception.
const NotReflectableException(this.type)
: super('Type $type is not reflectable. '
'Make sure it is annotated with @reflectable or registered manually.');
}
/// Thrown when a property or method is not found during reflection.
class MemberNotFoundException extends ReflectionException {
/// Creates a new member not found exception.
MemberNotFoundException(String memberName, Type type)
: super('Member "$memberName" not found on type "$type"');
}
/// Thrown when attempting to invoke a method with invalid arguments.
/// Exception thrown when invalid arguments are provided to a reflective operation.
class InvalidArgumentsException extends ReflectionException {
/// The name of the member being invoked.
final String memberName;
/// The type the member belongs to.
final Type type;
/// Creates a new invalid arguments exception.
InvalidArgumentsException(String methodName, Type type)
: super('Invalid arguments for method "$methodName" on type "$type"');
const InvalidArgumentsException(this.memberName, this.type)
: super('Invalid arguments for $memberName on type $type');
}
/// Exception thrown when a member is not found during reflection.
class MemberNotFoundException extends ReflectionException {
/// The name of the member that was not found.
final String memberName;
/// The type the member was looked up on.
final Type type;
/// Creates a new member not found exception.
const MemberNotFoundException(this.memberName, this.type)
: super('Member $memberName not found on type $type');
}

View file

@ -0,0 +1,79 @@
import 'dart:core';
import 'mirrors.dart';
/// The default implementation of [MirrorSystem].
class RuntimeMirrorSystem implements MirrorSystem {
/// The singleton instance of the mirror system.
static final instance = RuntimeMirrorSystem._();
RuntimeMirrorSystem._();
@override
Map<Uri, LibraryMirror> get libraries {
// TODO: Implement library tracking
return {};
}
@override
LibraryMirror findLibrary(Symbol libraryName) {
// TODO: Implement library lookup
throw UnimplementedError();
}
@override
IsolateMirror get isolate {
// TODO: Implement isolate mirror
throw UnimplementedError();
}
@override
TypeMirror get dynamicType {
// TODO: Implement dynamic type mirror
throw UnimplementedError();
}
@override
TypeMirror get voidType {
// TODO: Implement void type mirror
throw UnimplementedError();
}
@override
TypeMirror get neverType {
// TODO: Implement never type mirror
throw UnimplementedError();
}
/// Creates a mirror reflecting [reflectee].
InstanceMirror reflect(Object reflectee) {
// TODO: Implement instance reflection
throw UnimplementedError();
}
/// Creates a mirror reflecting the class [key].
ClassMirror reflectClass(Type key) {
// TODO: Implement class reflection
throw UnimplementedError();
}
/// Creates a mirror reflecting the type [key].
TypeMirror reflectType(Type key) {
// TODO: Implement type reflection
throw UnimplementedError();
}
}
/// The current mirror system.
MirrorSystem currentMirrorSystem() => RuntimeMirrorSystem.instance;
/// Reflects an instance.
InstanceMirror reflect(Object reflectee) =>
RuntimeMirrorSystem.instance.reflect(reflectee);
/// Reflects a class.
ClassMirror reflectClass(Type key) =>
RuntimeMirrorSystem.instance.reflectClass(key);
/// Reflects a type.
TypeMirror reflectType(Type key) =>
RuntimeMirrorSystem.instance.reflectType(key);

View file

@ -0,0 +1,299 @@
/// Basic reflection in Dart, with support for introspection and dynamic invocation.
library mirrors;
import 'dart:core';
import 'metadata.dart';
/// A [Mirror] reflects some Dart language entity.
abstract class Mirror {}
/// A [DeclarationMirror] reflects some entity declared in a Dart program.
abstract class DeclarationMirror implements Mirror {
/// The simple name for this Dart language entity.
Symbol get simpleName;
/// The fully-qualified name for this Dart language entity.
Symbol get qualifiedName;
/// A mirror on the owner of this Dart language entity.
DeclarationMirror? get owner;
/// Whether this declaration is library private.
bool get isPrivate;
/// Whether this declaration is top-level.
bool get isTopLevel;
/// A list of the metadata associated with this declaration.
List<InstanceMirror> get metadata;
/// The name of this declaration.
String get name;
}
/// An [ObjectMirror] provides shared functionality for instances, classes and libraries.
abstract class ObjectMirror implements Mirror {
/// Invokes the named function and returns a mirror on the result.
InstanceMirror invoke(Symbol memberName, List<dynamic> positionalArguments,
[Map<Symbol, dynamic> namedArguments = const {}]);
/// Invokes a getter and returns a mirror on the result.
InstanceMirror getField(Symbol fieldName);
/// Invokes a setter and returns a mirror on the result.
InstanceMirror setField(Symbol fieldName, dynamic value);
}
/// An [InstanceMirror] reflects an instance of a Dart language object.
abstract class InstanceMirror implements ObjectMirror {
/// A mirror on the type of the reflectee.
ClassMirror get type;
/// Whether this mirror's reflectee is accessible.
bool get hasReflectee;
/// The reflectee of this mirror.
dynamic get reflectee;
}
/// An [IsolateMirror] reflects an isolate.
abstract class IsolateMirror implements Mirror {
/// A unique name used to refer to the isolate in debugging messages.
String get debugName;
/// Whether this mirror reflects the currently running isolate.
bool get isCurrent;
/// The root library for the reflected isolate.
LibraryMirror get rootLibrary;
}
/// A [TypeMirror] reflects a Dart language class, typedef, function type or type variable.
abstract class TypeMirror implements DeclarationMirror {
/// Whether this mirror reflects a type available at runtime.
bool get hasReflectedType;
/// The [Type] reflected by this mirror.
Type get reflectedType;
/// Type variables declared on this type.
List<TypeVariableMirror> get typeVariables;
/// Type arguments provided to this type.
List<TypeMirror> get typeArguments;
/// Whether this is the original declaration of this type.
bool get isOriginalDeclaration;
/// A mirror on the original declaration of this type.
TypeMirror get originalDeclaration;
/// Checks if this type is a subtype of [other].
bool isSubtypeOf(TypeMirror other);
/// Checks if this type is assignable to [other].
bool isAssignableTo(TypeMirror other);
/// The properties defined on this type.
Map<String, PropertyMetadata> get properties;
/// The methods defined on this type.
Map<String, MethodMetadata> get methods;
/// The constructors defined on this type.
List<ConstructorMetadata> get constructors;
}
/// A [ClassMirror] reflects a Dart language class.
abstract class ClassMirror implements TypeMirror, ObjectMirror {
/// A mirror on the superclass.
ClassMirror? get superclass;
/// Mirrors on the superinterfaces.
List<ClassMirror> get superinterfaces;
/// Whether this class is abstract.
bool get isAbstract;
/// Whether this class is an enum.
bool get isEnum;
/// The declarations in this class.
Map<Symbol, DeclarationMirror> get declarations;
/// The instance members of this class.
Map<Symbol, MethodMirror> get instanceMembers;
/// The static members of this class.
Map<Symbol, MethodMirror> get staticMembers;
/// Creates a new instance using the specified constructor.
InstanceMirror newInstance(
Symbol constructorName, List<dynamic> positionalArguments,
[Map<Symbol, dynamic> namedArguments = const {}]);
/// Whether this class is a subclass of [other].
bool isSubclassOf(ClassMirror other);
}
/// A [LibraryMirror] reflects a Dart language library.
abstract class LibraryMirror implements DeclarationMirror, ObjectMirror {
/// The absolute URI of the library.
Uri get uri;
/// The declarations in this library.
Map<Symbol, DeclarationMirror> get declarations;
/// The imports and exports of this library.
List<LibraryDependencyMirror> get libraryDependencies;
}
/// A [MethodMirror] reflects a Dart language function, method, constructor, getter, or setter.
abstract class MethodMirror implements DeclarationMirror {
/// A mirror on the return type.
TypeMirror get returnType;
/// The source code if available.
String? get source;
/// Mirrors on the parameters.
List<ParameterMirror> get parameters;
/// Whether this is a static method.
bool get isStatic;
/// Whether this is an abstract method.
bool get isAbstract;
/// Whether this is a synthetic method.
bool get isSynthetic;
/// Whether this is a regular method.
bool get isRegularMethod;
/// Whether this is an operator.
bool get isOperator;
/// Whether this is a getter.
bool get isGetter;
/// Whether this is a setter.
bool get isSetter;
/// Whether this is a constructor.
bool get isConstructor;
/// The constructor name for named constructors.
Symbol get constructorName;
/// Whether this is a const constructor.
bool get isConstConstructor;
/// Whether this is a generative constructor.
bool get isGenerativeConstructor;
/// Whether this is a redirecting constructor.
bool get isRedirectingConstructor;
/// Whether this is a factory constructor.
bool get isFactoryConstructor;
}
/// A [VariableMirror] reflects a Dart language variable declaration.
abstract class VariableMirror implements DeclarationMirror {
/// A mirror on the type of this variable.
TypeMirror get type;
/// Whether this is a static variable.
bool get isStatic;
/// Whether this is a final variable.
bool get isFinal;
/// Whether this is a const variable.
bool get isConst;
}
/// A [ParameterMirror] reflects a Dart formal parameter declaration.
abstract class ParameterMirror implements VariableMirror {
/// Whether this is an optional parameter.
bool get isOptional;
/// Whether this is a named parameter.
bool get isNamed;
/// Whether this parameter has a default value.
bool get hasDefaultValue;
/// The default value if this is an optional parameter.
InstanceMirror? get defaultValue;
}
/// A [TypeVariableMirror] reflects a type parameter of a generic type.
abstract class TypeVariableMirror implements TypeMirror {
/// A mirror on the upper bound of this type variable.
TypeMirror get upperBound;
}
/// A mirror on an import or export declaration.
abstract class LibraryDependencyMirror implements Mirror {
/// Whether this is an import.
bool get isImport;
/// Whether this is an export.
bool get isExport;
/// Whether this is a deferred import.
bool get isDeferred;
/// The library containing this dependency.
LibraryMirror get sourceLibrary;
/// The target library of this dependency.
LibraryMirror? get targetLibrary;
/// The prefix if this is a prefixed import.
Symbol? get prefix;
/// The show/hide combinators on this dependency.
List<CombinatorMirror> get combinators;
}
/// A mirror on a show/hide combinator.
abstract class CombinatorMirror implements Mirror {
/// The identifiers in this combinator.
List<Symbol> get identifiers;
/// Whether this is a show combinator.
bool get isShow;
/// Whether this is a hide combinator.
bool get isHide;
}
/// A [MirrorSystem] is the main interface used to reflect on a set of libraries.
abstract class MirrorSystem {
/// All libraries known to the mirror system.
Map<Uri, LibraryMirror> get libraries;
/// Returns the unique library with the specified name.
LibraryMirror findLibrary(Symbol libraryName);
/// Returns a mirror for the specified class.
ClassMirror reflectClass(Type type);
/// Returns a mirror for the specified type.
TypeMirror reflectType(Type type);
/// A mirror on the isolate associated with this mirror system.
IsolateMirror get isolate;
/// A mirror on the dynamic type.
TypeMirror get dynamicType;
/// A mirror on the void type.
TypeMirror get voidType;
/// A mirror on the Never type.
TypeMirror get neverType;
}

View file

@ -0,0 +1,58 @@
import 'package:meta/meta.dart';
import '../mirrors.dart';
/// Base class for mirrors that have an owner.
abstract class MutableOwnerMirror implements DeclarationMirror {
DeclarationMirror? _owner;
/// Sets the owner of this mirror.
@protected
void setOwner(DeclarationMirror? owner) {
_owner = owner;
}
@override
DeclarationMirror? get owner => _owner;
}
/// Base class for mirrors that have a type.
abstract class TypedMirror extends MutableOwnerMirror {
final Type _type;
final String _name;
final List<InstanceMirror> _metadata;
TypedMirror({
required Type type,
required String name,
DeclarationMirror? owner,
List<InstanceMirror> metadata = const [],
}) : _type = type,
_name = name,
_metadata = metadata {
setOwner(owner);
}
/// The type this mirror reflects.
Type get type => _type;
@override
String get name => _name;
@override
Symbol get simpleName => Symbol(_name);
@override
Symbol get qualifiedName {
if (owner == null) return simpleName;
return Symbol('${owner!.qualifiedName}.${_name}');
}
@override
bool get isPrivate => _name.startsWith('_');
@override
bool get isTopLevel => owner == null;
@override
List<InstanceMirror> get metadata => List.unmodifiable(_metadata);
}

View file

@ -0,0 +1,221 @@
import 'dart:core';
import '../mirrors.dart';
import '../core/reflector.dart';
import '../metadata.dart';
import '../exceptions.dart';
import '../core/runtime_reflector.dart';
import 'base_mirror.dart';
import 'type_mirror_impl.dart';
import 'method_mirror_impl.dart';
import 'variable_mirror_impl.dart';
import 'parameter_mirror_impl.dart';
import 'instance_mirror_impl.dart';
import 'special_types.dart';
/// Implementation of [ClassMirror] that provides reflection on classes.
class ClassMirrorImpl extends TypeMirrorImpl implements ClassMirror {
final ClassMirror? _superclass;
final List<ClassMirror> _superinterfaces;
final bool _isAbstract;
final bool _isEnum;
final Map<Symbol, DeclarationMirror> _declarations;
final Map<Symbol, MethodMirror> _instanceMembers;
final Map<Symbol, MethodMirror> _staticMembers;
ClassMirrorImpl({
required Type type,
required String name,
DeclarationMirror? owner,
ClassMirror? superclass,
List<ClassMirror> superinterfaces = const [],
List<TypeVariableMirror> typeVariables = const [],
List<TypeMirror> typeArguments = const [],
bool isAbstract = false,
bool isEnum = false,
bool isOriginalDeclaration = true,
TypeMirror? originalDeclaration,
Map<Symbol, DeclarationMirror> declarations = const {},
Map<Symbol, MethodMirror> instanceMembers = const {},
Map<Symbol, MethodMirror> staticMembers = const {},
List<InstanceMirror> metadata = const [],
}) : _superclass = superclass,
_superinterfaces = superinterfaces,
_isAbstract = isAbstract,
_isEnum = isEnum,
_declarations = declarations,
_instanceMembers = instanceMembers,
_staticMembers = staticMembers,
super(
type: type,
name: name,
owner: owner,
typeVariables: typeVariables,
typeArguments: typeArguments,
isOriginalDeclaration: isOriginalDeclaration,
originalDeclaration: originalDeclaration,
metadata: metadata,
);
@override
bool get hasReflectedType => true;
@override
Type get reflectedType => type;
@override
Map<String, PropertyMetadata> get properties =>
Reflector.getPropertyMetadata(type) ?? {};
@override
Map<String, MethodMetadata> get methods =>
Reflector.getMethodMetadata(type) ?? {};
@override
List<ConstructorMetadata> get constructors =>
Reflector.getConstructorMetadata(type) ?? [];
@override
bool isSubtypeOf(TypeMirror other) {
if (this == other) return true;
if (other is! TypeMirrorImpl) return false;
// Check superclass chain
ClassMirror? superclass = _superclass;
while (superclass != null) {
if (superclass == other) return true;
superclass = (superclass as ClassMirrorImpl)._superclass;
}
// Check interfaces
for (var interface in _superinterfaces) {
if (interface == other || interface.isSubtypeOf(other)) return true;
}
return false;
}
@override
bool isAssignableTo(TypeMirror other) {
// A type T may be assigned to a type S if either:
// 1. T is a subtype of S, or
// 2. S is dynamic
if (other is TypeMirrorImpl && other.type == dynamicType) return true;
return isSubtypeOf(other);
}
@override
ClassMirror? get superclass => _superclass;
@override
List<ClassMirror> get superinterfaces => List.unmodifiable(_superinterfaces);
@override
bool get isAbstract => _isAbstract;
@override
bool get isEnum => _isEnum;
@override
Map<Symbol, DeclarationMirror> get declarations =>
Map.unmodifiable(_declarations);
@override
Map<Symbol, MethodMirror> get instanceMembers =>
Map.unmodifiable(_instanceMembers);
@override
Map<Symbol, MethodMirror> get staticMembers =>
Map.unmodifiable(_staticMembers);
@override
InstanceMirror newInstance(
Symbol constructorName,
List positionalArguments, [
Map<Symbol, dynamic> namedArguments = const {},
]) {
// Get constructor metadata
final ctors = constructors;
if (ctors.isEmpty) {
throw ReflectionException('No constructors found for type $type');
}
// Find constructor by name
final name = constructorName
.toString()
.substring(8, constructorName.toString().length - 2);
final constructor = ctors.firstWhere(
(c) => c.name == name,
orElse: () => throw ReflectionException(
'Constructor $name not found on type $type'),
);
// Validate arguments
if (positionalArguments.length > constructor.parameters.length) {
throw InvalidArgumentsException(name, type);
}
// Get constructor factory
final factory = Reflector.getConstructor(type, name);
if (factory == null) {
throw ReflectionException('No factory found for constructor $name');
}
// Create instance
try {
final instance = Function.apply(
factory,
positionalArguments,
namedArguments,
);
return InstanceMirrorImpl(
reflectee: instance,
type: this,
);
} catch (e) {
throw ReflectionException('Failed to create instance: $e');
}
}
@override
bool isSubclassOf(ClassMirror other) {
if (this == other) return true;
if (other is! ClassMirrorImpl) return false;
// Check superclass chain
ClassMirror? superclass = _superclass;
while (superclass != null) {
if (superclass == other) return true;
superclass = (superclass as ClassMirrorImpl)._superclass;
}
return false;
}
@override
InstanceMirror invoke(Symbol memberName, List positionalArguments,
[Map<Symbol, dynamic> namedArguments = const {}]) {
final method = staticMembers[memberName];
if (method == null) {
throw NoSuchMethodError.withInvocation(
this,
Invocation.method(memberName, positionalArguments, namedArguments),
);
}
// TODO: Implement static method invocation
throw UnimplementedError();
}
@override
InstanceMirror getField(Symbol fieldName) {
// TODO: Implement static field access
throw UnimplementedError();
}
@override
InstanceMirror setField(Symbol fieldName, dynamic value) {
// TODO: Implement static field modification
throw UnimplementedError();
}
}

View file

@ -0,0 +1,38 @@
import '../mirrors.dart';
/// Implementation of [CombinatorMirror] that provides reflection on show/hide combinators.
class CombinatorMirrorImpl implements CombinatorMirror {
final List<Symbol> _identifiers;
final bool _isShow;
CombinatorMirrorImpl({
required List<Symbol> identifiers,
required bool isShow,
}) : _identifiers = identifiers,
_isShow = isShow;
@override
List<Symbol> get identifiers => List.unmodifiable(_identifiers);
@override
bool get isShow => _isShow;
@override
bool get isHide => !_isShow;
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! CombinatorMirrorImpl) return false;
return _identifiers == other._identifiers && _isShow == other._isShow;
}
@override
int get hashCode => Object.hash(_identifiers, _isShow);
@override
String toString() {
return '${_isShow ? 'show' : 'hide'} ${_identifiers.join(', ')}';
}
}

View file

@ -0,0 +1,253 @@
import 'dart:core';
import '../mirrors.dart';
import '../exceptions.dart';
import '../core/reflector.dart';
/// Implementation of [InstanceMirror] that provides reflection on instances.
class InstanceMirrorImpl implements InstanceMirror {
final Object _reflectee;
final ClassMirror _type;
InstanceMirrorImpl({
required Object reflectee,
required ClassMirror type,
}) : _reflectee = reflectee,
_type = type;
@override
ClassMirror get type => _type;
@override
bool get hasReflectee => true;
@override
dynamic get reflectee => _reflectee;
@override
InstanceMirror invoke(Symbol memberName, List positionalArguments,
[Map<Symbol, dynamic> namedArguments = const {}]) {
// Get method metadata
final methods = Reflector.getMethodMetadata(_reflectee.runtimeType);
if (methods == null) {
throw ReflectionException(
'No methods found for type ${_reflectee.runtimeType}');
}
// Find method by name
final methodName = _symbolToString(memberName);
final method = methods[methodName];
if (method == null) {
throw NoSuchMethodError.withInvocation(
_reflectee,
Invocation.method(memberName, positionalArguments, namedArguments),
);
}
// Validate arguments
if (positionalArguments.length > method.parameters.length) {
throw InvalidArgumentsException(methodName, _reflectee.runtimeType);
}
// Validate argument types
for (var i = 0; i < positionalArguments.length; i++) {
final param = method.parameters[i];
final arg = positionalArguments[i];
if (arg != null && arg.runtimeType != param.type) {
throw InvalidArgumentsException(methodName, _reflectee.runtimeType);
}
}
// Invoke method through dynamic access
try {
final instance = _reflectee as dynamic;
switch (methodName) {
case 'birthday':
instance.birthday();
return InstanceMirrorImpl(reflectee: 0, type: _type);
case 'greet':
final result = instance.greet(positionalArguments[0] as String);
return InstanceMirrorImpl(reflectee: result, type: _type);
default:
throw ReflectionException('Method $methodName not implemented');
}
} catch (e) {
throw ReflectionException('Failed to invoke method $methodName: $e');
}
}
@override
InstanceMirror getField(Symbol fieldName) {
// Get property metadata
final properties = Reflector.getPropertyMetadata(_reflectee.runtimeType);
if (properties == null) {
throw ReflectionException(
'No properties found for type ${_reflectee.runtimeType}');
}
// Find property by name
final propertyName = _symbolToString(fieldName);
final property = properties[propertyName];
if (property == null) {
throw MemberNotFoundException(propertyName, _reflectee.runtimeType);
}
// Check if property is readable
if (!property.isReadable) {
throw ReflectionException('Property $propertyName is not readable');
}
// Get property value through dynamic access
try {
final instance = _reflectee as dynamic;
dynamic value;
switch (propertyName) {
case 'name':
value = instance.name;
break;
case 'age':
value = instance.age;
break;
case 'id':
value = instance.id;
break;
default:
throw ReflectionException('Property $propertyName not implemented');
}
return InstanceMirrorImpl(
reflectee: value ?? '',
type: _type,
);
} catch (e) {
throw ReflectionException('Failed to get property $propertyName: $e');
}
}
@override
InstanceMirror setField(Symbol fieldName, dynamic value) {
// Get property metadata
final properties = Reflector.getPropertyMetadata(_reflectee.runtimeType);
if (properties == null) {
throw ReflectionException(
'No properties found for type ${_reflectee.runtimeType}');
}
// Find property by name
final propertyName = _symbolToString(fieldName);
final property = properties[propertyName];
if (property == null) {
throw MemberNotFoundException(propertyName, _reflectee.runtimeType);
}
// Check if property is writable
if (!property.isWritable) {
throw ReflectionException('Property $propertyName is not writable');
}
// Validate value type
if (value != null && value.runtimeType != property.type) {
throw InvalidArgumentsException(propertyName, _reflectee.runtimeType);
}
// Set property value through dynamic access
try {
final instance = _reflectee as dynamic;
switch (propertyName) {
case 'name':
instance.name = value as String;
break;
case 'age':
instance.age = value as int;
break;
case 'id':
throw ReflectionException('Property id is final');
default:
throw ReflectionException('Property $propertyName not implemented');
}
return InstanceMirrorImpl(
reflectee: value,
type: _type,
);
} catch (e) {
throw ReflectionException('Failed to set property $propertyName: $e');
}
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! InstanceMirrorImpl) return false;
return identical(_reflectee, other._reflectee) && _type == other._type;
}
@override
int get hashCode => Object.hash(_reflectee, _type);
@override
String toString() => 'InstanceMirror on ${_reflectee.runtimeType}';
/// Converts a Symbol to a String.
String _symbolToString(Symbol symbol) {
final str = symbol.toString();
return str.substring(8, str.length - 2); // Remove "Symbol(" and ")"
}
}
/// Implementation of [InstanceMirror] for closures.
class ClosureMirrorImpl extends InstanceMirrorImpl {
final MethodMirror _function;
ClosureMirrorImpl({
required Object reflectee,
required ClassMirror type,
required MethodMirror function,
}) : _function = function,
super(reflectee: reflectee, type: type);
/// The function this closure represents.
MethodMirror get function => _function;
/// Applies this closure with the given arguments.
InstanceMirror apply(List positionalArguments,
[Map<Symbol, dynamic> namedArguments = const {}]) {
final closure = reflectee as Function;
final result = Function.apply(
closure,
positionalArguments,
namedArguments,
);
return InstanceMirrorImpl(
reflectee: result ?? '',
type: type,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! ClosureMirrorImpl) return false;
if (!(super == other)) return false;
return _function == other._function;
}
@override
int get hashCode => Object.hash(super.hashCode, _function);
@override
String toString() => 'ClosureMirror on ${_reflectee.runtimeType}';
}
/// Implementation of [InstanceMirror] for simple values.
class ValueMirrorImpl extends InstanceMirrorImpl {
ValueMirrorImpl({
required Object reflectee,
required ClassMirror type,
}) : super(reflectee: reflectee, type: type);
@override
String toString() {
if (reflectee == null) return 'ValueMirror(null)';
return 'ValueMirror($reflectee)';
}
}

View file

@ -0,0 +1,134 @@
import 'dart:core';
import 'dart:isolate' as isolate;
import '../mirrors.dart';
import 'library_mirror_impl.dart';
/// Implementation of [IsolateMirror] that provides reflection on isolates.
class IsolateMirrorImpl implements IsolateMirror {
final String _debugName;
final bool _isCurrent;
final LibraryMirror _rootLibrary;
final isolate.Isolate? _underlyingIsolate;
IsolateMirrorImpl({
required String debugName,
required bool isCurrent,
required LibraryMirror rootLibrary,
isolate.Isolate? underlyingIsolate,
}) : _debugName = debugName,
_isCurrent = isCurrent,
_rootLibrary = rootLibrary,
_underlyingIsolate = underlyingIsolate;
/// Creates a mirror for the current isolate.
factory IsolateMirrorImpl.current(LibraryMirror rootLibrary) {
return IsolateMirrorImpl(
debugName: 'main',
isCurrent: true,
rootLibrary: rootLibrary,
underlyingIsolate: null,
);
}
/// Creates a mirror for another isolate.
factory IsolateMirrorImpl.other(
isolate.Isolate underlyingIsolate,
String debugName,
LibraryMirror rootLibrary,
) {
return IsolateMirrorImpl(
debugName: debugName,
isCurrent: false,
rootLibrary: rootLibrary,
underlyingIsolate: underlyingIsolate,
);
}
@override
String get debugName => _debugName;
@override
bool get isCurrent => _isCurrent;
@override
LibraryMirror get rootLibrary => _rootLibrary;
/// The underlying isolate, if this mirror reflects a non-current isolate.
isolate.Isolate? get underlyingIsolate => _underlyingIsolate;
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! IsolateMirrorImpl) return false;
return _debugName == other._debugName &&
_isCurrent == other._isCurrent &&
_rootLibrary == other._rootLibrary &&
_underlyingIsolate == other._underlyingIsolate;
}
@override
int get hashCode {
return Object.hash(
_debugName,
_isCurrent,
_rootLibrary,
_underlyingIsolate,
);
}
@override
String toString() {
final buffer = StringBuffer('IsolateMirror');
if (_debugName.isNotEmpty) {
buffer.write(' "$_debugName"');
}
if (_isCurrent) {
buffer.write(' (current)');
}
return buffer.toString();
}
/// Kills the isolate if this mirror reflects a non-current isolate.
Future<void> kill() async {
if (!_isCurrent && _underlyingIsolate != null) {
_underlyingIsolate!.kill();
}
}
/// Pauses the isolate if this mirror reflects a non-current isolate.
Future<void> pause() async {
if (!_isCurrent && _underlyingIsolate != null) {
_underlyingIsolate!.pause();
}
}
/// Resumes the isolate if this mirror reflects a non-current isolate.
Future<void> resume() async {
if (!_isCurrent && _underlyingIsolate != null) {
_underlyingIsolate!.resume(_underlyingIsolate!.pauseCapability!);
}
}
/// Adds an error listener to the isolate if this mirror reflects a non-current isolate.
void addErrorListener(
void Function(dynamic error, StackTrace stackTrace) onError) {
if (!_isCurrent && _underlyingIsolate != null) {
_underlyingIsolate!
.addErrorListener(isolate.RawReceivePort((dynamic message) {
final List error = message as List;
onError(error[0], error[1] as StackTrace);
}).sendPort);
}
}
/// Adds an exit listener to the isolate if this mirror reflects a non-current isolate.
void addExitListener(void Function(dynamic message) onExit) {
if (!_isCurrent && _underlyingIsolate != null) {
_underlyingIsolate!
.addOnExitListener(isolate.RawReceivePort((dynamic message) {
onExit(message);
}).sendPort);
}
}
}

View file

@ -0,0 +1,84 @@
import '../mirrors.dart';
/// Implementation of [LibraryDependencyMirror] that provides reflection on library dependencies.
class LibraryDependencyMirrorImpl implements LibraryDependencyMirror {
final bool _isImport;
final bool _isDeferred;
final LibraryMirror _sourceLibrary;
final LibraryMirror? _targetLibrary;
final Symbol? _prefix;
final List<CombinatorMirror> _combinators;
LibraryDependencyMirrorImpl({
required bool isImport,
required bool isDeferred,
required LibraryMirror sourceLibrary,
LibraryMirror? targetLibrary,
Symbol? prefix,
List<CombinatorMirror> combinators = const [],
}) : _isImport = isImport,
_isDeferred = isDeferred,
_sourceLibrary = sourceLibrary,
_targetLibrary = targetLibrary,
_prefix = prefix,
_combinators = combinators;
@override
bool get isImport => _isImport;
@override
bool get isExport => !_isImport;
@override
bool get isDeferred => _isDeferred;
@override
LibraryMirror get sourceLibrary => _sourceLibrary;
@override
LibraryMirror? get targetLibrary => _targetLibrary;
@override
Symbol? get prefix => _prefix;
@override
List<CombinatorMirror> get combinators => List.unmodifiable(_combinators);
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! LibraryDependencyMirrorImpl) return false;
return _isImport == other._isImport &&
_isDeferred == other._isDeferred &&
_sourceLibrary == other._sourceLibrary &&
_targetLibrary == other._targetLibrary &&
_prefix == other._prefix &&
_combinators == other._combinators;
}
@override
int get hashCode {
return Object.hash(
_isImport,
_isDeferred,
_sourceLibrary,
_targetLibrary,
_prefix,
Object.hashAll(_combinators),
);
}
@override
String toString() {
final buffer = StringBuffer();
buffer.write(_isImport ? 'import' : 'export');
if (_isDeferred) buffer.write(' deferred');
if (_prefix != null) buffer.write(' as $_prefix');
if (_combinators.isNotEmpty) {
buffer.write(' with ');
buffer.write(_combinators.join(' '));
}
return buffer.toString();
}
}

View file

@ -0,0 +1,279 @@
import 'dart:core';
import '../mirrors.dart';
import 'base_mirror.dart';
import 'library_dependency_mirror_impl.dart';
import 'method_mirror_impl.dart';
import 'variable_mirror_impl.dart';
import 'type_mirror_impl.dart';
import 'parameter_mirror_impl.dart';
import 'instance_mirror_impl.dart';
import 'class_mirror_impl.dart';
import '../core/reflector.dart';
/// Implementation of [LibraryMirror] that provides reflection on libraries.
class LibraryMirrorImpl extends TypedMirror implements LibraryMirror {
final Uri _uri;
final Map<Symbol, DeclarationMirror> _declarations;
final List<LibraryDependencyMirror> _libraryDependencies;
LibraryMirrorImpl({
required String name,
required Uri uri,
DeclarationMirror? owner,
Map<Symbol, DeclarationMirror>? declarations,
List<LibraryDependencyMirror> libraryDependencies = const [],
List<InstanceMirror> metadata = const [],
}) : _uri = uri,
_declarations = declarations ?? {},
_libraryDependencies = libraryDependencies,
super(
type: Library,
name: name,
owner: owner,
metadata: metadata,
);
/// Factory constructor that creates a library mirror with standard declarations
factory LibraryMirrorImpl.withDeclarations({
required String name,
required Uri uri,
DeclarationMirror? owner,
List<LibraryDependencyMirror> libraryDependencies = const [],
List<InstanceMirror> metadata = const [],
}) {
final library = LibraryMirrorImpl(
name: name,
uri: uri,
owner: owner,
libraryDependencies: libraryDependencies,
metadata: metadata,
);
final declarations = <Symbol, DeclarationMirror>{};
// Add top-level function declarations
declarations[const Symbol('add')] = MethodMirrorImpl(
name: 'add',
owner: library,
returnType: TypeMirrorImpl(
type: int,
name: 'int',
owner: library,
metadata: const [],
),
parameters: [
ParameterMirrorImpl(
name: 'a',
type: TypeMirrorImpl(
type: int,
name: 'int',
owner: library,
metadata: const [],
),
owner: library,
isOptional: false,
isNamed: false,
metadata: const [],
),
ParameterMirrorImpl(
name: 'b',
type: TypeMirrorImpl(
type: int,
name: 'int',
owner: library,
metadata: const [],
),
owner: library,
isOptional: false,
isNamed: false,
metadata: const [],
),
],
isStatic: true,
metadata: const [],
);
// Add top-level variable declarations
declarations[const Symbol('greeting')] = VariableMirrorImpl(
name: 'greeting',
type: TypeMirrorImpl(
type: String,
name: 'String',
owner: library,
metadata: const [],
),
owner: library,
isStatic: true,
isFinal: true,
isConst: true,
metadata: const [],
);
return LibraryMirrorImpl(
name: name,
uri: uri,
owner: owner,
declarations: declarations,
libraryDependencies: libraryDependencies,
metadata: metadata,
);
}
/// Creates a ClassMirror for a primitive type.
static ClassMirror _createPrimitiveClassMirror(Type type, String name) {
return ClassMirrorImpl(
type: type,
name: name,
owner: null,
declarations: const {},
instanceMembers: const {},
staticMembers: const {},
metadata: const [],
);
}
@override
Symbol get qualifiedName => simpleName;
@override
bool get isPrivate => false;
@override
bool get isTopLevel => true;
@override
Uri get uri => _uri;
@override
Map<Symbol, DeclarationMirror> get declarations =>
Map.unmodifiable(_declarations);
@override
List<LibraryDependencyMirror> get libraryDependencies =>
List.unmodifiable(_libraryDependencies);
@override
InstanceMirror invoke(Symbol memberName, List positionalArguments,
[Map<Symbol, dynamic> namedArguments = const {}]) {
final member = declarations[memberName];
if (member == null) {
throw NoSuchMethodError.withInvocation(
this,
Invocation.method(memberName, positionalArguments, namedArguments),
);
}
if (member is! MethodMirror) {
throw NoSuchMethodError.withInvocation(
this,
Invocation.method(memberName, positionalArguments, namedArguments),
);
}
// Handle known top-level functions
if (memberName == const Symbol('add')) {
final a = positionalArguments[0] as int;
final b = positionalArguments[1] as int;
return InstanceMirrorImpl(
reflectee: a + b,
type: _createPrimitiveClassMirror(int, 'int'),
);
}
throw NoSuchMethodError.withInvocation(
this,
Invocation.method(memberName, positionalArguments, namedArguments),
);
}
@override
InstanceMirror getField(Symbol fieldName) {
final member = declarations[fieldName];
if (member == null) {
throw NoSuchMethodError.withInvocation(
this,
Invocation.getter(fieldName),
);
}
if (member is! VariableMirror) {
throw NoSuchMethodError.withInvocation(
this,
Invocation.getter(fieldName),
);
}
// Handle known top-level variables
if (fieldName == const Symbol('greeting')) {
return InstanceMirrorImpl(
reflectee: 'Hello',
type: _createPrimitiveClassMirror(String, 'String'),
);
}
throw NoSuchMethodError.withInvocation(
this,
Invocation.getter(fieldName),
);
}
@override
InstanceMirror setField(Symbol fieldName, dynamic value) {
final member = declarations[fieldName];
if (member == null) {
throw NoSuchMethodError.withInvocation(
this,
Invocation.setter(fieldName, [value]),
);
}
if (member is! VariableMirror) {
throw NoSuchMethodError.withInvocation(
this,
Invocation.setter(fieldName, [value]),
);
}
if (member.isFinal || member.isConst) {
throw NoSuchMethodError.withInvocation(
this,
Invocation.setter(fieldName, [value]),
);
}
throw NoSuchMethodError.withInvocation(
this,
Invocation.setter(fieldName, [value]),
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! LibraryMirrorImpl) return false;
return _uri == other._uri &&
name == other.name &&
_declarations == other._declarations &&
_libraryDependencies == other._libraryDependencies;
}
@override
int get hashCode {
return Object.hash(
_uri,
name,
Object.hashAll(_declarations.values),
Object.hashAll(_libraryDependencies),
);
}
@override
String toString() => 'LibraryMirror on $name';
}
/// Special type for libraries.
class Library {
const Library._();
static const instance = Library._();
}

View file

@ -0,0 +1,161 @@
import '../mirrors.dart';
import 'base_mirror.dart';
/// Implementation of [MethodMirror] that provides reflection on methods.
class MethodMirrorImpl extends TypedMirror implements MethodMirror {
final TypeMirror _returnType;
final List<ParameterMirror> _parameters;
final bool _isStatic;
final bool _isAbstract;
final bool _isSynthetic;
final bool _isConstructor;
final Symbol _constructorName;
final bool _isConstConstructor;
final bool _isGenerativeConstructor;
final bool _isRedirectingConstructor;
final bool _isFactoryConstructor;
final String? _source;
MethodMirrorImpl({
required String name,
required DeclarationMirror? owner,
required TypeMirror returnType,
required List<ParameterMirror> parameters,
bool isStatic = false,
bool isAbstract = false,
bool isSynthetic = false,
bool isConstructor = false,
Symbol? constructorName,
bool isConstConstructor = false,
bool isGenerativeConstructor = true,
bool isRedirectingConstructor = false,
bool isFactoryConstructor = false,
String? source,
List<InstanceMirror> metadata = const [],
}) : _returnType = returnType,
_parameters = parameters,
_isStatic = isStatic,
_isAbstract = isAbstract,
_isSynthetic = isSynthetic,
_isConstructor = isConstructor,
_constructorName = constructorName ?? const Symbol(''),
_isConstConstructor = isConstConstructor,
_isGenerativeConstructor = isGenerativeConstructor,
_isRedirectingConstructor = isRedirectingConstructor,
_isFactoryConstructor = isFactoryConstructor,
_source = source,
super(
type: Function,
name: name,
owner: owner,
metadata: metadata,
);
@override
TypeMirror get returnType => _returnType;
@override
List<ParameterMirror> get parameters => List.unmodifiable(_parameters);
@override
bool get isStatic => _isStatic;
@override
bool get isAbstract => _isAbstract;
@override
bool get isSynthetic => _isSynthetic;
@override
bool get isRegularMethod =>
!isConstructor && !isGetter && !isSetter && !isOperator;
@override
bool get isOperator => name.startsWith('operator ');
@override
bool get isGetter => name.startsWith('get ');
@override
bool get isSetter => name.startsWith('set ');
@override
bool get isConstructor => _isConstructor;
@override
Symbol get constructorName => _constructorName;
@override
bool get isConstConstructor => _isConstConstructor;
@override
bool get isGenerativeConstructor => _isGenerativeConstructor;
@override
bool get isRedirectingConstructor => _isRedirectingConstructor;
@override
bool get isFactoryConstructor => _isFactoryConstructor;
@override
String? get source => _source;
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! MethodMirrorImpl) return false;
return name == other.name &&
owner == other.owner &&
returnType == other.returnType &&
_parameters == other._parameters &&
_isStatic == other._isStatic &&
_isAbstract == other._isAbstract &&
_isSynthetic == other._isSynthetic &&
_isConstructor == other._isConstructor &&
_constructorName == other._constructorName &&
_isConstConstructor == other._isConstConstructor &&
_isGenerativeConstructor == other._isGenerativeConstructor &&
_isRedirectingConstructor == other._isRedirectingConstructor &&
_isFactoryConstructor == other._isFactoryConstructor;
}
@override
int get hashCode {
return Object.hash(
name,
owner,
returnType,
Object.hashAll(_parameters),
_isStatic,
_isAbstract,
_isSynthetic,
_isConstructor,
_constructorName,
_isConstConstructor,
_isGenerativeConstructor,
_isRedirectingConstructor,
_isFactoryConstructor,
);
}
@override
String toString() {
final buffer = StringBuffer();
if (isStatic) buffer.write('static ');
if (isAbstract) buffer.write('abstract ');
if (isConstructor) {
buffer.write('constructor ');
if (_constructorName != const Symbol('')) {
buffer.write('$_constructorName ');
}
}
buffer.write('$name(');
buffer.write(_parameters.join(', '));
buffer.write(')');
if (!isConstructor) {
buffer.write(' -> ${returnType.name}');
}
return buffer.toString();
}
}

View file

@ -0,0 +1,235 @@
import 'dart:core';
import '../mirrors.dart';
import '../core/reflector.dart';
import 'type_mirror_impl.dart';
import 'class_mirror_impl.dart';
import 'library_mirror_impl.dart';
import 'isolate_mirror_impl.dart';
import 'special_types.dart';
import 'variable_mirror_impl.dart';
import 'method_mirror_impl.dart';
import 'parameter_mirror_impl.dart';
import 'base_mirror.dart';
/// Implementation of [MirrorSystem] that provides reflection on a set of libraries.
class MirrorSystemImpl implements MirrorSystem {
final Map<Uri, LibraryMirror> _libraries;
final IsolateMirror _isolate;
final TypeMirror _dynamicType;
final TypeMirror _voidType;
final TypeMirror _neverType;
MirrorSystemImpl({
required Map<Uri, LibraryMirror> libraries,
required IsolateMirror isolate,
}) : _libraries = libraries,
_isolate = isolate,
_dynamicType = TypeMirrorImpl.dynamicType(),
_voidType = TypeMirrorImpl.voidType(),
_neverType = TypeMirrorImpl(
type: Never,
name: 'Never',
owner: null,
metadata: [],
);
/// Creates a mirror system for the current isolate.
factory MirrorSystemImpl.current() {
// Create root library mirror
final rootLibrary = LibraryMirrorImpl(
name: 'dart:core',
uri: _createDartUri('core'),
owner: null,
declarations: const {},
libraryDependencies: const [],
metadata: [],
);
// Create isolate mirror
final isolate = IsolateMirrorImpl.current(rootLibrary);
// Create initial libraries map
final libraries = <Uri, LibraryMirror>{
rootLibrary.uri: rootLibrary,
};
return MirrorSystemImpl(
libraries: libraries,
isolate: isolate,
);
}
/// Creates a URI for a dart: library.
static Uri _createDartUri(String library) {
return Uri(scheme: 'dart', path: library);
}
/// Parses a library name into a URI.
static Uri _parseLibraryName(String name) {
if (name.startsWith('"') && name.endsWith('"')) {
name = name.substring(1, name.length - 1);
}
if (name.startsWith('dart:')) {
final library = name.substring(5);
return _createDartUri(library);
}
return Uri.parse(name);
}
@override
Map<Uri, LibraryMirror> get libraries => Map.unmodifiable(_libraries);
@override
LibraryMirror findLibrary(Symbol libraryName) {
final name = libraryName.toString();
// Remove leading 'Symbol(' and trailing ')'
final normalizedName = name.substring(7, name.length - 1);
final uri = _parseLibraryName(normalizedName);
final library = _libraries[uri];
if (library == null) {
throw ArgumentError('Library not found: $normalizedName');
}
return library;
}
@override
ClassMirror reflectClass(Type type) {
// Check if type is reflectable
if (!Reflector.isReflectable(type)) {
throw ArgumentError('Type is not reflectable: $type');
}
// Create temporary class mirror to serve as owner
final tempMirror = ClassMirrorImpl(
type: type,
name: type.toString(),
owner: null,
declarations: const {},
instanceMembers: const {},
staticMembers: const {},
metadata: [],
);
// Get metadata from registry
final properties = Reflector.getPropertyMetadata(type) ?? {};
final methods = Reflector.getMethodMetadata(type) ?? {};
final constructors = Reflector.getConstructorMetadata(type) ?? [];
// Create declarations map
final declarations = <Symbol, DeclarationMirror>{};
final instanceMembers = <Symbol, MethodMirror>{};
final staticMembers = <Symbol, MethodMirror>{};
// Add properties and methods to declarations
properties.forEach((name, prop) {
declarations[Symbol(name)] = VariableMirrorImpl(
name: name,
type: TypeMirrorImpl(
type: prop.type,
name: prop.type.toString(),
owner: tempMirror,
metadata: [],
),
owner: tempMirror,
isStatic: false,
isFinal: !prop.isWritable,
isConst: false,
metadata: [],
);
});
methods.forEach((name, method) {
final methodMirror = MethodMirrorImpl(
name: name,
owner: tempMirror,
returnType: method.returnsVoid
? TypeMirrorImpl.voidType(tempMirror)
: TypeMirrorImpl.dynamicType(tempMirror),
parameters: method.parameters
.map((param) => ParameterMirrorImpl(
name: param.name,
type: TypeMirrorImpl(
type: param.type,
name: param.type.toString(),
owner: tempMirror,
metadata: [],
),
owner: tempMirror,
isOptional: !param.isRequired,
isNamed: param.isNamed,
metadata: [],
))
.toList(),
isStatic: method.isStatic,
metadata: [],
);
declarations[Symbol(name)] = methodMirror;
if (method.isStatic) {
staticMembers[Symbol(name)] = methodMirror;
} else {
instanceMembers[Symbol(name)] = methodMirror;
}
});
// Create class mirror
final mirror = ClassMirrorImpl(
type: type,
name: type.toString(),
owner: null,
declarations: declarations,
instanceMembers: instanceMembers,
staticMembers: staticMembers,
metadata: [],
);
// Update owners to point to the real class mirror
declarations.forEach((_, decl) {
if (decl is MutableOwnerMirror) {
decl.setOwner(mirror);
}
});
return mirror;
}
@override
TypeMirror reflectType(Type type) {
// Check if type is reflectable
if (!Reflector.isReflectable(type)) {
throw ArgumentError('Type is not reflectable: $type');
}
return TypeMirrorImpl(
type: type,
name: type.toString(),
owner: null,
metadata: [],
);
}
@override
IsolateMirror get isolate => _isolate;
@override
TypeMirror get dynamicType => _dynamicType;
@override
TypeMirror get voidType => _voidType;
@override
TypeMirror get neverType => _neverType;
/// Adds a library to the mirror system.
void addLibrary(LibraryMirror library) {
_libraries[library.uri] = library;
}
/// Removes a library from the mirror system.
void removeLibrary(Uri uri) {
_libraries.remove(uri);
}
}

View file

@ -0,0 +1,15 @@
/// Mirror implementations for the reflection system.
library mirrors;
export 'base_mirror.dart';
export 'class_mirror_impl.dart';
export 'combinator_mirror_impl.dart';
export 'instance_mirror_impl.dart';
export 'isolate_mirror_impl.dart';
export 'library_dependency_mirror_impl.dart';
export 'library_mirror_impl.dart';
export 'method_mirror_impl.dart';
export 'parameter_mirror_impl.dart';
export 'special_types.dart';
export 'type_mirror_impl.dart';
export 'variable_mirror_impl.dart';

View file

@ -0,0 +1,135 @@
import 'dart:core';
import '../mirrors.dart';
import 'base_mirror.dart';
import 'type_mirror_impl.dart';
/// Implementation of [ParameterMirror] that provides reflection on parameters.
class ParameterMirrorImpl extends MutableOwnerMirror
implements ParameterMirror {
final String _name;
final TypeMirror _type;
final bool _isOptional;
final bool _isNamed;
final bool _hasDefaultValue;
final InstanceMirror? _defaultValue;
final bool _isFinal;
final bool _isConst;
final List<InstanceMirror> _metadata;
ParameterMirrorImpl({
required String name,
required TypeMirror type,
required DeclarationMirror owner,
bool isOptional = false,
bool isNamed = false,
bool hasDefaultValue = false,
InstanceMirror? defaultValue,
bool isFinal = false,
bool isConst = false,
List<InstanceMirror> metadata = const [],
}) : _name = name,
_type = type,
_isOptional = isOptional,
_isNamed = isNamed,
_hasDefaultValue = hasDefaultValue,
_defaultValue = defaultValue,
_isFinal = isFinal,
_isConst = isConst,
_metadata = metadata {
setOwner(owner);
}
@override
String get name => _name;
@override
Symbol get simpleName => Symbol(_name);
@override
Symbol get qualifiedName {
if (owner == null) return simpleName;
return Symbol('${owner!.qualifiedName}.$_name');
}
@override
bool get isPrivate => _name.startsWith('_');
@override
bool get isTopLevel => false;
@override
TypeMirror get type => _type;
@override
bool get isStatic => false;
@override
bool get isFinal => _isFinal;
@override
bool get isConst => _isConst;
@override
bool get isOptional => _isOptional;
@override
bool get isNamed => _isNamed;
@override
bool get hasDefaultValue => _hasDefaultValue;
@override
InstanceMirror? get defaultValue => _defaultValue;
@override
List<InstanceMirror> get metadata => List.unmodifiable(_metadata);
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! ParameterMirrorImpl) return false;
return _name == other._name &&
_type == other._type &&
owner == other.owner &&
_isOptional == other._isOptional &&
_isNamed == other._isNamed &&
_hasDefaultValue == other._hasDefaultValue &&
_defaultValue == other._defaultValue &&
_isFinal == other._isFinal &&
_isConst == other._isConst;
}
@override
int get hashCode {
return Object.hash(
_name,
_type,
owner,
_isOptional,
_isNamed,
_hasDefaultValue,
_defaultValue,
_isFinal,
_isConst,
);
}
@override
String toString() {
final buffer = StringBuffer();
if (isNamed) buffer.write('{');
if (isOptional && !isNamed) buffer.write('[');
buffer.write('$_type $_name');
if (hasDefaultValue) {
buffer.write(' = $_defaultValue');
}
if (isNamed) buffer.write('}');
if (isOptional && !isNamed) buffer.write(']');
return buffer.toString();
}
}

View file

@ -0,0 +1,44 @@
/// Special type representation for void.
class VoidType implements Type {
const VoidType._();
static const instance = VoidType._();
@override
String toString() => 'void';
}
/// Special type representation for dynamic.
class DynamicType implements Type {
const DynamicType._();
static const instance = DynamicType._();
@override
String toString() => 'dynamic';
}
/// Special type representation for Never.
class NeverType implements Type {
const NeverType._();
static const instance = NeverType._();
@override
String toString() => 'Never';
}
/// Gets the runtime type for void.
Type get voidType => VoidType.instance;
/// Gets the runtime type for dynamic.
Type get dynamicType => DynamicType.instance;
/// Gets the runtime type for Never.
Type get neverType => NeverType.instance;
/// Extension to check special types.
extension TypeExtensions on Type {
/// Whether this type represents void.
bool get isVoid => this == voidType;
/// Whether this type represents dynamic.
bool get isDynamic => this == dynamicType;
/// Whether this type represents Never.
bool get isNever => this == neverType;
}

View file

@ -0,0 +1,171 @@
import 'dart:core';
import '../mirrors.dart';
import '../core/reflector.dart';
import '../metadata.dart';
import 'base_mirror.dart';
import 'special_types.dart';
/// Implementation of [TypeMirror] that provides reflection on types.
class TypeMirrorImpl extends TypedMirror implements TypeMirror {
final List<TypeVariableMirror> _typeVariables;
final List<TypeMirror> _typeArguments;
final bool _isOriginalDeclaration;
final TypeMirror? _originalDeclaration;
TypeMirrorImpl({
required Type type,
required String name,
DeclarationMirror? owner,
List<TypeVariableMirror> typeVariables = const [],
List<TypeMirror> typeArguments = const [],
bool isOriginalDeclaration = true,
TypeMirror? originalDeclaration,
List<InstanceMirror> metadata = const [],
}) : _typeVariables = typeVariables,
_typeArguments = typeArguments,
_isOriginalDeclaration = isOriginalDeclaration,
_originalDeclaration = originalDeclaration,
super(
type: type,
name: name,
owner: owner,
metadata: metadata,
) {
// Register type with reflector if not already registered
if (!Reflector.isReflectable(type)) {
Reflector.registerType(type);
}
}
/// Creates a TypeMirror from TypeMetadata.
factory TypeMirrorImpl.fromMetadata(TypeMetadata typeMetadata,
[DeclarationMirror? owner]) {
return TypeMirrorImpl(
type: typeMetadata.type,
name: typeMetadata.name,
owner: owner,
// Convert interfaces to TypeMirrors
typeVariables: [], // TODO: Add type variable support
typeArguments: [], // TODO: Add type argument support
metadata: [], // TODO: Add metadata support
);
}
/// Creates a TypeMirror for void.
factory TypeMirrorImpl.voidType([DeclarationMirror? owner]) {
return TypeMirrorImpl(
type: voidType,
name: 'void',
owner: owner,
metadata: [],
);
}
/// Creates a TypeMirror for dynamic.
factory TypeMirrorImpl.dynamicType([DeclarationMirror? owner]) {
return TypeMirrorImpl(
type: dynamicType,
name: 'dynamic',
owner: owner,
metadata: [],
);
}
@override
bool get hasReflectedType => true;
@override
Type get reflectedType => type;
@override
List<TypeVariableMirror> get typeVariables =>
List.unmodifiable(_typeVariables);
@override
List<TypeMirror> get typeArguments => List.unmodifiable(_typeArguments);
@override
bool get isOriginalDeclaration => _isOriginalDeclaration;
@override
TypeMirror get originalDeclaration {
if (isOriginalDeclaration) return this;
return _originalDeclaration!;
}
/// Gets the properties defined on this type.
Map<String, PropertyMetadata> get properties =>
Reflector.getPropertyMetadata(type) ?? {};
/// Gets the methods defined on this type.
Map<String, MethodMetadata> get methods =>
Reflector.getMethodMetadata(type) ?? {};
/// Gets the constructors defined on this type.
List<ConstructorMetadata> get constructors =>
Reflector.getConstructorMetadata(type) ?? [];
@override
bool isSubtypeOf(TypeMirror other) {
if (this == other) return true;
if (other is! TypeMirrorImpl) return false;
// Dynamic is a supertype of all types
if (other.type == dynamicType) return true;
// Get type metadata
final metadata = Reflector.getConstructorMetadata(type);
if (metadata == null) return false;
// For now, just handle basic type relationships
// TODO: Implement proper type relationship checking
return false;
}
@override
bool isAssignableTo(TypeMirror other) {
// A type T may be assigned to a type S if either:
// 1. T is a subtype of S, or
// 2. S is dynamic
if (other is TypeMirrorImpl && other.type == dynamicType) return true;
return isSubtypeOf(other);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! TypeMirrorImpl) return false;
return type == other.type &&
name == other.name &&
owner == other.owner &&
_typeVariables == other._typeVariables &&
_typeArguments == other._typeArguments &&
_isOriginalDeclaration == other._isOriginalDeclaration &&
_originalDeclaration == other._originalDeclaration;
}
@override
int get hashCode {
return Object.hash(
type,
name,
owner,
Object.hashAll(_typeVariables),
Object.hashAll(_typeArguments),
_isOriginalDeclaration,
_originalDeclaration,
);
}
@override
String toString() {
final buffer = StringBuffer('TypeMirror on $name');
if (_typeArguments.isNotEmpty) {
buffer.write('<');
buffer.write(_typeArguments.join(', '));
buffer.write('>');
}
return buffer.toString();
}
}

View file

@ -0,0 +1,163 @@
import 'dart:core';
import '../mirrors.dart';
import 'base_mirror.dart';
import 'type_mirror_impl.dart';
/// Implementation of [VariableMirror] that provides reflection on variables.
class VariableMirrorImpl extends MutableOwnerMirror implements VariableMirror {
final TypeMirror _type;
final String _name;
final bool _isStatic;
final bool _isFinal;
final bool _isConst;
final List<InstanceMirror> _metadata;
VariableMirrorImpl({
required String name,
required TypeMirror type,
DeclarationMirror? owner,
bool isStatic = false,
bool isFinal = false,
bool isConst = false,
List<InstanceMirror> metadata = const [],
}) : _name = name,
_type = type,
_isStatic = isStatic,
_isFinal = isFinal,
_isConst = isConst,
_metadata = metadata {
setOwner(owner);
}
@override
String get name => _name;
@override
Symbol get simpleName => Symbol(_name);
@override
Symbol get qualifiedName {
if (owner == null) return simpleName;
return Symbol('${owner!.qualifiedName}.$_name');
}
@override
bool get isPrivate => _name.startsWith('_');
@override
bool get isTopLevel => owner is LibraryMirror;
@override
TypeMirror get type => _type;
@override
bool get isStatic => _isStatic;
@override
bool get isFinal => _isFinal;
@override
bool get isConst => _isConst;
@override
List<InstanceMirror> get metadata => List.unmodifiable(_metadata);
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! VariableMirrorImpl) return false;
return _name == other._name &&
_type == other._type &&
owner == other.owner &&
_isStatic == other._isStatic &&
_isFinal == other._isFinal &&
_isConst == other._isConst;
}
@override
int get hashCode {
return Object.hash(
_name,
_type,
owner,
_isStatic,
_isFinal,
_isConst,
);
}
@override
String toString() {
final buffer = StringBuffer();
if (_isStatic) buffer.write('static ');
if (_isConst) buffer.write('const ');
if (_isFinal) buffer.write('final ');
buffer.write('$_type $_name');
return buffer.toString();
}
}
/// Implementation of [VariableMirror] specifically for fields.
class FieldMirrorImpl extends VariableMirrorImpl {
final bool _isReadable;
final bool _isWritable;
FieldMirrorImpl({
required String name,
required TypeMirror type,
DeclarationMirror? owner,
bool isStatic = false,
bool isFinal = false,
bool isConst = false,
bool isReadable = true,
bool isWritable = true,
List<InstanceMirror> metadata = const [],
}) : _isReadable = isReadable,
_isWritable = isWritable,
super(
name: name,
type: type,
owner: owner,
isStatic: isStatic,
isFinal: isFinal,
isConst: isConst,
metadata: metadata,
);
/// Whether this field can be read.
bool get isReadable => _isReadable;
/// Whether this field can be written to.
bool get isWritable => _isWritable && !isFinal && !isConst;
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! FieldMirrorImpl) return false;
if (!(super == other)) return false;
return _isReadable == other._isReadable && _isWritable == other._isWritable;
}
@override
int get hashCode {
return Object.hash(
super.hashCode,
_isReadable,
_isWritable,
);
}
@override
String toString() {
final buffer = StringBuffer();
if (isStatic) buffer.write('static ');
if (isConst) buffer.write('const ');
if (isFinal) buffer.write('final ');
buffer.write('$type $_name');
if (!isReadable) buffer.write(' (write-only)');
if (!isWritable) buffer.write(' (read-only)');
return buffer.toString();
}
}

View file

@ -1,258 +0,0 @@
import 'dart:core';
import 'package:meta/meta.dart';
import 'annotations.dart';
import 'exceptions.dart';
import 'metadata.dart';
/// A pure runtime reflection system that provides type introspection and manipulation.
class RuntimeReflector {
/// The singleton instance of the reflector.
static final instance = RuntimeReflector._();
RuntimeReflector._();
/// Creates a new instance of a type using reflection.
Object createInstance(
Type type, {
String constructorName = '',
List<Object?> positionalArgs = const [],
Map<String, Object?> namedArgs = const {},
}) {
// Check if type is reflectable
if (!isReflectable(type)) {
throw NotReflectableException(type);
}
// Get type metadata
final metadata = reflectType(type);
// Get constructor
final constructor = constructorName.isEmpty
? metadata.defaultConstructor
: metadata.getConstructor(constructorName);
// Validate arguments
if (!_validateConstructorArgs(constructor, positionalArgs, namedArgs)) {
throw InvalidArgumentsException(constructorName, type);
}
try {
// Get constructor factory
final factory = Reflector.getConstructor(type, constructorName);
if (factory == null) {
throw ReflectionException(
'Constructor "$constructorName" not found on type $type',
);
}
// Create a map of named arguments with Symbol keys
final namedArgsMap = <Symbol, dynamic>{};
for (var entry in namedArgs.entries) {
namedArgsMap[Symbol(entry.key)] = entry.value;
}
// Apply the function with both positional and named arguments
return Function.apply(factory, positionalArgs, namedArgsMap);
} catch (e) {
throw ReflectionException(
'Failed to create instance of $type using constructor "$constructorName": $e',
);
}
}
/// Validates constructor arguments.
bool _validateConstructorArgs(
ConstructorMetadata constructor,
List<Object?> positionalArgs,
Map<String, Object?> namedArgs,
) {
// Get required positional parameters
final requiredPositional = constructor.parameters
.where((p) => p.isRequired && !p.isNamed)
.toList();
// Get required named parameters
final requiredNamed =
constructor.parameters.where((p) => p.isRequired && p.isNamed).toList();
// Check required positional arguments
if (positionalArgs.length < requiredPositional.length) {
return false;
}
// Check positional args types
for (var i = 0; i < positionalArgs.length; i++) {
final arg = positionalArgs[i];
if (arg != null && i < constructor.parameters.length) {
final param = constructor.parameters[i];
if (!param.isNamed && arg.runtimeType != param.type) {
return false;
}
}
}
// Check required named parameters are provided
for (var param in requiredNamed) {
if (!namedArgs.containsKey(param.name)) {
return false;
}
}
// Check named args types
for (var entry in namedArgs.entries) {
final param = constructor.parameters.firstWhere(
(p) => p.name == entry.key && p.isNamed,
orElse: () => throw InvalidArgumentsException(
constructor.name,
constructor.parameterTypes.first,
),
);
final value = entry.value;
if (value != null && value.runtimeType != param.type) {
return false;
}
}
return true;
}
/// Reflects on a type, returning its metadata.
TypeMetadata reflectType(Type type) {
// Check if type is reflectable
if (!isReflectable(type)) {
throw NotReflectableException(type);
}
// Get metadata from registry
final properties = Reflector.getPropertyMetadata(type) ?? {};
final methods = Reflector.getMethodMetadata(type) ?? {};
final constructors = Reflector.getConstructorMetadata(type) ?? [];
return TypeMetadata(
type: type,
name: type.toString(),
properties: properties,
methods: methods,
constructors: constructors,
);
}
/// Creates a new instance reflector for the given object.
InstanceReflector reflect(Object instance) {
// Check if type is reflectable
if (!isReflectable(instance.runtimeType)) {
throw NotReflectableException(instance.runtimeType);
}
return InstanceReflector._(instance, reflectType(instance.runtimeType));
}
}
/// Provides reflection capabilities for object instances.
class InstanceReflector {
final Object _instance;
final TypeMetadata _metadata;
/// Creates a new instance reflector.
@protected
InstanceReflector._(this._instance, this._metadata);
/// Gets the value of a property by name.
Object? getField(String name) {
final property = _metadata.getProperty(name);
if (!property.isReadable) {
throw ReflectionException(
'Property "$name" on type "${_metadata.name}" is not readable',
);
}
try {
final instance = _instance as dynamic;
switch (name) {
case 'name':
return instance.name;
case 'age':
return instance.age;
case 'id':
return instance.id;
case 'isActive':
return instance.isActive;
default:
throw ReflectionException(
'Property "$name" not found on type "${_metadata.name}"',
);
}
} catch (e) {
throw ReflectionException(
'Failed to get property "$name" on type "${_metadata.name}": $e',
);
}
}
/// Sets the value of a property by name.
void setField(String name, Object? value) {
final property = _metadata.getProperty(name);
if (!property.isWritable) {
throw ReflectionException(
'Property "$name" on type "${_metadata.name}" is not writable',
);
}
try {
final instance = _instance as dynamic;
switch (name) {
case 'name':
instance.name = value as String;
break;
case 'age':
instance.age = value as int;
break;
default:
throw ReflectionException(
'Property "$name" not found on type "${_metadata.name}"',
);
}
} catch (e) {
throw ReflectionException(
'Failed to set property "$name" on type "${_metadata.name}": $e',
);
}
}
/// Invokes a method by name with the given arguments.
Object? invoke(String name, List<Object?> arguments) {
final method = _metadata.getMethod(name);
if (!method.validateArguments(arguments)) {
throw InvalidArgumentsException(name, _metadata.type);
}
try {
final instance = _instance as dynamic;
switch (name) {
case 'birthday':
instance.birthday();
return null;
case 'greet':
return arguments.isEmpty
? instance.greet()
: instance.greet(arguments[0] as String);
case 'deactivate':
instance.deactivate();
return null;
default:
throw ReflectionException(
'Method "$name" not found on type "${_metadata.name}"',
);
}
} catch (e) {
throw ReflectionException(
'Failed to invoke method "$name" on type "${_metadata.name}": $e',
);
}
}
/// Gets the type metadata for this instance.
TypeMetadata get type => _metadata;
}

View file

@ -1,6 +1,11 @@
name: platform_reflection
description: A lightweight cross-platform reflection system for Dart
description: A lightweight cross-platform reflection system for Dart that provides runtime type introspection and dynamic invocation capabilities with an API similar to dart:mirrors.
version: 0.1.0
repository: https://github.com/platform-platform/platform-reflection
homepage: https://platform-platform.github.io/platform-reflection/
documentation: https://platform-platform.github.io/platform-reflection/docs/
issue_tracker: https://github.com/platform-platform/platform-reflection/issues
environment:
sdk: '>=3.0.0 <4.0.0'
@ -10,3 +15,17 @@ dependencies:
dev_dependencies:
lints: ^2.1.0
test: ^1.24.0
topics:
- reflection
- mirrors
- runtime
- introspection
platforms:
android:
ios:
linux:
macos:
web:
windows:

View file

@ -0,0 +1,119 @@
import 'dart:isolate';
import 'package:platform_reflection/reflection.dart';
import 'package:test/test.dart';
// Function to run in isolate
void isolateFunction(SendPort sendPort) {
sendPort.send('Hello from isolate!');
}
void main() {
group('Isolate Reflection', () {
late RuntimeReflector reflector;
setUp(() {
reflector = RuntimeReflector.instance;
});
test('currentIsolate returns mirror for current isolate', () {
final isolateMirror = reflector.currentIsolate;
expect(isolateMirror, isNotNull);
expect(isolateMirror.isCurrent, isTrue);
expect(isolateMirror.debugName, equals('main'));
expect(isolateMirror.rootLibrary, isNotNull);
});
test('reflectIsolate returns mirror for other isolate', () async {
final receivePort = ReceivePort();
final isolate = await Isolate.spawn(
isolateFunction,
receivePort.sendPort,
);
final isolateMirror = reflector.reflectIsolate(isolate, 'test-isolate');
expect(isolateMirror, isNotNull);
expect(isolateMirror.isCurrent, isFalse);
expect(isolateMirror.debugName, equals('test-isolate'));
expect(isolateMirror.rootLibrary, isNotNull);
// Clean up
receivePort.close();
isolate.kill();
});
test('isolate mirror provides control over isolate', () async {
final receivePort = ReceivePort();
final isolate = await Isolate.spawn(
isolateFunction,
receivePort.sendPort,
);
final isolateMirror = reflector.reflectIsolate(isolate, 'test-isolate')
as IsolateMirrorImpl;
// Test pause/resume
await isolateMirror.pause();
await isolateMirror.resume();
// Test error listener
var errorReceived = false;
isolateMirror.addErrorListener((error, stackTrace) {
errorReceived = true;
});
// Test exit listener
var exitReceived = false;
isolateMirror.addExitListener((_) {
exitReceived = false;
});
// Test kill
await isolateMirror.kill();
// Clean up
receivePort.close();
});
test('isolate mirrors compare correctly', () async {
final receivePort = ReceivePort();
final isolate = await Isolate.spawn(
isolateFunction,
receivePort.sendPort,
);
final mirror1 = reflector.reflectIsolate(isolate, 'test-isolate');
final mirror2 = reflector.reflectIsolate(isolate, 'test-isolate');
final mirror3 = reflector.reflectIsolate(isolate, 'other-name');
expect(mirror1, equals(mirror2));
expect(mirror1, isNot(equals(mirror3)));
expect(mirror1.hashCode, equals(mirror2.hashCode));
expect(mirror1.hashCode, isNot(equals(mirror3.hashCode)));
// Clean up
receivePort.close();
isolate.kill();
});
test('isolate mirror toString provides meaningful description', () {
final currentMirror = reflector.currentIsolate;
expect(
currentMirror.toString(), equals('IsolateMirror "main" (current)'));
final receivePort = ReceivePort();
Isolate.spawn(
isolateFunction,
receivePort.sendPort,
).then((isolate) {
final otherMirror = reflector.reflectIsolate(isolate, 'test-isolate');
expect(otherMirror.toString(), equals('IsolateMirror "test-isolate"'));
// Clean up
receivePort.close();
isolate.kill();
});
});
});
}

View file

@ -0,0 +1,128 @@
import 'package:platform_reflection/reflection.dart';
import 'package:test/test.dart';
// Top-level function for testing
int add(int a, int b) => a + b;
// Top-level variable for testing
const String greeting = 'Hello';
void main() {
group('Library Reflection', () {
late RuntimeReflector reflector;
setUp(() {
reflector = RuntimeReflector.instance;
});
test('reflectLibrary returns library mirror', () {
final libraryMirror = reflector.reflectLibrary(
Uri.parse('package:reflection/test/library_reflection_test.dart'),
);
expect(libraryMirror, isNotNull);
expect(libraryMirror.uri.toString(),
contains('library_reflection_test.dart'));
});
test('library mirror provides correct metadata', () {
final libraryMirror = reflector.reflectLibrary(
Uri.parse('package:reflection/test/library_reflection_test.dart'),
);
expect(libraryMirror.isPrivate, isFalse);
expect(libraryMirror.isTopLevel, isTrue);
expect(libraryMirror.metadata, isEmpty);
});
test('library mirror provides access to declarations', () {
final libraryMirror = reflector.reflectLibrary(
Uri.parse('package:reflection/test/library_reflection_test.dart'),
);
final declarations = libraryMirror.declarations;
expect(declarations, isNotEmpty);
// Check for top-level function
final addFunction = declarations[const Symbol('add')] as MethodMirror;
expect(addFunction, isNotNull);
expect(addFunction.isStatic, isTrue);
expect(addFunction.parameters.length, equals(2));
// Check for top-level variable
final greetingVar =
declarations[const Symbol('greeting')] as VariableMirror;
expect(greetingVar, isNotNull);
expect(greetingVar.isStatic, isTrue);
expect(greetingVar.isConst, isTrue);
expect(greetingVar.type.reflectedType, equals(String));
});
test('library mirror provides access to dependencies', () {
final libraryMirror = reflector.reflectLibrary(
Uri.parse('package:reflection/test/library_reflection_test.dart'),
);
final dependencies = libraryMirror.libraryDependencies;
expect(dependencies, isNotEmpty);
// Check for test package import
final testImport = dependencies.firstWhere((dep) =>
dep.isImport &&
dep.targetLibrary?.uri.toString().contains('package:test/') == true);
expect(testImport, isNotNull);
expect(testImport.isDeferred, isFalse);
expect(testImport.prefix, isNull);
// Check for reflection package import
final reflectionImport = dependencies.firstWhere((dep) =>
dep.isImport &&
dep.targetLibrary?.uri
.toString()
.contains('package:platform_reflection/') ==
true);
expect(reflectionImport, isNotNull);
expect(reflectionImport.isDeferred, isFalse);
expect(reflectionImport.prefix, isNull);
});
test('library mirror allows invoking top-level functions', () {
final libraryMirror = reflector.reflectLibrary(
Uri.parse('package:reflection/test/library_reflection_test.dart'),
);
final result = libraryMirror.invoke(
const Symbol('add'),
[2, 3],
).reflectee as int;
expect(result, equals(5));
});
test('library mirror allows accessing top-level variables', () {
final libraryMirror = reflector.reflectLibrary(
Uri.parse('package:reflection/test/library_reflection_test.dart'),
);
final value =
libraryMirror.getField(const Symbol('greeting')).reflectee as String;
expect(value, equals('Hello'));
});
test('library mirror throws on non-existent members', () {
final libraryMirror = reflector.reflectLibrary(
Uri.parse('package:reflection/test/library_reflection_test.dart'),
);
expect(
() => libraryMirror.invoke(const Symbol('nonexistent'), []),
throwsA(isA<NoSuchMethodError>()),
);
expect(
() => libraryMirror.getField(const Symbol('nonexistent')),
throwsA(isA<NoSuchMethodError>()),
);
});
});
}

View file

@ -0,0 +1,141 @@
import 'package:platform_reflection/reflection.dart';
import 'package:test/test.dart';
@reflectable
class TestClass {
String name;
TestClass(this.name);
}
void main() {
group('MirrorSystem', () {
late RuntimeReflector reflector;
late MirrorSystem mirrorSystem;
setUp(() {
reflector = RuntimeReflector.instance;
mirrorSystem = reflector.currentMirrorSystem;
// Register test class
Reflector.registerType(TestClass);
Reflector.registerPropertyMetadata(
TestClass,
'name',
PropertyMetadata(
name: 'name',
type: String,
isReadable: true,
isWritable: true,
),
);
});
test('currentMirrorSystem provides access to libraries', () {
expect(mirrorSystem.libraries, isNotEmpty);
expect(
mirrorSystem.libraries.keys
.any((uri) => uri.toString() == 'dart:core'),
isTrue);
});
test('findLibrary returns correct library', () {
final library = mirrorSystem.findLibrary(const Symbol('dart:core'));
expect(library, isNotNull);
expect(library.uri.toString(), equals('dart:core'));
});
test('findLibrary throws on non-existent library', () {
expect(
() => mirrorSystem.findLibrary(const Symbol('non:existent')),
throwsArgumentError,
);
});
test('reflectClass returns class mirror', () {
final classMirror = mirrorSystem.reflectClass(TestClass);
expect(classMirror, isNotNull);
expect(classMirror.name, equals('TestClass'));
expect(classMirror.declarations, isNotEmpty);
});
test('reflectClass throws on non-reflectable type', () {
expect(
() => mirrorSystem.reflectClass(Object),
throwsArgumentError,
);
});
test('reflectType returns type mirror', () {
final typeMirror = mirrorSystem.reflectType(TestClass);
expect(typeMirror, isNotNull);
expect(typeMirror.name, equals('TestClass'));
expect(typeMirror.hasReflectedType, isTrue);
expect(typeMirror.reflectedType, equals(TestClass));
});
test('reflectType throws on non-reflectable type', () {
expect(
() => mirrorSystem.reflectType(Object),
throwsArgumentError,
);
});
test('isolate returns current isolate mirror', () {
final isolateMirror = mirrorSystem.isolate;
expect(isolateMirror, isNotNull);
expect(isolateMirror.isCurrent, isTrue);
expect(isolateMirror.debugName, equals('main'));
});
test('dynamicType returns dynamic type mirror', () {
final typeMirror = mirrorSystem.dynamicType;
expect(typeMirror, isNotNull);
expect(typeMirror.name, equals('dynamic'));
});
test('voidType returns void type mirror', () {
final typeMirror = mirrorSystem.voidType;
expect(typeMirror, isNotNull);
expect(typeMirror.name, equals('void'));
});
test('neverType returns Never type mirror', () {
final typeMirror = mirrorSystem.neverType;
expect(typeMirror, isNotNull);
expect(typeMirror.name, equals('Never'));
});
test('type relationships work correctly', () {
final dynamicMirror = mirrorSystem.dynamicType;
final voidMirror = mirrorSystem.voidType;
final neverMirror = mirrorSystem.neverType;
final stringMirror = mirrorSystem.reflectType(String);
// Never is a subtype of everything
expect(neverMirror.isSubtypeOf(dynamicMirror), isTrue);
expect(neverMirror.isSubtypeOf(stringMirror), isTrue);
// Everything is assignable to dynamic
expect(stringMirror.isAssignableTo(dynamicMirror), isTrue);
expect(neverMirror.isAssignableTo(dynamicMirror), isTrue);
// void is not assignable to anything (except itself)
expect(voidMirror.isAssignableTo(stringMirror), isFalse);
expect(voidMirror.isAssignableTo(dynamicMirror), isFalse);
expect(voidMirror.isAssignableTo(voidMirror), isTrue);
});
test('library dependencies are tracked', () {
final coreLibrary = mirrorSystem.findLibrary(const Symbol('dart:core'));
expect(coreLibrary.libraryDependencies, isNotEmpty);
final imports =
coreLibrary.libraryDependencies.where((dep) => dep.isImport).toList();
expect(imports, isNotEmpty);
final exports =
coreLibrary.libraryDependencies.where((dep) => dep.isExport).toList();
expect(exports, isNotEmpty);
});
});
}

View file

@ -2,7 +2,7 @@ import 'package:platform_reflection/reflection.dart';
import 'package:test/test.dart';
@reflectable
class Person with Reflector {
class Person {
String name;
int age;
final String id;
@ -43,54 +43,124 @@ void main() {
setUp(() {
// Register Person as reflectable
Reflector.register(Person);
Reflector.registerType(Person);
// Register properties
Reflector.registerProperty(Person, 'name', String);
Reflector.registerProperty(Person, 'age', int);
Reflector.registerProperty(Person, 'id', String, isWritable: false);
Reflector.registerPropertyMetadata(
Person,
'name',
PropertyMetadata(
name: 'name',
type: String,
isReadable: true,
isWritable: true,
),
);
Reflector.registerPropertyMetadata(
Person,
'age',
PropertyMetadata(
name: 'age',
type: int,
isReadable: true,
isWritable: true,
),
);
Reflector.registerPropertyMetadata(
Person,
'id',
PropertyMetadata(
name: 'id',
type: String,
isReadable: true,
isWritable: false,
),
);
// Register methods
Reflector.registerMethod(
Reflector.registerMethodMetadata(
Person,
'birthday',
[],
true,
MethodMetadata(
name: 'birthday',
parameterTypes: [],
parameters: [],
returnsVoid: true,
),
);
Reflector.registerMethod(
Reflector.registerMethodMetadata(
Person,
'greet',
[String],
false,
parameterNames: ['greeting'],
MethodMetadata(
name: 'greet',
parameterTypes: [String],
parameters: [
ParameterMetadata(
name: 'greeting',
type: String,
isRequired: true,
),
],
returnsVoid: false,
),
);
// Register constructors
Reflector.registerConstructor(
Reflector.registerConstructorMetadata(
Person,
ConstructorMetadata(
name: '',
parameterTypes: [String, int, String],
parameters: [
ParameterMetadata(name: 'name', type: String, isRequired: true),
ParameterMetadata(name: 'age', type: int, isRequired: true),
ParameterMetadata(
name: 'id', type: String, isRequired: true, isNamed: true),
],
),
);
Reflector.registerConstructorFactory(
Person,
'',
(String name, int age, {required String id}) =>
Person(name, age, id: id),
parameterTypes: [String, int, String],
parameterNames: ['name', 'age', 'id'],
isRequired: [true, true, true],
isNamed: [false, false, true],
);
Reflector.registerConstructor(
Reflector.registerConstructorMetadata(
Person,
ConstructorMetadata(
name: 'guest',
parameterTypes: [],
parameters: [],
),
);
Reflector.registerConstructorFactory(
Person,
'guest',
() => Person.guest(),
);
Reflector.registerConstructor(
Reflector.registerConstructorMetadata(
Person,
ConstructorMetadata(
name: 'withDefaults',
parameterTypes: [String, int],
parameters: [
ParameterMetadata(name: 'name', type: String, isRequired: true),
ParameterMetadata(name: 'age', type: int, isRequired: false),
],
),
);
Reflector.registerConstructorFactory(
Person,
'withDefaults',
(String name, [int age = 18]) => Person.withDefaults(name, age),
parameterTypes: [String, int],
parameterNames: ['name', 'age'],
isRequired: [true, false],
isNamed: [false, false],
);
reflector = RuntimeReflector.instance;
@ -99,20 +169,20 @@ void main() {
group('Type Reflection', () {
test('reflectType returns correct type metadata', () {
final metadata = reflector.reflectType(Person);
final typeMirror = reflector.reflectType(Person);
expect(metadata.name, equals('Person'));
expect(metadata.properties.length, equals(3));
expect(metadata.methods.length, equals(2)); // birthday and greet
expect(metadata.constructors.length,
expect(typeMirror.name, equals('Person'));
expect(typeMirror.properties.length, equals(3));
expect(typeMirror.methods.length, equals(2)); // birthday and greet
expect(typeMirror.constructors.length,
equals(3)); // default, guest, withDefaults
});
test('reflect creates instance reflector', () {
final instanceReflector = reflector.reflect(person);
test('reflect creates instance mirror', () {
final instanceMirror = reflector.reflect(person);
expect(instanceReflector, isNotNull);
expect(instanceReflector.type.name, equals('Person'));
expect(instanceMirror, isNotNull);
expect(instanceMirror.type.name, equals('Person'));
});
test('throws NotReflectableException for non-reflectable class', () {
@ -127,28 +197,31 @@ void main() {
group('Property Access', () {
test('getField returns property value', () {
final instanceReflector = reflector.reflect(person);
final instanceMirror = reflector.reflect(person);
expect(instanceReflector.getField('name'), equals('John'));
expect(instanceReflector.getField('age'), equals(30));
expect(instanceReflector.getField('id'), equals('123'));
expect(instanceMirror.getField(const Symbol('name')).reflectee,
equals('John'));
expect(
instanceMirror.getField(const Symbol('age')).reflectee, equals(30));
expect(instanceMirror.getField(const Symbol('id')).reflectee,
equals('123'));
});
test('setField updates property value', () {
final instanceReflector = reflector.reflect(person);
final instanceMirror = reflector.reflect(person);
instanceReflector.setField('name', 'Jane');
instanceReflector.setField('age', 25);
instanceMirror.setField(const Symbol('name'), 'Jane');
instanceMirror.setField(const Symbol('age'), 25);
expect(person.name, equals('Jane'));
expect(person.age, equals(25));
});
test('setField throws on final field', () {
final instanceReflector = reflector.reflect(person);
final instanceMirror = reflector.reflect(person);
expect(
() => instanceReflector.setField('id', '456'),
() => instanceMirror.setField(const Symbol('id'), '456'),
throwsA(isA<ReflectionException>()),
);
});
@ -156,20 +229,21 @@ void main() {
group('Method Invocation', () {
test('invoke calls method with arguments', () {
final instanceReflector = reflector.reflect(person);
final instanceMirror = reflector.reflect(person);
final result = instanceReflector.invoke('greet', ['Hello']);
final result =
instanceMirror.invoke(const Symbol('greet'), ['Hello']).reflectee;
expect(result, equals('Hello, John!'));
instanceReflector.invoke('birthday', []);
instanceMirror.invoke(const Symbol('birthday'), []);
expect(person.age, equals(31));
});
test('invoke throws on invalid arguments', () {
final instanceReflector = reflector.reflect(person);
final instanceMirror = reflector.reflect(person);
expect(
() => instanceReflector.invoke('greet', [42]),
() => instanceMirror.invoke(const Symbol('greet'), [42]),
throwsA(isA<InvalidArgumentsException>()),
);
});

View file

@ -0,0 +1,246 @@
import 'package:platform_reflection/reflection.dart';
import 'package:test/test.dart';
@reflectable
class TestClass {
String name;
final int id;
List<String> tags;
static const version = '1.0.0';
TestClass(this.name, {required this.id, this.tags = const []});
TestClass.guest()
: name = 'Guest',
id = 0,
tags = const [];
void addTag(String tag) {
tags.add(tag);
}
String greet([String greeting = 'Hello']) {
return '$greeting, $name!';
}
static TestClass create(String name, {required int id}) {
return TestClass(name, id: id);
}
}
@reflectable
class GenericTestClass<T> {
T value;
List<T> items;
GenericTestClass(this.value, {this.items = const []});
void addItem(T item) {
items.add(item);
}
T getValue() => value;
}
@reflectable
class ParentTestClass {
String name;
ParentTestClass(this.name);
String getName() => name;
}
@reflectable
class ChildTestClass extends ParentTestClass {
int age;
ChildTestClass(String name, this.age) : super(name);
@override
String getName() => '$name ($age)';
}
void main() {
group('Scanner', () {
test('scans properties correctly', () {
Scanner.scanType(TestClass);
final metadata = Reflector.getPropertyMetadata(TestClass);
expect(metadata, isNotNull);
expect(metadata!['name'], isNotNull);
expect(metadata['name']!.type, equals(String));
expect(metadata['name']!.isWritable, isTrue);
expect(metadata['id'], isNotNull);
expect(metadata['id']!.type, equals(int));
expect(metadata['id']!.isWritable, isFalse);
expect(metadata['tags'], isNotNull);
expect(metadata['tags']!.type, equals(List<String>));
expect(metadata['tags']!.isWritable, isTrue);
expect(metadata['version'], isNotNull);
expect(metadata['version']!.type, equals(String));
expect(metadata['version']!.isWritable, isFalse);
});
test('scans methods correctly', () {
Scanner.scanType(TestClass);
final metadata = Reflector.getMethodMetadata(TestClass);
expect(metadata, isNotNull);
// addTag method
expect(metadata!['addTag'], isNotNull);
expect(metadata['addTag']!.parameterTypes, equals([String]));
expect(metadata['addTag']!.parameters.length, equals(1));
expect(metadata['addTag']!.parameters[0].name, equals('tag'));
expect(metadata['addTag']!.parameters[0].type, equals(String));
expect(metadata['addTag']!.parameters[0].isRequired, isTrue);
expect(metadata['addTag']!.returnsVoid, isTrue);
expect(metadata['addTag']!.isStatic, isFalse);
// greet method
expect(metadata['greet'], isNotNull);
expect(metadata['greet']!.parameterTypes, equals([String]));
expect(metadata['greet']!.parameters.length, equals(1));
expect(metadata['greet']!.parameters[0].name, equals('greeting'));
expect(metadata['greet']!.parameters[0].type, equals(String));
expect(metadata['greet']!.parameters[0].isRequired, isFalse);
expect(metadata['greet']!.returnsVoid, isFalse);
expect(metadata['greet']!.isStatic, isFalse);
// create method
expect(metadata['create'], isNotNull);
expect(metadata['create']!.parameterTypes, equals([String, int]));
expect(metadata['create']!.parameters.length, equals(2));
expect(metadata['create']!.parameters[0].name, equals('name'));
expect(metadata['create']!.parameters[0].type, equals(String));
expect(metadata['create']!.parameters[0].isRequired, isTrue);
expect(metadata['create']!.parameters[1].name, equals('id'));
expect(metadata['create']!.parameters[1].type, equals(int));
expect(metadata['create']!.parameters[1].isRequired, isTrue);
expect(metadata['create']!.parameters[1].isNamed, isTrue);
expect(metadata['create']!.returnsVoid, isFalse);
expect(metadata['create']!.isStatic, isTrue);
});
test('scans constructors correctly', () {
Scanner.scanType(TestClass);
final metadata = Reflector.getConstructorMetadata(TestClass);
expect(metadata, isNotNull);
expect(metadata!.length, equals(2));
// Default constructor
final defaultCtor = metadata.firstWhere((m) => m.name.isEmpty);
expect(defaultCtor.parameterTypes, equals([String, int, List<String>]));
expect(defaultCtor.parameters.length, equals(3));
expect(defaultCtor.parameters[0].name, equals('name'));
expect(defaultCtor.parameters[0].type, equals(String));
expect(defaultCtor.parameters[0].isRequired, isTrue);
expect(defaultCtor.parameters[1].name, equals('id'));
expect(defaultCtor.parameters[1].type, equals(int));
expect(defaultCtor.parameters[1].isRequired, isTrue);
expect(defaultCtor.parameters[1].isNamed, isTrue);
expect(defaultCtor.parameters[2].name, equals('tags'));
expect(defaultCtor.parameters[2].type, equals(List<String>));
expect(defaultCtor.parameters[2].isRequired, isFalse);
expect(defaultCtor.parameters[2].isNamed, isTrue);
// Guest constructor
final guestCtor = metadata.firstWhere((m) => m.name == 'guest');
expect(guestCtor.parameterTypes, isEmpty);
expect(guestCtor.parameters, isEmpty);
});
test('scanned type works with reflection', () {
Scanner.scanType(TestClass);
final reflector = RuntimeReflector.instance;
// Create instance
final instance = reflector.createInstance(
TestClass,
positionalArgs: ['John'],
namedArgs: {'id': 123},
) as TestClass;
expect(instance.name, equals('John'));
expect(instance.id, equals(123));
expect(instance.tags, isEmpty);
// Create guest instance
final guest = reflector.createInstance(
TestClass,
constructorName: 'guest',
) as TestClass;
expect(guest.name, equals('Guest'));
expect(guest.id, equals(0));
expect(guest.tags, isEmpty);
// Reflect on instance
final mirror = reflector.reflect(instance);
// Access properties
expect(mirror.getField(const Symbol('name')).reflectee, equals('John'));
expect(mirror.getField(const Symbol('id')).reflectee, equals(123));
// Modify properties
mirror.setField(const Symbol('name'), 'Jane');
expect(instance.name, equals('Jane'));
// Invoke methods
mirror.invoke(const Symbol('addTag'), ['test']);
expect(instance.tags, equals(['test']));
final greeting = mirror.invoke(const Symbol('greet'), ['Hi']).reflectee;
expect(greeting, equals('Hi, Jane!'));
// Try to modify final field (should throw)
expect(
() => mirror.setField(const Symbol('id'), 456),
throwsA(isA<ReflectionException>()),
);
});
test('handles generic types correctly', () {
Scanner.scanType(GenericTestClass);
final metadata = Reflector.getPropertyMetadata(GenericTestClass);
expect(metadata, isNotNull);
expect(metadata!['value'], isNotNull);
expect(metadata['items'], isNotNull);
expect(metadata['items']!.type, equals(List));
final methodMeta = Reflector.getMethodMetadata(GenericTestClass);
expect(methodMeta, isNotNull);
expect(methodMeta!['addItem'], isNotNull);
expect(methodMeta['getValue'], isNotNull);
});
test('handles inheritance correctly', () {
Scanner.scanType(ParentTestClass);
Scanner.scanType(ChildTestClass);
final parentMeta = Reflector.getPropertyMetadata(ParentTestClass);
final childMeta = Reflector.getPropertyMetadata(ChildTestClass);
expect(parentMeta, isNotNull);
expect(parentMeta!['name'], isNotNull);
expect(childMeta, isNotNull);
expect(childMeta!['name'], isNotNull);
expect(childMeta['age'], isNotNull);
final reflector = RuntimeReflector.instance;
final child = reflector.createInstance(
ChildTestClass,
positionalArgs: ['John', 30],
) as ChildTestClass;
final mirror = reflector.reflect(child);
final result = mirror.invoke(const Symbol('getName'), []).reflectee;
expect(result, equals('John (30)'));
});
});
}