OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 library analyzer.src.dart.sdk.patch; | 5 library analyzer.src.dart.sdk.patch; |
6 | 6 |
7 import 'package:analyzer/dart/ast/ast.dart'; | 7 import 'package:analyzer/dart/ast/ast.dart'; |
8 import 'package:analyzer/dart/ast/token.dart'; | 8 import 'package:analyzer/dart/ast/token.dart'; |
9 import 'package:analyzer/error/listener.dart'; | 9 import 'package:analyzer/error/listener.dart'; |
10 import 'package:analyzer/file_system/file_system.dart'; | 10 import 'package:analyzer/file_system/file_system.dart'; |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
190 } | 190 } |
191 membersToAppend.add(patchMember); | 191 membersToAppend.add(patchMember); |
192 } | 192 } |
193 } else { | 193 } else { |
194 // TODO(scheglov) support field | 194 // TODO(scheglov) support field |
195 String className = patchClass.name.name; | 195 String className = patchClass.name.name; |
196 _failInPatch('contains an unsupported class member in $className', | 196 _failInPatch('contains an unsupported class member in $className', |
197 patchMember.offset); | 197 patchMember.offset); |
198 } | 198 } |
199 } | 199 } |
200 // Append new top-level declarations. | 200 // Append new class members. |
201 Token lastToken = baseClass.endToken.previous; | 201 _appendToNodeList( |
202 for (ClassMember newMember in membersToAppend) { | 202 baseClass.members, membersToAppend, baseClass.leftBracket); |
203 newMember.endToken.setNext(lastToken.next); | |
204 lastToken.setNext(newMember.beginToken); | |
205 baseClass.members.add(newMember); | |
206 lastToken = newMember.endToken; | |
207 } | |
208 } | 203 } |
209 | 204 |
210 void _patchDirectives( | 205 void _patchDirectives( |
211 Source baseSource, | 206 Source baseSource, |
212 CompilationUnit baseUnit, | 207 CompilationUnit baseUnit, |
213 Source patchSource, | 208 Source patchSource, |
214 CompilationUnit patchUnit, | 209 CompilationUnit patchUnit, |
215 bool addNewTopLevelDeclarations) { | 210 bool addNewTopLevelDeclarations) { |
216 for (Directive patchDirective in patchUnit.directives) { | 211 for (Directive patchDirective in patchUnit.directives) { |
217 if (patchDirective is ImportDirective) { | 212 if (patchDirective is ImportDirective) { |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 } else { | 267 } else { |
273 _failIfPublicName(patchDeclaration, patchDeclaration.name.name); | 268 _failIfPublicName(patchDeclaration, patchDeclaration.name.name); |
274 declarationsToAppend.add(patchDeclaration); | 269 declarationsToAppend.add(patchDeclaration); |
275 } | 270 } |
276 } else { | 271 } else { |
277 _failInPatch('contains an unsupported top-level declaration', | 272 _failInPatch('contains an unsupported top-level declaration', |
278 patchDeclaration.offset); | 273 patchDeclaration.offset); |
279 } | 274 } |
280 } | 275 } |
281 // Append new top-level declarations. | 276 // Append new top-level declarations. |
282 Token lastToken = baseUnit.endToken.previous; | 277 _appendToNodeList(baseUnit.declarations, declarationsToAppend, |
283 for (CompilationUnitMember newDeclaration in declarationsToAppend) { | 278 baseUnit.endToken.previous); |
284 newDeclaration.endToken.setNext(lastToken.next); | |
285 lastToken.setNext(newDeclaration.beginToken); | |
286 baseUnit.declarations.add(newDeclaration); | |
287 lastToken = newDeclaration.endToken; | |
288 } | |
289 } | 279 } |
290 | 280 |
291 /** | 281 /** |
292 * Parse the given [source] into AST. | 282 * Parse the given [source] into AST. |
293 */ | 283 */ |
294 @visibleForTesting | 284 @visibleForTesting |
295 static CompilationUnit parse( | 285 static CompilationUnit parse( |
296 Source source, bool strong, AnalysisErrorListener errorListener) { | 286 Source source, bool strong, AnalysisErrorListener errorListener) { |
297 String code = source.contents.data; | 287 String code = source.contents.data; |
298 | 288 |
299 CharSequenceReader reader = new CharSequenceReader(code); | 289 CharSequenceReader reader = new CharSequenceReader(code); |
300 Scanner scanner = new Scanner(source, reader, errorListener); | 290 Scanner scanner = new Scanner(source, reader, errorListener); |
301 scanner.scanGenericMethodComments = strong; | 291 scanner.scanGenericMethodComments = strong; |
302 Token token = scanner.tokenize(); | 292 Token token = scanner.tokenize(); |
303 LineInfo lineInfo = new LineInfo(scanner.lineStarts); | 293 LineInfo lineInfo = new LineInfo(scanner.lineStarts); |
304 | 294 |
305 Parser parser = new Parser(source, errorListener); | 295 Parser parser = new Parser(source, errorListener); |
306 parser.parseGenericMethodComments = strong; | 296 parser.parseGenericMethodComments = strong; |
307 CompilationUnit unit = parser.parseCompilationUnit(token); | 297 CompilationUnit unit = parser.parseCompilationUnit(token); |
308 unit.lineInfo = lineInfo; | 298 unit.lineInfo = lineInfo; |
309 return unit; | 299 return unit; |
310 } | 300 } |
311 | 301 |
312 /** | 302 /** |
| 303 * Append [newNodes] to the given [nodes] and attach new tokens to the end |
| 304 * token of the last [nodes] items, or, if it is empty, to [defaultPrevToken]. |
| 305 */ |
| 306 static void _appendToNodeList( |
| 307 NodeList<AstNode> nodes, List<AstNode> newNodes, Token defaultPrevToken) { |
| 308 Token prevToken = nodes.endToken ?? defaultPrevToken; |
| 309 for (AstNode newNode in newNodes) { |
| 310 newNode.endToken.setNext(prevToken.next); |
| 311 prevToken.setNext(newNode.beginToken); |
| 312 nodes.add(newNode); |
| 313 prevToken = newNode.endToken; |
| 314 } |
| 315 } |
| 316 |
| 317 /** |
313 * Return `true` if [metadata] has the `@patch` annotation. | 318 * Return `true` if [metadata] has the `@patch` annotation. |
314 */ | 319 */ |
315 static bool _hasPatchAnnotation(List<Annotation> metadata) { | 320 static bool _hasPatchAnnotation(List<Annotation> metadata) { |
316 return metadata.any((annotation) { | 321 return metadata.any((annotation) { |
317 Identifier name = annotation.name; | 322 Identifier name = annotation.name; |
318 return annotation.constructorName == null && | 323 return annotation.constructorName == null && |
319 name is SimpleIdentifier && | 324 name is SimpleIdentifier && |
320 name.name == 'patch'; | 325 name.name == 'patch'; |
321 }); | 326 }); |
322 } | 327 } |
323 | 328 |
324 /** | 329 /** |
325 * Remove the [token] from the stream. | 330 * Remove the [token] from the stream. |
326 */ | 331 */ |
327 static void _removeToken(Token token) { | 332 static void _removeToken(Token token) { |
328 token.previous.setNext(token.next); | 333 token.previous.setNext(token.next); |
329 } | 334 } |
330 | 335 |
331 /** | 336 /** |
332 * Replace tokens of the [oldNode] with tokens of the [newNode]. | 337 * Replace tokens of the [oldNode] with tokens of the [newNode]. |
333 */ | 338 */ |
334 static void _replaceNodeTokens(AstNode oldNode, AstNode newNode) { | 339 static void _replaceNodeTokens(AstNode oldNode, AstNode newNode) { |
335 oldNode.beginToken.previous.setNext(newNode.beginToken); | 340 oldNode.beginToken.previous.setNext(newNode.beginToken); |
336 newNode.endToken.setNext(oldNode.endToken.next); | 341 newNode.endToken.setNext(oldNode.endToken.next); |
337 } | 342 } |
338 } | 343 } |
OLD | NEW |