| 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. | 7 * straightforward, and essentially like an editor refactoring. |
| 8 */ | 8 */ |
| 9 library observe.transform; | 9 library observe.transform; |
| 10 | 10 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 } | 61 } |
| 62 | 62 |
| 63 TextEditTransaction _transformCompilationUnit( | 63 TextEditTransaction _transformCompilationUnit( |
| 64 String inputCode, SourceFile sourceFile, TransformLogger logger) { | 64 String inputCode, SourceFile sourceFile, TransformLogger logger) { |
| 65 var unit = _parseCompilationUnit(inputCode); | 65 var unit = _parseCompilationUnit(inputCode); |
| 66 var code = new TextEditTransaction(inputCode, sourceFile); | 66 var code = new TextEditTransaction(inputCode, sourceFile); |
| 67 for (var directive in unit.directives) { | 67 for (var directive in unit.directives) { |
| 68 if (directive is LibraryDirective && _hasObservable(directive)) { | 68 if (directive is LibraryDirective && _hasObservable(directive)) { |
| 69 logger.warning('@observable on a library no longer has any effect. ' | 69 logger.warning('@observable on a library no longer has any effect. ' |
| 70 'It should be placed on individual fields.', | 70 'It should be placed on individual fields.', |
| 71 _getSpan(sourceFile, directive)); | 71 span: _getSpan(sourceFile, directive)); |
| 72 break; | 72 break; |
| 73 } | 73 } |
| 74 } | 74 } |
| 75 | 75 |
| 76 for (var declaration in unit.declarations) { | 76 for (var declaration in unit.declarations) { |
| 77 if (declaration is ClassDeclaration) { | 77 if (declaration is ClassDeclaration) { |
| 78 _transformClass(declaration, code, sourceFile, logger); | 78 _transformClass(declaration, code, sourceFile, logger); |
| 79 } else if (declaration is TopLevelVariableDeclaration) { | 79 } else if (declaration is TopLevelVariableDeclaration) { |
| 80 if (_hasObservable(declaration)) { | 80 if (_hasObservable(declaration)) { |
| 81 logger.warning('Top-level fields can no longer be observable. ' | 81 logger.warning('Top-level fields can no longer be observable. ' |
| 82 'Observable fields should be put in an observable objects.', | 82 'Observable fields should be put in an observable objects.', |
| 83 _getSpan(sourceFile, declaration)); | 83 span: _getSpan(sourceFile, declaration)); |
| 84 } | 84 } |
| 85 } | 85 } |
| 86 } | 86 } |
| 87 return code; | 87 return code; |
| 88 } | 88 } |
| 89 | 89 |
| 90 /** Parse [code] using analyzer_experimental. */ | 90 /** Parse [code] using analyzer_experimental. */ |
| 91 CompilationUnit _parseCompilationUnit(String code) { | 91 CompilationUnit _parseCompilationUnit(String code) { |
| 92 var errorListener = new _ErrorCollector(); | 92 var errorListener = new _ErrorCollector(); |
| 93 var scanner = new StringScanner(null, code, errorListener); | 93 var scanner = new StringScanner(null, code, errorListener); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 117 return node.metadata.any((m) => m.name.name == name && | 117 return node.metadata.any((m) => m.name.name == name && |
| 118 m.constructorName == null && m.arguments == null); | 118 m.constructorName == null && m.arguments == null); |
| 119 } | 119 } |
| 120 | 120 |
| 121 void _transformClass(ClassDeclaration cls, TextEditTransaction code, | 121 void _transformClass(ClassDeclaration cls, TextEditTransaction code, |
| 122 SourceFile file, TransformLogger logger) { | 122 SourceFile file, TransformLogger logger) { |
| 123 | 123 |
| 124 if (_hasObservable(cls)) { | 124 if (_hasObservable(cls)) { |
| 125 logger.warning('@observable on a class no longer has any effect. ' | 125 logger.warning('@observable on a class no longer has any effect. ' |
| 126 'It should be placed on individual fields.', | 126 'It should be placed on individual fields.', |
| 127 _getSpan(file, cls)); | 127 span: _getSpan(file, cls)); |
| 128 } | 128 } |
| 129 | 129 |
| 130 // We'd like to track whether observable was declared explicitly, otherwise | 130 // We'd like to track whether observable was declared explicitly, otherwise |
| 131 // report a warning later below. Because we don't have type analysis (only | 131 // report a warning later below. Because we don't have type analysis (only |
| 132 // syntactic understanding of the code), we only report warnings that are | 132 // syntactic understanding of the code), we only report warnings that are |
| 133 // known to be true. | 133 // known to be true. |
| 134 var declaresObservable = false; | 134 var declaresObservable = false; |
| 135 if (cls.extendsClause != null) { | 135 if (cls.extendsClause != null) { |
| 136 var id = _getSimpleIdentifier(cls.extendsClause.superclass.name); | 136 var id = _getSimpleIdentifier(cls.extendsClause.superclass.name); |
| 137 if (id.name == 'ObservableBase') { | 137 if (id.name == 'ObservableBase') { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 var instanceFields = new Set<String>(); | 175 var instanceFields = new Set<String>(); |
| 176 var getters = new List<String>(); | 176 var getters = new List<String>(); |
| 177 var setters = new List<String>(); | 177 var setters = new List<String>(); |
| 178 | 178 |
| 179 for (var member in cls.members) { | 179 for (var member in cls.members) { |
| 180 if (member is FieldDeclaration) { | 180 if (member is FieldDeclaration) { |
| 181 if (member.isStatic) { | 181 if (member.isStatic) { |
| 182 if (_hasObservable(member)){ | 182 if (_hasObservable(member)){ |
| 183 logger.warning('Static fields can no longer be observable. ' | 183 logger.warning('Static fields can no longer be observable. ' |
| 184 'Observable fields should be put in an observable objects.', | 184 'Observable fields should be put in an observable objects.', |
| 185 _getSpan(file, member)); | 185 span: _getSpan(file, member)); |
| 186 } | 186 } |
| 187 continue; | 187 continue; |
| 188 } | 188 } |
| 189 if (_hasObservable(member)) { | 189 if (_hasObservable(member)) { |
| 190 if (!declaresObservable) { | 190 if (!declaresObservable) { |
| 191 logger.warning('Observable fields should be put in an observable ' | 191 logger.warning('Observable fields should be put in an observable ' |
| 192 'objects. Please declare that this class extends from ' | 192 'objects. Please declare that this class extends from ' |
| 193 'ObservableBase, includes ObservableMixin, or implements ' | 193 'ObservableBase, includes ObservableMixin, or implements ' |
| 194 'Observable.', | 194 'Observable.', |
| 195 _getSpan(file, member)); | 195 span: _getSpan(file, member)); |
| 196 } | 196 } |
| 197 _transformFields(file, member, code, logger); | 197 _transformFields(file, member, code, logger); |
| 198 | 198 |
| 199 var names = member.fields.variables.map((v) => v.name.name); | 199 var names = member.fields.variables.map((v) => v.name.name); |
| 200 | 200 |
| 201 getters.addAll(names); | 201 getters.addAll(names); |
| 202 if (!_isReadOnly(member.fields)) { | 202 if (!_isReadOnly(member.fields)) { |
| 203 setters.addAll(names); | 203 setters.addAll(names); |
| 204 instanceFields.addAll(names); | 204 instanceFields.addAll(names); |
| 205 } | 205 } |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 TextEditTransaction code, TransformLogger logger) { | 297 TextEditTransaction code, TransformLogger logger) { |
| 298 | 298 |
| 299 final fields = member.fields; | 299 final fields = member.fields; |
| 300 if (_isReadOnly(fields)) return; | 300 if (_isReadOnly(fields)) return; |
| 301 | 301 |
| 302 // Private fields aren't supported: | 302 // Private fields aren't supported: |
| 303 for (var field in fields.variables) { | 303 for (var field in fields.variables) { |
| 304 final name = field.name.name; | 304 final name = field.name.name; |
| 305 if (Identifier.isPrivateName(name)) { | 305 if (Identifier.isPrivateName(name)) { |
| 306 logger.warning('Cannot make private field $name observable.', | 306 logger.warning('Cannot make private field $name observable.', |
| 307 _getSpan(file, field)); | 307 span: _getSpan(file, field)); |
| 308 return; | 308 return; |
| 309 } | 309 } |
| 310 } | 310 } |
| 311 | 311 |
| 312 // Unfortunately "var" doesn't work in all positions where type annotations | 312 // Unfortunately "var" doesn't work in all positions where type annotations |
| 313 // are allowed, such as "var get name". So we use "dynamic" instead. | 313 // are allowed, such as "var get name". So we use "dynamic" instead. |
| 314 var type = 'dynamic'; | 314 var type = 'dynamic'; |
| 315 if (fields.type != null) { | 315 if (fields.type != null) { |
| 316 type = _getOriginalCode(code, fields.type); | 316 type = _getOriginalCode(code, fields.type); |
| 317 } else if (_hasKeyword(fields.keyword, Keyword.VAR)) { | 317 } else if (_hasKeyword(fields.keyword, Keyword.VAR)) { |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 | 372 |
| 373 Token _findFieldSeperator(Token token) { | 373 Token _findFieldSeperator(Token token) { |
| 374 while (token != null) { | 374 while (token != null) { |
| 375 if (token.type == TokenType.COMMA || token.type == TokenType.SEMICOLON) { | 375 if (token.type == TokenType.COMMA || token.type == TokenType.SEMICOLON) { |
| 376 break; | 376 break; |
| 377 } | 377 } |
| 378 token = token.next; | 378 token = token.next; |
| 379 } | 379 } |
| 380 return token; | 380 return token; |
| 381 } | 381 } |
| OLD | NEW |