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

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: Fix return type in test 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
Index: reflectable/lib/src/transformer_implementation.dart
diff --git a/reflectable/lib/src/transformer_implementation.dart b/reflectable/lib/src/transformer_implementation.dart
index 90c86356a5d92110c6e132d08ac4201f80dd8810..d7709061f90ca8f8b9a6f98ec3f5362c2ccea25b 100644
--- a/reflectable/lib/src/transformer_implementation.dart
+++ b/reflectable/lib/src/transformer_implementation.dart
@@ -50,39 +50,98 @@ 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));
}
+
+ Map<ClassElement, Map<String, ExecutableElement>> _instanceMemberCache =
+ new Map<ClassElement, Map<String, ExecutableElement>>();
eernst 2015/06/18 12:21:12 Do we need an more global mechanism to guide the e
sigurdm 2015/06/18 14:22:27 I am not sure - will leave a todo.
}
/// 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.reflectorDomain);
+ ClassDomain(this.classElement, this.declaredMethods,
+ this.declaredAccessors, this.constructors, this.reflectorDomain);
Iterable<ExecutableElement> get declarations {
- // TODO(sigurdm): Include constructors.
// TODO(sigurdm): Include fields.
- // TODO(sigurdm): Include getters and setters.
// TODO(sigurdm): Include type variables (if we decide to keep them).
- return [declaredMethods].expand((x) => x);
+ 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
@@ -94,40 +153,64 @@ class ClassDomain {
} else if (element is ConstructorElement) {
if (element.isFactory) {
result = constants.factoryConstructor;
- } else if (element.redirectedConstructor != null) {
- result = constants.redirectingConstructor;
} else {
result = constants.generativeConstructor;
}
if (element.isConst) {
result += constants.constAttribute;
}
+ if (element.redirectedConstructor != null) {
+ result += constants.redirectingConstructor;
+ }
} else {
result = constants.method;
}
if (element.isPrivate) {
result += constants.privateAttribute;
}
- if (element.isAbstract) {
- result += constants.abstractAttribute;
- }
+ assert(!element.isAbstract);
if (element.isStatic) {
result += constants.staticAttribute;
}
+ if (element.isSynthetic) {
+ result += constants.syntheticAttribute;
+ }
return result;
}
+ String nameOfDeclaration(ExecutableElement element) {
+ if (element is ConstructorElement) {
+ return element.name == ""
+ ? classElement.name
+ : "${classElement.name}.${element.name}";
+ }
+ return element.name;
+ }
+
/// Returns a String with the textual representation of the declarations-map.
String get declarationsString {
Iterable<String> declarationParts = declarations.map(
- (ExecutableElement instanceMember) {
- return '"${instanceMember.name}": '
- 'new MethodMirrorImpl("${instanceMember.name}", '
- '${_declarationDescriptor(instanceMember)}, this)';
+ (ExecutableElement declaration) {
+ return '"${nameOfDeclaration(declaration)}": '
+ 'new MethodMirrorImpl("${declaration.name}", '
+ '${_declarationDescriptor(declaration)}, this)';
});
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(", ")}}";
+ }
+
void computeNames(Namer namer) {
staticClassMirrorName = namer.freshName("Static_${baseName}_ClassMirror");
staticInstanceMirrorName =
@@ -383,21 +466,12 @@ 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 capability about support.
+ // TODO(sigurdm): Ask capabilities about support.
return true;
} else {
return capabilities.supportsInstanceInvoke(method.name);
@@ -405,16 +479,24 @@ class TransformerImplementation {
});
}
- Iterable<MethodElement> invocableInstanceMethods(
+ Iterable<PropertyAccessorElement> declaredAccessors(
+ ClassElement classElement, Capabilities capabilities) {
+ return classElement.accessors.where((PropertyAccessorElement accessor) {
+ if (accessor.isAbstract) return false;
+ if (accessor.isStatic) {
+ // TODO(sigurdm): Ask capabilities about support.
+ return true;
+ } else {
+ return capabilities.supportsInstanceInvoke(accessor.name);
+ }
+ });
+ }
+
+ Iterable<ConstructorElement> declaredConstructors(
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);
+ return classElement.constructors.where((ConstructorElement constructor) {
+ // TODO(sigurdm): Ask capabilities about support.
+ return true;
});
}
@@ -467,12 +549,15 @@ 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();
- domain.annotatedClasses.add(new ClassDomain(
- type, instanceMethods, declaredMethodsOfClass, domain));
+ List<PropertyAccessorElement> declaredAccessorsOfClass =
+ declaredAccessors(type, domain.capabilities).toList();
+ List<ConstructorElement> declaredConstructorsOfClass =
+ declaredConstructors(type, domain.capabilities).toList();
+ domain.annotatedClasses.add(new ClassDomain(type,
+ declaredMethodsOfClass, declaredAccessorsOfClass,
+ declaredConstructorsOfClass, domain));
}
}
}
@@ -771,6 +856,7 @@ class TransformerImplementation {
/// is the class modeled by [classElement].
String _staticClassMirrorCode(ClassDomain classDomain) {
String declarationsString = classDomain.declarationsString;
+ String instanceMembersString = classDomain.instanceMembersString;
return """
class ${classDomain.staticClassMirrorName} extends ClassMirrorUnimpl {
final String simpleName = "${classDomain.classElement.name}";
@@ -783,6 +869,16 @@ class ${classDomain.staticClassMirrorName} extends ClassMirrorUnimpl {
}
return _declarationsCache;
}
+
+ Map<String, MethodMirror> _instanceMembersCache;
+
+ Map<String, MethodMirror> get instanceMembers {
+ if (_instanceMembersCache == null) {
+ _instanceMembersCache = new UnmodifiableMapView($instanceMembersString);
+ }
+ return _instanceMembersCache;
+ }
+
}
""";
}
@@ -945,11 +1041,19 @@ 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)) {"

Powered by Google App Engine
This is Rietveld 408576698