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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // (c) 2015, the Dart Team. All rights reserved. Use of this 1 // (c) 2015, the Dart Team. All rights reserved. Use of this
2 // source code is governed by a BSD-style license that can be found in 2 // source code is governed by a BSD-style license that can be found in
3 // the LICENSE file. 3 // the LICENSE file.
4 4
5 library reflectable.src.transformer_implementation; 5 library reflectable.src.transformer_implementation;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:convert'; 8 import 'dart:convert';
9 import 'dart:io'; 9 import 'dart:io';
10 import 'dart:math' show max; 10 import 'dart:math' show max;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 reflectors 43 reflectors
44 .forEach((ReflectorDomain reflector) => reflector.computeNames(namer)); 44 .forEach((ReflectorDomain reflector) => reflector.computeNames(namer));
45 } 45 }
46 } 46 }
47 47
48 /// Information about the program parts that can be reflected by a given 48 /// Information about the program parts that can be reflected by a given
49 /// Reflector. 49 /// Reflector.
50 class ReflectorDomain { 50 class ReflectorDomain {
51 final ClassElement reflector; 51 final ClassElement reflector;
52 final List<ClassDomain> annotatedClasses; 52 final List<ClassDomain> annotatedClasses;
53 final Map<ClassElement, ClassDomain> classMap =
54 new Map<ClassElement, ClassDomain>();
53 final Capabilities capabilities; 55 final Capabilities capabilities;
54 56
55 /// Libraries that must be imported to `reflector.library`. 57 /// Libraries that must be imported to `reflector.library`.
56 final Set<LibraryElement> missingImports = new Set<LibraryElement>(); 58 final Set<LibraryElement> missingImports = new Set<LibraryElement>();
57 59
58 ReflectorDomain(this.reflector, this.annotatedClasses, this.capabilities); 60 ReflectorDomain(this.reflector, this.annotatedClasses, this.capabilities) {
61 for (ClassDomain classDomain in annotatedClasses) {
62 classMap[classDomain.classElement] = classDomain;
63 }
64 }
59 65
60 void computeNames(Namer namer) { 66 void computeNames(Namer namer) {
61 annotatedClasses 67 annotatedClasses
62 .forEach((ClassDomain classDomain) => classDomain.computeNames(namer)); 68 .forEach((ClassDomain classDomain) => classDomain.computeNames(namer));
63 } 69 }
70
71 Map<ClassElement, Map<String, ExecutableElement>> _instanceMemberCache =
72 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.
64 } 73 }
65 74
66 /// Information about reflectability for a given class. 75 /// Information about reflectability for a given class.
67 class ClassDomain { 76 class ClassDomain {
68 final ClassElement classElement; 77 final ClassElement classElement;
69 final Iterable<MethodElement> invokableMethods;
70 final Iterable<MethodElement> declaredMethods; 78 final Iterable<MethodElement> declaredMethods;
79 final Iterable<PropertyAccessorElement> declaredAccessors;
80 final Iterable<ConstructorElement> constructors;
71 81
72 ReflectorDomain reflectorDomain; 82 ReflectorDomain reflectorDomain;
83
84 Iterable<MethodElement> get invokableMethods => instanceMembers
85 .where((ExecutableElement element) => element is MethodElement);
86
73 String staticClassMirrorName; 87 String staticClassMirrorName;
74 String staticInstanceMirrorName; 88 String staticInstanceMirrorName;
75 String get baseName => classElement.name; 89 String get baseName => classElement.name;
76 90
77 ClassDomain(this.classElement, this.invokableMethods, this.declaredMethods, 91 ClassDomain(this.classElement, this.declaredMethods,
78 this.reflectorDomain); 92 this.declaredAccessors, this.constructors, this.reflectorDomain);
79 93
80 Iterable<ExecutableElement> get declarations { 94 Iterable<ExecutableElement> get declarations {
81 // TODO(sigurdm): Include constructors.
82 // TODO(sigurdm): Include fields. 95 // TODO(sigurdm): Include fields.
83 // TODO(sigurdm): Include getters and setters.
84 // TODO(sigurdm): Include type variables (if we decide to keep them). 96 // TODO(sigurdm): Include type variables (if we decide to keep them).
85 return [declaredMethods].expand((x) => x); 97 return [declaredMethods, declaredAccessors, constructors].expand((x) => x);
98 }
99
100 /// Finds all instance members by going through the class hierarchy.
101 Iterable<ExecutableElement> get instanceMembers {
102
103 Map<String, ExecutableElement> helper(ClassElement classElement) {
104 if (reflectorDomain._instanceMemberCache[classElement] != null) {
105 return reflectorDomain._instanceMemberCache[classElement];
106 }
107 Map<String, ExecutableElement> result =
108 new Map<String, ExecutableElement>();
109
110 void addIfCapable(ExecutableElement member) {
111 if (reflectorDomain.capabilities.supportsInstanceInvoke(member.name)) {
112 result[member.name] = member;
113 }
114 }
115 if (classElement.supertype != null) {
116 helper(classElement.supertype.element).forEach(
117 (String name, ExecutableElement member) {
118 addIfCapable(member);
119 });
120 }
121 for (InterfaceType mixin in classElement.mixins) {
122 helper(mixin.element).forEach((String name, ExecutableElement member) {
123 addIfCapable(member);
124 });
125 }
126 for (MethodElement member in classElement.methods) {
127 if (member.isAbstract || member.isStatic) continue;
128 addIfCapable(member);
129 }
130 for (PropertyAccessorElement member in classElement.accessors) {
131 if (member.isAbstract || member.isStatic) continue;
132 addIfCapable(member);
133 }
134 for (FieldElement field in classElement.fields) {
135 if (field.isStatic) continue;
136 if (field.isSynthetic) continue;
137 addIfCapable(field.getter);
138 if (!field.isFinal) {
139 addIfCapable(field.setter);
140 }
141 }
142 return result;
143 }
144 return helper(classElement).values;
86 } 145 }
87 146
88 /// Returns an integer encoding the kind and attributes of the given 147 /// Returns an integer encoding the kind and attributes of the given
89 /// method/constructor/getter/setter. 148 /// method/constructor/getter/setter.
90 int _declarationDescriptor(ExecutableElement element) { 149 int _declarationDescriptor(ExecutableElement element) {
91 int result; 150 int result;
92 if (element is PropertyAccessorElement) { 151 if (element is PropertyAccessorElement) {
93 result = element.isGetter ? constants.getter : constants.setter; 152 result = element.isGetter ? constants.getter : constants.setter;
94 } else if (element is ConstructorElement) { 153 } else if (element is ConstructorElement) {
95 if (element.isFactory) { 154 if (element.isFactory) {
96 result = constants.factoryConstructor; 155 result = constants.factoryConstructor;
97 } else if (element.redirectedConstructor != null) {
98 result = constants.redirectingConstructor;
99 } else { 156 } else {
100 result = constants.generativeConstructor; 157 result = constants.generativeConstructor;
101 } 158 }
102 if (element.isConst) { 159 if (element.isConst) {
103 result += constants.constAttribute; 160 result += constants.constAttribute;
104 } 161 }
162 if (element.redirectedConstructor != null) {
163 result += constants.redirectingConstructor;
164 }
105 } else { 165 } else {
106 result = constants.method; 166 result = constants.method;
107 } 167 }
108 if (element.isPrivate) { 168 if (element.isPrivate) {
109 result += constants.privateAttribute; 169 result += constants.privateAttribute;
110 } 170 }
111 if (element.isAbstract) { 171 assert(!element.isAbstract);
112 result += constants.abstractAttribute;
113 }
114 if (element.isStatic) { 172 if (element.isStatic) {
115 result += constants.staticAttribute; 173 result += constants.staticAttribute;
116 } 174 }
175 if (element.isSynthetic) {
176 result += constants.syntheticAttribute;
177 }
117 return result; 178 return result;
118 } 179 }
119 180
181 String nameOfDeclaration(ExecutableElement element) {
182 if (element is ConstructorElement) {
183 return element.name == ""
184 ? classElement.name
185 : "${classElement.name}.${element.name}";
186 }
187 return element.name;
188 }
189
120 /// Returns a String with the textual representation of the declarations-map. 190 /// Returns a String with the textual representation of the declarations-map.
121 String get declarationsString { 191 String get declarationsString {
122 Iterable<String> declarationParts = declarations.map( 192 Iterable<String> declarationParts = declarations.map(
123 (ExecutableElement instanceMember) { 193 (ExecutableElement declaration) {
124 return '"${instanceMember.name}": ' 194 return '"${nameOfDeclaration(declaration)}": '
125 'new MethodMirrorImpl("${instanceMember.name}", ' 195 'new MethodMirrorImpl("${declaration.name}", '
126 '${_declarationDescriptor(instanceMember)}, this)'; 196 '${_declarationDescriptor(declaration)}, this)';
127 }); 197 });
128 return "{${declarationParts.join(", ")}}"; 198 return "{${declarationParts.join(", ")}}";
129 } 199 }
130 200
201 /// Returns a String with the textual representation of the
202 /// instanceMembers-map.
203 String get instanceMembersString {
204 // TODO(sigurdm): Find out how to set the right owner.
205 Iterable<String> instanceMemberParts = instanceMembers.map(
206 (ExecutableElement declaration) {
207 return '"${nameOfDeclaration(declaration)}": '
208 'new MethodMirrorImpl("${declaration.name}", '
209 '${_declarationDescriptor(declaration)}, null)';
210 });
211 return "{${instanceMemberParts.join(", ")}}";
212 }
213
131 void computeNames(Namer namer) { 214 void computeNames(Namer namer) {
132 staticClassMirrorName = namer.freshName("Static_${baseName}_ClassMirror"); 215 staticClassMirrorName = namer.freshName("Static_${baseName}_ClassMirror");
133 staticInstanceMirrorName = 216 staticInstanceMirrorName =
134 namer.freshName("Static_${baseName}_InstanceMirror"); 217 namer.freshName("Static_${baseName}_InstanceMirror");
135 } 218 }
136 } 219 }
137 220
138 /// A wrapper around a list of Capabilities. 221 /// A wrapper around a list of Capabilities.
139 /// Supports queries about the methods supported by the set of capabilities. 222 /// Supports queries about the methods supported by the set of capabilities.
140 class Capabilities { 223 class Capabilities {
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 // have no effect; it might be better to emit a diagnostic message (a 459 // have no effect; it might be better to emit a diagnostic message (a
377 // hint?) in order to notify the programmer that "it does not work". 460 // hint?) in order to notify the programmer that "it does not work".
378 // The trade-off is that such constructs may have been written by 461 // The trade-off is that such constructs may have been written by
379 // programmers who are doing something else, intentionally. To emit a 462 // programmers who are doing something else, intentionally. To emit a
380 // diagnostic message, we must check whether there is a Reflectable 463 // diagnostic message, we must check whether there is a Reflectable
381 // somewhere inside this syntactic construct, and then emit the message 464 // somewhere inside this syntactic construct, and then emit the message
382 // in cases that we "consider likely to be misunderstood". 465 // in cases that we "consider likely to be misunderstood".
383 return null; 466 return null;
384 } 467 }
385 468
386 /// Finds all the methods in the class and all super-classes.
387 Iterable<MethodElement> allMethods(ClassElement classElement) {
388 List<MethodElement> result = new List<MethodElement>();
389 result.addAll(classElement.methods);
390 classElement.allSupertypes.forEach((InterfaceType superType) {
391 result.addAll(superType.methods);
392 });
393 return result;
394 }
395
396 Iterable<MethodElement> declaredMethods( 469 Iterable<MethodElement> declaredMethods(
397 ClassElement classElement, Capabilities capabilities) { 470 ClassElement classElement, Capabilities capabilities) {
398 return classElement.methods.where((MethodElement method) { 471 return classElement.methods.where((MethodElement method) {
472 if (method.isAbstract) return false;
399 if (method.isStatic) { 473 if (method.isStatic) {
400 // TODO(sigurdm): Ask capability about support. 474 // TODO(sigurdm): Ask capabilities about support.
401 return true; 475 return true;
402 } else { 476 } else {
403 return capabilities.supportsInstanceInvoke(method.name); 477 return capabilities.supportsInstanceInvoke(method.name);
404 } 478 }
405 }); 479 });
406 } 480 }
407 481
408 Iterable<MethodElement> invocableInstanceMethods( 482 Iterable<PropertyAccessorElement> declaredAccessors(
409 ClassElement classElement, Capabilities capabilities) { 483 ClassElement classElement, Capabilities capabilities) {
410 return allMethods(classElement).where((MethodElement method) { 484 return classElement.accessors.where((PropertyAccessorElement accessor) {
411 MethodDeclaration methodDeclaration = method.node; 485 if (accessor.isAbstract) return false;
412 // TODO(eernst): We currently ignore method declarations when 486 if (accessor.isStatic) {
413 // they are operators. One issue is generation of code (which 487 // TODO(sigurdm): Ask capabilities about support.
414 // does not work if we go ahead naively). 488 return true;
415 if (methodDeclaration.isOperator) return false; 489 } else {
416 String methodName = methodDeclaration.name.name; 490 return capabilities.supportsInstanceInvoke(accessor.name);
417 return capabilities.supportsInstanceInvoke(methodName); 491 }
418 }); 492 });
419 } 493 }
420 494
495 Iterable<ConstructorElement> declaredConstructors(
496 ClassElement classElement, Capabilities capabilities) {
497 return classElement.constructors.where((ConstructorElement constructor) {
498 // TODO(sigurdm): Ask capabilities about support.
499 return true;
500 });
501 }
502
421 /// Returns a [ReflectionWorld] instantiated with all the reflectors seen by 503 /// Returns a [ReflectionWorld] instantiated with all the reflectors seen by
422 /// [resolver] and all classes annotated by them. 504 /// [resolver] and all classes annotated by them.
423 /// 505 ///
424 /// TODO(eernst): Make sure it works also when other packages are being 506 /// TODO(eernst): Make sure it works also when other packages are being
425 /// used by the target program which have already been transformed by 507 /// used by the target program which have already been transformed by
426 /// this transformer (e.g., there would be a clash on the use of 508 /// this transformer (e.g., there would be a clash on the use of
427 /// reflectableClassId with values near 1000 for more than one class). 509 /// reflectableClassId with values near 1000 for more than one class).
428 ReflectionWorld _computeWorld(LibraryElement reflectableLibrary) { 510 ReflectionWorld _computeWorld(LibraryElement reflectableLibrary) {
429 ReflectionWorld world = new ReflectionWorld(reflectableLibrary); 511 ReflectionWorld world = new ReflectionWorld(reflectableLibrary);
430 Map<ClassElement, ReflectorDomain> domains = 512 Map<ClassElement, ReflectorDomain> domains =
(...skipping 29 matching lines...) Expand all
460 for (ElementAnnotation metadatum in type.metadata) { 542 for (ElementAnnotation metadatum in type.metadata) {
461 ClassElement reflector = 543 ClassElement reflector =
462 _getReflectableAnnotation(metadatum, focusClass); 544 _getReflectableAnnotation(metadatum, focusClass);
463 if (reflector == null) continue; 545 if (reflector == null) continue;
464 ReflectorDomain domain = domains.putIfAbsent(reflector, () { 546 ReflectorDomain domain = domains.putIfAbsent(reflector, () {
465 Capabilities capabilities = 547 Capabilities capabilities =
466 _capabilitiesOf(capabilityLibrary, reflector); 548 _capabilitiesOf(capabilityLibrary, reflector);
467 return new ReflectorDomain( 549 return new ReflectorDomain(
468 reflector, new List<ClassDomain>(), capabilities); 550 reflector, new List<ClassDomain>(), capabilities);
469 }); 551 });
470 List<MethodElement> instanceMethods =
471 invocableInstanceMethods(type, domain.capabilities).toList();
472 List<MethodElement> declaredMethodsOfClass = 552 List<MethodElement> declaredMethodsOfClass =
473 declaredMethods(type, domain.capabilities).toList(); 553 declaredMethods(type, domain.capabilities).toList();
474 domain.annotatedClasses.add(new ClassDomain( 554 List<PropertyAccessorElement> declaredAccessorsOfClass =
475 type, instanceMethods, declaredMethodsOfClass, domain)); 555 declaredAccessors(type, domain.capabilities).toList();
556 List<ConstructorElement> declaredConstructorsOfClass =
557 declaredConstructors(type, domain.capabilities).toList();
558 domain.annotatedClasses.add(new ClassDomain(type,
559 declaredMethodsOfClass, declaredAccessorsOfClass,
560 declaredConstructorsOfClass, domain));
476 } 561 }
477 } 562 }
478 } 563 }
479 } 564 }
480 domains.values.forEach(_collectMissingImports); 565 domains.values.forEach(_collectMissingImports);
481 566
482 world.reflectors.addAll(domains.values.toList()); 567 world.reflectors.addAll(domains.values.toList());
483 world.computeNames(namer); 568 world.computeNames(namer);
484 return world; 569 return world;
485 } 570 }
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after
764 Iterable<${prefix}ClassMirror> get annotatedClasses { 849 Iterable<${prefix}ClassMirror> get annotatedClasses {
765 return [${annotatedClassesStrings.join(", ")}]; 850 return [${annotatedClassesStrings.join(", ")}];
766 }"""); 851 }""");
767 } 852 }
768 853
769 /// Returns the source code for the reflection free subclass of 854 /// Returns the source code for the reflection free subclass of
770 /// [ClassMirror] which is specialized for a `reflectedType` which 855 /// [ClassMirror] which is specialized for a `reflectedType` which
771 /// is the class modeled by [classElement]. 856 /// is the class modeled by [classElement].
772 String _staticClassMirrorCode(ClassDomain classDomain) { 857 String _staticClassMirrorCode(ClassDomain classDomain) {
773 String declarationsString = classDomain.declarationsString; 858 String declarationsString = classDomain.declarationsString;
859 String instanceMembersString = classDomain.instanceMembersString;
774 return """ 860 return """
775 class ${classDomain.staticClassMirrorName} extends ClassMirrorUnimpl { 861 class ${classDomain.staticClassMirrorName} extends ClassMirrorUnimpl {
776 final String simpleName = "${classDomain.classElement.name}"; 862 final String simpleName = "${classDomain.classElement.name}";
777 863
778 Map<String, MethodMirror> _declarationsCache; 864 Map<String, MethodMirror> _declarationsCache;
779 865
780 Map<String, MethodMirror> get declarations { 866 Map<String, MethodMirror> get declarations {
781 if (_declarationsCache == null) { 867 if (_declarationsCache == null) {
782 _declarationsCache = new UnmodifiableMapView($declarationsString); 868 _declarationsCache = new UnmodifiableMapView($declarationsString);
783 } 869 }
784 return _declarationsCache; 870 return _declarationsCache;
785 } 871 }
872
873 Map<String, MethodMirror> _instanceMembersCache;
874
875 Map<String, MethodMirror> get instanceMembers {
876 if (_instanceMembersCache == null) {
877 _instanceMembersCache = new UnmodifiableMapView($instanceMembersString);
878 }
879 return _instanceMembersCache;
880 }
881
786 } 882 }
787 """; 883 """;
788 } 884 }
789 885
790 /// Perform some very simple steps that are consistent with Dart 886 /// Perform some very simple steps that are consistent with Dart
791 /// semantics for the evaluation of constant expressions, such that 887 /// semantics for the evaluation of constant expressions, such that
792 /// information about the value of a given `const` variable can be 888 /// information about the value of a given `const` variable can be
793 /// obtained. It is intended to help recognizing values of type 889 /// obtained. It is intended to help recognizing values of type
794 /// [ReflectCapability], so we only cover cases needed for that. 890 /// [ReflectCapability], so we only cover cases needed for that.
795 /// In particular, we cover lookup (e.g., with `const x = e` we can 891 /// In particular, we cover lookup (e.g., with `const x = e` we can
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
938 ListLiteral listLiteral = arguments[0]; 1034 ListLiteral listLiteral = arguments[0];
939 NodeList<Expression> expressions = listLiteral.elements; 1035 NodeList<Expression> expressions = listLiteral.elements;
940 return new Capabilities(expressions.map(capabilityOfExpression).toList()); 1036 return new Capabilities(expressions.map(capabilityOfExpression).toList());
941 } 1037 }
942 1038
943 /// Returns a [String] containing generated code for the `invoke` 1039 /// Returns a [String] containing generated code for the `invoke`
944 /// method of the static `InstanceMirror` class corresponding to 1040 /// method of the static `InstanceMirror` class corresponding to
945 /// the given [classElement], bounded by the permissions given 1041 /// the given [classElement], bounded by the permissions given
946 /// in [capabilities]. 1042 /// in [capabilities].
947 String _staticInstanceMirrorInvokeCode(ClassDomain classDomain) { 1043 String _staticInstanceMirrorInvokeCode(ClassDomain classDomain) {
1044
1045 String tearOff(MethodElement methodElement) {
1046 if (!methodElement.isOperator) return "reflectee.${methodElement.name}";
1047 if (methodElement.name == "[]=") return "(x, v) => reflectee[x] = v";
1048 if (methodElement.name == "[]") return "(x) => reflectee[x]";
1049 return "(x) => reflectee ${methodElement.name} x";
1050 }
1051
1052
948 List<String> methodCases = new List<String>(); 1053 List<String> methodCases = new List<String>();
949 for (MethodElement methodElement in classDomain.invokableMethods) { 1054 for (MethodElement methodElement in classDomain.invokableMethods) {
950 String methodName = methodElement.name; 1055 methodCases.add("if (memberName == '${methodElement.name}') {"
951 methodCases.add("if (memberName == '$methodName') {" 1056 "method = ${tearOff(methodElement)}; }");
952 "method = reflectee.$methodName; }");
953 } 1057 }
954 // TODO(eernst, sigurdm): Create an instance of [Invocation] in user code. 1058 // TODO(eernst, sigurdm): Create an instance of [Invocation] in user code.
955 methodCases.add("if (instanceMethodFilter.hasMatch(memberName)) {" 1059 methodCases.add("if (instanceMethodFilter.hasMatch(memberName)) {"
956 "throw new UnimplementedError('Should call noSuchMethod'); }"); 1060 "throw new UnimplementedError('Should call noSuchMethod'); }");
957 methodCases.add("{ throw new NoSuchInvokeCapabilityError(" 1061 methodCases.add("{ throw new NoSuchInvokeCapabilityError("
958 "reflectee, memberName, positionalArguments, namedArguments); }"); 1062 "reflectee, memberName, positionalArguments, namedArguments); }");
959 // Handle the cases where permission is given even though there is 1063 // Handle the cases where permission is given even though there is
960 // no corresponding method. One case is where _all_ methods can be 1064 // no corresponding method. One case is where _all_ methods can be
961 // invoked. Another case is when the user has specified a name 1065 // invoked. Another case is when the user has specified a name
962 // `"foo"` and a reflector `@reflector` allowing for invocation 1066 // `"foo"` and a reflector `@reflector` allowing for invocation
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
1218 TransformLogger get logger => _aggregateTransform.logger; 1322 TransformLogger get logger => _aggregateTransform.logger;
1219 Future<Asset> getInput(AssetId id) => _aggregateTransform.getInput(id); 1323 Future<Asset> getInput(AssetId id) => _aggregateTransform.getInput(id);
1220 Future<String> readInputAsString(AssetId id, {Encoding encoding}) { 1324 Future<String> readInputAsString(AssetId id, {Encoding encoding}) {
1221 return _aggregateTransform.readInputAsString(id, encoding: encoding); 1325 return _aggregateTransform.readInputAsString(id, encoding: encoding);
1222 } 1326 }
1223 Stream<List<int>> readInput(AssetId id) => _aggregateTransform.readInput(id); 1327 Stream<List<int>> readInput(AssetId id) => _aggregateTransform.readInput(id);
1224 Future<bool> hasInput(AssetId id) => _aggregateTransform.hasInput(id); 1328 Future<bool> hasInput(AssetId id) => _aggregateTransform.hasInput(id);
1225 void addOutput(Asset output) => _aggregateTransform.addOutput(output); 1329 void addOutput(Asset output) => _aggregateTransform.addOutput(output);
1226 void consumePrimary() => _aggregateTransform.consumePrimary(primaryInput.id); 1330 void consumePrimary() => _aggregateTransform.consumePrimary(primaryInput.id);
1227 } 1331 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698