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