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)) {" |