Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(169)

Unified Diff: reflectable/lib/src/transformer_implementation.dart

Issue 1182083002: Implement `.instanceMembers`. (Closed) Base URL: https://github.com/dart-lang/reflectable.git@master
Patch Set: Rebase Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « reflectable/lib/src/mirrors_unimpl.dart ('k') | test_reflectable/pubspec.yaml » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: reflectable/lib/src/transformer_implementation.dart
diff --git a/reflectable/lib/src/transformer_implementation.dart b/reflectable/lib/src/transformer_implementation.dart
index 5ac24924eef8745239228520109c3bac7b65a383..744a395b10e8661ad6303ec789ea187ef1653b6f 100644
--- a/reflectable/lib/src/transformer_implementation.dart
+++ b/reflectable/lib/src/transformer_implementation.dart
@@ -50,34 +50,48 @@ class ReflectionWorld {
class ReflectorDomain {
final ClassElement reflector;
final List<ClassDomain> annotatedClasses;
+ final Map<ClassElement, ClassDomain> classMap =
+ new Map<ClassElement, ClassDomain>();
final Capabilities capabilities;
/// Libraries that must be imported to `reflector.library`.
final Set<LibraryElement> missingImports = new Set<LibraryElement>();
- ReflectorDomain(this.reflector, this.annotatedClasses, this.capabilities);
+ ReflectorDomain(this.reflector, this.annotatedClasses, this.capabilities) {
+ for (ClassDomain classDomain in annotatedClasses) {
+ classMap[classDomain.classElement] = classDomain;
+ }
+ }
void computeNames(Namer namer) {
annotatedClasses
.forEach((ClassDomain classDomain) => classDomain.computeNames(namer));
}
+
+ // TODO(eernst, sigurdm): Perhaps reconsider what the best strategy for
+ // caching is.
+ Map<ClassElement, Map<String, ExecutableElement>> _instanceMemberCache =
+ new Map<ClassElement, Map<String, ExecutableElement>>();
}
/// Information about reflectability for a given class.
class ClassDomain {
final ClassElement classElement;
- final Iterable<MethodElement> invokableMethods;
final Iterable<MethodElement> declaredMethods;
final Iterable<PropertyAccessorElement> declaredAccessors;
final Iterable<ConstructorElement> constructors;
ReflectorDomain reflectorDomain;
+
+ Iterable<MethodElement> get invokableMethods => instanceMembers
+ .where((ExecutableElement element) => element is MethodElement);
+
String staticClassMirrorName;
String staticInstanceMirrorName;
String get baseName => classElement.name;
- ClassDomain(this.classElement, this.invokableMethods, this.declaredMethods,
- this.declaredAccessors, this.constructors, this.reflectorDomain);
+ ClassDomain(this.classElement, this.declaredMethods, this.declaredAccessors,
+ this.constructors, this.reflectorDomain);
Iterable<ExecutableElement> get declarations {
// TODO(sigurdm): Include fields.
@@ -85,6 +99,52 @@ class ClassDomain {
return [declaredMethods, declaredAccessors, constructors].expand((x) => x);
}
+ /// Finds all instance members by going through the class hierarchy.
+ Iterable<ExecutableElement> get instanceMembers {
+ Map<String, ExecutableElement> helper(ClassElement classElement) {
+ if (reflectorDomain._instanceMemberCache[classElement] != null) {
+ return reflectorDomain._instanceMemberCache[classElement];
+ }
+ Map<String, ExecutableElement> result =
+ new Map<String, ExecutableElement>();
+
+ void addIfCapable(ExecutableElement member) {
+ if (reflectorDomain.capabilities.supportsInstanceInvoke(member.name)) {
+ result[member.name] = member;
+ }
+ }
+ if (classElement.supertype != null) {
+ helper(classElement.supertype.element)
+ .forEach((String name, ExecutableElement member) {
+ addIfCapable(member);
+ });
+ }
+ for (InterfaceType mixin in classElement.mixins) {
+ helper(mixin.element).forEach((String name, ExecutableElement member) {
+ addIfCapable(member);
+ });
+ }
+ for (MethodElement member in classElement.methods) {
+ if (member.isAbstract || member.isStatic) continue;
+ addIfCapable(member);
+ }
+ for (PropertyAccessorElement member in classElement.accessors) {
+ if (member.isAbstract || member.isStatic) continue;
+ addIfCapable(member);
+ }
+ for (FieldElement field in classElement.fields) {
+ if (field.isStatic) continue;
+ if (field.isSynthetic) continue;
+ addIfCapable(field.getter);
+ if (!field.isFinal) {
+ addIfCapable(field.setter);
+ }
+ }
+ return result;
+ }
+ return helper(classElement).values;
+ }
+
/// Returns an integer encoding the kind and attributes of the given
/// method/constructor/getter/setter.
int _declarationDescriptor(ExecutableElement element) {
@@ -109,12 +169,15 @@ class ClassDomain {
if (element.isPrivate) {
result += constants.privateAttribute;
}
- if (element.isAbstract) {
- result += constants.abstractAttribute;
- }
if (element.isStatic) {
result += constants.staticAttribute;
}
+ if (element.isSynthetic) {
+ result += constants.syntheticAttribute;
+ }
+ if (element.isAbstract) {
+ result += constants.abstractAttribute;
+ }
return result;
}
@@ -138,6 +201,19 @@ class ClassDomain {
return "{${declarationParts.join(", ")}}";
}
+ /// Returns a String with the textual representation of the
+ /// instanceMembers-map.
+ String get instanceMembersString {
+ // TODO(sigurdm): Find out how to set the right owner.
+ Iterable<String> instanceMemberParts = instanceMembers
+ .map((ExecutableElement declaration) {
+ return '"${nameOfDeclaration(declaration)}": '
+ 'new MethodMirrorImpl("${declaration.name}", '
+ '${_declarationDescriptor(declaration)}, null)';
+ });
+ return "{${instanceMemberParts.join(", ")}}";
+ }
+
/// Returns a String with the textual representations of the metadata list.
// TODO(sigurdm, 17307): Make this less fragile when the analyzer's
// element-model exposes the metadata in a more friendly way.
@@ -416,20 +492,9 @@ class TransformerImplementation {
return null;
}
- /// Finds all the methods in the class and all super-classes.
- Iterable<MethodElement> allMethods(ClassElement classElement) {
- List<MethodElement> result = new List<MethodElement>();
- result.addAll(classElement.methods);
- classElement.allSupertypes.forEach((InterfaceType superType) {
- result.addAll(superType.methods);
- });
- return result;
- }
-
Iterable<MethodElement> declaredMethods(
ClassElement classElement, Capabilities capabilities) {
return classElement.methods.where((MethodElement method) {
- if (method.isAbstract) return false;
if (method.isStatic) {
// TODO(sigurdm): Ask capabilities about support.
return true;
@@ -459,19 +524,6 @@ class TransformerImplementation {
});
}
- Iterable<MethodElement> invocableInstanceMethods(
- ClassElement classElement, Capabilities capabilities) {
- return allMethods(classElement).where((MethodElement method) {
- MethodDeclaration methodDeclaration = method.node;
- // TODO(eernst): We currently ignore method declarations when
- // they are operators. One issue is generation of code (which
- // does not work if we go ahead naively).
- if (methodDeclaration.isOperator) return false;
- String methodName = methodDeclaration.name.name;
- return capabilities.supportsInstanceInvoke(methodName);
- });
- }
-
/// Returns a [ReflectionWorld] instantiated with all the reflectors seen by
/// [resolver] and all classes annotated by them.
///
@@ -521,15 +573,13 @@ class TransformerImplementation {
return new ReflectorDomain(
reflector, new List<ClassDomain>(), capabilities);
});
- List<MethodElement> instanceMethods =
- invocableInstanceMethods(type, domain.capabilities).toList();
List<MethodElement> declaredMethodsOfClass =
declaredMethods(type, domain.capabilities).toList();
List<PropertyAccessorElement> declaredAccessorsOfClass =
declaredAccessors(type, domain.capabilities).toList();
List<ConstructorElement> declaredConstructorsOfClass =
declaredConstructors(type, domain.capabilities).toList();
- domain.annotatedClasses.add(new ClassDomain(type, instanceMethods,
+ domain.annotatedClasses.add(new ClassDomain(type,
declaredMethodsOfClass, declaredAccessorsOfClass,
declaredConstructorsOfClass, domain));
}
@@ -831,8 +881,7 @@ class TransformerImplementation {
String _staticClassMirrorCode(ClassDomain classDomain) {
List<String> implementedMembers = new List<String>();
String simpleName = classDomain.classElement.name;
- implementedMembers
- .add('final String simpleName = "$simpleName";');
+ implementedMembers.add('final String simpleName = "$simpleName";');
// When/if we have library-mirrors there could be a generic implementation:
// String get qualifiedName => "${owner.qualifiedName}.${simpleName}";
String qualifiedName =
@@ -847,6 +896,16 @@ class TransformerImplementation {
}
return _declarationsCache;
}""");
+ String instanceMembersString = classDomain.instanceMembersString;
+ implementedMembers.add("""
+ Map<String, MethodMirror> _instanceMembersCache;
+
+ Map<String, MethodMirror> get instanceMembers {
+ if (_instanceMembersCache == null) {
+ _instanceMembersCache = new UnmodifiableMapView($instanceMembersString);
+ }
+ return _instanceMembersCache;
+ }""");
if (classDomain.reflectorDomain.capabilities.supportsMetadata) {
implementedMembers
.add("List<Object> metadata = ${classDomain.metadataString};");
@@ -1142,11 +1201,17 @@ class ${classDomain.staticClassMirrorName} extends ClassMirrorUnimpl {
/// the given [classElement], bounded by the permissions given
/// in [capabilities].
String _staticInstanceMirrorInvokeCode(ClassDomain classDomain) {
+ String tearOff(MethodElement methodElement) {
+ if (!methodElement.isOperator) return "reflectee.${methodElement.name}";
+ if (methodElement.name == "[]=") return "(x, v) => reflectee[x] = v";
+ if (methodElement.name == "[]") return "(x) => reflectee[x]";
+ return "(x) => reflectee ${methodElement.name} x";
+ }
+
List<String> methodCases = new List<String>();
for (MethodElement methodElement in classDomain.invokableMethods) {
- String methodName = methodElement.name;
- methodCases.add("if (memberName == '$methodName') {"
- "method = reflectee.$methodName; }");
+ methodCases.add("if (memberName == '${methodElement.name}') {"
+ "method = ${tearOff(methodElement)}; }");
}
// TODO(eernst, sigurdm): Create an instance of [Invocation] in user code.
methodCases.add("if (instanceMethodFilter.hasMatch(memberName)) {"
« no previous file with comments | « reflectable/lib/src/mirrors_unimpl.dart ('k') | test_reflectable/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698