| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * Code transform for @observable. The core transformation is relatively | 6 * Code transform for @observable. The core transformation is relatively |
| 7 * straightforward, and essentially like an editor refactoring. You can find the | 7 * straightforward, and essentially like an editor refactoring. You can find the |
| 8 * core implementation in [transformClass], which is ultimately called by | 8 * core implementation in [transformClass], which is ultimately called by |
| 9 * [transformObservables], the entry point to this library. | 9 * [transformObservables], the entry point to this library. |
| 10 */ | 10 */ |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 | 79 |
| 80 void transformClass(ClassDeclaration cls, TextEditTransaction code, | 80 void transformClass(ClassDeclaration cls, TextEditTransaction code, |
| 81 SourceFile file, Messages messages) { | 81 SourceFile file, Messages messages) { |
| 82 | 82 |
| 83 if (hasObservable(cls)) { | 83 if (hasObservable(cls)) { |
| 84 messages.warning('@observable on a class no longer has any effect. ' | 84 messages.warning('@observable on a class no longer has any effect. ' |
| 85 'It should be placed on individual fields.', | 85 'It should be placed on individual fields.', |
| 86 _getSpan(file, cls)); | 86 _getSpan(file, cls)); |
| 87 } | 87 } |
| 88 | 88 |
| 89 // We'd like to track whether observable was declared explicitly, otherwise |
| 90 // report a warning later below. Because we don't have type analysis (only |
| 91 // syntactic understanding of the code), we only report warnings that are |
| 92 // known to be true. |
| 93 var declaresObservable = false; |
| 94 if (cls.extendsClause != null) { |
| 95 var id = _getSimpleIdentifier(cls.extendsClause.superclass.name); |
| 96 if (id.name == "ObservableBase") { |
| 97 code.edit(id.offset, id.end, "ChangeNotifierBase"); |
| 98 declaresObservable = true; |
| 99 } else if (id.name == "ChangeNotifierBase") { |
| 100 declaresObservable = true; |
| 101 } |
| 102 } |
| 103 if (!declaresObservable && cls.withClause != null) { |
| 104 for (var type in cls.withClause.mixinTypes) { |
| 105 var id = _getSimpleIdentifier(type.name); |
| 106 if (id.name == "ObservableMixin") { |
| 107 code.edit(id.offset, id.end, "ChangeNotifierMixin"); |
| 108 declaresObservable = true; |
| 109 break; |
| 110 } else if (id.name == "ChangeNotifierMixin") { |
| 111 declaresObservable = true; |
| 112 break; |
| 113 } |
| 114 } |
| 115 } |
| 116 |
| 117 if (!declaresObservable && cls.implementsClause != null) { |
| 118 for (var type in cls.implementsClause.interfaces) { |
| 119 var id = _getSimpleIdentifier(type.name); |
| 120 if (id.name == "Observable") { |
| 121 declaresObservable = true; |
| 122 break; |
| 123 } else if (id.name == "ChangeNotifier") { |
| 124 declaresObservable = true; |
| 125 break; |
| 126 } |
| 127 } |
| 128 } |
| 129 |
| 89 // Track fields that were transformed. | 130 // Track fields that were transformed. |
| 90 var instanceFields = new Set<String>(); | 131 var instanceFields = new Set<String>(); |
| 91 var getters = new List<String>(); | 132 var getters = new List<String>(); |
| 92 var setters = new List<String>(); | 133 var setters = new List<String>(); |
| 93 | 134 |
| 94 for (var member in cls.members) { | 135 for (var member in cls.members) { |
| 95 if (member is FieldDeclaration) { | 136 if (member is FieldDeclaration) { |
| 96 bool isStatic = hasKeyword(member.keyword, Keyword.STATIC); | 137 bool isStatic = hasKeyword(member.keyword, Keyword.STATIC); |
| 97 if (isStatic) { | 138 if (isStatic) { |
| 98 if (hasObservable(member)){ | 139 if (hasObservable(member)){ |
| 99 messages.warning('Static fields can no longer be observable. ' | 140 messages.warning('Static fields can no longer be observable. ' |
| 100 'Observable fields should be put in an observable objects.', | 141 'Observable fields should be put in an observable objects.', |
| 101 _getSpan(file, member)); | 142 _getSpan(file, member)); |
| 102 } | 143 } |
| 103 continue; | 144 continue; |
| 104 } | 145 } |
| 105 if (hasObservable(member)) { | 146 if (hasObservable(member)) { |
| 147 if (!declaresObservable) { |
| 148 messages.warning('Observable fields should be put in an observable' |
| 149 ' objects. Please declare that this class extends from ' |
| 150 'ObservableBase, includes ObservableMixin, or implements ' |
| 151 'Observable.', |
| 152 _getSpan(file, member)); |
| 153 |
| 154 } |
| 106 transformFields(member.fields, code, member.offset, member.end); | 155 transformFields(member.fields, code, member.offset, member.end); |
| 107 | 156 |
| 108 var names = member.fields.variables.map((v) => v.name.name); | 157 var names = member.fields.variables.map((v) => v.name.name); |
| 109 | 158 |
| 110 getters.addAll(names); | 159 getters.addAll(names); |
| 111 if (!_isReadOnly(member.fields)) { | 160 if (!_isReadOnly(member.fields)) { |
| 112 setters.addAll(names); | 161 setters.addAll(names); |
| 113 instanceFields.addAll(names); | 162 instanceFields.addAll(names); |
| 114 } | 163 } |
| 115 } | 164 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 133 } | 182 } |
| 134 | 183 |
| 135 // Fix initializers, because they aren't allowed to call the setter. | 184 // Fix initializers, because they aren't allowed to call the setter. |
| 136 for (var member in cls.members) { | 185 for (var member in cls.members) { |
| 137 if (member is ConstructorDeclaration) { | 186 if (member is ConstructorDeclaration) { |
| 138 fixConstructor(member, code, instanceFields); | 187 fixConstructor(member, code, instanceFields); |
| 139 } | 188 } |
| 140 } | 189 } |
| 141 } | 190 } |
| 142 | 191 |
| 192 SimpleIdentifier _getSimpleIdentifier(Identifier id) => |
| 193 id is PrefixedIdentifier ? id.identifier : id; |
| 194 |
| 143 | 195 |
| 144 /** | 196 /** |
| 145 * Generates `getValueWorkaround` and `setValueWorkaround`. These will go away | 197 * Generates `getValueWorkaround` and `setValueWorkaround`. These will go away |
| 146 * shortly once dart2js supports mirrors. For the moment they provide something | 198 * shortly once dart2js supports mirrors. For the moment they provide something |
| 147 * that the binding system can use. | 199 * that the binding system can use. |
| 148 */ | 200 */ |
| 149 void mirrorWorkaround(ClassDeclaration cls, TextEditTransaction code, | 201 void mirrorWorkaround(ClassDeclaration cls, TextEditTransaction code, |
| 150 List<String> getters, List<String> setters) { | 202 List<String> getters, List<String> setters) { |
| 151 | 203 |
| 152 var sb = new StringBuffer('\ngetValueWorkaround(key) {\n'); | 204 var sb = new StringBuffer('\ngetValueWorkaround(key) {\n'); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 $type __\$$name$initializer; | 313 $type __\$$name$initializer; |
| 262 $type get $name => __\$$name; | 314 $type get $name => __\$$name; |
| 263 set $name($type value) { | 315 set $name($type value) { |
| 264 __\$$name = notifyPropertyChange(const Symbol('$name'), __\$$name, value); | 316 __\$$name = notifyPropertyChange(const Symbol('$name'), __\$$name, value); |
| 265 } | 317 } |
| 266 '''.replaceAll('\n', '\n$indent')); | 318 '''.replaceAll('\n', '\n$indent')); |
| 267 } | 319 } |
| 268 | 320 |
| 269 code.edit(begin, end, '$replace'); | 321 code.edit(begin, end, '$replace'); |
| 270 } | 322 } |
| OLD | NEW |