| OLD | NEW |
| 1 #!/usr/bin/env dart | 1 #!/usr/bin/env dart |
| 2 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 2 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
| 4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
| 5 | 5 |
| 6 /// Command line tool to merge the SDK libraries and our patch files. | 6 /// Command line tool to merge the SDK libraries and our patch files. |
| 7 /// This is currently designed as an offline tool, but we could automate it. | 7 /// This is currently designed as an offline tool, but we could automate it. |
| 8 | 8 |
| 9 import 'dart:io'; | 9 import 'dart:io'; |
| 10 import 'dart:math' as math; | 10 import 'dart:math' as math; |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 // the other files. | 257 // the other files. |
| 258 final patchFinder = new PatchFinder.parseAndVisit(name, patchContents); | 258 final patchFinder = new PatchFinder.parseAndVisit(name, patchContents); |
| 259 | 259 |
| 260 // Merge `external` declarations with the corresponding `@patch` code. | 260 // Merge `external` declarations with the corresponding `@patch` code. |
| 261 for (var partContent in partsContents) { | 261 for (var partContent in partsContents) { |
| 262 var partEdits = new StringEditBuffer(partContent); | 262 var partEdits = new StringEditBuffer(partContent); |
| 263 var partUnit = parseCompilationUnit(partContent); | 263 var partUnit = parseCompilationUnit(partContent); |
| 264 partUnit.accept(new PatchApplier(partEdits, patchFinder)); | 264 partUnit.accept(new PatchApplier(partEdits, patchFinder)); |
| 265 results.add(partEdits); | 265 results.add(partEdits); |
| 266 } | 266 } |
| 267 |
| 268 if (patchFinder.patches.length != patchFinder.applied.length) { |
| 269 print('Some elements marked as @patch do not have corresponding elements:'); |
| 270 for (var patched in patchFinder.patches.keys) { |
| 271 if (!patchFinder.applied.contains(patched)) { |
| 272 print('*** ${patched}'); |
| 273 } |
| 274 } |
| 275 throw "Failed to apply all @patch-es"; |
| 276 } |
| 277 |
| 267 return new List<String>.from(results.map((e) => e.toString())); | 278 return new List<String>.from(results.map((e) => e.toString())); |
| 268 } | 279 } |
| 269 | 280 |
| 270 /// Merge `@patch` declarations into `external` declarations. | 281 /// Merge `@patch` declarations into `external` declarations. |
| 271 class PatchApplier extends GeneralizingAstVisitor { | 282 class PatchApplier extends GeneralizingAstVisitor { |
| 272 final StringEditBuffer edits; | 283 final StringEditBuffer edits; |
| 273 final PatchFinder patch; | 284 final PatchFinder patch; |
| 274 | 285 |
| 275 bool _isLibrary = true; // until proven otherwise. | 286 bool _isLibrary = true; // until proven otherwise. |
| 276 | 287 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 for (var member in mergeMembers) { | 347 for (var member in mergeMembers) { |
| 337 var code = patch.contents.substring(member.offset, member.end); | 348 var code = patch.contents.substring(member.offset, member.end); |
| 338 edits.insert(pos, '\n\n ' + code); | 349 edits.insert(pos, '\n\n ' + code); |
| 339 } | 350 } |
| 340 } | 351 } |
| 341 | 352 |
| 342 void _maybePatch(AstNode node) { | 353 void _maybePatch(AstNode node) { |
| 343 if (node is FieldDeclaration) return; | 354 if (node is FieldDeclaration) return; |
| 344 | 355 |
| 345 var externalKeyword = (node as dynamic).externalKeyword; | 356 var externalKeyword = (node as dynamic).externalKeyword; |
| 346 if (externalKeyword == null) return; | |
| 347 | 357 |
| 348 var name = _qualifiedName(node); | 358 var name = _qualifiedName(node); |
| 349 var patchNode = patch.patches[name]; | 359 var patchNode = patch.patches[name]; |
| 350 if (patchNode == null) { | 360 if (patchNode == null) { |
| 351 print('warning: patch not found for $name: $node'); | 361 if (externalKeyword != null) { |
| 362 print('warning: patch not found for $name: $node'); |
| 363 } |
| 352 return; | 364 return; |
| 353 } | 365 } |
| 366 patch.applied.add(name); |
| 354 | 367 |
| 355 Annotation patchMeta = patchNode.metadata.lastWhere(_isPatchAnnotation); | 368 Annotation patchMeta = patchNode.metadata.lastWhere(_isPatchAnnotation); |
| 356 int start = patchMeta.endToken.next.offset; | 369 int start = patchMeta.endToken.next.offset; |
| 357 var code = patch.contents.substring(start, patchNode.end); | 370 var code = patch.contents.substring(start, patchNode.end); |
| 358 | 371 |
| 359 // For some node like static fields, the node's offset doesn't include | 372 // For some node like static fields, the node's offset doesn't include |
| 360 // the external keyword. Also starting from the keyword lets us preserve | 373 // the external keyword. Also starting from the keyword lets us preserve |
| 361 // documentation comments. | 374 // documentation comments. |
| 362 edits.replace(externalKeyword.offset, node.end, code); | 375 edits.replace(externalKeyword?.offset ?? node.offset, node.end, code); |
| 363 } | 376 } |
| 364 } | 377 } |
| 365 | 378 |
| 366 class PatchFinder extends GeneralizingAstVisitor { | 379 class PatchFinder extends GeneralizingAstVisitor { |
| 367 final String contents; | 380 final String contents; |
| 368 final CompilationUnit unit; | 381 final CompilationUnit unit; |
| 369 | 382 |
| 370 final Map patches = <String, Declaration>{}; | 383 final Map patches = <String, Declaration>{}; |
| 371 final Map mergeMembers = <String, List<ClassMember>>{}; | 384 final Map mergeMembers = <String, List<ClassMember>>{}; |
| 372 final List mergeDeclarations = <CompilationUnitMember>[]; | 385 final List mergeDeclarations = <CompilationUnitMember>[]; |
| 386 final Set<String> applied = new Set<String>(); |
| 373 | 387 |
| 374 PatchFinder.parseAndVisit(String name, String contents) | 388 PatchFinder.parseAndVisit(String name, String contents) |
| 375 : contents = contents, | 389 : contents = contents, |
| 376 unit = parseCompilationUnit(contents, name: name) { | 390 unit = parseCompilationUnit(contents, name: name) { |
| 377 visitCompilationUnit(unit); | 391 visitCompilationUnit(unit); |
| 378 } | 392 } |
| 379 | 393 |
| 380 @override | 394 @override |
| 381 visitCompilationUnitMember(CompilationUnitMember node) { | 395 visitCompilationUnitMember(CompilationUnitMember node) { |
| 382 mergeDeclarations.add(node); | 396 mergeDeclarations.add(node); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 if (diff != 0) return diff; | 541 if (diff != 0) return diff; |
| 528 return end - other.end; | 542 return end - other.end; |
| 529 } | 543 } |
| 530 } | 544 } |
| 531 | 545 |
| 532 List<SdkLibrary> _getSdkLibraries(String contents) { | 546 List<SdkLibrary> _getSdkLibraries(String contents) { |
| 533 var libraryBuilder = new SdkLibrariesReader_LibraryBuilder(true); | 547 var libraryBuilder = new SdkLibrariesReader_LibraryBuilder(true); |
| 534 parseCompilationUnit(contents).accept(libraryBuilder); | 548 parseCompilationUnit(contents).accept(libraryBuilder); |
| 535 return libraryBuilder.librariesMap.sdkLibraries; | 549 return libraryBuilder.librariesMap.sdkLibraries; |
| 536 } | 550 } |
| OLD | NEW |